@drax/identity-back 0.37.4 → 0.38.0
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/dist/index.js +11 -3
- package/dist/middleware/apiKeyMiddleware.js +5 -1
- package/dist/models/UserLoginFailModel.js +8 -8
- package/dist/models/UserSessionModel.js +8 -8
- package/dist/rbac/Rbac.js +21 -1
- package/dist/schemas/TokenPayloadSchema.js +14 -0
- package/dist/services/UserService.js +34 -14
- package/dist/utils/AuthUtils.js +14 -28
- package/package.json +7 -7
- package/src/index.ts +22 -2
- package/src/middleware/apiKeyMiddleware.ts +6 -2
- package/src/middleware/jwtMiddleware.ts +2 -2
- package/src/middleware/rbacMiddleware.ts +6 -6
- package/src/models/UserLoginFailModel.ts +8 -8
- package/src/models/UserSessionModel.ts +8 -8
- package/src/rbac/Rbac.ts +28 -4
- package/src/schemas/TokenPayloadSchema.ts +23 -0
- package/src/services/UserService.ts +42 -15
- package/src/utils/AuthUtils.ts +17 -31
- package/tsconfig.tsbuildinfo +1 -1
- package/types/index.d.ts +9 -3
- package/types/index.d.ts.map +1 -1
- package/types/middleware/apiKeyMiddleware.d.ts.map +1 -1
- package/types/models/UserLoginFailModel.d.ts +2 -2
- package/types/models/UserLoginFailModel.d.ts.map +1 -1
- package/types/models/UserSessionModel.d.ts +2 -2
- package/types/models/UserSessionModel.d.ts.map +1 -1
- package/types/rbac/Rbac.d.ts +7 -3
- package/types/rbac/Rbac.d.ts.map +1 -1
- package/types/schemas/TokenPayloadSchema.d.ts +35 -0
- package/types/schemas/TokenPayloadSchema.d.ts.map +1 -0
- package/types/schemas/UserLoginFailSchema.d.ts +1 -1
- package/types/schemas/UserSessionSchema.d.ts +1 -1
- package/types/services/UserService.d.ts +5 -1
- package/types/services/UserService.d.ts.map +1 -1
- package/types/utils/AuthUtils.d.ts +3 -4
- package/types/utils/AuthUtils.d.ts.map +1 -1
package/dist/index.js
CHANGED
|
@@ -30,6 +30,12 @@ import CreateOrUpdateRole from "./setup/CreateOrUpdateRole.js";
|
|
|
30
30
|
import LoadPermissions from "./setup/LoadPermissions.js";
|
|
31
31
|
import LoadIdentityConfigFromEnv from "./setup/LoadIdentityConfigFromEnv.js";
|
|
32
32
|
import RecoveryUserPassword from "./setup/RecoveryUserPassword.js";
|
|
33
|
+
import { RoleModel, RoleMongoSchema } from "./models/RoleModel.js";
|
|
34
|
+
import { TenantModel, TenantMongoSchema } from "./models/TenantModel.js";
|
|
35
|
+
import { UserModel, UserMongoSchema } from "./models/UserModel.js";
|
|
36
|
+
import { UserApiKeyModel, UserApiKeyMongoSchema } from "./models/UserApiKeyModel.js";
|
|
37
|
+
import { UserSessionModel, UserSessionMongoSchema } from "./models/UserSessionModel.js";
|
|
38
|
+
import { UserLoginFailModel, UserLoginFailMongoSchema } from "./models/UserLoginFailModel.js";
|
|
33
39
|
import RoleMongoRepository from "./repository/mongo/RoleMongoRepository.js";
|
|
34
40
|
import TenantMongoRepository from "./repository/mongo/TenantMongoRepository.js";
|
|
35
41
|
import UserMongoRepository from "./repository/mongo/UserMongoRepository.js";
|
|
@@ -52,14 +58,14 @@ import { UserSchema, UserBaseSchema } from "./schemas/UserSchema.js";
|
|
|
52
58
|
import { TenantSchema, TenantBaseSchema } from "./schemas/TenantSchema.js";
|
|
53
59
|
import { RoleSchema, RoleBaseSchema } from "./schemas/RoleSchema.js";
|
|
54
60
|
import { UserApiKeySchema, UserApiKeyBaseSchema } from "./schemas/UserApiKeySchema.js";
|
|
55
|
-
import { UserLoginFailBaseSchema
|
|
56
|
-
import { UserSessionBaseSchema
|
|
61
|
+
import { UserLoginFailBaseSchema } from "./schemas/UserLoginFailSchema.js";
|
|
62
|
+
import { UserSessionBaseSchema } from "./schemas/UserSessionSchema.js";
|
|
57
63
|
const graphqlMergeResult = await GraphqlMerge();
|
|
58
64
|
const identityTypeDefs = await graphqlMergeResult.typeDefs;
|
|
59
65
|
const identityResolvers = await graphqlMergeResult.resolvers;
|
|
60
66
|
export {
|
|
61
67
|
//Schemas
|
|
62
|
-
UserSchema, UserBaseSchema, TenantSchema, TenantBaseSchema, RoleSchema, RoleBaseSchema, UserApiKeyBaseSchema, UserApiKeySchema, UserLoginFailBaseSchema,
|
|
68
|
+
UserSchema, UserBaseSchema, TenantSchema, TenantBaseSchema, RoleSchema, RoleBaseSchema, UserApiKeyBaseSchema, UserApiKeySchema, UserLoginFailBaseSchema, UserSessionBaseSchema,
|
|
63
69
|
//Service
|
|
64
70
|
UserService, RoleService, TenantService, UserApiKeyService, UserSessionService, UserLoginFailService, PermissionService, Rbac,
|
|
65
71
|
//Factories
|
|
@@ -74,6 +80,8 @@ jwtMiddleware, rbacMiddleware, apiKeyMiddleware,
|
|
|
74
80
|
RolePermissions, TenantPermissions, UserPermissions, UserApiKeyPermissions, UserSessionPermissions, UserLoginFailPermissions,
|
|
75
81
|
//Mongo Repositories
|
|
76
82
|
RoleMongoRepository, TenantMongoRepository, UserMongoRepository, UserApiKeyMongoRepository, UserSessionMongoRepository, UserLoginFailMongoRepository,
|
|
83
|
+
//Mongo Models
|
|
84
|
+
RoleModel, TenantModel, UserModel, UserApiKeyModel, UserSessionModel, UserLoginFailModel, RoleMongoSchema, TenantMongoSchema, UserMongoSchema, UserApiKeyMongoSchema, UserSessionMongoSchema, UserLoginFailMongoSchema,
|
|
77
85
|
//Sqlite Repositories
|
|
78
86
|
RoleSqliteRepository, TenantSqliteRepository, UserSqliteRepository, UserApiKeySqliteRepository, UserLoginFailSqliteRepository, UserSessionSqliteRepository,
|
|
79
87
|
//Config
|
|
@@ -21,7 +21,7 @@ async function apiKeyMiddleware(request, reply) {
|
|
|
21
21
|
apiKey = request.headers?.authorization?.replace(/ApiKey /i, "");
|
|
22
22
|
}
|
|
23
23
|
//Por authorization '<uuid-key>'
|
|
24
|
-
const uuidRegex = /^[0-9a-
|
|
24
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
25
25
|
if (request.headers['authorization'] && uuidRegex.test(request.headers['authorization'])) {
|
|
26
26
|
apiKey = request.headers['authorization'];
|
|
27
27
|
}
|
|
@@ -32,7 +32,11 @@ async function apiKeyMiddleware(request, reply) {
|
|
|
32
32
|
id: userApiKey.user._id.toString(),
|
|
33
33
|
username: userApiKey.user.username,
|
|
34
34
|
roleId: userApiKey.user.role?._id?.toString(),
|
|
35
|
+
roleName: userApiKey.user.role?.name,
|
|
35
36
|
tenantId: userApiKey.user?.tenant?._id?.toString(),
|
|
37
|
+
tenantName: userApiKey.user?.tenant?.name,
|
|
38
|
+
apiKeyId: userApiKey?._id?.toString(),
|
|
39
|
+
apiKeyName: userApiKey?.name
|
|
36
40
|
};
|
|
37
41
|
request.authUser = authUser;
|
|
38
42
|
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { mongoose } from '@drax/common-back';
|
|
2
2
|
import uniqueValidator from 'mongoose-unique-validator';
|
|
3
3
|
import mongoosePaginate from 'mongoose-paginate-v2';
|
|
4
|
-
const
|
|
4
|
+
const UserLoginFailMongoSchema = new mongoose.Schema({
|
|
5
5
|
username: { type: String, required: false, index: false, unique: false },
|
|
6
6
|
userAgent: { type: String, required: false, index: false, unique: false },
|
|
7
7
|
ip: { type: String, required: false, index: false, unique: false },
|
|
8
8
|
}, { timestamps: true });
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
UserLoginFailMongoSchema.plugin(uniqueValidator, { message: 'validation.unique' });
|
|
10
|
+
UserLoginFailMongoSchema.plugin(mongoosePaginate);
|
|
11
|
+
UserLoginFailMongoSchema.virtual("id").get(function () {
|
|
12
12
|
return this._id.toString();
|
|
13
13
|
});
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
UserLoginFailMongoSchema.set('toJSON', { getters: true, virtuals: true });
|
|
15
|
+
UserLoginFailMongoSchema.set('toObject', { getters: true, virtuals: true });
|
|
16
16
|
const MODEL_NAME = 'UserLoginFail';
|
|
17
17
|
const COLLECTION_NAME = 'UserLoginFail';
|
|
18
|
-
const UserLoginFailModel = mongoose.model(MODEL_NAME,
|
|
19
|
-
export {
|
|
18
|
+
const UserLoginFailModel = mongoose.model(MODEL_NAME, UserLoginFailMongoSchema, COLLECTION_NAME);
|
|
19
|
+
export { UserLoginFailMongoSchema, UserLoginFailModel };
|
|
20
20
|
export default UserLoginFailModel;
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { mongoose } from '@drax/common-back';
|
|
2
2
|
import uniqueValidator from 'mongoose-unique-validator';
|
|
3
3
|
import mongoosePaginate from 'mongoose-paginate-v2';
|
|
4
|
-
const
|
|
4
|
+
const UserSessionMongoSchema = new mongoose.Schema({
|
|
5
5
|
uuid: { type: String, required: true, index: true, unique: false },
|
|
6
6
|
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true, index: true, unique: false },
|
|
7
7
|
userAgent: { type: String, required: false, index: false, unique: false },
|
|
8
8
|
ip: { type: String, required: false, index: false, unique: false },
|
|
9
9
|
}, { timestamps: true });
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
UserSessionMongoSchema.plugin(uniqueValidator, { message: 'validation.unique' });
|
|
11
|
+
UserSessionMongoSchema.plugin(mongoosePaginate);
|
|
12
|
+
UserSessionMongoSchema.virtual("id").get(function () {
|
|
13
13
|
return this._id.toString();
|
|
14
14
|
});
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
UserSessionMongoSchema.set('toJSON', { getters: true, virtuals: true });
|
|
16
|
+
UserSessionMongoSchema.set('toObject', { getters: true, virtuals: true });
|
|
17
17
|
const MODEL_NAME = 'UserSession';
|
|
18
18
|
const COLLECTION_NAME = 'UserSession';
|
|
19
|
-
const UserSessionModel = mongoose.model(MODEL_NAME,
|
|
20
|
-
export {
|
|
19
|
+
const UserSessionModel = mongoose.model(MODEL_NAME, UserSessionMongoSchema, COLLECTION_NAME);
|
|
20
|
+
export { UserSessionMongoSchema, UserSessionModel };
|
|
21
21
|
export default UserSessionModel;
|
package/dist/rbac/Rbac.js
CHANGED
|
@@ -11,8 +11,13 @@ class Rbac {
|
|
|
11
11
|
return {
|
|
12
12
|
id: this.userId,
|
|
13
13
|
username: this.username,
|
|
14
|
+
session: this.session,
|
|
14
15
|
roleId: this.roleId,
|
|
15
|
-
|
|
16
|
+
roleName: this.roleName,
|
|
17
|
+
tenantId: this.tenantId,
|
|
18
|
+
tenantName: this.tenantName,
|
|
19
|
+
apiKeyId: this.apiKeyId,
|
|
20
|
+
apiKeyName: this.apiKeyName
|
|
16
21
|
};
|
|
17
22
|
}
|
|
18
23
|
get username() {
|
|
@@ -21,12 +26,27 @@ class Rbac {
|
|
|
21
26
|
get userId() {
|
|
22
27
|
return this.authUser?.id.toString();
|
|
23
28
|
}
|
|
29
|
+
get session() {
|
|
30
|
+
return this.authUser?.session;
|
|
31
|
+
}
|
|
32
|
+
get apiKeyId() {
|
|
33
|
+
return this.authUser?.apiKeyId.toString();
|
|
34
|
+
}
|
|
35
|
+
get apiKeyName() {
|
|
36
|
+
return this.authUser?.apiKeyName;
|
|
37
|
+
}
|
|
24
38
|
get roleId() {
|
|
25
39
|
return this.authUser?.roleId.toString();
|
|
26
40
|
}
|
|
41
|
+
get roleName() {
|
|
42
|
+
return this.authUser?.roleName;
|
|
43
|
+
}
|
|
27
44
|
get tenantId() {
|
|
28
45
|
return this.authUser?.tenantId?.toString();
|
|
29
46
|
}
|
|
47
|
+
get tenantName() {
|
|
48
|
+
return this.authUser?.tenantName;
|
|
49
|
+
}
|
|
30
50
|
assertAuthenticated() {
|
|
31
51
|
if (!this.authUser) {
|
|
32
52
|
throw new UnauthorizedError();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const TokenPayloadSchema = z.object({
|
|
3
|
+
id: z.string(),
|
|
4
|
+
username: z.string(),
|
|
5
|
+
session: z.string(),
|
|
6
|
+
roleId: z.string(),
|
|
7
|
+
roleName: z.string().optional().nullable(),
|
|
8
|
+
tenantId: z.string().optional().nullable(),
|
|
9
|
+
tenantName: z.string().optional().nullable(),
|
|
10
|
+
apiKeyId: z.string().optional().nullable(),
|
|
11
|
+
apiKeyName: z.string().optional().nullable(),
|
|
12
|
+
});
|
|
13
|
+
export default TokenPayloadSchema;
|
|
14
|
+
export { TokenPayloadSchema };
|
|
@@ -15,19 +15,19 @@ class UserService extends AbstractService {
|
|
|
15
15
|
}
|
|
16
16
|
async auth(username, password, { userAgent, ip }) {
|
|
17
17
|
let user = null;
|
|
18
|
-
console.log("auth username", username);
|
|
19
18
|
user = await this.findByUsernameWithPassword(username);
|
|
20
19
|
if (user && user.active && AuthUtils.checkPassword(password, user.password)) {
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
const sessionUUID = await this.generateSession(user, userAgent, ip);
|
|
21
|
+
const tokenPayload = {
|
|
22
|
+
id: user._id.toString(),
|
|
23
|
+
username: user.username,
|
|
24
|
+
roleId: user.role?._id?.toString(),
|
|
25
|
+
roleName: user.role?.name,
|
|
26
|
+
tenantId: user.tenant ? user.tenant?._id?.toString() : null,
|
|
27
|
+
tenantName: user.tenant ? user.tenant?.name : null,
|
|
28
|
+
session: sessionUUID
|
|
29
|
+
};
|
|
30
|
+
const accessToken = AuthUtils.generateToken(tokenPayload);
|
|
31
31
|
return { accessToken: accessToken };
|
|
32
32
|
}
|
|
33
33
|
else {
|
|
@@ -40,11 +40,22 @@ class UserService extends AbstractService {
|
|
|
40
40
|
throw new BadCredentialsError();
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
+
async generateSession(user, userAgent, ip) {
|
|
44
|
+
const sessionUUID = randomUUID();
|
|
45
|
+
const sessionService = UserSessionServiceFactory();
|
|
46
|
+
await sessionService.create({
|
|
47
|
+
user: user._id.toString(),
|
|
48
|
+
uuid: sessionUUID,
|
|
49
|
+
userAgent: userAgent,
|
|
50
|
+
ip: ip
|
|
51
|
+
});
|
|
52
|
+
return sessionUUID;
|
|
53
|
+
}
|
|
43
54
|
async switchTenant(accessToken, tenantId) {
|
|
44
55
|
const newAccessToken = AuthUtils.switchTenant(accessToken, tenantId);
|
|
45
56
|
return { accessToken: newAccessToken };
|
|
46
57
|
}
|
|
47
|
-
async authByEmail(email, createIfNotFound = false, userData) {
|
|
58
|
+
async authByEmail(email, createIfNotFound = false, userData, { userAgent, ip }) {
|
|
48
59
|
let user = null;
|
|
49
60
|
console.log("auth email", email);
|
|
50
61
|
user = await this.findByEmail(email);
|
|
@@ -54,8 +65,17 @@ class UserService extends AbstractService {
|
|
|
54
65
|
user = await this.create(userData);
|
|
55
66
|
}
|
|
56
67
|
if (user && user.active) {
|
|
57
|
-
const
|
|
58
|
-
const
|
|
68
|
+
const sessionUUID = await this.generateSession(user, userAgent, ip);
|
|
69
|
+
const tokenPayload = {
|
|
70
|
+
id: user._id.toString(),
|
|
71
|
+
username: user.username,
|
|
72
|
+
roleId: user.role?._id?.toString(),
|
|
73
|
+
roleName: user.role?.name,
|
|
74
|
+
tenantId: user.tenant ? user.tenant?._id?.toString() : null,
|
|
75
|
+
tenantName: user.tenant ? user.tenant?.name : null,
|
|
76
|
+
session: sessionUUID
|
|
77
|
+
};
|
|
78
|
+
const accessToken = AuthUtils.generateToken(tokenPayload);
|
|
59
79
|
return { accessToken: accessToken };
|
|
60
80
|
}
|
|
61
81
|
else {
|
package/dist/utils/AuthUtils.js
CHANGED
|
@@ -3,6 +3,7 @@ import jsonwebtoken from "jsonwebtoken";
|
|
|
3
3
|
import { DraxConfig } from "@drax/common-back";
|
|
4
4
|
import IdentityConfig from "../config/IdentityConfig.js";
|
|
5
5
|
import crypto from "crypto";
|
|
6
|
+
import { TokenPayloadSchema } from "../schemas/TokenPayloadSchema.js";
|
|
6
7
|
class AuthUtils {
|
|
7
8
|
static verifyToken(token) {
|
|
8
9
|
const JWT_SECRET = DraxConfig.getOrLoad(IdentityConfig.JwtSecret);
|
|
@@ -12,7 +13,9 @@ class AuthUtils {
|
|
|
12
13
|
const options = {
|
|
13
14
|
algorithms: ['HS256'],
|
|
14
15
|
};
|
|
15
|
-
|
|
16
|
+
const tokenPayload = jsonwebtoken.verify(token, JWT_SECRET, options);
|
|
17
|
+
TokenPayloadSchema.parse(tokenPayload);
|
|
18
|
+
return tokenPayload;
|
|
16
19
|
}
|
|
17
20
|
static hashPassword(password) {
|
|
18
21
|
if (!password) {
|
|
@@ -25,17 +28,8 @@ class AuthUtils {
|
|
|
25
28
|
static checkPassword(password, hashPassword) {
|
|
26
29
|
return bcryptjs.compareSync(password, hashPassword);
|
|
27
30
|
}
|
|
28
|
-
static
|
|
29
|
-
|
|
30
|
-
id: userId,
|
|
31
|
-
username: username,
|
|
32
|
-
roleId: roleId,
|
|
33
|
-
tenantId: tenantId,
|
|
34
|
-
session: session
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
static generateToken(userId, username, roleId, tenantId, session) {
|
|
38
|
-
const payload = AuthUtils.tokenSignPayload(userId, username, roleId, tenantId, session);
|
|
31
|
+
static generateToken(payload) {
|
|
32
|
+
TokenPayloadSchema.parse(payload);
|
|
39
33
|
const JWT_SECRET = DraxConfig.getOrLoad(IdentityConfig.JwtSecret);
|
|
40
34
|
if (!JWT_SECRET) {
|
|
41
35
|
throw new Error("JWT_SECRET ENV must be provided");
|
|
@@ -44,9 +38,9 @@ class AuthUtils {
|
|
|
44
38
|
const JWT_ISSUER = DraxConfig.getOrLoad(IdentityConfig.JwtIssuer) || 'DRAX';
|
|
45
39
|
const options = {
|
|
46
40
|
expiresIn: JWT_EXPIRATION,
|
|
47
|
-
jwtid:
|
|
41
|
+
jwtid: payload.id,
|
|
48
42
|
algorithm: 'HS256',
|
|
49
|
-
audience: username,
|
|
43
|
+
audience: payload.username,
|
|
50
44
|
issuer: JWT_ISSUER
|
|
51
45
|
};
|
|
52
46
|
let token = jsonwebtoken.sign(payload, JWT_SECRET, options);
|
|
@@ -62,31 +56,23 @@ class AuthUtils {
|
|
|
62
56
|
}
|
|
63
57
|
static switchTenant(accessToken, newTenantId) {
|
|
64
58
|
// Verificar que el token actual sea válido
|
|
65
|
-
const
|
|
66
|
-
if (!
|
|
59
|
+
const tokenPayload = AuthUtils.verifyToken(accessToken);
|
|
60
|
+
if (!tokenPayload) {
|
|
67
61
|
throw new Error("Invalid access token");
|
|
68
62
|
}
|
|
69
|
-
|
|
70
|
-
const newPayload = {
|
|
71
|
-
id: decodedToken.id,
|
|
72
|
-
username: decodedToken.username,
|
|
73
|
-
roleId: decodedToken.roleId,
|
|
74
|
-
tenantId: newTenantId,
|
|
75
|
-
session: decodedToken.session,
|
|
76
|
-
exp: decodedToken.exp
|
|
77
|
-
};
|
|
63
|
+
tokenPayload.tenantId = newTenantId;
|
|
78
64
|
const JWT_SECRET = DraxConfig.getOrLoad(IdentityConfig.JwtSecret);
|
|
79
65
|
if (!JWT_SECRET) {
|
|
80
66
|
throw new Error("JWT_SECRET ENV must be provided");
|
|
81
67
|
}
|
|
82
68
|
const JWT_ISSUER = DraxConfig.getOrLoad(IdentityConfig.JwtIssuer) || 'DRAX';
|
|
83
69
|
const options = {
|
|
84
|
-
jwtid:
|
|
70
|
+
jwtid: tokenPayload.id,
|
|
85
71
|
algorithm: 'HS256',
|
|
86
|
-
audience:
|
|
72
|
+
audience: tokenPayload.username,
|
|
87
73
|
issuer: JWT_ISSUER
|
|
88
74
|
};
|
|
89
|
-
return jsonwebtoken.sign(
|
|
75
|
+
return jsonwebtoken.sign(tokenPayload, JWT_SECRET, options);
|
|
90
76
|
}
|
|
91
77
|
}
|
|
92
78
|
export default AuthUtils;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.38.0",
|
|
7
7
|
"description": "Identity module for user management, authentication and authorization.",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"types": "types/index.d.ts",
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
"author": "Cristian Incarnato & Drax Team",
|
|
29
29
|
"license": "ISC",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@drax/common-back": "^0.
|
|
32
|
-
"@drax/crud-back": "^0.
|
|
33
|
-
"@drax/crud-share": "^0.
|
|
34
|
-
"@drax/email-back": "^0.
|
|
35
|
-
"@drax/identity-share": "^0.
|
|
31
|
+
"@drax/common-back": "^0.38.0",
|
|
32
|
+
"@drax/crud-back": "^0.38.0",
|
|
33
|
+
"@drax/crud-share": "^0.38.0",
|
|
34
|
+
"@drax/email-back": "^0.38.0",
|
|
35
|
+
"@drax/identity-share": "^0.38.0",
|
|
36
36
|
"bcryptjs": "^2.4.3",
|
|
37
37
|
"graphql": "^16.8.2",
|
|
38
38
|
"jsonwebtoken": "^9.0.2"
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"debug": "0"
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "43c90f3c12165e7527edefbc80dd327a59236dd5"
|
|
67
67
|
}
|
package/src/index.ts
CHANGED
|
@@ -44,6 +44,13 @@ import type {IUserApiKeyRepository} from "./interfaces/IUserApiKeyRepository";
|
|
|
44
44
|
import type {IUserLoginFailRepository} from "./interfaces/IUserLoginFailRepository";
|
|
45
45
|
import type {IUserSessionRepository} from "./interfaces/IUserSessionRepository";
|
|
46
46
|
|
|
47
|
+
import {RoleModel, RoleMongoSchema} from "./models/RoleModel.js";
|
|
48
|
+
import {TenantModel, TenantMongoSchema} from "./models/TenantModel.js";
|
|
49
|
+
import {UserModel, UserMongoSchema} from "./models/UserModel.js";
|
|
50
|
+
import {UserApiKeyModel, UserApiKeyMongoSchema} from "./models/UserApiKeyModel.js";
|
|
51
|
+
import {UserSessionModel,UserSessionMongoSchema} from "./models/UserSessionModel.js";
|
|
52
|
+
import {UserLoginFailModel,UserLoginFailMongoSchema} from "./models/UserLoginFailModel.js";
|
|
53
|
+
|
|
47
54
|
|
|
48
55
|
import RoleMongoRepository from "./repository/mongo/RoleMongoRepository.js";
|
|
49
56
|
import TenantMongoRepository from "./repository/mongo/TenantMongoRepository.js";
|
|
@@ -101,9 +108,7 @@ export {
|
|
|
101
108
|
UserApiKeyBaseSchema,
|
|
102
109
|
UserApiKeySchema,
|
|
103
110
|
UserLoginFailBaseSchema,
|
|
104
|
-
UserLoginFailSchema,
|
|
105
111
|
UserSessionBaseSchema,
|
|
106
|
-
UserSessionSchema,
|
|
107
112
|
|
|
108
113
|
//Service
|
|
109
114
|
UserService,
|
|
@@ -158,6 +163,21 @@ export {
|
|
|
158
163
|
UserSessionMongoRepository,
|
|
159
164
|
UserLoginFailMongoRepository,
|
|
160
165
|
|
|
166
|
+
//Mongo Models
|
|
167
|
+
RoleModel,
|
|
168
|
+
TenantModel,
|
|
169
|
+
UserModel,
|
|
170
|
+
UserApiKeyModel,
|
|
171
|
+
UserSessionModel,
|
|
172
|
+
UserLoginFailModel,
|
|
173
|
+
|
|
174
|
+
RoleMongoSchema,
|
|
175
|
+
TenantMongoSchema,
|
|
176
|
+
UserMongoSchema,
|
|
177
|
+
UserApiKeyMongoSchema,
|
|
178
|
+
UserSessionMongoSchema,
|
|
179
|
+
UserLoginFailMongoSchema,
|
|
180
|
+
|
|
161
181
|
//Sqlite Repositories
|
|
162
182
|
RoleSqliteRepository,
|
|
163
183
|
TenantSqliteRepository,
|
|
@@ -29,19 +29,23 @@ async function apiKeyMiddleware (request, reply) {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
//Por authorization '<uuid-key>'
|
|
32
|
-
const uuidRegex =
|
|
32
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
33
33
|
if(request.headers['authorization'] && uuidRegex.test(request.headers['authorization'])){
|
|
34
34
|
apiKey = request.headers['authorization']
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
if(apiKey){
|
|
38
|
-
const userApiKey = await draxCache.getOrLoad(apiKey, userApiKeyLoader)
|
|
38
|
+
const userApiKey : IUserApiKey = await draxCache.getOrLoad(apiKey, userApiKeyLoader)
|
|
39
39
|
if(userApiKey && userApiKey.user){
|
|
40
40
|
const authUser: IAuthUser = {
|
|
41
41
|
id: userApiKey.user._id.toString(),
|
|
42
42
|
username: userApiKey.user.username,
|
|
43
43
|
roleId: userApiKey.user.role?._id?.toString(),
|
|
44
|
+
roleName: userApiKey.user.role?.name,
|
|
44
45
|
tenantId: userApiKey.user?.tenant?._id?.toString(),
|
|
46
|
+
tenantName: userApiKey.user?.tenant?.name,
|
|
47
|
+
apiKeyId: userApiKey?._id?.toString(),
|
|
48
|
+
apiKeyName: userApiKey?.name
|
|
45
49
|
}
|
|
46
50
|
request.authUser = authUser
|
|
47
51
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import AuthUtils from "../utils/AuthUtils.js";
|
|
2
|
-
import {
|
|
2
|
+
import {IAuthUser} from "@drax/identity-share";
|
|
3
3
|
|
|
4
4
|
function jwtMiddleware (request, reply, done) {
|
|
5
5
|
try{
|
|
@@ -14,7 +14,7 @@ function jwtMiddleware (request, reply, done) {
|
|
|
14
14
|
const routerPath = request.url
|
|
15
15
|
|
|
16
16
|
if(routerPath != '/api/auth/login' && token){
|
|
17
|
-
const authUser = AuthUtils.verifyToken(token)
|
|
17
|
+
const authUser: IAuthUser = AuthUtils.verifyToken(token)
|
|
18
18
|
if(authUser){
|
|
19
19
|
request.authUser = authUser
|
|
20
20
|
request.token = token
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {IAuthUser, IRbac, IRole} from "@drax/identity-share";
|
|
2
2
|
import {DraxCache, DraxConfig} from "@drax/common-back";
|
|
3
3
|
import RoleServiceFactory from "../factory/RoleServiceFactory.js";
|
|
4
4
|
import Rbac from "../rbac/Rbac.js";
|
|
@@ -16,14 +16,14 @@ async function roleLoader(k):Promise<IRole | null> {
|
|
|
16
16
|
|
|
17
17
|
async function rbacMiddleware (request, reply) {
|
|
18
18
|
try{
|
|
19
|
-
if(request.authUser as
|
|
20
|
-
const authUser = request.authUser
|
|
19
|
+
if(request.authUser as IAuthUser){
|
|
20
|
+
const authUser: IAuthUser = request.authUser
|
|
21
21
|
const cacheKey = authUser.roleId
|
|
22
|
-
const role = await draxCache.getOrLoad(cacheKey, roleLoader)
|
|
23
|
-
const rbac = new Rbac(authUser,role)
|
|
22
|
+
const role : IRole = await draxCache.getOrLoad(cacheKey, roleLoader)
|
|
23
|
+
const rbac: IRbac = new Rbac(authUser,role)
|
|
24
24
|
request.rbac = rbac
|
|
25
25
|
}else{
|
|
26
|
-
const rbac = new Rbac(null,null)
|
|
26
|
+
const rbac: IRbac = new Rbac(null,null)
|
|
27
27
|
request.rbac = rbac
|
|
28
28
|
}
|
|
29
29
|
return
|
|
@@ -4,30 +4,30 @@ import uniqueValidator from 'mongoose-unique-validator';
|
|
|
4
4
|
import mongoosePaginate from 'mongoose-paginate-v2'
|
|
5
5
|
import type {IUserLoginFail} from '@drax/identity-share'
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const UserLoginFailMongoSchema = new mongoose.Schema<IUserLoginFail>({
|
|
8
8
|
username: {type: String, required: false, index: false, unique: false },
|
|
9
9
|
userAgent: {type: String, required: false, index: false, unique: false },
|
|
10
10
|
ip: {type: String, required: false, index: false, unique: false },
|
|
11
11
|
}, {timestamps: true});
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
UserLoginFailMongoSchema.plugin(uniqueValidator, {message: 'validation.unique'});
|
|
14
|
+
UserLoginFailMongoSchema.plugin(mongoosePaginate);
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
UserLoginFailMongoSchema.virtual("id").get(function () {
|
|
17
17
|
return this._id.toString();
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
UserLoginFailMongoSchema.set('toJSON', {getters: true, virtuals: true});
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
UserLoginFailMongoSchema.set('toObject', {getters: true, virtuals: true});
|
|
24
24
|
|
|
25
25
|
const MODEL_NAME = 'UserLoginFail';
|
|
26
26
|
const COLLECTION_NAME = 'UserLoginFail';
|
|
27
|
-
const UserLoginFailModel = mongoose.model<IUserLoginFail, PaginateModel<IUserLoginFail>>(MODEL_NAME,
|
|
27
|
+
const UserLoginFailModel = mongoose.model<IUserLoginFail, PaginateModel<IUserLoginFail>>(MODEL_NAME, UserLoginFailMongoSchema,COLLECTION_NAME);
|
|
28
28
|
|
|
29
29
|
export {
|
|
30
|
-
|
|
30
|
+
UserLoginFailMongoSchema,
|
|
31
31
|
UserLoginFailModel
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -5,31 +5,31 @@ import uniqueValidator from 'mongoose-unique-validator';
|
|
|
5
5
|
import mongoosePaginate from 'mongoose-paginate-v2'
|
|
6
6
|
import type {IUserSession} from '@drax/identity-share'
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const UserSessionMongoSchema = new mongoose.Schema<IUserSession>({
|
|
9
9
|
uuid: {type: String, required: true, index: true, unique: false },
|
|
10
10
|
user: {type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true, index: true, unique: false },
|
|
11
11
|
userAgent: {type: String, required: false, index: false, unique: false },
|
|
12
12
|
ip: {type: String, required: false, index: false, unique: false },
|
|
13
13
|
}, {timestamps: true});
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
UserSessionMongoSchema.plugin(uniqueValidator, {message: 'validation.unique'});
|
|
16
|
+
UserSessionMongoSchema.plugin(mongoosePaginate);
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
UserSessionMongoSchema.virtual("id").get(function () {
|
|
19
19
|
return this._id.toString();
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
UserSessionMongoSchema.set('toJSON', {getters: true, virtuals: true});
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
UserSessionMongoSchema.set('toObject', {getters: true, virtuals: true});
|
|
26
26
|
|
|
27
27
|
const MODEL_NAME = 'UserSession';
|
|
28
28
|
const COLLECTION_NAME = 'UserSession';
|
|
29
|
-
const UserSessionModel = mongoose.model<IUserSession, PaginateModel<IUserSession>>(MODEL_NAME,
|
|
29
|
+
const UserSessionModel = mongoose.model<IUserSession, PaginateModel<IUserSession>>(MODEL_NAME, UserSessionMongoSchema,COLLECTION_NAME);
|
|
30
30
|
|
|
31
31
|
export {
|
|
32
|
-
|
|
32
|
+
UserSessionMongoSchema,
|
|
33
33
|
UserSessionModel
|
|
34
34
|
}
|
|
35
35
|
|
package/src/rbac/Rbac.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { IAuthUser, IRole, IRbac} from "@drax/identity-share";
|
|
2
2
|
import {UnauthorizedError, ForbiddenError} from "@drax/common-back";
|
|
3
|
-
import {IAuthUser} from "@drax/identity-share/dist";
|
|
4
3
|
|
|
5
4
|
class Rbac implements IRbac{
|
|
6
5
|
private role: IRole;
|
|
7
6
|
private authUser: IAuthUser;
|
|
8
7
|
|
|
9
|
-
constructor(authUser:
|
|
8
|
+
constructor(authUser: IAuthUser, role: IRole) {
|
|
10
9
|
this.authUser = authUser;
|
|
11
10
|
this.role = role;
|
|
12
11
|
}
|
|
@@ -19,8 +18,13 @@ class Rbac implements IRbac{
|
|
|
19
18
|
return {
|
|
20
19
|
id: this.userId,
|
|
21
20
|
username: this.username,
|
|
21
|
+
session: this.session,
|
|
22
22
|
roleId: this.roleId,
|
|
23
|
-
|
|
23
|
+
roleName: this.roleName,
|
|
24
|
+
tenantId: this.tenantId,
|
|
25
|
+
tenantName: this.tenantName,
|
|
26
|
+
apiKeyId: this.apiKeyId,
|
|
27
|
+
apiKeyName: this.apiKeyName
|
|
24
28
|
}
|
|
25
29
|
}
|
|
26
30
|
|
|
@@ -32,14 +36,34 @@ class Rbac implements IRbac{
|
|
|
32
36
|
return this.authUser?.id.toString()
|
|
33
37
|
}
|
|
34
38
|
|
|
39
|
+
get session(): string {
|
|
40
|
+
return this.authUser?.session
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get apiKeyId(): string {
|
|
44
|
+
return this.authUser?.apiKeyId.toString()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get apiKeyName(): string {
|
|
48
|
+
return this.authUser?.apiKeyName
|
|
49
|
+
}
|
|
50
|
+
|
|
35
51
|
get roleId(): string {
|
|
36
52
|
return this.authUser?.roleId.toString()
|
|
37
53
|
}
|
|
38
54
|
|
|
55
|
+
get roleName(): string {
|
|
56
|
+
return this.authUser?.roleName
|
|
57
|
+
}
|
|
58
|
+
|
|
39
59
|
get tenantId(): string | undefined {
|
|
40
60
|
return this.authUser?.tenantId?.toString();
|
|
41
61
|
}
|
|
42
62
|
|
|
63
|
+
get tenantName(): string | undefined {
|
|
64
|
+
return this.authUser?.tenantName;
|
|
65
|
+
}
|
|
66
|
+
|
|
43
67
|
assertAuthenticated() {
|
|
44
68
|
if (!this.authUser) {
|
|
45
69
|
throw new UnauthorizedError()
|