@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 @@
|
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"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"}
|
package/dist/hmac.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request signing v3 primitives for Node.js (node:crypto).
|
|
3
|
+
* @module @devorash/node
|
|
4
|
+
*/
|
|
5
|
+
import { type SigningDirection } from "@devorash/core";
|
|
6
|
+
/** Lowercase hex SHA-256 of exact bytes. */
|
|
7
|
+
export declare function sha256Hex(bytes: Uint8Array): string;
|
|
8
|
+
/** Lowercase hex HMAC-SHA256 of a canonical string, keyed by the secret's ASCII bytes. */
|
|
9
|
+
export declare function hmacHex(secretKey: string, canonical: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Constant-time comparison of a provided signature with the expected one.
|
|
12
|
+
* The provided value must be exactly 64 lowercase hex characters; it is never
|
|
13
|
+
* decoded leniently.
|
|
14
|
+
*/
|
|
15
|
+
export declare function signatureMatches(secretKey: string, canonical: string, provided: string): boolean;
|
|
16
|
+
/** Headers for an outgoing signed request. */
|
|
17
|
+
export declare function signRequest(input: {
|
|
18
|
+
secretKey: string;
|
|
19
|
+
direction: SigningDirection;
|
|
20
|
+
keyId: string;
|
|
21
|
+
orgId: string;
|
|
22
|
+
method: string;
|
|
23
|
+
path: string;
|
|
24
|
+
query?: string;
|
|
25
|
+
body?: Uint8Array;
|
|
26
|
+
}): Record<string, string>;
|
|
27
|
+
//# sourceMappingURL=hmac.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hmac.d.ts","sourceRoot":"","sources":["../src/hmac.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAKN,KAAK,gBAAgB,EACrB,MAAM,gBAAgB,CAAA;AAEvB,4CAA4C;AAC5C,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEnD;AAED,0FAA0F;AAC1F,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAIpE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAMhG;AAED,8CAA8C;AAC9C,wBAAgB,WAAW,CAAC,KAAK,EAAE;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,gBAAgB,CAAA;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,UAAU,CAAA;CACjB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAwBzB"}
|
package/dist/hmac.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request signing v3 primitives for Node.js (node:crypto).
|
|
3
|
+
* @module @devorash/node
|
|
4
|
+
*/
|
|
5
|
+
import { createHash, createHmac, randomUUID, timingSafeEqual } from "crypto";
|
|
6
|
+
import { SECURITY_HEADERS, SIGNING, SIGNED_HEADER_PATTERNS, buildCanonicalString, } from "@devorash/core";
|
|
7
|
+
/** Lowercase hex SHA-256 of exact bytes. */
|
|
8
|
+
export function sha256Hex(bytes) {
|
|
9
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
10
|
+
}
|
|
11
|
+
/** Lowercase hex HMAC-SHA256 of a canonical string, keyed by the secret's ASCII bytes. */
|
|
12
|
+
export function hmacHex(secretKey, canonical) {
|
|
13
|
+
return createHmac("sha256", Buffer.from(secretKey, "ascii"))
|
|
14
|
+
.update(Buffer.from(canonical, "ascii"))
|
|
15
|
+
.digest("hex");
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Constant-time comparison of a provided signature with the expected one.
|
|
19
|
+
* The provided value must be exactly 64 lowercase hex characters; it is never
|
|
20
|
+
* decoded leniently.
|
|
21
|
+
*/
|
|
22
|
+
export function signatureMatches(secretKey, canonical, provided) {
|
|
23
|
+
if (!SIGNED_HEADER_PATTERNS.signature.test(provided))
|
|
24
|
+
return false;
|
|
25
|
+
return timingSafeEqual(Buffer.from(hmacHex(secretKey, canonical), "hex"), Buffer.from(provided, "hex"));
|
|
26
|
+
}
|
|
27
|
+
/** Headers for an outgoing signed request. */
|
|
28
|
+
export function signRequest(input) {
|
|
29
|
+
const body = input.body ?? new Uint8Array();
|
|
30
|
+
const sentAt = String(Math.floor(Date.now() / 1000));
|
|
31
|
+
const requestId = randomUUID();
|
|
32
|
+
const canonical = buildCanonicalString({
|
|
33
|
+
direction: input.direction,
|
|
34
|
+
keyId: input.keyId,
|
|
35
|
+
orgId: input.orgId,
|
|
36
|
+
sentAt,
|
|
37
|
+
requestId,
|
|
38
|
+
method: input.method,
|
|
39
|
+
path: input.path,
|
|
40
|
+
query: input.query ?? "",
|
|
41
|
+
bodySha256: sha256Hex(body),
|
|
42
|
+
});
|
|
43
|
+
return {
|
|
44
|
+
[SECURITY_HEADERS.SIGNATURE_VERSION]: SIGNING.VERSION,
|
|
45
|
+
[SECURITY_HEADERS.KEY_ID]: input.keyId,
|
|
46
|
+
[SECURITY_HEADERS.ORG_ID]: input.orgId,
|
|
47
|
+
[SECURITY_HEADERS.SENT_AT]: sentAt,
|
|
48
|
+
[SECURITY_HEADERS.REQUEST_ID]: requestId,
|
|
49
|
+
[SECURITY_HEADERS.SIGNATURE]: hmacHex(input.secretKey, canonical),
|
|
50
|
+
...(body.byteLength > 0 ? { "Content-Type": "application/json" } : {}),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=hmac.js.map
|
package/dist/hmac.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hmac.js","sourceRoot":"","sources":["../src/hmac.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAA;AAC5E,OAAO,EACN,gBAAgB,EAChB,OAAO,EACP,sBAAsB,EACtB,oBAAoB,GAEpB,MAAM,gBAAgB,CAAA;AAEvB,4CAA4C;AAC5C,MAAM,UAAU,SAAS,CAAC,KAAiB;IAC1C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AACxD,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,OAAO,CAAC,SAAiB,EAAE,SAAiB;IAC3D,OAAO,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;SAC1D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;SACvC,MAAM,CAAC,KAAK,CAAC,CAAA;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB,EAAE,SAAiB,EAAE,QAAgB;IACtF,IAAI,CAAC,sBAAsB,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAA;IAClE,OAAO,eAAe,CACrB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,KAAK,CAAC,EACjD,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAC5B,CAAA;AACF,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,WAAW,CAAC,KAS3B;IACA,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,IAAI,UAAU,EAAE,CAAA;IAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAA;IACpD,MAAM,SAAS,GAAG,UAAU,EAAE,CAAA;IAC9B,MAAM,SAAS,GAAG,oBAAoB,CAAC;QACtC,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,MAAM;QACN,SAAS;QACT,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE;QACxB,UAAU,EAAE,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CAAA;IACF,OAAO;QACN,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC,OAAO;QACrD,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,KAAK;QACtC,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,KAAK;QACtC,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,MAAM;QAClC,CAAC,gBAAgB,CAAC,UAAU,CAAC,EAAE,SAAS;QACxC,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,SAAS,CAAC;QACjE,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtE,CAAA;AACF,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Devora Node.js Backend SDK
|
|
3
|
+
*
|
|
4
|
+
* Secure backend SDK for enabling impersonation in your Node.js application.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { devoraSDK, DEVORA_ENDPOINTS } from "@devorash/node";
|
|
9
|
+
*
|
|
10
|
+
* const sdk = devoraSDK({
|
|
11
|
+
* apiKey: process.env.DEVORA_API_KEY!,
|
|
12
|
+
* secretKey: process.env.DEVORA_SECRET_KEY!,
|
|
13
|
+
* orgId: "your-org-id",
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* const routes = [
|
|
17
|
+
* sdk.register(DEVORA_ENDPOINTS.USER_SEARCH, async (req) => {
|
|
18
|
+
* const { term } = req.query;
|
|
19
|
+
* return { users: await searchUsers(term) };
|
|
20
|
+
* }),
|
|
21
|
+
* sdk.register(DEVORA_ENDPOINTS.IMPERSONATE, async (req) => {
|
|
22
|
+
* const { id } = req.params;
|
|
23
|
+
* return { token: await generateToken(id), data: {} };
|
|
24
|
+
* }),
|
|
25
|
+
* sdk.register(DEVORA_ENDPOINTS.TERMINATE, async (req) => {
|
|
26
|
+
* const { id } = req.params;
|
|
27
|
+
* await invalidateSession(id);
|
|
28
|
+
* return { success: true };
|
|
29
|
+
* }),
|
|
30
|
+
* ];
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @packageDocumentation
|
|
34
|
+
* @module @devorash/node
|
|
35
|
+
*/
|
|
36
|
+
export { devoraSDK, resolveEnvironment } from "./sdk.js";
|
|
37
|
+
export { sha256Hex, signRequest } from "./hmac.js";
|
|
38
|
+
export { controlPlaneFetch, readBoundedJsonObject, ControlPlaneResponseError, MAX_CONTROL_RESPONSE_BYTES, } from "./transport.js";
|
|
39
|
+
export { processRequest, createGenericHandler, stripMountPath, DEFAULT_MAX_BODY_SIZE, type AdapterRequest, } from "./handler.js";
|
|
40
|
+
export { createImpersonationGuard, validateImpersonationContext, resolveImpersonationIdentities, isWriteOperation, } from "./middleware.js";
|
|
41
|
+
export type { ImpersonationContext, ImpersonationContextResult, ImpersonationGuardOptions, MiddlewareRequest, MiddlewareResponse, MiddlewareNext, ScopeEndpoint, } from "./middleware.js";
|
|
42
|
+
export { createScopeConfigFetcher } from "./scope-config.js";
|
|
43
|
+
export type { ScopeConfig, ScopeConfigFetcherOptions } from "./scope-config.js";
|
|
44
|
+
export { InMemoryReplayStore } from "./replay-store.js";
|
|
45
|
+
export type { ReplayStore } from "./replay-store.js";
|
|
46
|
+
export type { NodeBackendSDKConfig, Logger, SDKRoute, DevoraBackendSDK, RegisterOptions, SDKStats, SessionStatusResult, ValidationResult, SignedRequestInput, FrameworkAdapter, DevoraEnvironment, } from "./types.js";
|
|
47
|
+
export { DEVORA_ENDPOINTS, ENDPOINT_METHODS, PROTECTED_ENDPOINTS, SECURITY_HEADERS, SDK_DEFAULTS, SDK_VERSION, ERROR_CODES, DevoraSDKError, DevoraSecurityError, DevoraValidationError, DevoraConfigError, matchPath, createSuccessResponse, createErrorResponse, } from "@devorash/core";
|
|
48
|
+
export type { DevoraRequest, DevoraResponse, DevoraUser, UserSearchRequest, UserSearchResponse, ImpersonationScope, ImpersonationDuration, DevoraImpersonationContext, ImpersonationStartRequest, ImpersonationStartResponse, ImpersonationTerminateRequest, ImpersonationTerminateResponse, RouteHandler, RouteDefinition, ConnectionTestResponse, HealthCheckResponse, } from "@devorash/core";
|
|
49
|
+
export { resolveBrowserSession, BROWSER_SESSION_RESPONSE_HEADERS, type ResolveBrowserSessionInput, } from "./browser-session.js";
|
|
50
|
+
export { BROWSER_SESSION_BRIDGE } from "@devorash/core";
|
|
51
|
+
export type { SessionBridgeResult, BrowserResumeCode } from "@devorash/core";
|
|
52
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAGxD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EACN,iBAAiB,EACjB,qBAAqB,EACrB,yBAAyB,EACzB,0BAA0B,GAC1B,MAAM,gBAAgB,CAAA;AAGvB,OAAO,EACN,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,qBAAqB,EACrB,KAAK,cAAc,GACnB,MAAM,cAAc,CAAA;AAGrB,OAAO,EACN,wBAAwB,EACxB,4BAA4B,EAC5B,8BAA8B,EAC9B,gBAAgB,GAChB,MAAM,iBAAiB,CAAA;AACxB,YAAY,EACX,oBAAoB,EACpB,0BAA0B,EAC1B,yBAAyB,EACzB,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,aAAa,GACb,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA;AAC5D,YAAY,EAAE,WAAW,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAA;AAG/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAGpD,YAAY,EACX,oBAAoB,EACpB,MAAM,EACN,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,QAAQ,EACR,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,GACjB,MAAM,YAAY,CAAA;AAGnB,OAAO,EAEN,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EAEnB,gBAAgB,EAEhB,YAAY,EACZ,WAAW,EAEX,WAAW,EAEX,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,EAEjB,SAAS,EACT,qBAAqB,EACrB,mBAAmB,GACnB,MAAM,gBAAgB,CAAA;AAGvB,YAAY,EACX,aAAa,EACb,cAAc,EACd,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,0BAA0B,EAC1B,yBAAyB,EACzB,0BAA0B,EAC1B,6BAA6B,EAC7B,8BAA8B,EAC9B,YAAY,EACZ,eAAe,EACf,sBAAsB,EACtB,mBAAmB,GACnB,MAAM,gBAAgB,CAAA;AAGvB,OAAO,EACN,qBAAqB,EACrB,gCAAgC,EAChC,KAAK,0BAA0B,GAC/B,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AACvD,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Devora Node.js Backend SDK
|
|
3
|
+
*
|
|
4
|
+
* Secure backend SDK for enabling impersonation in your Node.js application.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { devoraSDK, DEVORA_ENDPOINTS } from "@devorash/node";
|
|
9
|
+
*
|
|
10
|
+
* const sdk = devoraSDK({
|
|
11
|
+
* apiKey: process.env.DEVORA_API_KEY!,
|
|
12
|
+
* secretKey: process.env.DEVORA_SECRET_KEY!,
|
|
13
|
+
* orgId: "your-org-id",
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* const routes = [
|
|
17
|
+
* sdk.register(DEVORA_ENDPOINTS.USER_SEARCH, async (req) => {
|
|
18
|
+
* const { term } = req.query;
|
|
19
|
+
* return { users: await searchUsers(term) };
|
|
20
|
+
* }),
|
|
21
|
+
* sdk.register(DEVORA_ENDPOINTS.IMPERSONATE, async (req) => {
|
|
22
|
+
* const { id } = req.params;
|
|
23
|
+
* return { token: await generateToken(id), data: {} };
|
|
24
|
+
* }),
|
|
25
|
+
* sdk.register(DEVORA_ENDPOINTS.TERMINATE, async (req) => {
|
|
26
|
+
* const { id } = req.params;
|
|
27
|
+
* await invalidateSession(id);
|
|
28
|
+
* return { success: true };
|
|
29
|
+
* }),
|
|
30
|
+
* ];
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @packageDocumentation
|
|
34
|
+
* @module @devorash/node
|
|
35
|
+
*/
|
|
36
|
+
// Main SDK
|
|
37
|
+
export { devoraSDK, resolveEnvironment } from "./sdk.js";
|
|
38
|
+
// HMAC utilities
|
|
39
|
+
export { sha256Hex, signRequest } from "./hmac.js";
|
|
40
|
+
export { controlPlaneFetch, readBoundedJsonObject, ControlPlaneResponseError, MAX_CONTROL_RESPONSE_BYTES, } from "./transport.js";
|
|
41
|
+
// Request handler
|
|
42
|
+
export { processRequest, createGenericHandler, stripMountPath, DEFAULT_MAX_BODY_SIZE, } from "./handler.js";
|
|
43
|
+
// Impersonation middleware
|
|
44
|
+
export { createImpersonationGuard, validateImpersonationContext, resolveImpersonationIdentities, isWriteOperation, } from "./middleware.js";
|
|
45
|
+
// Scope configuration
|
|
46
|
+
export { createScopeConfigFetcher } from "./scope-config.js";
|
|
47
|
+
// Persistent replay protection
|
|
48
|
+
export { InMemoryReplayStore } from "./replay-store.js";
|
|
49
|
+
// Re-export commonly used items from core
|
|
50
|
+
export {
|
|
51
|
+
// Endpoints
|
|
52
|
+
DEVORA_ENDPOINTS, ENDPOINT_METHODS, PROTECTED_ENDPOINTS,
|
|
53
|
+
// Security headers
|
|
54
|
+
SECURITY_HEADERS,
|
|
55
|
+
// Defaults
|
|
56
|
+
SDK_DEFAULTS, SDK_VERSION,
|
|
57
|
+
// Error codes
|
|
58
|
+
ERROR_CODES,
|
|
59
|
+
// Errors
|
|
60
|
+
DevoraSDKError, DevoraSecurityError, DevoraValidationError, DevoraConfigError,
|
|
61
|
+
// Utilities
|
|
62
|
+
matchPath, createSuccessResponse, createErrorResponse, } from "@devorash/core";
|
|
63
|
+
// Browser-session bridge (server side)
|
|
64
|
+
export { resolveBrowserSession, BROWSER_SESSION_RESPONSE_HEADERS, } from "./browser-session.js";
|
|
65
|
+
export { BROWSER_SESSION_BRIDGE } from "@devorash/core";
|
|
66
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,WAAW;AACX,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAExD,iBAAiB;AACjB,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EACN,iBAAiB,EACjB,qBAAqB,EACrB,yBAAyB,EACzB,0BAA0B,GAC1B,MAAM,gBAAgB,CAAA;AAEvB,kBAAkB;AAClB,OAAO,EACN,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,qBAAqB,GAErB,MAAM,cAAc,CAAA;AAErB,2BAA2B;AAC3B,OAAO,EACN,wBAAwB,EACxB,4BAA4B,EAC5B,8BAA8B,EAC9B,gBAAgB,GAChB,MAAM,iBAAiB,CAAA;AAWxB,sBAAsB;AACtB,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA;AAG5D,+BAA+B;AAC/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAkBvD,0CAA0C;AAC1C,OAAO;AACN,YAAY;AACZ,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB;AACnB,mBAAmB;AACnB,gBAAgB;AAChB,WAAW;AACX,YAAY,EACZ,WAAW;AACX,cAAc;AACd,WAAW;AACX,SAAS;AACT,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB;AACjB,YAAY;AACZ,SAAS,EACT,qBAAqB,EACrB,mBAAmB,GACnB,MAAM,gBAAgB,CAAA;AAsBvB,uCAAuC;AACvC,OAAO,EACN,qBAAqB,EACrB,gCAAgC,GAEhC,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Impersonation scope enforcement middleware
|
|
3
|
+
*
|
|
4
|
+
* Provides defense-in-depth by validating impersonation scope on the backend,
|
|
5
|
+
* blocking write operations in read-only mode even if the frontend SDK is bypassed.
|
|
6
|
+
*
|
|
7
|
+
* @module @devorash/node
|
|
8
|
+
*/
|
|
9
|
+
import { type ImpersonationScope } from "@devorash/core";
|
|
10
|
+
import type { DevoraBackendSDK } from "./types.js";
|
|
11
|
+
/**
|
|
12
|
+
* Impersonation context extracted from JWT or request
|
|
13
|
+
*/
|
|
14
|
+
export interface ImpersonationContext {
|
|
15
|
+
/** Whether this is an impersonation session */
|
|
16
|
+
isImpersonation: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* The Devora agent actually performing the action. Optional only because
|
|
19
|
+
* `impersonator` (the field name the SDK handler emits) is accepted as an
|
|
20
|
+
* equivalent source; one of the two must be present.
|
|
21
|
+
*/
|
|
22
|
+
actor?: {
|
|
23
|
+
id: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* The authenticated customer user being represented. `targetUser` is
|
|
27
|
+
* accepted as an equivalent source.
|
|
28
|
+
*/
|
|
29
|
+
subject?: {
|
|
30
|
+
id: string;
|
|
31
|
+
};
|
|
32
|
+
/** Access scope: "read" or "write" */
|
|
33
|
+
scope: ImpersonationScope;
|
|
34
|
+
/** Devora session ID */
|
|
35
|
+
sessionId?: string;
|
|
36
|
+
/** This is always a distinct customer impersonation session, never customer MFA. */
|
|
37
|
+
authMethod: "devora_impersonation";
|
|
38
|
+
/** How the Devora request was authorized. */
|
|
39
|
+
authorizationSource: "standard" | "self_approved" | "self_approved_read" | "break_glass";
|
|
40
|
+
/** Whether the customer backend permitted recording for this exact session. */
|
|
41
|
+
recordingAllowed: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* When the session expires.
|
|
44
|
+
*
|
|
45
|
+
* IMPORTANT: This should be a Unix timestamp in MILLISECONDS (matching JavaScript's Date.now()).
|
|
46
|
+
* If your JWT uses seconds (standard Unix timestamp), multiply by 1000 when extracting.
|
|
47
|
+
*
|
|
48
|
+
* Example:
|
|
49
|
+
* ```typescript
|
|
50
|
+
* getImpersonationContext: (req) => ({
|
|
51
|
+
* ...req.user.devora,
|
|
52
|
+
* // Convert seconds to milliseconds if needed
|
|
53
|
+
* expiresAt: req.user.devora.expiresAt * 1000,
|
|
54
|
+
* })
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
expiresAt?: number;
|
|
58
|
+
/** Information about the impersonator (agent) */
|
|
59
|
+
impersonator?: {
|
|
60
|
+
id: string;
|
|
61
|
+
email?: string;
|
|
62
|
+
name?: string;
|
|
63
|
+
};
|
|
64
|
+
/** Information about the impersonated customer user */
|
|
65
|
+
targetUser?: {
|
|
66
|
+
id: string;
|
|
67
|
+
email?: string;
|
|
68
|
+
name?: string;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* What a context extractor may return: the context, or `null`/`undefined` for
|
|
73
|
+
* ordinary (non-impersonated) traffic. Async extractors are awaited.
|
|
74
|
+
*/
|
|
75
|
+
export type ImpersonationContextResult = ImpersonationContext | null | undefined | Promise<ImpersonationContext | null | undefined>;
|
|
76
|
+
/** Resolve the canonical actor/subject ids from either field-name convention. */
|
|
77
|
+
export declare function resolveImpersonationIdentities(context: Pick<ImpersonationContext, "actor" | "subject" | "impersonator" | "targetUser">): {
|
|
78
|
+
actorId?: string;
|
|
79
|
+
subjectId?: string;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Generic request interface for middleware
|
|
83
|
+
*/
|
|
84
|
+
export interface MiddlewareRequest {
|
|
85
|
+
method: string;
|
|
86
|
+
path: string;
|
|
87
|
+
url?: string;
|
|
88
|
+
originalUrl?: string;
|
|
89
|
+
/** Express: the mount path of the router running the guard. */
|
|
90
|
+
baseUrl?: string;
|
|
91
|
+
/** Request headers (lower-case names); used to detect method-override headers. */
|
|
92
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
93
|
+
/**
|
|
94
|
+
* Origin-form targets (`/path?query`, full client-visible path) the framework
|
|
95
|
+
* dispatches on after any rewrites. Adapters set this; the default is
|
|
96
|
+
* `baseUrl + url`. Safe-read allow rules must match every routed target and
|
|
97
|
+
* the original target; deny rules match any of them.
|
|
98
|
+
*/
|
|
99
|
+
routedUrls?: string[];
|
|
100
|
+
/**
|
|
101
|
+
* Additional deny-only views of the same request (for example a path with a
|
|
102
|
+
* framework base path or locale prefix removed). They can only block.
|
|
103
|
+
*/
|
|
104
|
+
aliasUrls?: string[];
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Generic response interface for middleware
|
|
108
|
+
*/
|
|
109
|
+
export interface MiddlewareResponse {
|
|
110
|
+
status: (code: number) => MiddlewareResponse;
|
|
111
|
+
json: (body: unknown) => void;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Next function type for middleware
|
|
115
|
+
*/
|
|
116
|
+
export type MiddlewareNext = () => void | Promise<void>;
|
|
117
|
+
export type { ScopeEndpoint } from "./scope-config.js";
|
|
118
|
+
/**
|
|
119
|
+
* Options for the impersonation guard middleware
|
|
120
|
+
*/
|
|
121
|
+
export interface ImpersonationGuardOptions<TRequest = MiddlewareRequest> {
|
|
122
|
+
/** Initialized Devora SDK used to load the centrally managed policy. */
|
|
123
|
+
sdk: DevoraBackendSDK;
|
|
124
|
+
/**
|
|
125
|
+
* Function to extract impersonation context from the request, typically from
|
|
126
|
+
* the authenticated session or JWT claims. Return `null` for ordinary traffic.
|
|
127
|
+
* May be async. Any other non-context value fails closed with a 500.
|
|
128
|
+
*/
|
|
129
|
+
getImpersonationContext: (req: TRequest) => ImpersonationContextResult;
|
|
130
|
+
/**
|
|
131
|
+
* Callback when a request is blocked.
|
|
132
|
+
* Useful for logging or alerting. Errors it throws are ignored.
|
|
133
|
+
*/
|
|
134
|
+
onBlocked?: (req: TRequest, context: ImpersonationContext) => void;
|
|
135
|
+
/**
|
|
136
|
+
* Custom response when a request is blocked.
|
|
137
|
+
* Defaults to a standard 403 response.
|
|
138
|
+
*/
|
|
139
|
+
blockedResponse?: {
|
|
140
|
+
status?: number;
|
|
141
|
+
message?: string;
|
|
142
|
+
errorCode?: string;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Whether to show warnings in console when requests are blocked.
|
|
146
|
+
* Defaults to true in development.
|
|
147
|
+
*/
|
|
148
|
+
showWarnings?: boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Enforce server-side session liveness in addition to scope and expiry. When true, the
|
|
151
|
+
* guard asks Devora whether the request's session is still live and blocks it if the
|
|
152
|
+
* session was terminated or revoked early (before its hard expiry). On by default.
|
|
153
|
+
*
|
|
154
|
+
* Requires `getImpersonationContext` to return a `sessionId`. Adds at most one cached
|
|
155
|
+
* lookup per session per `livenessCacheTtlMs`.
|
|
156
|
+
*/
|
|
157
|
+
enforceLiveness?: boolean;
|
|
158
|
+
/**
|
|
159
|
+
* How long, in milliseconds, to cache a liveness result per session. Lower values detect
|
|
160
|
+
* early termination faster at the cost of more lookups. Default 5000 (5 seconds).
|
|
161
|
+
*/
|
|
162
|
+
livenessCacheTtlMs?: number;
|
|
163
|
+
/**
|
|
164
|
+
* Behavior when Devora cannot be reached for a liveness check:
|
|
165
|
+
* - "allow": fall back to scope and expiry enforcement (local development only).
|
|
166
|
+
* - "deny" (default): fail closed — block impersonated requests until Devora is reachable.
|
|
167
|
+
*/
|
|
168
|
+
onLivenessUnavailable?: "allow" | "deny";
|
|
169
|
+
/**
|
|
170
|
+
* Path where you mounted the browser-session bridge handler, for example
|
|
171
|
+
* `/api/devora/browser-session`. When set, a `POST` to exactly this path is
|
|
172
|
+
* allowed in read scope (it mints a resume code, it is not a customer write).
|
|
173
|
+
* The blocklist and `isImpersonationAllowed` still apply. Off by default:
|
|
174
|
+
* only set it when the bridge is actually mounted at that path.
|
|
175
|
+
*/
|
|
176
|
+
bridgePath?: string;
|
|
177
|
+
/**
|
|
178
|
+
* Semantic authorization hook for application-specific high-risk actions.
|
|
179
|
+
* It runs after the static blocklist and before scope allowlisting. Returning
|
|
180
|
+
* false blocks the impersonated request; normal customer traffic is untouched.
|
|
181
|
+
*/
|
|
182
|
+
isImpersonationAllowed?: (req: TRequest, context: ImpersonationContext) => boolean | Promise<boolean>;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Create an impersonation guard middleware
|
|
186
|
+
*
|
|
187
|
+
* This middleware validates impersonation scope and blocks write operations
|
|
188
|
+
* in read-only mode. It provides defense-in-depth protection on the backend.
|
|
189
|
+
*
|
|
190
|
+
* Every request target the framework may dispatch on is judged: the original
|
|
191
|
+
* target, the effective target after rewrites/mounts, and any deny-only aliases.
|
|
192
|
+
* Policy patterns match the full client-visible path, including mount prefixes.
|
|
193
|
+
*
|
|
194
|
+
* Enforcement Priority:
|
|
195
|
+
* 1. Check blacklist first - if match, BLOCK (regardless of scope)
|
|
196
|
+
* 2. Run the application's isImpersonationAllowed hook
|
|
197
|
+
* 3. If scope is "write", ALLOW (blacklist already checked)
|
|
198
|
+
* 4. If scope is "read" and write method, check whitelist
|
|
199
|
+
* 5. If not in whitelist, BLOCK
|
|
200
|
+
*/
|
|
201
|
+
export declare function createImpersonationGuard<TRequest extends MiddlewareRequest = MiddlewareRequest>(options: ImpersonationGuardOptions<TRequest>): (req: TRequest, res: MiddlewareResponse, next: MiddlewareNext) => Promise<void>;
|
|
202
|
+
/**
|
|
203
|
+
* Validate impersonation context
|
|
204
|
+
*
|
|
205
|
+
* Utility function to check if impersonation context is valid and not expired.
|
|
206
|
+
* Types are checked strictly; nothing is coerced.
|
|
207
|
+
*/
|
|
208
|
+
export declare function validateImpersonationContext(context: ImpersonationContext | undefined | null): {
|
|
209
|
+
valid: boolean;
|
|
210
|
+
expired?: boolean;
|
|
211
|
+
error?: string;
|
|
212
|
+
};
|
|
213
|
+
/**
|
|
214
|
+
* Check if a request method is a write operation
|
|
215
|
+
*
|
|
216
|
+
* @deprecated Use isWriteMethod from @devorash/core instead
|
|
217
|
+
*/
|
|
218
|
+
export declare function isWriteOperation(method: string): boolean;
|
|
219
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
|