@yrpri/api 9.0.133 → 9.0.135
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/agents/managers/newAiModelSetup.js +72 -0
- package/app.js +2 -2
- package/controllers/users.cjs +104 -2
- package/models/domain.cjs +1 -0
- package/package.json +1 -1
- package/scripts/agents/changeModelForWorkflowGroupTemplate.d.ts +1 -0
- package/scripts/agents/changeModelForWorkflowGroupTemplate.js +82 -0
- package/scripts/change/setUseNewVersion.cjs +1 -0
- package/scripts/domains/importDomainsFromXls.js +5 -3
- package/scripts/keys/addOidcToDomain.cjs +3 -1
- package/scripts/users/createUserAddDomain.js +1 -1
- package/scripts/users/importUsersForDomainsFromXls.js +1 -1
- package/scripts/users/updatePasswordFromSsn.js +1 -1
- package/scripts/users/updateUserSsnFromEmail.js +1 -1
- package/services/auth/audkenniRestService.d.ts +14 -0
- package/services/auth/audkenniRestService.js +52 -0
|
@@ -644,6 +644,43 @@ export class NewAiModelSetup {
|
|
|
644
644
|
await gemini25ProPreview2.save();
|
|
645
645
|
console.log("Google model already exists: Gemini 2.5 Pro");
|
|
646
646
|
}
|
|
647
|
+
const gemini25ProFinalPreview = await PsAiModel.findOne({
|
|
648
|
+
where: { name: "Gemini 2.5 Pro Final Preview" },
|
|
649
|
+
});
|
|
650
|
+
const gemini25ProFinalConfig = {
|
|
651
|
+
type: PsAiModelType.TextReasoning,
|
|
652
|
+
modelSize: PsAiModelSize.Large,
|
|
653
|
+
provider: "google",
|
|
654
|
+
prices: {
|
|
655
|
+
costInTokensPerMillion: 1.25,
|
|
656
|
+
costOutTokensPerMillion: 10,
|
|
657
|
+
costInCachedContextTokensPerMillion: 0.875,
|
|
658
|
+
longContextTokenThreshold: 200000,
|
|
659
|
+
longContextCostInTokensPerMillion: 2.5,
|
|
660
|
+
longContextCostInCachedContextTokensPerMillion: 1.75,
|
|
661
|
+
longContextCostOutTokensPerMillion: 15,
|
|
662
|
+
currency: "USD",
|
|
663
|
+
},
|
|
664
|
+
model: "gemini-2-5-pro-preview-06-05",
|
|
665
|
+
active: true,
|
|
666
|
+
maxTokensOut: 100000,
|
|
667
|
+
defaultTemperature: 0.0,
|
|
668
|
+
};
|
|
669
|
+
if (!gemini25ProFinalPreview) {
|
|
670
|
+
await PsAiModel.create({
|
|
671
|
+
name: "Gemini 2.5 Pro Final Preview",
|
|
672
|
+
organization_id: 1,
|
|
673
|
+
user_id: userId,
|
|
674
|
+
configuration: gemini25ProFinalConfig,
|
|
675
|
+
});
|
|
676
|
+
console.log("Created Google model: Gemini 2.5 Pro Final Preview");
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
gemini25ProFinalPreview.set("configuration", gemini25ProFinalConfig);
|
|
680
|
+
gemini25ProFinalPreview.changed("configuration", true);
|
|
681
|
+
await gemini25ProFinalPreview.save();
|
|
682
|
+
console.log("Google model already exists: Gemini 2.5 Pro Final Preview");
|
|
683
|
+
}
|
|
647
684
|
const gemini25FlashPreview1 = await PsAiModel.findOne({
|
|
648
685
|
where: { name: "Gemini 2.5 Flash Preview 1" },
|
|
649
686
|
});
|
|
@@ -681,6 +718,39 @@ export class NewAiModelSetup {
|
|
|
681
718
|
await gemini25FlashPreview1.save();
|
|
682
719
|
console.log("Google model already exists: Gemini 2.5 Pro");
|
|
683
720
|
}
|
|
721
|
+
const gemini25FlashPreview = await PsAiModel.findOne({
|
|
722
|
+
where: { name: "Gemini 2.5 Flash Preview" },
|
|
723
|
+
});
|
|
724
|
+
const gemini25FlashPreviewConfig = {
|
|
725
|
+
type: PsAiModelType.Text,
|
|
726
|
+
modelSize: PsAiModelSize.Medium,
|
|
727
|
+
provider: "google",
|
|
728
|
+
prices: {
|
|
729
|
+
costInTokensPerMillion: 0.15,
|
|
730
|
+
costOutTokensPerMillion: 0.6,
|
|
731
|
+
costInCachedContextTokensPerMillion: 0.09,
|
|
732
|
+
currency: "USD",
|
|
733
|
+
},
|
|
734
|
+
maxTokensOut: 8192,
|
|
735
|
+
defaultTemperature: 0.0,
|
|
736
|
+
model: "gemini-2-5-flash-preview-05-20",
|
|
737
|
+
active: true,
|
|
738
|
+
};
|
|
739
|
+
if (!gemini25FlashPreview) {
|
|
740
|
+
await PsAiModel.create({
|
|
741
|
+
name: "Gemini 2.5 Flash Preview",
|
|
742
|
+
organization_id: 1,
|
|
743
|
+
user_id: userId,
|
|
744
|
+
configuration: gemini25FlashPreviewConfig,
|
|
745
|
+
});
|
|
746
|
+
console.log("Created Google model: Gemini 2.5 Flash Preview");
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
gemini25FlashPreview.set("configuration", gemini25FlashPreviewConfig);
|
|
750
|
+
gemini25FlashPreview.changed("configuration", true);
|
|
751
|
+
await gemini25FlashPreview.save();
|
|
752
|
+
console.log("Google model already exists: Gemini 2.5 Flash Preview");
|
|
753
|
+
}
|
|
684
754
|
}
|
|
685
755
|
/**
|
|
686
756
|
* Master seeding function which calls the provider-specific functions
|
|
@@ -790,7 +860,9 @@ export class NewAiModelSetup {
|
|
|
790
860
|
{ name: "Gemini 2.0 Flash", envKey: "GEMINI_API_KEY" },
|
|
791
861
|
{ name: "Gemini 2.5 Pro Preview 1", envKey: "GEMINI_API_KEY" },
|
|
792
862
|
{ name: "Gemini 2.5 Pro Preview 2", envKey: "GEMINI_API_KEY" },
|
|
863
|
+
{ name: "Gemini 2.5 Pro Final Preview", envKey: "GEMINI_API_KEY" },
|
|
793
864
|
{ name: "Gemini 2.5 Flash Preview 1", envKey: "GEMINI_API_KEY" },
|
|
865
|
+
{ name: "Gemini 2.5 Flash Preview", envKey: "GEMINI_API_KEY" },
|
|
794
866
|
{ name: "o1 24", envKey: "OPENAI_API_KEY" },
|
|
795
867
|
{ name: "o3 mini", envKey: "OPENAI_API_KEY" },
|
|
796
868
|
{ name: "o4 mini", envKey: "OPENAI_API_KEY" },
|
package/app.js
CHANGED
|
@@ -198,10 +198,10 @@ export class YourPrioritiesApi {
|
|
|
198
198
|
this.addDirnameToRequest();
|
|
199
199
|
this.forceHttps();
|
|
200
200
|
this.initializeMiddlewares();
|
|
201
|
-
this.setupNewWebAppVersionHandling();
|
|
202
201
|
this.handleShortenedRedirects();
|
|
203
202
|
this.initializeRateLimiting();
|
|
204
203
|
this.setupDomainAndCommunity();
|
|
204
|
+
this.setupNewWebAppVersionHandling();
|
|
205
205
|
this.setupSitemapRoute();
|
|
206
206
|
this.initializePassportStrategies();
|
|
207
207
|
this.addInviteAsAnonMiddleWare();
|
|
@@ -216,10 +216,10 @@ export class YourPrioritiesApi {
|
|
|
216
216
|
this.addDirnameToRequest();
|
|
217
217
|
this.forceHttps();
|
|
218
218
|
this.initializeMiddlewares();
|
|
219
|
-
this.setupNewWebAppVersionHandling();
|
|
220
219
|
this.handleShortenedRedirects();
|
|
221
220
|
this.initializeRateLimiting();
|
|
222
221
|
this.setupDomainAndCommunity();
|
|
222
|
+
this.setupNewWebAppVersionHandling();
|
|
223
223
|
this.setupSitemapRoute();
|
|
224
224
|
this.initializePassportStrategies();
|
|
225
225
|
this.addInviteAsAnonMiddleWare();
|
package/controllers/users.cjs
CHANGED
|
@@ -1437,7 +1437,6 @@ router.delete('/anonymize_current_user', function (req, res) {
|
|
|
1437
1437
|
}
|
|
1438
1438
|
});
|
|
1439
1439
|
router.post('/logout', function (req, res) {
|
|
1440
|
-
log.info("Anon debug logout");
|
|
1441
1440
|
if (req.isAuthenticated()) {
|
|
1442
1441
|
log.info('User Logging out', { userId: req.user.id, context: 'logout' });
|
|
1443
1442
|
}
|
|
@@ -1447,8 +1446,11 @@ router.post('/logout', function (req, res) {
|
|
|
1447
1446
|
const oidcProvider = req.ypDomain &&
|
|
1448
1447
|
req.ypDomain.loginProviders &&
|
|
1449
1448
|
req.ypDomain.loginProviders.find((p) => p.provider === 'oidc');
|
|
1449
|
+
log.info("oidcProvider", { oidcProvider });
|
|
1450
1450
|
if (req.sso && oidcProvider && oidcProvider.endSessionURL) {
|
|
1451
|
+
log.info("Logging out from OIDC");
|
|
1451
1452
|
logoutFromSession(req, res, 200, () => {
|
|
1453
|
+
log.info("Logging out from OIDC", { oidcProvider });
|
|
1452
1454
|
req.sso.logout(oidcProvider.name, { postLogoutRedirectUri: '/' }, req, res, (error) => {
|
|
1453
1455
|
if (error) {
|
|
1454
1456
|
log.error('Error logging out from OIDC', { err: error });
|
|
@@ -2208,6 +2210,103 @@ router.get('/:id/status_update/:bulkStatusUpdateId', function (req, res, next) {
|
|
|
2208
2210
|
});
|
|
2209
2211
|
}
|
|
2210
2212
|
});
|
|
2213
|
+
// Audkenni REST Authentication
|
|
2214
|
+
router.post('/auth/audkenni-rest/start', async function (req, res) {
|
|
2215
|
+
try {
|
|
2216
|
+
const { phone, authenticator } = req.body;
|
|
2217
|
+
if (!phone || !authenticator) {
|
|
2218
|
+
res.status(400).send({ error: 'missing_parameters' });
|
|
2219
|
+
return;
|
|
2220
|
+
}
|
|
2221
|
+
const { default: AudkenniRestService } = await import('../services/auth/audkenniRestService.js');
|
|
2222
|
+
const service = new AudkenniRestService();
|
|
2223
|
+
const startData = await service.start();
|
|
2224
|
+
const callbacks = (startData.callbacks || []).map((cb) => {
|
|
2225
|
+
if (cb.type === 'NameCallback') {
|
|
2226
|
+
cb.input[0].value = phone;
|
|
2227
|
+
}
|
|
2228
|
+
else if (cb.type === 'ChoiceCallback') {
|
|
2229
|
+
const index = cb.output[1].value.indexOf(authenticator);
|
|
2230
|
+
cb.input[0].value = index >= 0 ? index : 0;
|
|
2231
|
+
}
|
|
2232
|
+
return cb;
|
|
2233
|
+
});
|
|
2234
|
+
await service.continue(startData.authId, callbacks);
|
|
2235
|
+
res.send({ pollId: startData.authId });
|
|
2236
|
+
}
|
|
2237
|
+
catch (error) {
|
|
2238
|
+
log.error('Error starting Audkenni REST login', { error });
|
|
2239
|
+
res.status(500).send({ error: 'audkenni_start_failed' });
|
|
2240
|
+
}
|
|
2241
|
+
});
|
|
2242
|
+
router.post('/auth/audkenni-rest/continue', async function (req, res) {
|
|
2243
|
+
try {
|
|
2244
|
+
const { authId, callbacks } = req.body;
|
|
2245
|
+
const { default: AudkenniRestService } = await import('../services/auth/audkenniRestService.js');
|
|
2246
|
+
const service = new AudkenniRestService();
|
|
2247
|
+
const data = await service.continue(authId, callbacks);
|
|
2248
|
+
res.send({ authId: data.authId, callbacks: data.callbacks, tokenId: data.tokenId });
|
|
2249
|
+
}
|
|
2250
|
+
catch (error) {
|
|
2251
|
+
log.error('Error continuing Audkenni REST login', { error });
|
|
2252
|
+
res.status(500).send({ error: 'audkenni_continue_failed' });
|
|
2253
|
+
}
|
|
2254
|
+
});
|
|
2255
|
+
router.get('/auth/audkenni-rest/poll/:id', async function (req, res) {
|
|
2256
|
+
try {
|
|
2257
|
+
const authId = req.params.id;
|
|
2258
|
+
const { default: AudkenniRestService } = await import('../services/auth/audkenniRestService.js');
|
|
2259
|
+
const service = new AudkenniRestService();
|
|
2260
|
+
const result = await service.poll(authId);
|
|
2261
|
+
if (!result.tokenId) {
|
|
2262
|
+
res.send({ pending: true });
|
|
2263
|
+
return;
|
|
2264
|
+
}
|
|
2265
|
+
const profile = result.profile || { nationalRegisterId: result.nationalId, name: result.name, provider: 'oidc' };
|
|
2266
|
+
models.User.serializeOidcUser(profile, req, function (error, user) {
|
|
2267
|
+
if (error || !user) {
|
|
2268
|
+
log.error('Error serializing Audkenni user', { error });
|
|
2269
|
+
res.status(500).send({ error: 'audkenni_login_failed' });
|
|
2270
|
+
}
|
|
2271
|
+
else {
|
|
2272
|
+
req.logIn(user, async function (err) {
|
|
2273
|
+
if (err) {
|
|
2274
|
+
log.error('Error logging in Audkenni user', { err });
|
|
2275
|
+
res.status(500).send({ error: 'audkenni_login_failed' });
|
|
2276
|
+
}
|
|
2277
|
+
else {
|
|
2278
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
2279
|
+
getUserWithAll(user.id, true, function (getErr, fullUser) {
|
|
2280
|
+
if (getErr || !fullUser) {
|
|
2281
|
+
res.status(500).send({ error: 'audkenni_user_fetch_failed' });
|
|
2282
|
+
}
|
|
2283
|
+
else {
|
|
2284
|
+
if (fullUser.email) {
|
|
2285
|
+
delete fullUser.email;
|
|
2286
|
+
}
|
|
2287
|
+
else {
|
|
2288
|
+
fullUser.missingEmail = true;
|
|
2289
|
+
}
|
|
2290
|
+
if (fullUser.private_profile_data && fullUser.private_profile_data.registration_answers) {
|
|
2291
|
+
fullUser.dataValues.hasRegistrationAnswers = true;
|
|
2292
|
+
}
|
|
2293
|
+
else {
|
|
2294
|
+
fullUser.dataValues.hasRegistrationAnswers = false;
|
|
2295
|
+
}
|
|
2296
|
+
delete fullUser.private_profile_data;
|
|
2297
|
+
res.send(fullUser);
|
|
2298
|
+
}
|
|
2299
|
+
});
|
|
2300
|
+
}
|
|
2301
|
+
});
|
|
2302
|
+
}
|
|
2303
|
+
});
|
|
2304
|
+
}
|
|
2305
|
+
catch (error) {
|
|
2306
|
+
log.error('Error polling Audkenni REST login', { error });
|
|
2307
|
+
res.status(500).send({ error: 'audkenni_poll_failed' });
|
|
2308
|
+
}
|
|
2309
|
+
});
|
|
2211
2310
|
// Facebook Authentication
|
|
2212
2311
|
router.get('/auth/facebook', function (req, res) {
|
|
2213
2312
|
req.sso.authenticate('facebook-strategy-' + req.ypDomain.id, {}, req, res, function (error, user) {
|
|
@@ -2287,7 +2386,10 @@ router.get('/auth/audkenni/callback', async function (req, res) {
|
|
|
2287
2386
|
}
|
|
2288
2387
|
}
|
|
2289
2388
|
else {
|
|
2290
|
-
if (process.env.
|
|
2389
|
+
if (process.env.REDIRECT_AFTER_AUDKENNI_URL) {
|
|
2390
|
+
res.redirect(process.env.REDIRECT_AFTER_AUDKENNI_URL);
|
|
2391
|
+
}
|
|
2392
|
+
else if (process.env.REDIRECT_TO_ROOT_AFTER_OIDC) {
|
|
2291
2393
|
res.redirect('/');
|
|
2292
2394
|
}
|
|
2293
2395
|
else {
|
package/models/domain.cjs
CHANGED
|
@@ -237,6 +237,7 @@ module.exports = (sequelize, DataTypes) => {
|
|
|
237
237
|
authorizationURL: domain.secret_api_keys.oidc.authorizationURL,
|
|
238
238
|
tokenURL: domain.secret_api_keys.oidc.tokenURL,
|
|
239
239
|
userInfoURL: domain.secret_api_keys.oidc.userInfoURL,
|
|
240
|
+
endSessionURL: domain.secret_api_keys.oidc.endSessionURL,
|
|
240
241
|
callbackUrl: "https://" +
|
|
241
242
|
callbackDomainName +
|
|
242
243
|
"/api/users/auth/audkenni/callback",
|
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { initializeModels, PsAgent, PsAiModel, } from "@policysynth/agents/dbModels/index.js";
|
|
2
|
+
import { PsAiModelSize, PsAiModelType } from "@policysynth/agents/aiModelTypes.js";
|
|
3
|
+
import models from "../../models/index.cjs";
|
|
4
|
+
(async () => {
|
|
5
|
+
const [groupIdArg, sizeArg, typeArg, modelNameArg] = process.argv.slice(2);
|
|
6
|
+
if (!groupIdArg || !sizeArg || !typeArg || !modelNameArg) {
|
|
7
|
+
console.error("Usage: ts-node changeModelForWorkflowGroupTemplate.ts <groupId> <modelSize (small, medium, large)> <modeltype: text, textReasoning> <model_name>");
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
const groupId = Number(groupIdArg);
|
|
11
|
+
if (isNaN(groupId)) {
|
|
12
|
+
console.error("groupId must be a number");
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
const sizeMap = {
|
|
16
|
+
small: PsAiModelSize.Small,
|
|
17
|
+
medium: PsAiModelSize.Medium,
|
|
18
|
+
large: PsAiModelSize.Large,
|
|
19
|
+
};
|
|
20
|
+
const typeMap = {
|
|
21
|
+
text: PsAiModelType.Text,
|
|
22
|
+
textreasoning: PsAiModelType.TextReasoning,
|
|
23
|
+
};
|
|
24
|
+
const size = sizeMap[sizeArg.toLowerCase()];
|
|
25
|
+
const modelType = typeMap[typeArg.toLowerCase()];
|
|
26
|
+
if (!size) {
|
|
27
|
+
console.error("modelSize must be one of small, medium or large");
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
if (!modelType) {
|
|
31
|
+
console.error("modeltype must be text or textReasoning");
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
await initializeModels();
|
|
36
|
+
const group = await models.Group.findByPk(groupId);
|
|
37
|
+
if (!group) {
|
|
38
|
+
throw new Error(`Group ${groupId} not found`);
|
|
39
|
+
}
|
|
40
|
+
const topLevelAgentId = group.configuration?.agents?.topLevelAgentId;
|
|
41
|
+
if (!topLevelAgentId) {
|
|
42
|
+
throw new Error("Top level agent id not found in group configuration");
|
|
43
|
+
}
|
|
44
|
+
const subAgents = await PsAgent.findAll({
|
|
45
|
+
where: { group_id: groupId, parent_agent_id: topLevelAgentId },
|
|
46
|
+
});
|
|
47
|
+
if (subAgents.length === 0) {
|
|
48
|
+
throw new Error("No sub-agents found for workflow group");
|
|
49
|
+
}
|
|
50
|
+
const newModel = await PsAiModel.findOne({
|
|
51
|
+
where: { configuration: { model: modelNameArg } },
|
|
52
|
+
});
|
|
53
|
+
if (!newModel) {
|
|
54
|
+
throw new Error(`AI model with configuration.model ${modelNameArg} not found`);
|
|
55
|
+
}
|
|
56
|
+
const privateConfig = (group.private_access_configuration ?? []);
|
|
57
|
+
for (const agent of subAgents) {
|
|
58
|
+
const currentModels = await agent.getAiModels();
|
|
59
|
+
for (const current of currentModels) {
|
|
60
|
+
const cfg = current.configuration || {};
|
|
61
|
+
if (cfg.modelSize === size && cfg.type === modelType) {
|
|
62
|
+
await agent.removeAiModel(current);
|
|
63
|
+
const entry = privateConfig.find((p) => p.aiModelId === current.id);
|
|
64
|
+
if (entry)
|
|
65
|
+
entry.aiModelId = newModel.id;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
await agent.addAiModel(newModel);
|
|
69
|
+
console.log(`Updated agent ${agent.id} to use model ${newModel.name}`);
|
|
70
|
+
}
|
|
71
|
+
group.set("private_access_configuration", privateConfig);
|
|
72
|
+
group.changed("private_access_configuration", true);
|
|
73
|
+
await group.save();
|
|
74
|
+
console.log(`Group ${groupId} updated successfully`);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
console.error(error);
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
await models.sequelize.close();
|
|
81
|
+
}
|
|
82
|
+
})();
|
|
@@ -7,6 +7,7 @@ models.Domain.findOne({ where: { id: domainId } }).then(async (domain) => {
|
|
|
7
7
|
console.log("Domain " + domain.domain_name);
|
|
8
8
|
if (useNewVersionStatus === "true" || useNewVersionStatus === "false") {
|
|
9
9
|
domain.set("configuration.useNewVersion", useNewVersionStatus === "true" ? true : false);
|
|
10
|
+
domain.changed("configuration", true);
|
|
10
11
|
await domain.save();
|
|
11
12
|
console.log("Set useNewVersionStatus to " + useNewVersionStatus);
|
|
12
13
|
}
|
|
@@ -2,9 +2,9 @@ import ExcelJS from 'exceljs';
|
|
|
2
2
|
import models from '../../models/index.cjs';
|
|
3
3
|
(async () => {
|
|
4
4
|
try {
|
|
5
|
-
const [xlsPath, clientId, clientSecret, issuer, authorizationURL, tokenURL, userInfoURL,] = process.argv.slice(2);
|
|
5
|
+
const [xlsPath, clientId, clientSecret, issuer, authorizationURL, tokenURL, userInfoURL, endSessionURL,] = process.argv.slice(2);
|
|
6
6
|
if (!xlsPath) {
|
|
7
|
-
console.log('Usage: node importDomainsFromXls.js <path-to-xls> [clientId clientSecret issuer authorizationURL tokenURL userInfoURL]');
|
|
7
|
+
console.log('Usage: node importDomainsFromXls.js <path-to-xls> [clientId clientSecret issuer authorizationURL tokenURL userInfoURL endSessionURL]');
|
|
8
8
|
process.exit(1);
|
|
9
9
|
}
|
|
10
10
|
const oidcProvided = clientId &&
|
|
@@ -12,7 +12,8 @@ import models from '../../models/index.cjs';
|
|
|
12
12
|
issuer &&
|
|
13
13
|
authorizationURL &&
|
|
14
14
|
tokenURL &&
|
|
15
|
-
userInfoURL
|
|
15
|
+
userInfoURL &&
|
|
16
|
+
endSessionURL;
|
|
16
17
|
const workbook = new ExcelJS.Workbook();
|
|
17
18
|
await workbook.xlsx.readFile(xlsPath);
|
|
18
19
|
const worksheet = workbook.getWorksheet(1);
|
|
@@ -29,6 +30,7 @@ import models from '../../models/index.cjs';
|
|
|
29
30
|
authorizationURL,
|
|
30
31
|
tokenURL,
|
|
31
32
|
userInfoURL,
|
|
33
|
+
endSessionURL,
|
|
32
34
|
}
|
|
33
35
|
: null;
|
|
34
36
|
for (let i = 2; i <= worksheet.rowCount; i++) {
|
|
@@ -8,6 +8,7 @@ const issuer = process.argv[5];
|
|
|
8
8
|
const authorizationURL = process.argv[6];
|
|
9
9
|
const tokenURL = process.argv[7];
|
|
10
10
|
const userInfoURL = process.argv[8];
|
|
11
|
+
const endSessionURL = process.argv[9];
|
|
11
12
|
console.log(`Updating OIDC keys for domain ${domainId}`);
|
|
12
13
|
async.series([
|
|
13
14
|
function (callback) {
|
|
@@ -29,7 +30,8 @@ async.series([
|
|
|
29
30
|
issuer: issuer,
|
|
30
31
|
authorizationURL: authorizationURL,
|
|
31
32
|
tokenURL: tokenURL,
|
|
32
|
-
userInfoURL: userInfoURL
|
|
33
|
+
userInfoURL: userInfoURL,
|
|
34
|
+
endSessionURL: endSessionURL
|
|
33
35
|
};
|
|
34
36
|
console.log("Updated secret_api_keys:", JSON.stringify(domain.secret_api_keys, null, 2));
|
|
35
37
|
domain.changed('secret_api_keys', true);
|
|
@@ -18,7 +18,7 @@ import models from '../../models/index.cjs';
|
|
|
18
18
|
const fullUserName = String(row.getCell(2).text).trim();
|
|
19
19
|
const userEmail = String(row.getCell(3).text).trim().toLowerCase();
|
|
20
20
|
const userSsn = String(row.getCell(4).text).trim();
|
|
21
|
-
const userSsnNumber = userSsn
|
|
21
|
+
const userSsnNumber = userSsn || undefined;
|
|
22
22
|
if (!domainName || !fullUserName || !userEmail) {
|
|
23
23
|
throw new Error(`Missing data in row ${i}`);
|
|
24
24
|
}
|
|
@@ -7,7 +7,7 @@ import models from '../../models/index.cjs';
|
|
|
7
7
|
console.log('Usage: node updatePasswordFromSsn.js <ssn> <newPassword>');
|
|
8
8
|
process.exit(1);
|
|
9
9
|
}
|
|
10
|
-
const ssn =
|
|
10
|
+
const ssn = ssnArg;
|
|
11
11
|
const user = await models.User.findOne({ where: { ssn } });
|
|
12
12
|
if (!user) {
|
|
13
13
|
console.error(`User with ssn ${ssn} not found`);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface AudkenniAuthResponse {
|
|
2
|
+
authId?: string;
|
|
3
|
+
callbacks?: any[];
|
|
4
|
+
tokenId?: string;
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
}
|
|
7
|
+
export default class AudkenniRestService {
|
|
8
|
+
private endpoint;
|
|
9
|
+
private client;
|
|
10
|
+
start(): Promise<AudkenniAuthResponse>;
|
|
11
|
+
authenticate(phone: string, authenticator: 'sim' | 'app'): Promise<AudkenniAuthResponse>;
|
|
12
|
+
continue(authId: string, callbacks: any[]): Promise<AudkenniAuthResponse>;
|
|
13
|
+
poll(authId: string, callbacks?: any[], interval?: number, maxAttempts?: number): Promise<AudkenniAuthResponse>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
export default class AudkenniRestService {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.endpoint = "https://idp.audkenni.is/sso/json/realms/root/realms/audkenni/authenticate";
|
|
5
|
+
this.client = axios.create({
|
|
6
|
+
headers: {
|
|
7
|
+
Accept: "application/json",
|
|
8
|
+
"Content-Type": "application/json",
|
|
9
|
+
},
|
|
10
|
+
validateStatus: () => true,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
async start() {
|
|
14
|
+
const { data } = await this.client.post(this.endpoint, {});
|
|
15
|
+
return data;
|
|
16
|
+
}
|
|
17
|
+
async authenticate(phone, authenticator) {
|
|
18
|
+
const startData = await this.start();
|
|
19
|
+
if (!startData.authId || !startData.callbacks) {
|
|
20
|
+
throw new Error('Invalid start response');
|
|
21
|
+
}
|
|
22
|
+
const callbacks = (startData.callbacks || []).map((cb) => {
|
|
23
|
+
if (cb.type === 'NameCallback') {
|
|
24
|
+
cb.input[0].value = phone;
|
|
25
|
+
}
|
|
26
|
+
else if (cb.type === 'ChoiceCallback') {
|
|
27
|
+
const choices = cb.output?.find((o) => o.name === 'choices')?.value || [];
|
|
28
|
+
const idx = choices.findIndex((c) => c.toLowerCase().includes(authenticator));
|
|
29
|
+
cb.input[0].value = idx >= 0 ? idx : 0;
|
|
30
|
+
}
|
|
31
|
+
return cb;
|
|
32
|
+
});
|
|
33
|
+
const cont = await this.continue(startData.authId, callbacks);
|
|
34
|
+
return this.poll(cont.authId || startData.authId, cont.callbacks);
|
|
35
|
+
}
|
|
36
|
+
async continue(authId, callbacks) {
|
|
37
|
+
const payload = { authId, callbacks };
|
|
38
|
+
const { data } = await this.client.post(this.endpoint, payload);
|
|
39
|
+
return data;
|
|
40
|
+
}
|
|
41
|
+
async poll(authId, callbacks, interval = 2000, maxAttempts = 30) {
|
|
42
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
43
|
+
const payload = callbacks ? { authId, callbacks } : { authId };
|
|
44
|
+
const { data } = await this.client.post(this.endpoint, payload);
|
|
45
|
+
if (data.tokenId) {
|
|
46
|
+
return data;
|
|
47
|
+
}
|
|
48
|
+
await new Promise((r) => setTimeout(r, interval));
|
|
49
|
+
}
|
|
50
|
+
throw new Error("Timeout waiting for tokenId");
|
|
51
|
+
}
|
|
52
|
+
}
|