@cequrebackends/plugin-security 0.12.2

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 ADDED
@@ -0,0 +1,23 @@
1
+ # @cequrebackends/plugin-security
2
+
3
+ Security enforcement plugin for Cequre backends. Handles access control, rate limiting, field encryption, and audit logging.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add @cequrebackends/plugin-security
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { CequreRuntime } from "@cequrebackends/cequre-ts";
15
+ import { defaultSecurity } from "@cequrebackends/plugin-security";
16
+
17
+ const runtime = new CequreRuntime(schema, {
18
+ adapter,
19
+ plugins: [
20
+ defaultSecurity()
21
+ ]
22
+ });
23
+ ```
@@ -0,0 +1,39 @@
1
+ import type { CequreAST } from "@cequrebackends/cequre-ts";
2
+ export interface CequreAuditEvent {
3
+ action: string;
4
+ collection?: string;
5
+ recordId?: string;
6
+ userId?: string;
7
+ requestId?: string;
8
+ metadata?: Record<string, unknown>;
9
+ }
10
+ export interface AuditLogEntry extends CequreAuditEvent {
11
+ id?: string;
12
+ hmac: string;
13
+ prevHmac: string | null;
14
+ createdAt?: string;
15
+ }
16
+ /**
17
+ * Resolves the audit HMAC key. Precedence:
18
+ * 1. `config.security.audit.secret` (explicit operator override)
19
+ * 2. `CEQURE_AUDIT_SECRET` environment variable
20
+ * 3. HKDF-SHA256 derivation from `JWT_SECRET`
21
+ */
22
+ export declare function resolveAuditSecret(config: CequreAST): Promise<CryptoKey>;
23
+ /**
24
+ * Computes the HMAC-SHA256 over `canonical(payload) + prevHmac`.
25
+ */
26
+ export declare function computeAuditHmac(key: CryptoKey, event: CequreAuditEvent, prevHmac: string | null): Promise<string>;
27
+ /**
28
+ * Verifies an HMAC against an event + previous HMAC.
29
+ */
30
+ export declare function verifyAuditHmac(key: CryptoKey, event: CequreAuditEvent, prevHmac: string | null, storedHmac: string): Promise<boolean>;
31
+ /**
32
+ * Walks an ordered list of audit entries and returns the index of the first
33
+ * entry whose HMAC does not validate against the chain (or null if clean).
34
+ */
35
+ export declare function verifyAuditChain(key: CryptoKey, entries: AuditLogEntry[]): Promise<{
36
+ ok: boolean;
37
+ firstBadIndex: number | null;
38
+ }>;
39
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAG3D,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,aAAc,SAAQ,gBAAgB;IACrD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAuB9E;AAiBD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,gBAAgB,EACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,GACtB,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,gBAAgB,EACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAGlB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,SAAS,EACd,OAAO,EAAE,aAAa,EAAE,GACvB,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAgBxD"}
@@ -0,0 +1,3 @@
1
+ import type { CequreRuntime } from "@cequrebackends/cequre-ts";
2
+ export declare function setupAuthRoutes(cequre: CequreRuntime<any>): void;
3
+ //# sourceMappingURL=auth-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-routes.d.ts","sourceRoot":"","sources":["../src/auth-routes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAoD/D,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,QA8azD"}
package/dist/auth.d.ts ADDED
@@ -0,0 +1,61 @@
1
+ import type { CequreAdapter } from "@cequrebackends/cequre-ts";
2
+ import type { CollectionConfig } from "@cequrebackends/cequre-ts";
3
+ import type { AuthUser } from "@cequrebackends/cequre-ts";
4
+ import { type TokenStore } from "./token-store";
5
+ export interface JWTConfig {
6
+ secret: string;
7
+ previousSecret?: string;
8
+ issuer?: string;
9
+ audience?: string;
10
+ accessTokenExpiry?: string;
11
+ refreshTokenExpiry?: string;
12
+ }
13
+ export interface TokenPair {
14
+ accessToken: string;
15
+ refreshToken: string;
16
+ user: AuthUser;
17
+ }
18
+ export declare class JWTAuthenticator {
19
+ private config;
20
+ private adapter;
21
+ private tokenStore;
22
+ private collections?;
23
+ private platformAdminCollection?;
24
+ private cleanupTimer;
25
+ constructor(config: JWTConfig, adapter: CequreAdapter, tokenStore?: TokenStore, collections?: CollectionConfig[], platformAdminCollection?: string);
26
+ generateTokenPair(user: Record<string, unknown>, collection: string): Promise<TokenPair>;
27
+ refreshTokenPair(refreshToken: string): Promise<TokenPair | null>;
28
+ verifyAccessToken(token: string): Promise<AuthUser | null>;
29
+ revokeRefreshToken(refreshToken: string): Promise<void>;
30
+ /**
31
+ * Revoke all refresh tokens for a given user (e.g. after password reset/change).
32
+ */
33
+ revokeAllForUser(userId: string): Promise<void>;
34
+ generatePasswordResetToken(userId: string, collection: string): Promise<string>;
35
+ verifyPasswordResetToken(token: string): Promise<{
36
+ userId: string;
37
+ collection: string;
38
+ } | null>;
39
+ /**
40
+ * Generates a short-lived MFA challenge token (5 min expiry).
41
+ * Uses type: "mfa" — distinct from "reset" so the two flows
42
+ * can't be confused or cross-used.
43
+ */
44
+ generateMFAChallengeToken(userId: string, collection: string): Promise<string>;
45
+ /**
46
+ * Verifies an MFA challenge token. Only accepts type: "mfa" —
47
+ * password reset tokens (type: "reset") are rejected.
48
+ */
49
+ verifyMFAChallengeToken(token: string): Promise<{
50
+ userId: string;
51
+ collection: string;
52
+ } | null>;
53
+ /**
54
+ * Shared verify+rotation logic for typed JWT tokens (reset, mfa).
55
+ * Tries the primary secret first, then falls back to `previousSecret`
56
+ * during a rotation grace period. Rejects tokens whose `type` claim
57
+ * doesn't match `expectedType`.
58
+ */
59
+ private verifyTypedToken;
60
+ }
61
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAOpE,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,QAAQ,CAAC;CAChB;AAMD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,WAAW,CAAC,CAAqB;IACzC,OAAO,CAAC,uBAAuB,CAAC,CAAS;IACzC,OAAO,CAAC,YAAY,CAAiC;gBAEzC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,UAAU,CAAC,EAAE,UAAU,EAAE,WAAW,CAAC,EAAE,gBAAgB,EAAE,EAAE,uBAAuB,CAAC,EAAE,MAAM;IAW5I,iBAAiB,CACrB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,SAAS,CAAC;IA8Df,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAoCjE,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IA+B1D,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7D;;OAEG;IACG,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAW/E,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAIrG;;;;OAIG;IACG,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAWpF;;;OAGG;IACG,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAIpG;;;;;OAKG;YACW,gBAAgB;CAmB/B"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Derives an AES-256-GCM CryptoKey from a passphrase string.
3
+ * Uses HKDF-SHA256 with a fixed label for key separation from other
4
+ * Cequre crypto uses (JWT signing, audit HMAC).
5
+ */
6
+ export declare function resolveEncryptionKey(passphrase: string): Promise<CryptoKey>;
7
+ /**
8
+ * Encrypts a string value using AES-256-GCM.
9
+ * Returns "enc:v1:<base64(iv)>:<base64(ciphertext)>".
10
+ * A random 12-byte IV is generated per call, so the same plaintext
11
+ * produces different ciphertexts each time.
12
+ */
13
+ export declare function encryptField(key: CryptoKey, plaintext: string): Promise<string>;
14
+ /**
15
+ * Decrypts an "enc:v1:..." value.
16
+ * Returns null for:
17
+ * - non-encrypted values (no prefix) — so encrypted and plaintext can coexist
18
+ * - decryption failures (tampered ciphertext, wrong key)
19
+ */
20
+ export declare function decryptField(key: CryptoKey, value: string): Promise<string | null>;
21
+ /**
22
+ * Check if a value is encrypted (has the enc:v1: prefix).
23
+ */
24
+ export declare function isEncrypted(value: unknown): value is string;
25
+ //# sourceMappingURL=encryption.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../src/encryption.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAYjF;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOrF;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBxF;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAE3D"}
@@ -0,0 +1,11 @@
1
+ import type { CequrePlugin } from "@cequrebackends/cequre-ts";
2
+ export * from './auth';
3
+ export * from './rate-limiter';
4
+ export { type TokenStore, InMemoryTokenStore, AdapterTokenStore, REFRESH_TOKEN_COLLECTION } from './token-store';
5
+ export * from './audit';
6
+ export * from './encryption';
7
+ export * from './mfa';
8
+ export { type SecretsProvider, EnvVarSecrets } from './secrets';
9
+ export { signWebhook, verifyWebhookSignature, WEBHOOK_SIGNATURE_HEADER } from './webhooks';
10
+ export declare function defaultSecurity(): CequrePlugin;
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAqB,MAAM,2BAA2B,CAAC;AAMjF,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,KAAK,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACjH,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,OAAO,CAAC;AACtB,OAAO,EAAE,KAAK,eAAe,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAI3F,wBAAgB,eAAe,IAAI,YAAY,CAuI9C"}