kempo 4.2.39 → 4.3.0
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/README.md +7 -0
- package/app-public/default.template.html +1 -1
- package/dist/admin/nav.fragment.html +5 -0
- package/dist/admin/realtime/index.page.html +81 -0
- package/dist/admin/settings/[owner]/[name]/index.page.html +52 -1
- package/dist/admin/settings/index.page.html +12 -1
- package/dist/kempo/api/realtime/WS.js +2 -0
- package/dist/kempo/api/realtime/WS.js.map +1 -0
- package/dist/kempo/api/realtime/connections/GET.js +2 -0
- package/dist/kempo/api/realtime/connections/GET.js.map +1 -0
- package/dist/kempo/icons/credit_card.svg +1 -0
- package/dist/kempo/icons/sensors.svg +1 -0
- package/dist/kempo/realtime.js +2 -0
- package/dist/kempo/realtime.js.map +1 -0
- package/dist/kempo/sdk.js +1 -1
- package/dist/kempo/sdk.js.map +1 -1
- package/middleware/kempo.js +30 -15
- package/package.json +2 -2
- package/scripts/init-db.js +4 -1
- package/server/db/schema.js +30 -1
- package/server/sdk.js +5 -0
- package/server/utils/extensions/contentDirs.js +27 -0
- package/server/utils/realtime/Hub.js +676 -0
- package/server/utils/realtime/channels.js +247 -0
- package/server/utils/realtime/closeConnection.js +4 -0
- package/server/utils/realtime/constants.js +20 -0
- package/server/utils/realtime/duration.js +18 -0
- package/server/utils/realtime/getHub.js +15 -0
- package/server/utils/realtime/index.js +14 -0
- package/server/utils/realtime/listConnections.js +4 -0
- package/server/utils/realtime/listSubscribers.js +4 -0
- package/server/utils/realtime/pruneMessages.js +45 -0
- package/server/utils/realtime/publish.js +86 -0
- package/server/utils/realtime/sendToConnection.js +4 -0
- package/server/utils/routing/serveUnmatched.js +8 -1
- package/server/utils/settings/getPublicSettings.js +4 -2
- package/server/utils/settings/getSettingWithMetadata.js +11 -4
- package/server/utils/settings/helpers.js +8 -2
- package/server/utils/settings/listSettings.js +9 -1
- package/server/utils/settings/secretCrypto.js +41 -0
- package/server/utils/settings/setSetting.js +31 -10
|
@@ -2,32 +2,53 @@ import db from '../../db/index.js';
|
|
|
2
2
|
import { setting } from '../../db/schema.js';
|
|
3
3
|
import { eq } from 'drizzle-orm';
|
|
4
4
|
import { serializeValue } from './helpers.js';
|
|
5
|
+
import { SECRET_MASK } from './secretCrypto.js';
|
|
5
6
|
|
|
6
7
|
export default async (owner, name, value, type = null, isPublic = false, description = null) => {
|
|
7
8
|
if(!owner || !name){
|
|
8
9
|
return [{ code: 400, msg: 'Both owner and name are required' }, null];
|
|
9
10
|
}
|
|
10
|
-
|
|
11
|
+
|
|
11
12
|
try {
|
|
12
13
|
const fullName = `${owner}:${name}`;
|
|
13
14
|
const detectedType = type || (typeof value === 'object' ? 'json' : typeof value);
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const existing = await db
|
|
15
|
+
|
|
16
|
+
const [existing] = await db
|
|
17
17
|
.select()
|
|
18
18
|
.from(setting)
|
|
19
19
|
.where(eq(setting.name, fullName))
|
|
20
20
|
.limit(1);
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
Secrets are never public, and the admin UI only ever shows SECRET_MASK back for an existing
|
|
24
|
+
one — if that's what comes back unchanged, keep the stored ciphertext instead of encrypting
|
|
25
|
+
the mask itself. A masked value with nothing to preserve (no prior secret) means the caller
|
|
26
|
+
never actually supplied a new one.
|
|
27
|
+
*/
|
|
28
|
+
let serializedValue;
|
|
29
|
+
if(detectedType === 'secret'){
|
|
30
|
+
isPublic = false;
|
|
31
|
+
if(value === SECRET_MASK){
|
|
32
|
+
if(!existing || existing.type !== 'secret'){
|
|
33
|
+
return [{ code: 400, msg: 'A secret value is required' }, null];
|
|
34
|
+
}
|
|
35
|
+
serializedValue = existing.value;
|
|
36
|
+
} else {
|
|
37
|
+
serializedValue = serializeValue(value, detectedType);
|
|
38
|
+
}
|
|
39
|
+
} else {
|
|
40
|
+
serializedValue = serializeValue(value, detectedType);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if(existing){
|
|
23
44
|
await db
|
|
24
45
|
.update(setting)
|
|
25
|
-
.set({
|
|
46
|
+
.set({
|
|
26
47
|
value: serializedValue,
|
|
27
48
|
type: detectedType,
|
|
28
49
|
isPublic,
|
|
29
50
|
description,
|
|
30
|
-
updatedAt: new Date()
|
|
51
|
+
updatedAt: new Date()
|
|
31
52
|
})
|
|
32
53
|
.where(eq(setting.name, fullName));
|
|
33
54
|
} else {
|
|
@@ -41,8 +62,8 @@ export default async (owner, name, value, type = null, isPublic = false, descrip
|
|
|
41
62
|
updatedAt: new Date()
|
|
42
63
|
});
|
|
43
64
|
}
|
|
44
|
-
|
|
45
|
-
return [null, { name: fullName, value, type: detectedType, isPublic, description }];
|
|
65
|
+
|
|
66
|
+
return [null, { name: fullName, value: detectedType === 'secret' ? SECRET_MASK : value, type: detectedType, isPublic, description }];
|
|
46
67
|
} catch(error){
|
|
47
68
|
return [{ code: 500, msg: 'Failed to save setting' }, null];
|
|
48
69
|
}
|