@hitchy/plugin-auth 0.4.6 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2022 cepharum GmbH
3
+ Copyright (c) 2024 cepharum GmbH
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,96 +1,90 @@
1
- "use strict";
2
-
3
- module.exports = function() {
4
-
1
+ /**
2
+ * Implements request handlers for common requests related to authenticating as
3
+ * a user.
4
+ */
5
+ export default class UserController {
5
6
  /**
6
- * Implements request handlers for common requests related to authenticating as
7
- * a user.
7
+ * Responds on request for changing authenticated user's password.
8
+ *
9
+ * This handler assumes to follow one or more policy handler(s) which
10
+ * actually manage the process of changing the password.
11
+ *
12
+ * @param {Hitchy.Core.IncomingMessage} req request descriptor
13
+ * @param {Hitchy.Core.ServerResponse} res response manager
14
+ * @returns {void}
8
15
  */
9
- class UserController {
10
- /**
11
- * Responds on request for changing authenticated user's password.
12
- *
13
- * This handler assumes to follow one or more policy handler(s) which
14
- * actually manage the process of changing the password.
15
- *
16
- * @param {Hitchy.Core.IncomingMessage} req request descriptor
17
- * @param {Hitchy.Core.ServerResponse} res response manager
18
- * @returns {void}
19
- */
20
- static changePassword( req, res ) {
21
- res.format( {
22
- default() {
23
- res.json( {
24
- success: true
25
- } );
26
- },
27
- } );
28
- }
29
-
30
- /**
31
- * Responds on success after authenticating as a user.
32
- *
33
- * This request handler assumes to follow one or more policy handler(s)
34
- * which actually manage authentication.
35
- *
36
- * @param {Hitchy.Core.IncomingMessage} req request descriptor
37
- * @param {Hitchy.Core.ServerResponse} res response manager
38
- * @returns {void}
39
- */
40
- static authenticate( req, res ) {
41
- res.format( {
42
- default() {
43
- res.json( {
44
- success: true,
45
- authenticated: Boolean( req.user ),
46
- } );
47
- },
48
- } );
49
- }
16
+ static changePassword( req, res ) {
17
+ res.format( {
18
+ default() {
19
+ res.json( {
20
+ success: true
21
+ } );
22
+ },
23
+ } );
24
+ }
50
25
 
51
- /**
52
- * Provides status of current request's user being authenticated or not.
53
- *
54
- * @param {Hitchy.Core.IncomingMessage} req request descriptor
55
- * @param {Hitchy.Core.ServerResponse} res response manager
56
- * @returns {void}
57
- */
58
- static getCurrent( req, res ) {
59
- res.format( {
60
- default() {
61
- res.json( {
62
- success: true,
63
- authenticated: req.user ? {
64
- uuid: req.user.uuid,
65
- name: req.user.name,
66
- strategy: req.user.strategy || "local",
67
- roles: req.user.roles.map( role => role.name ),
68
- } : false,
69
- } );
70
- },
71
- } );
72
- }
26
+ /**
27
+ * Responds on success after authenticating as a user.
28
+ *
29
+ * This request handler assumes to follow one or more policy handler(s)
30
+ * which actually manage authentication.
31
+ *
32
+ * @param {Hitchy.Core.IncomingMessage} req request descriptor
33
+ * @param {Hitchy.Core.ServerResponse} res response manager
34
+ * @returns {void}
35
+ */
36
+ static authenticate( req, res ) {
37
+ res.format( {
38
+ default() {
39
+ res.json( {
40
+ success: true,
41
+ authenticated: Boolean( req.user ),
42
+ } );
43
+ },
44
+ } );
45
+ }
73
46
 
74
- /**
75
- * Drops authentication of current request's user. This request handler
76
- * is assuming to be a follow-up handler to some policy actually dropping
77
- * the user's authentication.
78
- *
79
- * @param {Hitchy.Core.IncomingMessage} req request descriptor
80
- * @param {Hitchy.Core.ServerResponse} res response manager
81
- * @returns {void}
82
- */
83
- static unauthenticate( req, res ) {
84
- res.format( {
85
- default() {
86
- res.json( {
87
- success: true,
88
- } );
89
- },
90
- } );
91
- }
47
+ /**
48
+ * Provides status of current request's user being authenticated or not.
49
+ *
50
+ * @param {Hitchy.Core.IncomingMessage} req request descriptor
51
+ * @param {Hitchy.Core.ServerResponse} res response manager
52
+ * @returns {void}
53
+ */
54
+ static getCurrent( req, res ) {
55
+ res.format( {
56
+ default() {
57
+ res.json( {
58
+ success: true,
59
+ authenticated: req.user ? {
60
+ uuid: req.user.uuid,
61
+ name: req.user.name,
62
+ strategy: req.user.strategy || "local",
63
+ roles: req.user.roles.map( role => role.name ),
64
+ } : false,
65
+ } );
66
+ },
67
+ } );
92
68
  }
93
69
 
94
- return UserController;
95
- };
70
+ /**
71
+ * Drops authentication of current request's user. This request handler
72
+ * is assuming to be a follow-up handler to some policy actually dropping
73
+ * the user's authentication.
74
+ *
75
+ * @param {Hitchy.Core.IncomingMessage} req request descriptor
76
+ * @param {Hitchy.Core.ServerResponse} res response manager
77
+ * @returns {void}
78
+ */
79
+ static unauthenticate( req, res ) {
80
+ res.format( {
81
+ default() {
82
+ res.json( {
83
+ success: true,
84
+ } );
85
+ },
86
+ } );
87
+ }
96
88
 
89
+ static useCMP = false;
90
+ }
@@ -1,6 +1,4 @@
1
- "use strict";
2
-
3
- module.exports = function() {
1
+ export default function() { // eslint-disable-line jsdoc/require-jsdoc
4
2
  const api = this;
5
3
  const { services } = api;
6
4
 
@@ -46,4 +44,4 @@ module.exports = function() {
46
44
  },
47
45
  },
48
46
  };
49
- };
47
+ }
package/api/model/role.js CHANGED
@@ -1,11 +1,4 @@
1
- "use strict";
2
-
3
- /**
4
- * Defines role model.
5
- *
6
- * @returns {Hitchy.Plugin.Odem.ModelSchema} definition of role model
7
- */
8
- module.exports = function() {
1
+ export default function() { // eslint-disable-line jsdoc/require-jsdoc
9
2
  const api = this;
10
3
  const { models } = api;
11
4
 
@@ -15,7 +8,7 @@ module.exports = function() {
15
8
  * @property {string} name unique name of user
16
9
  *
17
10
  * @name Hitchy.Plugin.Auth.Role
18
- * @type Hitchy.Plugin.Odem.Model
11
+ * @type {Hitchy.Plugin.Odem.Model}
19
12
  */
20
13
  return {
21
14
  props: {
@@ -37,4 +30,4 @@ module.exports = function() {
37
30
  },
38
31
  },
39
32
  };
40
- };
33
+ }
@@ -1,12 +1,4 @@
1
- "use strict";
2
-
3
1
  /**
4
- * Defines model associating users with roles.
5
- *
6
- * @returns {Hitchy.Plugin.Odem.ModelSchema} definition of model associating users with roles
7
- */
8
- module.exports = function() {
9
- /**
10
2
  * Implements model of a user suitable for authenticating as.
11
3
  *
12
4
  * @property {Buffer} role UUID of associated role
@@ -14,16 +6,15 @@ module.exports = function() {
14
6
  *
15
7
  * @name Hitchy.Plugin.Auth.UserToRole
16
8
  */
17
- return {
18
- props: {
19
- user: {
20
- required: true,
21
- type: "uuid",
22
- },
23
- role: {
24
- required: true,
25
- type: "uuid",
26
- },
9
+ export default {
10
+ props: {
11
+ user: {
12
+ required: true,
13
+ type: "uuid",
27
14
  },
28
- };
15
+ role: {
16
+ required: true,
17
+ type: "uuid",
18
+ },
19
+ },
29
20
  };
package/api/model/user.js CHANGED
@@ -1,13 +1,6 @@
1
- "use strict";
1
+ import Crypto from "node:crypto";
2
2
 
3
- const crypto = require( "crypto" );
4
-
5
- /**
6
- * Defines user model.
7
- *
8
- * @returns {Hitchy.Plugin.Odem.ModelSchema} definition of user model
9
- */
10
- module.exports = function() {
3
+ export default function() { // eslint-disable-line jsdoc/require-jsdoc
11
4
  const api = this;
12
5
  const { services, models } = api;
13
6
 
@@ -62,7 +55,7 @@ module.exports = function() {
62
55
 
63
56
  async beforeSave( existsAlready, record ) {
64
57
  if ( record.password ) {
65
- record.password = await this.hashPassword( record.password ); // eslint-disable-line no-param-reassign
58
+ record.password = await this.hashPassword( record.password );
66
59
  }
67
60
 
68
61
  return record;
@@ -105,7 +98,7 @@ module.exports = function() {
105
98
 
106
99
  switch ( algorithmName || "SCRYPT" ) {
107
100
  case "SSHA512" : {
108
- const hash = crypto.createHash( "SHA512" );
101
+ const hash = Crypto.createHash( "SHA512" );
109
102
  hash.update( normalized );
110
103
  hash.update( salt );
111
104
 
@@ -113,7 +106,7 @@ module.exports = function() {
113
106
  }
114
107
 
115
108
  case "SCRYPT" :
116
- return await new Promise( ( resolve, reject ) => crypto.scrypt( normalized, salt, 64, {
109
+ return await new Promise( ( resolve, reject ) => Crypto.scrypt( normalized, salt, 64, {
117
110
  cost: 16384,
118
111
  blockSize: 8,
119
112
  parallelization: 1,
@@ -173,7 +166,7 @@ module.exports = function() {
173
166
  * @returns {Promise<number>} promise for random integer in selected range
174
167
  */
175
168
  function randomNumber( min, max ) {
176
- return new Promise( ( resolve, reject ) => crypto.randomInt( min, max, ( error, number ) => {
169
+ return new Promise( ( resolve, reject ) => Crypto.randomInt( min, max, ( error, number ) => {
177
170
  if ( error ) {
178
171
  reject( error );
179
172
  } else {
@@ -189,7 +182,7 @@ module.exports = function() {
189
182
  * @returns {Promise<Buffer>} promise for selected number of random octets
190
183
  */
191
184
  function randomOctets( size ) {
192
- return new Promise( ( resolve, reject ) => crypto.randomBytes( size, ( error, octets ) => {
185
+ return new Promise( ( resolve, reject ) => Crypto.randomBytes( size, ( error, octets ) => {
193
186
  if ( error ) {
194
187
  reject( error );
195
188
  } else {
@@ -227,4 +220,4 @@ module.exports = function() {
227
220
  },
228
221
  },
229
222
  };
230
- };
223
+ }
@@ -1,6 +1,4 @@
1
- "use strict";
2
-
3
- module.exports = function() {
1
+ export default function() { // eslint-disable-line jsdoc/require-jsdoc
4
2
  const api = this;
5
3
  const { models, service } = api;
6
4
 
@@ -78,7 +76,7 @@ module.exports = function() {
78
76
 
79
77
  service.AuthManager.checkAuthentication( parts[1], parts[2] )
80
78
  .then( user => {
81
- req.user = user; // eslint-disable-line no-param-reassign
79
+ req.user = user;
82
80
 
83
81
  this.qualifyAuthenticated( req, res, next );
84
82
  } )
@@ -101,7 +99,7 @@ module.exports = function() {
101
99
 
102
100
  req.fetchBody()
103
101
  .then( body => {
104
- req.body = body; // eslint-disable-line no-param-reassign
102
+ req.body = body;
105
103
 
106
104
  return new Promise( ( resolve, reject ) => {
107
105
  AuthenticationPassport.authenticate( strategy || defaultStrategy )( req, res, err => {
@@ -148,7 +146,7 @@ module.exports = function() {
148
146
 
149
147
  service.AuthManager.listRolesOfUser( new models.User( uuid ) )
150
148
  .then( roles => {
151
- req.user.roles = roles; // eslint-disable-line no-param-reassign
149
+ req.user.roles = roles;
152
150
 
153
151
  logDebug( "authenticated as", req.user.name );
154
152
 
@@ -197,11 +195,11 @@ module.exports = function() {
197
195
  } );
198
196
  } else {
199
197
  // re-generating session on change of user authentication mitigates session-related attacks
200
- // -> passport's logout does not seem to exist, so we can't rely on passport regenerating the session
198
+ // -> passport's logout does not seem to exist, so we can not rely on passport regenerating the session
201
199
  await new Promise( ( resolve, reject ) => req.session.regenerate( error => ( error ? reject( error ) : resolve() ) ) );
202
200
  }
203
201
 
204
- req.user = undefined; // eslint-disable-line no-param-reassign
202
+ req.user = undefined;
205
203
 
206
204
  res.set( "X-Authenticated-As", undefined );
207
205
  res.set( "X-Authorized-As", undefined );
@@ -260,5 +258,4 @@ module.exports = function() {
260
258
  }
261
259
 
262
260
  return AuthenticationPolicy;
263
- };
264
-
261
+ }
@@ -1,34 +1,30 @@
1
- "use strict";
2
-
3
- module.exports = function() {
1
+ /**
2
+ * Implements commonly useful policy handlers for testing a request's
3
+ * authorizations.
4
+ */
5
+ export default class AuthorizationPolicy {
4
6
  /**
5
- * Implements commonly useful policy handlers for testing a request's
6
- * authorizations.
7
+ * Ensures current request's user has administrative privileges.
8
+ *
9
+ * @param {Hitchy.Core.IncomingMessage} req request descriptor
10
+ * @param {Hitchy.Core.ServerResponse} res response manager
11
+ * @param {Hitchy.Core.ContinuationHandler} next invoke to continue request handling
12
+ * @returns {void}
7
13
  */
8
- class AuthorizationPolicy {
9
- /**
10
- * Ensures current request's user has administrative privileges.
11
- *
12
- * @param {Hitchy.Core.IncomingMessage} req request descriptor
13
- * @param {Hitchy.Core.ServerResponse} res response manager
14
- * @param {Hitchy.Core.ContinuationHandler} next invoke to continue request handling
15
- * @returns {void}
16
- */
17
- static mustBeAdmin( req, res, next ) {
18
- const { adminRole } = this.services.AuthManager;
19
-
20
- if ( req.user && Array.isArray( req.user.roles ) && req.user.roles.some( role => role.name === adminRole ) ) {
21
- next();
22
- return;
23
- }
14
+ static mustBeAdmin( req, res, next ) {
15
+ const { adminRole } = this.services.AuthManager;
24
16
 
25
- res
26
- .status( 403 )
27
- .json( {
28
- error: "access forbidden: must be admin",
29
- } );
17
+ if ( req.user && Array.isArray( req.user.roles ) && req.user.roles.some( role => role.name === adminRole ) ) {
18
+ next();
19
+ return;
30
20
  }
21
+
22
+ res
23
+ .status( 403 )
24
+ .json( {
25
+ error: "access forbidden: must be admin",
26
+ } );
31
27
  }
32
28
 
33
- return AuthorizationPolicy;
34
- };
29
+ static useCMP = false;
30
+ }
@@ -1,6 +1,4 @@
1
- "use strict";
2
-
3
- module.exports = function() {
1
+ export default function() { // eslint-disable-line jsdoc/require-jsdoc
4
2
  const api = this;
5
3
  const { models } = api;
6
4
 
@@ -22,7 +20,7 @@ module.exports = function() {
22
20
  }
23
21
 
24
22
  res.status( 403 ).json( {
25
- error: "access forbidden: this isn't you"
23
+ error: "access forbidden: this is not you"
26
24
  } );
27
25
  },
28
26
 
@@ -130,4 +128,4 @@ module.exports = function() {
130
128
  next();
131
129
  }
132
130
  };
133
- };
131
+ }
@@ -1,6 +1,4 @@
1
- "use strict";
2
-
3
- module.exports = function() {
1
+ export default function() { // eslint-disable-line jsdoc/require-jsdoc
4
2
  const api = this;
5
3
  const { models, services } = api;
6
4
 
@@ -63,7 +61,7 @@ module.exports = function() {
63
61
  const { Role } = models;
64
62
 
65
63
  if ( !( role instanceof Role ) ) {
66
- role = String( role ); // eslint-disable-line no-param-reassign
64
+ role = String( role );
67
65
 
68
66
  if ( !/^[a-z_]/i.test( role ) || /\s/.test( role ) ) {
69
67
  throw new TypeError( "missing role information" );
@@ -290,4 +288,4 @@ module.exports = function() {
290
288
  }
291
289
 
292
290
  return AuthManager;
293
- };
291
+ }
@@ -1,8 +1,6 @@
1
- "use strict";
1
+ import PassportLib from "passport";
2
2
 
3
- const PassportLib = require( "passport" );
4
-
5
- module.exports = function() {
3
+ export default function() { // eslint-disable-line jsdoc/require-jsdoc
6
4
  const api = this;
7
5
 
8
6
  const logAlert = api.log( "hitchy:auth:alert" );
@@ -28,7 +26,7 @@ module.exports = function() {
28
26
  } );
29
27
 
30
28
  passport.deserializeUser( ( uuid, done ) => {
31
- /** @type Hitchy.Plugin.Auth.User */
29
+ /** @type {Hitchy.Plugin.Auth.User} */
32
30
  const user = new User( uuid );
33
31
 
34
32
  user.$exists
@@ -68,4 +66,4 @@ module.exports = function() {
68
66
  };
69
67
 
70
68
  return passport;
71
- };
69
+ }
@@ -1,6 +1,4 @@
1
- "use strict";
2
-
3
- const LocalStrategy = require( "passport-local" ).Strategy;
1
+ import { Strategy as LocalStrategy } from "passport-local";
4
2
 
5
3
  /**
6
4
  * Temporarily tracks additional session data per remotely authenticated user.
@@ -15,7 +13,7 @@ const LocalStrategy = require( "passport-local" ).Strategy;
15
13
  */
16
14
  const RemoteAuthCustomData = new Map();
17
15
 
18
- module.exports = function() {
16
+ export default function() { // eslint-disable-line jsdoc/require-jsdoc
19
17
  const api = this;
20
18
  const { models, services } = api;
21
19
 
@@ -62,7 +60,7 @@ module.exports = function() {
62
60
  *
63
61
  * @param {string} username name of user to authenticate
64
62
  * @param {string} password named user's password for authentication
65
- * @param {function(Error?, object, object)} done invoked with optional error, authenticated user or some message as feedback
63
+ * @param {function(Error?, object, object):void} done invoked with optional error, authenticated user or some message as feedback
66
64
  * @returns {void}
67
65
  */
68
66
  static checkAuthentication( username, password, done ) {
@@ -136,7 +134,7 @@ module.exports = function() {
136
134
  * @param {Hitchy.Plugin.Auth.SamlConfig} config SAML protocol configuration
137
135
  * @returns {Strategy} generated strategy for use with passport.js
138
136
  */
139
- static generateSaml( strategyName, config ) {
137
+ static async generateSaml( strategyName, config ) {
140
138
  const verifyLocalProfileOnLogin = ( req, userInfo, done ) => {
141
139
  RemoteAuthCustomData.set( `${strategyName}:${userInfo.nameID}`, { ...userInfo } );
142
140
 
@@ -147,7 +145,7 @@ module.exports = function() {
147
145
  getLocalProfile( strategyName, userInfo.nameID, false, done );
148
146
  };
149
147
 
150
- const { Strategy } = require( "passport-saml" );
148
+ const { Strategy } = await import( "passport-saml" );
151
149
  const strategy = new Strategy( {
152
150
  ...config,
153
151
  passReqToCallback: true,
@@ -224,15 +222,15 @@ module.exports = function() {
224
222
  * supporting OpenID Connect with Authorization Code Flow.
225
223
  *
226
224
  * @param {string} strategyName name of resulting strategy in context of your application
227
- * @param {ClientMetaData} config OpenID Connect client configuration
225
+ * @param {object} config OpenID Connect client configuration
228
226
  * @returns {Promise<Strategy>} promises generated strategy for use with passport.js
229
227
  */
230
- static async generateOpenIdConnect( strategyName, config ) { // eslint-disable-line consistent-this
228
+ static async generateOpenIdConnect( strategyName, config ) {
231
229
  const verifyLocalProfileOnLogin = ( req, tokens, userInfo, done ) => {
232
230
  getLocalProfile( strategyName, userInfo.preferred_username, true, done );
233
231
  };
234
232
 
235
- const { Issuer, Strategy, generators } = require( "openid-client" );
233
+ const { Issuer, Strategy, generators } = await import( "openid-client" );
236
234
  const issuer = await Issuer.discover( config.discovery_url );
237
235
  const client = new issuer.Client( config );
238
236
 
@@ -248,7 +246,7 @@ module.exports = function() {
248
246
  return Promise.resolve( false );
249
247
  }
250
248
 
251
- const state = req.session[key] = generators.state( 32 ); // eslint-disable-line no-param-reassign
249
+ const state = req.session[key] = generators.state( 32 );
252
250
 
253
251
  // redirect user to discovered end_session_url of IdP
254
252
  req.context.response.redirect( 302, client.endSessionUrl( { state } ) );
@@ -280,4 +278,4 @@ module.exports = function() {
280
278
  }
281
279
 
282
280
  return AuthenticationStrategies;
283
- };
281
+ }
@@ -1,15 +1,13 @@
1
- "use strict";
2
-
3
- module.exports = function() {
1
+ export default function() { // eslint-disable-line jsdoc/require-jsdoc
4
2
  /**
5
3
  * Implements behavior of a single node in a hierarchy of authorization
6
4
  * rules.
7
5
  *
8
6
  * @property {?AuthorizationNode} parent refers to superordinated node
9
7
  * @property {?string} name name of segment addressing this node in context of its parent
10
- * @property {{accept: object<string, number>, reject: object<string, number>}} roles maps names of roles into number of rules requesting to accept/reject
11
- * @property {{accept: object<string, number>, reject: object<string, number>}} users lists UUIDs of users to accept/reject in context of node
12
- * @property {object<string,AuthorizationNode>} children maps relative names into subordinated nodes
8
+ * @property {{accept: Object<string, number>, reject: Object<string, number>}} roles maps names of roles into number of rules requesting to accept/reject
9
+ * @property {{accept: Object<string, number>, reject: Object<string, number>}} users lists UUIDs of users to accept/reject in context of node
10
+ * @property {Object<string,AuthorizationNode>} children maps relative names into subordinated nodes
13
11
  */
14
12
  class AuthorizationNode {
15
13
  /**
@@ -193,7 +191,7 @@ module.exports = function() {
193
191
  /**
194
192
  * Indicates if current node lacks any viable information.
195
193
  *
196
- * @returns {boolean} true if node hasn't any viable information affecting authorization checks
194
+ * @returns {boolean} true if node has not any viable information affecting authorization checks
197
195
  */
198
196
  isSpare() {
199
197
  for ( const list of [ this.users.accept, this.users.reject, this.roles.accept, this.roles.reject ] ) {
@@ -242,7 +240,7 @@ module.exports = function() {
242
240
  * Transfer every valuable information to a clone of current node and
243
241
  * return it.
244
242
  *
245
- * @returns {AuthorizationNode} clone of current node limited to currently valuable data, undefined if node isn't required anymore
243
+ * @returns {AuthorizationNode} clone of current node limited to currently valuable data, undefined if node is not required anymore
246
244
  */
247
245
  gc() {
248
246
  const children = this.children;
@@ -293,4 +291,4 @@ module.exports = function() {
293
291
  }
294
292
 
295
293
  return AuthorizationNode;
296
- };
294
+ }
@@ -1,6 +1,4 @@
1
- "use strict";
2
-
3
- module.exports = function() {
1
+ export default function() { // eslint-disable-line jsdoc/require-jsdoc
4
2
  const api = this;
5
3
 
6
4
  const logError = api.log( "hitchy:plugin:auth:error" );
@@ -12,11 +10,11 @@ module.exports = function() {
12
10
  class AuthorizationPolicyGenerator {
13
11
  /**
14
12
  * Generates policy handler testing a request's user for having any of
15
- * the listed roles and instantly rejecting requests of users who don't.
13
+ * the listed roles and instantly rejecting requests of users who do not.
16
14
  * Request is also rejected of request's user is unknown.
17
15
  *
18
16
  * @param {string|string[]} roles lists roles to accept
19
- * @returns {Hitchy.Core.RequestPolicyHandler} policy handler rejecting requests of users who doesn't have any of the listed roles
17
+ * @returns {Hitchy.Core.RequestPolicyHandler} policy handler rejecting requests of users who does not have any of the listed roles
20
18
  */
21
19
  static hasRole( roles ) {
22
20
  if ( !roles ) {
@@ -35,7 +33,7 @@ module.exports = function() {
35
33
 
36
34
  return ( req, res, next ) => {
37
35
  if ( req.user && Array.isArray( req.user.roles ) ) {
38
- const { adminRole } = req.hitchy.runtime.services.AuthManager;
36
+ const { adminRole } = req.hitchy.services.AuthManager;
39
37
  const userRoles = req.user.roles;
40
38
  const numUserRoles = userRoles.length;
41
39
 
@@ -60,10 +58,10 @@ module.exports = function() {
60
58
  /**
61
59
  * Generates policy handler testing a request's user for being
62
60
  * authorized to access at least one of the listed resources and
63
- * instantly rejecting requests of users who don't.
61
+ * instantly rejecting requests of users who do not.
64
62
  *
65
63
  * @param {string|string[]} resource name(s) of resource(s)
66
- * @returns {Hitchy.Core.RequestPolicyHandler} policy handler rejecting requests of users who mustn't access any of the named resources
64
+ * @returns {Hitchy.Core.RequestPolicyHandler} policy handler rejecting requests of users who must not access any of the named resources
67
65
  */
68
66
  static mayAccess( resource ) {
69
67
  if ( !resource ) {
@@ -92,4 +90,4 @@ module.exports = function() {
92
90
  }
93
91
 
94
92
  return AuthorizationPolicyGenerator;
95
- };
93
+ }
@@ -1,6 +1,4 @@
1
- "use strict";
2
-
3
- module.exports = function() {
1
+ export default function() { // eslint-disable-line jsdoc/require-jsdoc
4
2
  const api = this;
5
3
  const { services, models } = api;
6
4
 
@@ -300,4 +298,4 @@ module.exports = function() {
300
298
  }
301
299
 
302
300
  return AuthorizationTree;
303
- };
301
+ }
@@ -1,6 +1,4 @@
1
- "use strict";
2
-
3
- module.exports = function() {
1
+ export default function() { // eslint-disable-line jsdoc/require-jsdoc
4
2
  const api = this;
5
3
  const { service } = api;
6
4
 
@@ -22,8 +20,8 @@ module.exports = function() {
22
20
  const adminRole = service.AuthManager.adminRole;
23
21
 
24
22
  if ( adminRole && Array.isArray( userInfo?.roles ) ) {
25
- for ( const role of userInfo.roles ) {
26
- if ( role?.name === adminRole ) {
23
+ for ( let i = 0; i < userInfo.roles.length; i++ ) {
24
+ if ( userInfo.roles[i]?.name === adminRole ) {
27
25
  return true;
28
26
  }
29
27
  }
@@ -70,4 +68,4 @@ module.exports = function() {
70
68
  }
71
69
 
72
70
  return AuthorizationService;
73
- };
71
+ }
@@ -1,6 +1,4 @@
1
- "use strict";
2
-
3
- module.exports = function( options, HitchyPluginSession ) {
1
+ export default function( options, HitchyPluginSession ) { // eslint-disable-line jsdoc/require-jsdoc
4
2
  const api = this;
5
3
 
6
4
  const logDebug = api.log( "hitchy:auth:debug" );
@@ -93,7 +91,7 @@ module.exports = function( options, HitchyPluginSession ) {
93
91
  *
94
92
  * This method is used by passport.
95
93
  *
96
- * @param {function(error: (Error|undefined)): void} doneFn callback invoked when session has been re-generated or some error occurred
94
+ * @param {function((Error|undefined)): void} doneFn callback invoked when session has been re-generated or some error occurred
97
95
  * @returns {void}
98
96
  */
99
97
  regenerate( doneFn ) {
@@ -134,7 +132,7 @@ module.exports = function( options, HitchyPluginSession ) {
134
132
  *
135
133
  * This method is used by passport.
136
134
  *
137
- * @param {function(error: (Error|undefined)): void} doneFn callback invoked when session has been saved or some error occurred
135
+ * @param {function((Error|undefined)):void} doneFn callback invoked when session has been saved or some error occurred
138
136
  * @returns {void}
139
137
  */
140
138
  save( doneFn ) {
@@ -147,4 +145,4 @@ module.exports = function( options, HitchyPluginSession ) {
147
145
  }
148
146
 
149
147
  return PassportCompatibleSession;
150
- };
148
+ }
package/config/auth.js CHANGED
@@ -1,20 +1,14 @@
1
- "use strict";
2
-
3
- module.exports = function() {
4
- return {
5
- auth: {
6
- prefix: "/api/auth",
7
- strategies: {
8
- // local: this.runtime.services.AuthStrategies.generateLocal()
9
- },
10
- authorizations: {
11
- // "feature.export.pdf": "@customers"
12
- // "feature.export.text": "@customers,@testers"
13
- },
14
- roles: [
15
- // "customers",
16
- // "testers",
17
- ],
18
- }
19
- };
1
+ export const auth = {
2
+ prefix: "/api/auth",
3
+ strategies: {
4
+ // local: this.services.AuthStrategies.generateLocal()
5
+ },
6
+ authorizations: {
7
+ // "feature.export.pdf": "@customers"
8
+ // "feature.export.text": "@customers,@testers"
9
+ },
10
+ roles: [
11
+ // "customers",
12
+ // "testers",
13
+ ],
20
14
  };
package/hash-password.js CHANGED
@@ -1,41 +1,16 @@
1
- /**
2
- * (c) 2020 cepharum GmbH, Berlin, http://cepharum.de
3
- *
4
- * The MIT License (MIT)
5
- *
6
- * Copyright (c) 2020 cepharum GmbH
7
- *
8
- * Permission is hereby granted, free of charge, to any person obtaining a copy
9
- * of this software and associated documentation files (the "Software"), to deal
10
- * in the Software without restriction, including without limitation the rights
11
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
- * copies of the Software, and to permit persons to whom the Software is
13
- * furnished to do so, subject to the following conditions:
14
- *
15
- * The above copyright notice and this permission notice shall be included in all
16
- * copies or substantial portions of the Software.
17
- *
18
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
- * SOFTWARE.
25
- *
26
- * @author: cepharum
27
- */
1
+ #!/usr/bin/env node
2
+ import UserModel from "./api/model/user.js";
28
3
 
29
- "use strict";
30
-
31
- const { hashPassword } = require( "./api/model/user" )().methods;
32
4
  const chunks = [];
33
5
 
34
6
  process.stdin.on( "data", chunk => chunks.push( chunk ) );
35
- process.stdin.on( "end", () => {
36
- hashPassword( Buffer.concat( chunks ) )
7
+ process.stdin.once( "end", () => {
8
+ const input = Buffer.concat( chunks );
9
+
10
+ UserModel.call( { services: {}, models: {} } )
11
+ .methods.hashPassword( input )
37
12
  .then( password => {
38
- console.log( password );
13
+ console.log( password ); // eslint-disable-line no-console
39
14
  } )
40
15
  .catch( console.error );
41
16
  } );
package/index.js CHANGED
@@ -1,6 +1,4 @@
1
- "use strict";
2
-
3
- module.exports = function( options, plugins ) {
1
+ export default function( options, plugins ) { // eslint-disable-line jsdoc/require-jsdoc
4
2
  const api = this;
5
3
 
6
4
  const logWarning = api.log( "hitchy:session:warning" );
@@ -32,7 +30,9 @@ module.exports = function( options, plugins ) {
32
30
  const roles = api.config.auth.roles;
33
31
 
34
32
  if ( Array.isArray( roles ) && roles.length > 0 ) {
35
- for ( const roleName of roles ) {
33
+ for ( let i = 0; i < roles.length; i++ ) {
34
+ const roleName = roles[i];
35
+
36
36
  if ( typeof roleName === "string" && roleName && !/\s/.test( roleName.trim() ) ) {
37
37
  await AuthManager.asRole( roleName.trim(), true ); // eslint-disable-line no-await-in-loop
38
38
  } else {
@@ -53,7 +53,7 @@ module.exports = function( options, plugins ) {
53
53
  const policies = {};
54
54
 
55
55
  if ( session.disable ) {
56
- logWarning( "server-side sessions are disabled, thus passport isn't integrated for commonly handling all requests automatically" );
56
+ logWarning( "server-side sessions are disabled, thus passport is not integrated for commonly handling all requests automatically" );
57
57
 
58
58
  policies["/"] = [
59
59
  "authentication.handleBasicAuth",
@@ -67,7 +67,7 @@ module.exports = function( options, plugins ) {
67
67
 
68
68
  return prefix === false ? policies : {
69
69
  ...policies,
70
- [`POST ${prefix}/login/:strategy?`]: ["authentication.login"],
70
+ [`POST ${prefix}/login{/:strategy}`]: ["authentication.login"],
71
71
  [`GET ${prefix}/login/:strategy`]: ["authentication.login"],
72
72
  [`GET ${prefix}/logout`]: ["authentication.logout"],
73
73
  [`POST ${prefix}/password`]: ["user.changePassword"],
@@ -80,7 +80,7 @@ module.exports = function( options, plugins ) {
80
80
 
81
81
  return prefix === false ? {} : {
82
82
  after: {
83
- [`POST ${prefix}/login/:strategy?`]: "user.authenticate",
83
+ [`POST ${prefix}/login{/:strategy}`]: "user.authenticate",
84
84
  [`GET ${prefix}/login/:strategy`]: "user.authenticate",
85
85
  [`GET ${prefix}/current`]: "user.getCurrent",
86
86
  [`GET ${prefix}/logout`]: "user.unauthenticate",
@@ -98,4 +98,4 @@ module.exports = function( options, plugins ) {
98
98
  }
99
99
 
100
100
  return pluginApi;
101
- };
101
+ }
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@hitchy/plugin-auth",
3
- "version": "0.4.6",
3
+ "version": "0.5.1",
4
4
  "description": "user authentication and authorization for Hitchy",
5
+ "type": "module",
5
6
  "main": "index.js",
6
7
  "types": "index.d.ts",
7
8
  "scripts": {
@@ -11,6 +12,9 @@
11
12
  "docs:dev": "vitepress dev docs",
12
13
  "docs:build": "vitepress build docs"
13
14
  },
15
+ "bin": {
16
+ "hash-password": "./hash-password.js"
17
+ },
14
18
  "repository": {
15
19
  "type": "git",
16
20
  "url": "https://gitlab.com/hitchy/plugin-auth.git"
@@ -22,24 +26,26 @@
22
26
  },
23
27
  "homepage": "https://auth.hitchy.org",
24
28
  "peerDependencies": {
25
- "@hitchy/core": "0.8.x",
26
- "@hitchy/plugin-odem": "0.9.x",
29
+ "@hitchy/core": "1.x",
27
30
  "@hitchy/plugin-cookies": "0.1.x",
31
+ "@hitchy/plugin-odem": "0.9.x",
28
32
  "@hitchy/plugin-session": "0.4.x"
29
33
  },
30
34
  "devDependencies": {
31
- "@hitchy/server-dev-tools": "^0.4.9",
35
+ "@hitchy/core": "^1.0.1",
36
+ "@hitchy/server-dev-tools": "^0.8.5",
32
37
  "@hitchy/types": "^0.1.3",
33
38
  "c8": "^10.1.2",
34
- "eslint": "^8.57.0",
35
- "eslint-config-cepharum": "^1.0.14",
36
- "eslint-plugin-promise": "^6.6.0",
37
- "mocha": "^10.7.3",
38
- "openid-client": "^5.6.5",
39
+ "eslint": "^9.15.0",
40
+ "eslint-config-cepharum": "^2.0.2",
41
+ "mermaid": "^11.4.0",
42
+ "mocha": "^10.8.2",
43
+ "openid-client": "^5.7.0",
39
44
  "passport-saml": "^3.2.4",
40
45
  "should": "^13.2.3",
41
46
  "should-http": "^0.1.1",
42
- "vitepress": "^1.3.4"
47
+ "vitepress": "^1.5.0",
48
+ "vitepress-plugin-mermaid": "^2.0.17"
43
49
  },
44
50
  "dependencies": {
45
51
  "passport": "^0.7.0",
@@ -51,6 +57,6 @@
51
57
  "hash-password.js",
52
58
  "hitchy.json",
53
59
  "index.d.ts",
54
- "index.js"
60
+ "index.cjs"
55
61
  ]
56
62
  }