@devorash/node 0.1.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/LICENSE +21 -0
- package/README.md +279 -0
- package/dist/browser-session.d.ts +40 -0
- package/dist/browser-session.d.ts.map +1 -0
- package/dist/browser-session.js +48 -0
- package/dist/browser-session.js.map +1 -0
- package/dist/handler.d.ts +53 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +226 -0
- package/dist/handler.js.map +1 -0
- package/dist/hmac.d.ts +27 -0
- package/dist/hmac.d.ts.map +1 -0
- package/dist/hmac.js +53 -0
- package/dist/hmac.js.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +66 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware.d.ts +219 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +374 -0
- package/dist/middleware.js.map +1 -0
- package/dist/replay-store.d.ts +21 -0
- package/dist/replay-store.d.ts.map +1 -0
- package/dist/replay-store.js +18 -0
- package/dist/replay-store.js.map +1 -0
- package/dist/scope-config.d.ts +66 -0
- package/dist/scope-config.d.ts.map +1 -0
- package/dist/scope-config.js +199 -0
- package/dist/scope-config.js.map +1 -0
- package/dist/sdk.d.ts +11 -0
- package/dist/sdk.d.ts.map +1 -0
- package/dist/sdk.js +416 -0
- package/dist/sdk.js.map +1 -0
- package/dist/transport.d.ts +19 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +77 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +191 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scope configuration fetching and caching for backend SDK
|
|
3
|
+
*
|
|
4
|
+
* Fetches centrally managed whitelist and blacklist configuration from the Devora platform
|
|
5
|
+
* and caches it with automatic refresh.
|
|
6
|
+
*
|
|
7
|
+
* @module @devorash/node
|
|
8
|
+
*/
|
|
9
|
+
import { SDK_DEFAULTS, createLogger } from "@devorash/core";
|
|
10
|
+
import { controlPlaneFetch, readBoundedJsonObject } from "./transport.js";
|
|
11
|
+
/** Largest accepted policy: entries per list, and the longest pattern. */
|
|
12
|
+
const MAX_POLICY_ENTRIES = 1000;
|
|
13
|
+
const MAX_PATTERN_LENGTH = 500;
|
|
14
|
+
/** A server-sent cache horizon is never trusted beyond this. */
|
|
15
|
+
const MAX_POLICY_TTL_MS = 60 * 60 * 1000;
|
|
16
|
+
function readEndpoints(value) {
|
|
17
|
+
if (!Array.isArray(value) || value.length > MAX_POLICY_ENTRIES)
|
|
18
|
+
return null;
|
|
19
|
+
const endpoints = [];
|
|
20
|
+
for (const entry of value) {
|
|
21
|
+
const method = entry?.method;
|
|
22
|
+
const pattern = entry?.pattern;
|
|
23
|
+
if (typeof method !== "string" ||
|
|
24
|
+
!/^(\*|[A-Z]{3,7})(?![\s\S])/.test(method) ||
|
|
25
|
+
typeof pattern !== "string" ||
|
|
26
|
+
!pattern ||
|
|
27
|
+
pattern.length > MAX_PATTERN_LENGTH)
|
|
28
|
+
return null;
|
|
29
|
+
endpoints.push({ method, pattern });
|
|
30
|
+
}
|
|
31
|
+
return endpoints;
|
|
32
|
+
}
|
|
33
|
+
/** Validate a policy response; `null` when any part is malformed (fail closed). */
|
|
34
|
+
function readPolicy(data, now) {
|
|
35
|
+
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
36
|
+
return null;
|
|
37
|
+
const source = data;
|
|
38
|
+
const safeReadEndpoints = readEndpoints(source.safeReadEndpoints);
|
|
39
|
+
const blockedEndpoints = readEndpoints(source.blockedEndpoints);
|
|
40
|
+
const version = source.version;
|
|
41
|
+
const requested = source.cachedUntil;
|
|
42
|
+
// Missing policy fields must not become an empty deny list. The server
|
|
43
|
+
// always sends all four fields, including an explicit version zero.
|
|
44
|
+
if (!safeReadEndpoints ||
|
|
45
|
+
!blockedEndpoints ||
|
|
46
|
+
typeof version !== "number" ||
|
|
47
|
+
!Number.isSafeInteger(version) ||
|
|
48
|
+
version < 0 ||
|
|
49
|
+
typeof requested !== "number" ||
|
|
50
|
+
!Number.isSafeInteger(requested) ||
|
|
51
|
+
requested <= 0)
|
|
52
|
+
return null;
|
|
53
|
+
return {
|
|
54
|
+
safeReadEndpoints,
|
|
55
|
+
blockedEndpoints,
|
|
56
|
+
version: version,
|
|
57
|
+
cachedUntil: Math.min(Math.max(requested, now), now + MAX_POLICY_TTL_MS),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** How long a cached policy may be served past its window during an outage. */
|
|
61
|
+
export const STALE_GRACE_MS = 5 * 60 * 1000;
|
|
62
|
+
const DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
63
|
+
/**
|
|
64
|
+
* Create a scope config fetcher
|
|
65
|
+
*
|
|
66
|
+
* Handles fetching scope configuration from Devora API with caching
|
|
67
|
+
* and automatic background refresh.
|
|
68
|
+
*/
|
|
69
|
+
export function createScopeConfigFetcher(options) {
|
|
70
|
+
const { signRequest, apiUrl = SDK_DEFAULTS.API_URL, debug = false, cacheTtlMs = DEFAULT_CACHE_TTL_MS, } = options;
|
|
71
|
+
if (!Number.isSafeInteger(cacheTtlMs) || cacheTtlMs <= 0 || cacheTtlMs > MAX_POLICY_TTL_MS)
|
|
72
|
+
throw new Error("Devora SDK: cacheTtlMs must be an integer between 1 and 3600000");
|
|
73
|
+
const logger = createLogger("Devora ScopeConfig", debug);
|
|
74
|
+
let cachedConfig = null;
|
|
75
|
+
let refreshTimer = null;
|
|
76
|
+
let pendingFetch = null;
|
|
77
|
+
let etag = null;
|
|
78
|
+
let staleUntil = 0;
|
|
79
|
+
/**
|
|
80
|
+
* Fetch scope config from Devora API
|
|
81
|
+
*/
|
|
82
|
+
async function fetchConfig() {
|
|
83
|
+
if (pendingFetch)
|
|
84
|
+
return pendingFetch;
|
|
85
|
+
pendingFetch = (async () => {
|
|
86
|
+
try {
|
|
87
|
+
const response = await controlPlaneFetch(`${apiUrl}/api/sdk/scope-config`, {
|
|
88
|
+
method: "GET",
|
|
89
|
+
headers: {
|
|
90
|
+
...signRequest(),
|
|
91
|
+
...(etag ? { "If-None-Match": etag } : {}),
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
if (response.status === 304 && cachedConfig) {
|
|
95
|
+
// A 304 re-validates the whole server window. Using a shorter TTL
|
|
96
|
+
// here would multiply request volume against the per-key rate limit.
|
|
97
|
+
const cachedUntil = Date.now() + cacheTtlMs;
|
|
98
|
+
cachedConfig = { ...cachedConfig, cachedUntil };
|
|
99
|
+
staleUntil = cachedUntil + STALE_GRACE_MS;
|
|
100
|
+
return cachedConfig;
|
|
101
|
+
}
|
|
102
|
+
if (!response.ok) {
|
|
103
|
+
logger.warn("Failed to fetch scope config:", response.status);
|
|
104
|
+
return cachedConfig && Date.now() < staleUntil ? cachedConfig : null;
|
|
105
|
+
}
|
|
106
|
+
const result = await readBoundedJsonObject(response);
|
|
107
|
+
const config = result.success === true ? readPolicy(result.data, Date.now()) : null;
|
|
108
|
+
if (!config) {
|
|
109
|
+
logger.warn("Invalid scope config response");
|
|
110
|
+
return cachedConfig && Date.now() < staleUntil ? cachedConfig : null;
|
|
111
|
+
}
|
|
112
|
+
const previousVersion = cachedConfig?.version;
|
|
113
|
+
etag = response.headers.get("etag");
|
|
114
|
+
cachedConfig = config;
|
|
115
|
+
staleUntil = config.cachedUntil + STALE_GRACE_MS;
|
|
116
|
+
if (previousVersion === undefined || config.version !== previousVersion) {
|
|
117
|
+
logger.log("Scope config updated", {
|
|
118
|
+
version: config.version,
|
|
119
|
+
whitelist: config.safeReadEndpoints.length,
|
|
120
|
+
blacklist: config.blockedEndpoints.length,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return cachedConfig;
|
|
124
|
+
}
|
|
125
|
+
catch (e) {
|
|
126
|
+
logger.warn("Error fetching scope config:", e);
|
|
127
|
+
return cachedConfig && Date.now() < staleUntil ? cachedConfig : null;
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
pendingFetch = null;
|
|
131
|
+
}
|
|
132
|
+
})();
|
|
133
|
+
return pendingFetch;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Schedule background refresh
|
|
137
|
+
*/
|
|
138
|
+
function scheduleRefresh() {
|
|
139
|
+
if (refreshTimer) {
|
|
140
|
+
clearTimeout(refreshTimer);
|
|
141
|
+
}
|
|
142
|
+
// Refresh 30s before expiry. The floor must stay below the window or the
|
|
143
|
+
// timer can never keep the cache warm and requests pay a synchronous fetch.
|
|
144
|
+
const refreshIn = cachedConfig?.cachedUntil
|
|
145
|
+
? Math.max(cachedConfig.cachedUntil - Date.now() - 30_000, Math.min(cacheTtlMs / 2, 60_000))
|
|
146
|
+
: cacheTtlMs;
|
|
147
|
+
refreshTimer = setTimeout(async () => {
|
|
148
|
+
await fetchConfig();
|
|
149
|
+
scheduleRefresh();
|
|
150
|
+
}, refreshIn);
|
|
151
|
+
// Don't let the background refresh loop keep a process (script, test, serverless
|
|
152
|
+
// invocation) alive on its own.
|
|
153
|
+
refreshTimer.unref?.();
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Get config (fetch if not cached or expired)
|
|
157
|
+
*/
|
|
158
|
+
async function getConfig() {
|
|
159
|
+
// Return cached if still valid
|
|
160
|
+
if (cachedConfig && Date.now() < cachedConfig.cachedUntil) {
|
|
161
|
+
return cachedConfig;
|
|
162
|
+
}
|
|
163
|
+
// Fetch fresh config
|
|
164
|
+
const config = await fetchConfig();
|
|
165
|
+
// Schedule background refresh
|
|
166
|
+
if (config && !refreshTimer) {
|
|
167
|
+
scheduleRefresh();
|
|
168
|
+
}
|
|
169
|
+
return config;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get cached config without fetching
|
|
173
|
+
*/
|
|
174
|
+
function getCachedConfig() {
|
|
175
|
+
return cachedConfig;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Force refresh config
|
|
179
|
+
*/
|
|
180
|
+
async function refresh() {
|
|
181
|
+
return fetchConfig();
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Stop background refresh
|
|
185
|
+
*/
|
|
186
|
+
function stop() {
|
|
187
|
+
if (refreshTimer) {
|
|
188
|
+
clearTimeout(refreshTimer);
|
|
189
|
+
refreshTimer = null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
getConfig,
|
|
194
|
+
getCachedConfig,
|
|
195
|
+
refresh,
|
|
196
|
+
stop,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=scope-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope-config.js","sourceRoot":"","sources":["../src/scope-config.ts"],"names":[],"mappings":"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"}
|
package/dist/sdk.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { DevoraBackendSDK, NodeBackendSDKConfig, DevoraEnvironment } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Create a Devora Backend SDK instance
|
|
4
|
+
*
|
|
5
|
+
* Security: The SDK authenticates requests using HMAC-SHA256 signatures.
|
|
6
|
+
* The secret key is unique per organization, so valid HMAC = authenticated request.
|
|
7
|
+
*/
|
|
8
|
+
/** Explicit option first, then DEVORA_ENV / NODE_ENV as hints, else production. */
|
|
9
|
+
export declare function resolveEnvironment(explicit?: DevoraEnvironment): DevoraEnvironment;
|
|
10
|
+
export declare function devoraSDK(config: NodeBackendSDKConfig): DevoraBackendSDK;
|
|
11
|
+
//# sourceMappingURL=sdk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../src/sdk.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EACX,gBAAgB,EAEhB,oBAAoB,EAMpB,iBAAiB,EACjB,MAAM,YAAY,CAAA;AA4CnB;;;;;GAKG;AACH,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,iBAAiB,GAAG,iBAAiB,CAKlF;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,oBAAoB,GAAG,gBAAgB,CA8ZxE"}
|
package/dist/sdk.js
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main Devora Backend SDK implementation
|
|
3
|
+
* @module @devorash/node
|
|
4
|
+
*/
|
|
5
|
+
import { DEVORA_ENDPOINTS, ENDPOINT_METHODS, PROTECTED_ENDPOINTS, SDK_DEFAULTS, SDK_PACKAGES, SDK_VERSION, validateTimestamp, SIGNING, SIGNED_HEADER_PATTERNS, buildCanonicalString, hasIdentityContentEncoding, isValidSignedPath, isValidSignedQuery, parseSignatureHeaders, replayExpiresAtMs, replayNamespace, assertTimestampTolerance, isValidTimestampTolerance, createSDKInfo, createLogger, BROWSER_SESSION_BRIDGE, } from "@devorash/core";
|
|
6
|
+
import { sha256Hex, signatureMatches, signRequest } from "./hmac.js";
|
|
7
|
+
import { controlPlaneFetch, readBoundedJsonObject } from "./transport.js";
|
|
8
|
+
import { createScopeConfigFetcher } from "./scope-config.js";
|
|
9
|
+
import { InMemoryReplayStore } from "./replay-store.js";
|
|
10
|
+
/**
|
|
11
|
+
* Validate secret key format
|
|
12
|
+
* Expected format: sk_server_live_xxx
|
|
13
|
+
*/
|
|
14
|
+
function validateSecretKeyFormat(secretKey) {
|
|
15
|
+
return SIGNED_HEADER_PATTERNS.secretKey.test(secretKey)
|
|
16
|
+
? { valid: true }
|
|
17
|
+
: {
|
|
18
|
+
valid: false,
|
|
19
|
+
error: "Invalid secret key format. Expected sk_server_live_ followed by 64 characters",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Resolve and validate the Devora API origin.
|
|
24
|
+
* Only https origins are accepted (http for localhost/127.0.0.1 development).
|
|
25
|
+
*/
|
|
26
|
+
function resolveApiUrl(override) {
|
|
27
|
+
if (!override)
|
|
28
|
+
return SDK_DEFAULTS.API_URL;
|
|
29
|
+
let parsed;
|
|
30
|
+
try {
|
|
31
|
+
parsed = new URL(override);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
throw new Error(`Devora SDK: apiUrl is not a valid URL: ${override}`);
|
|
35
|
+
}
|
|
36
|
+
const isLocalhost = parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
|
|
37
|
+
if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && isLocalhost)) {
|
|
38
|
+
throw new Error("Devora SDK: apiUrl must use https (http is allowed for localhost only)");
|
|
39
|
+
}
|
|
40
|
+
if (parsed.username ||
|
|
41
|
+
parsed.password ||
|
|
42
|
+
(parsed.pathname && parsed.pathname !== "/") ||
|
|
43
|
+
parsed.search ||
|
|
44
|
+
parsed.hash) {
|
|
45
|
+
throw new Error("Devora SDK: apiUrl must be an origin without path, query, or credentials");
|
|
46
|
+
}
|
|
47
|
+
return parsed.origin;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create a Devora Backend SDK instance
|
|
51
|
+
*
|
|
52
|
+
* Security: The SDK authenticates requests using HMAC-SHA256 signatures.
|
|
53
|
+
* The secret key is unique per organization, so valid HMAC = authenticated request.
|
|
54
|
+
*/
|
|
55
|
+
/** Explicit option first, then DEVORA_ENV / NODE_ENV as hints, else production. */
|
|
56
|
+
export function resolveEnvironment(explicit) {
|
|
57
|
+
const raw = (explicit ?? process.env.DEVORA_ENV ?? process.env.NODE_ENV ?? "production")
|
|
58
|
+
.toString()
|
|
59
|
+
.toLowerCase();
|
|
60
|
+
return raw === "development" || raw === "test" ? raw : "production";
|
|
61
|
+
}
|
|
62
|
+
export function devoraSDK(config) {
|
|
63
|
+
// Runtime allowlist: unknown capture/preferences are ignored in JavaScript too.
|
|
64
|
+
config = {
|
|
65
|
+
apiKey: config.apiKey,
|
|
66
|
+
secretKey: config.secretKey,
|
|
67
|
+
orgId: config.orgId,
|
|
68
|
+
apiUrl: config.apiUrl,
|
|
69
|
+
debug: config.debug,
|
|
70
|
+
timestampTolerance: config.timestampTolerance,
|
|
71
|
+
logRequests: config.logRequests,
|
|
72
|
+
logger: config.logger,
|
|
73
|
+
collectStats: config.collectStats,
|
|
74
|
+
replayStore: config.replayStore,
|
|
75
|
+
environment: config.environment,
|
|
76
|
+
};
|
|
77
|
+
// Validate configuration
|
|
78
|
+
if (!config.secretKey) {
|
|
79
|
+
throw new Error("Devora SDK: secretKey is required");
|
|
80
|
+
}
|
|
81
|
+
if (!SIGNED_HEADER_PATTERNS.keyId.test(config.apiKey ?? "")) {
|
|
82
|
+
throw new Error("Devora SDK: apiKey must be a server key identifier (pk_server_live_*)");
|
|
83
|
+
}
|
|
84
|
+
if (!config.orgId?.trim()) {
|
|
85
|
+
throw new Error("Devora SDK: orgId is required");
|
|
86
|
+
}
|
|
87
|
+
assertTimestampTolerance(config.timestampTolerance);
|
|
88
|
+
const apiUrl = resolveApiUrl(config.apiUrl);
|
|
89
|
+
// Fail closed: anything that is not explicitly a development/test runtime is
|
|
90
|
+
// production, and production must share replay protection across instances.
|
|
91
|
+
const environment = resolveEnvironment(config.environment);
|
|
92
|
+
if (environment === "production" && !config.replayStore)
|
|
93
|
+
throw new Error('Devora SDK: replayStore is required in production. Pass a persistent ReplayStore, or set environment: "development" (InMemoryReplayStore) for local development only.');
|
|
94
|
+
const replayStore = config.replayStore ?? new InMemoryReplayStore();
|
|
95
|
+
// Validate secret key format (security check)
|
|
96
|
+
const secretKeyValidation = validateSecretKeyFormat(config.secretKey);
|
|
97
|
+
if (!secretKeyValidation.valid) {
|
|
98
|
+
throw new Error(`Devora SDK: ${secretKeyValidation.error}`);
|
|
99
|
+
}
|
|
100
|
+
// Initialize logger - uses global config by default, can be overridden with debug option
|
|
101
|
+
const logger = createLogger("Devora SDK", config.debug);
|
|
102
|
+
// SDK info
|
|
103
|
+
const info = createSDKInfo(SDK_PACKAGES.NODE, "backend", "node");
|
|
104
|
+
// Statistics
|
|
105
|
+
const stats = {
|
|
106
|
+
totalRequests: 0,
|
|
107
|
+
successfulRequests: 0,
|
|
108
|
+
failedRequests: 0,
|
|
109
|
+
securityErrors: 0,
|
|
110
|
+
requestsByEndpoint: {},
|
|
111
|
+
};
|
|
112
|
+
// Registered routes
|
|
113
|
+
const routes = [];
|
|
114
|
+
const scopeConfig = createScopeConfigFetcher({
|
|
115
|
+
apiKey: config.apiKey,
|
|
116
|
+
signRequest: () => signRequest({
|
|
117
|
+
secretKey: config.secretKey,
|
|
118
|
+
direction: SIGNING.CUSTOMER_TO_DEVORA,
|
|
119
|
+
keyId: config.apiKey,
|
|
120
|
+
orgId: config.orgId,
|
|
121
|
+
method: "GET",
|
|
122
|
+
path: "/api/sdk/scope-config",
|
|
123
|
+
}),
|
|
124
|
+
apiUrl,
|
|
125
|
+
debug: config.debug,
|
|
126
|
+
});
|
|
127
|
+
const ready = scopeConfig.getConfig().then((policy) => {
|
|
128
|
+
if (!policy) {
|
|
129
|
+
logger.warn("Scope policy could not be loaded; getScopeConfig() may return null until refresh succeeds");
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
// Register built-in routes
|
|
133
|
+
registerBuiltInRoutes();
|
|
134
|
+
/**
|
|
135
|
+
* Register built-in /test and /health endpoints
|
|
136
|
+
*/
|
|
137
|
+
function registerBuiltInRoutes() {
|
|
138
|
+
// Test endpoint
|
|
139
|
+
routes.push({
|
|
140
|
+
path: DEVORA_ENDPOINTS.TEST,
|
|
141
|
+
method: "GET",
|
|
142
|
+
isBuiltIn: true,
|
|
143
|
+
handler: async (req) => {
|
|
144
|
+
logger.log("Test endpoint called", { orgId: req.orgId, keyId: req.keyId });
|
|
145
|
+
return {
|
|
146
|
+
status: "success",
|
|
147
|
+
message: "Devora SDK connection test successful",
|
|
148
|
+
timestamp: Date.now(),
|
|
149
|
+
orgId: req.orgId,
|
|
150
|
+
keyId: req.keyId,
|
|
151
|
+
sdk: info,
|
|
152
|
+
security: {
|
|
153
|
+
hmacValidated: true,
|
|
154
|
+
timestampValid: true,
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
// Health endpoint
|
|
160
|
+
routes.push({
|
|
161
|
+
path: DEVORA_ENDPOINTS.HEALTH,
|
|
162
|
+
method: "GET",
|
|
163
|
+
isBuiltIn: true,
|
|
164
|
+
handler: async () => {
|
|
165
|
+
const endpointMap = {};
|
|
166
|
+
for (const route of routes) {
|
|
167
|
+
endpointMap[route.path] = route.method;
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
status: "healthy",
|
|
171
|
+
sdk: info,
|
|
172
|
+
stats: config.collectStats ? { ...stats } : undefined,
|
|
173
|
+
endpoints: endpointMap,
|
|
174
|
+
};
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Register a new endpoint handler
|
|
180
|
+
*/
|
|
181
|
+
function register(path, handler, options) {
|
|
182
|
+
// Check if path is a predefined endpoint
|
|
183
|
+
const isPredefined = Object.values(DEVORA_ENDPOINTS).includes(path);
|
|
184
|
+
// Check if it's a protected endpoint
|
|
185
|
+
if (PROTECTED_ENDPOINTS.includes(path)) {
|
|
186
|
+
throw new Error(`Cannot override protected endpoint: ${path}. This endpoint is built into the SDK.`);
|
|
187
|
+
}
|
|
188
|
+
// Auto-detect method if using predefined endpoints
|
|
189
|
+
let method = options?.method ?? "GET";
|
|
190
|
+
if (isPredefined) {
|
|
191
|
+
method = ENDPOINT_METHODS[path];
|
|
192
|
+
logger.log(`Using predefined endpoint: ${path}`, { method });
|
|
193
|
+
}
|
|
194
|
+
else if (config.debug) {
|
|
195
|
+
logger.warn(`Using custom endpoint path: ${path}. Consider using DEVORA_ENDPOINTS constants for consistency.`);
|
|
196
|
+
}
|
|
197
|
+
// Check for duplicates (including built-in routes not caught by PROTECTED_ENDPOINTS)
|
|
198
|
+
const existingRoute = routes.find((r) => r.path === path);
|
|
199
|
+
if (existingRoute) {
|
|
200
|
+
const routeType = existingRoute.isBuiltIn ? "built-in" : "custom";
|
|
201
|
+
throw new Error(`Endpoint already registered: ${path} (existing route is ${routeType})`);
|
|
202
|
+
}
|
|
203
|
+
const route = {
|
|
204
|
+
path,
|
|
205
|
+
method,
|
|
206
|
+
handler,
|
|
207
|
+
isBuiltIn: false,
|
|
208
|
+
};
|
|
209
|
+
routes.push(route);
|
|
210
|
+
logger.log(`Registered endpoint: ${method} ${path}`, {
|
|
211
|
+
predefined: isPredefined,
|
|
212
|
+
});
|
|
213
|
+
return route;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Get all registered routes
|
|
217
|
+
*/
|
|
218
|
+
function getRoutes() {
|
|
219
|
+
return [...routes];
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Get statistics
|
|
223
|
+
*/
|
|
224
|
+
function getStats() {
|
|
225
|
+
return {
|
|
226
|
+
...stats,
|
|
227
|
+
requestsByEndpoint: { ...stats.requestsByEndpoint },
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Record a processed request for statistics.
|
|
232
|
+
*/
|
|
233
|
+
function recordRequest(endpoint, outcome) {
|
|
234
|
+
stats.totalRequests++;
|
|
235
|
+
if (config.collectStats) {
|
|
236
|
+
stats.requestsByEndpoint[endpoint] = (stats.requestsByEndpoint[endpoint] ?? 0) + 1;
|
|
237
|
+
}
|
|
238
|
+
if (outcome === "success") {
|
|
239
|
+
stats.successfulRequests++;
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
stats.failedRequests++;
|
|
243
|
+
if (outcome === "security_error") {
|
|
244
|
+
stats.securityErrors++;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Verify a signed request from Devora (signature v3) over its exact bytes.
|
|
249
|
+
* Steps before the replay store never touch it, so unauthenticated traffic
|
|
250
|
+
* cannot burn request ids.
|
|
251
|
+
*/
|
|
252
|
+
async function verifyRequest(request, options = {}) {
|
|
253
|
+
const tolerance = options.timestampTolerance ?? config.timestampTolerance ?? SDK_DEFAULTS.TIMESTAMP_TOLERANCE;
|
|
254
|
+
if (!isValidTimestampTolerance(tolerance))
|
|
255
|
+
return { valid: false, error: "Invalid timestamp tolerance", errorCode: "TIMESTAMP_EXPIRED" };
|
|
256
|
+
const parsed = parseSignatureHeaders(request.headers);
|
|
257
|
+
if (!parsed.valid)
|
|
258
|
+
return { valid: false, error: parsed.error, errorCode: parsed.errorCode };
|
|
259
|
+
const headers = parsed.headers;
|
|
260
|
+
if (headers.keyId !== config.apiKey || headers.orgId !== config.orgId)
|
|
261
|
+
return {
|
|
262
|
+
valid: false,
|
|
263
|
+
error: "Request key or organization does not match SDK configuration",
|
|
264
|
+
errorCode: "ORG_MISMATCH",
|
|
265
|
+
};
|
|
266
|
+
const sentAt = Number(headers.sentAt);
|
|
267
|
+
const timestamp = validateTimestamp(sentAt, tolerance);
|
|
268
|
+
if (!timestamp.valid)
|
|
269
|
+
return { valid: false, error: timestamp.error, errorCode: "TIMESTAMP_EXPIRED" };
|
|
270
|
+
if (!SIGNED_HEADER_PATTERNS.method.test(request.method) ||
|
|
271
|
+
!isValidSignedPath(request.path) ||
|
|
272
|
+
!isValidSignedQuery(request.query))
|
|
273
|
+
return { valid: false, error: "Invalid request target", errorCode: "INVALID_REQUEST_TARGET" };
|
|
274
|
+
if (!hasIdentityContentEncoding(request.headers))
|
|
275
|
+
return {
|
|
276
|
+
valid: false,
|
|
277
|
+
error: "Content-Encoding is not supported",
|
|
278
|
+
errorCode: "UNSUPPORTED_CONTENT_ENCODING",
|
|
279
|
+
};
|
|
280
|
+
const canonical = buildCanonicalString({
|
|
281
|
+
direction: SIGNING.DEVORA_TO_CUSTOMER,
|
|
282
|
+
keyId: headers.keyId,
|
|
283
|
+
orgId: headers.orgId,
|
|
284
|
+
sentAt: headers.sentAt,
|
|
285
|
+
requestId: headers.requestId,
|
|
286
|
+
method: request.method,
|
|
287
|
+
path: request.path,
|
|
288
|
+
query: request.query,
|
|
289
|
+
bodySha256: sha256Hex(request.body),
|
|
290
|
+
});
|
|
291
|
+
if (!signatureMatches(config.secretKey, canonical, headers.signature))
|
|
292
|
+
return { valid: false, error: "Invalid HMAC signature", errorCode: "INVALID_SIGNATURE" };
|
|
293
|
+
let fresh;
|
|
294
|
+
try {
|
|
295
|
+
fresh = await replayStore.consume(replayNamespace(SIGNING.DEVORA_TO_CUSTOMER, headers.keyId), headers.requestId, replayExpiresAtMs(sentAt, Math.floor(Date.now() / 1000), tolerance));
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
return {
|
|
299
|
+
valid: false,
|
|
300
|
+
error: "Replay protection is unavailable",
|
|
301
|
+
errorCode: "REPLAY_STORE_UNAVAILABLE",
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
if (typeof fresh !== "boolean")
|
|
305
|
+
return {
|
|
306
|
+
valid: false,
|
|
307
|
+
error: "Replay store must return a boolean decision",
|
|
308
|
+
errorCode: "REPLAY_STORE_UNAVAILABLE",
|
|
309
|
+
};
|
|
310
|
+
if (!fresh)
|
|
311
|
+
return { valid: false, error: "Request was already processed", errorCode: "REPLAYED_REQUEST" };
|
|
312
|
+
return {
|
|
313
|
+
valid: true,
|
|
314
|
+
orgId: headers.orgId,
|
|
315
|
+
keyId: headers.keyId,
|
|
316
|
+
timestamp: sentAt,
|
|
317
|
+
requestId: headers.requestId,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
/** POST a signed JSON body to a Devora SDK endpoint and read a bounded JSON object reply. */
|
|
321
|
+
async function signedDevoraPost(path, payload) {
|
|
322
|
+
const body = new TextEncoder().encode(JSON.stringify(payload));
|
|
323
|
+
const response = await controlPlaneFetch(`${apiUrl}${path}`, {
|
|
324
|
+
method: "POST",
|
|
325
|
+
headers: signRequest({
|
|
326
|
+
secretKey: config.secretKey,
|
|
327
|
+
direction: SIGNING.CUSTOMER_TO_DEVORA,
|
|
328
|
+
keyId: config.apiKey,
|
|
329
|
+
orgId: config.orgId,
|
|
330
|
+
method: "POST",
|
|
331
|
+
path,
|
|
332
|
+
body,
|
|
333
|
+
}),
|
|
334
|
+
body,
|
|
335
|
+
});
|
|
336
|
+
const json = await readBoundedJsonObject(response).catch(() => null);
|
|
337
|
+
return { status: response.status, ok: response.ok, json };
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Check whether a Devora session is still live (server-side liveness check).
|
|
341
|
+
* Returns null if Devora is unreachable so callers can choose fail-open/closed.
|
|
342
|
+
*/
|
|
343
|
+
async function getSessionStatus(sessionId) {
|
|
344
|
+
if (!sessionId || sessionId.length > 128)
|
|
345
|
+
return null;
|
|
346
|
+
try {
|
|
347
|
+
const { status, ok, json } = await signedDevoraPost("/api/sdk/session-status", { sessionId });
|
|
348
|
+
if (status === 404)
|
|
349
|
+
return { valid: false, error: "SESSION_NOT_FOUND" };
|
|
350
|
+
// 429/5xx/other failures are "unavailable", never a liveness verdict.
|
|
351
|
+
if (!ok || !json || json.success !== true)
|
|
352
|
+
return null;
|
|
353
|
+
const data = json.data;
|
|
354
|
+
if (!data ||
|
|
355
|
+
typeof data !== "object" ||
|
|
356
|
+
typeof data.valid !== "boolean")
|
|
357
|
+
return null;
|
|
358
|
+
return data;
|
|
359
|
+
}
|
|
360
|
+
catch {
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Server-to-server: mint a one-time browser resume code (signed, customer-to-devora).
|
|
366
|
+
*/
|
|
367
|
+
async function createBrowserResumeCode(input) {
|
|
368
|
+
if (!input.sessionId || input.sessionId.length > 128)
|
|
369
|
+
return { error: "INVALID_SESSION" };
|
|
370
|
+
if (!BROWSER_SESSION_BRIDGE.TAB_REF_PATTERN.test(input.tabRef))
|
|
371
|
+
return { error: "INVALID_TAB_REF" };
|
|
372
|
+
try {
|
|
373
|
+
const { status, ok, json } = await signedDevoraPost(BROWSER_SESSION_BRIDGE.RESUME_CODE_ENDPOINT, {
|
|
374
|
+
sessionId: input.sessionId,
|
|
375
|
+
tabRef: input.tabRef,
|
|
376
|
+
origin: input.origin,
|
|
377
|
+
});
|
|
378
|
+
const data = json?.data;
|
|
379
|
+
if (ok && json?.success === true && typeof data?.code === "string")
|
|
380
|
+
return data;
|
|
381
|
+
if (status >= 500 || status === 429)
|
|
382
|
+
return null;
|
|
383
|
+
return {
|
|
384
|
+
error: typeof json?.error === "string" ? json.error : "RESUME_REJECTED",
|
|
385
|
+
status,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
catch {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
// Return SDK instance
|
|
393
|
+
const sdk = {
|
|
394
|
+
config: Object.freeze({ ...config, secretKey: "[REDACTED]" }),
|
|
395
|
+
info,
|
|
396
|
+
ready,
|
|
397
|
+
register,
|
|
398
|
+
getRoutes,
|
|
399
|
+
getStats,
|
|
400
|
+
getScopeConfig: scopeConfig.getConfig,
|
|
401
|
+
isPolicyLoaded: () => scopeConfig.getCachedConfig() !== null,
|
|
402
|
+
getCachedScopeConfig: scopeConfig.getCachedConfig,
|
|
403
|
+
refreshScopeConfig: scopeConfig.refresh,
|
|
404
|
+
getSessionStatus,
|
|
405
|
+
createBrowserResumeCode,
|
|
406
|
+
destroy: scopeConfig.stop,
|
|
407
|
+
_recordRequest: recordRequest,
|
|
408
|
+
verifyRequest,
|
|
409
|
+
};
|
|
410
|
+
logger.log("Devora SDK initialized", {
|
|
411
|
+
version: SDK_VERSION,
|
|
412
|
+
debug: config.debug,
|
|
413
|
+
});
|
|
414
|
+
return sdk;
|
|
415
|
+
}
|
|
416
|
+
//# sourceMappingURL=sdk.js.map
|
package/dist/sdk.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk.js","sourceRoot":"","sources":["../src/sdk.ts"],"names":[],"mappings":"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"}
|