@xeplr/auth 1.0.0 → 1.0.2

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 (59) hide show
  1. package/bin/migrate.js +58 -25
  2. package/bin/server.js +12 -30
  3. package/index.js +188 -48
  4. package/lib/adminRouter.js +20 -92
  5. package/lib/authHelper.js +26 -3
  6. package/lib/authMiddleware.js +39 -13
  7. package/lib/authRouter.js +144 -12
  8. package/lib/authService.js +448 -16
  9. package/lib/hooks.js +50 -0
  10. package/lib/mtMembershipMiddleware.js +61 -0
  11. package/lib/seed.js +74 -0
  12. package/lib/sessionService.js +54 -6
  13. package/lib/ticketService.js +88 -0
  14. package/lib/tokenDecision.js +45 -0
  15. package/migrations/0001_extensions.sql +9 -0
  16. package/migrations/0002_users.sql +31 -0
  17. package/migrations/0003_catalog_tables.sql +82 -0
  18. package/migrations/0004_role_mappings.sql +78 -0
  19. package/migrations/0005_user_tenants_mapping.sql +39 -0
  20. package/migrations/0006_seed_catalog.sql +120 -0
  21. package/models/Api.js +3 -0
  22. package/models/ApisRolesMapping.js +3 -0
  23. package/models/Menu.js +3 -0
  24. package/models/MenuRolesMapping.js +3 -0
  25. package/models/Role.js +8 -0
  26. package/models/UiElement.js +3 -0
  27. package/models/UiElementsRolesMapping.js +3 -0
  28. package/models/UiPage.js +3 -0
  29. package/models/UiPagesRolesMapping.js +3 -0
  30. package/models/User.js +3 -13
  31. package/models/UserRolesMapping.js +3 -0
  32. package/models/UserTenantsMapping.js +20 -2
  33. package/models/index.js +0 -2
  34. package/package.json +26 -5
  35. package/migrations/0001_users.js +0 -22
  36. package/migrations/0002_menus.js +0 -16
  37. package/migrations/0003_apis.js +0 -16
  38. package/migrations/0004_uiPages.js +0 -16
  39. package/migrations/0005_uiElements.js +0 -16
  40. package/migrations/0006_roles.js +0 -15
  41. package/migrations/0007_apisRolesMapping.js +0 -16
  42. package/migrations/0008_uiPagesRolesMapping.js +0 -16
  43. package/migrations/0009_uiElementsRolesMapping.js +0 -16
  44. package/migrations/0010_menuRolesMapping.js +0 -16
  45. package/migrations/0011_userRolesMapping.js +0 -16
  46. package/migrations/0012_users_add_reset_token.js +0 -13
  47. package/migrations/0013_add_isPublic.js +0 -27
  48. package/migrations/0014_users_add_activation_token.js +0 -13
  49. package/migrations/0015_add_mt_columns.js +0 -41
  50. package/migrations/0016_tenants.js +0 -23
  51. package/migrations/0017_userTenantsMapping.js +0 -20
  52. package/models/Tenant.js +0 -63
  53. package/seeds/001_roles.js +0 -26
  54. package/seeds/002_apis.js +0 -70
  55. package/seeds/003_pages.js +0 -41
  56. package/seeds/004_elements.js +0 -46
  57. package/seeds/005_menus.js +0 -35
  58. package/seeds/006_default_tenant.js +0 -50
  59. package/seeds/zzz_admin_access.js +0 -49
@@ -0,0 +1,120 @@
1
+ -- 0006_seed_catalog.sql
2
+ -- Base roles + the full apis/uiPages/uiElements/menus catalog for every route
3
+ -- xeplr-auth ships (authRouter.js + adminRouter.js), plus the "god-mode"
4
+ -- mapping of Super Admin/Admin to everything that exists at this point.
5
+ --
6
+ -- ids use pgcrypto's gen_random_bytes (enabled in 0001) to match the app's
7
+ -- own generateId() shape: a 24-char lowercase hex string.
8
+ --
9
+ -- isPublic:true rows need no role mapping — accessService.getUserAccess()
10
+ -- unions every isPublic:true row into every authenticated user's access,
11
+ -- regardless of role (see @xeplr/auth/lib/accessService.js getPublicItems()).
12
+
13
+ INSERT INTO "roles" (id, name, "isActive", "mtId1", "recordCreatedDate", "recordModifiedDate") VALUES
14
+ (encode(gen_random_bytes(12), 'hex'), 'Super Admin', true, '*', now(), now()),
15
+ (encode(gen_random_bytes(12), 'hex'), 'Admin', true, '*', now(), now()),
16
+ (encode(gen_random_bytes(12), 'hex'), 'Editor', true, '*', now(), now()),
17
+ (encode(gen_random_bytes(12), 'hex'), 'Viewer', true, '*', now(), now());
18
+
19
+ INSERT INTO "apis" (id, name, "apiGroup", "isPublic", "isActive", "mtId1", "recordCreatedDate", "recordModifiedDate") VALUES
20
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/register', '', true, true, '*', now(), now()),
21
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/activate', '', true, true, '*', now(), now()),
22
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/login', '', true, true, '*', now(), now()),
23
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/forgot-password', '', true, true, '*', now(), now()),
24
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/reset-password', '', true, true, '*', now(), now()),
25
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/refresh', '', true, true, '*', now(), now()),
26
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/logout', '', true, true, '*', now(), now()),
27
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/me', 'account:view', false, true, '*', now(), now()),
28
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/profile', 'account:view', false, true, '*', now(), now()),
29
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/profile/avatar', 'account:edit', false, true, '*', now(), now()),
30
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/change-password', 'account:edit', false, true, '*', now(), now()),
31
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/request-phone-otp', 'account:edit', false, true, '*', now(), now()),
32
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/verify-phone-otp', 'account:edit', false, true, '*', now(), now()),
33
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/users', 'users:view', false, true, '*', now(), now()),
34
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/roles', 'users:view', false, true, '*', now(), now()),
35
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/user-role', 'users:edit', false, true, '*', now(), now()),
36
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/access-items', 'access:view', false, true, '*', now(), now()),
37
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/access-role', 'access:edit', false, true, '*', now(), now()),
38
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/module-role', 'access:edit', false, true, '*', now(), now()),
39
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/master/roles', 'settings:view', false, true, '*', now(), now()),
40
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/master/roles/save', 'settings:edit', false, true, '*', now(), now()),
41
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/master/roles/delete', 'settings:delete', false, true, '*', now(), now()),
42
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/master/apis', 'settings:view', false, true, '*', now(), now()),
43
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/master/apis/save', 'settings:edit', false, true, '*', now(), now()),
44
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/master/apis/delete', 'settings:delete', false, true, '*', now(), now()),
45
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/master/pages', 'settings:view', false, true, '*', now(), now()),
46
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/master/pages/save', 'settings:edit', false, true, '*', now(), now()),
47
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/master/pages/delete', 'settings:delete', false, true, '*', now(), now()),
48
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/master/elements', 'settings:view', false, true, '*', now(), now()),
49
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/master/elements/save', 'settings:edit', false, true, '*', now(), now()),
50
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/master/elements/delete', 'settings:delete', false, true, '*', now(), now()),
51
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/master/menus', 'settings:view', false, true, '*', now(), now()),
52
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/master/menus/save', 'settings:edit', false, true, '*', now(), now()),
53
+ (encode(gen_random_bytes(12), 'hex'), '/auth/api/admin/master/menus/delete', 'settings:delete', false, true, '*', now(), now());
54
+
55
+ INSERT INTO "uiPages" (id, name, "uiPagesGroup", "isPublic", "isActive", "mtId1", "recordCreatedDate", "recordModifiedDate") VALUES
56
+ (encode(gen_random_bytes(12), 'hex'), 'Login', '', true, true, '*', now(), now()),
57
+ (encode(gen_random_bytes(12), 'hex'), 'Register', '', true, true, '*', now(), now()),
58
+ (encode(gen_random_bytes(12), 'hex'), 'Forgot Password', '', true, true, '*', now(), now()),
59
+ (encode(gen_random_bytes(12), 'hex'), 'Reset Password', '', true, true, '*', now(), now()),
60
+ (encode(gen_random_bytes(12), 'hex'), 'Activate Account', '', true, true, '*', now(), now()),
61
+ (encode(gen_random_bytes(12), 'hex'), 'Not Activated', '', true, true, '*', now(), now()),
62
+ (encode(gen_random_bytes(12), 'hex'), 'Profile', 'account:view', true, true, '*', now(), now()),
63
+ (encode(gen_random_bytes(12), 'hex'), 'Change Password', 'account:edit', true, true, '*', now(), now()),
64
+ (encode(gen_random_bytes(12), 'hex'), 'User Roles', 'users:view', false, true, '*', now(), now()),
65
+ (encode(gen_random_bytes(12), 'hex'), 'Access Matrix', 'access:view', false, true, '*', now(), now()),
66
+ (encode(gen_random_bytes(12), 'hex'), 'Master Settings', 'settings:view', false, true, '*', now(), now());
67
+
68
+ INSERT INTO "uiElements" (id, name, "uiElementsGroup", "isActive", "mtId1", "recordCreatedDate", "recordModifiedDate") VALUES
69
+ (encode(gen_random_bytes(12), 'hex'), 'Assign Role Button', 'users:edit', true, '*', now(), now()),
70
+ (encode(gen_random_bytes(12), 'hex'), 'Remove Role Button', 'users:edit', true, '*', now(), now()),
71
+ (encode(gen_random_bytes(12), 'hex'), 'Toggle Access Checkbox', 'access:edit', true, '*', now(), now()),
72
+ (encode(gen_random_bytes(12), 'hex'), 'Toggle Module Access Checkbox', 'access:edit', true, '*', now(), now()),
73
+ (encode(gen_random_bytes(12), 'hex'), 'Add Role Button', 'settings:edit', true, '*', now(), now()),
74
+ (encode(gen_random_bytes(12), 'hex'), 'Delete Role Button', 'settings:delete', true, '*', now(), now()),
75
+ (encode(gen_random_bytes(12), 'hex'), 'Add API Button', 'settings:edit', true, '*', now(), now()),
76
+ (encode(gen_random_bytes(12), 'hex'), 'Delete API Button', 'settings:delete', true, '*', now(), now()),
77
+ (encode(gen_random_bytes(12), 'hex'), 'Add Page Button', 'settings:edit', true, '*', now(), now()),
78
+ (encode(gen_random_bytes(12), 'hex'), 'Delete Page Button', 'settings:delete', true, '*', now(), now()),
79
+ (encode(gen_random_bytes(12), 'hex'), 'Add Element Button', 'settings:edit', true, '*', now(), now()),
80
+ (encode(gen_random_bytes(12), 'hex'), 'Delete Element Button', 'settings:delete', true, '*', now(), now()),
81
+ (encode(gen_random_bytes(12), 'hex'), 'Add Menu Button', 'settings:edit', true, '*', now(), now()),
82
+ (encode(gen_random_bytes(12), 'hex'), 'Delete Menu Button', 'settings:delete', true, '*', now(), now());
83
+
84
+ INSERT INTO "menus" (id, name, "menuGroup", "isPublic", "isActive", "mtId1", "recordCreatedDate", "recordModifiedDate") VALUES
85
+ (encode(gen_random_bytes(12), 'hex'), 'Login', '', true, true, '*', now(), now()),
86
+ (encode(gen_random_bytes(12), 'hex'), 'Register', '', true, true, '*', now(), now()),
87
+ (encode(gen_random_bytes(12), 'hex'), 'Forgot Password', '', true, true, '*', now(), now()),
88
+ (encode(gen_random_bytes(12), 'hex'), 'Reset Password', '', true, true, '*', now(), now()),
89
+ (encode(gen_random_bytes(12), 'hex'), 'Activate Account', '', true, true, '*', now(), now()),
90
+ (encode(gen_random_bytes(12), 'hex'), 'Not Activated', '', true, true, '*', now(), now()),
91
+ (encode(gen_random_bytes(12), 'hex'), 'Notifications', 'account:view', true, true, '*', now(), now()),
92
+ (encode(gen_random_bytes(12), 'hex'), 'Profile', 'account:view', true, true, '*', now(), now()),
93
+ (encode(gen_random_bytes(12), 'hex'), 'Change Password', 'account:edit', true, true, '*', now(), now()),
94
+ (encode(gen_random_bytes(12), 'hex'), 'User Roles', 'users:view', false, true, '*', now(), now()),
95
+ (encode(gen_random_bytes(12), 'hex'), 'Access Matrix', 'access:view', false, true, '*', now(), now()),
96
+ (encode(gen_random_bytes(12), 'hex'), 'Master Settings', 'settings:view', false, true, '*', now(), now()),
97
+ (encode(gen_random_bytes(12), 'hex'), 'Admin', 'admin:view', false, true, '*', now(), now());
98
+
99
+ -- God-mode: Super Admin + Admin see everything that exists at this point,
100
+ -- public or not (isPublic:true rows would reach them anyway — this also
101
+ -- covers the non-public ones without hand-picking which).
102
+ INSERT INTO "apisRolesMapping" (id, "roleId", "apiId", "isActive", "mtId1", "recordCreatedDate", "recordModifiedDate")
103
+ SELECT encode(gen_random_bytes(12), 'hex'), r.id, a.id, true, '*', now(), now()
104
+ FROM "roles" r CROSS JOIN "apis" a
105
+ WHERE r.name IN ('Super Admin', 'Admin');
106
+
107
+ INSERT INTO "uiPagesRolesMapping" (id, "roleId", "uiPageId", "isActive", "mtId1", "recordCreatedDate", "recordModifiedDate")
108
+ SELECT encode(gen_random_bytes(12), 'hex'), r.id, p.id, true, '*', now(), now()
109
+ FROM "roles" r CROSS JOIN "uiPages" p
110
+ WHERE r.name IN ('Super Admin', 'Admin');
111
+
112
+ INSERT INTO "uiElementsRolesMapping" (id, "roleId", "uiElementId", "isActive", "mtId1", "recordCreatedDate", "recordModifiedDate")
113
+ SELECT encode(gen_random_bytes(12), 'hex'), r.id, e.id, true, '*', now(), now()
114
+ FROM "roles" r CROSS JOIN "uiElements" e
115
+ WHERE r.name IN ('Super Admin', 'Admin');
116
+
117
+ INSERT INTO "menuRolesMapping" (id, "menuId", "roleId", "isActive", "mtId1", "recordCreatedDate", "recordModifiedDate")
118
+ SELECT encode(gen_random_bytes(12), 'hex'), m.id, r.id, true, '*', now(), now()
119
+ FROM "roles" r CROSS JOIN "menus" m
120
+ WHERE r.name IN ('Super Admin', 'Admin');
package/models/Api.js CHANGED
@@ -4,6 +4,9 @@ class Api extends BaseModel {
4
4
  static get tableName() { return 'apis'; }
5
5
  static get idColumn() { return 'id'; }
6
6
 
7
+ // Shared RBAC catalog, not per-tenant data — see Role.js for why.
8
+ static get multiTenant() { return false; }
9
+
7
10
  static get jsonSchema() {
8
11
  return {
9
12
  type: 'object',
@@ -4,6 +4,9 @@ class ApisRolesMapping extends BaseModel {
4
4
  static get tableName() { return 'apisRolesMapping'; }
5
5
  static get idColumn() { return 'id'; }
6
6
 
7
+ // Shared RBAC catalog, not per-tenant data — see Role.js for why.
8
+ static get multiTenant() { return false; }
9
+
7
10
  static get jsonSchema() {
8
11
  return {
9
12
  type: 'object',
package/models/Menu.js CHANGED
@@ -4,6 +4,9 @@ class Menu extends BaseModel {
4
4
  static get tableName() { return 'menus'; }
5
5
  static get idColumn() { return 'id'; }
6
6
 
7
+ // Shared RBAC catalog, not per-tenant data — see Role.js for why.
8
+ static get multiTenant() { return false; }
9
+
7
10
  static get jsonSchema() {
8
11
  return {
9
12
  type: 'object',
@@ -4,6 +4,9 @@ class MenuRolesMapping extends BaseModel {
4
4
  static get tableName() { return 'menuRolesMapping'; }
5
5
  static get idColumn() { return 'id'; }
6
6
 
7
+ // Shared RBAC catalog, not per-tenant data — see Role.js for why.
8
+ static get multiTenant() { return false; }
9
+
7
10
  static get jsonSchema() {
8
11
  return {
9
12
  type: 'object',
package/models/Role.js CHANGED
@@ -9,6 +9,14 @@ class Role extends BaseModel {
9
9
  return 'id';
10
10
  }
11
11
 
12
+ // Shared RBAC catalog (role definitions), not per-tenant data — tenant
13
+ // scoping happens on userTenantsMapping.roleId, not here. Must opt out:
14
+ // a brand-new user creating their first company has no MT context yet, and
15
+ // BaseModel's fail-closed tenant modifier would otherwise return zero rows.
16
+ static get multiTenant() {
17
+ return false;
18
+ }
19
+
12
20
  static get jsonSchema() {
13
21
  return {
14
22
  type: 'object',
@@ -4,6 +4,9 @@ class UiElement extends BaseModel {
4
4
  static get tableName() { return 'uiElements'; }
5
5
  static get idColumn() { return 'id'; }
6
6
 
7
+ // Shared RBAC catalog, not per-tenant data — see Role.js for why.
8
+ static get multiTenant() { return false; }
9
+
7
10
  static get jsonSchema() {
8
11
  return {
9
12
  type: 'object',
@@ -4,6 +4,9 @@ class UiElementsRolesMapping extends BaseModel {
4
4
  static get tableName() { return 'uiElementsRolesMapping'; }
5
5
  static get idColumn() { return 'id'; }
6
6
 
7
+ // Shared RBAC catalog, not per-tenant data — see Role.js for why.
8
+ static get multiTenant() { return false; }
9
+
7
10
  static get jsonSchema() {
8
11
  return {
9
12
  type: 'object',
package/models/UiPage.js CHANGED
@@ -4,6 +4,9 @@ class UiPage extends BaseModel {
4
4
  static get tableName() { return 'uiPages'; }
5
5
  static get idColumn() { return 'id'; }
6
6
 
7
+ // Shared RBAC catalog, not per-tenant data — see Role.js for why.
8
+ static get multiTenant() { return false; }
9
+
7
10
  static get jsonSchema() {
8
11
  return {
9
12
  type: 'object',
@@ -4,6 +4,9 @@ class UiPagesRolesMapping extends BaseModel {
4
4
  static get tableName() { return 'uiPagesRolesMapping'; }
5
5
  static get idColumn() { return 'id'; }
6
6
 
7
+ // Shared RBAC catalog, not per-tenant data — see Role.js for why.
8
+ static get multiTenant() { return false; }
9
+
7
10
  static get jsonSchema() {
8
11
  return {
9
12
  type: 'object',
package/models/User.js CHANGED
@@ -18,9 +18,12 @@ class User extends BaseModel {
18
18
  id: { type: 'string', maxLength: 25 },
19
19
  email: { type: 'string', maxLength: 255 },
20
20
  phoneNumber: { type: ['string', 'null'], maxLength: 255 },
21
+ phoneVerified: { type: 'boolean' },
22
+ phoneVerifiedOn: { type: ['string', 'null'] },
21
23
  name: { type: ['string', 'null'], maxLength: 255 },
22
24
  pwd: { type: ['string', 'null'], maxLength: 255 },
23
25
  pwdSalt: { type: ['string', 'null'], maxLength: 100 },
26
+ profilePicUrl: { type: ['string', 'null'], maxLength: 500 },
24
27
  isActive: { type: 'boolean' },
25
28
  mtId1: { type: ['string', 'null'], maxLength: 25 },
26
29
  mtId2: { type: ['string', 'null'], maxLength: 25 },
@@ -43,7 +46,6 @@ class User extends BaseModel {
43
46
 
44
47
  static get relationMappings() {
45
48
  const Role = require('./Role');
46
- const Tenant = require('./Tenant');
47
49
  return {
48
50
  roles: {
49
51
  relation: BaseModel.ManyToManyRelation,
@@ -56,18 +58,6 @@ class User extends BaseModel {
56
58
  },
57
59
  to: 'roles.id'
58
60
  }
59
- },
60
- tenants: {
61
- relation: BaseModel.ManyToManyRelation,
62
- modelClass: Tenant,
63
- join: {
64
- from: 'users.id',
65
- through: {
66
- from: 'userTenantsMapping.userId',
67
- to: 'userTenantsMapping.tenantId'
68
- },
69
- to: 'tenants.id'
70
- }
71
61
  }
72
62
  };
73
63
  }
@@ -4,6 +4,9 @@ class UserRolesMapping extends BaseModel {
4
4
  static get tableName() { return 'userRolesMapping'; }
5
5
  static get idColumn() { return 'id'; }
6
6
 
7
+ // Shared RBAC catalog, not per-tenant data — see Role.js for why.
8
+ static get multiTenant() { return false; }
9
+
7
10
  static get jsonSchema() {
8
11
  return {
9
12
  type: 'object',
@@ -8,11 +8,16 @@ class UserTenantsMapping extends BaseModel {
8
8
  static get jsonSchema() {
9
9
  return {
10
10
  type: 'object',
11
- required: ['id', 'userId', 'tenantId'],
11
+ required: ['id', 'userId', 'level', 'value'],
12
12
  properties: {
13
13
  id: { type: 'string', maxLength: 25 },
14
14
  userId: { type: 'string', maxLength: 25 },
15
- tenantId: { type: 'string', maxLength: 25 },
15
+ // Generic MT slot (l1-l4, matching mtId1-4) — NOT the app-defined name
16
+ // (companyId/workspaceId/...); that mapping lives only in the app's
17
+ // own registerMTs() config (see @xeplr/db BaseModel.registerMTs).
18
+ level: { type: 'string', enum: ['l1', 'l2', 'l3', 'l4'] },
19
+ value: { type: 'string', maxLength: 255 }, // the app's own id at that level
20
+ roleId: { type: ['string', 'null'], maxLength: 25 }, // scoped role for this grant (null = access only)
16
21
  mtId1: { type: ['string', 'null'], maxLength: 25 },
17
22
  mtId2: { type: ['string', 'null'], maxLength: 25 },
18
23
  mtId3: { type: ['string', 'null'], maxLength: 25 },
@@ -25,6 +30,19 @@ class UserTenantsMapping extends BaseModel {
25
30
  }
26
31
  };
27
32
  }
33
+
34
+ static get relationMappings() {
35
+ const Role = require('./Role');
36
+ return {
37
+ // no `tenant` relation on purpose: auth does not own a tenant tree,
38
+ // `value` is a bare, app-interpreted id at the given level.
39
+ role: {
40
+ relation: BaseModel.BelongsToOneRelation,
41
+ modelClass: Role,
42
+ join: { from: 'userTenantsMapping.roleId', to: 'roles.id' }
43
+ }
44
+ };
45
+ }
28
46
  }
29
47
 
30
48
  module.exports = UserTenantsMapping;
package/models/index.js CHANGED
@@ -9,7 +9,6 @@ const UiPagesRolesMapping = require('./UiPagesRolesMapping');
9
9
  const UiElementsRolesMapping = require('./UiElementsRolesMapping');
10
10
  const MenuRolesMapping = require('./MenuRolesMapping');
11
11
  const UserRolesMapping = require('./UserRolesMapping');
12
- const Tenant = require('./Tenant');
13
12
  const UserTenantsMapping = require('./UserTenantsMapping');
14
13
 
15
14
  module.exports = {
@@ -24,6 +23,5 @@ module.exports = {
24
23
  UiElementsRolesMapping,
25
24
  MenuRolesMapping,
26
25
  UserRolesMapping,
27
- Tenant,
28
26
  UserTenantsMapping
29
27
  };
package/package.json CHANGED
@@ -1,9 +1,15 @@
1
1
  {
2
2
  "name": "@xeplr/auth",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Pluggable authentication service: register, login, forgot/reset password, RBAC, multi-tenancy",
5
5
  "main": "index.js",
6
- "files": ["index.js", "lib/", "bin/", "models/", "migrations/", "seeds/"],
6
+ "files": [
7
+ "index.js",
8
+ "lib/",
9
+ "bin/",
10
+ "models/",
11
+ "migrations/"
12
+ ],
7
13
  "bin": {
8
14
  "xeplr-auth-migrate": "./bin/migrate.js",
9
15
  "xeplr-auth-server": "./bin/server.js"
@@ -13,14 +19,29 @@
13
19
  "./bin/server": "./bin/server.js",
14
20
  "./package.json": "./package.json"
15
21
  },
16
- "keywords": ["auth", "authentication", "jwt", "rbac", "express", "middleware", "multi-tenancy"],
22
+ "keywords": [
23
+ "auth",
24
+ "authentication",
25
+ "jwt",
26
+ "rbac",
27
+ "express",
28
+ "middleware",
29
+ "multi-tenancy"
30
+ ],
17
31
  "author": "xeplr",
18
32
  "license": "MIT",
19
- "repository": { "type": "git", "url": "https://github.com/Xeplr/xeplr-auth" },
20
- "publishConfig": { "access": "public" },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/Xeplr/xeplr-auth"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
21
40
  "dependencies": {
22
41
  "bcrypt": "^6.0.0",
42
+ "ioredis": "^5.6.1",
23
43
  "jsonwebtoken": "^9.0.3",
44
+ "multer": "^1.4.5-lts.1",
24
45
  "@xeplr/base-apis": "^1.0.0",
25
46
  "@xeplr/db": "^1.0.0",
26
47
  "@xeplr/utils": "^1.0.0"
@@ -1,22 +0,0 @@
1
- exports.up = function(knex) {
2
- return knex.schema.createTable('users', function(table) {
3
- table.string('id', 25).primary();
4
- table.string('email', 255).notNullable();
5
- table.string('phoneNumber', 255);
6
- table.string('name', 255);
7
- table.string('pwd', 255);
8
- table.string('pwdSalt', 100);
9
- table.boolean('isActive').defaultTo(false);
10
- table.boolean('isActivated').defaultTo(false);
11
- table.timestamp('activatedOn');
12
- table.string('activatedBy', 25);
13
- table.timestamp('recordCreatedDate');
14
- table.timestamp('recordModifiedDate');
15
- table.string('recordCreatedBy', 25);
16
- table.string('recordModifiedBy', 25);
17
- });
18
- };
19
-
20
- exports.down = function(knex) {
21
- return knex.schema.dropTableIfExists('users');
22
- };
@@ -1,16 +0,0 @@
1
- exports.up = function(knex) {
2
- return knex.schema.createTable('menus', function(table) {
3
- table.string('id', 25).primary();
4
- table.string('name', 255);
5
- table.string('menuGroup', 255);
6
- table.boolean('isActive').defaultTo(false);
7
- table.timestamp('recordCreatedDate');
8
- table.timestamp('recordModifiedDate');
9
- table.string('recordCreatedBy', 25);
10
- table.string('recordModifiedBy', 25);
11
- });
12
- };
13
-
14
- exports.down = function(knex) {
15
- return knex.schema.dropTableIfExists('menus');
16
- };
@@ -1,16 +0,0 @@
1
- exports.up = function(knex) {
2
- return knex.schema.createTable('apis', function(table) {
3
- table.string('id', 25).primary();
4
- table.string('name', 255);
5
- table.string('apiGroup', 255);
6
- table.boolean('isActive').defaultTo(false);
7
- table.timestamp('recordCreatedDate');
8
- table.timestamp('recordModifiedDate');
9
- table.string('recordCreatedBy', 25);
10
- table.string('recordModifiedBy', 25);
11
- });
12
- };
13
-
14
- exports.down = function(knex) {
15
- return knex.schema.dropTableIfExists('apis');
16
- };
@@ -1,16 +0,0 @@
1
- exports.up = function(knex) {
2
- return knex.schema.createTable('uiPages', function(table) {
3
- table.string('id', 25).primary();
4
- table.string('name', 255);
5
- table.string('uiPagesGroup', 255);
6
- table.boolean('isActive').defaultTo(false);
7
- table.timestamp('recordCreatedDate');
8
- table.timestamp('recordModifiedDate');
9
- table.string('recordCreatedBy', 25);
10
- table.string('recordModifiedBy', 25);
11
- });
12
- };
13
-
14
- exports.down = function(knex) {
15
- return knex.schema.dropTableIfExists('uiPages');
16
- };
@@ -1,16 +0,0 @@
1
- exports.up = function(knex) {
2
- return knex.schema.createTable('uiElements', function(table) {
3
- table.string('id', 25).primary();
4
- table.string('name', 255);
5
- table.string('uiElementsGroup', 255);
6
- table.boolean('isActive').defaultTo(false);
7
- table.timestamp('recordCreatedDate');
8
- table.timestamp('recordModifiedDate');
9
- table.string('recordCreatedBy', 25);
10
- table.string('recordModifiedBy', 25);
11
- });
12
- };
13
-
14
- exports.down = function(knex) {
15
- return knex.schema.dropTableIfExists('uiElements');
16
- };
@@ -1,15 +0,0 @@
1
- exports.up = function(knex) {
2
- return knex.schema.createTable('roles', function(table) {
3
- table.string('id', 25).primary();
4
- table.string('name', 255);
5
- table.boolean('isActive').defaultTo(false);
6
- table.timestamp('recordCreatedDate');
7
- table.timestamp('recordModifiedDate');
8
- table.string('recordCreatedBy', 25);
9
- table.string('recordModifiedBy', 25);
10
- });
11
- };
12
-
13
- exports.down = function(knex) {
14
- return knex.schema.dropTableIfExists('roles');
15
- };
@@ -1,16 +0,0 @@
1
- exports.up = function(knex) {
2
- return knex.schema.createTable('apisRolesMapping', function(table) {
3
- table.string('id', 25).primary();
4
- table.string('roleId', 25).references('id').inTable('roles');
5
- table.string('apiId', 25).references('id').inTable('apis');
6
- table.boolean('isActive').defaultTo(false);
7
- table.timestamp('recordCreatedDate');
8
- table.timestamp('recordModifiedDate');
9
- table.string('recordCreatedBy', 25);
10
- table.string('recordModifiedBy', 25);
11
- });
12
- };
13
-
14
- exports.down = function(knex) {
15
- return knex.schema.dropTableIfExists('apisRolesMapping');
16
- };
@@ -1,16 +0,0 @@
1
- exports.up = function(knex) {
2
- return knex.schema.createTable('uiPagesRolesMapping', function(table) {
3
- table.string('id', 25).primary();
4
- table.string('roleId', 25).references('id').inTable('roles');
5
- table.string('uiPageId', 25).references('id').inTable('uiPages');
6
- table.boolean('isActive').defaultTo(false);
7
- table.timestamp('recordCreatedDate');
8
- table.timestamp('recordModifiedDate');
9
- table.string('recordCreatedBy', 25);
10
- table.string('recordModifiedBy', 25);
11
- });
12
- };
13
-
14
- exports.down = function(knex) {
15
- return knex.schema.dropTableIfExists('uiPagesRolesMapping');
16
- };
@@ -1,16 +0,0 @@
1
- exports.up = function(knex) {
2
- return knex.schema.createTable('uiElementsRolesMapping', function(table) {
3
- table.string('id', 25).primary();
4
- table.string('roleId', 25).references('id').inTable('roles');
5
- table.string('uiElementId', 25).references('id').inTable('uiElements');
6
- table.boolean('isActive').defaultTo(false);
7
- table.timestamp('recordCreatedDate');
8
- table.timestamp('recordModifiedDate');
9
- table.string('recordCreatedBy', 25);
10
- table.string('recordModifiedBy', 25);
11
- });
12
- };
13
-
14
- exports.down = function(knex) {
15
- return knex.schema.dropTableIfExists('uiElementsRolesMapping');
16
- };
@@ -1,16 +0,0 @@
1
- exports.up = function(knex) {
2
- return knex.schema.createTable('menuRolesMapping', function(table) {
3
- table.string('id', 25).primary();
4
- table.string('menuId', 25).references('id').inTable('menus');
5
- table.string('roleId', 25).references('id').inTable('roles');
6
- table.boolean('isActive').defaultTo(false);
7
- table.timestamp('recordCreatedDate');
8
- table.timestamp('recordModifiedDate');
9
- table.string('recordCreatedBy', 25);
10
- table.string('recordModifiedBy', 25);
11
- });
12
- };
13
-
14
- exports.down = function(knex) {
15
- return knex.schema.dropTableIfExists('menuRolesMapping');
16
- };
@@ -1,16 +0,0 @@
1
- exports.up = function(knex) {
2
- return knex.schema.createTable('userRolesMapping', function(table) {
3
- table.string('id', 25).primary();
4
- table.string('userId', 25).references('id').inTable('users');
5
- table.string('roleId', 25).references('id').inTable('roles');
6
- table.boolean('isActive').defaultTo(false);
7
- table.timestamp('recordCreatedDate');
8
- table.timestamp('recordModifiedDate');
9
- table.string('recordCreatedBy', 25);
10
- table.string('recordModifiedBy', 25);
11
- });
12
- };
13
-
14
- exports.down = function(knex) {
15
- return knex.schema.dropTableIfExists('userRolesMapping');
16
- };
@@ -1,13 +0,0 @@
1
- exports.up = function(knex) {
2
- return knex.schema.alterTable('users', function(table) {
3
- table.string('resetToken', 255);
4
- table.timestamp('resetTokenExpiry');
5
- });
6
- };
7
-
8
- exports.down = function(knex) {
9
- return knex.schema.alterTable('users', function(table) {
10
- table.dropColumn('resetToken');
11
- table.dropColumn('resetTokenExpiry');
12
- });
13
- };
@@ -1,27 +0,0 @@
1
- exports.up = function(knex) {
2
- return Promise.all([
3
- knex.schema.alterTable('apis', function(table) {
4
- table.boolean('isPublic').defaultTo(false);
5
- }),
6
- knex.schema.alterTable('uiPages', function(table) {
7
- table.boolean('isPublic').defaultTo(false);
8
- }),
9
- knex.schema.alterTable('menus', function(table) {
10
- table.boolean('isPublic').defaultTo(false);
11
- })
12
- ]);
13
- };
14
-
15
- exports.down = function(knex) {
16
- return Promise.all([
17
- knex.schema.alterTable('apis', function(table) {
18
- table.dropColumn('isPublic');
19
- }),
20
- knex.schema.alterTable('uiPages', function(table) {
21
- table.dropColumn('isPublic');
22
- }),
23
- knex.schema.alterTable('menus', function(table) {
24
- table.dropColumn('isPublic');
25
- })
26
- ]);
27
- };
@@ -1,13 +0,0 @@
1
- exports.up = function(knex) {
2
- return knex.schema.alterTable('users', function(table) {
3
- table.string('activationToken', 255);
4
- table.string('normalizedEmail', 255).index();
5
- });
6
- };
7
-
8
- exports.down = function(knex) {
9
- return knex.schema.alterTable('users', function(table) {
10
- table.dropColumn('activationToken');
11
- table.dropColumn('normalizedEmail');
12
- });
13
- };