@casual-simulation/aux-records 3.4.6-alpha.14668890889 → 3.5.0-alpha.15119114602

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 (211) hide show
  1. package/AIController.js +835 -890
  2. package/AIController.js.map +1 -1
  3. package/AIHumeInterface.js +43 -54
  4. package/AIHumeInterface.js.map +1 -1
  5. package/AIOpenAIRealtimeInterface.js +60 -71
  6. package/AIOpenAIRealtimeInterface.js.map +1 -1
  7. package/AnthropicAIChatInterface.js +96 -142
  8. package/AnthropicAIChatInterface.js.map +1 -1
  9. package/AuthController.d.ts +3 -2
  10. package/AuthController.js +1907 -1933
  11. package/AuthController.js.map +1 -1
  12. package/AuthStore.d.ts +1 -10
  13. package/BlockadeLabsGenerateSkyboxInterface.js +57 -72
  14. package/BlockadeLabsGenerateSkyboxInterface.js.map +1 -1
  15. package/CachingConfigStore.js +30 -45
  16. package/CachingConfigStore.js.map +1 -1
  17. package/CachingPolicyStore.d.ts +8 -2
  18. package/CachingPolicyStore.js +108 -135
  19. package/CachingPolicyStore.js.map +1 -1
  20. package/ComIdConfig.d.ts +18 -18
  21. package/ComIdConfig.js.map +1 -1
  22. package/ConsoleAuthMessenger.js +7 -20
  23. package/ConsoleAuthMessenger.js.map +1 -1
  24. package/DataRecordsController.d.ts +2 -2
  25. package/DataRecordsController.js +369 -377
  26. package/DataRecordsController.js.map +1 -1
  27. package/DataRecordsStore.d.ts +1 -1
  28. package/DataRecordsStore.js +1 -1
  29. package/DataRecordsStore.js.map +1 -1
  30. package/EventRecordsController.js +226 -240
  31. package/EventRecordsController.js.map +1 -1
  32. package/FileRecordsController.d.ts +13 -2
  33. package/FileRecordsController.js +458 -450
  34. package/FileRecordsController.js.map +1 -1
  35. package/GoogleAIChatInterface.js +133 -179
  36. package/GoogleAIChatInterface.js.map +1 -1
  37. package/LivekitController.js +43 -54
  38. package/LivekitController.js.map +1 -1
  39. package/LoomController.js +64 -75
  40. package/LoomController.js.map +1 -1
  41. package/MemoryAuthMessenger.js +10 -23
  42. package/MemoryAuthMessenger.js.map +1 -1
  43. package/MemoryCache.js +18 -35
  44. package/MemoryCache.js.map +1 -1
  45. package/MemoryFileRecordsLookup.js +105 -125
  46. package/MemoryFileRecordsLookup.js.map +1 -1
  47. package/MemoryModerationJobProvider.js +17 -30
  48. package/MemoryModerationJobProvider.js.map +1 -1
  49. package/MemoryRateLimiter.js +12 -27
  50. package/MemoryRateLimiter.js.map +1 -1
  51. package/MemoryStore.d.ts +18 -6
  52. package/MemoryStore.js +1879 -1997
  53. package/MemoryStore.js.map +1 -1
  54. package/MetricsStore.d.ts +2 -2
  55. package/ModerationController.js +186 -200
  56. package/ModerationController.js.map +1 -1
  57. package/OpenAIChatInterface.js +105 -135
  58. package/OpenAIChatInterface.js.map +1 -1
  59. package/OpenAIImageInterface.js +57 -51
  60. package/OpenAIImageInterface.js.map +1 -1
  61. package/PolicyController.d.ts +150 -10
  62. package/PolicyController.js +1546 -1299
  63. package/PolicyController.js.map +1 -1
  64. package/PolicyStore.d.ts +110 -2
  65. package/PolicyStore.js +36 -1
  66. package/PolicyStore.js.map +1 -1
  67. package/PrivoClient.js +398 -435
  68. package/PrivoClient.js.map +1 -1
  69. package/RateLimitController.js +25 -36
  70. package/RateLimitController.js.map +1 -1
  71. package/RecordsClient.js +51 -74
  72. package/RecordsClient.js.map +1 -1
  73. package/RecordsController.d.ts +2 -42
  74. package/RecordsController.js +1026 -1182
  75. package/RecordsController.js.map +1 -1
  76. package/RecordsServer.d.ts +196 -27
  77. package/RecordsServer.js +1701 -1343
  78. package/RecordsServer.js.map +1 -1
  79. package/RecordsStore.d.ts +1 -10
  80. package/RecordsStore.js.map +1 -1
  81. package/ServerConfig.d.ts +339 -195
  82. package/ServerConfig.js +13 -0
  83. package/ServerConfig.js.map +1 -1
  84. package/SloydInterface.js +62 -75
  85. package/SloydInterface.js.map +1 -1
  86. package/StabilityAIImageInterface.js +150 -167
  87. package/StabilityAIImageInterface.js.map +1 -1
  88. package/SubscriptionConfigBuilder.d.ts +6 -1
  89. package/SubscriptionConfigBuilder.js +22 -0
  90. package/SubscriptionConfigBuilder.js.map +1 -1
  91. package/SubscriptionConfiguration.d.ts +266 -169
  92. package/SubscriptionConfiguration.js +101 -79
  93. package/SubscriptionConfiguration.js.map +1 -1
  94. package/SubscriptionController.d.ts +2 -1
  95. package/SubscriptionController.js +643 -650
  96. package/SubscriptionController.js.map +1 -1
  97. package/SystemNotificationMessenger.d.ts +21 -4
  98. package/SystemNotificationMessenger.js +36 -30
  99. package/SystemNotificationMessenger.js.map +1 -1
  100. package/TestUtils.d.ts +9 -1
  101. package/TestUtils.js +105 -129
  102. package/TestUtils.js.map +1 -1
  103. package/Utils.d.ts +2 -16
  104. package/Utils.js +21 -22
  105. package/Utils.js.map +1 -1
  106. package/crud/CrudHelpers.js +17 -26
  107. package/crud/CrudHelpers.js.map +1 -1
  108. package/crud/CrudRecordsController.d.ts +1 -1
  109. package/crud/CrudRecordsController.js +259 -267
  110. package/crud/CrudRecordsController.js.map +1 -1
  111. package/crud/CrudRecordsControllerTests.js +174 -185
  112. package/crud/CrudRecordsControllerTests.js.map +1 -1
  113. package/crud/CrudRecordsStore.d.ts +7 -3
  114. package/crud/MemoryCrudRecordsStore.d.ts +4 -4
  115. package/crud/MemoryCrudRecordsStore.js +98 -118
  116. package/crud/MemoryCrudRecordsStore.js.map +1 -1
  117. package/crud/sub/MemorySubCrudRecordsStore.d.ts +24 -0
  118. package/crud/sub/MemorySubCrudRecordsStore.js +146 -0
  119. package/crud/sub/MemorySubCrudRecordsStore.js.map +1 -0
  120. package/crud/sub/SubCrudRecordsController.d.ts +182 -0
  121. package/crud/sub/SubCrudRecordsController.js +360 -0
  122. package/crud/sub/SubCrudRecordsController.js.map +1 -0
  123. package/crud/sub/SubCrudRecordsControllerTests.d.ts +39 -0
  124. package/crud/sub/SubCrudRecordsControllerTests.js +821 -0
  125. package/crud/sub/SubCrudRecordsControllerTests.js.map +1 -0
  126. package/crud/sub/SubCrudRecordsStore.d.ts +95 -0
  127. package/{forms/index.js → crud/sub/SubCrudRecordsStore.js} +2 -2
  128. package/crud/sub/SubCrudRecordsStore.js.map +1 -0
  129. package/crud/sub/index.d.ts +3 -0
  130. package/crud/sub/index.js +20 -0
  131. package/{forms → crud/sub}/index.js.map +1 -1
  132. package/index.d.ts +1 -1
  133. package/index.js +1 -1
  134. package/index.js.map +1 -1
  135. package/notifications/MemoryNotificationRecordsStore.js +189 -198
  136. package/notifications/MemoryNotificationRecordsStore.js.map +1 -1
  137. package/notifications/NotificationRecordsController.js +438 -460
  138. package/notifications/NotificationRecordsController.js.map +1 -1
  139. package/notifications/NotificationRecordsStore.d.ts +2 -1
  140. package/notifications/WebPushInterface.d.ts +0 -1
  141. package/notifications/WebPushInterface.js +0 -1
  142. package/notifications/WebPushInterface.js.map +1 -1
  143. package/package.json +6 -6
  144. package/packages/MemoryPackageRecordsStore.d.ts +10 -0
  145. package/packages/MemoryPackageRecordsStore.js +38 -0
  146. package/packages/MemoryPackageRecordsStore.js.map +1 -0
  147. package/packages/PackageRecordsController.d.ts +26 -0
  148. package/packages/PackageRecordsController.js +49 -0
  149. package/packages/PackageRecordsController.js.map +1 -0
  150. package/packages/PackageRecordsStore.d.ts +32 -0
  151. package/packages/PackageRecordsStore.js +19 -0
  152. package/packages/PackageRecordsStore.js.map +1 -0
  153. package/packages/index.d.ts +4 -0
  154. package/packages/index.js +21 -0
  155. package/packages/index.js.map +1 -0
  156. package/packages/version/MemoryPackageVersionRecordsStore.d.ts +21 -0
  157. package/packages/version/MemoryPackageVersionRecordsStore.js +177 -0
  158. package/packages/version/MemoryPackageVersionRecordsStore.js.map +1 -0
  159. package/packages/version/PackageVersionRecordsController.d.ts +144 -0
  160. package/packages/version/PackageVersionRecordsController.js +656 -0
  161. package/packages/version/PackageVersionRecordsController.js.map +1 -0
  162. package/packages/version/PackageVersionRecordsStore.d.ts +342 -0
  163. package/packages/version/PackageVersionRecordsStore.js +126 -0
  164. package/packages/version/PackageVersionRecordsStore.js.map +1 -0
  165. package/packages/version/index.d.ts +4 -0
  166. package/packages/version/index.js +21 -0
  167. package/packages/version/index.js.map +1 -0
  168. package/tracing/TracingDecorators.js +31 -40
  169. package/tracing/TracingDecorators.js.map +1 -1
  170. package/webhooks/MemoryWebhookRecordsStore.js +56 -72
  171. package/webhooks/MemoryWebhookRecordsStore.js.map +1 -1
  172. package/webhooks/WebhookEnvironment.d.ts +3 -3
  173. package/webhooks/WebhookRecordsController.d.ts +2 -1
  174. package/webhooks/WebhookRecordsController.js +389 -382
  175. package/webhooks/WebhookRecordsController.js.map +1 -1
  176. package/webhooks/WebhookRecordsStore.d.ts +2 -1
  177. package/websockets/InstRecordsStore.d.ts +50 -0
  178. package/websockets/InstRecordsStore.js +17 -0
  179. package/websockets/InstRecordsStore.js.map +1 -1
  180. package/websockets/MemoryTempInstRecordsStore.d.ts +5 -0
  181. package/websockets/MemoryTempInstRecordsStore.js +168 -179
  182. package/websockets/MemoryTempInstRecordsStore.js.map +1 -1
  183. package/websockets/MemoryWebsocketConnectionStore.js +98 -135
  184. package/websockets/MemoryWebsocketConnectionStore.js.map +1 -1
  185. package/websockets/MemoryWebsocketMessenger.js +29 -48
  186. package/websockets/MemoryWebsocketMessenger.js.map +1 -1
  187. package/websockets/SplitInstRecordsStore.d.ts +4 -1
  188. package/websockets/SplitInstRecordsStore.js +167 -185
  189. package/websockets/SplitInstRecordsStore.js.map +1 -1
  190. package/websockets/TemporaryInstRecordsStore.d.ts +19 -1
  191. package/websockets/TemporaryInstRecordsStore.js +17 -0
  192. package/websockets/TemporaryInstRecordsStore.js.map +1 -1
  193. package/websockets/WebsocketController.d.ts +147 -3
  194. package/websockets/WebsocketController.js +1735 -1391
  195. package/websockets/WebsocketController.js.map +1 -1
  196. package/websockets/index.d.ts +0 -1
  197. package/websockets/index.js +0 -1
  198. package/websockets/index.js.map +1 -1
  199. package/AAGUID.d.ts +0 -11
  200. package/AAGUID.js +0 -116
  201. package/AAGUID.js.map +0 -1
  202. package/AuthUtils.d.ts +0 -162
  203. package/AuthUtils.js +0 -327
  204. package/AuthUtils.js.map +0 -1
  205. package/forms/FormError.d.ts +0 -43
  206. package/forms/FormError.js +0 -56
  207. package/forms/FormError.js.map +0 -1
  208. package/forms/index.d.ts +0 -2
  209. package/websockets/Utils.d.ts +0 -33
  210. package/websockets/Utils.js +0 -82
  211. package/websockets/Utils.js.map +0 -1
package/AuthController.js CHANGED
@@ -4,34 +4,13 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  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;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
8
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
9
- return new (P || (P = Promise))(function (resolve, reject) {
10
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
11
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
12
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
13
- step((generator = generator.apply(thisArg, _arguments || [])).next());
14
- });
15
- };
16
- var __rest = (this && this.__rest) || function (s, e) {
17
- var t = {};
18
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
19
- t[p] = s[p];
20
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
21
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
22
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
23
- t[p[i]] = s[p[i]];
24
- }
25
- return t;
26
- };
27
7
  import { v4 as uuid } from 'uuid';
28
8
  import { randomBytes } from 'tweetnacl';
29
9
  import { hashHighEntropyPasswordWithSalt, hashLowEntropyPasswordWithSalt, verifyPasswordAgainstHashes, } from './InstrumentedHashHelpers';
30
10
  import { fromByteArray } from 'base64-js';
31
11
  import { cleanupObject, isActiveSubscription, isStringValid } from './Utils';
32
- import { formatV1ConnectionKey, formatV1SessionKey, isSuperUserRole, parseSessionKey, verifyConnectionToken, } from './AuthUtils';
33
12
  import { randomCode } from './CryptoUtils';
34
- import { parseConnectionToken } from '@casual-simulation/aux-common';
13
+ import { parseConnectionToken, formatV1ConnectionKey, formatV1SessionKey, isSuperUserRole, parseSessionKey, verifyConnectionToken, } from '@casual-simulation/aux-common';
35
14
  import { DateTime } from 'luxon';
36
15
  import { generateAuthenticationOptions, generateRegistrationOptions, verifyAuthenticationResponse, verifyRegistrationResponse, } from '@simplewebauthn/server';
37
16
  import { base64URLStringToBuffer, bufferToBase64URLString, } from './Base64UrlUtils';
@@ -135,2191 +114,2176 @@ export class AuthController {
135
114
  set privoEnabled(value) {
136
115
  this._privoEnabled = value;
137
116
  }
138
- createAccount(request) {
117
+ async createAccount(request) {
139
118
  var _a;
140
- return __awaiter(this, void 0, void 0, function* () {
141
- try {
142
- const createSession = (_a = request.createSession) !== null && _a !== void 0 ? _a : true;
143
- if (!isSuperUserRole(request.userRole)) {
144
- return {
145
- success: false,
146
- errorCode: 'not_authorized',
147
- errorMessage: 'You are not authorized to perform this action.',
148
- };
149
- }
150
- const newUser = {
151
- id: uuid(),
152
- email: null,
153
- phoneNumber: null,
154
- allSessionRevokeTimeMs: null,
155
- currentLoginRequestId: null,
156
- };
157
- const result = yield this._store.saveNewUser(newUser);
158
- if (result.success === false) {
159
- return result;
160
- }
161
- if (createSession) {
162
- const { info } = yield this._issueSession({
163
- userId: newUser.id,
164
- lifetimeMs: null,
165
- ipAddress: request.ipAddress,
166
- revocable: false,
167
- });
168
- return Object.assign({ success: true }, info);
169
- }
170
- else {
171
- return {
172
- success: true,
173
- userId: newUser.id,
174
- sessionKey: null,
175
- connectionKey: null,
176
- expireTimeMs: null,
177
- metadata: {
178
- hasUserAuthenticator: false,
179
- userAuthenticatorCredentialIds: [],
180
- hasPushSubscription: false,
181
- pushSubscriptionIds: [],
182
- },
183
- };
184
- }
185
- }
186
- catch (err) {
187
- const span = trace.getActiveSpan();
188
- span === null || span === void 0 ? void 0 : span.recordException(err);
189
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
190
- console.error('[AuthController] Error occurred while creating account', err);
119
+ try {
120
+ const createSession = (_a = request.createSession) !== null && _a !== void 0 ? _a : true;
121
+ if (!isSuperUserRole(request.userRole)) {
191
122
  return {
192
123
  success: false,
193
- errorCode: 'server_error',
194
- errorMessage: 'A server error occurred.',
124
+ errorCode: 'not_authorized',
125
+ errorMessage: 'You are not authorized to perform this action.',
195
126
  };
196
127
  }
197
- });
198
- }
199
- issueSession(request) {
200
- return __awaiter(this, void 0, void 0, function* () {
201
- try {
202
- if (request.requestingUserRole !== 'system') {
203
- return {
204
- success: false,
205
- errorCode: 'not_authorized',
206
- errorMessage: 'You are not authorized to perform this action.',
207
- };
208
- }
209
- const lifetimeMs = request.lifetimeMs === undefined
210
- ? SESSION_LIFETIME_MS
211
- : request.lifetimeMs;
212
- const { info } = yield this._issueSession({
213
- userId: request.userId,
214
- lifetimeMs,
128
+ const newUser = {
129
+ id: uuid(),
130
+ email: null,
131
+ phoneNumber: null,
132
+ allSessionRevokeTimeMs: null,
133
+ currentLoginRequestId: null,
134
+ };
135
+ const result = await this._store.saveNewUser(newUser);
136
+ if (result.success === false) {
137
+ return result;
138
+ }
139
+ if (createSession) {
140
+ const { info } = await this._issueSession({
141
+ userId: newUser.id,
142
+ lifetimeMs: null,
215
143
  ipAddress: request.ipAddress,
144
+ revocable: false,
216
145
  });
217
- return Object.assign({ success: true }, info);
146
+ return {
147
+ success: true,
148
+ ...info,
149
+ };
218
150
  }
219
- catch (err) {
220
- const span = trace.getActiveSpan();
221
- span === null || span === void 0 ? void 0 : span.recordException(err);
222
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
223
- console.error('[AuthController] Error occurred while issuing session', err);
151
+ else {
224
152
  return {
225
- success: false,
226
- errorCode: 'server_error',
227
- errorMessage: 'A server error occurred.',
153
+ success: true,
154
+ userId: newUser.id,
155
+ sessionKey: null,
156
+ connectionKey: null,
157
+ expireTimeMs: null,
158
+ metadata: {
159
+ hasUserAuthenticator: false,
160
+ userAuthenticatorCredentialIds: [],
161
+ hasPushSubscription: false,
162
+ pushSubscriptionIds: [],
163
+ },
228
164
  };
229
165
  }
230
- });
166
+ }
167
+ catch (err) {
168
+ const span = trace.getActiveSpan();
169
+ span === null || span === void 0 ? void 0 : span.recordException(err);
170
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
171
+ console.error('[AuthController] Error occurred while creating account', err);
172
+ return {
173
+ success: false,
174
+ errorCode: 'server_error',
175
+ errorMessage: 'A server error occurred.',
176
+ };
177
+ }
178
+ }
179
+ async issueSession(request) {
180
+ try {
181
+ if (request.requestingUserRole !== 'system') {
182
+ return {
183
+ success: false,
184
+ errorCode: 'not_authorized',
185
+ errorMessage: 'You are not authorized to perform this action.',
186
+ };
187
+ }
188
+ const lifetimeMs = request.lifetimeMs === undefined
189
+ ? SESSION_LIFETIME_MS
190
+ : request.lifetimeMs;
191
+ const { info } = await this._issueSession({
192
+ userId: request.userId,
193
+ lifetimeMs,
194
+ ipAddress: request.ipAddress,
195
+ });
196
+ return {
197
+ success: true,
198
+ ...info,
199
+ };
200
+ }
201
+ catch (err) {
202
+ const span = trace.getActiveSpan();
203
+ span === null || span === void 0 ? void 0 : span.recordException(err);
204
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
205
+ console.error('[AuthController] Error occurred while issuing session', err);
206
+ return {
207
+ success: false,
208
+ errorCode: 'server_error',
209
+ errorMessage: 'A server error occurred.',
210
+ };
211
+ }
231
212
  }
232
213
  _hashHighEntropyPasswordWithSalt(sessionSecret, sessionId) {
233
214
  return hashHighEntropyPasswordWithSalt(sessionSecret, sessionId);
234
215
  }
235
- requestLogin(request) {
236
- return __awaiter(this, void 0, void 0, function* () {
237
- if (typeof request.address !== 'string' || request.address === '') {
216
+ async requestLogin(request) {
217
+ if (typeof request.address !== 'string' || request.address === '') {
218
+ return {
219
+ success: false,
220
+ errorCode: 'unacceptable_address',
221
+ errorMessage: 'The given address is invalid. It must be a string.',
222
+ };
223
+ }
224
+ else if (typeof request.addressType !== 'string' ||
225
+ !(request.addressType === 'email' ||
226
+ request.addressType === 'phone')) {
227
+ return {
228
+ success: false,
229
+ errorCode: 'unacceptable_address_type',
230
+ errorMessage: 'The given address type is invalid. It must be a string containing either "email" or "phone".',
231
+ };
232
+ }
233
+ else if (typeof request.ipAddress !== 'string' ||
234
+ request.ipAddress === '') {
235
+ return {
236
+ success: false,
237
+ errorCode: 'unacceptable_ip_address',
238
+ errorMessage: 'The given IP address is invalid. It must be a string.',
239
+ };
240
+ }
241
+ if (request.addressType === 'email') {
242
+ if (request.address.length > MAX_EMAIL_ADDRESS_LENGTH) {
238
243
  return {
239
244
  success: false,
240
245
  errorCode: 'unacceptable_address',
241
- errorMessage: 'The given address is invalid. It must be a string.',
246
+ errorMessage: `The given email address is too long. It must be ${MAX_EMAIL_ADDRESS_LENGTH} characters or shorter in length.`,
242
247
  };
243
248
  }
244
- else if (typeof request.addressType !== 'string' ||
245
- !(request.addressType === 'email' ||
246
- request.addressType === 'phone')) {
249
+ }
250
+ else if (request.addressType === 'phone') {
251
+ if (request.address.length > MAX_SMS_ADDRESS_LENGTH) {
247
252
  return {
248
253
  success: false,
249
- errorCode: 'unacceptable_address_type',
250
- errorMessage: 'The given address type is invalid. It must be a string containing either "email" or "phone".',
254
+ errorCode: 'unacceptable_address',
255
+ errorMessage: `The given SMS address is too long. It must be ${MAX_SMS_ADDRESS_LENGTH} digits or shorter in length.`,
251
256
  };
252
257
  }
253
- else if (typeof request.ipAddress !== 'string' ||
254
- request.ipAddress === '') {
258
+ }
259
+ try {
260
+ let newUser = false;
261
+ const supported = await this._messenger.supportsAddressType(request.addressType);
262
+ if (!supported) {
255
263
  return {
256
264
  success: false,
257
- errorCode: 'unacceptable_ip_address',
258
- errorMessage: 'The given IP address is invalid. It must be a string.',
265
+ errorCode: 'address_type_not_supported',
266
+ errorMessage: request.addressType === 'email'
267
+ ? 'Email addresses are not supported.'
268
+ : 'Phone numbers are not supported',
259
269
  };
260
270
  }
261
- if (request.addressType === 'email') {
262
- if (request.address.length > MAX_EMAIL_ADDRESS_LENGTH) {
263
- return {
264
- success: false,
265
- errorCode: 'unacceptable_address',
266
- errorMessage: `The given email address is too long. It must be ${MAX_EMAIL_ADDRESS_LENGTH} characters or shorter in length.`,
267
- };
268
- }
269
- }
270
- else if (request.addressType === 'phone') {
271
- if (request.address.length > MAX_SMS_ADDRESS_LENGTH) {
271
+ let user = await this._store.findUserByAddress(request.address, request.addressType);
272
+ if (!user) {
273
+ newUser = true;
274
+ user = {
275
+ id: uuid(),
276
+ email: request.addressType === 'email'
277
+ ? request.address
278
+ : null,
279
+ phoneNumber: request.addressType === 'phone'
280
+ ? request.address
281
+ : null,
282
+ allSessionRevokeTimeMs: null,
283
+ currentLoginRequestId: null,
284
+ };
285
+ if (!(await this._validateAddress(request.address, request.addressType))) {
286
+ console.log(`[AuthController] [requestLogin] Login attempt rejected for new user with address (type: ${request.addressType}) that is not allowed.`);
272
287
  return {
273
288
  success: false,
274
289
  errorCode: 'unacceptable_address',
275
- errorMessage: `The given SMS address is too long. It must be ${MAX_SMS_ADDRESS_LENGTH} digits or shorter in length.`,
290
+ errorMessage: 'The given address is not accepted.',
276
291
  };
277
292
  }
278
293
  }
279
- try {
280
- let newUser = false;
281
- const supported = yield this._messenger.supportsAddressType(request.addressType);
282
- if (!supported) {
283
- return {
284
- success: false,
285
- errorCode: 'address_type_not_supported',
286
- errorMessage: request.addressType === 'email'
287
- ? 'Email addresses are not supported.'
288
- : 'Phone numbers are not supported',
289
- };
290
- }
291
- let user = yield this._store.findUserByAddress(request.address, request.addressType);
292
- if (!user) {
293
- newUser = true;
294
- user = {
295
- id: uuid(),
296
- email: request.addressType === 'email'
297
- ? request.address
298
- : null,
299
- phoneNumber: request.addressType === 'phone'
300
- ? request.address
301
- : null,
302
- allSessionRevokeTimeMs: null,
303
- currentLoginRequestId: null,
304
- };
305
- if (!(yield this._validateAddress(request.address, request.addressType))) {
306
- console.log(`[AuthController] [requestLogin] Login attempt rejected for new user with address (type: ${request.addressType}) that is not allowed.`);
307
- return {
308
- success: false,
309
- errorCode: 'unacceptable_address',
310
- errorMessage: 'The given address is not accepted.',
311
- };
294
+ if (user.banTimeMs > 0) {
295
+ return {
296
+ success: false,
297
+ errorCode: 'user_is_banned',
298
+ errorMessage: 'The user has been banned.',
299
+ banReason: user.banReason,
300
+ };
301
+ }
302
+ const requestTime = Date.now();
303
+ const requestId = fromByteArray(randomBytes(LOGIN_REQUEST_ID_BYTE_LENGTH));
304
+ const code = randomCode();
305
+ const hash = hashLowEntropyPasswordWithSalt(code, requestId);
306
+ const loginRequest = {
307
+ userId: user.id,
308
+ requestId: requestId,
309
+ secretHash: hash,
310
+ address: request.address,
311
+ addressType: request.addressType,
312
+ attemptCount: 0,
313
+ requestTimeMs: requestTime,
314
+ expireTimeMs: requestTime + LOGIN_REQUEST_LIFETIME_MS,
315
+ completedTimeMs: null,
316
+ ipAddress: request.ipAddress,
317
+ };
318
+ const result = await this._messenger.sendCode(loginRequest.address, loginRequest.addressType, code);
319
+ if (result.success === true) {
320
+ if (newUser) {
321
+ const result = await this._store.saveNewUser(user);
322
+ if (result.success === false) {
323
+ user = await this._store.findUserByAddress(request.address, request.addressType);
324
+ if (!user) {
325
+ console.log('[AuthController] Could not find user even though it is supposed to already exist.');
326
+ return {
327
+ success: false,
328
+ errorCode: 'server_error',
329
+ errorMessage: 'The server encountered an error.',
330
+ };
331
+ }
332
+ loginRequest.userId = user.id;
312
333
  }
313
334
  }
314
- if (user.banTimeMs > 0) {
315
- return {
316
- success: false,
317
- errorCode: 'user_is_banned',
318
- errorMessage: 'The user has been banned.',
319
- banReason: user.banReason,
320
- };
321
- }
322
- const requestTime = Date.now();
323
- const requestId = fromByteArray(randomBytes(LOGIN_REQUEST_ID_BYTE_LENGTH));
324
- const code = randomCode();
325
- const hash = hashLowEntropyPasswordWithSalt(code, requestId);
326
- const loginRequest = {
327
- userId: user.id,
328
- requestId: requestId,
329
- secretHash: hash,
335
+ await this._store.saveLoginRequest(loginRequest);
336
+ await this._store.setCurrentLoginRequest(loginRequest.userId, loginRequest.requestId);
337
+ return {
338
+ success: true,
339
+ requestId: loginRequest.requestId,
340
+ userId: loginRequest.userId,
330
341
  address: request.address,
331
342
  addressType: request.addressType,
332
- attemptCount: 0,
333
- requestTimeMs: requestTime,
334
- expireTimeMs: requestTime + LOGIN_REQUEST_LIFETIME_MS,
335
- completedTimeMs: null,
336
- ipAddress: request.ipAddress,
343
+ expireTimeMs: loginRequest.expireTimeMs,
337
344
  };
338
- const result = yield this._messenger.sendCode(loginRequest.address, loginRequest.addressType, code);
339
- if (result.success === true) {
340
- if (newUser) {
341
- const result = yield this._store.saveNewUser(user);
342
- if (result.success === false) {
343
- user = yield this._store.findUserByAddress(request.address, request.addressType);
344
- if (!user) {
345
- console.log('[AuthController] Could not find user even though it is supposed to already exist.');
346
- return {
347
- success: false,
348
- errorCode: 'server_error',
349
- errorMessage: 'The server encountered an error.',
350
- };
351
- }
352
- loginRequest.userId = user.id;
353
- }
354
- }
355
- yield this._store.saveLoginRequest(loginRequest);
356
- yield this._store.setCurrentLoginRequest(loginRequest.userId, loginRequest.requestId);
357
- return {
358
- success: true,
359
- requestId: loginRequest.requestId,
360
- userId: loginRequest.userId,
361
- address: request.address,
362
- addressType: request.addressType,
363
- expireTimeMs: loginRequest.expireTimeMs,
364
- };
365
- }
366
- else {
367
- return {
368
- success: false,
369
- errorCode: result.errorCode,
370
- errorMessage: result.errorMessage,
371
- };
372
- }
373
345
  }
374
- catch (err) {
375
- const span = trace.getActiveSpan();
376
- span === null || span === void 0 ? void 0 : span.recordException(err);
377
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
378
- console.error('[AuthController] Error Occurred while Creating Login Request', err);
346
+ else {
379
347
  return {
380
348
  success: false,
381
- errorCode: 'server_error',
382
- errorMessage: 'A server error occurred.',
349
+ errorCode: result.errorCode,
350
+ errorMessage: result.errorMessage,
383
351
  };
384
352
  }
385
- });
353
+ }
354
+ catch (err) {
355
+ const span = trace.getActiveSpan();
356
+ span === null || span === void 0 ? void 0 : span.recordException(err);
357
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
358
+ console.error('[AuthController] Error Occurred while Creating Login Request', err);
359
+ return {
360
+ success: false,
361
+ errorCode: 'server_error',
362
+ errorMessage: 'A server error occurred.',
363
+ };
364
+ }
386
365
  }
387
- _validateAddress(address, addressType) {
388
- return __awaiter(this, void 0, void 0, function* () {
389
- try {
390
- const rules = addressType === 'email'
391
- ? yield this._store.listEmailRules()
392
- : yield this._store.listSmsRules();
393
- if (rules) {
394
- return isStringValid(address, rules);
395
- }
396
- else {
397
- return true;
398
- }
366
+ async _validateAddress(address, addressType) {
367
+ try {
368
+ const rules = addressType === 'email'
369
+ ? await this._store.listEmailRules()
370
+ : await this._store.listSmsRules();
371
+ if (rules) {
372
+ return isStringValid(address, rules);
399
373
  }
400
- catch (err) {
401
- console.error(`[AuthController] Error occurred while validating address`, err);
402
- return false;
374
+ else {
375
+ return true;
403
376
  }
404
- });
377
+ }
378
+ catch (err) {
379
+ console.error(`[AuthController] Error occurred while validating address`, err);
380
+ return false;
381
+ }
405
382
  }
406
- completeLogin(request) {
407
- return __awaiter(this, void 0, void 0, function* () {
408
- if (typeof request.userId !== 'string' || request.userId === '') {
383
+ async completeLogin(request) {
384
+ if (typeof request.userId !== 'string' || request.userId === '') {
385
+ return {
386
+ success: false,
387
+ errorCode: 'unacceptable_user_id',
388
+ errorMessage: 'The given userId is invalid. It must be a string.',
389
+ };
390
+ }
391
+ else if (typeof request.requestId !== 'string' ||
392
+ request.requestId === '') {
393
+ return {
394
+ success: false,
395
+ errorCode: 'unacceptable_request_id',
396
+ errorMessage: 'The given requestId is invalid. It must be a string.',
397
+ };
398
+ }
399
+ else if (typeof request.code !== 'string' || request.code === '') {
400
+ return {
401
+ success: false,
402
+ errorCode: 'unacceptable_code',
403
+ errorMessage: 'The given code is invalid. It must be a string.',
404
+ };
405
+ }
406
+ else if (typeof request.ipAddress !== 'string' ||
407
+ request.ipAddress === '') {
408
+ return {
409
+ success: false,
410
+ errorCode: 'unacceptable_ip_address',
411
+ errorMessage: 'The given IP address is invalid. It must be a string.',
412
+ };
413
+ }
414
+ try {
415
+ const loginRequest = await this._store.findLoginRequest(request.userId, request.requestId);
416
+ if (!loginRequest) {
409
417
  return {
410
418
  success: false,
411
- errorCode: 'unacceptable_user_id',
412
- errorMessage: 'The given userId is invalid. It must be a string.',
419
+ errorCode: 'invalid_request',
420
+ errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
413
421
  };
414
422
  }
415
- else if (typeof request.requestId !== 'string' ||
416
- request.requestId === '') {
423
+ let validRequest = true;
424
+ if (Date.now() >= loginRequest.expireTimeMs) {
425
+ validRequest = false;
426
+ }
427
+ else if (loginRequest.completedTimeMs > 0) {
428
+ validRequest = false;
429
+ }
430
+ else if (loginRequest.attemptCount >= MAX_LOGIN_REQUEST_ATTEMPTS) {
431
+ validRequest = false;
432
+ }
433
+ else if (loginRequest.ipAddress !== request.ipAddress) {
434
+ validRequest = false;
435
+ }
436
+ if (!validRequest) {
417
437
  return {
418
438
  success: false,
419
- errorCode: 'unacceptable_request_id',
420
- errorMessage: 'The given requestId is invalid. It must be a string.',
439
+ errorCode: 'invalid_request',
440
+ errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
421
441
  };
422
442
  }
423
- else if (typeof request.code !== 'string' || request.code === '') {
443
+ let validCode = false;
444
+ try {
445
+ if (this.verifyPasswordAgainstHashes(request.code, loginRequest.requestId, [loginRequest.secretHash])) {
446
+ validCode = true;
447
+ }
448
+ }
449
+ catch (err) {
450
+ console.error('[AuthController] Error occurred while verifying login request code', err);
451
+ }
452
+ if (!validCode) {
453
+ await this._store.incrementLoginRequestAttemptCount(loginRequest.userId, loginRequest.requestId);
424
454
  return {
425
455
  success: false,
426
- errorCode: 'unacceptable_code',
427
- errorMessage: 'The given code is invalid. It must be a string.',
456
+ errorCode: 'invalid_code',
457
+ errorMessage: 'The code is invalid.',
428
458
  };
429
459
  }
430
- else if (typeof request.ipAddress !== 'string' ||
431
- request.ipAddress === '') {
460
+ const user = await this._store.findUser(loginRequest.userId);
461
+ if (!user) {
432
462
  return {
433
463
  success: false,
434
- errorCode: 'unacceptable_ip_address',
435
- errorMessage: 'The given IP address is invalid. It must be a string.',
464
+ errorCode: 'invalid_request',
465
+ errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
436
466
  };
437
467
  }
438
- try {
439
- const loginRequest = yield this._store.findLoginRequest(request.userId, request.requestId);
440
- if (!loginRequest) {
441
- return {
442
- success: false,
443
- errorCode: 'invalid_request',
444
- errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
445
- };
446
- }
447
- let validRequest = true;
448
- if (Date.now() >= loginRequest.expireTimeMs) {
449
- validRequest = false;
450
- }
451
- else if (loginRequest.completedTimeMs > 0) {
452
- validRequest = false;
453
- }
454
- else if (loginRequest.attemptCount >= MAX_LOGIN_REQUEST_ATTEMPTS) {
455
- validRequest = false;
456
- }
457
- else if (loginRequest.ipAddress !== request.ipAddress) {
458
- validRequest = false;
459
- }
460
- if (!validRequest) {
461
- return {
462
- success: false,
463
- errorCode: 'invalid_request',
464
- errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
465
- };
466
- }
467
- let validCode = false;
468
- try {
469
- if (this.verifyPasswordAgainstHashes(request.code, loginRequest.requestId, [loginRequest.secretHash])) {
470
- validCode = true;
471
- }
472
- }
473
- catch (err) {
474
- console.error('[AuthController] Error occurred while verifying login request code', err);
475
- }
476
- if (!validCode) {
477
- yield this._store.incrementLoginRequestAttemptCount(loginRequest.userId, loginRequest.requestId);
478
- return {
479
- success: false,
480
- errorCode: 'invalid_code',
481
- errorMessage: 'The code is invalid.',
482
- };
483
- }
484
- const user = yield this._store.findUser(loginRequest.userId);
485
- if (!user) {
486
- return {
487
- success: false,
488
- errorCode: 'invalid_request',
489
- errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
490
- };
491
- }
492
- if (user.currentLoginRequestId !== loginRequest.requestId) {
493
- return {
494
- success: false,
495
- errorCode: 'invalid_request',
496
- errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
497
- };
498
- }
499
- const { info } = yield this._issueSession({
500
- userId: loginRequest.userId,
501
- lifetimeMs: SESSION_LIFETIME_MS,
502
- requestId: loginRequest.requestId,
503
- ipAddress: request.ipAddress,
504
- });
505
- return Object.assign({ success: true }, info);
506
- }
507
- catch (err) {
508
- const span = trace.getActiveSpan();
509
- span === null || span === void 0 ? void 0 : span.recordException(err);
510
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
511
- console.error('[AuthController] Error occurred while completing login request', err);
468
+ if (user.currentLoginRequestId !== loginRequest.requestId) {
512
469
  return {
513
470
  success: false,
514
- errorCode: 'server_error',
515
- errorMessage: 'A server error occurred.',
471
+ errorCode: 'invalid_request',
472
+ errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
516
473
  };
517
474
  }
518
- });
475
+ const { info } = await this._issueSession({
476
+ userId: loginRequest.userId,
477
+ lifetimeMs: SESSION_LIFETIME_MS,
478
+ requestId: loginRequest.requestId,
479
+ ipAddress: request.ipAddress,
480
+ });
481
+ return {
482
+ success: true,
483
+ ...info,
484
+ };
485
+ }
486
+ catch (err) {
487
+ const span = trace.getActiveSpan();
488
+ span === null || span === void 0 ? void 0 : span.recordException(err);
489
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
490
+ console.error('[AuthController] Error occurred while completing login request', err);
491
+ return {
492
+ success: false,
493
+ errorCode: 'server_error',
494
+ errorMessage: 'A server error occurred.',
495
+ };
496
+ }
519
497
  }
520
- requestOpenIDLogin(request) {
521
- return __awaiter(this, void 0, void 0, function* () {
522
- try {
523
- if (request.provider !== PRIVO_OPEN_ID_PROVIDER) {
524
- return {
525
- success: false,
526
- errorCode: 'not_supported',
527
- errorMessage: 'The given provider is not supported.',
528
- };
529
- }
530
- if (!this._privoClient) {
531
- return {
532
- success: false,
533
- errorCode: 'not_supported',
534
- errorMessage: 'Privo features are not supported on this server.',
535
- };
536
- }
537
- const config = yield this._config.getPrivoConfiguration();
538
- if (!config) {
539
- return {
540
- success: false,
541
- errorCode: 'not_supported',
542
- errorMessage: 'Privo features are not supported on this server.',
543
- };
544
- }
545
- const requestId = uuid();
546
- const state = uuid();
547
- const result = yield this._privoClient.generateAuthorizationUrl(state);
548
- const loginRequest = {
549
- requestId: requestId,
550
- state: state,
551
- provider: PRIVO_OPEN_ID_PROVIDER,
552
- codeMethod: result.codeMethod,
553
- codeVerifier: result.codeVerifier,
554
- authorizationUrl: result.authorizationUrl,
555
- redirectUrl: result.redirectUrl,
556
- completedTimeMs: null,
557
- ipAddress: request.ipAddress,
558
- scope: result.scope,
559
- requestTimeMs: Date.now(),
560
- expireTimeMs: Date.now() + OPEN_ID_LOGIN_REQUEST_LIFETIME_MS,
561
- };
562
- yield this._store.saveOpenIDLoginRequest(loginRequest);
498
+ async requestOpenIDLogin(request) {
499
+ try {
500
+ if (request.provider !== PRIVO_OPEN_ID_PROVIDER) {
563
501
  return {
564
- success: true,
565
- authorizationUrl: result.authorizationUrl,
566
- requestId: requestId,
502
+ success: false,
503
+ errorCode: 'not_supported',
504
+ errorMessage: 'The given provider is not supported.',
567
505
  };
568
506
  }
569
- catch (err) {
570
- const span = trace.getActiveSpan();
571
- span === null || span === void 0 ? void 0 : span.recordException(err);
572
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
573
- console.error('[AuthController] Error occurred while requesting Privo login', err);
507
+ if (!this._privoClient) {
574
508
  return {
575
509
  success: false,
576
- errorCode: 'server_error',
577
- errorMessage: 'A server error occurred.',
510
+ errorCode: 'not_supported',
511
+ errorMessage: 'Privo features are not supported on this server.',
578
512
  };
579
513
  }
580
- });
514
+ const config = await this._config.getPrivoConfiguration();
515
+ if (!config) {
516
+ return {
517
+ success: false,
518
+ errorCode: 'not_supported',
519
+ errorMessage: 'Privo features are not supported on this server.',
520
+ };
521
+ }
522
+ const requestId = uuid();
523
+ const state = uuid();
524
+ const result = await this._privoClient.generateAuthorizationUrl(state);
525
+ const loginRequest = {
526
+ requestId: requestId,
527
+ state: state,
528
+ provider: PRIVO_OPEN_ID_PROVIDER,
529
+ codeMethod: result.codeMethod,
530
+ codeVerifier: result.codeVerifier,
531
+ authorizationUrl: result.authorizationUrl,
532
+ redirectUrl: result.redirectUrl,
533
+ completedTimeMs: null,
534
+ ipAddress: request.ipAddress,
535
+ scope: result.scope,
536
+ requestTimeMs: Date.now(),
537
+ expireTimeMs: Date.now() + OPEN_ID_LOGIN_REQUEST_LIFETIME_MS,
538
+ };
539
+ await this._store.saveOpenIDLoginRequest(loginRequest);
540
+ return {
541
+ success: true,
542
+ authorizationUrl: result.authorizationUrl,
543
+ requestId: requestId,
544
+ };
545
+ }
546
+ catch (err) {
547
+ const span = trace.getActiveSpan();
548
+ span === null || span === void 0 ? void 0 : span.recordException(err);
549
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
550
+ console.error('[AuthController] Error occurred while requesting Privo login', err);
551
+ return {
552
+ success: false,
553
+ errorCode: 'server_error',
554
+ errorMessage: 'A server error occurred.',
555
+ };
556
+ }
581
557
  }
582
- processOpenIDAuthorizationCode(request) {
583
- return __awaiter(this, void 0, void 0, function* () {
584
- try {
585
- if (!this._privoClient) {
586
- return {
587
- success: false,
588
- errorCode: 'not_supported',
589
- errorMessage: 'Privo features are not supported on this server.',
590
- };
591
- }
592
- const config = yield this._config.getPrivoConfiguration();
593
- if (!config) {
594
- return {
595
- success: false,
596
- errorCode: 'not_supported',
597
- errorMessage: 'Privo features are not supported on this server.',
598
- };
599
- }
600
- const state = request.state;
601
- const loginRequest = yield this._store.findOpenIDLoginRequestByState(state);
602
- if (!loginRequest) {
603
- console.log('[AuthController] Could not find login request.');
604
- return {
605
- success: false,
606
- errorCode: 'invalid_request',
607
- errorMessage: INVALID_AUTHORIZATION_REQUEST_ERROR_MESSAGE,
608
- };
609
- }
610
- let validRequest = true;
611
- if (Date.now() >= loginRequest.expireTimeMs) {
612
- validRequest = false;
613
- }
614
- else if (loginRequest.completedTimeMs > 0) {
615
- validRequest = false;
616
- }
617
- else if (loginRequest.authorizationTimeMs > 0) {
618
- validRequest = false;
619
- }
620
- else if (loginRequest.ipAddress !== request.ipAddress) {
621
- validRequest = false;
622
- }
623
- if (!validRequest) {
624
- return {
625
- success: false,
626
- errorCode: 'invalid_request',
627
- errorMessage: INVALID_AUTHORIZATION_REQUEST_ERROR_MESSAGE,
628
- };
629
- }
630
- if (loginRequest.provider !== PRIVO_OPEN_ID_PROVIDER) {
631
- return {
632
- success: false,
633
- errorCode: 'invalid_request',
634
- errorMessage: INVALID_AUTHORIZATION_REQUEST_ERROR_MESSAGE,
635
- };
636
- }
637
- yield this._store.saveOpenIDLoginRequestAuthorizationCode(loginRequest.requestId, request.authorizationCode, Date.now());
558
+ async processOpenIDAuthorizationCode(request) {
559
+ try {
560
+ if (!this._privoClient) {
638
561
  return {
639
- success: true,
562
+ success: false,
563
+ errorCode: 'not_supported',
564
+ errorMessage: 'Privo features are not supported on this server.',
640
565
  };
641
566
  }
642
- catch (err) {
643
- const span = trace.getActiveSpan();
644
- span === null || span === void 0 ? void 0 : span.recordException(err);
645
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
646
- console.error('[AuthController] Error occurred while processing Privo authorization code', err);
567
+ const config = await this._config.getPrivoConfiguration();
568
+ if (!config) {
647
569
  return {
648
570
  success: false,
649
- errorCode: 'server_error',
650
- errorMessage: 'A server error occurred.',
571
+ errorCode: 'not_supported',
572
+ errorMessage: 'Privo features are not supported on this server.',
573
+ };
574
+ }
575
+ const state = request.state;
576
+ const loginRequest = await this._store.findOpenIDLoginRequestByState(state);
577
+ if (!loginRequest) {
578
+ console.log('[AuthController] Could not find login request.');
579
+ return {
580
+ success: false,
581
+ errorCode: 'invalid_request',
582
+ errorMessage: INVALID_AUTHORIZATION_REQUEST_ERROR_MESSAGE,
583
+ };
584
+ }
585
+ let validRequest = true;
586
+ if (Date.now() >= loginRequest.expireTimeMs) {
587
+ validRequest = false;
588
+ }
589
+ else if (loginRequest.completedTimeMs > 0) {
590
+ validRequest = false;
591
+ }
592
+ else if (loginRequest.authorizationTimeMs > 0) {
593
+ validRequest = false;
594
+ }
595
+ else if (loginRequest.ipAddress !== request.ipAddress) {
596
+ validRequest = false;
597
+ }
598
+ if (!validRequest) {
599
+ return {
600
+ success: false,
601
+ errorCode: 'invalid_request',
602
+ errorMessage: INVALID_AUTHORIZATION_REQUEST_ERROR_MESSAGE,
603
+ };
604
+ }
605
+ if (loginRequest.provider !== PRIVO_OPEN_ID_PROVIDER) {
606
+ return {
607
+ success: false,
608
+ errorCode: 'invalid_request',
609
+ errorMessage: INVALID_AUTHORIZATION_REQUEST_ERROR_MESSAGE,
651
610
  };
652
611
  }
653
- });
612
+ await this._store.saveOpenIDLoginRequestAuthorizationCode(loginRequest.requestId, request.authorizationCode, Date.now());
613
+ return {
614
+ success: true,
615
+ };
616
+ }
617
+ catch (err) {
618
+ const span = trace.getActiveSpan();
619
+ span === null || span === void 0 ? void 0 : span.recordException(err);
620
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
621
+ console.error('[AuthController] Error occurred while processing Privo authorization code', err);
622
+ return {
623
+ success: false,
624
+ errorCode: 'server_error',
625
+ errorMessage: 'A server error occurred.',
626
+ };
627
+ }
654
628
  }
655
- completeOpenIDLogin(request) {
629
+ async completeOpenIDLogin(request) {
656
630
  var _a, _b, _c, _d;
657
- return __awaiter(this, void 0, void 0, function* () {
658
- try {
659
- if (!this._privoClient) {
660
- return {
661
- success: false,
662
- errorCode: 'not_supported',
663
- errorMessage: 'Privo features are not supported on this server.',
664
- };
665
- }
666
- const config = yield this._config.getPrivoConfiguration();
667
- if (!config) {
668
- return {
669
- success: false,
670
- errorCode: 'not_supported',
671
- errorMessage: 'Privo features are not supported on this server.',
672
- };
673
- }
674
- const requestId = request.requestId;
675
- const loginRequest = yield this._store.findOpenIDLoginRequest(requestId);
676
- if (!loginRequest) {
677
- return {
678
- success: false,
679
- errorCode: 'invalid_request',
680
- errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
681
- };
682
- }
683
- let validRequest = true;
684
- if (Date.now() >= loginRequest.expireTimeMs) {
685
- validRequest = false;
686
- }
687
- else if (loginRequest.completedTimeMs > 0) {
688
- validRequest = false;
689
- }
690
- else if (loginRequest.ipAddress !== request.ipAddress) {
691
- validRequest = false;
692
- }
693
- if (!validRequest) {
694
- return {
695
- success: false,
696
- errorCode: 'invalid_request',
697
- errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
698
- };
699
- }
700
- if (loginRequest.provider !== PRIVO_OPEN_ID_PROVIDER) {
701
- return {
702
- success: false,
703
- errorCode: 'invalid_request',
704
- errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
705
- };
706
- }
707
- if (!loginRequest.authorizationTimeMs ||
708
- !loginRequest.authorizationCode) {
709
- return {
710
- success: false,
711
- errorCode: 'not_completed',
712
- errorMessage: 'The login request has not been completed.',
713
- };
714
- }
715
- const result = yield this._privoClient.processAuthorizationCallback({
716
- code: loginRequest.authorizationCode,
717
- state: loginRequest.state,
718
- codeVerifier: loginRequest.codeVerifier,
719
- redirectUrl: loginRequest.redirectUrl,
720
- });
721
- const serviceId = result.userInfo.serviceId;
722
- const email = result.userInfo.email;
723
- if (result.userInfo.roleIdentifier !== config.roleIds.adult &&
724
- result.userInfo.roleIdentifier !== config.roleIds.child) {
725
- return {
726
- success: false,
727
- errorCode: 'invalid_request',
728
- errorMessage: "The login request is invalid. You attempted to sign into an account that is associated with a parent email address. This is not allowed because we don't ask consent for parent accounts, but all accounts must have consent. Please sign up with a new account instead.",
729
- };
730
- }
731
- let user;
732
- if (serviceId) {
733
- user = yield this._store.findUserByPrivoServiceId(result.userInfo.serviceId);
734
- }
735
- if (!user && email) {
736
- user = yield this._store.findUserByAddress(email, 'email');
737
- }
738
- if (!user) {
739
- console.log('[AuthController] [completeOpenIDLogin] Could not find user.');
740
- return {
741
- success: false,
742
- errorCode: 'invalid_request',
743
- errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
744
- };
745
- }
746
- if (!user.privoServiceId) {
747
- console.log(`[AuthController] [completeOpenIDLogin] Updating user service ID.`);
748
- user = Object.assign(Object.assign({}, user), { privoServiceId: serviceId });
749
- yield this._store.saveUser(Object.assign({}, user));
750
- }
751
- else if (user.privoServiceId !== serviceId) {
752
- console.log(`[AuthController] [completeOpenIDLogin] User's service ID (${user.privoServiceId}) doesnt match the one returned by Privo (${serviceId}).`);
753
- return {
754
- success: false,
755
- errorCode: 'invalid_request',
756
- errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
757
- };
758
- }
759
- const privacyFeatures = getPrivacyFeaturesFromPermissions(config.featureIds, result.userInfo.permissions);
760
- if (((_a = user.privacyFeatures) === null || _a === void 0 ? void 0 : _a.publishData) !==
761
- privacyFeatures.publishData ||
762
- ((_b = user.privacyFeatures) === null || _b === void 0 ? void 0 : _b.allowPublicData) !==
763
- privacyFeatures.allowPublicData ||
764
- ((_c = user.privacyFeatures) === null || _c === void 0 ? void 0 : _c.allowAI) !== privacyFeatures.allowAI ||
765
- ((_d = user.privacyFeatures) === null || _d === void 0 ? void 0 : _d.allowPublicInsts) !==
766
- privacyFeatures.allowPublicInsts) {
767
- console.log(`[AuthController] [completeOpenIDLogin] Updating user privacy features.`);
768
- user = Object.assign(Object.assign({}, user), { privacyFeatures });
769
- yield this._store.saveUser(Object.assign({}, user));
770
- }
771
- const now = Date.now();
772
- const expiry = now + result.expiresIn * 1000;
773
- const { info } = yield this._issueSession({
774
- userId: user.id,
775
- lifetimeMs: SESSION_LIFETIME_MS,
776
- oidRequestId: loginRequest.requestId,
777
- oidAccessToken: result.accessToken,
778
- oidRefreshToken: result.refreshToken,
779
- oidIdToken: result.idToken,
780
- oidScope: loginRequest.scope,
781
- oidTokenType: result.tokenType,
782
- oidExpiresAtMs: expiry,
783
- oidProvider: loginRequest.provider,
784
- ipAddress: request.ipAddress,
785
- });
786
- return Object.assign({ success: true }, info);
631
+ try {
632
+ if (!this._privoClient) {
633
+ return {
634
+ success: false,
635
+ errorCode: 'not_supported',
636
+ errorMessage: 'Privo features are not supported on this server.',
637
+ };
787
638
  }
788
- catch (err) {
789
- const span = trace.getActiveSpan();
790
- span === null || span === void 0 ? void 0 : span.recordException(err);
791
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
792
- console.error('[AuthController] Error occurred while completing Privo login', err);
639
+ const config = await this._config.getPrivoConfiguration();
640
+ if (!config) {
793
641
  return {
794
642
  success: false,
795
- errorCode: 'server_error',
796
- errorMessage: 'A server error occurred.',
643
+ errorCode: 'not_supported',
644
+ errorMessage: 'Privo features are not supported on this server.',
797
645
  };
798
646
  }
799
- });
800
- }
801
- requestPrivoSignUp(request) {
802
- return __awaiter(this, void 0, void 0, function* () {
803
- try {
804
- if (!this._privoClient) {
805
- return {
806
- success: false,
807
- errorCode: 'not_supported',
808
- errorMessage: 'Privo features are not supported on this server.',
809
- };
810
- }
811
- const config = yield this._config.getPrivoConfiguration();
812
- if (!config) {
813
- return {
814
- success: false,
815
- errorCode: 'not_supported',
816
- errorMessage: 'Privo features are not supported on this server.',
817
- };
818
- }
819
- const lowercaseName = request.name.trim().toLowerCase();
820
- const lowercaseDisplayName = request.displayName
821
- .trim()
822
- .toLowerCase();
823
- if (lowercaseDisplayName.includes(lowercaseName)) {
824
- return {
825
- success: false,
826
- errorCode: 'invalid_display_name',
827
- errorMessage: 'The display name cannot contain your name.',
828
- };
829
- }
830
- if (request.email &&
831
- request.parentEmail &&
832
- request.parentEmail.localeCompare(request.email, undefined, {
833
- sensitivity: 'base',
834
- }) === 0) {
835
- return {
836
- success: false,
837
- errorCode: 'unacceptable_request',
838
- errorMessage: 'The parent email must be different from the child email.',
839
- };
840
- }
841
- const now = new Date(Date.now());
842
- const years = Math.floor(-DateTime.fromJSDate(request.dateOfBirth)
843
- .diff(DateTime.fromJSDate(now), 'years')
844
- .as('years'));
845
- let updatePasswordUrl;
846
- let serviceId;
847
- let parentServiceId;
848
- let consentUrl;
849
- if (years < 0) {
850
- return {
851
- success: false,
852
- errorCode: 'unacceptable_request',
853
- errorMessage: 'The given date of birth cannot be in the future.',
854
- };
855
- }
856
- let privacyFeatures;
857
- if (years < config.ageOfConsent) {
858
- if (!request.parentEmail) {
859
- return {
860
- success: false,
861
- errorCode: 'parent_email_required',
862
- errorMessage: 'A parent email is required to sign up a child.',
863
- };
864
- }
865
- const result = yield this._privoClient.createChildAccount({
866
- childFirstName: request.name,
867
- childDateOfBirth: request.dateOfBirth,
868
- childEmail: request.email,
869
- childDisplayName: request.displayName,
870
- parentEmail: request.parentEmail,
871
- featureIds: [
872
- config.featureIds.childPrivoSSO,
873
- config.featureIds.joinAndCollaborate,
874
- config.featureIds.projectDevelopment,
875
- config.featureIds.publishProjects,
876
- config.featureIds.buildAIEggs,
877
- ],
878
- });
879
- if (result.success === false) {
880
- return result;
881
- }
882
- serviceId = result.childServiceId;
883
- parentServiceId = result.parentServiceId;
884
- updatePasswordUrl = result.updatePasswordLink;
885
- consentUrl = result.consentUrl;
886
- privacyFeatures = getPrivacyFeaturesFromPermissions(config.featureIds, result.features);
887
- }
888
- else {
889
- if (!request.email) {
890
- return {
891
- success: false,
892
- errorCode: 'unacceptable_request',
893
- errorMessage: 'An email is required to sign up an adult.',
894
- };
895
- }
896
- const result = yield this._privoClient.createAdultAccount({
897
- adultFirstName: request.name,
898
- adultEmail: request.email,
899
- adultDateOfBirth: request.dateOfBirth,
900
- adultDisplayName: request.displayName,
901
- featureIds: [
902
- config.featureIds.adultPrivoSSO,
903
- config.featureIds.joinAndCollaborate,
904
- config.featureIds.projectDevelopment,
905
- config.featureIds.publishProjects,
906
- config.featureIds.buildAIEggs,
907
- ],
908
- });
909
- if (result.success === false) {
910
- return result;
911
- }
912
- serviceId = result.adultServiceId;
913
- updatePasswordUrl = result.updatePasswordLink;
914
- consentUrl = result.consentUrl;
915
- privacyFeatures = getPrivacyFeaturesFromPermissions(config.featureIds, result.features);
916
- }
917
- const user = {
918
- id: uuid(),
919
- email: null, // We don't store the email because it is stored in Privo.
920
- phoneNumber: null,
921
- name: null, // We don't store the name because it is stored in Privo.
922
- allSessionRevokeTimeMs: null,
923
- currentLoginRequestId: null,
647
+ const requestId = request.requestId;
648
+ const loginRequest = await this._store.findOpenIDLoginRequest(requestId);
649
+ if (!loginRequest) {
650
+ return {
651
+ success: false,
652
+ errorCode: 'invalid_request',
653
+ errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
654
+ };
655
+ }
656
+ let validRequest = true;
657
+ if (Date.now() >= loginRequest.expireTimeMs) {
658
+ validRequest = false;
659
+ }
660
+ else if (loginRequest.completedTimeMs > 0) {
661
+ validRequest = false;
662
+ }
663
+ else if (loginRequest.ipAddress !== request.ipAddress) {
664
+ validRequest = false;
665
+ }
666
+ if (!validRequest) {
667
+ return {
668
+ success: false,
669
+ errorCode: 'invalid_request',
670
+ errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
671
+ };
672
+ }
673
+ if (loginRequest.provider !== PRIVO_OPEN_ID_PROVIDER) {
674
+ return {
675
+ success: false,
676
+ errorCode: 'invalid_request',
677
+ errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
678
+ };
679
+ }
680
+ if (!loginRequest.authorizationTimeMs ||
681
+ !loginRequest.authorizationCode) {
682
+ return {
683
+ success: false,
684
+ errorCode: 'not_completed',
685
+ errorMessage: 'The login request has not been completed.',
686
+ };
687
+ }
688
+ const result = await this._privoClient.processAuthorizationCallback({
689
+ code: loginRequest.authorizationCode,
690
+ state: loginRequest.state,
691
+ codeVerifier: loginRequest.codeVerifier,
692
+ redirectUrl: loginRequest.redirectUrl,
693
+ });
694
+ const serviceId = result.userInfo.serviceId;
695
+ const email = result.userInfo.email;
696
+ if (result.userInfo.roleIdentifier !== config.roleIds.adult &&
697
+ result.userInfo.roleIdentifier !== config.roleIds.child) {
698
+ return {
699
+ success: false,
700
+ errorCode: 'invalid_request',
701
+ errorMessage: "The login request is invalid. You attempted to sign into an account that is associated with a parent email address. This is not allowed because we don't ask consent for parent accounts, but all accounts must have consent. Please sign up with a new account instead.",
702
+ };
703
+ }
704
+ let user;
705
+ if (serviceId) {
706
+ user = await this._store.findUserByPrivoServiceId(result.userInfo.serviceId);
707
+ }
708
+ if (!user && email) {
709
+ user = await this._store.findUserByAddress(email, 'email');
710
+ }
711
+ if (!user) {
712
+ console.log('[AuthController] [completeOpenIDLogin] Could not find user.');
713
+ return {
714
+ success: false,
715
+ errorCode: 'invalid_request',
716
+ errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
717
+ };
718
+ }
719
+ if (!user.privoServiceId) {
720
+ console.log(`[AuthController] [completeOpenIDLogin] Updating user service ID.`);
721
+ user = {
722
+ ...user,
924
723
  privoServiceId: serviceId,
925
- privoParentServiceId: parentServiceId,
926
- privoConsentUrl: consentUrl,
927
- privacyFeatures,
928
724
  };
929
- // TODO: Add user to DB
930
- const saveUserResult = yield this._store.saveNewUser(user);
931
- if (saveUserResult.success === false) {
932
- console.error('[AuthController] Error saving new user', saveUserResult);
933
- return {
934
- success: false,
935
- errorCode: 'server_error',
936
- errorMessage: 'A server error occurred.',
937
- };
938
- }
939
- const userId = user.id;
940
- const { info } = yield this._issueSession({
941
- userId,
942
- lifetimeMs: SESSION_LIFETIME_MS,
943
- ipAddress: request.ipAddress,
725
+ await this._store.saveUser({
726
+ ...user,
944
727
  });
945
- return Object.assign(Object.assign({ success: true }, info), { updatePasswordUrl });
946
728
  }
947
- catch (err) {
948
- const span = trace.getActiveSpan();
949
- span === null || span === void 0 ? void 0 : span.recordException(err);
950
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
951
- console.error(`[AuthController] Error occurred while requesting Privo sign up`, err);
729
+ else if (user.privoServiceId !== serviceId) {
730
+ console.log(`[AuthController] [completeOpenIDLogin] User's service ID (${user.privoServiceId}) doesnt match the one returned by Privo (${serviceId}).`);
952
731
  return {
953
732
  success: false,
954
- errorCode: 'server_error',
955
- errorMessage: 'A server error occurred.',
733
+ errorCode: 'invalid_request',
734
+ errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
735
+ };
736
+ }
737
+ const privacyFeatures = getPrivacyFeaturesFromPermissions(config.featureIds, result.userInfo.permissions);
738
+ if (((_a = user.privacyFeatures) === null || _a === void 0 ? void 0 : _a.publishData) !==
739
+ privacyFeatures.publishData ||
740
+ ((_b = user.privacyFeatures) === null || _b === void 0 ? void 0 : _b.allowPublicData) !==
741
+ privacyFeatures.allowPublicData ||
742
+ ((_c = user.privacyFeatures) === null || _c === void 0 ? void 0 : _c.allowAI) !== privacyFeatures.allowAI ||
743
+ ((_d = user.privacyFeatures) === null || _d === void 0 ? void 0 : _d.allowPublicInsts) !==
744
+ privacyFeatures.allowPublicInsts) {
745
+ console.log(`[AuthController] [completeOpenIDLogin] Updating user privacy features.`);
746
+ user = {
747
+ ...user,
748
+ privacyFeatures,
956
749
  };
750
+ await this._store.saveUser({
751
+ ...user,
752
+ });
957
753
  }
958
- });
754
+ const now = Date.now();
755
+ const expiry = now + result.expiresIn * 1000;
756
+ const { info } = await this._issueSession({
757
+ userId: user.id,
758
+ lifetimeMs: SESSION_LIFETIME_MS,
759
+ oidRequestId: loginRequest.requestId,
760
+ oidAccessToken: result.accessToken,
761
+ oidRefreshToken: result.refreshToken,
762
+ oidIdToken: result.idToken,
763
+ oidScope: loginRequest.scope,
764
+ oidTokenType: result.tokenType,
765
+ oidExpiresAtMs: expiry,
766
+ oidProvider: loginRequest.provider,
767
+ ipAddress: request.ipAddress,
768
+ });
769
+ return {
770
+ success: true,
771
+ ...info,
772
+ };
773
+ }
774
+ catch (err) {
775
+ const span = trace.getActiveSpan();
776
+ span === null || span === void 0 ? void 0 : span.recordException(err);
777
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
778
+ console.error('[AuthController] Error occurred while completing Privo login', err);
779
+ return {
780
+ success: false,
781
+ errorCode: 'server_error',
782
+ errorMessage: 'A server error occurred.',
783
+ };
784
+ }
959
785
  }
960
- requestWebAuthnRegistration(request) {
961
- var _a;
962
- return __awaiter(this, void 0, void 0, function* () {
963
- try {
964
- if (this._webAuthNRelyingParties.length <= 0) {
965
- return {
966
- success: false,
967
- errorCode: 'not_supported',
968
- errorMessage: 'WebAuthn is not supported on this server.',
969
- };
970
- }
971
- const relyingParty = findRelyingPartyForOrigin(this._webAuthNRelyingParties, request.originOrHost);
972
- if (!relyingParty) {
973
- return {
974
- success: false,
975
- errorCode: 'invalid_origin',
976
- errorMessage: 'The request must be made from an authorized origin.',
977
- };
978
- }
979
- const user = yield this._store.findUser(request.userId);
980
- if (!user) {
981
- return {
982
- success: false,
983
- errorCode: 'not_logged_in',
984
- errorMessage: 'You need to be logged in for the operation to work.',
985
- };
986
- }
987
- const authenticators = yield this._store.listUserAuthenticators(user.id);
988
- const options = yield generateRegistrationOptions({
989
- rpName: relyingParty.name,
990
- rpID: relyingParty.id,
991
- userID: user.id,
992
- userName: (_a = user.email) !== null && _a !== void 0 ? _a : user.phoneNumber,
993
- attestationType: 'none',
994
- excludeCredentials: authenticators.map((auth) => ({
995
- id: base64URLStringToBuffer(auth.credentialId),
996
- type: 'public-key',
997
- transports: auth.transports,
998
- })),
999
- authenticatorSelection: {
1000
- residentKey: 'preferred',
1001
- userVerification: 'preferred',
1002
- authenticatorAttachment: 'platform',
1003
- },
1004
- });
1005
- yield this._store.setCurrentWebAuthnChallenge(user.id, options.challenge);
786
+ async requestPrivoSignUp(request) {
787
+ try {
788
+ if (!this._privoClient) {
1006
789
  return {
1007
- success: true,
1008
- options,
790
+ success: false,
791
+ errorCode: 'not_supported',
792
+ errorMessage: 'Privo features are not supported on this server.',
1009
793
  };
1010
794
  }
1011
- catch (err) {
1012
- const span = trace.getActiveSpan();
1013
- span === null || span === void 0 ? void 0 : span.recordException(err);
1014
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1015
- console.error(`[AuthController] Error occurred while requesting WebAuthn registration options`, err);
795
+ const config = await this._config.getPrivoConfiguration();
796
+ if (!config) {
1016
797
  return {
1017
798
  success: false,
1018
- errorCode: 'server_error',
1019
- errorMessage: 'A server error occurred.',
799
+ errorCode: 'not_supported',
800
+ errorMessage: 'Privo features are not supported on this server.',
1020
801
  };
1021
802
  }
1022
- });
1023
- }
1024
- completeWebAuthnRegistration(request) {
1025
- return __awaiter(this, void 0, void 0, function* () {
1026
- try {
1027
- if (this._webAuthNRelyingParties.length <= 0) {
1028
- return {
1029
- success: false,
1030
- errorCode: 'not_supported',
1031
- errorMessage: 'WebAuthn is not supported on this server.',
1032
- };
1033
- }
1034
- const relyingParty = findRelyingPartyForOrigin(this._webAuthNRelyingParties, request.originOrHost);
1035
- if (!relyingParty) {
1036
- return {
1037
- success: false,
1038
- errorCode: 'invalid_origin',
1039
- errorMessage: 'The request must be made from an authorized origin.',
1040
- };
1041
- }
1042
- const user = yield this._store.findUser(request.userId);
1043
- if (!user) {
803
+ const lowercaseName = request.name.trim().toLowerCase();
804
+ const lowercaseDisplayName = request.displayName
805
+ .trim()
806
+ .toLowerCase();
807
+ if (lowercaseDisplayName.includes(lowercaseName)) {
808
+ return {
809
+ success: false,
810
+ errorCode: 'invalid_display_name',
811
+ errorMessage: 'The display name cannot contain your name.',
812
+ };
813
+ }
814
+ if (request.email &&
815
+ request.parentEmail &&
816
+ request.parentEmail.localeCompare(request.email, undefined, {
817
+ sensitivity: 'base',
818
+ }) === 0) {
819
+ return {
820
+ success: false,
821
+ errorCode: 'unacceptable_request',
822
+ errorMessage: 'The parent email must be different from the child email.',
823
+ };
824
+ }
825
+ const now = new Date(Date.now());
826
+ const years = Math.floor(-DateTime.fromJSDate(request.dateOfBirth)
827
+ .diff(DateTime.fromJSDate(now), 'years')
828
+ .as('years'));
829
+ let updatePasswordUrl;
830
+ let serviceId;
831
+ let parentServiceId;
832
+ let consentUrl;
833
+ if (years < 0) {
834
+ return {
835
+ success: false,
836
+ errorCode: 'unacceptable_request',
837
+ errorMessage: 'The given date of birth cannot be in the future.',
838
+ };
839
+ }
840
+ let privacyFeatures;
841
+ if (years < config.ageOfConsent) {
842
+ if (!request.parentEmail) {
1044
843
  return {
1045
844
  success: false,
1046
- errorCode: 'not_logged_in',
1047
- errorMessage: 'You need to be logged in for the operation to work.',
845
+ errorCode: 'parent_email_required',
846
+ errorMessage: 'A parent email is required to sign up a child.',
1048
847
  };
1049
848
  }
1050
- const currentChallenge = user.currentWebAuthnChallenge;
1051
- try {
1052
- const verification = yield verifyRegistrationResponse({
1053
- response: request.response,
1054
- expectedChallenge: currentChallenge,
1055
- expectedOrigin: relyingParty.origin,
1056
- expectedRPID: relyingParty.id,
1057
- });
1058
- if (verification.verified) {
1059
- const registration = verification.registrationInfo;
1060
- const credentialId = bufferToBase64URLString(registration.credentialID);
1061
- const authenticator = {
1062
- id: uuid(),
1063
- userId: user.id,
1064
- credentialId,
1065
- credentialPublicKey: registration.credentialPublicKey,
1066
- counter: registration.counter,
1067
- credentialBackedUp: registration.credentialBackedUp,
1068
- credentialDeviceType: registration.credentialDeviceType,
1069
- transports: request.response.response.transports,
1070
- aaguid: verification.registrationInfo.aaguid,
1071
- registeringUserAgent: request.userAgent,
1072
- createdAtMs: Date.now(),
1073
- };
1074
- yield this._store.setCurrentWebAuthnChallenge(user.id, null);
1075
- yield this._store.saveUserAuthenticator(authenticator);
1076
- return {
1077
- success: true,
1078
- };
1079
- }
1080
- else {
1081
- return {
1082
- success: false,
1083
- errorCode: 'not_authorized',
1084
- errorMessage: 'The registration response was not authorized.',
1085
- };
1086
- }
849
+ const result = await this._privoClient.createChildAccount({
850
+ childFirstName: request.name,
851
+ childDateOfBirth: request.dateOfBirth,
852
+ childEmail: request.email,
853
+ childDisplayName: request.displayName,
854
+ parentEmail: request.parentEmail,
855
+ featureIds: [
856
+ config.featureIds.childPrivoSSO,
857
+ config.featureIds.joinAndCollaborate,
858
+ config.featureIds.projectDevelopment,
859
+ config.featureIds.publishProjects,
860
+ config.featureIds.buildAIEggs,
861
+ ],
862
+ });
863
+ if (result.success === false) {
864
+ return result;
1087
865
  }
1088
- catch (err) {
1089
- console.error(`[AuthController] Error occurred while verifying WebAuthn registration response`, err);
866
+ serviceId = result.childServiceId;
867
+ parentServiceId = result.parentServiceId;
868
+ updatePasswordUrl = result.updatePasswordLink;
869
+ consentUrl = result.consentUrl;
870
+ privacyFeatures = getPrivacyFeaturesFromPermissions(config.featureIds, result.features);
871
+ }
872
+ else {
873
+ if (!request.email) {
1090
874
  return {
1091
875
  success: false,
1092
876
  errorCode: 'unacceptable_request',
1093
- errorMessage: err.message,
1094
- };
877
+ errorMessage: 'An email is required to sign up an adult.',
878
+ };
879
+ }
880
+ const result = await this._privoClient.createAdultAccount({
881
+ adultFirstName: request.name,
882
+ adultEmail: request.email,
883
+ adultDateOfBirth: request.dateOfBirth,
884
+ adultDisplayName: request.displayName,
885
+ featureIds: [
886
+ config.featureIds.adultPrivoSSO,
887
+ config.featureIds.joinAndCollaborate,
888
+ config.featureIds.projectDevelopment,
889
+ config.featureIds.publishProjects,
890
+ config.featureIds.buildAIEggs,
891
+ ],
892
+ });
893
+ if (result.success === false) {
894
+ return result;
1095
895
  }
896
+ serviceId = result.adultServiceId;
897
+ updatePasswordUrl = result.updatePasswordLink;
898
+ consentUrl = result.consentUrl;
899
+ privacyFeatures = getPrivacyFeaturesFromPermissions(config.featureIds, result.features);
900
+ }
901
+ const user = {
902
+ id: uuid(),
903
+ email: null, // We don't store the email because it is stored in Privo.
904
+ phoneNumber: null,
905
+ name: null, // We don't store the name because it is stored in Privo.
906
+ allSessionRevokeTimeMs: null,
907
+ currentLoginRequestId: null,
908
+ privoServiceId: serviceId,
909
+ privoParentServiceId: parentServiceId,
910
+ privoConsentUrl: consentUrl,
911
+ privacyFeatures,
912
+ };
913
+ // TODO: Add user to DB
914
+ const saveUserResult = await this._store.saveNewUser(user);
915
+ if (saveUserResult.success === false) {
916
+ console.error('[AuthController] Error saving new user', saveUserResult);
917
+ return {
918
+ success: false,
919
+ errorCode: 'server_error',
920
+ errorMessage: 'A server error occurred.',
921
+ };
1096
922
  }
1097
- catch (err) {
1098
- const span = trace.getActiveSpan();
1099
- span === null || span === void 0 ? void 0 : span.recordException(err);
1100
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1101
- console.error(`[AuthController] Error occurred while completing WebAuthn registration`, err);
923
+ const userId = user.id;
924
+ const { info } = await this._issueSession({
925
+ userId,
926
+ lifetimeMs: SESSION_LIFETIME_MS,
927
+ ipAddress: request.ipAddress,
928
+ });
929
+ return {
930
+ success: true,
931
+ ...info,
932
+ updatePasswordUrl,
933
+ };
934
+ }
935
+ catch (err) {
936
+ const span = trace.getActiveSpan();
937
+ span === null || span === void 0 ? void 0 : span.recordException(err);
938
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
939
+ console.error(`[AuthController] Error occurred while requesting Privo sign up`, err);
940
+ return {
941
+ success: false,
942
+ errorCode: 'server_error',
943
+ errorMessage: 'A server error occurred.',
944
+ };
945
+ }
946
+ }
947
+ async requestWebAuthnRegistration(request) {
948
+ var _a;
949
+ try {
950
+ if (this._webAuthNRelyingParties.length <= 0) {
951
+ return {
952
+ success: false,
953
+ errorCode: 'not_supported',
954
+ errorMessage: 'WebAuthn is not supported on this server.',
955
+ };
956
+ }
957
+ const relyingParty = findRelyingPartyForOrigin(this._webAuthNRelyingParties, request.originOrHost);
958
+ if (!relyingParty) {
959
+ return {
960
+ success: false,
961
+ errorCode: 'invalid_origin',
962
+ errorMessage: 'The request must be made from an authorized origin.',
963
+ };
964
+ }
965
+ const user = await this._store.findUser(request.userId);
966
+ if (!user) {
967
+ return {
968
+ success: false,
969
+ errorCode: 'not_logged_in',
970
+ errorMessage: 'You need to be logged in for the operation to work.',
971
+ };
972
+ }
973
+ const authenticators = await this._store.listUserAuthenticators(user.id);
974
+ const options = await generateRegistrationOptions({
975
+ rpName: relyingParty.name,
976
+ rpID: relyingParty.id,
977
+ userID: user.id,
978
+ userName: (_a = user.email) !== null && _a !== void 0 ? _a : user.phoneNumber,
979
+ attestationType: 'none',
980
+ excludeCredentials: authenticators.map((auth) => ({
981
+ id: base64URLStringToBuffer(auth.credentialId),
982
+ type: 'public-key',
983
+ transports: auth.transports,
984
+ })),
985
+ authenticatorSelection: {
986
+ residentKey: 'preferred',
987
+ userVerification: 'preferred',
988
+ authenticatorAttachment: 'platform',
989
+ },
990
+ });
991
+ await this._store.setCurrentWebAuthnChallenge(user.id, options.challenge);
992
+ return {
993
+ success: true,
994
+ options,
995
+ };
996
+ }
997
+ catch (err) {
998
+ const span = trace.getActiveSpan();
999
+ span === null || span === void 0 ? void 0 : span.recordException(err);
1000
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1001
+ console.error(`[AuthController] Error occurred while requesting WebAuthn registration options`, err);
1002
+ return {
1003
+ success: false,
1004
+ errorCode: 'server_error',
1005
+ errorMessage: 'A server error occurred.',
1006
+ };
1007
+ }
1008
+ }
1009
+ async completeWebAuthnRegistration(request) {
1010
+ try {
1011
+ if (this._webAuthNRelyingParties.length <= 0) {
1102
1012
  return {
1103
1013
  success: false,
1104
- errorCode: 'server_error',
1105
- errorMessage: 'A server error occurred.',
1014
+ errorCode: 'not_supported',
1015
+ errorMessage: 'WebAuthn is not supported on this server.',
1106
1016
  };
1107
1017
  }
1108
- });
1109
- }
1110
- requestWebAuthnLogin(request) {
1111
- return __awaiter(this, void 0, void 0, function* () {
1112
- try {
1113
- if (this._webAuthNRelyingParties.length <= 0) {
1114
- return {
1115
- success: false,
1116
- errorCode: 'not_supported',
1117
- errorMessage: 'WebAuthn is not supported on this server.',
1118
- };
1119
- }
1120
- const relyingParty = findRelyingPartyForOrigin(this._webAuthNRelyingParties, request.originOrHost);
1121
- if (!relyingParty) {
1122
- return {
1123
- success: false,
1124
- errorCode: 'invalid_origin',
1125
- errorMessage: 'The request must be made from an authorized origin.',
1126
- };
1127
- }
1128
- const options = yield generateAuthenticationOptions({
1129
- rpID: relyingParty.id,
1130
- userVerification: 'preferred',
1131
- });
1132
- const requestId = uuid();
1133
- const nowMs = Date.now();
1134
- yield this._store.saveWebAuthnLoginRequest({
1135
- requestId: requestId,
1136
- challenge: options.challenge,
1137
- requestTimeMs: nowMs,
1138
- expireTimeMs: nowMs + WEB_AUTHN_LOGIN_REQUEST_LIFETIME_MS,
1139
- completedTimeMs: null,
1140
- ipAddress: request.ipAddress,
1141
- userId: null,
1142
- });
1018
+ const relyingParty = findRelyingPartyForOrigin(this._webAuthNRelyingParties, request.originOrHost);
1019
+ if (!relyingParty) {
1143
1020
  return {
1144
- success: true,
1145
- requestId,
1146
- options,
1021
+ success: false,
1022
+ errorCode: 'invalid_origin',
1023
+ errorMessage: 'The request must be made from an authorized origin.',
1147
1024
  };
1148
1025
  }
1149
- catch (err) {
1150
- const span = trace.getActiveSpan();
1151
- span === null || span === void 0 ? void 0 : span.recordException(err);
1152
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1153
- console.error(`[AuthController] Error occurred while requesting WebAuthn login`, err);
1026
+ const user = await this._store.findUser(request.userId);
1027
+ if (!user) {
1154
1028
  return {
1155
1029
  success: false,
1156
- errorCode: 'server_error',
1157
- errorMessage: 'A server error occurred.',
1030
+ errorCode: 'not_logged_in',
1031
+ errorMessage: 'You need to be logged in for the operation to work.',
1158
1032
  };
1159
1033
  }
1160
- });
1161
- }
1162
- completeWebAuthnLogin(request) {
1163
- return __awaiter(this, void 0, void 0, function* () {
1034
+ const currentChallenge = user.currentWebAuthnChallenge;
1164
1035
  try {
1165
- if (this._webAuthNRelyingParties.length <= 0) {
1166
- return {
1167
- success: false,
1168
- errorCode: 'not_supported',
1169
- errorMessage: 'WebAuthn is not supported on this server.',
1170
- };
1171
- }
1172
- const relyingParty = findRelyingPartyForOrigin(this._webAuthNRelyingParties, request.originOrHost);
1173
- if (!relyingParty) {
1174
- return {
1175
- success: false,
1176
- errorCode: 'invalid_origin',
1177
- errorMessage: 'The request must be made from an authorized origin.',
1178
- };
1179
- }
1180
- const loginRequest = yield this._store.findWebAuthnLoginRequest(request.requestId);
1181
- if (!loginRequest) {
1182
- console.error('could not find login request!');
1183
- return {
1184
- success: false,
1185
- errorCode: 'invalid_request',
1186
- errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
1187
- };
1188
- }
1189
- let validRequest = true;
1190
- if (Date.now() >= loginRequest.expireTimeMs) {
1191
- console.error('Expired!');
1192
- validRequest = false;
1193
- }
1194
- else if (loginRequest.completedTimeMs > 0) {
1195
- console.error('Completed!');
1196
- validRequest = false;
1197
- }
1198
- else if (loginRequest.ipAddress !== request.ipAddress) {
1199
- console.error('Wrong IP!');
1200
- validRequest = false;
1201
- }
1202
- if (!validRequest) {
1203
- return {
1204
- success: false,
1205
- errorCode: 'invalid_request',
1206
- errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
1207
- };
1208
- }
1209
- const { authenticator, user } = yield this._store.findUserAuthenticatorByCredentialId(request.response.id);
1210
- if (!authenticator) {
1211
- console.error('No Authenticator!');
1212
- return {
1213
- success: false,
1214
- errorCode: 'invalid_request',
1215
- errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
1216
- };
1217
- }
1218
- if (user.banTimeMs > 0) {
1036
+ const verification = await verifyRegistrationResponse({
1037
+ response: request.response,
1038
+ expectedChallenge: currentChallenge,
1039
+ expectedOrigin: relyingParty.origin,
1040
+ expectedRPID: relyingParty.id,
1041
+ });
1042
+ if (verification.verified) {
1043
+ const registration = verification.registrationInfo;
1044
+ const credentialId = bufferToBase64URLString(registration.credentialID);
1045
+ const authenticator = {
1046
+ id: uuid(),
1047
+ userId: user.id,
1048
+ credentialId,
1049
+ credentialPublicKey: registration.credentialPublicKey,
1050
+ counter: registration.counter,
1051
+ credentialBackedUp: registration.credentialBackedUp,
1052
+ credentialDeviceType: registration.credentialDeviceType,
1053
+ transports: request.response.response.transports,
1054
+ aaguid: verification.registrationInfo.aaguid,
1055
+ registeringUserAgent: request.userAgent,
1056
+ createdAtMs: Date.now(),
1057
+ };
1058
+ await this._store.setCurrentWebAuthnChallenge(user.id, null);
1059
+ await this._store.saveUserAuthenticator(authenticator);
1219
1060
  return {
1220
- success: false,
1221
- errorCode: 'user_is_banned',
1222
- errorMessage: 'The user has been banned.',
1223
- banReason: user.banReason,
1061
+ success: true,
1224
1062
  };
1225
1063
  }
1226
- try {
1227
- const options = yield verifyAuthenticationResponse({
1228
- response: request.response,
1229
- expectedChallenge: loginRequest.challenge,
1230
- expectedOrigin: relyingParty.origin,
1231
- expectedRPID: relyingParty.id,
1232
- authenticator: {
1233
- credentialID: new Uint8Array(base64URLStringToBuffer(authenticator.credentialId)),
1234
- counter: authenticator.counter,
1235
- credentialPublicKey: authenticator.credentialPublicKey,
1236
- transports: authenticator.transports,
1237
- },
1238
- });
1239
- if (!options.verified) {
1240
- console.error('Not verified!');
1241
- return {
1242
- success: false,
1243
- errorCode: 'invalid_request',
1244
- errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
1245
- };
1246
- }
1247
- yield this._store.saveUserAuthenticatorCounter(authenticator.id, options.authenticationInfo.newCounter);
1248
- }
1249
- catch (err) {
1250
- console.error(`[AuthController] Error occurred while verifying WebAuthn login response`, err);
1064
+ else {
1251
1065
  return {
1252
1066
  success: false,
1253
- errorCode: 'invalid_request',
1254
- errorMessage: err.message,
1067
+ errorCode: 'not_authorized',
1068
+ errorMessage: 'The registration response was not authorized.',
1255
1069
  };
1256
1070
  }
1257
- const { info } = yield this._issueSession({
1258
- userId: user.id,
1259
- lifetimeMs: SESSION_LIFETIME_MS,
1260
- ipAddress: request.ipAddress,
1261
- webauthnRequestId: loginRequest.requestId,
1262
- oidRequestId: null,
1263
- });
1264
- return Object.assign({ success: true }, info);
1265
1071
  }
1266
1072
  catch (err) {
1267
- const span = trace.getActiveSpan();
1268
- span === null || span === void 0 ? void 0 : span.recordException(err);
1269
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1270
- console.error(`[AuthController] Error occurred while requesting WebAuthn login`, err);
1073
+ console.error(`[AuthController] Error occurred while verifying WebAuthn registration response`, err);
1271
1074
  return {
1272
1075
  success: false,
1273
- errorCode: 'server_error',
1274
- errorMessage: 'A server error occurred.',
1076
+ errorCode: 'unacceptable_request',
1077
+ errorMessage: err.message,
1275
1078
  };
1276
1079
  }
1277
- });
1080
+ }
1081
+ catch (err) {
1082
+ const span = trace.getActiveSpan();
1083
+ span === null || span === void 0 ? void 0 : span.recordException(err);
1084
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1085
+ console.error(`[AuthController] Error occurred while completing WebAuthn registration`, err);
1086
+ return {
1087
+ success: false,
1088
+ errorCode: 'server_error',
1089
+ errorMessage: 'A server error occurred.',
1090
+ };
1091
+ }
1278
1092
  }
1279
- listUserAuthenticators(userId) {
1280
- return __awaiter(this, void 0, void 0, function* () {
1281
- try {
1282
- if (!userId) {
1283
- return {
1284
- success: false,
1285
- errorCode: 'not_logged_in',
1286
- errorMessage: 'You need to be logged in for the operation to work.',
1287
- };
1288
- }
1289
- const authenticators = yield this._store.listUserAuthenticators(userId);
1093
+ async requestWebAuthnLogin(request) {
1094
+ try {
1095
+ if (this._webAuthNRelyingParties.length <= 0) {
1290
1096
  return {
1291
- success: true,
1292
- authenticators: authenticators.map((a) => ({
1293
- id: a.id,
1294
- aaguid: a.aaguid,
1295
- userId: a.userId,
1296
- credentialId: a.credentialId,
1297
- credentialDeviceType: a.credentialDeviceType,
1298
- credentialBackedUp: a.credentialBackedUp,
1299
- counter: a.counter,
1300
- transports: a.transports,
1301
- registeringUserAgent: a.registeringUserAgent,
1302
- createdAtMs: a.createdAtMs,
1303
- })),
1097
+ success: false,
1098
+ errorCode: 'not_supported',
1099
+ errorMessage: 'WebAuthn is not supported on this server.',
1304
1100
  };
1305
1101
  }
1306
- catch (err) {
1307
- const span = trace.getActiveSpan();
1308
- span === null || span === void 0 ? void 0 : span.recordException(err);
1309
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1310
- console.error(`[AuthController] Error occurred while listing user authenticators`, err);
1102
+ const relyingParty = findRelyingPartyForOrigin(this._webAuthNRelyingParties, request.originOrHost);
1103
+ if (!relyingParty) {
1311
1104
  return {
1312
1105
  success: false,
1313
- errorCode: 'server_error',
1314
- errorMessage: 'A server error occurred.',
1106
+ errorCode: 'invalid_origin',
1107
+ errorMessage: 'The request must be made from an authorized origin.',
1108
+ };
1109
+ }
1110
+ const options = await generateAuthenticationOptions({
1111
+ rpID: relyingParty.id,
1112
+ userVerification: 'preferred',
1113
+ });
1114
+ const requestId = uuid();
1115
+ const nowMs = Date.now();
1116
+ await this._store.saveWebAuthnLoginRequest({
1117
+ requestId: requestId,
1118
+ challenge: options.challenge,
1119
+ requestTimeMs: nowMs,
1120
+ expireTimeMs: nowMs + WEB_AUTHN_LOGIN_REQUEST_LIFETIME_MS,
1121
+ completedTimeMs: null,
1122
+ ipAddress: request.ipAddress,
1123
+ userId: null,
1124
+ });
1125
+ return {
1126
+ success: true,
1127
+ requestId,
1128
+ options,
1129
+ };
1130
+ }
1131
+ catch (err) {
1132
+ const span = trace.getActiveSpan();
1133
+ span === null || span === void 0 ? void 0 : span.recordException(err);
1134
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1135
+ console.error(`[AuthController] Error occurred while requesting WebAuthn login`, err);
1136
+ return {
1137
+ success: false,
1138
+ errorCode: 'server_error',
1139
+ errorMessage: 'A server error occurred.',
1140
+ };
1141
+ }
1142
+ }
1143
+ async completeWebAuthnLogin(request) {
1144
+ try {
1145
+ if (this._webAuthNRelyingParties.length <= 0) {
1146
+ return {
1147
+ success: false,
1148
+ errorCode: 'not_supported',
1149
+ errorMessage: 'WebAuthn is not supported on this server.',
1315
1150
  };
1316
1151
  }
1317
- });
1318
- }
1319
- deleteUserAuthenticator(userId, authenticatorId) {
1320
- return __awaiter(this, void 0, void 0, function* () {
1321
- try {
1322
- if (!userId) {
1323
- return {
1324
- success: false,
1325
- errorCode: 'not_logged_in',
1326
- errorMessage: 'You need to be logged in for the operation to work.',
1327
- };
1328
- }
1329
- const numDeleted = yield this._store.deleteUserAuthenticator(userId, authenticatorId);
1330
- if (numDeleted <= 0) {
1331
- return {
1332
- success: false,
1333
- errorCode: 'not_found',
1334
- errorMessage: 'The given authenticator was not found.',
1335
- };
1336
- }
1152
+ const relyingParty = findRelyingPartyForOrigin(this._webAuthNRelyingParties, request.originOrHost);
1153
+ if (!relyingParty) {
1337
1154
  return {
1338
- success: true,
1155
+ success: false,
1156
+ errorCode: 'invalid_origin',
1157
+ errorMessage: 'The request must be made from an authorized origin.',
1339
1158
  };
1340
1159
  }
1341
- catch (err) {
1342
- const span = trace.getActiveSpan();
1343
- span === null || span === void 0 ? void 0 : span.recordException(err);
1344
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1345
- console.error(`[AuthController] Error occurred while deleting a user authenticator`, err);
1160
+ const loginRequest = await this._store.findWebAuthnLoginRequest(request.requestId);
1161
+ if (!loginRequest) {
1162
+ console.error('could not find login request!');
1346
1163
  return {
1347
1164
  success: false,
1348
- errorCode: 'server_error',
1349
- errorMessage: 'A server error occurred.',
1165
+ errorCode: 'invalid_request',
1166
+ errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
1350
1167
  };
1351
1168
  }
1352
- });
1353
- }
1354
- validateSessionKey(key) {
1355
- return __awaiter(this, void 0, void 0, function* () {
1356
- if (typeof key !== 'string' || key === '') {
1169
+ let validRequest = true;
1170
+ if (Date.now() >= loginRequest.expireTimeMs) {
1171
+ console.error('Expired!');
1172
+ validRequest = false;
1173
+ }
1174
+ else if (loginRequest.completedTimeMs > 0) {
1175
+ console.error('Completed!');
1176
+ validRequest = false;
1177
+ }
1178
+ else if (loginRequest.ipAddress !== request.ipAddress) {
1179
+ console.error('Wrong IP!');
1180
+ validRequest = false;
1181
+ }
1182
+ if (!validRequest) {
1357
1183
  return {
1358
1184
  success: false,
1359
- errorCode: 'unacceptable_session_key',
1360
- errorMessage: 'The given session key is invalid. It must be a correctly formatted string.',
1185
+ errorCode: 'invalid_request',
1186
+ errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
1187
+ };
1188
+ }
1189
+ const { authenticator, user } = await this._store.findUserAuthenticatorByCredentialId(request.response.id);
1190
+ if (!authenticator) {
1191
+ console.error('No Authenticator!');
1192
+ return {
1193
+ success: false,
1194
+ errorCode: 'invalid_request',
1195
+ errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
1196
+ };
1197
+ }
1198
+ if (user.banTimeMs > 0) {
1199
+ return {
1200
+ success: false,
1201
+ errorCode: 'user_is_banned',
1202
+ errorMessage: 'The user has been banned.',
1203
+ banReason: user.banReason,
1361
1204
  };
1362
1205
  }
1363
1206
  try {
1364
- const keyValues = parseSessionKey(key);
1365
- if (!keyValues) {
1366
- console.log('[AuthController] [validateSessionKey] Could not parse key.');
1367
- return {
1368
- success: false,
1369
- errorCode: 'unacceptable_session_key',
1370
- errorMessage: 'The given session key is invalid. It must be a correctly formatted string.',
1371
- };
1372
- }
1373
- const [userId, sessionId, sessionSecret] = keyValues;
1374
- const session = yield this._store.findSession(userId, sessionId);
1375
- if (!session) {
1376
- console.log('[AuthController] [validateSessionKey] Could not find session.');
1377
- return {
1378
- success: false,
1379
- errorCode: 'invalid_key',
1380
- errorMessage: INVALID_KEY_ERROR_MESSAGE,
1381
- };
1382
- }
1383
- if (!this.verifyPasswordAgainstHashes(sessionSecret, session.sessionId, [session.secretHash])) {
1384
- console.log('[AuthController] [validateSessionKey] Session secret was invalid.');
1385
- return {
1386
- success: false,
1387
- errorCode: 'invalid_key',
1388
- errorMessage: INVALID_KEY_ERROR_MESSAGE,
1389
- };
1390
- }
1391
- const now = Date.now();
1392
- if (session.revokeTimeMs && now >= session.revokeTimeMs) {
1393
- console.log('[AuthController] [validateSessionKey] Session has been revoked.');
1394
- return {
1395
- success: false,
1396
- errorCode: 'invalid_key',
1397
- errorMessage: INVALID_KEY_ERROR_MESSAGE,
1398
- };
1399
- }
1400
- if (typeof session.expireTimeMs === 'number' &&
1401
- now >= session.expireTimeMs) {
1402
- console.log('[AuthController] [validateSessionKey] Session has expired.', session);
1403
- return {
1404
- success: false,
1405
- errorCode: 'session_expired',
1406
- errorMessage: 'The session has expired.',
1407
- };
1408
- }
1409
- const userInfo = yield this._store.findUser(userId);
1410
- if (!userInfo) {
1411
- console.log('[AuthController] [validateSessionKey] Unable to find user!');
1207
+ const options = await verifyAuthenticationResponse({
1208
+ response: request.response,
1209
+ expectedChallenge: loginRequest.challenge,
1210
+ expectedOrigin: relyingParty.origin,
1211
+ expectedRPID: relyingParty.id,
1212
+ authenticator: {
1213
+ credentialID: new Uint8Array(base64URLStringToBuffer(authenticator.credentialId)),
1214
+ counter: authenticator.counter,
1215
+ credentialPublicKey: authenticator.credentialPublicKey,
1216
+ transports: authenticator.transports,
1217
+ },
1218
+ });
1219
+ if (!options.verified) {
1220
+ console.error('Not verified!');
1412
1221
  return {
1413
1222
  success: false,
1414
- errorCode: 'invalid_key',
1415
- errorMessage: INVALID_KEY_ERROR_MESSAGE,
1223
+ errorCode: 'invalid_request',
1224
+ errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
1416
1225
  };
1417
1226
  }
1418
- else {
1419
- if (typeof userInfo.allSessionRevokeTimeMs === 'number') {
1420
- if (userInfo.allSessionRevokeTimeMs >=
1421
- session.grantedTimeMs &&
1422
- (session.revocable !== false || !!session.revokeTimeMs)) {
1423
- return {
1424
- success: false,
1425
- errorCode: 'invalid_key',
1426
- errorMessage: INVALID_KEY_ERROR_MESSAGE,
1427
- };
1428
- }
1429
- }
1430
- if (userInfo.banTimeMs > 0) {
1431
- return {
1432
- success: false,
1433
- errorCode: 'user_is_banned',
1434
- errorMessage: 'The user has been banned.',
1435
- banReason: userInfo.banReason,
1436
- };
1437
- }
1438
- }
1439
- const { subscriptionId, subscriptionTier } = yield this._getSubscriptionInfo(userInfo);
1227
+ await this._store.saveUserAuthenticatorCounter(authenticator.id, options.authenticationInfo.newCounter);
1228
+ }
1229
+ catch (err) {
1230
+ console.error(`[AuthController] Error occurred while verifying WebAuthn login response`, err);
1440
1231
  return {
1441
- success: true,
1442
- userId: session.userId,
1443
- sessionId: session.sessionId,
1444
- allSessionsRevokedTimeMs: userInfo.allSessionRevokeTimeMs,
1445
- subscriptionId: subscriptionId !== null && subscriptionId !== void 0 ? subscriptionId : undefined,
1446
- subscriptionTier: subscriptionTier !== null && subscriptionTier !== void 0 ? subscriptionTier : undefined,
1447
- privacyFeatures: userInfo.privacyFeatures,
1448
- role: userInfo.role,
1232
+ success: false,
1233
+ errorCode: 'invalid_request',
1234
+ errorMessage: err.message,
1449
1235
  };
1450
1236
  }
1451
- catch (err) {
1452
- const span = trace.getActiveSpan();
1453
- span === null || span === void 0 ? void 0 : span.recordException(err);
1454
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1455
- console.error('[AuthController] Error ocurred while validating a session key', err);
1237
+ const { info } = await this._issueSession({
1238
+ userId: user.id,
1239
+ lifetimeMs: SESSION_LIFETIME_MS,
1240
+ ipAddress: request.ipAddress,
1241
+ webauthnRequestId: loginRequest.requestId,
1242
+ oidRequestId: null,
1243
+ });
1244
+ return {
1245
+ success: true,
1246
+ ...info,
1247
+ };
1248
+ }
1249
+ catch (err) {
1250
+ const span = trace.getActiveSpan();
1251
+ span === null || span === void 0 ? void 0 : span.recordException(err);
1252
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1253
+ console.error(`[AuthController] Error occurred while requesting WebAuthn login`, err);
1254
+ return {
1255
+ success: false,
1256
+ errorCode: 'server_error',
1257
+ errorMessage: 'A server error occurred.',
1258
+ };
1259
+ }
1260
+ }
1261
+ async listUserAuthenticators(userId) {
1262
+ try {
1263
+ if (!userId) {
1456
1264
  return {
1457
1265
  success: false,
1458
- errorCode: 'server_error',
1459
- errorMessage: 'A server error occurred.',
1266
+ errorCode: 'not_logged_in',
1267
+ errorMessage: 'You need to be logged in for the operation to work.',
1460
1268
  };
1461
1269
  }
1462
- });
1270
+ const authenticators = await this._store.listUserAuthenticators(userId);
1271
+ return {
1272
+ success: true,
1273
+ authenticators: authenticators.map((a) => ({
1274
+ id: a.id,
1275
+ aaguid: a.aaguid,
1276
+ userId: a.userId,
1277
+ credentialId: a.credentialId,
1278
+ credentialDeviceType: a.credentialDeviceType,
1279
+ credentialBackedUp: a.credentialBackedUp,
1280
+ counter: a.counter,
1281
+ transports: a.transports,
1282
+ registeringUserAgent: a.registeringUserAgent,
1283
+ createdAtMs: a.createdAtMs,
1284
+ })),
1285
+ };
1286
+ }
1287
+ catch (err) {
1288
+ const span = trace.getActiveSpan();
1289
+ span === null || span === void 0 ? void 0 : span.recordException(err);
1290
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1291
+ console.error(`[AuthController] Error occurred while listing user authenticators`, err);
1292
+ return {
1293
+ success: false,
1294
+ errorCode: 'server_error',
1295
+ errorMessage: 'A server error occurred.',
1296
+ };
1297
+ }
1463
1298
  }
1464
- verifyPasswordAgainstHashes(sessionSecret, sessionId, hashes) {
1465
- return verifyPasswordAgainstHashes(sessionSecret, sessionId, hashes);
1299
+ async deleteUserAuthenticator(userId, authenticatorId) {
1300
+ try {
1301
+ if (!userId) {
1302
+ return {
1303
+ success: false,
1304
+ errorCode: 'not_logged_in',
1305
+ errorMessage: 'You need to be logged in for the operation to work.',
1306
+ };
1307
+ }
1308
+ const numDeleted = await this._store.deleteUserAuthenticator(userId, authenticatorId);
1309
+ if (numDeleted <= 0) {
1310
+ return {
1311
+ success: false,
1312
+ errorCode: 'not_found',
1313
+ errorMessage: 'The given authenticator was not found.',
1314
+ };
1315
+ }
1316
+ return {
1317
+ success: true,
1318
+ };
1319
+ }
1320
+ catch (err) {
1321
+ const span = trace.getActiveSpan();
1322
+ span === null || span === void 0 ? void 0 : span.recordException(err);
1323
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1324
+ console.error(`[AuthController] Error occurred while deleting a user authenticator`, err);
1325
+ return {
1326
+ success: false,
1327
+ errorCode: 'server_error',
1328
+ errorMessage: 'A server error occurred.',
1329
+ };
1330
+ }
1466
1331
  }
1467
- validateConnectionToken(token) {
1468
- return __awaiter(this, void 0, void 0, function* () {
1469
- if (typeof token !== 'string' || token === '') {
1332
+ async validateSessionKey(key) {
1333
+ if (typeof key !== 'string' || key === '') {
1334
+ return {
1335
+ success: false,
1336
+ errorCode: 'unacceptable_session_key',
1337
+ errorMessage: 'The given session key is invalid. It must be a correctly formatted string.',
1338
+ };
1339
+ }
1340
+ try {
1341
+ const keyValues = parseSessionKey(key);
1342
+ if (!keyValues) {
1343
+ console.log('[AuthController] [validateSessionKey] Could not parse key.');
1470
1344
  return {
1471
1345
  success: false,
1472
- errorCode: 'unacceptable_connection_token',
1473
- errorMessage: 'The given connection token is invalid. It must be a correctly formatted string.',
1346
+ errorCode: 'unacceptable_session_key',
1347
+ errorMessage: 'The given session key is invalid. It must be a correctly formatted string.',
1474
1348
  };
1475
1349
  }
1476
- try {
1477
- const tokenValues = parseConnectionToken(token);
1478
- if (!tokenValues) {
1479
- console.log('[AuthController] [validateConnectionToken] Could not parse token.');
1480
- return {
1481
- success: false,
1482
- errorCode: 'unacceptable_connection_token',
1483
- errorMessage: 'The given connection token is invalid. It must be a correctly formatted string.',
1484
- };
1485
- }
1486
- const [userId, sessionId, connectionId, recordName, inst, hash] = tokenValues;
1487
- const session = yield this._store.findSession(userId, sessionId);
1488
- if (!session) {
1489
- console.log('[AuthController] [validateConnectionToken] Could not find session.');
1490
- return {
1491
- success: false,
1492
- errorCode: 'invalid_token',
1493
- errorMessage: INVALID_TOKEN_ERROR_MESSAGE,
1494
- };
1495
- }
1496
- if (!verifyConnectionToken(token, session.connectionSecret)) {
1497
- console.log('[AuthController] [validateConnectionToken] Connection token was invalid.');
1498
- return {
1499
- success: false,
1500
- errorCode: 'invalid_token',
1501
- errorMessage: INVALID_TOKEN_ERROR_MESSAGE,
1502
- };
1503
- }
1504
- const now = Date.now();
1505
- if (session.revokeTimeMs && now >= session.revokeTimeMs) {
1506
- console.log('[AuthController] [validateConnectionToken] Session has been revoked.');
1507
- return {
1508
- success: false,
1509
- errorCode: 'invalid_token',
1510
- errorMessage: INVALID_TOKEN_ERROR_MESSAGE,
1511
- };
1512
- }
1513
- if (typeof session.expireTimeMs === 'number' &&
1514
- now >= session.expireTimeMs) {
1515
- console.log('[AuthController] [validateConnectionToken] Session has expired.');
1516
- return {
1517
- success: false,
1518
- errorCode: 'session_expired',
1519
- errorMessage: 'The session has expired.',
1520
- };
1521
- }
1522
- const userInfo = yield this._store.findUser(userId);
1523
- if (!userInfo) {
1524
- console.log('[AuthController] [validateConnectionToken] Unable to find user!');
1525
- return {
1526
- success: false,
1527
- errorCode: 'invalid_token',
1528
- errorMessage: INVALID_TOKEN_ERROR_MESSAGE,
1529
- };
1530
- }
1531
- else {
1532
- if (typeof userInfo.allSessionRevokeTimeMs === 'number') {
1533
- if (userInfo.allSessionRevokeTimeMs >=
1534
- session.grantedTimeMs &&
1535
- (session.revocable !== false || !!session.revokeTimeMs)) {
1536
- return {
1537
- success: false,
1538
- errorCode: 'invalid_token',
1539
- errorMessage: INVALID_TOKEN_ERROR_MESSAGE,
1540
- };
1541
- }
1542
- }
1543
- if (userInfo.banTimeMs > 0) {
1544
- return {
1545
- success: false,
1546
- errorCode: 'user_is_banned',
1547
- errorMessage: 'The user has been banned.',
1548
- banReason: userInfo.banReason,
1549
- };
1550
- }
1551
- }
1552
- const { subscriptionId, subscriptionTier } = yield this._getSubscriptionInfo(userInfo);
1350
+ const [userId, sessionId, sessionSecret] = keyValues;
1351
+ const session = await this._store.findSession(userId, sessionId);
1352
+ if (!session) {
1353
+ console.log('[AuthController] [validateSessionKey] Could not find session.');
1553
1354
  return {
1554
- success: true,
1555
- userId: session.userId,
1556
- sessionId: session.sessionId,
1557
- connectionId: connectionId,
1558
- recordName: recordName,
1559
- inst: inst,
1560
- allSessionsRevokedTimeMs: userInfo.allSessionRevokeTimeMs,
1561
- subscriptionId: subscriptionId !== null && subscriptionId !== void 0 ? subscriptionId : undefined,
1562
- subscriptionTier: subscriptionTier !== null && subscriptionTier !== void 0 ? subscriptionTier : undefined,
1563
- privacyFeatures: userInfo.privacyFeatures,
1355
+ success: false,
1356
+ errorCode: 'invalid_key',
1357
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
1564
1358
  };
1565
1359
  }
1566
- catch (err) {
1567
- const span = trace.getActiveSpan();
1568
- span === null || span === void 0 ? void 0 : span.recordException(err);
1569
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1570
- console.error('[AuthController] Error ocurred while validating a connection token', err);
1360
+ if (!this.verifyPasswordAgainstHashes(sessionSecret, session.sessionId, [session.secretHash])) {
1361
+ console.log('[AuthController] [validateSessionKey] Session secret was invalid.');
1571
1362
  return {
1572
1363
  success: false,
1573
- errorCode: 'server_error',
1574
- errorMessage: 'A server error occurred.',
1364
+ errorCode: 'invalid_key',
1365
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
1575
1366
  };
1576
1367
  }
1577
- });
1578
- }
1579
- revokeSession(request) {
1580
- var _a;
1581
- return __awaiter(this, void 0, void 0, function* () {
1582
- if (typeof request.userId !== 'string' || request.userId === '') {
1368
+ const now = Date.now();
1369
+ if (session.revokeTimeMs && now >= session.revokeTimeMs) {
1370
+ console.log('[AuthController] [validateSessionKey] Session has been revoked.');
1583
1371
  return {
1584
1372
  success: false,
1585
- errorCode: 'unacceptable_user_id',
1586
- errorMessage: 'The given userId is invalid. It must be a string.',
1373
+ errorCode: 'invalid_key',
1374
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
1587
1375
  };
1588
1376
  }
1589
- else if (typeof request.sessionId !== 'string' ||
1590
- request.sessionId === '') {
1377
+ if (typeof session.expireTimeMs === 'number' &&
1378
+ now >= session.expireTimeMs) {
1379
+ console.log('[AuthController] [validateSessionKey] Session has expired.', session);
1591
1380
  return {
1592
1381
  success: false,
1593
- errorCode: 'unacceptable_session_id',
1594
- errorMessage: 'The given sessionId is invalid. It must be a string.',
1382
+ errorCode: 'session_expired',
1383
+ errorMessage: 'The session has expired.',
1595
1384
  };
1596
1385
  }
1597
- else if (typeof request.sessionKey !== 'string' ||
1598
- request.sessionKey === '') {
1386
+ const userInfo = await this._store.findUser(userId);
1387
+ if (!userInfo) {
1388
+ console.log('[AuthController] [validateSessionKey] Unable to find user!');
1599
1389
  return {
1600
1390
  success: false,
1601
- errorCode: 'unacceptable_session_key',
1602
- errorMessage: 'The given session key is invalid. It must be a string.',
1391
+ errorCode: 'invalid_key',
1392
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
1603
1393
  };
1604
1394
  }
1605
- try {
1606
- const keyResult = yield this.validateSessionKey(request.sessionKey);
1607
- if (keyResult.success === false) {
1608
- return keyResult;
1609
- }
1610
- else if (keyResult.userId !== request.userId) {
1611
- return {
1612
- success: false,
1613
- errorCode: 'invalid_key',
1614
- errorMessage: INVALID_KEY_ERROR_MESSAGE,
1615
- };
1616
- }
1617
- const session = yield this._store.findSession(request.userId, request.sessionId);
1618
- if (!session) {
1619
- return {
1620
- success: false,
1621
- errorCode: 'session_not_found',
1622
- errorMessage: 'The session was not found.',
1623
- };
1624
- }
1625
- if (session.revokeTimeMs) {
1626
- return {
1627
- success: false,
1628
- errorCode: 'session_already_revoked',
1629
- errorMessage: 'The session has already been revoked.',
1630
- };
1395
+ else {
1396
+ if (typeof userInfo.allSessionRevokeTimeMs === 'number') {
1397
+ if (userInfo.allSessionRevokeTimeMs >=
1398
+ session.grantedTimeMs &&
1399
+ (session.revocable !== false || !!session.revokeTimeMs)) {
1400
+ return {
1401
+ success: false,
1402
+ errorCode: 'invalid_key',
1403
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
1404
+ };
1405
+ }
1631
1406
  }
1632
- if (session.revocable === false) {
1407
+ if (userInfo.banTimeMs > 0) {
1633
1408
  return {
1634
1409
  success: false,
1635
- errorCode: 'session_is_not_revokable',
1636
- errorMessage: 'The session cannot be revoked.',
1410
+ errorCode: 'user_is_banned',
1411
+ errorMessage: 'The user has been banned.',
1412
+ banReason: userInfo.banReason,
1637
1413
  };
1638
1414
  }
1639
- const newSession = Object.assign(Object.assign({}, session), { revokeTimeMs: Date.now() });
1640
- yield this._store.saveSession(newSession);
1641
- let logoutUrl;
1642
- if (session.oidProvider === PRIVO_OPEN_ID_PROVIDER) {
1643
- logoutUrl = yield this._privoClient.generateLogoutUrl((_a = session.oidIdToken) !== null && _a !== void 0 ? _a : session.oidAccessToken);
1644
- }
1645
- return {
1646
- success: true,
1647
- logoutUrl,
1648
- };
1649
- }
1650
- catch (err) {
1651
- const span = trace.getActiveSpan();
1652
- span === null || span === void 0 ? void 0 : span.recordException(err);
1653
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1654
- console.error('[AuthController] Error ocurred while revoking session', err);
1655
- return {
1656
- success: false,
1657
- errorCode: 'server_error',
1658
- errorMessage: 'A server error ocurred.',
1659
- };
1660
1415
  }
1661
- });
1416
+ const { subscriptionId, subscriptionTier } = await this._getSubscriptionInfo(userInfo);
1417
+ return {
1418
+ success: true,
1419
+ userId: session.userId,
1420
+ sessionId: session.sessionId,
1421
+ allSessionsRevokedTimeMs: userInfo.allSessionRevokeTimeMs,
1422
+ subscriptionId: subscriptionId !== null && subscriptionId !== void 0 ? subscriptionId : undefined,
1423
+ subscriptionTier: subscriptionTier !== null && subscriptionTier !== void 0 ? subscriptionTier : undefined,
1424
+ privacyFeatures: userInfo.privacyFeatures,
1425
+ role: userInfo.role,
1426
+ };
1427
+ }
1428
+ catch (err) {
1429
+ const span = trace.getActiveSpan();
1430
+ span === null || span === void 0 ? void 0 : span.recordException(err);
1431
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1432
+ console.error('[AuthController] Error ocurred while validating a session key', err);
1433
+ return {
1434
+ success: false,
1435
+ errorCode: 'server_error',
1436
+ errorMessage: 'A server error occurred.',
1437
+ };
1438
+ }
1662
1439
  }
1663
- /**
1664
- * Attempts to revoke all the sessions for the specified user.
1665
- * @param request The request.
1666
- */
1667
- revokeAllSessions(request) {
1668
- return __awaiter(this, void 0, void 0, function* () {
1669
- if (typeof request.userId !== 'string' || request.userId === '') {
1440
+ verifyPasswordAgainstHashes(sessionSecret, sessionId, hashes) {
1441
+ return verifyPasswordAgainstHashes(sessionSecret, sessionId, hashes);
1442
+ }
1443
+ async validateConnectionToken(token) {
1444
+ if (typeof token !== 'string' || token === '') {
1445
+ return {
1446
+ success: false,
1447
+ errorCode: 'unacceptable_connection_token',
1448
+ errorMessage: 'The given connection token is invalid. It must be a correctly formatted string.',
1449
+ };
1450
+ }
1451
+ try {
1452
+ const tokenValues = parseConnectionToken(token);
1453
+ if (!tokenValues) {
1454
+ console.log('[AuthController] [validateConnectionToken] Could not parse token.');
1670
1455
  return {
1671
1456
  success: false,
1672
- errorCode: 'unacceptable_user_id',
1673
- errorMessage: 'The given userId is invalid. It must be a string.',
1457
+ errorCode: 'unacceptable_connection_token',
1458
+ errorMessage: 'The given connection token is invalid. It must be a correctly formatted string.',
1674
1459
  };
1675
1460
  }
1676
- else if (typeof request.sessionKey !== 'string' ||
1677
- request.sessionKey === '') {
1461
+ const [userId, sessionId, connectionId, recordName, inst, hash] = tokenValues;
1462
+ const session = await this._store.findSession(userId, sessionId);
1463
+ if (!session) {
1464
+ console.log('[AuthController] [validateConnectionToken] Could not find session.');
1678
1465
  return {
1679
1466
  success: false,
1680
- errorCode: 'unacceptable_session_key',
1681
- errorMessage: 'The given session key is invalid. It must be a string.',
1467
+ errorCode: 'invalid_token',
1468
+ errorMessage: INVALID_TOKEN_ERROR_MESSAGE,
1682
1469
  };
1683
1470
  }
1684
- try {
1685
- const keyResult = yield this.validateSessionKey(request.sessionKey);
1686
- if (keyResult.success === false) {
1687
- return keyResult;
1688
- }
1689
- else if (keyResult.userId !== request.userId) {
1690
- return {
1691
- success: false,
1692
- errorCode: 'invalid_key',
1693
- errorMessage: INVALID_KEY_ERROR_MESSAGE,
1694
- };
1695
- }
1696
- yield this._store.setRevokeAllSessionsTimeForUser(request.userId, Date.now());
1471
+ if (!verifyConnectionToken(token, session.connectionSecret)) {
1472
+ console.log('[AuthController] [validateConnectionToken] Connection token was invalid.');
1697
1473
  return {
1698
- success: true,
1474
+ success: false,
1475
+ errorCode: 'invalid_token',
1476
+ errorMessage: INVALID_TOKEN_ERROR_MESSAGE,
1699
1477
  };
1700
1478
  }
1701
- catch (err) {
1702
- const span = trace.getActiveSpan();
1703
- span === null || span === void 0 ? void 0 : span.recordException(err);
1704
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1705
- console.error('[AuthController] Error ocurred while revoking all sessions', err);
1479
+ const now = Date.now();
1480
+ if (session.revokeTimeMs && now >= session.revokeTimeMs) {
1481
+ console.log('[AuthController] [validateConnectionToken] Session has been revoked.');
1706
1482
  return {
1707
1483
  success: false,
1708
- errorCode: 'server_error',
1709
- errorMessage: 'A server error occurred.',
1484
+ errorCode: 'invalid_token',
1485
+ errorMessage: INVALID_TOKEN_ERROR_MESSAGE,
1710
1486
  };
1711
1487
  }
1712
- });
1713
- }
1714
- /**
1715
- * Attempts to replace the given session key with a new key.
1716
- * @param request The request.
1717
- */
1718
- replaceSession(request) {
1719
- return __awaiter(this, void 0, void 0, function* () {
1720
- if (typeof request.sessionKey !== 'string' ||
1721
- request.sessionKey === '') {
1488
+ if (typeof session.expireTimeMs === 'number' &&
1489
+ now >= session.expireTimeMs) {
1490
+ console.log('[AuthController] [validateConnectionToken] Session has expired.');
1722
1491
  return {
1723
1492
  success: false,
1724
- errorCode: 'unacceptable_session_key',
1725
- errorMessage: 'The given sessionKey is invalid. It must be a string.',
1493
+ errorCode: 'session_expired',
1494
+ errorMessage: 'The session has expired.',
1726
1495
  };
1727
1496
  }
1728
- else if (typeof request.ipAddress !== 'string' ||
1729
- request.ipAddress === '') {
1497
+ const userInfo = await this._store.findUser(userId);
1498
+ if (!userInfo) {
1499
+ console.log('[AuthController] [validateConnectionToken] Unable to find user!');
1730
1500
  return {
1731
1501
  success: false,
1732
- errorCode: 'unacceptable_ip_address',
1733
- errorMessage: 'The given IP address is invalid. It must be a string.',
1502
+ errorCode: 'invalid_token',
1503
+ errorMessage: INVALID_TOKEN_ERROR_MESSAGE,
1734
1504
  };
1735
1505
  }
1736
- try {
1737
- const keyResult = yield this.validateSessionKey(request.sessionKey);
1738
- if (keyResult.success === false) {
1739
- return keyResult;
1740
- }
1741
- const userId = keyResult.userId;
1742
- const session = yield this._store.findSession(userId, keyResult.sessionId);
1743
- if (!session) {
1744
- console.log('[AuthController] [replaceSession] Could not find session.');
1745
- return {
1746
- success: false,
1747
- errorCode: 'invalid_key',
1748
- errorMessage: INVALID_KEY_ERROR_MESSAGE,
1749
- };
1506
+ else {
1507
+ if (typeof userInfo.allSessionRevokeTimeMs === 'number') {
1508
+ if (userInfo.allSessionRevokeTimeMs >=
1509
+ session.grantedTimeMs &&
1510
+ (session.revocable !== false || !!session.revokeTimeMs)) {
1511
+ return {
1512
+ success: false,
1513
+ errorCode: 'invalid_token',
1514
+ errorMessage: INVALID_TOKEN_ERROR_MESSAGE,
1515
+ };
1516
+ }
1750
1517
  }
1751
- if (session.revocable === false) {
1752
- console.log('[AuthController] [replaceSession] Session is irrevokable.');
1518
+ if (userInfo.banTimeMs > 0) {
1753
1519
  return {
1754
1520
  success: false,
1755
- errorCode: 'invalid_key',
1756
- errorMessage: INVALID_KEY_ERROR_MESSAGE,
1521
+ errorCode: 'user_is_banned',
1522
+ errorMessage: 'The user has been banned.',
1523
+ banReason: userInfo.banReason,
1757
1524
  };
1758
1525
  }
1759
- const { info } = yield this._issueSession({
1760
- userId,
1761
- lifetimeMs: SESSION_LIFETIME_MS,
1762
- previousSession: session,
1763
- ipAddress: request.ipAddress,
1764
- });
1765
- return Object.assign({ success: true }, info);
1766
1526
  }
1767
- catch (err) {
1768
- const span = trace.getActiveSpan();
1769
- span === null || span === void 0 ? void 0 : span.recordException(err);
1770
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1771
- console.error('[AuthController] Error ocurred while replacing session', err);
1527
+ const { subscriptionId, subscriptionTier } = await this._getSubscriptionInfo(userInfo);
1528
+ return {
1529
+ success: true,
1530
+ userId: session.userId,
1531
+ sessionId: session.sessionId,
1532
+ connectionId: connectionId,
1533
+ recordName: recordName,
1534
+ inst: inst,
1535
+ allSessionsRevokedTimeMs: userInfo.allSessionRevokeTimeMs,
1536
+ subscriptionId: subscriptionId !== null && subscriptionId !== void 0 ? subscriptionId : undefined,
1537
+ subscriptionTier: subscriptionTier !== null && subscriptionTier !== void 0 ? subscriptionTier : undefined,
1538
+ privacyFeatures: userInfo.privacyFeatures,
1539
+ };
1540
+ }
1541
+ catch (err) {
1542
+ const span = trace.getActiveSpan();
1543
+ span === null || span === void 0 ? void 0 : span.recordException(err);
1544
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1545
+ console.error('[AuthController] Error ocurred while validating a connection token', err);
1546
+ return {
1547
+ success: false,
1548
+ errorCode: 'server_error',
1549
+ errorMessage: 'A server error occurred.',
1550
+ };
1551
+ }
1552
+ }
1553
+ async revokeSession(request) {
1554
+ var _a;
1555
+ if (typeof request.userId !== 'string' || request.userId === '') {
1556
+ return {
1557
+ success: false,
1558
+ errorCode: 'unacceptable_user_id',
1559
+ errorMessage: 'The given userId is invalid. It must be a string.',
1560
+ };
1561
+ }
1562
+ else if (typeof request.sessionId !== 'string' ||
1563
+ request.sessionId === '') {
1564
+ return {
1565
+ success: false,
1566
+ errorCode: 'unacceptable_session_id',
1567
+ errorMessage: 'The given sessionId is invalid. It must be a string.',
1568
+ };
1569
+ }
1570
+ else if (typeof request.sessionKey !== 'string' ||
1571
+ request.sessionKey === '') {
1572
+ return {
1573
+ success: false,
1574
+ errorCode: 'unacceptable_session_key',
1575
+ errorMessage: 'The given session key is invalid. It must be a string.',
1576
+ };
1577
+ }
1578
+ try {
1579
+ const keyResult = await this.validateSessionKey(request.sessionKey);
1580
+ if (keyResult.success === false) {
1581
+ return keyResult;
1582
+ }
1583
+ else if (keyResult.userId !== request.userId) {
1772
1584
  return {
1773
1585
  success: false,
1774
- errorCode: 'server_error',
1775
- errorMessage: 'A server error ocurred.',
1586
+ errorCode: 'invalid_key',
1587
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
1776
1588
  };
1777
1589
  }
1778
- });
1779
- }
1780
- /**
1781
- * Lists all the sessions for a given user.
1782
- * @param request The request.
1783
- */
1784
- listSessions(request) {
1785
- return __awaiter(this, void 0, void 0, function* () {
1786
- if (typeof request.userId !== 'string' || request.userId === '') {
1590
+ const session = await this._store.findSession(request.userId, request.sessionId);
1591
+ if (!session) {
1787
1592
  return {
1788
1593
  success: false,
1789
- errorCode: 'unacceptable_user_id',
1790
- errorMessage: 'The given userId is invalid. It must be a string.',
1594
+ errorCode: 'session_not_found',
1595
+ errorMessage: 'The session was not found.',
1791
1596
  };
1792
1597
  }
1793
- else if (typeof request.expireTimeMs !== 'number' &&
1794
- request.expireTimeMs !== null &&
1795
- typeof request.expireTimeMs !== 'undefined') {
1598
+ if (session.revokeTimeMs) {
1796
1599
  return {
1797
1600
  success: false,
1798
- errorCode: 'unacceptable_expire_time',
1799
- errorMessage: 'The given expiration time is invalid. It must be a number or null.',
1601
+ errorCode: 'session_already_revoked',
1602
+ errorMessage: 'The session has already been revoked.',
1800
1603
  };
1801
1604
  }
1802
- else if (typeof request.sessionKey !== 'string' ||
1803
- request.sessionKey === '') {
1605
+ if (session.revocable === false) {
1804
1606
  return {
1805
1607
  success: false,
1806
- errorCode: 'unacceptable_session_key',
1807
- errorMessage: 'The given session key is invalid. It must be a string.',
1608
+ errorCode: 'session_is_not_revokable',
1609
+ errorMessage: 'The session cannot be revoked.',
1808
1610
  };
1809
1611
  }
1810
- try {
1811
- const keyResult = yield this.validateSessionKey(request.sessionKey);
1812
- if (keyResult.success === false) {
1813
- return keyResult;
1814
- }
1815
- else if (!isSuperUserRole(keyResult.role) &&
1816
- keyResult.userId !== request.userId) {
1817
- return {
1818
- success: false,
1819
- errorCode: 'invalid_key',
1820
- errorMessage: INVALID_KEY_ERROR_MESSAGE,
1821
- };
1822
- }
1823
- const result = yield this._store.listSessions(request.userId, request.expireTimeMs);
1824
- if (result.success === false) {
1825
- return result;
1826
- }
1827
- return {
1828
- success: true,
1829
- sessions: result.sessions.map((s) => ({
1830
- userId: s.userId,
1831
- sessionId: s.sessionId,
1832
- grantedTimeMs: s.grantedTimeMs,
1833
- expireTimeMs: s.expireTimeMs,
1834
- revokeTimeMs: keyResult.allSessionsRevokedTimeMs >= s.grantedTimeMs &&
1835
- (!s.revokeTimeMs ||
1836
- s.revokeTimeMs > keyResult.allSessionsRevokedTimeMs)
1837
- ? keyResult.allSessionsRevokedTimeMs
1838
- : s.revokeTimeMs,
1839
- currentSession: s.sessionId === keyResult.sessionId,
1840
- ipAddress: s.ipAddress,
1841
- nextSessionId: s.nextSessionId,
1842
- })),
1843
- };
1612
+ const newSession = {
1613
+ ...session,
1614
+ revokeTimeMs: Date.now(),
1615
+ };
1616
+ await this._store.saveSession(newSession);
1617
+ let logoutUrl;
1618
+ if (session.oidProvider === PRIVO_OPEN_ID_PROVIDER) {
1619
+ logoutUrl = await this._privoClient.generateLogoutUrl((_a = session.oidIdToken) !== null && _a !== void 0 ? _a : session.oidAccessToken);
1844
1620
  }
1845
- catch (err) {
1846
- const span = trace.getActiveSpan();
1847
- span === null || span === void 0 ? void 0 : span.recordException(err);
1848
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1849
- console.error('[AuthController] Error ocurred while listing sessions', err);
1621
+ return {
1622
+ success: true,
1623
+ logoutUrl,
1624
+ };
1625
+ }
1626
+ catch (err) {
1627
+ const span = trace.getActiveSpan();
1628
+ span === null || span === void 0 ? void 0 : span.recordException(err);
1629
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1630
+ console.error('[AuthController] Error ocurred while revoking session', err);
1631
+ return {
1632
+ success: false,
1633
+ errorCode: 'server_error',
1634
+ errorMessage: 'A server error ocurred.',
1635
+ };
1636
+ }
1637
+ }
1638
+ /**
1639
+ * Attempts to revoke all the sessions for the specified user.
1640
+ * @param request The request.
1641
+ */
1642
+ async revokeAllSessions(request) {
1643
+ if (typeof request.userId !== 'string' || request.userId === '') {
1644
+ return {
1645
+ success: false,
1646
+ errorCode: 'unacceptable_user_id',
1647
+ errorMessage: 'The given userId is invalid. It must be a string.',
1648
+ };
1649
+ }
1650
+ else if (typeof request.sessionKey !== 'string' ||
1651
+ request.sessionKey === '') {
1652
+ return {
1653
+ success: false,
1654
+ errorCode: 'unacceptable_session_key',
1655
+ errorMessage: 'The given session key is invalid. It must be a string.',
1656
+ };
1657
+ }
1658
+ try {
1659
+ const keyResult = await this.validateSessionKey(request.sessionKey);
1660
+ if (keyResult.success === false) {
1661
+ return keyResult;
1662
+ }
1663
+ else if (keyResult.userId !== request.userId) {
1850
1664
  return {
1851
1665
  success: false,
1852
- errorCode: 'server_error',
1853
- errorMessage: 'A server error occurred.',
1666
+ errorCode: 'invalid_key',
1667
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
1854
1668
  };
1855
1669
  }
1856
- });
1670
+ await this._store.setRevokeAllSessionsTimeForUser(request.userId, Date.now());
1671
+ return {
1672
+ success: true,
1673
+ };
1674
+ }
1675
+ catch (err) {
1676
+ const span = trace.getActiveSpan();
1677
+ span === null || span === void 0 ? void 0 : span.recordException(err);
1678
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1679
+ console.error('[AuthController] Error ocurred while revoking all sessions', err);
1680
+ return {
1681
+ success: false,
1682
+ errorCode: 'server_error',
1683
+ errorMessage: 'A server error occurred.',
1684
+ };
1685
+ }
1857
1686
  }
1858
1687
  /**
1859
- * Gets the information for a specific user.
1688
+ * Attempts to replace the given session key with a new key.
1860
1689
  * @param request The request.
1861
1690
  */
1862
- getUserInfo(request) {
1863
- var _a, _b, _c, _d, _e;
1864
- return __awaiter(this, void 0, void 0, function* () {
1865
- if (typeof request.userId !== 'string' || request.userId === '') {
1691
+ async replaceSession(request) {
1692
+ if (typeof request.sessionKey !== 'string' ||
1693
+ request.sessionKey === '') {
1694
+ return {
1695
+ success: false,
1696
+ errorCode: 'unacceptable_session_key',
1697
+ errorMessage: 'The given sessionKey is invalid. It must be a string.',
1698
+ };
1699
+ }
1700
+ else if (typeof request.ipAddress !== 'string' ||
1701
+ request.ipAddress === '') {
1702
+ return {
1703
+ success: false,
1704
+ errorCode: 'unacceptable_ip_address',
1705
+ errorMessage: 'The given IP address is invalid. It must be a string.',
1706
+ };
1707
+ }
1708
+ try {
1709
+ const keyResult = await this.validateSessionKey(request.sessionKey);
1710
+ if (keyResult.success === false) {
1711
+ return keyResult;
1712
+ }
1713
+ const userId = keyResult.userId;
1714
+ const session = await this._store.findSession(userId, keyResult.sessionId);
1715
+ if (!session) {
1716
+ console.log('[AuthController] [replaceSession] Could not find session.');
1866
1717
  return {
1867
1718
  success: false,
1868
- errorCode: 'unacceptable_user_id',
1869
- errorMessage: 'The given userId is invalid. It must be a string.',
1719
+ errorCode: 'invalid_key',
1720
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
1870
1721
  };
1871
1722
  }
1872
- else if (typeof request.sessionKey !== 'string' ||
1873
- request.sessionKey === '') {
1723
+ if (session.revocable === false) {
1724
+ console.log('[AuthController] [replaceSession] Session is irrevokable.');
1874
1725
  return {
1875
1726
  success: false,
1876
- errorCode: 'unacceptable_session_key',
1877
- errorMessage: 'The given session key is invalid. It must be a string.',
1727
+ errorCode: 'invalid_key',
1728
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
1878
1729
  };
1879
1730
  }
1880
- try {
1881
- const keyResult = yield this.validateSessionKey(request.sessionKey);
1882
- if (keyResult.success === false) {
1883
- return keyResult;
1884
- }
1885
- else if (!isSuperUserRole(keyResult.role) &&
1886
- keyResult.userId !== request.userId) {
1887
- console.log('[AuthController] [getUserInfo] Request User ID doesnt match session key User ID!');
1888
- return {
1889
- success: false,
1890
- errorCode: 'invalid_key',
1891
- errorMessage: INVALID_KEY_ERROR_MESSAGE,
1892
- };
1893
- }
1894
- const result = yield this._store.findUser(request.userId);
1895
- if (!result) {
1896
- throw new Error('Unable to find user even though a valid session key was presented!');
1897
- }
1898
- const { hasActiveSubscription, subscriptionTier: tier } = yield this._getSubscriptionInfo(result);
1899
- let privacyFeatures;
1900
- let displayName = null;
1901
- let email = result.email;
1902
- let name = result.name;
1903
- const privoConfig = yield this._config.getPrivoConfiguration();
1904
- if (privoConfig && result.privoServiceId) {
1905
- const userInfo = yield this._privoClient.getUserInfo(result.privoServiceId);
1906
- privacyFeatures = getPrivacyFeaturesFromPermissions(privoConfig.featureIds, userInfo.permissions);
1907
- displayName = userInfo.displayName;
1908
- email = userInfo.email;
1909
- name = userInfo.givenName;
1910
- if (((_a = result.privacyFeatures) === null || _a === void 0 ? void 0 : _a.publishData) !==
1911
- privacyFeatures.publishData ||
1912
- ((_b = result.privacyFeatures) === null || _b === void 0 ? void 0 : _b.allowPublicData) !==
1913
- privacyFeatures.allowPublicData ||
1914
- ((_c = result.privacyFeatures) === null || _c === void 0 ? void 0 : _c.allowAI) !==
1915
- privacyFeatures.allowAI ||
1916
- ((_d = result.privacyFeatures) === null || _d === void 0 ? void 0 : _d.allowPublicInsts) !==
1917
- privacyFeatures.allowPublicInsts) {
1918
- yield this._store.saveUser(Object.assign(Object.assign({}, result), { privacyFeatures: Object.assign({}, privacyFeatures) }));
1919
- }
1920
- }
1921
- else if (result.privacyFeatures) {
1922
- privacyFeatures = Object.assign({}, result.privacyFeatures);
1923
- }
1924
- else {
1925
- privacyFeatures = {
1926
- publishData: true,
1927
- allowPublicData: true,
1928
- allowAI: true,
1929
- allowPublicInsts: true,
1930
- };
1931
- }
1731
+ const { info } = await this._issueSession({
1732
+ userId,
1733
+ lifetimeMs: SESSION_LIFETIME_MS,
1734
+ previousSession: session,
1735
+ ipAddress: request.ipAddress,
1736
+ });
1737
+ return {
1738
+ success: true,
1739
+ ...info,
1740
+ };
1741
+ }
1742
+ catch (err) {
1743
+ const span = trace.getActiveSpan();
1744
+ span === null || span === void 0 ? void 0 : span.recordException(err);
1745
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1746
+ console.error('[AuthController] Error ocurred while replacing session', err);
1747
+ return {
1748
+ success: false,
1749
+ errorCode: 'server_error',
1750
+ errorMessage: 'A server error ocurred.',
1751
+ };
1752
+ }
1753
+ }
1754
+ /**
1755
+ * Lists all the sessions for a given user.
1756
+ * @param request The request.
1757
+ */
1758
+ async listSessions(request) {
1759
+ if (typeof request.userId !== 'string' || request.userId === '') {
1760
+ return {
1761
+ success: false,
1762
+ errorCode: 'unacceptable_user_id',
1763
+ errorMessage: 'The given userId is invalid. It must be a string.',
1764
+ };
1765
+ }
1766
+ else if (typeof request.expireTimeMs !== 'number' &&
1767
+ request.expireTimeMs !== null &&
1768
+ typeof request.expireTimeMs !== 'undefined') {
1769
+ return {
1770
+ success: false,
1771
+ errorCode: 'unacceptable_expire_time',
1772
+ errorMessage: 'The given expiration time is invalid. It must be a number or null.',
1773
+ };
1774
+ }
1775
+ else if (typeof request.sessionKey !== 'string' ||
1776
+ request.sessionKey === '') {
1777
+ return {
1778
+ success: false,
1779
+ errorCode: 'unacceptable_session_key',
1780
+ errorMessage: 'The given session key is invalid. It must be a string.',
1781
+ };
1782
+ }
1783
+ try {
1784
+ const keyResult = await this.validateSessionKey(request.sessionKey);
1785
+ if (keyResult.success === false) {
1786
+ return keyResult;
1787
+ }
1788
+ else if (!isSuperUserRole(keyResult.role) &&
1789
+ keyResult.userId !== request.userId) {
1932
1790
  return {
1933
- success: true,
1934
- userId: result.id,
1935
- name: name,
1936
- displayName,
1937
- email: email,
1938
- phoneNumber: result.phoneNumber,
1939
- avatarPortraitUrl: result.avatarPortraitUrl,
1940
- avatarUrl: result.avatarUrl,
1941
- hasActiveSubscription: hasActiveSubscription,
1942
- subscriptionTier: tier !== null && tier !== void 0 ? tier : null,
1943
- privacyFeatures: privacyFeatures,
1944
- role: (_e = result.role) !== null && _e !== void 0 ? _e : 'none',
1791
+ success: false,
1792
+ errorCode: 'invalid_key',
1793
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
1945
1794
  };
1946
1795
  }
1947
- catch (err) {
1948
- const span = trace.getActiveSpan();
1949
- span === null || span === void 0 ? void 0 : span.recordException(err);
1950
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1951
- console.error('[AuthController] Error ocurred while getting user info', err);
1796
+ const result = await this._store.listSessions(request.userId, request.expireTimeMs);
1797
+ if (result.success === false) {
1798
+ return result;
1799
+ }
1800
+ return {
1801
+ success: true,
1802
+ sessions: result.sessions.map((s) => ({
1803
+ userId: s.userId,
1804
+ sessionId: s.sessionId,
1805
+ grantedTimeMs: s.grantedTimeMs,
1806
+ expireTimeMs: s.expireTimeMs,
1807
+ revokeTimeMs: keyResult.allSessionsRevokedTimeMs >= s.grantedTimeMs &&
1808
+ (!s.revokeTimeMs ||
1809
+ s.revokeTimeMs > keyResult.allSessionsRevokedTimeMs)
1810
+ ? keyResult.allSessionsRevokedTimeMs
1811
+ : s.revokeTimeMs,
1812
+ currentSession: s.sessionId === keyResult.sessionId,
1813
+ ipAddress: s.ipAddress,
1814
+ nextSessionId: s.nextSessionId,
1815
+ })),
1816
+ };
1817
+ }
1818
+ catch (err) {
1819
+ const span = trace.getActiveSpan();
1820
+ span === null || span === void 0 ? void 0 : span.recordException(err);
1821
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1822
+ console.error('[AuthController] Error ocurred while listing sessions', err);
1823
+ return {
1824
+ success: false,
1825
+ errorCode: 'server_error',
1826
+ errorMessage: 'A server error occurred.',
1827
+ };
1828
+ }
1829
+ }
1830
+ /**
1831
+ * Gets the information for a specific user.
1832
+ * @param request The request.
1833
+ */
1834
+ async getUserInfo(request) {
1835
+ var _a, _b, _c, _d, _e;
1836
+ if (typeof request.userId !== 'string' || request.userId === '') {
1837
+ return {
1838
+ success: false,
1839
+ errorCode: 'unacceptable_user_id',
1840
+ errorMessage: 'The given userId is invalid. It must be a string.',
1841
+ };
1842
+ }
1843
+ else if (typeof request.sessionKey !== 'string' ||
1844
+ request.sessionKey === '') {
1845
+ return {
1846
+ success: false,
1847
+ errorCode: 'unacceptable_session_key',
1848
+ errorMessage: 'The given session key is invalid. It must be a string.',
1849
+ };
1850
+ }
1851
+ try {
1852
+ const keyResult = await this.validateSessionKey(request.sessionKey);
1853
+ if (keyResult.success === false) {
1854
+ return keyResult;
1855
+ }
1856
+ else if (!isSuperUserRole(keyResult.role) &&
1857
+ keyResult.userId !== request.userId) {
1858
+ console.log('[AuthController] [getUserInfo] Request User ID doesnt match session key User ID!');
1952
1859
  return {
1953
1860
  success: false,
1954
- errorCode: 'server_error',
1955
- errorMessage: 'A server error occurred.',
1861
+ errorCode: 'invalid_key',
1862
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
1863
+ };
1864
+ }
1865
+ const result = await this._store.findUser(request.userId);
1866
+ if (!result) {
1867
+ throw new Error('Unable to find user even though a valid session key was presented!');
1868
+ }
1869
+ const { hasActiveSubscription, subscriptionTier: tier } = await this._getSubscriptionInfo(result);
1870
+ let privacyFeatures;
1871
+ let displayName = null;
1872
+ let email = result.email;
1873
+ let name = result.name;
1874
+ const privoConfig = await this._config.getPrivoConfiguration();
1875
+ if (privoConfig && result.privoServiceId) {
1876
+ const userInfo = await this._privoClient.getUserInfo(result.privoServiceId);
1877
+ privacyFeatures = getPrivacyFeaturesFromPermissions(privoConfig.featureIds, userInfo.permissions);
1878
+ displayName = userInfo.displayName;
1879
+ email = userInfo.email;
1880
+ name = userInfo.givenName;
1881
+ if (((_a = result.privacyFeatures) === null || _a === void 0 ? void 0 : _a.publishData) !==
1882
+ privacyFeatures.publishData ||
1883
+ ((_b = result.privacyFeatures) === null || _b === void 0 ? void 0 : _b.allowPublicData) !==
1884
+ privacyFeatures.allowPublicData ||
1885
+ ((_c = result.privacyFeatures) === null || _c === void 0 ? void 0 : _c.allowAI) !==
1886
+ privacyFeatures.allowAI ||
1887
+ ((_d = result.privacyFeatures) === null || _d === void 0 ? void 0 : _d.allowPublicInsts) !==
1888
+ privacyFeatures.allowPublicInsts) {
1889
+ await this._store.saveUser({
1890
+ ...result,
1891
+ privacyFeatures: {
1892
+ ...privacyFeatures,
1893
+ },
1894
+ });
1895
+ }
1896
+ }
1897
+ else if (result.privacyFeatures) {
1898
+ privacyFeatures = {
1899
+ ...result.privacyFeatures,
1900
+ };
1901
+ }
1902
+ else {
1903
+ privacyFeatures = {
1904
+ publishData: true,
1905
+ allowPublicData: true,
1906
+ allowAI: true,
1907
+ allowPublicInsts: true,
1956
1908
  };
1957
1909
  }
1958
- });
1910
+ return {
1911
+ success: true,
1912
+ userId: result.id,
1913
+ name: name,
1914
+ displayName,
1915
+ email: email,
1916
+ phoneNumber: result.phoneNumber,
1917
+ avatarPortraitUrl: result.avatarPortraitUrl,
1918
+ avatarUrl: result.avatarUrl,
1919
+ hasActiveSubscription: hasActiveSubscription,
1920
+ subscriptionTier: tier !== null && tier !== void 0 ? tier : null,
1921
+ privacyFeatures: privacyFeatures,
1922
+ role: (_e = result.role) !== null && _e !== void 0 ? _e : 'none',
1923
+ };
1924
+ }
1925
+ catch (err) {
1926
+ const span = trace.getActiveSpan();
1927
+ span === null || span === void 0 ? void 0 : span.recordException(err);
1928
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1929
+ console.error('[AuthController] Error ocurred while getting user info', err);
1930
+ return {
1931
+ success: false,
1932
+ errorCode: 'server_error',
1933
+ errorMessage: 'A server error occurred.',
1934
+ };
1935
+ }
1959
1936
  }
1960
1937
  /**
1961
1938
  * Gets the public information for a specific user.
1962
1939
  * @param userId The ID of the user whose information is being requested.
1963
1940
  */
1964
- getPublicUserInfo(userId) {
1965
- return __awaiter(this, void 0, void 0, function* () {
1966
- if (typeof userId !== 'string' || userId === '') {
1967
- return {
1968
- success: false,
1969
- errorCode: 'unacceptable_user_id',
1970
- errorMessage: 'The given userId is invalid. It must be a string.',
1971
- };
1972
- }
1973
- try {
1974
- const result = yield this._store.findUser(userId);
1975
- if (!result) {
1976
- return {
1977
- success: true,
1978
- user: null,
1979
- };
1980
- }
1981
- let displayName = null;
1982
- const privoConfig = yield this._config.getPrivoConfiguration();
1983
- if (privoConfig && result.privoServiceId) {
1984
- const userInfo = yield this._privoClient.getUserInfo(result.privoServiceId);
1985
- displayName = userInfo.displayName;
1986
- }
1941
+ async getPublicUserInfo(userId) {
1942
+ if (typeof userId !== 'string' || userId === '') {
1943
+ return {
1944
+ success: false,
1945
+ errorCode: 'unacceptable_user_id',
1946
+ errorMessage: 'The given userId is invalid. It must be a string.',
1947
+ };
1948
+ }
1949
+ try {
1950
+ const result = await this._store.findUser(userId);
1951
+ if (!result) {
1987
1952
  return {
1988
1953
  success: true,
1989
- user: {
1990
- userId: result.id,
1991
- name: result.name,
1992
- email: result.email,
1993
- displayName,
1994
- },
1954
+ user: null,
1995
1955
  };
1996
1956
  }
1997
- catch (err) {
1998
- const span = trace.getActiveSpan();
1999
- span === null || span === void 0 ? void 0 : span.recordException(err);
2000
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
2001
- console.error('[AuthController] Error ocurred while getting user info', err);
2002
- return {
2003
- success: false,
2004
- errorCode: 'server_error',
2005
- errorMessage: 'A server error occurred.',
2006
- };
1957
+ let displayName = null;
1958
+ const privoConfig = await this._config.getPrivoConfiguration();
1959
+ if (privoConfig && result.privoServiceId) {
1960
+ const userInfo = await this._privoClient.getUserInfo(result.privoServiceId);
1961
+ displayName = userInfo.displayName;
2007
1962
  }
2008
- });
1963
+ return {
1964
+ success: true,
1965
+ user: {
1966
+ userId: result.id,
1967
+ name: result.name,
1968
+ email: result.email,
1969
+ displayName,
1970
+ },
1971
+ };
1972
+ }
1973
+ catch (err) {
1974
+ const span = trace.getActiveSpan();
1975
+ span === null || span === void 0 ? void 0 : span.recordException(err);
1976
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
1977
+ console.error('[AuthController] Error ocurred while getting user info', err);
1978
+ return {
1979
+ success: false,
1980
+ errorCode: 'server_error',
1981
+ errorMessage: 'A server error occurred.',
1982
+ };
1983
+ }
2009
1984
  }
2010
- _getSubscriptionInfo(user) {
2011
- return __awaiter(this, void 0, void 0, function* () {
2012
- const hasActiveSubscription = this._forceAllowSubscriptionFeatures ||
2013
- isActiveSubscription(user.subscriptionStatus);
2014
- let tier = null;
2015
- let sub = null;
2016
- const subscriptionConfig = yield this._config.getSubscriptionConfiguration();
2017
- if (hasActiveSubscription) {
2018
- if (user.subscriptionId) {
2019
- sub = subscriptionConfig === null || subscriptionConfig === void 0 ? void 0 : subscriptionConfig.subscriptions.find((s) => s.id === user.subscriptionId);
2020
- }
2021
- if (!sub) {
2022
- sub = subscriptionConfig === null || subscriptionConfig === void 0 ? void 0 : subscriptionConfig.subscriptions[0];
2023
- if (sub) {
2024
- console.log('[AuthController] [getUserInfo] Using first subscription for user.');
2025
- }
2026
- }
2027
- tier = 'beta';
1985
+ async _getSubscriptionInfo(user) {
1986
+ const hasActiveSubscription = this._forceAllowSubscriptionFeatures ||
1987
+ isActiveSubscription(user.subscriptionStatus);
1988
+ let tier = null;
1989
+ let sub = null;
1990
+ const subscriptionConfig = await this._config.getSubscriptionConfiguration();
1991
+ if (hasActiveSubscription) {
1992
+ if (user.subscriptionId) {
1993
+ sub = subscriptionConfig === null || subscriptionConfig === void 0 ? void 0 : subscriptionConfig.subscriptions.find((s) => s.id === user.subscriptionId);
2028
1994
  }
2029
1995
  if (!sub) {
2030
- sub = subscriptionConfig === null || subscriptionConfig === void 0 ? void 0 : subscriptionConfig.subscriptions.find((s) => s.defaultSubscription);
1996
+ sub = subscriptionConfig === null || subscriptionConfig === void 0 ? void 0 : subscriptionConfig.subscriptions[0];
2031
1997
  if (sub) {
2032
- console.log('[AuthController] [getUserInfo] Using default subscription for user.');
1998
+ console.log('[AuthController] [getUserInfo] Using first subscription for user.');
2033
1999
  }
2034
2000
  }
2001
+ tier = 'beta';
2002
+ }
2003
+ if (!sub) {
2004
+ sub = subscriptionConfig === null || subscriptionConfig === void 0 ? void 0 : subscriptionConfig.subscriptions.find((s) => s.defaultSubscription);
2035
2005
  if (sub) {
2036
- tier = sub.tier || 'beta';
2006
+ console.log('[AuthController] [getUserInfo] Using default subscription for user.');
2037
2007
  }
2038
- return {
2039
- hasActiveSubscription,
2040
- subscriptionId: sub === null || sub === void 0 ? void 0 : sub.id,
2041
- subscriptionTier: tier,
2042
- };
2043
- });
2008
+ }
2009
+ if (sub) {
2010
+ tier = sub.tier || 'beta';
2011
+ }
2012
+ return {
2013
+ hasActiveSubscription,
2014
+ subscriptionId: sub === null || sub === void 0 ? void 0 : sub.id,
2015
+ subscriptionTier: tier,
2016
+ };
2044
2017
  }
2045
2018
  /**
2046
2019
  * Attempts to update a user's metadata.
2047
2020
  * @param request The request for the operation.
2048
2021
  */
2049
- updateUserInfo(request) {
2050
- return __awaiter(this, void 0, void 0, function* () {
2051
- if (typeof request.userId !== 'string' || request.userId === '') {
2022
+ async updateUserInfo(request) {
2023
+ if (typeof request.userId !== 'string' || request.userId === '') {
2024
+ return {
2025
+ success: false,
2026
+ errorCode: 'unacceptable_user_id',
2027
+ errorMessage: 'The given userId is invalid. It must be a string.',
2028
+ };
2029
+ }
2030
+ else if (typeof request.sessionKey !== 'string' ||
2031
+ request.sessionKey === '') {
2032
+ return {
2033
+ success: false,
2034
+ errorCode: 'unacceptable_session_key',
2035
+ errorMessage: 'The given session key is invalid. It must be a string.',
2036
+ };
2037
+ }
2038
+ else if (typeof request.update !== 'object' ||
2039
+ request.update === null ||
2040
+ Array.isArray(request.update)) {
2041
+ return {
2042
+ success: false,
2043
+ errorCode: 'unacceptable_update',
2044
+ errorMessage: 'The given update is invalid. It must be an object.',
2045
+ };
2046
+ }
2047
+ try {
2048
+ const keyResult = await this.validateSessionKey(request.sessionKey);
2049
+ if (keyResult.success === false) {
2050
+ return keyResult;
2051
+ }
2052
+ else if (keyResult.userId !== request.userId) {
2053
+ console.log('[AuthController] [updateUserInfo] Request User ID doesnt match session key User ID!');
2052
2054
  return {
2053
2055
  success: false,
2054
- errorCode: 'unacceptable_user_id',
2055
- errorMessage: 'The given userId is invalid. It must be a string.',
2056
- };
2057
- }
2058
- else if (typeof request.sessionKey !== 'string' ||
2059
- request.sessionKey === '') {
2056
+ errorCode: 'invalid_key',
2057
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
2058
+ };
2059
+ }
2060
+ const user = await this._store.findUser(request.userId);
2061
+ if (!user) {
2062
+ throw new Error('Unable to find user even though a valid session key was presented!');
2063
+ }
2064
+ const cleaned = cleanupObject({
2065
+ name: request.update.name,
2066
+ avatarUrl: request.update.avatarUrl,
2067
+ avatarPortraitUrl: request.update.avatarPortraitUrl,
2068
+ email: request.update.email,
2069
+ phoneNumber: request.update.phoneNumber,
2070
+ });
2071
+ await this._store.saveUser({
2072
+ ...user,
2073
+ ...cleaned,
2074
+ });
2075
+ return {
2076
+ success: true,
2077
+ userId: user.id,
2078
+ };
2079
+ }
2080
+ catch (err) {
2081
+ const span = trace.getActiveSpan();
2082
+ span === null || span === void 0 ? void 0 : span.recordException(err);
2083
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
2084
+ console.error('[AuthController] Error ocurred while getting user info', err);
2085
+ return {
2086
+ success: false,
2087
+ errorCode: 'server_error',
2088
+ errorMessage: 'A server error occurred.',
2089
+ };
2090
+ }
2091
+ }
2092
+ /**
2093
+ * Attempts to request a change in privacy features for a user.
2094
+ */
2095
+ async requestPrivacyFeaturesChange(request) {
2096
+ var _a;
2097
+ try {
2098
+ if (!this._privoClient) {
2060
2099
  return {
2061
2100
  success: false,
2062
- errorCode: 'unacceptable_session_key',
2063
- errorMessage: 'The given session key is invalid. It must be a string.',
2101
+ errorCode: 'not_supported',
2102
+ errorMessage: 'Privo features are not supported on this server.',
2064
2103
  };
2065
2104
  }
2066
- else if (typeof request.update !== 'object' ||
2067
- request.update === null ||
2068
- Array.isArray(request.update)) {
2105
+ const config = await this._config.getPrivoConfiguration();
2106
+ if (!config) {
2069
2107
  return {
2070
2108
  success: false,
2071
- errorCode: 'unacceptable_update',
2072
- errorMessage: 'The given update is invalid. It must be an object.',
2109
+ errorCode: 'not_supported',
2110
+ errorMessage: 'Privo features are not supported on this server.',
2073
2111
  };
2074
2112
  }
2075
- try {
2076
- const keyResult = yield this.validateSessionKey(request.sessionKey);
2077
- if (keyResult.success === false) {
2078
- return keyResult;
2079
- }
2080
- else if (keyResult.userId !== request.userId) {
2081
- console.log('[AuthController] [updateUserInfo] Request User ID doesnt match session key User ID!');
2082
- return {
2083
- success: false,
2084
- errorCode: 'invalid_key',
2085
- errorMessage: INVALID_KEY_ERROR_MESSAGE,
2086
- };
2087
- }
2088
- const user = yield this._store.findUser(request.userId);
2089
- if (!user) {
2090
- throw new Error('Unable to find user even though a valid session key was presented!');
2091
- }
2092
- const cleaned = cleanupObject({
2093
- name: request.update.name,
2094
- avatarUrl: request.update.avatarUrl,
2095
- avatarPortraitUrl: request.update.avatarPortraitUrl,
2096
- email: request.update.email,
2097
- phoneNumber: request.update.phoneNumber,
2098
- });
2099
- yield this._store.saveUser(Object.assign(Object.assign({}, user), cleaned));
2100
- return {
2101
- success: true,
2102
- userId: user.id,
2103
- };
2113
+ const keyResult = await this.validateSessionKey(request.sessionKey);
2114
+ if (keyResult.success === false) {
2115
+ return keyResult;
2104
2116
  }
2105
- catch (err) {
2106
- const span = trace.getActiveSpan();
2107
- span === null || span === void 0 ? void 0 : span.recordException(err);
2108
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
2109
- console.error('[AuthController] Error ocurred while getting user info', err);
2117
+ else if (keyResult.userId !== request.userId &&
2118
+ keyResult.role !== 'superUser') {
2119
+ console.log('[AuthController] [requestPrivacyFeaturesChange] Request User ID doesnt match session key User ID!');
2110
2120
  return {
2111
2121
  success: false,
2112
- errorCode: 'server_error',
2113
- errorMessage: 'A server error occurred.',
2122
+ errorCode: 'invalid_key',
2123
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
2114
2124
  };
2115
2125
  }
2116
- });
2117
- }
2118
- /**
2119
- * Attempts to request a change in privacy features for a user.
2120
- */
2121
- requestPrivacyFeaturesChange(request) {
2122
- var _a;
2123
- return __awaiter(this, void 0, void 0, function* () {
2124
- try {
2125
- if (!this._privoClient) {
2126
- return {
2127
- success: false,
2128
- errorCode: 'not_supported',
2129
- errorMessage: 'Privo features are not supported on this server.',
2130
- };
2131
- }
2132
- const config = yield this._config.getPrivoConfiguration();
2133
- if (!config) {
2134
- return {
2135
- success: false,
2136
- errorCode: 'not_supported',
2137
- errorMessage: 'Privo features are not supported on this server.',
2138
- };
2139
- }
2140
- const keyResult = yield this.validateSessionKey(request.sessionKey);
2141
- if (keyResult.success === false) {
2142
- return keyResult;
2143
- }
2144
- else if (keyResult.userId !== request.userId &&
2145
- keyResult.role !== 'superUser') {
2146
- console.log('[AuthController] [requestPrivacyFeaturesChange] Request User ID doesnt match session key User ID!');
2147
- return {
2148
- success: false,
2149
- errorCode: 'invalid_key',
2150
- errorMessage: INVALID_KEY_ERROR_MESSAGE,
2151
- };
2152
- }
2153
- const user = yield this._store.findUser(request.userId);
2154
- if (!user) {
2155
- throw new Error('Unable to find user even though a valid session key was presented!');
2156
- }
2157
- if (!user.privoServiceId) {
2158
- return {
2159
- success: false,
2160
- errorCode: 'not_supported',
2161
- errorMessage: 'Privo features are not supported on this server.',
2162
- };
2163
- }
2164
- const result = yield this._privoClient.resendConsentRequest(user.privoServiceId, (_a = user.privoParentServiceId) !== null && _a !== void 0 ? _a : user.privoServiceId);
2165
- if (result.success === false) {
2166
- return result;
2167
- }
2168
- console.log(`[AuthController] [requestPrivacyFeaturesChange] [userId: ${request.userId}] Requested privacy features change.`);
2169
- return {
2170
- success: true,
2171
- };
2126
+ const user = await this._store.findUser(request.userId);
2127
+ if (!user) {
2128
+ throw new Error('Unable to find user even though a valid session key was presented!');
2172
2129
  }
2173
- catch (err) {
2174
- const span = trace.getActiveSpan();
2175
- span === null || span === void 0 ? void 0 : span.recordException(err);
2176
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
2177
- console.error('[AuthController] Error ocurred while requesting a change in privacy features', err);
2130
+ if (!user.privoServiceId) {
2178
2131
  return {
2179
2132
  success: false,
2180
- errorCode: 'server_error',
2181
- errorMessage: 'A server error occurred.',
2133
+ errorCode: 'not_supported',
2134
+ errorMessage: 'Privo features are not supported on this server.',
2182
2135
  };
2183
2136
  }
2184
- });
2137
+ const result = await this._privoClient.resendConsentRequest(user.privoServiceId, (_a = user.privoParentServiceId) !== null && _a !== void 0 ? _a : user.privoServiceId);
2138
+ if (result.success === false) {
2139
+ return result;
2140
+ }
2141
+ console.log(`[AuthController] [requestPrivacyFeaturesChange] [userId: ${request.userId}] Requested privacy features change.`);
2142
+ return {
2143
+ success: true,
2144
+ };
2145
+ }
2146
+ catch (err) {
2147
+ const span = trace.getActiveSpan();
2148
+ span === null || span === void 0 ? void 0 : span.recordException(err);
2149
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
2150
+ console.error('[AuthController] Error ocurred while requesting a change in privacy features', err);
2151
+ return {
2152
+ success: false,
2153
+ errorCode: 'server_error',
2154
+ errorMessage: 'A server error occurred.',
2155
+ };
2156
+ }
2185
2157
  }
2186
2158
  /**
2187
2159
  * Lists the email rules that should be used.
2188
2160
  */
2189
- listEmailRules() {
2190
- return __awaiter(this, void 0, void 0, function* () {
2191
- try {
2192
- const rules = yield this._store.listEmailRules();
2193
- return {
2194
- success: true,
2195
- rules,
2196
- };
2197
- }
2198
- catch (err) {
2199
- const span = trace.getActiveSpan();
2200
- span === null || span === void 0 ? void 0 : span.recordException(err);
2201
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
2202
- console.error('[AuthController] Error ocurred while listing email rules', err);
2203
- return {
2204
- success: false,
2205
- errorCode: 'server_error',
2206
- errorMessage: 'A server error occurred.',
2207
- };
2208
- }
2209
- });
2161
+ async listEmailRules() {
2162
+ try {
2163
+ const rules = await this._store.listEmailRules();
2164
+ return {
2165
+ success: true,
2166
+ rules,
2167
+ };
2168
+ }
2169
+ catch (err) {
2170
+ const span = trace.getActiveSpan();
2171
+ span === null || span === void 0 ? void 0 : span.recordException(err);
2172
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
2173
+ console.error('[AuthController] Error ocurred while listing email rules', err);
2174
+ return {
2175
+ success: false,
2176
+ errorCode: 'server_error',
2177
+ errorMessage: 'A server error occurred.',
2178
+ };
2179
+ }
2210
2180
  }
2211
2181
  /**
2212
2182
  * Lists the SMS rules that should be used.
2213
2183
  */
2214
- listSmsRules() {
2215
- return __awaiter(this, void 0, void 0, function* () {
2216
- try {
2217
- const rules = yield this._store.listSmsRules();
2184
+ async listSmsRules() {
2185
+ try {
2186
+ const rules = await this._store.listSmsRules();
2187
+ return {
2188
+ success: true,
2189
+ rules,
2190
+ };
2191
+ }
2192
+ catch (err) {
2193
+ const span = trace.getActiveSpan();
2194
+ span === null || span === void 0 ? void 0 : span.recordException(err);
2195
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
2196
+ console.error('[AuthController] Error ocurred while listing email rules', err);
2197
+ return {
2198
+ success: false,
2199
+ errorCode: 'server_error',
2200
+ errorMessage: 'A server error occurred.',
2201
+ };
2202
+ }
2203
+ }
2204
+ async isValidEmailAddress(email) {
2205
+ try {
2206
+ const valid = await this._validateAddress(email, 'email');
2207
+ if (!valid) {
2218
2208
  return {
2219
2209
  success: true,
2220
- rules,
2210
+ allowed: false,
2221
2211
  };
2222
2212
  }
2223
- catch (err) {
2224
- const span = trace.getActiveSpan();
2225
- span === null || span === void 0 ? void 0 : span.recordException(err);
2226
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
2227
- console.error('[AuthController] Error ocurred while listing email rules', err);
2228
- return {
2229
- success: false,
2230
- errorCode: 'server_error',
2231
- errorMessage: 'A server error occurred.',
2232
- };
2233
- }
2234
- });
2235
- }
2236
- isValidEmailAddress(email) {
2237
- return __awaiter(this, void 0, void 0, function* () {
2238
- try {
2239
- const valid = yield this._validateAddress(email, 'email');
2240
- if (!valid) {
2213
+ if (this._privoClient) {
2214
+ const config = await this._config.getPrivoConfiguration();
2215
+ if (config) {
2216
+ const result = await this._privoClient.checkEmail(email);
2217
+ const allowed = result.available && !result.profanity;
2241
2218
  return {
2242
2219
  success: true,
2243
- allowed: false,
2220
+ allowed,
2221
+ suggestions: result.suggestions,
2222
+ profanity: result.profanity,
2244
2223
  };
2245
2224
  }
2246
- if (this._privoClient) {
2247
- const config = yield this._config.getPrivoConfiguration();
2248
- if (config) {
2249
- const result = yield this._privoClient.checkEmail(email);
2250
- const allowed = result.available && !result.profanity;
2251
- return {
2252
- success: true,
2253
- allowed,
2254
- suggestions: result.suggestions,
2255
- profanity: result.profanity,
2256
- };
2257
- }
2258
- }
2259
- return {
2260
- success: true,
2261
- allowed: true,
2262
- };
2263
- }
2264
- catch (err) {
2265
- const span = trace.getActiveSpan();
2266
- span === null || span === void 0 ? void 0 : span.recordException(err);
2267
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
2268
- console.error('[AuthController] Error ocurred while checking if email address is valid', err);
2269
- return {
2270
- success: false,
2271
- errorCode: 'server_error',
2272
- errorMessage: 'A server error occurred.',
2273
- };
2274
2225
  }
2275
- });
2226
+ return {
2227
+ success: true,
2228
+ allowed: true,
2229
+ };
2230
+ }
2231
+ catch (err) {
2232
+ const span = trace.getActiveSpan();
2233
+ span === null || span === void 0 ? void 0 : span.recordException(err);
2234
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
2235
+ console.error('[AuthController] Error ocurred while checking if email address is valid', err);
2236
+ return {
2237
+ success: false,
2238
+ errorCode: 'server_error',
2239
+ errorMessage: 'A server error occurred.',
2240
+ };
2241
+ }
2276
2242
  }
2277
- isValidDisplayName(displayName, name) {
2278
- return __awaiter(this, void 0, void 0, function* () {
2279
- try {
2280
- if (this._privoClient) {
2281
- if (name) {
2282
- const lowercaseName = name.trim().toLowerCase();
2283
- const lowercaseDisplayName = displayName
2284
- .trim()
2285
- .toLowerCase();
2286
- if (lowercaseDisplayName.includes(lowercaseName)) {
2287
- return {
2288
- success: true,
2289
- allowed: false,
2290
- containsName: true,
2291
- };
2292
- }
2293
- }
2294
- const config = yield this._config.getPrivoConfiguration();
2295
- if (config) {
2296
- const result = yield this._privoClient.checkDisplayName(displayName);
2297
- const allowed = result.available && !result.profanity;
2243
+ async isValidDisplayName(displayName, name) {
2244
+ try {
2245
+ if (this._privoClient) {
2246
+ if (name) {
2247
+ const lowercaseName = name.trim().toLowerCase();
2248
+ const lowercaseDisplayName = displayName
2249
+ .trim()
2250
+ .toLowerCase();
2251
+ if (lowercaseDisplayName.includes(lowercaseName)) {
2298
2252
  return {
2299
2253
  success: true,
2300
- allowed,
2301
- suggestions: result.suggestions,
2302
- profanity: result.profanity,
2254
+ allowed: false,
2255
+ containsName: true,
2303
2256
  };
2304
2257
  }
2305
2258
  }
2306
- return {
2307
- success: true,
2308
- allowed: true,
2309
- };
2310
- }
2311
- catch (err) {
2312
- const span = trace.getActiveSpan();
2313
- span === null || span === void 0 ? void 0 : span.recordException(err);
2314
- span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
2315
- console.error('[AuthController] Error ocurred while checking if display name is valid', err);
2316
- return {
2317
- success: false,
2318
- errorCode: 'server_error',
2319
- errorMessage: 'A server error occurred.',
2320
- };
2259
+ const config = await this._config.getPrivoConfiguration();
2260
+ if (config) {
2261
+ const result = await this._privoClient.checkDisplayName(displayName);
2262
+ const allowed = result.available && !result.profanity;
2263
+ return {
2264
+ success: true,
2265
+ allowed,
2266
+ suggestions: result.suggestions,
2267
+ profanity: result.profanity,
2268
+ };
2269
+ }
2321
2270
  }
2322
- });
2271
+ return {
2272
+ success: true,
2273
+ allowed: true,
2274
+ };
2275
+ }
2276
+ catch (err) {
2277
+ const span = trace.getActiveSpan();
2278
+ span === null || span === void 0 ? void 0 : span.recordException(err);
2279
+ span === null || span === void 0 ? void 0 : span.setStatus({ code: SpanStatusCode.ERROR });
2280
+ console.error('[AuthController] Error ocurred while checking if display name is valid', err);
2281
+ return {
2282
+ success: false,
2283
+ errorCode: 'server_error',
2284
+ errorMessage: 'A server error occurred.',
2285
+ };
2286
+ }
2323
2287
  }
2324
2288
  /**
2325
2289
  * Issues a new session for the given user.
@@ -2328,48 +2292,59 @@ export class AuthController {
2328
2292
  * @param previousSession The previous session that this session is replacing. If null, then this session is not related to another session.
2329
2293
  * @param ipAddress The IP address that the session is being issued to. Should be null if the ip address is not known.
2330
2294
  */
2331
- _issueSession(_a) {
2332
- var _b, _c, _d, _e, _f;
2333
- var { userId, lifetimeMs, previousSession, ipAddress, requestId } = _a, rest = __rest(_a, ["userId", "lifetimeMs", "previousSession", "ipAddress", "requestId"]);
2334
- return __awaiter(this, void 0, void 0, function* () {
2335
- const now = Date.now();
2336
- const newSessionId = fromByteArray(randomBytes(SESSION_ID_BYTE_LENGTH));
2337
- const newSessionSecret = fromByteArray(randomBytes(SESSION_SECRET_BYTE_LENGTH));
2338
- const newConnectionSecret = fromByteArray(randomBytes(SESSION_SECRET_BYTE_LENGTH));
2339
- const newSession = Object.assign(Object.assign({}, rest), { userId: userId, sessionId: newSessionId, requestId: requestId !== null && requestId !== void 0 ? requestId : null, secretHash: this._hashHighEntropyPasswordWithSalt(newSessionSecret, newSessionId), connectionSecret: newConnectionSecret, grantedTimeMs: now, revokeTimeMs: null, expireTimeMs: lifetimeMs ? now + lifetimeMs : null, previousSessionId: (_b = previousSession === null || previousSession === void 0 ? void 0 : previousSession.sessionId) !== null && _b !== void 0 ? _b : null, nextSessionId: null, ipAddress: ipAddress });
2340
- if (requestId) {
2341
- yield this._store.markLoginRequestComplete(userId, requestId, now);
2342
- }
2343
- if (rest.webauthnRequestId) {
2344
- yield this._store.markWebAuthnLoginRequestComplete(rest.webauthnRequestId, userId, now);
2345
- }
2346
- if (rest.oidRequestId) {
2347
- yield this._store.markOpenIDLoginRequestComplete(rest.oidRequestId, now);
2348
- }
2349
- if (previousSession) {
2350
- yield this._store.replaceSession(previousSession, newSession, now);
2351
- }
2352
- else {
2353
- yield this._store.saveSession(newSession);
2354
- }
2355
- const metadata = yield this._store.findUserLoginMetadata(userId);
2356
- const info = {
2357
- userId,
2358
- sessionKey: formatV1SessionKey(userId, newSessionId, newSessionSecret, newSession.expireTimeMs),
2359
- connectionKey: formatV1ConnectionKey(userId, newSessionId, newConnectionSecret, newSession.expireTimeMs),
2360
- expireTimeMs: newSession.expireTimeMs,
2361
- metadata: {
2362
- hasUserAuthenticator: (_c = metadata === null || metadata === void 0 ? void 0 : metadata.hasUserAuthenticator) !== null && _c !== void 0 ? _c : false,
2363
- userAuthenticatorCredentialIds: (_d = metadata === null || metadata === void 0 ? void 0 : metadata.userAuthenticatorCredentialIds) !== null && _d !== void 0 ? _d : [],
2364
- hasPushSubscription: (_e = metadata === null || metadata === void 0 ? void 0 : metadata.hasPushSubscription) !== null && _e !== void 0 ? _e : false,
2365
- pushSubscriptionIds: (_f = metadata === null || metadata === void 0 ? void 0 : metadata.pushSubscriptionIds) !== null && _f !== void 0 ? _f : [],
2366
- },
2367
- };
2368
- return {
2369
- newSession,
2370
- info,
2371
- };
2372
- });
2295
+ async _issueSession({ userId, lifetimeMs, previousSession, ipAddress, requestId, ...rest }) {
2296
+ var _a, _b, _c, _d, _e;
2297
+ const now = Date.now();
2298
+ const newSessionId = fromByteArray(randomBytes(SESSION_ID_BYTE_LENGTH));
2299
+ const newSessionSecret = fromByteArray(randomBytes(SESSION_SECRET_BYTE_LENGTH));
2300
+ const newConnectionSecret = fromByteArray(randomBytes(SESSION_SECRET_BYTE_LENGTH));
2301
+ const newSession = {
2302
+ ...rest,
2303
+ userId: userId,
2304
+ sessionId: newSessionId,
2305
+ requestId: requestId !== null && requestId !== void 0 ? requestId : null,
2306
+ secretHash: this._hashHighEntropyPasswordWithSalt(newSessionSecret, newSessionId),
2307
+ connectionSecret: newConnectionSecret,
2308
+ grantedTimeMs: now,
2309
+ revokeTimeMs: null,
2310
+ expireTimeMs: lifetimeMs ? now + lifetimeMs : null,
2311
+ previousSessionId: (_a = previousSession === null || previousSession === void 0 ? void 0 : previousSession.sessionId) !== null && _a !== void 0 ? _a : null,
2312
+ nextSessionId: null,
2313
+ ipAddress: ipAddress,
2314
+ };
2315
+ if (requestId) {
2316
+ await this._store.markLoginRequestComplete(userId, requestId, now);
2317
+ }
2318
+ if (rest.webauthnRequestId) {
2319
+ await this._store.markWebAuthnLoginRequestComplete(rest.webauthnRequestId, userId, now);
2320
+ }
2321
+ if (rest.oidRequestId) {
2322
+ await this._store.markOpenIDLoginRequestComplete(rest.oidRequestId, now);
2323
+ }
2324
+ if (previousSession) {
2325
+ await this._store.replaceSession(previousSession, newSession, now);
2326
+ }
2327
+ else {
2328
+ await this._store.saveSession(newSession);
2329
+ }
2330
+ const metadata = await this._store.findUserLoginMetadata(userId);
2331
+ const info = {
2332
+ userId,
2333
+ sessionKey: formatV1SessionKey(userId, newSessionId, newSessionSecret, newSession.expireTimeMs),
2334
+ connectionKey: formatV1ConnectionKey(userId, newSessionId, newConnectionSecret, newSession.expireTimeMs),
2335
+ expireTimeMs: newSession.expireTimeMs,
2336
+ metadata: {
2337
+ hasUserAuthenticator: (_b = metadata === null || metadata === void 0 ? void 0 : metadata.hasUserAuthenticator) !== null && _b !== void 0 ? _b : false,
2338
+ userAuthenticatorCredentialIds: (_c = metadata === null || metadata === void 0 ? void 0 : metadata.userAuthenticatorCredentialIds) !== null && _c !== void 0 ? _c : [],
2339
+ hasPushSubscription: (_d = metadata === null || metadata === void 0 ? void 0 : metadata.hasPushSubscription) !== null && _d !== void 0 ? _d : false,
2340
+ pushSubscriptionIds: (_e = metadata === null || metadata === void 0 ? void 0 : metadata.pushSubscriptionIds) !== null && _e !== void 0 ? _e : [],
2341
+ },
2342
+ };
2343
+ console.log(`[AuthController] [issueSession userId: ${userId} newSessionId: ${newSessionId} expiresAt: ${newSession.expireTimeMs}] Issued session.`);
2344
+ return {
2345
+ newSession,
2346
+ info,
2347
+ };
2373
2348
  }
2374
2349
  }
2375
2350
  __decorate([
@@ -2466,32 +2441,31 @@ __decorate([
2466
2441
  * Validates the given session key using the given auth controller.
2467
2442
  * @param sessionKey The session key to validate.
2468
2443
  */
2469
- export function validateSessionKey(auth, sessionKey) {
2470
- return __awaiter(this, void 0, void 0, function* () {
2471
- if (!sessionKey) {
2472
- return {
2473
- success: false,
2474
- userId: null,
2475
- errorCode: 'no_session_key',
2476
- errorMessage: 'A session key was not provided, but it is required for this operation.',
2477
- };
2478
- }
2479
- const result = yield auth.validateSessionKey(sessionKey);
2480
- if (result.success === true) {
2481
- const span = trace.getActiveSpan();
2482
- if (span) {
2483
- span.setAttributes({
2484
- [SEMATTRS_ENDUSER_ID]: result.userId,
2485
- ['request.userId']: result.userId,
2486
- ['request.userRole']: result.role,
2487
- ['request.sessionId']: result.sessionId,
2488
- ['request.subscriptionId']: result.subscriptionId,
2489
- ['request.subscriptionTier']: result.subscriptionTier,
2490
- });
2491
- }
2444
+ export async function validateSessionKey(auth, sessionKey) {
2445
+ if (!sessionKey) {
2446
+ return {
2447
+ success: false,
2448
+ userId: null,
2449
+ role: null,
2450
+ errorCode: 'no_session_key',
2451
+ errorMessage: 'A session key was not provided, but it is required for this operation.',
2452
+ };
2453
+ }
2454
+ const result = await auth.validateSessionKey(sessionKey);
2455
+ if (result.success === true) {
2456
+ const span = trace.getActiveSpan();
2457
+ if (span) {
2458
+ span.setAttributes({
2459
+ [SEMATTRS_ENDUSER_ID]: result.userId,
2460
+ ['request.userId']: result.userId,
2461
+ ['request.userRole']: result.role,
2462
+ ['request.sessionId']: result.sessionId,
2463
+ ['request.subscriptionId']: result.subscriptionId,
2464
+ ['request.subscriptionTier']: result.subscriptionTier,
2465
+ });
2492
2466
  }
2493
- return result;
2494
- });
2467
+ }
2468
+ return result;
2495
2469
  }
2496
2470
  export function getPrivacyFeaturesFromPermissions(featureIds, permissions) {
2497
2471
  const publishData = permissions.some((p) => p.on && p.featureId === featureIds.projectDevelopment);