@objectstack/core 7.9.0 → 8.0.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/dist/index.cjs +119 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +54 -1
- package/dist/index.d.ts +54 -1
- package/dist/index.js +112 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
API_KEY_PREFIX: () => API_KEY_PREFIX,
|
|
33
34
|
ApiRegistry: () => ApiRegistry,
|
|
34
35
|
CORE_FALLBACK_FACTORIES: () => CORE_FALLBACK_FACTORIES,
|
|
35
36
|
DependencyResolver: () => DependencyResolver,
|
|
@@ -63,11 +64,17 @@ __export(index_exports, {
|
|
|
63
64
|
createMemoryQueue: () => createMemoryQueue,
|
|
64
65
|
createPluginConfigValidator: () => createPluginConfigValidator,
|
|
65
66
|
createPluginPermissionEnforcer: () => createPluginPermissionEnforcer,
|
|
67
|
+
extractApiKey: () => extractApiKey,
|
|
68
|
+
generateApiKey: () => generateApiKey,
|
|
66
69
|
generateEd25519KeyPair: () => generateEd25519KeyPair,
|
|
67
70
|
getEnv: () => getEnv,
|
|
68
71
|
getMemoryUsage: () => getMemoryUsage,
|
|
72
|
+
hashApiKey: () => hashApiKey,
|
|
73
|
+
isExpired: () => isExpired,
|
|
69
74
|
isNode: () => isNode,
|
|
75
|
+
parseScopes: () => parseScopes,
|
|
70
76
|
parseSignature: () => parseSignature,
|
|
77
|
+
resolveApiKeyPrincipal: () => resolveApiKeyPrincipal,
|
|
71
78
|
resolveLocale: () => resolveLocale,
|
|
72
79
|
safeExit: () => safeExit,
|
|
73
80
|
signPayload: () => signPayload,
|
|
@@ -3946,6 +3953,109 @@ var PluginSecurityScanner = class {
|
|
|
3946
3953
|
}
|
|
3947
3954
|
};
|
|
3948
3955
|
|
|
3956
|
+
// src/security/api-key.ts
|
|
3957
|
+
var import_node_crypto2 = require("crypto");
|
|
3958
|
+
var API_KEY_PREFIX = "osk_";
|
|
3959
|
+
var API_KEY_ENTROPY_BYTES = 32;
|
|
3960
|
+
var VISIBLE_PREFIX_LEN = 12;
|
|
3961
|
+
function hashApiKey(raw) {
|
|
3962
|
+
return (0, import_node_crypto2.createHash)("sha256").update(raw, "utf8").digest("hex");
|
|
3963
|
+
}
|
|
3964
|
+
function generateApiKey(prefix = API_KEY_PREFIX) {
|
|
3965
|
+
const secret = (0, import_node_crypto2.randomBytes)(API_KEY_ENTROPY_BYTES).toString("base64url");
|
|
3966
|
+
const raw = `${prefix}${secret}`;
|
|
3967
|
+
return {
|
|
3968
|
+
raw,
|
|
3969
|
+
hash: hashApiKey(raw),
|
|
3970
|
+
prefix: raw.slice(0, VISIBLE_PREFIX_LEN)
|
|
3971
|
+
};
|
|
3972
|
+
}
|
|
3973
|
+
function extractApiKey(headers) {
|
|
3974
|
+
const x = readHeader(headers, "x-api-key");
|
|
3975
|
+
if (x && x.trim()) return x.trim();
|
|
3976
|
+
const auth = readHeader(headers, "authorization");
|
|
3977
|
+
if (!auth) return void 0;
|
|
3978
|
+
const m = auth.match(/^ApiKey\s+(.+)$/i);
|
|
3979
|
+
const token = m?.[1]?.trim();
|
|
3980
|
+
return token || void 0;
|
|
3981
|
+
}
|
|
3982
|
+
function parseScopes(value) {
|
|
3983
|
+
if (Array.isArray(value)) {
|
|
3984
|
+
return value.filter((s) => typeof s === "string" && s.length > 0);
|
|
3985
|
+
}
|
|
3986
|
+
if (typeof value === "string" && value.trim()) {
|
|
3987
|
+
const parsed = safeJsonParse(value, []);
|
|
3988
|
+
if (Array.isArray(parsed)) {
|
|
3989
|
+
return parsed.filter((s) => typeof s === "string" && s.length > 0);
|
|
3990
|
+
}
|
|
3991
|
+
}
|
|
3992
|
+
return [];
|
|
3993
|
+
}
|
|
3994
|
+
function isExpired(value, nowMs) {
|
|
3995
|
+
if (value == null) return false;
|
|
3996
|
+
let ms;
|
|
3997
|
+
if (typeof value === "number") {
|
|
3998
|
+
ms = value < 1e12 ? value * 1e3 : value;
|
|
3999
|
+
} else if (value instanceof Date) {
|
|
4000
|
+
ms = value.getTime();
|
|
4001
|
+
} else if (typeof value === "string") {
|
|
4002
|
+
ms = Date.parse(value);
|
|
4003
|
+
} else {
|
|
4004
|
+
return false;
|
|
4005
|
+
}
|
|
4006
|
+
if (Number.isNaN(ms)) return false;
|
|
4007
|
+
return ms <= nowMs;
|
|
4008
|
+
}
|
|
4009
|
+
async function resolveApiKeyPrincipal(ql, headers, nowMs = Date.now()) {
|
|
4010
|
+
const apiKey = extractApiKey(headers);
|
|
4011
|
+
if (!apiKey) return void 0;
|
|
4012
|
+
if (!ql || typeof ql.find !== "function") return void 0;
|
|
4013
|
+
let rows;
|
|
4014
|
+
try {
|
|
4015
|
+
rows = await ql.find("sys_api_key", {
|
|
4016
|
+
where: { key: hashApiKey(apiKey), revoked: false },
|
|
4017
|
+
limit: 1,
|
|
4018
|
+
context: { isSystem: true }
|
|
4019
|
+
});
|
|
4020
|
+
} catch {
|
|
4021
|
+
return void 0;
|
|
4022
|
+
}
|
|
4023
|
+
if (rows && rows.value) rows = rows.value;
|
|
4024
|
+
const row = Array.isArray(rows) ? rows[0] : void 0;
|
|
4025
|
+
if (!row || row.revoked === true) return void 0;
|
|
4026
|
+
const expiresAt = row.expires_at ?? row.expiresAt;
|
|
4027
|
+
if (isExpired(expiresAt, nowMs)) return void 0;
|
|
4028
|
+
const userId = row.user_id ?? row.userId;
|
|
4029
|
+
if (!userId || typeof userId !== "string") return void 0;
|
|
4030
|
+
return {
|
|
4031
|
+
userId,
|
|
4032
|
+
tenantId: row.organization_id ?? row.organizationId ?? void 0,
|
|
4033
|
+
scopes: parseScopes(row.scopes)
|
|
4034
|
+
};
|
|
4035
|
+
}
|
|
4036
|
+
function readHeader(headers, name) {
|
|
4037
|
+
if (!headers) return void 0;
|
|
4038
|
+
const lower = name.toLowerCase();
|
|
4039
|
+
if (typeof headers.get === "function") {
|
|
4040
|
+
const v = headers.get(name) ?? headers.get(lower);
|
|
4041
|
+
return v == null ? void 0 : String(v);
|
|
4042
|
+
}
|
|
4043
|
+
for (const key of Object.keys(headers)) {
|
|
4044
|
+
if (key.toLowerCase() === lower) {
|
|
4045
|
+
const v = headers[key];
|
|
4046
|
+
return Array.isArray(v) ? v[0] : v == null ? void 0 : String(v);
|
|
4047
|
+
}
|
|
4048
|
+
}
|
|
4049
|
+
return void 0;
|
|
4050
|
+
}
|
|
4051
|
+
function safeJsonParse(s, fallback) {
|
|
4052
|
+
try {
|
|
4053
|
+
return JSON.parse(s);
|
|
4054
|
+
} catch {
|
|
4055
|
+
return fallback;
|
|
4056
|
+
}
|
|
4057
|
+
}
|
|
4058
|
+
|
|
3949
4059
|
// src/health-monitor.ts
|
|
3950
4060
|
var PluginHealthMonitor = class {
|
|
3951
4061
|
constructor(logger) {
|
|
@@ -4189,7 +4299,7 @@ var PluginHealthMonitor = class {
|
|
|
4189
4299
|
};
|
|
4190
4300
|
|
|
4191
4301
|
// src/hot-reload.ts
|
|
4192
|
-
var
|
|
4302
|
+
var import_node_crypto3 = require("crypto");
|
|
4193
4303
|
var generateUUID = () => {
|
|
4194
4304
|
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
4195
4305
|
return crypto.randomUUID();
|
|
@@ -4284,7 +4394,7 @@ var PluginStateManager = class {
|
|
|
4284
4394
|
*/
|
|
4285
4395
|
calculateChecksum(state) {
|
|
4286
4396
|
const stateStr = JSON.stringify(state);
|
|
4287
|
-
return (0,
|
|
4397
|
+
return (0, import_node_crypto3.createHash)("sha256").update(stateStr).digest("hex");
|
|
4288
4398
|
}
|
|
4289
4399
|
/**
|
|
4290
4400
|
* Shutdown state manager
|
|
@@ -4861,6 +4971,7 @@ var NamespaceResolver = class {
|
|
|
4861
4971
|
};
|
|
4862
4972
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4863
4973
|
0 && (module.exports = {
|
|
4974
|
+
API_KEY_PREFIX,
|
|
4864
4975
|
ApiRegistry,
|
|
4865
4976
|
CORE_FALLBACK_FACTORIES,
|
|
4866
4977
|
DependencyResolver,
|
|
@@ -4894,11 +5005,17 @@ var NamespaceResolver = class {
|
|
|
4894
5005
|
createMemoryQueue,
|
|
4895
5006
|
createPluginConfigValidator,
|
|
4896
5007
|
createPluginPermissionEnforcer,
|
|
5008
|
+
extractApiKey,
|
|
5009
|
+
generateApiKey,
|
|
4897
5010
|
generateEd25519KeyPair,
|
|
4898
5011
|
getEnv,
|
|
4899
5012
|
getMemoryUsage,
|
|
5013
|
+
hashApiKey,
|
|
5014
|
+
isExpired,
|
|
4900
5015
|
isNode,
|
|
5016
|
+
parseScopes,
|
|
4901
5017
|
parseSignature,
|
|
5018
|
+
resolveApiKeyPrincipal,
|
|
4902
5019
|
resolveLocale,
|
|
4903
5020
|
safeExit,
|
|
4904
5021
|
signPayload,
|