@drax/identity-back 0.0.9 → 0.0.10

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.
Files changed (188) hide show
  1. package/dist/errors/BadCredentialsError.js +10 -0
  2. package/dist/errors/UnauthorizedError.js +10 -0
  3. package/dist/factory/RoleServiceFactory.js +16 -3
  4. package/dist/factory/UserServiceFactory.js +17 -3
  5. package/dist/graphql/resolvers/role.resolvers.js +98 -11
  6. package/dist/graphql/resolvers/user.resolvers.js +134 -15
  7. package/dist/graphql/types/role.graphql +6 -4
  8. package/dist/graphql/types/user.graphql +36 -9
  9. package/dist/i18n/messages/validation-i18n.js +21 -0
  10. package/dist/index.js +22 -7
  11. package/dist/interfaces/IID.js +1 -0
  12. package/dist/interfaces/IJwtUser.js +1 -0
  13. package/dist/middleware/jwtMiddleware.js +19 -0
  14. package/dist/middleware/rbacMiddleware.js +36 -0
  15. package/dist/models/RoleModel.js +0 -8
  16. package/dist/models/UserModel.js +1 -2
  17. package/dist/permissions/IdentityPermissions.js +16 -0
  18. package/dist/rbac/Rbac.js +20 -0
  19. package/dist/repository/mongo/RoleMongoRepository.js +41 -0
  20. package/dist/repository/mongo/UserMongoRepository.js +82 -0
  21. package/dist/repository/sqlite/RoleSqliteRepository.js +115 -0
  22. package/dist/repository/sqlite/UserSqliteRepository.js +157 -0
  23. package/dist/routes/RoleRoutes.js +145 -0
  24. package/dist/routes/UserRoutes.js +199 -0
  25. package/dist/routes/authRoutes.js +12 -4
  26. package/dist/services/AuthService.js +0 -15
  27. package/dist/services/PermissionService.js +19 -0
  28. package/dist/services/RoleService.js +48 -16
  29. package/dist/services/UserService.js +82 -23
  30. package/dist/utils/AuthUtils.js +20 -6
  31. package/dist/utils/DbSetupUtils.js +28 -0
  32. package/dist/zod/RoleZod.js +8 -0
  33. package/dist/zod/UserZod.js +18 -0
  34. package/package.json +17 -10
  35. package/src/errors/BadCredentialsError.ts +13 -0
  36. package/src/errors/UnauthorizedError.ts +13 -0
  37. package/src/factory/RoleServiceFactory.ts +20 -3
  38. package/src/factory/UserServiceFactory.ts +20 -3
  39. package/src/graphql/resolvers/role.resolvers.ts +92 -11
  40. package/src/graphql/resolvers/user.resolvers.ts +128 -15
  41. package/src/graphql/types/role.graphql +6 -4
  42. package/src/graphql/types/user.graphql +36 -9
  43. package/src/index.ts +50 -10
  44. package/src/interfaces/IID.ts +5 -0
  45. package/src/interfaces/IJwtUser.ts +7 -0
  46. package/src/interfaces/IRole.ts +15 -5
  47. package/src/interfaces/IRoleRepository.ts +8 -5
  48. package/src/interfaces/IUser.ts +30 -6
  49. package/src/interfaces/IUserGroup.ts +2 -1
  50. package/src/interfaces/IUserRepository.ts +11 -6
  51. package/src/middleware/jwtMiddleware.ts +22 -0
  52. package/src/middleware/rbacMiddleware.ts +40 -0
  53. package/src/models/RoleModel.ts +0 -9
  54. package/src/models/UserModel.ts +1 -2
  55. package/src/permissions/IdentityPermissions.ts +20 -0
  56. package/src/rbac/Rbac.ts +31 -0
  57. package/src/repository/mongo/RoleMongoRepository.ts +57 -0
  58. package/src/repository/mongo/UserMongoRepository.ts +104 -0
  59. package/src/repository/sqlite/RoleSqliteRepository.ts +151 -0
  60. package/src/repository/sqlite/UserSqliteRepository.ts +194 -0
  61. package/src/routes/RoleRoutes.ts +141 -0
  62. package/src/routes/UserRoutes.ts +198 -0
  63. package/src/services/PermissionService.ts +26 -0
  64. package/src/services/RoleService.ts +46 -21
  65. package/src/services/UserService.ts +86 -28
  66. package/src/utils/AuthUtils.ts +22 -7
  67. package/src/utils/DbSetupUtils.ts +39 -0
  68. package/src/zod/RoleZod.ts +14 -0
  69. package/src/zod/UserZod.ts +26 -0
  70. package/test/data-json/roles/admin-role.json +1 -1
  71. package/test/data-obj/roles/{admin-role.ts → admin-mongo-role.ts} +2 -1
  72. package/test/data-obj/roles/admin-sqlite-role.ts +9 -0
  73. package/test/data-obj/roles/operator-sqlite-role.ts +9 -0
  74. package/test/data-obj/users/root-mongo-user.ts +15 -0
  75. package/test/data-obj/users/root-sqlite-user.ts +16 -0
  76. package/test/{initializers → db}/MongoInMemory.ts +2 -1
  77. package/test/initializers/RoleMongoInitializer.ts +15 -0
  78. package/test/initializers/RoleSqliteInitializer.ts +18 -0
  79. package/test/repository/{role-repository.test.ts → mongo/role-mongo-repository.test.ts} +14 -24
  80. package/test/repository/mongo/user-mongo-repository.test.ts +121 -0
  81. package/test/repository/sqlite/role-sqlite-repository.test.ts +70 -0
  82. package/test/repository/sqlite/user-sqlite-repository.test.ts +126 -0
  83. package/test/service/mock-service.test.ts +3 -3
  84. package/test/service/role-service.test.ts +5 -5
  85. package/test/service/user-service.test.ts +42 -15
  86. package/test.db +0 -0
  87. package/tsconfig.json +16 -3
  88. package/tsconfig.tsbuildinfo +1 -1
  89. package/types/errors/BadCredentialsError.d.ts +6 -0
  90. package/types/errors/BadCredentialsError.d.ts.map +1 -0
  91. package/types/errors/UnauthorizedError.d.ts +6 -0
  92. package/types/errors/UnauthorizedError.d.ts.map +1 -0
  93. package/types/factory/RoleServiceFactory.d.ts +2 -2
  94. package/types/factory/RoleServiceFactory.d.ts.map +1 -1
  95. package/types/factory/UserServiceFactory.d.ts +2 -2
  96. package/types/factory/UserServiceFactory.d.ts.map +1 -1
  97. package/types/graphql/resolvers/role.resolvers.d.ts +24 -7
  98. package/types/graphql/resolvers/role.resolvers.d.ts.map +1 -1
  99. package/types/graphql/resolvers/user.resolvers.d.ts +38 -7
  100. package/types/graphql/resolvers/user.resolvers.d.ts.map +1 -1
  101. package/types/i18n/messages/validation-i18n.d.ts +4 -0
  102. package/types/i18n/messages/validation-i18n.d.ts.map +1 -0
  103. package/types/index.d.ts +21 -5
  104. package/types/index.d.ts.map +1 -1
  105. package/types/interfaces/IID.d.ts +6 -0
  106. package/types/interfaces/IID.d.ts.map +1 -0
  107. package/types/interfaces/IJwtUser.d.ts +7 -0
  108. package/types/interfaces/IJwtUser.d.ts.map +1 -0
  109. package/types/interfaces/IRole.d.ts +13 -6
  110. package/types/interfaces/IRole.d.ts.map +1 -1
  111. package/types/interfaces/IRoleRepository.d.ts +8 -4
  112. package/types/interfaces/IRoleRepository.d.ts.map +1 -1
  113. package/types/interfaces/IUser.d.ts +29 -8
  114. package/types/interfaces/IUser.d.ts.map +1 -1
  115. package/types/interfaces/IUserGroup.d.ts +3 -2
  116. package/types/interfaces/IUserGroup.d.ts.map +1 -1
  117. package/types/interfaces/IUserRepository.d.ts +10 -6
  118. package/types/interfaces/IUserRepository.d.ts.map +1 -1
  119. package/types/middleware/jwtMiddleware.d.ts +4 -0
  120. package/types/middleware/jwtMiddleware.d.ts.map +1 -0
  121. package/types/middleware/rbacMiddleware.d.ts +4 -0
  122. package/types/middleware/rbacMiddleware.d.ts.map +1 -0
  123. package/types/models/RoleModel.d.ts +8 -8
  124. package/types/models/RoleModel.d.ts.map +1 -1
  125. package/types/models/UserGroupModel.d.ts +8 -8
  126. package/types/models/UserGroupModel.d.ts.map +1 -1
  127. package/types/models/UserModel.d.ts +8 -8
  128. package/types/models/UserModel.d.ts.map +1 -1
  129. package/types/permissions/IdentityPermissions.d.ts +16 -0
  130. package/types/permissions/IdentityPermissions.d.ts.map +1 -0
  131. package/types/rbac/Rbac.d.ts +12 -0
  132. package/types/rbac/Rbac.d.ts.map +1 -0
  133. package/types/repository/mongo/RoleMongoRepository.d.ts +14 -0
  134. package/types/repository/mongo/RoleMongoRepository.d.ts.map +1 -0
  135. package/types/repository/mongo/UserMongoRepository.d.ts +18 -0
  136. package/types/repository/mongo/UserMongoRepository.d.ts.map +1 -0
  137. package/types/repository/sqlite/RoleSqliteRepository.d.ts +19 -0
  138. package/types/repository/sqlite/RoleSqliteRepository.d.ts.map +1 -0
  139. package/types/repository/sqlite/UserSqliteRepository.d.ts +24 -0
  140. package/types/repository/sqlite/UserSqliteRepository.d.ts.map +1 -0
  141. package/types/routes/RoleRoutes.d.ts +4 -0
  142. package/types/routes/RoleRoutes.d.ts.map +1 -0
  143. package/types/routes/UserRoutes.d.ts +4 -0
  144. package/types/routes/UserRoutes.d.ts.map +1 -0
  145. package/types/routes/authRoutes.d.ts.map +1 -1
  146. package/types/services/AuthService.d.ts +0 -3
  147. package/types/services/AuthService.d.ts.map +1 -1
  148. package/types/services/PermissionService.d.ts +9 -0
  149. package/types/services/PermissionService.d.ts.map +1 -0
  150. package/types/services/RoleService.d.ts +6 -8
  151. package/types/services/RoleService.d.ts.map +1 -1
  152. package/types/services/UserService.d.ts +13 -11
  153. package/types/services/UserService.d.ts.map +1 -1
  154. package/types/utils/AuthUtils.d.ts +5 -2
  155. package/types/utils/AuthUtils.d.ts.map +1 -1
  156. package/types/utils/DbSetupUtils.d.ts +10 -0
  157. package/types/utils/DbSetupUtils.d.ts.map +1 -0
  158. package/types/zod/RoleZod.d.ts +10 -0
  159. package/types/zod/RoleZod.d.ts.map +1 -0
  160. package/types/zod/UserZod.d.ts +53 -0
  161. package/types/zod/UserZod.d.ts.map +1 -0
  162. package/dist/factory/AuthServiceFactory.js +0 -8
  163. package/dist/graphql/resolvers/auth.resolvers.js +0 -16
  164. package/dist/graphql/types/auth.graphql +0 -12
  165. package/dist/repository/RoleRepository.js +0 -29
  166. package/dist/repository/UserRepository.js +0 -33
  167. package/src/factory/AuthServiceFactory.ts +0 -10
  168. package/src/graphql/resolvers/auth.resolvers.ts +0 -20
  169. package/src/graphql/types/auth.graphql +0 -12
  170. package/src/repository/RoleRepository.ts +0 -42
  171. package/src/repository/UserRepository.ts +0 -47
  172. package/src/routes/authRoutes.ts +0 -22
  173. package/src/services/AuthService.ts +0 -29
  174. package/test/data-obj/users/root-user.ts +0 -15
  175. package/test/initializers/MongoInMemory.mjs +0 -34
  176. package/test/initializers/RoleInitializer.mjs +0 -11
  177. package/test/initializers/RoleInitializer.ts +0 -15
  178. package/test/repository/user-repository.test.ts +0 -54
  179. package/types/factory/AuthServiceFactory.d.ts +0 -4
  180. package/types/factory/AuthServiceFactory.d.ts.map +0 -1
  181. package/types/graphql/resolvers/auth.resolvers.d.ts +0 -12
  182. package/types/graphql/resolvers/auth.resolvers.d.ts.map +0 -1
  183. package/types/repository/RoleRepository.d.ts +0 -41
  184. package/types/repository/RoleRepository.d.ts.map +0 -1
  185. package/types/repository/UserRepository.d.ts +0 -40
  186. package/types/repository/UserRepository.d.ts.map +0 -1
  187. package/types/routes/AuthRoutes.d.ts +0 -3
  188. package/types/routes/AuthRoutes.d.ts.map +0 -1
@@ -0,0 +1,199 @@
1
+ import UserServiceFactory from "../factory/UserServiceFactory.js";
2
+ import { ValidationError } from "@drax/common-back";
3
+ import { IdentityPermissions } from "../permissions/IdentityPermissions.js";
4
+ import UnauthorizedError from "../errors/UnauthorizedError.js";
5
+ import BadCredentialsError from "../errors/BadCredentialsError.js";
6
+ const userService = UserServiceFactory;
7
+ async function UserRoutes(fastify, options) {
8
+ fastify.post('/api/auth', async (request, reply) => {
9
+ try {
10
+ const username = request.body.username;
11
+ const password = request.body.password;
12
+ return await userService.auth(username, password);
13
+ }
14
+ catch (e) {
15
+ console.error('/api/auth error', e);
16
+ if (e instanceof BadCredentialsError) {
17
+ reply.code(401);
18
+ reply.send({ error: e.message });
19
+ }
20
+ reply.code(500);
21
+ reply.send({ error: 'error.server' });
22
+ }
23
+ });
24
+ fastify.get('/api/me', async (request, reply) => {
25
+ try {
26
+ if (request.authUser) {
27
+ let user = await userService.findById(request.authUser.id);
28
+ delete user.password;
29
+ return user;
30
+ }
31
+ else {
32
+ throw new UnauthorizedError();
33
+ }
34
+ }
35
+ catch (e) {
36
+ if (e instanceof UnauthorizedError) {
37
+ reply.code(401);
38
+ reply.send({ error: "Unauthorized" });
39
+ }
40
+ else if (e instanceof UnauthorizedError) {
41
+ reply.statusCode = e.statusCode;
42
+ reply.send({ error: e.message });
43
+ }
44
+ else {
45
+ reply.statusCode = 500;
46
+ reply.send({ error: 'error.server' });
47
+ }
48
+ }
49
+ });
50
+ fastify.get('/api/users', async (request, reply) => {
51
+ try {
52
+ request.rbac.assertPermission(IdentityPermissions.ViewUser);
53
+ const page = request.query.page;
54
+ const limit = request.query.limit;
55
+ const search = request.query.search;
56
+ let paginateResult = await userService.paginate(page, limit, search);
57
+ return paginateResult;
58
+ }
59
+ catch (e) {
60
+ if (e instanceof ValidationError) {
61
+ reply.statusCode = e.statusCode;
62
+ reply.send({ error: e.message, inputErrors: e.errors });
63
+ }
64
+ else if (e instanceof UnauthorizedError) {
65
+ reply.statusCode = e.statusCode;
66
+ reply.send({ error: e.message });
67
+ }
68
+ else {
69
+ reply.statusCode = 500;
70
+ reply.send({ error: 'error.server' });
71
+ }
72
+ }
73
+ });
74
+ fastify.post('/api/users', async (request, reply) => {
75
+ try {
76
+ request.rbac.assertPermission(IdentityPermissions.CreateUser);
77
+ const payload = request.body;
78
+ let user = await userService.create(payload);
79
+ return user;
80
+ }
81
+ catch (e) {
82
+ if (e instanceof ValidationError) {
83
+ reply.statusCode = e.statusCode;
84
+ reply.send({ error: e.message, inputErrors: e.errors });
85
+ }
86
+ else if (e instanceof UnauthorizedError) {
87
+ reply.statusCode = e.statusCode;
88
+ reply.send({ error: e.message });
89
+ }
90
+ else {
91
+ reply.statusCode = 500;
92
+ reply.send({ error: 'error.server' });
93
+ }
94
+ }
95
+ });
96
+ fastify.put('/api/users/:id', async (request, reply) => {
97
+ try {
98
+ request.rbac.assertPermission(IdentityPermissions.UpdateUser);
99
+ const id = request.params.id;
100
+ const payload = request.body;
101
+ let user = await userService.update(id, payload);
102
+ return user;
103
+ }
104
+ catch (e) {
105
+ if (e instanceof ValidationError) {
106
+ reply.statusCode = e.statusCode;
107
+ reply.send({ error: e.message, inputErrors: e.errors });
108
+ }
109
+ if (e instanceof UnauthorizedError) {
110
+ reply.statusCode = e.statusCode;
111
+ reply.send({ error: e.message });
112
+ }
113
+ else if (e instanceof UnauthorizedError) {
114
+ reply.statusCode = e.statusCode;
115
+ reply.send({ error: e.message });
116
+ }
117
+ else {
118
+ reply.statusCode = 500;
119
+ reply.send({ error: 'error.server' });
120
+ }
121
+ }
122
+ });
123
+ fastify.delete('/api/users/:id', async (request, reply) => {
124
+ try {
125
+ request.rbac.assertPermission(IdentityPermissions.DeleteUser);
126
+ const id = request.params.id;
127
+ let r = await userService.delete(id);
128
+ return r;
129
+ }
130
+ catch (e) {
131
+ if (e instanceof ValidationError) {
132
+ reply.statusCode = e.statusCode;
133
+ reply.send({ error: e.message, inputErrors: e.errors });
134
+ }
135
+ else if (e instanceof UnauthorizedError) {
136
+ reply.statusCode = e.statusCode;
137
+ reply.send({ error: e.message });
138
+ }
139
+ else {
140
+ reply.statusCode = 500;
141
+ reply.send({ error: 'error.server' });
142
+ }
143
+ }
144
+ });
145
+ fastify.post('/api/password', async (request, reply) => {
146
+ try {
147
+ if (!request.authUser) {
148
+ throw new UnauthorizedError();
149
+ }
150
+ const userId = request.authUser.id;
151
+ const currentPassword = request.body.currentPassword;
152
+ const newPassword = request.body.newPassword;
153
+ return await userService.changeOwnPassword(userId, currentPassword, newPassword);
154
+ }
155
+ catch (e) {
156
+ console.error('/api/password error', e);
157
+ if (e instanceof ValidationError) {
158
+ reply.statusCode = e.statusCode;
159
+ reply.send({ error: e.message, inputErrors: e.errors });
160
+ }
161
+ else if (e instanceof UnauthorizedError) {
162
+ reply.statusCode = e.statusCode;
163
+ reply.send({ error: e.message });
164
+ }
165
+ else {
166
+ reply.statusCode = 500;
167
+ reply.send({ error: 'error.server' });
168
+ }
169
+ }
170
+ });
171
+ fastify.post('/api/password/:id', async (request, reply) => {
172
+ try {
173
+ request.rbac.assertPermission(IdentityPermissions.UpdateUser);
174
+ const userId = request.params.id;
175
+ if (!userId) {
176
+ throw new UnauthorizedError();
177
+ }
178
+ const newPassword = request.body.newPassword;
179
+ return await userService.changeUserPassword(userId, newPassword);
180
+ }
181
+ catch (e) {
182
+ console.error('/api/password error', e);
183
+ if (e instanceof ValidationError) {
184
+ reply.statusCode = e.statusCode;
185
+ reply.send({ error: e.message, inputErrors: e.errors });
186
+ }
187
+ else if (e instanceof UnauthorizedError) {
188
+ reply.statusCode = e.statusCode;
189
+ reply.send({ error: e.message });
190
+ }
191
+ else {
192
+ reply.statusCode = 500;
193
+ reply.send({ error: 'error.server' });
194
+ }
195
+ }
196
+ });
197
+ }
198
+ export default UserRoutes;
199
+ export { UserRoutes };
@@ -1,21 +1,29 @@
1
- import AuthServiceFactory from "../factory/AuthServiceFactory.js";
2
- const authService = AuthServiceFactory();
1
+ import UserServiceFactory from "../factory/UserServiceFactory.js";
2
+ const userService = UserServiceFactory();
3
3
  async function authRoutes(fastify, options) {
4
4
  fastify.post('/api/auth', async (request, reply) => {
5
5
  try {
6
6
  const username = request.body.username;
7
7
  const password = request.body.password;
8
- return await authService.auth(username, password);
8
+ console.log("/api/auth username", username);
9
+ return await userService.auth(username, password);
9
10
  }
10
11
  catch (e) {
11
12
  if (e.message === "BadCredentials") {
12
13
  reply.code(401);
13
14
  reply.send({ error: e.message });
14
15
  }
15
- console.log(e);
16
+ console.error(e);
16
17
  throw e;
17
18
  }
18
19
  });
20
+ fastify.get('/api/me', async (request, reply) => {
21
+ console.log("/api/me request.authUser:", request.authUser);
22
+ let user = await userService.findById(request.authUser.id);
23
+ user = user.toObject();
24
+ delete user.password;
25
+ return user;
26
+ });
19
27
  }
20
28
  export default authRoutes;
21
29
  export { authRoutes };
@@ -1,21 +1,6 @@
1
- import AuthUtils from "../utils/AuthUtils.js";
2
1
  class AuthService {
3
2
  constructor(userService) {
4
3
  this._userService = userService;
5
4
  }
6
- async auth(username, password) {
7
- let user = null;
8
- user = await this._userService.findByUsername(username);
9
- //Si obtuve usuario chequeo la password
10
- if (user && AuthUtils.checkPassword(password, user.password)) {
11
- //TODO: Generar Sesion
12
- const session = '123';
13
- const accessToken = AuthUtils.generateToken(user._id.toString(), user.username, session);
14
- return { accessToken: accessToken };
15
- }
16
- else {
17
- throw Error('BadCredentials');
18
- }
19
- }
20
5
  }
21
6
  export default AuthService;
@@ -0,0 +1,19 @@
1
+ const permissions = [];
2
+ class PermissionService {
3
+ static addPermission(permission) {
4
+ if (PermissionService.hasPermission(permission))
5
+ return;
6
+ permissions.push(permission);
7
+ }
8
+ static removePermission(permission) {
9
+ permissions.splice(permissions.indexOf(permission), 1);
10
+ }
11
+ static hasPermission(permission) {
12
+ return permissions.includes(permission);
13
+ }
14
+ static getPermissions() {
15
+ return permissions;
16
+ }
17
+ }
18
+ export default PermissionService;
19
+ export { PermissionService };
@@ -1,30 +1,62 @@
1
+ import { ValidationError, ZodErrorToValidationError } from "@drax/common-back";
2
+ import { roleSchema } from "../zod/RoleZod.js";
3
+ import { ZodError } from "zod";
4
+ import UnauthorizedError from "../errors/UnauthorizedError.js";
1
5
  class RoleService {
2
6
  constructor(roleRepostitory) {
3
7
  this._repository = roleRepostitory;
8
+ console.log("RoleService constructor");
4
9
  }
5
10
  async create(roleData) {
6
- const role = await this._repository.create(roleData);
7
- return role;
11
+ try {
12
+ roleData.name = roleData?.name?.trim();
13
+ await roleSchema.parseAsync(roleData);
14
+ const role = await this._repository.create(roleData);
15
+ return role;
16
+ }
17
+ catch (e) {
18
+ if (e instanceof ZodError) {
19
+ throw ZodErrorToValidationError(e, roleData);
20
+ }
21
+ throw e;
22
+ }
8
23
  }
9
- async update(_id, roleData) {
10
- const role = await this._repository.update(_id, roleData);
11
- return role;
24
+ async update(id, roleData) {
25
+ try {
26
+ roleData.name = roleData?.name?.trim();
27
+ await roleSchema.parseAsync(roleData);
28
+ const currentRole = await this.findById(id);
29
+ if (currentRole.readonly) {
30
+ throw new ValidationError([{ field: 'name', reason: "role.readonly", value: roleData.name }]);
31
+ }
32
+ const role = await this._repository.update(id, roleData);
33
+ return role;
34
+ }
35
+ catch (e) {
36
+ if (e instanceof ZodError) {
37
+ throw ZodErrorToValidationError(e, roleData);
38
+ }
39
+ throw e;
40
+ }
12
41
  }
13
- async delete(_id) {
14
- const deletedRole = await this._repository.delete(_id);
42
+ async delete(id) {
43
+ const currentRole = await this.findById(id);
44
+ if (currentRole.readonly) {
45
+ throw new UnauthorizedError();
46
+ }
47
+ const deletedRole = await this._repository.delete(id);
15
48
  return deletedRole;
16
49
  }
17
- async findById(_id) {
18
- const role = await this._repository.findById(_id);
50
+ async findById(id) {
51
+ const role = await this._repository.findById(id);
19
52
  return role;
20
53
  }
21
- async paginate(filters, page = 1, limit = 10) {
22
- const query = {};
23
- const options = {
24
- page: page,
25
- limit: limit
26
- };
27
- const pagination = await this._repository.paginate(query, options);
54
+ async fetchAll() {
55
+ const roles = await this._repository.fetchAll();
56
+ return roles;
57
+ }
58
+ async paginate(page = 1, limit = 5, search, filters) {
59
+ const pagination = await this._repository.paginate(page, limit, search, filters);
28
60
  return pagination;
29
61
  }
30
62
  }
@@ -1,42 +1,101 @@
1
+ import { ZodError } from "zod";
2
+ import { ValidationError, ZodErrorToValidationError } from "@drax/common-back";
1
3
  import AuthUtils from "../utils/AuthUtils.js";
4
+ import { createUserSchema, editUserSchema, } from "../zod/UserZod.js";
5
+ import BadCredentialsError from "../errors/BadCredentialsError.js";
2
6
  class UserService {
3
7
  constructor(userRepository) {
4
8
  this._repository = userRepository;
9
+ console.log("UserService constructor");
10
+ }
11
+ async auth(username, password) {
12
+ let user = null;
13
+ console.log("auth username", username);
14
+ user = await this.findByUsername(username);
15
+ if (user && user.active && AuthUtils.checkPassword(password, user.password)) {
16
+ //TODO: Generar Sesion
17
+ const session = '123';
18
+ const accessToken = AuthUtils.generateToken(user.id.toString(), user.username, user.role.id, session);
19
+ return { accessToken: accessToken };
20
+ }
21
+ else {
22
+ throw new BadCredentialsError();
23
+ }
24
+ }
25
+ async changeUserPassword(userId, newPassword) {
26
+ const user = await this.findById(userId);
27
+ if (user) {
28
+ newPassword = AuthUtils.hashPassword(newPassword);
29
+ await this._repository.changePassword(userId, newPassword);
30
+ return true;
31
+ }
32
+ else {
33
+ throw new ValidationError([{ field: 'userId', reason: 'validation.notFound' }]);
34
+ }
35
+ }
36
+ async changeOwnPassword(userId, currentPassword, newPassword) {
37
+ const user = await this.findById(userId);
38
+ if (user && user.active) {
39
+ if (AuthUtils.checkPassword(currentPassword, user.password)) {
40
+ newPassword = AuthUtils.hashPassword(newPassword);
41
+ await this._repository.changePassword(userId, newPassword);
42
+ return true;
43
+ }
44
+ else {
45
+ throw new ValidationError([{ field: 'currentPassword', reason: 'validation.notMatch' }]);
46
+ }
47
+ }
48
+ else {
49
+ throw new BadCredentialsError();
50
+ }
5
51
  }
6
52
  async create(userData) {
7
- userData.name = userData?.name?.trim();
8
- userData.username = userData.username.trim();
9
- userData.password = AuthUtils.hashPassword(userData.password.trim());
10
- const user = await this._repository.create(userData);
11
- return user;
53
+ try {
54
+ userData.name = userData?.name?.trim();
55
+ userData.username = userData.username.trim();
56
+ userData.password = userData.password.trim();
57
+ await createUserSchema.parseAsync(userData);
58
+ userData.password = AuthUtils.hashPassword(userData.password.trim());
59
+ const user = await this._repository.create(userData);
60
+ return user;
61
+ }
62
+ catch (e) {
63
+ if (e instanceof ZodError) {
64
+ throw ZodErrorToValidationError(e, userData);
65
+ }
66
+ throw e;
67
+ }
12
68
  }
13
- async update(_id, userData) {
14
- userData.name = userData.name.trim();
15
- userData.username = userData.username.trim();
16
- delete userData.password;
17
- const user = await this._repository.update(_id, userData);
18
- return user;
69
+ async update(id, userData) {
70
+ try {
71
+ userData.name = userData.name.trim();
72
+ userData.username = userData.username.trim();
73
+ delete userData.password;
74
+ await editUserSchema.parseAsync(userData);
75
+ const user = await this._repository.update(id, userData);
76
+ return user;
77
+ }
78
+ catch (e) {
79
+ if (e instanceof ZodError) {
80
+ throw ZodErrorToValidationError(e, userData);
81
+ }
82
+ throw e;
83
+ }
19
84
  }
20
- async delete(_id) {
21
- const deletedRole = await this._repository.delete(_id);
85
+ async delete(id) {
86
+ const deletedRole = await this._repository.delete(id);
22
87
  return deletedRole;
23
88
  }
24
- async findById(_id) {
25
- const user = await this._repository.findById(_id);
89
+ async findById(id) {
90
+ const user = await this._repository.findById(id);
26
91
  return user;
27
92
  }
28
93
  async findByUsername(username) {
29
94
  const user = await this._repository.findByUsername(username);
30
95
  return user;
31
96
  }
32
- async paginate(filters, page = 1, limit = 10) {
33
- const query = {};
34
- const options = {
35
- page: page,
36
- limit: limit
37
- };
38
- const pagination = await this._repository.paginate(query, options);
39
- console.log("pagination", pagination);
97
+ async paginate(page = 1, limit = 10, search, filters) {
98
+ const pagination = await this._repository.paginate(page, limit, search, filters);
40
99
  return pagination;
41
100
  }
42
101
  }
@@ -1,6 +1,16 @@
1
1
  import bcryptjs from "bcryptjs";
2
2
  import jsonwebtoken from "jsonwebtoken";
3
3
  class AuthUtils {
4
+ static verifyToken(token) {
5
+ const JWT_SECRET = process.env.JWT_SECRET;
6
+ if (!JWT_SECRET) {
7
+ throw new Error("JWT_SECRET ENV must be provided");
8
+ }
9
+ const options = {
10
+ algorithms: ['HS256'],
11
+ };
12
+ return jsonwebtoken.verify(token, JWT_SECRET, options);
13
+ }
4
14
  static hashPassword(password) {
5
15
  if (!password) {
6
16
  throw new Error("password must be provided");
@@ -12,22 +22,26 @@ class AuthUtils {
12
22
  static checkPassword(password, hashPassword) {
13
23
  return bcryptjs.compareSync(password, hashPassword);
14
24
  }
15
- static tokenSignPayload(userId, username, session) {
25
+ static tokenSignPayload(userId, username, roleId, session) {
16
26
  return {
17
27
  id: userId,
18
28
  username: username,
29
+ roleId: roleId,
19
30
  session: session
20
31
  };
21
32
  }
22
- static generateToken(userId, username, session) {
23
- const payload = AuthUtils.tokenSignPayload(userId, username, session);
24
- const JWT_SECRET = process.env.JWT_SECRET ? process.env.JWT_SECRET : 'KRgDV3CeR5lVhsFF';
33
+ static generateToken(userId, username, roleId, session) {
34
+ const payload = AuthUtils.tokenSignPayload(userId, username, roleId, session);
35
+ const JWT_SECRET = process.env.JWT_SECRET;
36
+ if (!JWT_SECRET) {
37
+ throw new Error("JWT_SECRET ENV must be provided");
38
+ }
25
39
  const options = {
26
- expiresIn: process.env.JWT_LOGIN_EXPIRED_IN || '1h',
40
+ expiresIn: process.env.JWT_EXPIRATION || '1h',
27
41
  jwtid: userId,
28
42
  algorithm: 'HS256',
29
43
  audience: username,
30
- issuer: process.env.ISSUER ? process.env.ISSUER : 'drax'
44
+ issuer: process.env.JWT_ISSUER ? process.env.JWT_ISSUER : 'drax'
31
45
  };
32
46
  let token = jsonwebtoken.sign(payload, JWT_SECRET, options);
33
47
  return token;
@@ -0,0 +1,28 @@
1
+ var DbEngine;
2
+ (function (DbEngine) {
3
+ DbEngine["Sqlite"] = "sqlite";
4
+ DbEngine["Mongo"] = "mongo";
5
+ })(DbEngine || (DbEngine = {}));
6
+ class DbSetupUtils {
7
+ static getDbEngine() {
8
+ if (!process.env.DB_ENGINE) {
9
+ throw new Error("process.env.DB_ENGINE is not defined");
10
+ }
11
+ const dbEngine = process.env.DB_ENGINE;
12
+ if (!Object.values(DbEngine).includes(dbEngine)) {
13
+ throw new Error("process.env.DB_ENGINE must be one of " + Object.values(DbEngine).join(", "));
14
+ }
15
+ return dbEngine;
16
+ }
17
+ static getDbUri() {
18
+ switch (DbSetupUtils.getDbEngine()) {
19
+ case DbEngine.Mongo:
20
+ return process.env.MONGO_URI;
21
+ case DbEngine.Sqlite:
22
+ return process.env.SQLITE_DATABASE;
23
+ default:
24
+ throw new Error("process.env.DB_ENGINE must be one of " + Object.values(DbEngine).join(", "));
25
+ }
26
+ }
27
+ }
28
+ export { DbEngine, DbSetupUtils };
@@ -0,0 +1,8 @@
1
+ import { object, string } from "zod";
2
+ const roleSchema = object({
3
+ name: string({ required_error: "validation.required" })
4
+ .min(1, "validation.required")
5
+ .regex(/^[A-Z]/, "validation.startWithUpperCase"),
6
+ });
7
+ export default roleSchema;
8
+ export { roleSchema };
@@ -0,0 +1,18 @@
1
+ import { object, string } from "zod";
2
+ export const userBaseSchema = object({
3
+ name: string({ required_error: "validation.required" })
4
+ .min(1, "validation.required"),
5
+ username: string({ required_error: "validation.required" })
6
+ .min(1, "validation.required"),
7
+ email: string({ required_error: "validation.required" })
8
+ .email("validation.email.invalid"),
9
+ role: string({ required_error: "validation.required" })
10
+ .min(1, "validation.required")
11
+ });
12
+ export const createUserSchema = userBaseSchema.extend({
13
+ password: string({ required_error: "validation.required" })
14
+ .min(1, "validation.required")
15
+ .min(8, "validation.password.min8")
16
+ .max(32, "validation.password.max32"),
17
+ });
18
+ export const editUserSchema = userBaseSchema.extend({});
package/package.json CHANGED
@@ -3,32 +3,38 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.0.9",
6
+ "version": "0.0.10",
7
7
  "description": "Identity module for user management, authentication and authorization.",
8
8
  "main": "dist/index.js",
9
9
  "types": "types/index.d.ts",
10
10
  "type": "module",
11
11
  "scripts": {
12
12
  "serve": "nodemon --exec node --loader ts-node/esm src/index.ts",
13
- "prepublish": "npm run tsc && npm run copygql",
13
+ "prepublish": "tsc && npm run copygql",
14
14
  "clean": "rm -rf dist",
15
15
  "copygql": "copyfiles -u 1 ./**/*.graphql dist/",
16
16
  "tsc": "tsc -b tsconfig.json",
17
- "test": "node --loader tsx --test test/**/*",
18
- "testRepositoryRole": "node --loader tsx --test test/repository/role*",
19
- "testServiceRole": "node --loader tsx --test test/service/role*",
20
- "testRepositoryUser": "node --loader tsx --test test/repository/user*",
21
- "testServiceUser": "node --loader tsx --test test/service/user*",
22
- "testcoverage": "node --loader tsx --experimental-test-coverage test/service/*"
17
+ "test": "node --import tsx --test test/**/*",
18
+ "testMongoRepositoryRole": "node --import tsx --test test/repository/mongo/role*",
19
+ "testMongoRepositoryUser": "node --import tsx --test test/repository/mongo/user*",
20
+ "testSqliteRepositoryUser": "node --import tsx --test test/repository/sqlite/user*",
21
+ "testSqliteRepositoryRole": "node --import tsx --test test/repository/sqlite/role*",
22
+ "testServiceRole": "node --import tsx --test test/service/role*",
23
+ "testServiceUser": "node --import tsx --test test/service/user*",
24
+ "testcoverage": "node --import tsx --experimental-test-coverage test/service/*"
23
25
  },
24
26
  "author": "Cristian Incarnato & Drax Team",
25
27
  "license": "ISC",
26
28
  "dependencies": {
27
29
  "bcryptjs": "^2.4.3",
28
30
  "express-jwt": "^8.4.1",
29
- "jsonwebtoken": "^9.0.2"
31
+ "graphql": "^16.8.2",
32
+ "jsonwebtoken": "^9.0.2",
33
+ "zod": "^3.23.8"
30
34
  },
31
35
  "peerDependencies": {
36
+ "better-sqlite3": "^11.0.0",
37
+ "fastify": "^4.27.0",
32
38
  "mongoose": "^8.3.4",
33
39
  "mongoose-paginate-v2": "^1.8.0",
34
40
  "mongoose-unique-validator": "^5.0.0"
@@ -41,6 +47,7 @@
41
47
  "mongodb-memory-server": "^9.2.0",
42
48
  "nodemon": "^3.1.0",
43
49
  "ts-node": "^10.9.2",
50
+ "tsc-alias": "^1.8.10",
44
51
  "tsx": "^3.12.7",
45
52
  "typescript": "^5.4.5"
46
53
  },
@@ -49,5 +56,5 @@
49
56
  "debug": "0"
50
57
  }
51
58
  },
52
- "gitHead": "26465c7ca403bae9b9a67fa249aee660fb4f3dd4"
59
+ "gitHead": "c30e1965d551cc63001a301b8dc98e26eba3afe1"
53
60
  }
@@ -0,0 +1,13 @@
1
+ class BadCredentialsError extends Error {
2
+ constructor() {
3
+ super('error.badCredentials')
4
+ this.name = 'BadCredentialsError';
5
+ }
6
+
7
+ get statusCode(){
8
+ return 401
9
+ }
10
+
11
+ }
12
+
13
+ export default BadCredentialsError