@exulu/backend 0.2.1 → 0.2.3
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/dist/index.cjs +118 -38
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +118 -38
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -194,6 +194,10 @@ var usersSchema = {
|
|
|
194
194
|
name: "apikey",
|
|
195
195
|
type: "text"
|
|
196
196
|
},
|
|
197
|
+
{
|
|
198
|
+
name: "last_used",
|
|
199
|
+
type: "date"
|
|
200
|
+
},
|
|
197
201
|
{
|
|
198
202
|
name: "role",
|
|
199
203
|
type: "reference",
|
|
@@ -202,10 +206,6 @@ var usersSchema = {
|
|
|
202
206
|
field: "id",
|
|
203
207
|
onDelete: "CASCADE"
|
|
204
208
|
}
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
name: "last_used",
|
|
208
|
-
type: "date"
|
|
209
209
|
}
|
|
210
210
|
]
|
|
211
211
|
};
|
|
@@ -404,7 +404,61 @@ var sanitizeName = (name) => {
|
|
|
404
404
|
};
|
|
405
405
|
|
|
406
406
|
// src/postgres/init-db.ts
|
|
407
|
+
var import_bcryptjs2 = __toESM(require("bcryptjs"), 1);
|
|
408
|
+
|
|
409
|
+
// src/auth/generate-key.ts
|
|
407
410
|
var import_bcryptjs = __toESM(require("bcryptjs"), 1);
|
|
411
|
+
var SALT_ROUNDS = 12;
|
|
412
|
+
async function encryptApiKey(apikey) {
|
|
413
|
+
const hash = await import_bcryptjs.default.hash(apikey, SALT_ROUNDS);
|
|
414
|
+
return hash;
|
|
415
|
+
}
|
|
416
|
+
var generateApiKey = async (name, email) => {
|
|
417
|
+
const { db: db2 } = await postgresClient();
|
|
418
|
+
console.log("[EXULU] Inserting default user and admin role.");
|
|
419
|
+
const existingRole = await db2.from("roles").where({ name: "admin" }).first();
|
|
420
|
+
let roleId;
|
|
421
|
+
if (!existingRole) {
|
|
422
|
+
console.log("[EXULU] Creating default admin role.");
|
|
423
|
+
const role = await db2.from("roles").insert({
|
|
424
|
+
name: "admin",
|
|
425
|
+
is_admin: true,
|
|
426
|
+
agents: []
|
|
427
|
+
}).returning("id");
|
|
428
|
+
roleId = role[0].id;
|
|
429
|
+
} else {
|
|
430
|
+
roleId = existingRole.id;
|
|
431
|
+
}
|
|
432
|
+
const newKeyName = name;
|
|
433
|
+
const plainKey = `sk_${Math.random().toString(36).substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`;
|
|
434
|
+
const postFix = `/${newKeyName.toLowerCase().trim().replaceAll(" ", "_")}`;
|
|
435
|
+
const encryptedKey = await encryptApiKey(plainKey);
|
|
436
|
+
const existingApiUser = await db2.from("users").where({ email }).first();
|
|
437
|
+
if (!existingApiUser) {
|
|
438
|
+
console.log("[EXULU] Creating default api user.");
|
|
439
|
+
await db2.from("users").insert({
|
|
440
|
+
name,
|
|
441
|
+
email,
|
|
442
|
+
super_admin: true,
|
|
443
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
444
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
445
|
+
type: "api",
|
|
446
|
+
apikey: `${encryptedKey}${postFix}`,
|
|
447
|
+
// password: "admin", todo add this again when we implement password auth / encryption as alternative to OTP
|
|
448
|
+
role: roleId
|
|
449
|
+
});
|
|
450
|
+
console.log("[EXULU] Default api user created. Key: ", `${plainKey}${postFix}`);
|
|
451
|
+
} else {
|
|
452
|
+
console.log("[EXULU] API user with that name already exists.");
|
|
453
|
+
}
|
|
454
|
+
console.log("[EXULU] Key generated, copy and use the plain key from here, you will not be able to access it again.");
|
|
455
|
+
console.log("[EXULU] Key: ", `${plainKey}${postFix}`);
|
|
456
|
+
return {
|
|
457
|
+
key: `${plainKey}${postFix}`
|
|
458
|
+
};
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
// src/postgres/init-db.ts
|
|
408
462
|
var up = async function(knex) {
|
|
409
463
|
if (!await knex.schema.hasTable("roles")) {
|
|
410
464
|
await knex.schema.createTable("roles", (table) => {
|
|
@@ -509,6 +563,7 @@ var up = async function(knex) {
|
|
|
509
563
|
table.timestamp("emailVerified", { useTz: true });
|
|
510
564
|
table.text("image");
|
|
511
565
|
for (const field of usersSchema.fields) {
|
|
566
|
+
console.log("[EXULU] field", field);
|
|
512
567
|
const { type, name, references, default: defaultValue } = field;
|
|
513
568
|
if (name === "id" || name === "name" || name === "email" || name === "emailVerified" || name === "image") {
|
|
514
569
|
continue;
|
|
@@ -552,9 +607,9 @@ var up = async function(knex) {
|
|
|
552
607
|
});
|
|
553
608
|
}
|
|
554
609
|
};
|
|
555
|
-
var
|
|
556
|
-
async function
|
|
557
|
-
const hash = await
|
|
610
|
+
var SALT_ROUNDS2 = 12;
|
|
611
|
+
async function encryptApiKey2(apikey) {
|
|
612
|
+
const hash = await import_bcryptjs2.default.hash(apikey, SALT_ROUNDS2);
|
|
558
613
|
return hash;
|
|
559
614
|
}
|
|
560
615
|
var execute = async () => {
|
|
@@ -578,7 +633,7 @@ var execute = async () => {
|
|
|
578
633
|
const newKeyName = "exulu_default_key";
|
|
579
634
|
const plainKey = `sk_${Math.random().toString(36).substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`;
|
|
580
635
|
const postFix = `/${newKeyName.toLowerCase().trim().replaceAll(" ", "_")}`;
|
|
581
|
-
const encryptedKey = await
|
|
636
|
+
const encryptedKey = await encryptApiKey2(plainKey);
|
|
582
637
|
const existingUser = await db2.from("users").where({ email: "admin@exulu.com" }).first();
|
|
583
638
|
if (!existingUser) {
|
|
584
639
|
console.log("[EXULU] Creating default admin user.");
|
|
@@ -593,23 +648,9 @@ var execute = async () => {
|
|
|
593
648
|
role: roleId
|
|
594
649
|
});
|
|
595
650
|
}
|
|
596
|
-
const
|
|
597
|
-
if (!existingApiUser) {
|
|
598
|
-
console.log("[EXULU] Creating default api user.");
|
|
599
|
-
await db2.from("users").insert({
|
|
600
|
-
name: "exulu",
|
|
601
|
-
email: "admin@exulu.com",
|
|
602
|
-
super_admin: true,
|
|
603
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
604
|
-
updatedAt: /* @__PURE__ */ new Date(),
|
|
605
|
-
type: "api",
|
|
606
|
-
apikey: `${encryptedKey}${postFix}`,
|
|
607
|
-
// password: "admin", todo add this again when we implement password auth / encryption as alternative to OTP
|
|
608
|
-
role: roleId
|
|
609
|
-
});
|
|
610
|
-
}
|
|
651
|
+
const { key } = await generateApiKey("exulu", "api@exulu.com");
|
|
611
652
|
console.log("[EXULU] Database initialized.");
|
|
612
|
-
console.log("[EXULU] Default api key: ", `${
|
|
653
|
+
console.log("[EXULU] Default api key: ", `${key}`);
|
|
613
654
|
return;
|
|
614
655
|
};
|
|
615
656
|
|
|
@@ -1469,13 +1510,14 @@ var import_express = require("express");
|
|
|
1469
1510
|
var import_jwt = require("next-auth/jwt");
|
|
1470
1511
|
|
|
1471
1512
|
// src/auth/auth.ts
|
|
1472
|
-
var
|
|
1513
|
+
var import_bcryptjs3 = __toESM(require("bcryptjs"), 1);
|
|
1473
1514
|
var authentication = async ({
|
|
1474
1515
|
apikey,
|
|
1475
1516
|
authtoken,
|
|
1476
1517
|
internalkey,
|
|
1477
1518
|
db: db2
|
|
1478
1519
|
}) => {
|
|
1520
|
+
console.log("[EXULU] apikey", apikey);
|
|
1479
1521
|
if (internalkey) {
|
|
1480
1522
|
if (!process.env.INTERNAL_SECRET) {
|
|
1481
1523
|
return {
|
|
@@ -1543,31 +1585,38 @@ var authentication = async ({
|
|
|
1543
1585
|
code: 401
|
|
1544
1586
|
};
|
|
1545
1587
|
}
|
|
1546
|
-
const
|
|
1547
|
-
const
|
|
1548
|
-
const
|
|
1549
|
-
|
|
1588
|
+
const request_key_parts = apikey.split("/");
|
|
1589
|
+
const request_key_name = request_key_parts.pop();
|
|
1590
|
+
const request_key_last_slash_index = apikey.lastIndexOf("/");
|
|
1591
|
+
const request_key_compare_value = apikey.substring(0, request_key_last_slash_index);
|
|
1592
|
+
if (!request_key_name) {
|
|
1550
1593
|
return {
|
|
1551
1594
|
error: true,
|
|
1552
1595
|
message: "Provided api key does not include postfix with key name ({key}/{name}).",
|
|
1553
1596
|
code: 401
|
|
1554
1597
|
};
|
|
1555
1598
|
}
|
|
1556
|
-
if (!
|
|
1599
|
+
if (!request_key_compare_value) {
|
|
1557
1600
|
return {
|
|
1558
1601
|
error: true,
|
|
1559
1602
|
message: "Provided api key is not in the correct format.",
|
|
1560
1603
|
code: 401
|
|
1561
1604
|
};
|
|
1562
1605
|
}
|
|
1563
|
-
|
|
1606
|
+
console.log("[EXULU] users", users);
|
|
1607
|
+
console.log("[EXULU] request_key_name", request_key_name);
|
|
1608
|
+
console.log("[EXULU] request_key_compare_value", request_key_compare_value);
|
|
1609
|
+
const filtered = users.filter(({ apikey: apikey2, id }) => apikey2.includes(request_key_name));
|
|
1610
|
+
console.log("[EXULU] filtered", filtered);
|
|
1564
1611
|
for (const user of filtered) {
|
|
1565
|
-
const
|
|
1566
|
-
const
|
|
1567
|
-
|
|
1612
|
+
const user_key_last_slash_index = user.apikey.lastIndexOf("/");
|
|
1613
|
+
const user_key_compare_value = user.apikey.substring(0, user_key_last_slash_index);
|
|
1614
|
+
console.log("[EXULU] user_key_compare_value", user_key_compare_value);
|
|
1615
|
+
const isMatch = await import_bcryptjs3.default.compare(request_key_compare_value, user_key_compare_value);
|
|
1616
|
+
console.log("[EXULU] isMatch", isMatch);
|
|
1568
1617
|
if (isMatch) {
|
|
1569
1618
|
await db2.from("users").where({ id: user.id }).update({
|
|
1570
|
-
|
|
1619
|
+
last_used: /* @__PURE__ */ new Date()
|
|
1571
1620
|
}).returning("id");
|
|
1572
1621
|
return {
|
|
1573
1622
|
error: false,
|
|
@@ -1576,6 +1625,12 @@ var authentication = async ({
|
|
|
1576
1625
|
};
|
|
1577
1626
|
}
|
|
1578
1627
|
}
|
|
1628
|
+
console.log("[EXULU] No matching api key found.");
|
|
1629
|
+
return {
|
|
1630
|
+
error: true,
|
|
1631
|
+
message: "No matching api key found.",
|
|
1632
|
+
code: 401
|
|
1633
|
+
};
|
|
1579
1634
|
}
|
|
1580
1635
|
return {
|
|
1581
1636
|
error: true,
|
|
@@ -2723,13 +2778,22 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
2723
2778
|
if (!exists) {
|
|
2724
2779
|
throw new Error("Table with name " + context.getTableName() + " does not exist.");
|
|
2725
2780
|
}
|
|
2726
|
-
const
|
|
2781
|
+
const query = db2.from(context.getTableName()).select("id");
|
|
2727
2782
|
if (id) {
|
|
2728
|
-
|
|
2783
|
+
query.where({ id });
|
|
2729
2784
|
}
|
|
2730
2785
|
if (external_id) {
|
|
2731
|
-
|
|
2786
|
+
query.where({ external_id });
|
|
2787
|
+
}
|
|
2788
|
+
const item = await query.first();
|
|
2789
|
+
if (!item) {
|
|
2790
|
+
throw new Error("Item not found.");
|
|
2732
2791
|
}
|
|
2792
|
+
const chunks = await db2.from(context.getChunksTableName()).where({ source: item.id }).select("id");
|
|
2793
|
+
if (chunks.length > 0) {
|
|
2794
|
+
await db2.from(context.getChunksTableName()).where({ source: item.id }).delete();
|
|
2795
|
+
}
|
|
2796
|
+
const mutation = db2.from(context.getTableName()).where({ id: item.id }).delete().returning("id");
|
|
2733
2797
|
const result = await mutation;
|
|
2734
2798
|
return result;
|
|
2735
2799
|
};
|
|
@@ -2840,12 +2904,25 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
2840
2904
|
});
|
|
2841
2905
|
app.post("/items/:context", async (req, res) => {
|
|
2842
2906
|
try {
|
|
2907
|
+
console.log("[EXULU] post items");
|
|
2843
2908
|
if (!req.params.context) {
|
|
2844
2909
|
res.status(400).json({
|
|
2845
2910
|
message: "Missing context in request."
|
|
2846
2911
|
});
|
|
2847
2912
|
return;
|
|
2848
2913
|
}
|
|
2914
|
+
if (!req.body) {
|
|
2915
|
+
res.status(400).json({
|
|
2916
|
+
message: "Missing body in request."
|
|
2917
|
+
});
|
|
2918
|
+
return;
|
|
2919
|
+
}
|
|
2920
|
+
if (!req.body.name) {
|
|
2921
|
+
res.status(400).json({
|
|
2922
|
+
message: "Missing in body of request."
|
|
2923
|
+
});
|
|
2924
|
+
return;
|
|
2925
|
+
}
|
|
2849
2926
|
const authenticationResult = await requestValidators.authenticate(req);
|
|
2850
2927
|
if (!authenticationResult.user?.id) {
|
|
2851
2928
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
@@ -3783,6 +3860,9 @@ var ExuluJobs = {
|
|
|
3783
3860
|
var ExuluDatabase = {
|
|
3784
3861
|
init: async () => {
|
|
3785
3862
|
await execute();
|
|
3863
|
+
},
|
|
3864
|
+
generateApiKey: async (name, email) => {
|
|
3865
|
+
return await generateApiKey(name, email);
|
|
3786
3866
|
}
|
|
3787
3867
|
};
|
|
3788
3868
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.d.cts
CHANGED
|
@@ -449,6 +449,9 @@ declare const ExuluJobs: {
|
|
|
449
449
|
|
|
450
450
|
declare const ExuluDatabase: {
|
|
451
451
|
init: () => Promise<void>;
|
|
452
|
+
generateApiKey: (name: string, email: string) => Promise<{
|
|
453
|
+
key: string;
|
|
454
|
+
}>;
|
|
452
455
|
};
|
|
453
456
|
|
|
454
457
|
export { type STATISTICS_TYPE as EXULU_STATISTICS_TYPE, STATISTICS_TYPE_ENUM as EXULU_STATISTICS_TYPE_ENUM, ExuluAgent, ExuluApp, authentication as ExuluAuthentication, ExuluContext, ExuluDatabase, ExuluEmbedder, ExuluJobs, queues as ExuluQueues, ExuluSource, ExuluTool, ExuluWorkflow, ExuluZodFileType };
|
package/dist/index.d.ts
CHANGED
|
@@ -449,6 +449,9 @@ declare const ExuluJobs: {
|
|
|
449
449
|
|
|
450
450
|
declare const ExuluDatabase: {
|
|
451
451
|
init: () => Promise<void>;
|
|
452
|
+
generateApiKey: (name: string, email: string) => Promise<{
|
|
453
|
+
key: string;
|
|
454
|
+
}>;
|
|
452
455
|
};
|
|
453
456
|
|
|
454
457
|
export { type STATISTICS_TYPE as EXULU_STATISTICS_TYPE, STATISTICS_TYPE_ENUM as EXULU_STATISTICS_TYPE_ENUM, ExuluAgent, ExuluApp, authentication as ExuluAuthentication, ExuluContext, ExuluDatabase, ExuluEmbedder, ExuluJobs, queues as ExuluQueues, ExuluSource, ExuluTool, ExuluWorkflow, ExuluZodFileType };
|
package/dist/index.js
CHANGED
|
@@ -153,6 +153,10 @@ var usersSchema = {
|
|
|
153
153
|
name: "apikey",
|
|
154
154
|
type: "text"
|
|
155
155
|
},
|
|
156
|
+
{
|
|
157
|
+
name: "last_used",
|
|
158
|
+
type: "date"
|
|
159
|
+
},
|
|
156
160
|
{
|
|
157
161
|
name: "role",
|
|
158
162
|
type: "reference",
|
|
@@ -161,10 +165,6 @@ var usersSchema = {
|
|
|
161
165
|
field: "id",
|
|
162
166
|
onDelete: "CASCADE"
|
|
163
167
|
}
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
name: "last_used",
|
|
167
|
-
type: "date"
|
|
168
168
|
}
|
|
169
169
|
]
|
|
170
170
|
};
|
|
@@ -363,7 +363,61 @@ var sanitizeName = (name) => {
|
|
|
363
363
|
};
|
|
364
364
|
|
|
365
365
|
// src/postgres/init-db.ts
|
|
366
|
+
import bcrypt2 from "bcryptjs";
|
|
367
|
+
|
|
368
|
+
// src/auth/generate-key.ts
|
|
366
369
|
import bcrypt from "bcryptjs";
|
|
370
|
+
var SALT_ROUNDS = 12;
|
|
371
|
+
async function encryptApiKey(apikey) {
|
|
372
|
+
const hash = await bcrypt.hash(apikey, SALT_ROUNDS);
|
|
373
|
+
return hash;
|
|
374
|
+
}
|
|
375
|
+
var generateApiKey = async (name, email) => {
|
|
376
|
+
const { db: db2 } = await postgresClient();
|
|
377
|
+
console.log("[EXULU] Inserting default user and admin role.");
|
|
378
|
+
const existingRole = await db2.from("roles").where({ name: "admin" }).first();
|
|
379
|
+
let roleId;
|
|
380
|
+
if (!existingRole) {
|
|
381
|
+
console.log("[EXULU] Creating default admin role.");
|
|
382
|
+
const role = await db2.from("roles").insert({
|
|
383
|
+
name: "admin",
|
|
384
|
+
is_admin: true,
|
|
385
|
+
agents: []
|
|
386
|
+
}).returning("id");
|
|
387
|
+
roleId = role[0].id;
|
|
388
|
+
} else {
|
|
389
|
+
roleId = existingRole.id;
|
|
390
|
+
}
|
|
391
|
+
const newKeyName = name;
|
|
392
|
+
const plainKey = `sk_${Math.random().toString(36).substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`;
|
|
393
|
+
const postFix = `/${newKeyName.toLowerCase().trim().replaceAll(" ", "_")}`;
|
|
394
|
+
const encryptedKey = await encryptApiKey(plainKey);
|
|
395
|
+
const existingApiUser = await db2.from("users").where({ email }).first();
|
|
396
|
+
if (!existingApiUser) {
|
|
397
|
+
console.log("[EXULU] Creating default api user.");
|
|
398
|
+
await db2.from("users").insert({
|
|
399
|
+
name,
|
|
400
|
+
email,
|
|
401
|
+
super_admin: true,
|
|
402
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
403
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
404
|
+
type: "api",
|
|
405
|
+
apikey: `${encryptedKey}${postFix}`,
|
|
406
|
+
// password: "admin", todo add this again when we implement password auth / encryption as alternative to OTP
|
|
407
|
+
role: roleId
|
|
408
|
+
});
|
|
409
|
+
console.log("[EXULU] Default api user created. Key: ", `${plainKey}${postFix}`);
|
|
410
|
+
} else {
|
|
411
|
+
console.log("[EXULU] API user with that name already exists.");
|
|
412
|
+
}
|
|
413
|
+
console.log("[EXULU] Key generated, copy and use the plain key from here, you will not be able to access it again.");
|
|
414
|
+
console.log("[EXULU] Key: ", `${plainKey}${postFix}`);
|
|
415
|
+
return {
|
|
416
|
+
key: `${plainKey}${postFix}`
|
|
417
|
+
};
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
// src/postgres/init-db.ts
|
|
367
421
|
var up = async function(knex) {
|
|
368
422
|
if (!await knex.schema.hasTable("roles")) {
|
|
369
423
|
await knex.schema.createTable("roles", (table) => {
|
|
@@ -468,6 +522,7 @@ var up = async function(knex) {
|
|
|
468
522
|
table.timestamp("emailVerified", { useTz: true });
|
|
469
523
|
table.text("image");
|
|
470
524
|
for (const field of usersSchema.fields) {
|
|
525
|
+
console.log("[EXULU] field", field);
|
|
471
526
|
const { type, name, references, default: defaultValue } = field;
|
|
472
527
|
if (name === "id" || name === "name" || name === "email" || name === "emailVerified" || name === "image") {
|
|
473
528
|
continue;
|
|
@@ -511,9 +566,9 @@ var up = async function(knex) {
|
|
|
511
566
|
});
|
|
512
567
|
}
|
|
513
568
|
};
|
|
514
|
-
var
|
|
515
|
-
async function
|
|
516
|
-
const hash = await
|
|
569
|
+
var SALT_ROUNDS2 = 12;
|
|
570
|
+
async function encryptApiKey2(apikey) {
|
|
571
|
+
const hash = await bcrypt2.hash(apikey, SALT_ROUNDS2);
|
|
517
572
|
return hash;
|
|
518
573
|
}
|
|
519
574
|
var execute = async () => {
|
|
@@ -537,7 +592,7 @@ var execute = async () => {
|
|
|
537
592
|
const newKeyName = "exulu_default_key";
|
|
538
593
|
const plainKey = `sk_${Math.random().toString(36).substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`;
|
|
539
594
|
const postFix = `/${newKeyName.toLowerCase().trim().replaceAll(" ", "_")}`;
|
|
540
|
-
const encryptedKey = await
|
|
595
|
+
const encryptedKey = await encryptApiKey2(plainKey);
|
|
541
596
|
const existingUser = await db2.from("users").where({ email: "admin@exulu.com" }).first();
|
|
542
597
|
if (!existingUser) {
|
|
543
598
|
console.log("[EXULU] Creating default admin user.");
|
|
@@ -552,23 +607,9 @@ var execute = async () => {
|
|
|
552
607
|
role: roleId
|
|
553
608
|
});
|
|
554
609
|
}
|
|
555
|
-
const
|
|
556
|
-
if (!existingApiUser) {
|
|
557
|
-
console.log("[EXULU] Creating default api user.");
|
|
558
|
-
await db2.from("users").insert({
|
|
559
|
-
name: "exulu",
|
|
560
|
-
email: "admin@exulu.com",
|
|
561
|
-
super_admin: true,
|
|
562
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
563
|
-
updatedAt: /* @__PURE__ */ new Date(),
|
|
564
|
-
type: "api",
|
|
565
|
-
apikey: `${encryptedKey}${postFix}`,
|
|
566
|
-
// password: "admin", todo add this again when we implement password auth / encryption as alternative to OTP
|
|
567
|
-
role: roleId
|
|
568
|
-
});
|
|
569
|
-
}
|
|
610
|
+
const { key } = await generateApiKey("exulu", "api@exulu.com");
|
|
570
611
|
console.log("[EXULU] Database initialized.");
|
|
571
|
-
console.log("[EXULU] Default api key: ", `${
|
|
612
|
+
console.log("[EXULU] Default api key: ", `${key}`);
|
|
572
613
|
return;
|
|
573
614
|
};
|
|
574
615
|
|
|
@@ -1428,13 +1469,14 @@ import "express";
|
|
|
1428
1469
|
import { getToken } from "next-auth/jwt";
|
|
1429
1470
|
|
|
1430
1471
|
// src/auth/auth.ts
|
|
1431
|
-
import
|
|
1472
|
+
import bcrypt3 from "bcryptjs";
|
|
1432
1473
|
var authentication = async ({
|
|
1433
1474
|
apikey,
|
|
1434
1475
|
authtoken,
|
|
1435
1476
|
internalkey,
|
|
1436
1477
|
db: db2
|
|
1437
1478
|
}) => {
|
|
1479
|
+
console.log("[EXULU] apikey", apikey);
|
|
1438
1480
|
if (internalkey) {
|
|
1439
1481
|
if (!process.env.INTERNAL_SECRET) {
|
|
1440
1482
|
return {
|
|
@@ -1502,31 +1544,38 @@ var authentication = async ({
|
|
|
1502
1544
|
code: 401
|
|
1503
1545
|
};
|
|
1504
1546
|
}
|
|
1505
|
-
const
|
|
1506
|
-
const
|
|
1507
|
-
const
|
|
1508
|
-
|
|
1547
|
+
const request_key_parts = apikey.split("/");
|
|
1548
|
+
const request_key_name = request_key_parts.pop();
|
|
1549
|
+
const request_key_last_slash_index = apikey.lastIndexOf("/");
|
|
1550
|
+
const request_key_compare_value = apikey.substring(0, request_key_last_slash_index);
|
|
1551
|
+
if (!request_key_name) {
|
|
1509
1552
|
return {
|
|
1510
1553
|
error: true,
|
|
1511
1554
|
message: "Provided api key does not include postfix with key name ({key}/{name}).",
|
|
1512
1555
|
code: 401
|
|
1513
1556
|
};
|
|
1514
1557
|
}
|
|
1515
|
-
if (!
|
|
1558
|
+
if (!request_key_compare_value) {
|
|
1516
1559
|
return {
|
|
1517
1560
|
error: true,
|
|
1518
1561
|
message: "Provided api key is not in the correct format.",
|
|
1519
1562
|
code: 401
|
|
1520
1563
|
};
|
|
1521
1564
|
}
|
|
1522
|
-
|
|
1565
|
+
console.log("[EXULU] users", users);
|
|
1566
|
+
console.log("[EXULU] request_key_name", request_key_name);
|
|
1567
|
+
console.log("[EXULU] request_key_compare_value", request_key_compare_value);
|
|
1568
|
+
const filtered = users.filter(({ apikey: apikey2, id }) => apikey2.includes(request_key_name));
|
|
1569
|
+
console.log("[EXULU] filtered", filtered);
|
|
1523
1570
|
for (const user of filtered) {
|
|
1524
|
-
const
|
|
1525
|
-
const
|
|
1526
|
-
|
|
1571
|
+
const user_key_last_slash_index = user.apikey.lastIndexOf("/");
|
|
1572
|
+
const user_key_compare_value = user.apikey.substring(0, user_key_last_slash_index);
|
|
1573
|
+
console.log("[EXULU] user_key_compare_value", user_key_compare_value);
|
|
1574
|
+
const isMatch = await bcrypt3.compare(request_key_compare_value, user_key_compare_value);
|
|
1575
|
+
console.log("[EXULU] isMatch", isMatch);
|
|
1527
1576
|
if (isMatch) {
|
|
1528
1577
|
await db2.from("users").where({ id: user.id }).update({
|
|
1529
|
-
|
|
1578
|
+
last_used: /* @__PURE__ */ new Date()
|
|
1530
1579
|
}).returning("id");
|
|
1531
1580
|
return {
|
|
1532
1581
|
error: false,
|
|
@@ -1535,6 +1584,12 @@ var authentication = async ({
|
|
|
1535
1584
|
};
|
|
1536
1585
|
}
|
|
1537
1586
|
}
|
|
1587
|
+
console.log("[EXULU] No matching api key found.");
|
|
1588
|
+
return {
|
|
1589
|
+
error: true,
|
|
1590
|
+
message: "No matching api key found.",
|
|
1591
|
+
code: 401
|
|
1592
|
+
};
|
|
1538
1593
|
}
|
|
1539
1594
|
return {
|
|
1540
1595
|
error: true,
|
|
@@ -2682,13 +2737,22 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
2682
2737
|
if (!exists) {
|
|
2683
2738
|
throw new Error("Table with name " + context.getTableName() + " does not exist.");
|
|
2684
2739
|
}
|
|
2685
|
-
const
|
|
2740
|
+
const query = db2.from(context.getTableName()).select("id");
|
|
2686
2741
|
if (id) {
|
|
2687
|
-
|
|
2742
|
+
query.where({ id });
|
|
2688
2743
|
}
|
|
2689
2744
|
if (external_id) {
|
|
2690
|
-
|
|
2745
|
+
query.where({ external_id });
|
|
2746
|
+
}
|
|
2747
|
+
const item = await query.first();
|
|
2748
|
+
if (!item) {
|
|
2749
|
+
throw new Error("Item not found.");
|
|
2691
2750
|
}
|
|
2751
|
+
const chunks = await db2.from(context.getChunksTableName()).where({ source: item.id }).select("id");
|
|
2752
|
+
if (chunks.length > 0) {
|
|
2753
|
+
await db2.from(context.getChunksTableName()).where({ source: item.id }).delete();
|
|
2754
|
+
}
|
|
2755
|
+
const mutation = db2.from(context.getTableName()).where({ id: item.id }).delete().returning("id");
|
|
2692
2756
|
const result = await mutation;
|
|
2693
2757
|
return result;
|
|
2694
2758
|
};
|
|
@@ -2799,12 +2863,25 @@ var createExpressRoutes = async (app, agents, embedders, tools, workflows, conte
|
|
|
2799
2863
|
});
|
|
2800
2864
|
app.post("/items/:context", async (req, res) => {
|
|
2801
2865
|
try {
|
|
2866
|
+
console.log("[EXULU] post items");
|
|
2802
2867
|
if (!req.params.context) {
|
|
2803
2868
|
res.status(400).json({
|
|
2804
2869
|
message: "Missing context in request."
|
|
2805
2870
|
});
|
|
2806
2871
|
return;
|
|
2807
2872
|
}
|
|
2873
|
+
if (!req.body) {
|
|
2874
|
+
res.status(400).json({
|
|
2875
|
+
message: "Missing body in request."
|
|
2876
|
+
});
|
|
2877
|
+
return;
|
|
2878
|
+
}
|
|
2879
|
+
if (!req.body.name) {
|
|
2880
|
+
res.status(400).json({
|
|
2881
|
+
message: "Missing in body of request."
|
|
2882
|
+
});
|
|
2883
|
+
return;
|
|
2884
|
+
}
|
|
2808
2885
|
const authenticationResult = await requestValidators.authenticate(req);
|
|
2809
2886
|
if (!authenticationResult.user?.id) {
|
|
2810
2887
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
@@ -3742,6 +3819,9 @@ var ExuluJobs = {
|
|
|
3742
3819
|
var ExuluDatabase = {
|
|
3743
3820
|
init: async () => {
|
|
3744
3821
|
await execute();
|
|
3822
|
+
},
|
|
3823
|
+
generateApiKey: async (name, email) => {
|
|
3824
|
+
return await generateApiKey(name, email);
|
|
3745
3825
|
}
|
|
3746
3826
|
};
|
|
3747
3827
|
export {
|