@servicelabsco/slabs-access-manager 1.0.53 → 1.0.55

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 (174) hide show
  1. package/dist/access/controllers/device.auth.controller.d.ts +44 -0
  2. package/dist/access/controllers/device.auth.controller.js +69 -0
  3. package/dist/access/controllers/device.auth.controller.js.map +1 -0
  4. package/dist/access/controllers/index.d.ts +4 -0
  5. package/dist/access/controllers/index.js +4 -0
  6. package/dist/access/controllers/index.js.map +1 -1
  7. package/dist/access/controllers/oauth.as.controller.d.ts +52 -0
  8. package/dist/access/controllers/oauth.as.controller.js +117 -0
  9. package/dist/access/controllers/oauth.as.controller.js.map +1 -0
  10. package/dist/access/controllers/oauth.discovery.controller.d.ts +16 -0
  11. package/dist/access/controllers/oauth.discovery.controller.js +35 -0
  12. package/dist/access/controllers/oauth.discovery.controller.js.map +1 -0
  13. package/dist/access/controllers/ui.action.controller.d.ts +13 -0
  14. package/dist/access/controllers/ui.action.controller.js +76 -0
  15. package/dist/access/controllers/ui.action.controller.js.map +1 -0
  16. package/dist/access/dtos/device.decide.dto.d.ts +5 -0
  17. package/dist/access/dtos/device.decide.dto.js +36 -0
  18. package/dist/access/dtos/device.decide.dto.js.map +1 -0
  19. package/dist/access/dtos/device.poll.dto.d.ts +3 -0
  20. package/dist/access/dtos/device.poll.dto.js +24 -0
  21. package/dist/access/dtos/device.poll.dto.js.map +1 -0
  22. package/dist/access/dtos/index.d.ts +5 -0
  23. package/dist/access/dtos/index.js +5 -0
  24. package/dist/access/dtos/index.js.map +1 -1
  25. package/dist/access/dtos/oauth.consent.decide.dto.d.ts +5 -0
  26. package/dist/access/dtos/oauth.consent.decide.dto.js +38 -0
  27. package/dist/access/dtos/oauth.consent.decide.dto.js.map +1 -0
  28. package/dist/access/dtos/oauth.register.dto.d.ts +7 -0
  29. package/dist/access/dtos/oauth.register.dto.js +51 -0
  30. package/dist/access/dtos/oauth.register.dto.js.map +1 -0
  31. package/dist/access/dtos/update.ui.action.attributes.dto.d.ts +3 -0
  32. package/dist/access/dtos/update.ui.action.attributes.dto.js +23 -0
  33. package/dist/access/dtos/update.ui.action.attributes.dto.js.map +1 -0
  34. package/dist/access/entities/device.code.entity.d.ts +17 -0
  35. package/dist/access/entities/device.code.entity.js +74 -0
  36. package/dist/access/entities/device.code.entity.js.map +1 -0
  37. package/dist/access/entities/index.d.ts +3 -0
  38. package/dist/access/entities/index.js +3 -0
  39. package/dist/access/entities/index.js.map +1 -1
  40. package/dist/access/entities/menu.action.entity.d.ts +1 -0
  41. package/dist/access/entities/menu.action.entity.js +4 -0
  42. package/dist/access/entities/menu.action.entity.js.map +1 -1
  43. package/dist/access/entities/oauth.authorization.entity.d.ts +23 -0
  44. package/dist/access/entities/oauth.authorization.entity.js +98 -0
  45. package/dist/access/entities/oauth.authorization.entity.js.map +1 -0
  46. package/dist/access/entities/oauth.client.entity.d.ts +10 -0
  47. package/dist/access/entities/oauth.client.entity.js +49 -0
  48. package/dist/access/entities/oauth.client.entity.js.map +1 -0
  49. package/dist/access/es6.classes.d.ts +25 -7
  50. package/dist/access/es6.classes.js +38 -1
  51. package/dist/access/es6.classes.js.map +1 -1
  52. package/dist/access/libraries/evaluate.email.rule.js.map +1 -1
  53. package/dist/access/libraries/extract.client.credentials.d.ts +12 -0
  54. package/dist/access/libraries/extract.client.credentials.js +41 -0
  55. package/dist/access/libraries/extract.client.credentials.js.map +1 -0
  56. package/dist/access/libraries/index.d.ts +2 -0
  57. package/dist/access/libraries/index.js +2 -0
  58. package/dist/access/libraries/index.js.map +1 -1
  59. package/dist/access/libraries/oauth.pkce.d.ts +6 -0
  60. package/dist/access/libraries/oauth.pkce.js +25 -0
  61. package/dist/access/libraries/oauth.pkce.js.map +1 -0
  62. package/dist/access/libraries/process.email.notification.js +3 -3
  63. package/dist/access/libraries/process.email.notification.js.map +1 -1
  64. package/dist/access/libraries/process.internal.notification.js +3 -3
  65. package/dist/access/libraries/process.internal.notification.js.map +1 -1
  66. package/dist/access/libraries/sanitize.email.addresses.d.ts +3 -1
  67. package/dist/access/libraries/sanitize.email.addresses.js +28 -25
  68. package/dist/access/libraries/sanitize.email.addresses.js.map +1 -1
  69. package/dist/access/libraries/send.email.notification.js +1 -1
  70. package/dist/access/libraries/send.email.notification.js.map +1 -1
  71. package/dist/access/middlewares/external.access.middleware.d.ts +3 -5
  72. package/dist/access/middlewares/external.access.middleware.js +9 -17
  73. package/dist/access/middlewares/external.access.middleware.js.map +1 -1
  74. package/dist/access/middlewares/index.d.ts +1 -0
  75. package/dist/access/middlewares/index.js +1 -0
  76. package/dist/access/middlewares/index.js.map +1 -1
  77. package/dist/access/middlewares/mcp.access.middleware.d.ts +7 -0
  78. package/dist/access/middlewares/mcp.access.middleware.js +34 -0
  79. package/dist/access/middlewares/mcp.access.middleware.js.map +1 -0
  80. package/dist/access/services/credential.resolve.service.d.ts +22 -0
  81. package/dist/access/services/credential.resolve.service.js +106 -0
  82. package/dist/access/services/credential.resolve.service.js.map +1 -0
  83. package/dist/access/services/device.auth.service.d.ts +50 -0
  84. package/dist/access/services/device.auth.service.js +177 -0
  85. package/dist/access/services/device.auth.service.js.map +1 -0
  86. package/dist/access/services/index.d.ts +3 -0
  87. package/dist/access/services/index.js +3 -0
  88. package/dist/access/services/index.js.map +1 -1
  89. package/dist/access/services/oauth.as.service.d.ts +96 -0
  90. package/dist/access/services/oauth.as.service.js +299 -0
  91. package/dist/access/services/oauth.as.service.js.map +1 -0
  92. package/dist/app.module.js +2 -1
  93. package/dist/app.module.js.map +1 -1
  94. package/dist/config/entity.constants.d.ts +6 -0
  95. package/dist/config/entity.constants.js +6 -0
  96. package/dist/config/entity.constants.js.map +1 -1
  97. package/dist/development/registries/development.entity.registry.js +2 -0
  98. package/dist/development/registries/development.entity.registry.js.map +1 -1
  99. package/dist/main.js +1 -0
  100. package/dist/main.js.map +1 -1
  101. package/dist/mcp/admin/tools/admin.tool.registry.js +10 -0
  102. package/dist/mcp/admin/tools/admin.tool.registry.js.map +1 -1
  103. package/dist/mcp/admin/tools/index.d.ts +1 -0
  104. package/dist/mcp/admin/tools/index.js +1 -0
  105. package/dist/mcp/admin/tools/index.js.map +1 -1
  106. package/dist/mcp/admin/tools/menu_ui_action/index.d.ts +5 -0
  107. package/dist/mcp/admin/tools/menu_ui_action/index.js +22 -0
  108. package/dist/mcp/admin/tools/menu_ui_action/index.js.map +1 -0
  109. package/dist/mcp/admin/tools/menu_ui_action/menu.ui.action.create.tool.d.ts +22 -0
  110. package/dist/mcp/admin/tools/menu_ui_action/menu.ui.action.create.tool.js +25 -0
  111. package/dist/mcp/admin/tools/menu_ui_action/menu.ui.action.create.tool.js.map +1 -0
  112. package/dist/mcp/admin/tools/menu_ui_action/menu.ui.action.delete.tool.d.ts +17 -0
  113. package/dist/mcp/admin/tools/menu_ui_action/menu.ui.action.delete.tool.js +23 -0
  114. package/dist/mcp/admin/tools/menu_ui_action/menu.ui.action.delete.tool.js.map +1 -0
  115. package/dist/mcp/admin/tools/menu_ui_action/menu.ui.action.get.tool.d.ts +17 -0
  116. package/dist/mcp/admin/tools/menu_ui_action/menu.ui.action.get.tool.js +23 -0
  117. package/dist/mcp/admin/tools/menu_ui_action/menu.ui.action.get.tool.js.map +1 -0
  118. package/dist/mcp/admin/tools/menu_ui_action/menu.ui.action.list.tool.d.ts +23 -0
  119. package/dist/mcp/admin/tools/menu_ui_action/menu.ui.action.list.tool.js +37 -0
  120. package/dist/mcp/admin/tools/menu_ui_action/menu.ui.action.list.tool.js.map +1 -0
  121. package/dist/mcp/admin/tools/menu_ui_action/menu.ui.action.update.tool.d.ts +20 -0
  122. package/dist/mcp/admin/tools/menu_ui_action/menu.ui.action.update.tool.js +25 -0
  123. package/dist/mcp/admin/tools/menu_ui_action/menu.ui.action.update.tool.js.map +1 -0
  124. package/dist/mcp/auth/execution.context.interface.d.ts +9 -0
  125. package/dist/mcp/auth/execution.context.interface.js +3 -0
  126. package/dist/mcp/auth/execution.context.interface.js.map +1 -0
  127. package/dist/mcp/auth/index.d.ts +1 -0
  128. package/dist/mcp/auth/index.js +18 -0
  129. package/dist/mcp/auth/index.js.map +1 -0
  130. package/dist/mcp/es6.classes.d.ts +7 -1
  131. package/dist/mcp/es6.classes.js +14 -1
  132. package/dist/mcp/es6.classes.js.map +1 -1
  133. package/dist/mcp/http/admin.mcp.controller.js +1 -1
  134. package/dist/mcp/http/admin.mcp.controller.js.map +1 -1
  135. package/dist/mcp/http/business.mcp.controller.js +5 -5
  136. package/dist/mcp/http/business.mcp.controller.js.map +1 -1
  137. package/dist/mcp/http/index.d.ts +1 -0
  138. package/dist/mcp/http/index.js +1 -0
  139. package/dist/mcp/http/index.js.map +1 -1
  140. package/dist/mcp/http/mcp.http.module.js +2 -1
  141. package/dist/mcp/http/mcp.http.module.js.map +1 -1
  142. package/dist/mcp/http/mcp.request.handler.js +1 -1
  143. package/dist/mcp/http/mcp.request.handler.js.map +1 -1
  144. package/dist/mcp/http/prm.controller.d.ts +10 -0
  145. package/dist/mcp/http/prm.controller.js +45 -0
  146. package/dist/mcp/http/prm.controller.js.map +1 -0
  147. package/dist/mcp/http/unauthorized.mcp.response.d.ts +6 -3
  148. package/dist/mcp/http/unauthorized.mcp.response.js +27 -17
  149. package/dist/mcp/http/unauthorized.mcp.response.js.map +1 -1
  150. package/dist/mcp/index.d.ts +1 -0
  151. package/dist/mcp/index.js +1 -0
  152. package/dist/mcp/index.js.map +1 -1
  153. package/dist/migrations/1785056165556-AddDisplayOrderUtlMenuActionsTable.d.ts +5 -0
  154. package/dist/migrations/1785056165556-AddDisplayOrderUtlMenuActionsTable.js +15 -0
  155. package/dist/migrations/1785056165556-AddDisplayOrderUtlMenuActionsTable.js.map +1 -0
  156. package/dist/migrations/1785057482427-CreateDeviceCodesTable.d.ts +5 -0
  157. package/dist/migrations/1785057482427-CreateDeviceCodesTable.js +25 -0
  158. package/dist/migrations/1785057482427-CreateDeviceCodesTable.js.map +1 -0
  159. package/dist/migrations/1785058700995-CreateOauthClientsTable.d.ts +5 -0
  160. package/dist/migrations/1785058700995-CreateOauthClientsTable.js +23 -0
  161. package/dist/migrations/1785058700995-CreateOauthClientsTable.js.map +1 -0
  162. package/dist/migrations/1785058701000-CreateOauthAuthorizationsTable.d.ts +5 -0
  163. package/dist/migrations/1785058701000-CreateOauthAuthorizationsTable.js +31 -0
  164. package/dist/migrations/1785058701000-CreateOauthAuthorizationsTable.js.map +1 -0
  165. package/dist/migrations/{1788000000000-CreateBzEventTriggersTable.d.ts → 1785163352085-CreateBzEventTriggersTable.d.ts} +1 -1
  166. package/dist/migrations/{1788000000000-CreateBzEventTriggersTable.js → 1785163352085-CreateBzEventTriggersTable.js} +4 -4
  167. package/dist/migrations/{1788000000000-CreateBzEventTriggersTable.js.map → 1785163352085-CreateBzEventTriggersTable.js.map} +1 -1
  168. package/dist/migrations/{1789000000000-RenameSourceHashToTableNameBzEventTriggersTable.d.ts → 1785163353086-RenameSourceHashToTableNameBzEventTriggersTable.d.ts} +1 -1
  169. package/dist/migrations/{1789000000000-RenameSourceHashToTableNameBzEventTriggersTable.js → 1785163353086-RenameSourceHashToTableNameBzEventTriggersTable.js} +4 -4
  170. package/dist/migrations/{1789000000000-RenameSourceHashToTableNameBzEventTriggersTable.js.map → 1785163353086-RenameSourceHashToTableNameBzEventTriggersTable.js.map} +1 -1
  171. package/dist/migrations/{1790000000000-CreateBzEventTriggerLogsTable.d.ts → 1785163354087-CreateBzEventTriggerLogsTable.d.ts} +1 -1
  172. package/dist/migrations/{1790000000000-CreateBzEventTriggerLogsTable.js → 1785163354087-CreateBzEventTriggerLogsTable.js} +4 -4
  173. package/dist/migrations/{1790000000000-CreateBzEventTriggerLogsTable.js.map → 1785163354087-CreateBzEventTriggerLogsTable.js.map} +1 -1
  174. package/package.json +1 -1
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.DeviceAuthService = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const nestjs_utility_services_1 = require("@servicelabsco/nestjs-utility-services");
15
+ const crypto_1 = require("crypto");
16
+ const typeorm_1 = require("typeorm");
17
+ const device_code_entity_1 = require("../entities/device.code.entity");
18
+ const access_business_entity_1 = require("../entities/access.business.entity");
19
+ const create_user_business_secret_1 = require("../libraries/create.user.business.secret");
20
+ const extract_client_credentials_1 = require("../libraries/extract.client.credentials");
21
+ const access_business_service_1 = require("./access.business.service");
22
+ const DEVICE_TTL_MS = 15 * 60_000;
23
+ const POLL_INTERVAL_S = 5;
24
+ const CODE_ALPHABET = 'BCDFGHJKMNPQRSTVWXYZ23456789';
25
+ let DeviceAuthService = class DeviceAuthService {
26
+ constructor(accessBusinessService) {
27
+ this.accessBusinessService = accessBusinessService;
28
+ }
29
+ async start() {
30
+ const deviceCode = (0, crypto_1.randomBytes)(32).toString('hex');
31
+ const userCode = this.generateUserCode();
32
+ const row = device_code_entity_1.DeviceCodeEntity.create({
33
+ device_code_hash: this.hash(deviceCode),
34
+ user_code: userCode,
35
+ expires_at: new Date(Date.now() + DEVICE_TTL_MS),
36
+ });
37
+ await row.save();
38
+ const verificationUri = this.verificationUri();
39
+ return {
40
+ device_code: deviceCode,
41
+ user_code: userCode,
42
+ verification_uri: verificationUri,
43
+ verification_uri_complete: `${verificationUri}?code=${encodeURIComponent(userCode)}`,
44
+ expires_in: DEVICE_TTL_MS / 1000,
45
+ interval: POLL_INTERVAL_S,
46
+ };
47
+ }
48
+ async getForApproval(userCode) {
49
+ const row = await this.findByUserCode(userCode);
50
+ if (!row)
51
+ return { status: 'not_found' };
52
+ if (row.denied_at)
53
+ return { status: 'denied', user_code: row.user_code };
54
+ if (row.consumed_at || row.approved_at)
55
+ return { status: 'decided', user_code: row.user_code };
56
+ if (row.expires_at.getTime() <= Date.now())
57
+ return { status: 'expired', user_code: row.user_code };
58
+ return {
59
+ status: 'pending',
60
+ user_code: row.user_code,
61
+ expires_at: row.expires_at,
62
+ };
63
+ }
64
+ async decide(userCode, action, businessId) {
65
+ const user = nestjs_utility_services_1.Auth.user();
66
+ if (!user?.id)
67
+ throw new nestjs_utility_services_1.AccessException('Login required to approve device login.');
68
+ const row = await this.findByUserCode(userCode);
69
+ if (!row)
70
+ throw new nestjs_utility_services_1.OperationException('Unknown device code.');
71
+ if (row.expires_at.getTime() <= Date.now())
72
+ throw new nestjs_utility_services_1.OperationException('This login expired. Start again from the CLI.');
73
+ if (row.denied_at || row.approved_at)
74
+ return { status: 'already_decided' };
75
+ if (action === 'deny') {
76
+ const denied = await device_code_entity_1.DeviceCodeEntity.update({ id: row.id, approved_at: (0, typeorm_1.IsNull)(), denied_at: (0, typeorm_1.IsNull)() }, { denied_at: new Date(), approved_by_user_id: user.id });
77
+ return { status: denied.affected ? 'denied' : 'already_decided' };
78
+ }
79
+ const business = await this.resolveBusinessForApprove(businessId);
80
+ const claimed = await device_code_entity_1.DeviceCodeEntity.update({ id: row.id, approved_at: (0, typeorm_1.IsNull)(), denied_at: (0, typeorm_1.IsNull)() }, {
81
+ approved_at: new Date(),
82
+ approved_by_user_id: user.id,
83
+ business_id: business.id,
84
+ });
85
+ if (!claimed.affected)
86
+ return { status: 'already_decided' };
87
+ return { status: 'approved', business_id: business.id };
88
+ }
89
+ async poll(deviceCode) {
90
+ const row = await device_code_entity_1.DeviceCodeEntity.findOne({ where: { device_code_hash: this.hash(deviceCode) } });
91
+ if (!row)
92
+ return { status: 'expired' };
93
+ if (row.denied_at)
94
+ return { status: 'denied' };
95
+ if (row.consumed_at)
96
+ return { status: 'expired' };
97
+ if (row.expires_at.getTime() <= Date.now())
98
+ return { status: 'expired' };
99
+ if (!row.approved_at)
100
+ return { status: 'pending' };
101
+ const claimed = await device_code_entity_1.DeviceCodeEntity.update({ id: row.id, consumed_at: (0, typeorm_1.IsNull)() }, { consumed_at: new Date() });
102
+ if (!claimed.affected)
103
+ return { status: 'expired' };
104
+ const minted = await this.mintPersonalKey(row);
105
+ return {
106
+ status: 'approved',
107
+ access_token: minted.access_token,
108
+ token_type: 'Bearer',
109
+ client_id: minted.client_id,
110
+ client_secret: minted.client_secret,
111
+ };
112
+ }
113
+ async mintPersonalKey(row) {
114
+ if (!row.approved_by_user_id || !row.business_id) {
115
+ throw new nestjs_utility_services_1.OperationException('Device login is missing approver or business.');
116
+ }
117
+ const business = await access_business_entity_1.AccessBusinessEntity.findOne({ where: { id: row.business_id } });
118
+ if (!business)
119
+ throw new nestjs_utility_services_1.OperationException('Business for device login no longer exists.');
120
+ const accessObject = { id: row.approved_by_user_id, auth_attributes: { business_id: business.id } };
121
+ nestjs_utility_services_1.Auth.login(accessObject);
122
+ const name = `CLI · device login · ${new Date().toISOString().slice(0, 16)}`;
123
+ const secret = await new create_user_business_secret_1.CreateUserBusinessSecret(business).process({ name });
124
+ row.user_secret_id = secret.id;
125
+ await row.save();
126
+ return {
127
+ client_id: secret.client_id,
128
+ client_secret: secret.client_secret,
129
+ access_token: extract_client_credentials_1.ExtractClientCredentials.formatPersonalAccessToken(secret.client_id, secret.client_secret),
130
+ };
131
+ }
132
+ async resolveBusinessForApprove(businessId) {
133
+ if (businessId) {
134
+ const business = await access_business_entity_1.AccessBusinessEntity.findOne({ where: { id: businessId } });
135
+ if (!business)
136
+ throw new nestjs_utility_services_1.OperationException('Unknown business_id.');
137
+ return business;
138
+ }
139
+ return this.accessBusinessService.validateAccess();
140
+ }
141
+ async findByUserCode(userCode) {
142
+ const formatted = this.normalizeUserCode(userCode);
143
+ if (!formatted)
144
+ return null;
145
+ return device_code_entity_1.DeviceCodeEntity.findOne({ where: { user_code: formatted } });
146
+ }
147
+ normalizeUserCode(userCode) {
148
+ const normalized = String(userCode || '')
149
+ .trim()
150
+ .toUpperCase()
151
+ .replace(/[^A-Z0-9]/g, '');
152
+ if (normalized.length !== 8)
153
+ return null;
154
+ return `${normalized.slice(0, 4)}-${normalized.slice(4)}`;
155
+ }
156
+ generateUserCode() {
157
+ let raw = '';
158
+ for (let i = 0; i < 8; i++) {
159
+ raw += CODE_ALPHABET[(0, crypto_1.randomBytes)(1)[0] % CODE_ALPHABET.length];
160
+ }
161
+ return `${raw.slice(0, 4)}-${raw.slice(4)}`;
162
+ }
163
+ hash(value) {
164
+ return (0, crypto_1.createHash)('sha256').update(value).digest('hex');
165
+ }
166
+ verificationUri() {
167
+ return (process.env.DEVICE_AUTH_VERIFICATION_URI ||
168
+ process.env.FRONTEND_DEVICE_URL ||
169
+ `${(process.env.SERVER_URL || 'http://localhost:4000').replace(/\/+$/, '')}/device`);
170
+ }
171
+ };
172
+ exports.DeviceAuthService = DeviceAuthService;
173
+ exports.DeviceAuthService = DeviceAuthService = __decorate([
174
+ (0, common_1.Injectable)(),
175
+ __metadata("design:paramtypes", [access_business_service_1.AccessBusinessService])
176
+ ], DeviceAuthService);
177
+ //# sourceMappingURL=device.auth.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.auth.service.js","sourceRoot":"","sources":["../../../src/access/services/device.auth.service.ts"],"names":[],"mappings":"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"}
@@ -8,8 +8,10 @@ export * from './business.preference.service';
8
8
  export * from './business.property.service';
9
9
  export * from './business.script.service';
10
10
  export * from './business.user.role.service';
11
+ export * from './credential.resolve.service';
11
12
  export * from './currency.service';
12
13
  export * from './custom.field.service';
14
+ export * from './device.auth.service';
13
15
  export * from './gchat.service';
14
16
  export * from './gmail.integration.service';
15
17
  export * from './gpt.service';
@@ -18,6 +20,7 @@ export * from './listing.service';
18
20
  export * from './load.entity.service';
19
21
  export * from './lock.script.service';
20
22
  export * from './notification.service';
23
+ export * from './oauth.as.service';
21
24
  export * from './overriding.script.service';
22
25
  export * from './platform.service';
23
26
  export * from './request.log.service';
@@ -24,8 +24,10 @@ __exportStar(require("./business.preference.service"), exports);
24
24
  __exportStar(require("./business.property.service"), exports);
25
25
  __exportStar(require("./business.script.service"), exports);
26
26
  __exportStar(require("./business.user.role.service"), exports);
27
+ __exportStar(require("./credential.resolve.service"), exports);
27
28
  __exportStar(require("./currency.service"), exports);
28
29
  __exportStar(require("./custom.field.service"), exports);
30
+ __exportStar(require("./device.auth.service"), exports);
29
31
  __exportStar(require("./gchat.service"), exports);
30
32
  __exportStar(require("./gmail.integration.service"), exports);
31
33
  __exportStar(require("./gpt.service"), exports);
@@ -34,6 +36,7 @@ __exportStar(require("./listing.service"), exports);
34
36
  __exportStar(require("./load.entity.service"), exports);
35
37
  __exportStar(require("./lock.script.service"), exports);
36
38
  __exportStar(require("./notification.service"), exports);
39
+ __exportStar(require("./oauth.as.service"), exports);
37
40
  __exportStar(require("./overriding.script.service"), exports);
38
41
  __exportStar(require("./platform.service"), exports);
39
42
  __exportStar(require("./request.log.service"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/access/services/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4DAA0C;AAAA,0DAAwC;AAAA,wDAAsC;AAAA,4DAA0C;AAAA,sDAAoC;AAAA,2DAAyC;AAAA,gEAA8C;AAAA,8DAA4C;AAAA,4DAA0C;AAAA,+DAA6C;AAAA,qDAAmC;AAAA,yDAAuC;AAAA,kDAAgC;AAAA,8DAA4C;AAAA,gDAA8B;AAAA,+DAA6C;AAAA,oDAAkC;AAAA,wDAAsC;AAAA,wDAAsC;AAAA,yDAAuC;AAAA,8DAA4C;AAAA,qDAAmC;AAAA,wDAAsC;AAAA,6DAA2C;AAAA,uDAAqC;AAAA,kDAAgC;AAAA,kDAAgC;AAAA,iEAA+C;AAAA,8DAA4C;AAAA,4DAA0C;AAAA,oDAAkC;AAAA,oDAAkC;AAAA,qDAAkC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/access/services/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4DAA0C;AAAA,0DAAwC;AAAA,wDAAsC;AAAA,4DAA0C;AAAA,sDAAoC;AAAA,2DAAyC;AAAA,gEAA8C;AAAA,8DAA4C;AAAA,4DAA0C;AAAA,+DAA6C;AAAA,+DAA6C;AAAA,qDAAmC;AAAA,yDAAuC;AAAA,wDAAsC;AAAA,kDAAgC;AAAA,8DAA4C;AAAA,gDAA8B;AAAA,+DAA6C;AAAA,oDAAkC;AAAA,wDAAsC;AAAA,wDAAsC;AAAA,yDAAuC;AAAA,qDAAmC;AAAA,8DAA4C;AAAA,qDAAmC;AAAA,wDAAsC;AAAA,6DAA2C;AAAA,uDAAqC;AAAA,kDAAgC;AAAA,kDAAgC;AAAA,iEAA+C;AAAA,8DAA4C;AAAA,4DAA0C;AAAA,oDAAkC;AAAA,oDAAkC;AAAA,qDAAkC"}
@@ -0,0 +1,96 @@
1
+ import { OauthRegisterDto } from '../dtos/oauth.register.dto';
2
+ import { AccessBusinessService } from './access.business.service';
3
+ export declare class OauthProtocolError extends Error {
4
+ readonly error: string;
5
+ readonly status: number;
6
+ constructor(error: string, message?: string, status?: number);
7
+ }
8
+ export declare class OauthAsService {
9
+ private readonly accessBusinessService;
10
+ constructor(accessBusinessService: AccessBusinessService);
11
+ issuer(): string;
12
+ scopesSupported(): string[];
13
+ authorizationServerMetadata(): {
14
+ issuer: string;
15
+ authorization_endpoint: string;
16
+ token_endpoint: string;
17
+ registration_endpoint: string;
18
+ response_types_supported: string[];
19
+ grant_types_supported: string[];
20
+ code_challenge_methods_supported: string[];
21
+ token_endpoint_auth_methods_supported: string[];
22
+ scopes_supported: string[];
23
+ };
24
+ register(dto: OauthRegisterDto): Promise<{
25
+ client_id: string;
26
+ client_name: string;
27
+ redirect_uris: string[];
28
+ grant_types: string[];
29
+ response_types: string[];
30
+ token_endpoint_auth_method: string;
31
+ client_id_issued_at: number;
32
+ }>;
33
+ beginAuthorize(query: Record<string, string | undefined>): Promise<{
34
+ kind: 'error_page';
35
+ error: string;
36
+ message: string;
37
+ } | {
38
+ kind: 'login_redirect';
39
+ url: string;
40
+ } | {
41
+ kind: 'consent_redirect';
42
+ url: string;
43
+ } | {
44
+ kind: 'protocol_redirect';
45
+ url: string;
46
+ }>;
47
+ getConsent(authorizationId: number): Promise<{
48
+ status: "not_found";
49
+ authorization_id?: undefined;
50
+ client_name?: undefined;
51
+ redirect_host?: undefined;
52
+ scope?: undefined;
53
+ expires_at?: undefined;
54
+ } | {
55
+ status: "decided";
56
+ authorization_id: number;
57
+ client_name?: undefined;
58
+ redirect_host?: undefined;
59
+ scope?: undefined;
60
+ expires_at?: undefined;
61
+ } | {
62
+ status: "expired";
63
+ authorization_id: number;
64
+ client_name?: undefined;
65
+ redirect_host?: undefined;
66
+ scope?: undefined;
67
+ expires_at?: undefined;
68
+ } | {
69
+ status: "pending";
70
+ authorization_id: number;
71
+ client_name: string;
72
+ redirect_host: string;
73
+ scope: string;
74
+ expires_at: Date;
75
+ }>;
76
+ decideConsent(authorizationId: number, action: 'approve' | 'deny', businessId?: number): Promise<{
77
+ status: "already_decided";
78
+ redirect_to: string;
79
+ } | {
80
+ status: "denied";
81
+ redirect_to: string;
82
+ } | {
83
+ status: "approved";
84
+ redirect_to: string;
85
+ }>;
86
+ exchangeToken(body: Record<string, string | undefined>): Promise<{
87
+ access_token: string;
88
+ token_type: string;
89
+ scope: string;
90
+ }>;
91
+ private mintPersonalKey;
92
+ private resolveBusiness;
93
+ private errorRedirect;
94
+ private frontendBase;
95
+ private buildAuthorizeReturnUrl;
96
+ }
@@ -0,0 +1,299 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.OauthAsService = exports.OauthProtocolError = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const nestjs_utility_services_1 = require("@servicelabsco/nestjs-utility-services");
15
+ const typeorm_1 = require("typeorm");
16
+ const access_business_entity_1 = require("../entities/access.business.entity");
17
+ const oauth_authorization_entity_1 = require("../entities/oauth.authorization.entity");
18
+ const oauth_client_entity_1 = require("../entities/oauth.client.entity");
19
+ const create_user_business_secret_1 = require("../libraries/create.user.business.secret");
20
+ const extract_client_credentials_1 = require("../libraries/extract.client.credentials");
21
+ const oauth_pkce_1 = require("../libraries/oauth.pkce");
22
+ const access_business_service_1 = require("./access.business.service");
23
+ const PENDING_TTL_MS = 10 * 60_000;
24
+ const CODE_TTL_MS = 2 * 60_000;
25
+ const DEFAULT_SCOPE = 'mcp';
26
+ class OauthProtocolError extends Error {
27
+ constructor(error, message, status = 400) {
28
+ super(message || error);
29
+ this.error = error;
30
+ this.status = status;
31
+ }
32
+ }
33
+ exports.OauthProtocolError = OauthProtocolError;
34
+ let OauthAsService = class OauthAsService {
35
+ constructor(accessBusinessService) {
36
+ this.accessBusinessService = accessBusinessService;
37
+ }
38
+ issuer() {
39
+ return (process.env.MCP_AUTHORIZATION_SERVER || process.env.SERVER_URL || `http://127.0.0.1:${process.env.SERVER_PORT || 4000}`).replace(/\/+$/, '');
40
+ }
41
+ scopesSupported() {
42
+ return (process.env.MCP_SCOPES_SUPPORTED || 'mcp,reporting:read')
43
+ .split(',')
44
+ .map((s) => s.trim())
45
+ .filter(Boolean);
46
+ }
47
+ authorizationServerMetadata() {
48
+ const issuer = this.issuer();
49
+ return {
50
+ issuer,
51
+ authorization_endpoint: `${issuer}/oauth/authorize`,
52
+ token_endpoint: `${issuer}/oauth/token`,
53
+ registration_endpoint: `${issuer}/oauth/register`,
54
+ response_types_supported: ['code'],
55
+ grant_types_supported: ['authorization_code'],
56
+ code_challenge_methods_supported: ['S256'],
57
+ token_endpoint_auth_methods_supported: ['none'],
58
+ scopes_supported: this.scopesSupported(),
59
+ };
60
+ }
61
+ async register(dto) {
62
+ const redirectUris = (dto.redirect_uris || []).map((u) => String(u).trim()).filter(Boolean);
63
+ if (!redirectUris.length)
64
+ throw new OauthProtocolError('invalid_client_metadata', 'redirect_uris is required');
65
+ for (const uri of redirectUris) {
66
+ try {
67
+ new URL(uri);
68
+ }
69
+ catch {
70
+ throw new OauthProtocolError('invalid_redirect_uri', `Invalid redirect_uri: ${uri}`);
71
+ }
72
+ }
73
+ if (dto.token_endpoint_auth_method && dto.token_endpoint_auth_method !== 'none') {
74
+ throw new OauthProtocolError('invalid_client_metadata', 'Only token_endpoint_auth_method=none is supported');
75
+ }
76
+ const clientId = oauth_pkce_1.OauthPkce.randomToken(16);
77
+ const row = oauth_client_entity_1.OauthClientEntity.create({
78
+ client_id: clientId,
79
+ client_name: dto.client_name || 'MCP client',
80
+ redirect_uris: redirectUris,
81
+ token_endpoint_auth_method: 'none',
82
+ grant_types: dto.grant_types?.length ? dto.grant_types : ['authorization_code'],
83
+ response_types: dto.response_types?.length ? dto.response_types : ['code'],
84
+ });
85
+ await row.save();
86
+ return {
87
+ client_id: row.client_id,
88
+ client_name: row.client_name,
89
+ redirect_uris: row.redirect_uris,
90
+ grant_types: row.grant_types,
91
+ response_types: row.response_types,
92
+ token_endpoint_auth_method: 'none',
93
+ client_id_issued_at: Math.floor(Date.now() / 1000),
94
+ };
95
+ }
96
+ async beginAuthorize(query) {
97
+ const clientId = query.client_id?.trim();
98
+ if (!clientId)
99
+ return { kind: 'error_page', error: 'invalid_request', message: 'client_id is required' };
100
+ const client = await oauth_client_entity_1.OauthClientEntity.findOne({ where: { client_id: clientId } });
101
+ if (!client)
102
+ return { kind: 'error_page', error: 'invalid_client', message: 'Unknown client_id' };
103
+ const redirectUri = query.redirect_uri?.trim();
104
+ if (!redirectUri || !client.redirect_uris.includes(redirectUri)) {
105
+ return { kind: 'error_page', error: 'invalid_request', message: 'redirect_uri is not registered for this client' };
106
+ }
107
+ const state = query.state;
108
+ const back = (error, description) => {
109
+ const url = new URL(redirectUri);
110
+ url.searchParams.set('error', error);
111
+ if (description)
112
+ url.searchParams.set('error_description', description);
113
+ if (state)
114
+ url.searchParams.set('state', state);
115
+ return { kind: 'protocol_redirect', url: url.toString() };
116
+ };
117
+ if (query.response_type !== 'code')
118
+ return back('unsupported_response_type', 'Only response_type=code is supported');
119
+ if (!query.code_challenge || query.code_challenge_method !== 'S256') {
120
+ return back('invalid_request', 'PKCE S256 is required');
121
+ }
122
+ const requestedScope = (query.scope || DEFAULT_SCOPE).trim() || DEFAULT_SCOPE;
123
+ const allowed = this.scopesSupported();
124
+ if (!requestedScope.split(/\s+/).every((s) => allowed.includes(s))) {
125
+ return back('invalid_scope', `Supported scopes: ${allowed.join(' ')}`);
126
+ }
127
+ if (!nestjs_utility_services_1.Auth.check()) {
128
+ const authorizeUrl = this.buildAuthorizeReturnUrl(query);
129
+ const loginBase = process.env.OAUTH_LOGIN_URI || process.env.FRONTEND_LOGIN_URL || `${this.frontendBase()}/login`;
130
+ const url = new URL(loginBase);
131
+ url.searchParams.set('return_to', authorizeUrl);
132
+ return { kind: 'login_redirect', url: url.toString() };
133
+ }
134
+ const pending = oauth_authorization_entity_1.OauthAuthorizationEntity.create({
135
+ client_id: clientId,
136
+ redirect_uri: redirectUri,
137
+ scope: requestedScope,
138
+ state: state || null,
139
+ code_challenge: query.code_challenge,
140
+ code_challenge_method: 'S256',
141
+ resource: query.resource || null,
142
+ expires_at: new Date(Date.now() + PENDING_TTL_MS),
143
+ });
144
+ await pending.save();
145
+ const consentBase = process.env.OAUTH_CONSENT_URI || `${this.frontendBase()}/oauth/consent`;
146
+ const consentUrl = new URL(consentBase);
147
+ consentUrl.searchParams.set('authorization_id', String(pending.id));
148
+ return { kind: 'consent_redirect', url: consentUrl.toString() };
149
+ }
150
+ async getConsent(authorizationId) {
151
+ if (!nestjs_utility_services_1.Auth.check())
152
+ throw new nestjs_utility_services_1.AccessException('Login required.');
153
+ const row = await oauth_authorization_entity_1.OauthAuthorizationEntity.findOne({ where: { id: authorizationId } });
154
+ if (!row)
155
+ return { status: 'not_found' };
156
+ const client = await oauth_client_entity_1.OauthClientEntity.findOne({ where: { client_id: row.client_id } });
157
+ if (row.denied_at)
158
+ return { status: 'decided', authorization_id: row.id };
159
+ if (row.approved_at)
160
+ return { status: 'decided', authorization_id: row.id };
161
+ if (row.expires_at.getTime() <= Date.now())
162
+ return { status: 'expired', authorization_id: row.id };
163
+ return {
164
+ status: 'pending',
165
+ authorization_id: row.id,
166
+ client_name: client?.client_name || row.client_id,
167
+ redirect_host: oauth_pkce_1.OauthPkce.safeRedirectHost(row.redirect_uri),
168
+ scope: row.scope,
169
+ expires_at: row.expires_at,
170
+ };
171
+ }
172
+ async decideConsent(authorizationId, action, businessId) {
173
+ const user = nestjs_utility_services_1.Auth.user();
174
+ if (!user?.id)
175
+ throw new nestjs_utility_services_1.AccessException('Login required to approve MCP connect.');
176
+ const row = await oauth_authorization_entity_1.OauthAuthorizationEntity.findOne({ where: { id: authorizationId } });
177
+ if (!row)
178
+ throw new nestjs_utility_services_1.OperationException('Unknown authorization.');
179
+ if (row.expires_at.getTime() <= Date.now())
180
+ throw new nestjs_utility_services_1.OperationException('This authorization expired. Start Connect again.');
181
+ if (row.denied_at || row.approved_at) {
182
+ return { status: 'already_decided', redirect_to: this.errorRedirect(row, 'access_denied', 'Already decided') };
183
+ }
184
+ if (action === 'deny') {
185
+ const denied = await oauth_authorization_entity_1.OauthAuthorizationEntity.update({ id: row.id, approved_at: (0, typeorm_1.IsNull)(), denied_at: (0, typeorm_1.IsNull)() }, { denied_at: new Date(), approved_by_user_id: user.id });
186
+ if (!denied.affected) {
187
+ return { status: 'already_decided', redirect_to: this.errorRedirect(row, 'access_denied', 'Already decided') };
188
+ }
189
+ return { status: 'denied', redirect_to: this.errorRedirect(row, 'access_denied') };
190
+ }
191
+ const business = await this.resolveBusiness(businessId);
192
+ const code = oauth_pkce_1.OauthPkce.randomToken(32);
193
+ const claimed = await oauth_authorization_entity_1.OauthAuthorizationEntity.update({ id: row.id, approved_at: (0, typeorm_1.IsNull)(), denied_at: (0, typeorm_1.IsNull)() }, {
194
+ approved_at: new Date(),
195
+ approved_by_user_id: user.id,
196
+ business_id: business.id,
197
+ code_hash: oauth_pkce_1.OauthPkce.sha256Hex(code),
198
+ expires_at: new Date(Date.now() + CODE_TTL_MS),
199
+ });
200
+ if (!claimed.affected) {
201
+ return { status: 'already_decided', redirect_to: this.errorRedirect(row, 'access_denied', 'Already decided') };
202
+ }
203
+ const url = new URL(row.redirect_uri);
204
+ url.searchParams.set('code', code);
205
+ if (row.state)
206
+ url.searchParams.set('state', row.state);
207
+ url.searchParams.set('iss', this.issuer());
208
+ return { status: 'approved', redirect_to: url.toString() };
209
+ }
210
+ async exchangeToken(body) {
211
+ if (body.grant_type !== 'authorization_code') {
212
+ throw new OauthProtocolError('unsupported_grant_type', 'Only authorization_code is supported');
213
+ }
214
+ const code = body.code?.trim();
215
+ const redirectUri = body.redirect_uri?.trim();
216
+ const codeVerifier = body.code_verifier?.trim();
217
+ if (!code || !redirectUri || !codeVerifier) {
218
+ throw new OauthProtocolError('invalid_request', 'code, redirect_uri, and code_verifier are required');
219
+ }
220
+ const row = await oauth_authorization_entity_1.OauthAuthorizationEntity.findOne({ where: { code_hash: oauth_pkce_1.OauthPkce.sha256Hex(code) } });
221
+ if (!row || !row.approved_at || !row.approved_by_user_id) {
222
+ throw new OauthProtocolError('invalid_grant', 'Invalid authorization code');
223
+ }
224
+ if (row.consumed_at)
225
+ throw new OauthProtocolError('invalid_grant', 'Authorization code already used');
226
+ if (row.expires_at.getTime() <= Date.now())
227
+ throw new OauthProtocolError('invalid_grant', 'Authorization code expired');
228
+ if (redirectUri !== row.redirect_uri)
229
+ throw new OauthProtocolError('invalid_grant', 'redirect_uri mismatch');
230
+ if (body.client_id && body.client_id !== row.client_id) {
231
+ throw new OauthProtocolError('invalid_grant', 'client_id mismatch');
232
+ }
233
+ if (oauth_pkce_1.OauthPkce.s256Base64Url(codeVerifier) !== row.code_challenge) {
234
+ throw new OauthProtocolError('invalid_grant', 'PKCE verification failed');
235
+ }
236
+ const claimed = await oauth_authorization_entity_1.OauthAuthorizationEntity.update({ id: row.id, consumed_at: (0, typeorm_1.IsNull)() }, { consumed_at: new Date() });
237
+ if (!claimed.affected)
238
+ throw new OauthProtocolError('invalid_grant', 'Authorization code already used');
239
+ const minted = await this.mintPersonalKey(row);
240
+ return {
241
+ access_token: minted.access_token,
242
+ token_type: 'Bearer',
243
+ scope: row.scope || DEFAULT_SCOPE,
244
+ };
245
+ }
246
+ async mintPersonalKey(row) {
247
+ if (!row.approved_by_user_id || !row.business_id) {
248
+ throw new OauthProtocolError('server_error', 'Authorization missing approver or business', 500);
249
+ }
250
+ const business = await access_business_entity_1.AccessBusinessEntity.findOne({ where: { id: row.business_id } });
251
+ if (!business)
252
+ throw new OauthProtocolError('server_error', 'Business no longer exists', 500);
253
+ nestjs_utility_services_1.Auth.login({ id: row.approved_by_user_id, auth_attributes: { business_id: business.id } });
254
+ const name = `MCP · browser connect · ${new Date().toISOString().slice(0, 16)}`;
255
+ const secret = await new create_user_business_secret_1.CreateUserBusinessSecret(business).process({ name });
256
+ row.user_secret_id = secret.id;
257
+ await row.save();
258
+ return {
259
+ access_token: extract_client_credentials_1.ExtractClientCredentials.formatPersonalAccessToken(secret.client_id, secret.client_secret),
260
+ client_id: secret.client_id,
261
+ client_secret: secret.client_secret,
262
+ };
263
+ }
264
+ async resolveBusiness(businessId) {
265
+ if (businessId) {
266
+ const business = await access_business_entity_1.AccessBusinessEntity.findOne({ where: { id: businessId } });
267
+ if (!business)
268
+ throw new nestjs_utility_services_1.OperationException('Unknown business_id.');
269
+ return business;
270
+ }
271
+ return this.accessBusinessService.validateAccess();
272
+ }
273
+ errorRedirect(row, error, description) {
274
+ const url = new URL(row.redirect_uri);
275
+ url.searchParams.set('error', error);
276
+ if (description)
277
+ url.searchParams.set('error_description', description);
278
+ if (row.state)
279
+ url.searchParams.set('state', row.state);
280
+ return url.toString();
281
+ }
282
+ frontendBase() {
283
+ return (process.env.FRONTEND_URL || process.env.SERVER_URL || 'http://localhost:3000').replace(/\/+$/, '');
284
+ }
285
+ buildAuthorizeReturnUrl(query) {
286
+ const url = new URL(`${this.issuer()}/oauth/authorize`);
287
+ for (const [key, value] of Object.entries(query)) {
288
+ if (value !== undefined && value !== null && value !== '')
289
+ url.searchParams.set(key, value);
290
+ }
291
+ return url.toString();
292
+ }
293
+ };
294
+ exports.OauthAsService = OauthAsService;
295
+ exports.OauthAsService = OauthAsService = __decorate([
296
+ (0, common_1.Injectable)(),
297
+ __metadata("design:paramtypes", [access_business_service_1.AccessBusinessService])
298
+ ], OauthAsService);
299
+ //# sourceMappingURL=oauth.as.service.js.map