@casual-simulation/aux-records 3.4.6-alpha.14601027727 → 3.5.0-alpha.15117651144
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AIController.js +835 -890
- package/AIController.js.map +1 -1
- package/AIHumeInterface.js +43 -54
- package/AIHumeInterface.js.map +1 -1
- package/AIOpenAIRealtimeInterface.js +60 -71
- package/AIOpenAIRealtimeInterface.js.map +1 -1
- package/AnthropicAIChatInterface.js +96 -142
- package/AnthropicAIChatInterface.js.map +1 -1
- package/AuthController.d.ts +3 -2
- package/AuthController.js +1907 -1933
- package/AuthController.js.map +1 -1
- package/AuthStore.d.ts +1 -10
- package/BlockadeLabsGenerateSkyboxInterface.js +57 -72
- package/BlockadeLabsGenerateSkyboxInterface.js.map +1 -1
- package/CachingConfigStore.js +30 -45
- package/CachingConfigStore.js.map +1 -1
- package/CachingPolicyStore.d.ts +8 -2
- package/CachingPolicyStore.js +108 -135
- package/CachingPolicyStore.js.map +1 -1
- package/ComIdConfig.d.ts +18 -18
- package/ComIdConfig.js.map +1 -1
- package/ConsoleAuthMessenger.js +7 -20
- package/ConsoleAuthMessenger.js.map +1 -1
- package/DataRecordsController.d.ts +2 -2
- package/DataRecordsController.js +369 -377
- package/DataRecordsController.js.map +1 -1
- package/DataRecordsStore.d.ts +1 -1
- package/DataRecordsStore.js +1 -1
- package/DataRecordsStore.js.map +1 -1
- package/EventRecordsController.js +226 -240
- package/EventRecordsController.js.map +1 -1
- package/FileRecordsController.d.ts +13 -2
- package/FileRecordsController.js +458 -450
- package/FileRecordsController.js.map +1 -1
- package/GoogleAIChatInterface.js +133 -179
- package/GoogleAIChatInterface.js.map +1 -1
- package/LivekitController.js +43 -54
- package/LivekitController.js.map +1 -1
- package/LoomController.js +64 -75
- package/LoomController.js.map +1 -1
- package/MemoryAuthMessenger.js +10 -23
- package/MemoryAuthMessenger.js.map +1 -1
- package/MemoryCache.js +18 -35
- package/MemoryCache.js.map +1 -1
- package/MemoryFileRecordsLookup.js +105 -125
- package/MemoryFileRecordsLookup.js.map +1 -1
- package/MemoryModerationJobProvider.js +17 -30
- package/MemoryModerationJobProvider.js.map +1 -1
- package/MemoryRateLimiter.js +12 -27
- package/MemoryRateLimiter.js.map +1 -1
- package/MemoryStore.d.ts +18 -6
- package/MemoryStore.js +1879 -1997
- package/MemoryStore.js.map +1 -1
- package/MetricsStore.d.ts +2 -2
- package/ModerationController.js +186 -200
- package/ModerationController.js.map +1 -1
- package/OpenAIChatInterface.js +105 -135
- package/OpenAIChatInterface.js.map +1 -1
- package/OpenAIImageInterface.js +57 -51
- package/OpenAIImageInterface.js.map +1 -1
- package/PolicyController.d.ts +150 -10
- package/PolicyController.js +1546 -1299
- package/PolicyController.js.map +1 -1
- package/PolicyStore.d.ts +110 -2
- package/PolicyStore.js +36 -1
- package/PolicyStore.js.map +1 -1
- package/PrivoClient.js +398 -435
- package/PrivoClient.js.map +1 -1
- package/RateLimitController.js +25 -36
- package/RateLimitController.js.map +1 -1
- package/RecordsClient.js +51 -74
- package/RecordsClient.js.map +1 -1
- package/RecordsController.d.ts +2 -42
- package/RecordsController.js +1026 -1182
- package/RecordsController.js.map +1 -1
- package/RecordsServer.d.ts +196 -27
- package/RecordsServer.js +1701 -1343
- package/RecordsServer.js.map +1 -1
- package/RecordsStore.d.ts +1 -10
- package/RecordsStore.js.map +1 -1
- package/ServerConfig.d.ts +339 -195
- package/ServerConfig.js +13 -0
- package/ServerConfig.js.map +1 -1
- package/SloydInterface.js +62 -75
- package/SloydInterface.js.map +1 -1
- package/StabilityAIImageInterface.js +150 -167
- package/StabilityAIImageInterface.js.map +1 -1
- package/SubscriptionConfigBuilder.d.ts +6 -1
- package/SubscriptionConfigBuilder.js +22 -0
- package/SubscriptionConfigBuilder.js.map +1 -1
- package/SubscriptionConfiguration.d.ts +266 -169
- package/SubscriptionConfiguration.js +101 -79
- package/SubscriptionConfiguration.js.map +1 -1
- package/SubscriptionController.d.ts +2 -1
- package/SubscriptionController.js +643 -650
- package/SubscriptionController.js.map +1 -1
- package/SystemNotificationMessenger.d.ts +21 -4
- package/SystemNotificationMessenger.js +36 -30
- package/SystemNotificationMessenger.js.map +1 -1
- package/TestUtils.d.ts +9 -1
- package/TestUtils.js +105 -129
- package/TestUtils.js.map +1 -1
- package/Utils.d.ts +2 -16
- package/Utils.js +21 -22
- package/Utils.js.map +1 -1
- package/crud/CrudHelpers.js +17 -26
- package/crud/CrudHelpers.js.map +1 -1
- package/crud/CrudRecordsController.d.ts +1 -1
- package/crud/CrudRecordsController.js +259 -267
- package/crud/CrudRecordsController.js.map +1 -1
- package/crud/CrudRecordsControllerTests.js +174 -185
- package/crud/CrudRecordsControllerTests.js.map +1 -1
- package/crud/CrudRecordsStore.d.ts +7 -3
- package/crud/MemoryCrudRecordsStore.d.ts +4 -4
- package/crud/MemoryCrudRecordsStore.js +98 -118
- package/crud/MemoryCrudRecordsStore.js.map +1 -1
- package/crud/sub/MemorySubCrudRecordsStore.d.ts +24 -0
- package/crud/sub/MemorySubCrudRecordsStore.js +146 -0
- package/crud/sub/MemorySubCrudRecordsStore.js.map +1 -0
- package/crud/sub/SubCrudRecordsController.d.ts +182 -0
- package/crud/sub/SubCrudRecordsController.js +360 -0
- package/crud/sub/SubCrudRecordsController.js.map +1 -0
- package/crud/sub/SubCrudRecordsControllerTests.d.ts +39 -0
- package/crud/sub/SubCrudRecordsControllerTests.js +821 -0
- package/crud/sub/SubCrudRecordsControllerTests.js.map +1 -0
- package/crud/sub/SubCrudRecordsStore.d.ts +95 -0
- package/{forms/index.js → crud/sub/SubCrudRecordsStore.js} +2 -2
- package/crud/sub/SubCrudRecordsStore.js.map +1 -0
- package/crud/sub/index.d.ts +3 -0
- package/crud/sub/index.js +20 -0
- package/{forms → crud/sub}/index.js.map +1 -1
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/notifications/MemoryNotificationRecordsStore.js +189 -198
- package/notifications/MemoryNotificationRecordsStore.js.map +1 -1
- package/notifications/NotificationRecordsController.js +438 -460
- package/notifications/NotificationRecordsController.js.map +1 -1
- package/notifications/NotificationRecordsStore.d.ts +2 -1
- package/notifications/WebPushInterface.d.ts +0 -1
- package/notifications/WebPushInterface.js +0 -1
- package/notifications/WebPushInterface.js.map +1 -1
- package/package.json +6 -6
- package/packages/MemoryPackageRecordsStore.d.ts +10 -0
- package/packages/MemoryPackageRecordsStore.js +38 -0
- package/packages/MemoryPackageRecordsStore.js.map +1 -0
- package/packages/PackageRecordsController.d.ts +26 -0
- package/packages/PackageRecordsController.js +49 -0
- package/packages/PackageRecordsController.js.map +1 -0
- package/packages/PackageRecordsStore.d.ts +32 -0
- package/packages/PackageRecordsStore.js +19 -0
- package/packages/PackageRecordsStore.js.map +1 -0
- package/packages/index.d.ts +4 -0
- package/packages/index.js +21 -0
- package/packages/index.js.map +1 -0
- package/packages/version/MemoryPackageVersionRecordsStore.d.ts +21 -0
- package/packages/version/MemoryPackageVersionRecordsStore.js +177 -0
- package/packages/version/MemoryPackageVersionRecordsStore.js.map +1 -0
- package/packages/version/PackageVersionRecordsController.d.ts +144 -0
- package/packages/version/PackageVersionRecordsController.js +656 -0
- package/packages/version/PackageVersionRecordsController.js.map +1 -0
- package/packages/version/PackageVersionRecordsStore.d.ts +342 -0
- package/packages/version/PackageVersionRecordsStore.js +126 -0
- package/packages/version/PackageVersionRecordsStore.js.map +1 -0
- package/packages/version/index.d.ts +4 -0
- package/packages/version/index.js +21 -0
- package/packages/version/index.js.map +1 -0
- package/tracing/TracingDecorators.js +31 -40
- package/tracing/TracingDecorators.js.map +1 -1
- package/webhooks/MemoryWebhookRecordsStore.js +56 -72
- package/webhooks/MemoryWebhookRecordsStore.js.map +1 -1
- package/webhooks/WebhookEnvironment.d.ts +3 -3
- package/webhooks/WebhookRecordsController.d.ts +2 -1
- package/webhooks/WebhookRecordsController.js +389 -382
- package/webhooks/WebhookRecordsController.js.map +1 -1
- package/webhooks/WebhookRecordsStore.d.ts +2 -1
- package/websockets/InstRecordsStore.d.ts +50 -0
- package/websockets/InstRecordsStore.js +17 -0
- package/websockets/InstRecordsStore.js.map +1 -1
- package/websockets/MemoryTempInstRecordsStore.d.ts +5 -0
- package/websockets/MemoryTempInstRecordsStore.js +168 -179
- package/websockets/MemoryTempInstRecordsStore.js.map +1 -1
- package/websockets/MemoryWebsocketConnectionStore.js +98 -135
- package/websockets/MemoryWebsocketConnectionStore.js.map +1 -1
- package/websockets/MemoryWebsocketMessenger.js +29 -48
- package/websockets/MemoryWebsocketMessenger.js.map +1 -1
- package/websockets/SplitInstRecordsStore.d.ts +4 -1
- package/websockets/SplitInstRecordsStore.js +167 -185
- package/websockets/SplitInstRecordsStore.js.map +1 -1
- package/websockets/TemporaryInstRecordsStore.d.ts +19 -1
- package/websockets/TemporaryInstRecordsStore.js +17 -0
- package/websockets/TemporaryInstRecordsStore.js.map +1 -1
- package/websockets/WebsocketController.d.ts +147 -3
- package/websockets/WebsocketController.js +1735 -1391
- package/websockets/WebsocketController.js.map +1 -1
- package/websockets/index.d.ts +0 -1
- package/websockets/index.js +0 -1
- package/websockets/index.js.map +1 -1
- package/AAGUID.d.ts +0 -11
- package/AAGUID.js +0 -116
- package/AAGUID.js.map +0 -1
- package/AuthUtils.d.ts +0 -162
- package/AuthUtils.js +0 -327
- package/AuthUtils.js.map +0 -1
- package/forms/FormError.d.ts +0 -43
- package/forms/FormError.js +0 -56
- package/forms/FormError.js.map +0 -1
- package/forms/index.d.ts +0 -2
- package/websockets/Utils.d.ts +0 -33
- package/websockets/Utils.js +0 -82
- 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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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: '
|
|
194
|
-
errorMessage: '
|
|
124
|
+
errorCode: 'not_authorized',
|
|
125
|
+
errorMessage: 'You are not authorized to perform this action.',
|
|
195
126
|
};
|
|
196
127
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
:
|
|
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
|
|
146
|
+
return {
|
|
147
|
+
success: true,
|
|
148
|
+
...info,
|
|
149
|
+
};
|
|
218
150
|
}
|
|
219
|
-
|
|
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:
|
|
226
|
-
|
|
227
|
-
|
|
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
|
-
|
|
237
|
-
|
|
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:
|
|
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
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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: '
|
|
250
|
-
errorMessage:
|
|
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
|
-
|
|
254
|
-
|
|
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: '
|
|
258
|
-
errorMessage:
|
|
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
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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:
|
|
290
|
+
errorMessage: 'The given address is not accepted.',
|
|
276
291
|
};
|
|
277
292
|
}
|
|
278
293
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
382
|
-
errorMessage:
|
|
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
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
-
|
|
401
|
-
|
|
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
|
-
|
|
408
|
-
|
|
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: '
|
|
412
|
-
errorMessage:
|
|
419
|
+
errorCode: 'invalid_request',
|
|
420
|
+
errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
|
|
413
421
|
};
|
|
414
422
|
}
|
|
415
|
-
|
|
416
|
-
|
|
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: '
|
|
420
|
-
errorMessage:
|
|
439
|
+
errorCode: 'invalid_request',
|
|
440
|
+
errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
|
|
421
441
|
};
|
|
422
442
|
}
|
|
423
|
-
|
|
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: '
|
|
427
|
-
errorMessage: 'The
|
|
456
|
+
errorCode: 'invalid_code',
|
|
457
|
+
errorMessage: 'The code is invalid.',
|
|
428
458
|
};
|
|
429
459
|
}
|
|
430
|
-
|
|
431
|
-
|
|
460
|
+
const user = await this._store.findUser(loginRequest.userId);
|
|
461
|
+
if (!user) {
|
|
432
462
|
return {
|
|
433
463
|
success: false,
|
|
434
|
-
errorCode: '
|
|
435
|
-
errorMessage:
|
|
464
|
+
errorCode: 'invalid_request',
|
|
465
|
+
errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
|
|
436
466
|
};
|
|
437
467
|
}
|
|
438
|
-
|
|
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: '
|
|
515
|
-
errorMessage:
|
|
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
|
-
|
|
522
|
-
|
|
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:
|
|
565
|
-
|
|
566
|
-
|
|
502
|
+
success: false,
|
|
503
|
+
errorCode: 'not_supported',
|
|
504
|
+
errorMessage: 'The given provider is not supported.',
|
|
567
505
|
};
|
|
568
506
|
}
|
|
569
|
-
|
|
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: '
|
|
577
|
-
errorMessage: '
|
|
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
|
-
|
|
584
|
-
|
|
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:
|
|
562
|
+
success: false,
|
|
563
|
+
errorCode: 'not_supported',
|
|
564
|
+
errorMessage: 'Privo features are not supported on this server.',
|
|
640
565
|
};
|
|
641
566
|
}
|
|
642
|
-
|
|
643
|
-
|
|
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: '
|
|
650
|
-
errorMessage: '
|
|
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
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
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
|
-
|
|
789
|
-
|
|
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: '
|
|
796
|
-
errorMessage: '
|
|
643
|
+
errorCode: 'not_supported',
|
|
644
|
+
errorMessage: 'Privo features are not supported on this server.',
|
|
797
645
|
};
|
|
798
646
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
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
|
-
|
|
930
|
-
|
|
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
|
-
|
|
948
|
-
|
|
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: '
|
|
955
|
-
errorMessage:
|
|
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
|
-
|
|
961
|
-
|
|
962
|
-
|
|
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:
|
|
1008
|
-
|
|
790
|
+
success: false,
|
|
791
|
+
errorCode: 'not_supported',
|
|
792
|
+
errorMessage: 'Privo features are not supported on this server.',
|
|
1009
793
|
};
|
|
1010
794
|
}
|
|
1011
|
-
|
|
1012
|
-
|
|
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: '
|
|
1019
|
-
errorMessage: '
|
|
799
|
+
errorCode: 'not_supported',
|
|
800
|
+
errorMessage: 'Privo features are not supported on this server.',
|
|
1020
801
|
};
|
|
1021
802
|
}
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
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: '
|
|
1047
|
-
errorMessage: '
|
|
845
|
+
errorCode: 'parent_email_required',
|
|
846
|
+
errorMessage: 'A parent email is required to sign up a child.',
|
|
1048
847
|
};
|
|
1049
848
|
}
|
|
1050
|
-
const
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
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
|
-
|
|
1089
|
-
|
|
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:
|
|
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
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
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: '
|
|
1105
|
-
errorMessage: '
|
|
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:
|
|
1145
|
-
|
|
1146
|
-
|
|
1021
|
+
success: false,
|
|
1022
|
+
errorCode: 'invalid_origin',
|
|
1023
|
+
errorMessage: 'The request must be made from an authorized origin.',
|
|
1147
1024
|
};
|
|
1148
1025
|
}
|
|
1149
|
-
|
|
1150
|
-
|
|
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: '
|
|
1157
|
-
errorMessage: '
|
|
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
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
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:
|
|
1221
|
-
errorCode: 'user_is_banned',
|
|
1222
|
-
errorMessage: 'The user has been banned.',
|
|
1223
|
-
banReason: user.banReason,
|
|
1061
|
+
success: true,
|
|
1224
1062
|
};
|
|
1225
1063
|
}
|
|
1226
|
-
|
|
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: '
|
|
1254
|
-
errorMessage:
|
|
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
|
-
|
|
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: '
|
|
1274
|
-
errorMessage:
|
|
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
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
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:
|
|
1292
|
-
|
|
1293
|
-
|
|
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
|
-
|
|
1307
|
-
|
|
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: '
|
|
1314
|
-
errorMessage: '
|
|
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:
|
|
1155
|
+
success: false,
|
|
1156
|
+
errorCode: 'invalid_origin',
|
|
1157
|
+
errorMessage: 'The request must be made from an authorized origin.',
|
|
1339
1158
|
};
|
|
1340
1159
|
}
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
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: '
|
|
1349
|
-
errorMessage:
|
|
1165
|
+
errorCode: 'invalid_request',
|
|
1166
|
+
errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
|
|
1350
1167
|
};
|
|
1351
1168
|
}
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
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: '
|
|
1360
|
-
errorMessage:
|
|
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
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
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: '
|
|
1415
|
-
errorMessage:
|
|
1223
|
+
errorCode: 'invalid_request',
|
|
1224
|
+
errorMessage: INVALID_REQUEST_ERROR_MESSAGE,
|
|
1416
1225
|
};
|
|
1417
1226
|
}
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
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:
|
|
1442
|
-
|
|
1443
|
-
|
|
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
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
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: '
|
|
1459
|
-
errorMessage: '
|
|
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
|
-
|
|
1465
|
-
|
|
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
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
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: '
|
|
1473
|
-
errorMessage: 'The given
|
|
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
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
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:
|
|
1555
|
-
|
|
1556
|
-
|
|
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
|
-
|
|
1567
|
-
|
|
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: '
|
|
1574
|
-
errorMessage:
|
|
1364
|
+
errorCode: 'invalid_key',
|
|
1365
|
+
errorMessage: INVALID_KEY_ERROR_MESSAGE,
|
|
1575
1366
|
};
|
|
1576
1367
|
}
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
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: '
|
|
1586
|
-
errorMessage:
|
|
1373
|
+
errorCode: 'invalid_key',
|
|
1374
|
+
errorMessage: INVALID_KEY_ERROR_MESSAGE,
|
|
1587
1375
|
};
|
|
1588
1376
|
}
|
|
1589
|
-
|
|
1590
|
-
|
|
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: '
|
|
1594
|
-
errorMessage: 'The
|
|
1382
|
+
errorCode: 'session_expired',
|
|
1383
|
+
errorMessage: 'The session has expired.',
|
|
1595
1384
|
};
|
|
1596
1385
|
}
|
|
1597
|
-
|
|
1598
|
-
|
|
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: '
|
|
1602
|
-
errorMessage:
|
|
1391
|
+
errorCode: 'invalid_key',
|
|
1392
|
+
errorMessage: INVALID_KEY_ERROR_MESSAGE,
|
|
1603
1393
|
};
|
|
1604
1394
|
}
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
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 (
|
|
1407
|
+
if (userInfo.banTimeMs > 0) {
|
|
1633
1408
|
return {
|
|
1634
1409
|
success: false,
|
|
1635
|
-
errorCode: '
|
|
1636
|
-
errorMessage: 'The
|
|
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
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
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: '
|
|
1673
|
-
errorMessage: 'The given
|
|
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
|
-
|
|
1677
|
-
|
|
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: '
|
|
1681
|
-
errorMessage:
|
|
1467
|
+
errorCode: 'invalid_token',
|
|
1468
|
+
errorMessage: INVALID_TOKEN_ERROR_MESSAGE,
|
|
1682
1469
|
};
|
|
1683
1470
|
}
|
|
1684
|
-
|
|
1685
|
-
|
|
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:
|
|
1474
|
+
success: false,
|
|
1475
|
+
errorCode: 'invalid_token',
|
|
1476
|
+
errorMessage: INVALID_TOKEN_ERROR_MESSAGE,
|
|
1699
1477
|
};
|
|
1700
1478
|
}
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
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: '
|
|
1709
|
-
errorMessage:
|
|
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: '
|
|
1725
|
-
errorMessage: 'The
|
|
1493
|
+
errorCode: 'session_expired',
|
|
1494
|
+
errorMessage: 'The session has expired.',
|
|
1726
1495
|
};
|
|
1727
1496
|
}
|
|
1728
|
-
|
|
1729
|
-
|
|
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: '
|
|
1733
|
-
errorMessage:
|
|
1502
|
+
errorCode: 'invalid_token',
|
|
1503
|
+
errorMessage: INVALID_TOKEN_ERROR_MESSAGE,
|
|
1734
1504
|
};
|
|
1735
1505
|
}
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
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 (
|
|
1752
|
-
console.log('[AuthController] [replaceSession] Session is irrevokable.');
|
|
1518
|
+
if (userInfo.banTimeMs > 0) {
|
|
1753
1519
|
return {
|
|
1754
1520
|
success: false,
|
|
1755
|
-
errorCode: '
|
|
1756
|
-
errorMessage:
|
|
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
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
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: '
|
|
1775
|
-
errorMessage:
|
|
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: '
|
|
1790
|
-
errorMessage: 'The
|
|
1594
|
+
errorCode: 'session_not_found',
|
|
1595
|
+
errorMessage: 'The session was not found.',
|
|
1791
1596
|
};
|
|
1792
1597
|
}
|
|
1793
|
-
|
|
1794
|
-
request.expireTimeMs !== null &&
|
|
1795
|
-
typeof request.expireTimeMs !== 'undefined') {
|
|
1598
|
+
if (session.revokeTimeMs) {
|
|
1796
1599
|
return {
|
|
1797
1600
|
success: false,
|
|
1798
|
-
errorCode: '
|
|
1799
|
-
errorMessage: 'The
|
|
1601
|
+
errorCode: 'session_already_revoked',
|
|
1602
|
+
errorMessage: 'The session has already been revoked.',
|
|
1800
1603
|
};
|
|
1801
1604
|
}
|
|
1802
|
-
|
|
1803
|
-
request.sessionKey === '') {
|
|
1605
|
+
if (session.revocable === false) {
|
|
1804
1606
|
return {
|
|
1805
1607
|
success: false,
|
|
1806
|
-
errorCode: '
|
|
1807
|
-
errorMessage: 'The
|
|
1608
|
+
errorCode: 'session_is_not_revokable',
|
|
1609
|
+
errorMessage: 'The session cannot be revoked.',
|
|
1808
1610
|
};
|
|
1809
1611
|
}
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
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
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
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: '
|
|
1853
|
-
errorMessage:
|
|
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
|
-
*
|
|
1688
|
+
* Attempts to replace the given session key with a new key.
|
|
1860
1689
|
* @param request The request.
|
|
1861
1690
|
*/
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
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: '
|
|
1869
|
-
errorMessage:
|
|
1719
|
+
errorCode: 'invalid_key',
|
|
1720
|
+
errorMessage: INVALID_KEY_ERROR_MESSAGE,
|
|
1870
1721
|
};
|
|
1871
1722
|
}
|
|
1872
|
-
|
|
1873
|
-
|
|
1723
|
+
if (session.revocable === false) {
|
|
1724
|
+
console.log('[AuthController] [replaceSession] Session is irrevokable.');
|
|
1874
1725
|
return {
|
|
1875
1726
|
success: false,
|
|
1876
|
-
errorCode: '
|
|
1877
|
-
errorMessage:
|
|
1727
|
+
errorCode: 'invalid_key',
|
|
1728
|
+
errorMessage: INVALID_KEY_ERROR_MESSAGE,
|
|
1878
1729
|
};
|
|
1879
1730
|
}
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
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:
|
|
1934
|
-
|
|
1935
|
-
|
|
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
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
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: '
|
|
1955
|
-
errorMessage:
|
|
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
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
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
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
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
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
if (
|
|
2018
|
-
|
|
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
|
|
1996
|
+
sub = subscriptionConfig === null || subscriptionConfig === void 0 ? void 0 : subscriptionConfig.subscriptions[0];
|
|
2031
1997
|
if (sub) {
|
|
2032
|
-
console.log('[AuthController] [getUserInfo] Using
|
|
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
|
-
|
|
2006
|
+
console.log('[AuthController] [getUserInfo] Using default subscription for user.');
|
|
2037
2007
|
}
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
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
|
-
|
|
2051
|
-
|
|
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: '
|
|
2055
|
-
errorMessage:
|
|
2056
|
-
};
|
|
2057
|
-
}
|
|
2058
|
-
|
|
2059
|
-
|
|
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: '
|
|
2063
|
-
errorMessage: '
|
|
2101
|
+
errorCode: 'not_supported',
|
|
2102
|
+
errorMessage: 'Privo features are not supported on this server.',
|
|
2064
2103
|
};
|
|
2065
2104
|
}
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
Array.isArray(request.update)) {
|
|
2105
|
+
const config = await this._config.getPrivoConfiguration();
|
|
2106
|
+
if (!config) {
|
|
2069
2107
|
return {
|
|
2070
2108
|
success: false,
|
|
2071
|
-
errorCode: '
|
|
2072
|
-
errorMessage: '
|
|
2109
|
+
errorCode: 'not_supported',
|
|
2110
|
+
errorMessage: 'Privo features are not supported on this server.',
|
|
2073
2111
|
};
|
|
2074
2112
|
}
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
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
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
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: '
|
|
2113
|
-
errorMessage:
|
|
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
|
-
|
|
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: '
|
|
2181
|
-
errorMessage: '
|
|
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
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
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
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
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
|
-
|
|
2210
|
+
allowed: false,
|
|
2221
2211
|
};
|
|
2222
2212
|
}
|
|
2223
|
-
|
|
2224
|
-
const
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
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
|
|
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
|
-
|
|
2279
|
-
|
|
2280
|
-
if (
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
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
|
-
|
|
2302
|
-
profanity: result.profanity,
|
|
2254
|
+
allowed: false,
|
|
2255
|
+
containsName: true,
|
|
2303
2256
|
};
|
|
2304
2257
|
}
|
|
2305
2258
|
}
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
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(
|
|
2332
|
-
var _b, _c, _d, _e
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
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
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
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
|
-
|
|
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);
|