@anby/platform-sdk 0.1.0 → 0.7.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/cjs/apps/publish.d.ts +23 -0
- package/dist/cjs/apps/publish.d.ts.map +1 -1
- package/dist/cjs/apps/publish.js +65 -5
- package/dist/cjs/apps/publish.js.map +1 -1
- package/dist/cjs/auth/index.d.ts +33 -3
- package/dist/cjs/auth/index.d.ts.map +1 -1
- package/dist/cjs/auth/index.js +105 -24
- package/dist/cjs/auth/index.js.map +1 -1
- package/dist/cjs/bootstrap/cache.d.ts +4 -0
- package/dist/cjs/bootstrap/cache.d.ts.map +1 -0
- package/dist/cjs/bootstrap/cache.js +52 -0
- package/dist/cjs/bootstrap/cache.js.map +1 -0
- package/dist/cjs/bootstrap/index.d.ts +79 -0
- package/dist/cjs/bootstrap/index.d.ts.map +1 -0
- package/dist/cjs/bootstrap/index.js +280 -0
- package/dist/cjs/bootstrap/index.js.map +1 -0
- package/dist/cjs/bootstrap/types.d.ts +53 -0
- package/dist/cjs/bootstrap/types.d.ts.map +1 -0
- package/dist/cjs/bootstrap/types.js +14 -0
- package/dist/cjs/bootstrap/types.js.map +1 -0
- package/dist/cjs/events/http-transport.d.ts +38 -0
- package/dist/cjs/events/http-transport.d.ts.map +1 -0
- package/dist/cjs/events/http-transport.js +63 -0
- package/dist/cjs/events/http-transport.js.map +1 -0
- package/dist/cjs/events/index.d.ts +49 -0
- package/dist/cjs/events/index.d.ts.map +1 -1
- package/dist/cjs/events/index.js +14 -1
- package/dist/cjs/events/index.js.map +1 -1
- package/dist/cjs/index.d.ts +6 -3
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +30 -11
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/vite/index.d.ts +20 -0
- package/dist/cjs/vite/index.d.ts.map +1 -0
- package/dist/cjs/vite/index.js +154 -0
- package/dist/cjs/vite/index.js.map +1 -0
- package/dist/esm/apps/publish.js +31 -5
- package/dist/esm/apps/publish.js.map +1 -1
- package/dist/esm/auth/index.js +102 -23
- package/dist/esm/auth/index.js.map +1 -1
- package/dist/esm/bootstrap/cache.js +48 -0
- package/dist/esm/bootstrap/cache.js.map +1 -0
- package/dist/esm/bootstrap/index.js +272 -0
- package/dist/esm/bootstrap/index.js.map +1 -0
- package/dist/esm/bootstrap/types.js +11 -0
- package/dist/esm/bootstrap/types.js.map +1 -0
- package/dist/esm/events/http-transport.js +59 -0
- package/dist/esm/events/http-transport.js.map +1 -0
- package/dist/esm/events/index.js +14 -1
- package/dist/esm/events/index.js.map +1 -1
- package/dist/esm/index.js +8 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/package.json +1 -0
- package/dist/esm/vite/index.js +151 -0
- package/dist/esm/vite/index.js.map +1 -0
- package/package.json +20 -7
- package/src/apps/publish.ts +45 -6
- package/src/auth/index.test.ts +249 -0
- package/src/auth/index.ts +126 -32
- package/src/bootstrap/cache.ts +60 -0
- package/src/bootstrap/index.test.ts +277 -0
- package/src/bootstrap/index.ts +350 -0
- package/src/bootstrap/types.ts +56 -0
- package/src/events/http-transport.test.ts +135 -0
- package/src/events/http-transport.ts +77 -0
- package/src/events/index.ts +73 -2
- package/src/index.ts +29 -1
- package/src/vite/index.ts +195 -0
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* which the registry verifies via `HmacGuard` and then persists via the same
|
|
11
11
|
* `registry.service.publishApp()`.
|
|
12
12
|
*/
|
|
13
|
+
import { type AppManifest } from '@anby/manifest-schema';
|
|
13
14
|
export interface PublishAppOptions {
|
|
14
15
|
/**
|
|
15
16
|
* Path to the manifest file. Defaults to `./anby-app.manifest.json` in the
|
|
@@ -62,7 +63,29 @@ export interface PublishAppResult {
|
|
|
62
63
|
appId: string;
|
|
63
64
|
version: string;
|
|
64
65
|
};
|
|
66
|
+
/**
|
|
67
|
+
* Ed25519 private key (PEM) returned ONCE on first publish. Used to
|
|
68
|
+
* assemble the ANBY_APP_TOKEN connection string for the developer to
|
|
69
|
+
* paste into their app's env. Null on subsequent publishes — the
|
|
70
|
+
* registry never re-returns the key.
|
|
71
|
+
*
|
|
72
|
+
* The CLI uses this to print the assembled token. Programmatic
|
|
73
|
+
* callers should treat this field as a secret and avoid logging it.
|
|
74
|
+
*/
|
|
75
|
+
privateKey: string | null;
|
|
65
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Public helper: load the manifest from disk and return it with all
|
|
79
|
+
* `provides.entities[].schema` paths resolved to inlined JSON content.
|
|
80
|
+
*
|
|
81
|
+
* Used both internally by `publishAppFromManifest` and by services that
|
|
82
|
+
* want to expose the wire-format manifest over HTTP (e.g. a Remix route
|
|
83
|
+
* at `/_anby/manifest`) so the Marketplace submit form can fetch it
|
|
84
|
+
* without requiring the publisher to paste anything by hand.
|
|
85
|
+
*/
|
|
86
|
+
export declare function getInlinedManifest(opts?: {
|
|
87
|
+
manifestPath?: string;
|
|
88
|
+
}): Promise<AppManifest>;
|
|
66
89
|
export declare function publishAppFromManifest(opts?: PublishAppOptions): Promise<PublishAppResult | null>;
|
|
67
90
|
/**
|
|
68
91
|
* Fire-and-forget wrapper for use inside service entrypoints. Logs on both
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../../src/apps/publish.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../../src/apps/publish.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAI3E,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE;QACH,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C;;;;;;;;OAQG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAcD;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAO,GACnC,OAAO,CAAC,WAAW,CAAC,CAMtB;AA6ED,wBAAsB,sBAAsB,CAC1C,IAAI,GAAE,iBAAsB,GAC3B,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAuFlC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,iBAAsB,GAAG,IAAI,CAMpE"}
|
package/dist/cjs/apps/publish.js
CHANGED
|
@@ -11,7 +11,41 @@
|
|
|
11
11
|
* which the registry verifies via `HmacGuard` and then persists via the same
|
|
12
12
|
* `registry.service.publishApp()`.
|
|
13
13
|
*/
|
|
14
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
17
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
18
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
19
|
+
}
|
|
20
|
+
Object.defineProperty(o, k2, desc);
|
|
21
|
+
}) : (function(o, m, k, k2) {
|
|
22
|
+
if (k2 === undefined) k2 = k;
|
|
23
|
+
o[k2] = m[k];
|
|
24
|
+
}));
|
|
25
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
26
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
27
|
+
}) : function(o, v) {
|
|
28
|
+
o["default"] = v;
|
|
29
|
+
});
|
|
30
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
31
|
+
var ownKeys = function(o) {
|
|
32
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
33
|
+
var ar = [];
|
|
34
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
35
|
+
return ar;
|
|
36
|
+
};
|
|
37
|
+
return ownKeys(o);
|
|
38
|
+
};
|
|
39
|
+
return function (mod) {
|
|
40
|
+
if (mod && mod.__esModule) return mod;
|
|
41
|
+
var result = {};
|
|
42
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
43
|
+
__setModuleDefault(result, mod);
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
})();
|
|
14
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.getInlinedManifest = getInlinedManifest;
|
|
15
49
|
exports.publishAppFromManifest = publishAppFromManifest;
|
|
16
50
|
exports.autoPublishOnBoot = autoPublishOnBoot;
|
|
17
51
|
const promises_1 = require("node:fs/promises");
|
|
@@ -28,6 +62,20 @@ async function loadManifest(path) {
|
|
|
28
62
|
}
|
|
29
63
|
return parsed;
|
|
30
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Public helper: load the manifest from disk and return it with all
|
|
67
|
+
* `provides.entities[].schema` paths resolved to inlined JSON content.
|
|
68
|
+
*
|
|
69
|
+
* Used both internally by `publishAppFromManifest` and by services that
|
|
70
|
+
* want to expose the wire-format manifest over HTTP (e.g. a Remix route
|
|
71
|
+
* at `/_anby/manifest`) so the Marketplace submit form can fetch it
|
|
72
|
+
* without requiring the publisher to paste anything by hand.
|
|
73
|
+
*/
|
|
74
|
+
async function getInlinedManifest(opts = {}) {
|
|
75
|
+
const manifestPath = (0, node_path_1.resolve)(opts.manifestPath ?? (0, node_path_1.join)(process.cwd(), 'anby-app.manifest.json'));
|
|
76
|
+
const raw = await loadManifest(manifestPath);
|
|
77
|
+
return inlineEntitySchemas(raw, manifestPath);
|
|
78
|
+
}
|
|
31
79
|
/**
|
|
32
80
|
* Entity schema inliner (CR-4).
|
|
33
81
|
*
|
|
@@ -98,16 +146,28 @@ async function inlineEntitySchemas(manifest, manifestPath) {
|
|
|
98
146
|
async function publishAppFromManifest(opts = {}) {
|
|
99
147
|
try {
|
|
100
148
|
const manifestPath = (0, node_path_1.resolve)(opts.manifestPath ?? (0, node_path_1.join)(process.cwd(), 'anby-app.manifest.json'));
|
|
101
|
-
const rawManifest = await loadManifest(manifestPath);
|
|
102
149
|
// CR-4: inline schema content before sending. Manifest on disk uses
|
|
103
150
|
// relative paths for DX; wire format sends the actual JSON object.
|
|
104
|
-
const manifest = await
|
|
151
|
+
const manifest = await getInlinedManifest({ manifestPath });
|
|
105
152
|
const publicUrl = opts.publicUrl ??
|
|
106
153
|
process.env.APP_PUBLIC_URL ??
|
|
107
154
|
`http://localhost:${manifest.runtime.port}`;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
155
|
+
// PLAN-app-bootstrap-phase2 PR4: prefer the registry URL discovered
|
|
156
|
+
// by bootstrapFromToken. Falls back to the explicit option, then env,
|
|
157
|
+
// then localhost. The discovered value is the registry HOST root
|
|
158
|
+
// (no /registry suffix), so this code can append /registry/apps below.
|
|
159
|
+
let registryUrl = opts.registryUrl ?? process.env.REGISTRY_URL;
|
|
160
|
+
if (!registryUrl) {
|
|
161
|
+
try {
|
|
162
|
+
// Lazy require to avoid a circular import at module load time.
|
|
163
|
+
const { getDiscoveredRegistryBaseUrl } = await Promise.resolve().then(() => __importStar(require('../bootstrap/index.js')));
|
|
164
|
+
registryUrl = await getDiscoveredRegistryBaseUrl();
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// bootstrap not started yet — fall back to localhost dev default.
|
|
168
|
+
registryUrl = 'http://localhost:3003';
|
|
169
|
+
}
|
|
170
|
+
}
|
|
111
171
|
const internalApiSecret = opts.internalApiSecret ?? process.env.INTERNAL_API_SECRET ?? '';
|
|
112
172
|
if (!internalApiSecret) {
|
|
113
173
|
throw new Error('INTERNAL_API_SECRET is not set — cannot sign publish request');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../../../src/apps/publish.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG
|
|
1
|
+
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../../../src/apps/publish.ts"],"names":[],"mappings":"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"}
|
package/dist/cjs/auth/index.d.ts
CHANGED
|
@@ -1,15 +1,45 @@
|
|
|
1
|
+
export declare const JWT_ISSUER = "anby-auth-service";
|
|
2
|
+
export declare const JWT_AUDIENCE = "anby-platform";
|
|
3
|
+
export declare const TYP_USER = "user";
|
|
4
|
+
export declare const TYP_INTERNAL = "internal";
|
|
5
|
+
export declare const TYP_OAUTH_STATE = "oauth-state";
|
|
1
6
|
export interface AuthUser {
|
|
2
7
|
id: string;
|
|
3
8
|
email: string;
|
|
4
9
|
name?: string;
|
|
5
10
|
tenantId: string;
|
|
6
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Auth SDK config. Pass via configureAuth() before any verify* call.
|
|
14
|
+
*
|
|
15
|
+
* After PR4 cleanup, only the RS256 + HMAC fields exist:
|
|
16
|
+
* - jwtPublicKey: REQUIRED for any user/internal token verification
|
|
17
|
+
* - hmacSecret: REQUIRED for service-to-service HMAC (registry use case)
|
|
18
|
+
*
|
|
19
|
+
* For services that only verify JWTs and never use HMAC, pass only jwtPublicKey.
|
|
20
|
+
* For services that only use HMAC (e.g. app-registry), pass only hmacSecret.
|
|
21
|
+
*/
|
|
7
22
|
export interface AuthConfig {
|
|
8
|
-
|
|
9
|
-
|
|
23
|
+
jwtPublicKey?: string;
|
|
24
|
+
hmacSecret?: string;
|
|
10
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Configure the SDK's auth state. Call once at service boot, before any
|
|
28
|
+
* verify* call.
|
|
29
|
+
*/
|
|
11
30
|
export declare function configureAuth(config: AuthConfig): void;
|
|
12
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Verify a user session JWT (RS256). CRITICAL (cross-token confusion fix):
|
|
33
|
+
* rejects tokens with typ != "user". An internal-token (typ:internal) or
|
|
34
|
+
* oauth-state token (typ:oauth-state) presented as a user session is rejected
|
|
35
|
+
* even if the signature, iss, aud, and exp would all validate.
|
|
36
|
+
*/
|
|
37
|
+
export declare function verifyUserJwt(token: string): AuthUser;
|
|
38
|
+
/**
|
|
39
|
+
* Verify an internal-service JWT (RS256). CRITICAL: rejects tokens with
|
|
40
|
+
* typ != "internal".
|
|
41
|
+
*/
|
|
42
|
+
export declare function verifyInternalJwt(token: string): AuthUser;
|
|
13
43
|
export declare function verifyHmac(userValue: string, signature: string): boolean;
|
|
14
44
|
/**
|
|
15
45
|
* Compute an HMAC signature for service-to-service calls. Pair the returned
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/index.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,UAAU,sBAAsB,CAAC;AAC9C,eAAO,MAAM,YAAY,kBAAkB,CAAC;AAC5C,eAAO,MAAM,QAAQ,SAAS,CAAC;AAC/B,eAAO,MAAM,YAAY,aAAa,CAAC;AACvC,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAE7C,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,UAAU;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AASD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAWtD;AAgBD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAkBrD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAkBzD;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAaxE;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAMnE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CA4CrE;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,CAStD"}
|
package/dist/cjs/auth/index.js
CHANGED
|
@@ -3,26 +3,45 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TYP_OAUTH_STATE = exports.TYP_INTERNAL = exports.TYP_USER = exports.JWT_AUDIENCE = exports.JWT_ISSUER = void 0;
|
|
6
7
|
exports.configureAuth = configureAuth;
|
|
7
|
-
exports.
|
|
8
|
+
exports.verifyUserJwt = verifyUserJwt;
|
|
9
|
+
exports.verifyInternalJwt = verifyInternalJwt;
|
|
8
10
|
exports.verifyHmac = verifyHmac;
|
|
9
11
|
exports.signHmac = signHmac;
|
|
10
12
|
exports.authenticateRequest = authenticateRequest;
|
|
11
13
|
exports.requireAuth = requireAuth;
|
|
12
14
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
13
15
|
const crypto_1 = __importDefault(require("crypto"));
|
|
16
|
+
// JWT claim conventions for the asymmetric (RS256) auth path. Must match
|
|
17
|
+
// anby-auth-service/src/auth/auth.service.ts. All RS256 tokens carry these
|
|
18
|
+
// iss/aud/typ claims; all RS256 verifiers enforce them.
|
|
19
|
+
//
|
|
20
|
+
// PR4 cleanup: HS256 fallback paths removed. SDK is RS256-only.
|
|
21
|
+
exports.JWT_ISSUER = 'anby-auth-service';
|
|
22
|
+
exports.JWT_AUDIENCE = 'anby-platform';
|
|
23
|
+
exports.TYP_USER = 'user';
|
|
24
|
+
exports.TYP_INTERNAL = 'internal';
|
|
25
|
+
exports.TYP_OAUTH_STATE = 'oauth-state';
|
|
14
26
|
let _config = null;
|
|
27
|
+
/**
|
|
28
|
+
* Configure the SDK's auth state. Call once at service boot, before any
|
|
29
|
+
* verify* call.
|
|
30
|
+
*/
|
|
15
31
|
function configureAuth(config) {
|
|
16
|
-
|
|
32
|
+
const jwtPublicKey = config.jwtPublicKey ?? null;
|
|
33
|
+
const hmacSecret = config.hmacSecret ?? null;
|
|
34
|
+
if (!jwtPublicKey && !hmacSecret) {
|
|
35
|
+
throw new Error('configureAuth: at least one of jwtPublicKey or hmacSecret must be set');
|
|
36
|
+
}
|
|
37
|
+
_config = { jwtPublicKey, hmacSecret };
|
|
17
38
|
}
|
|
18
39
|
function getConfig() {
|
|
19
40
|
if (!_config)
|
|
20
41
|
throw new Error('Auth not configured. Call configureAuth() first.');
|
|
21
42
|
return _config;
|
|
22
43
|
}
|
|
23
|
-
function
|
|
24
|
-
const config = getConfig();
|
|
25
|
-
const payload = jsonwebtoken_1.default.verify(token, config.jwtSecret);
|
|
44
|
+
function payloadToAuthUser(payload) {
|
|
26
45
|
return {
|
|
27
46
|
id: payload.sub,
|
|
28
47
|
email: payload.email,
|
|
@@ -30,13 +49,68 @@ function verifyJwt(token) {
|
|
|
30
49
|
tenantId: payload.tenantId || 'default',
|
|
31
50
|
};
|
|
32
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Verify a user session JWT (RS256). CRITICAL (cross-token confusion fix):
|
|
54
|
+
* rejects tokens with typ != "user". An internal-token (typ:internal) or
|
|
55
|
+
* oauth-state token (typ:oauth-state) presented as a user session is rejected
|
|
56
|
+
* even if the signature, iss, aud, and exp would all validate.
|
|
57
|
+
*/
|
|
58
|
+
function verifyUserJwt(token) {
|
|
59
|
+
const config = getConfig();
|
|
60
|
+
if (!config.jwtPublicKey) {
|
|
61
|
+
throw new Error('jwtPublicKey not configured');
|
|
62
|
+
}
|
|
63
|
+
if (!token || token.split('.').length !== 3) {
|
|
64
|
+
throw new Error('Invalid token format');
|
|
65
|
+
}
|
|
66
|
+
const payload = jsonwebtoken_1.default.verify(token, config.jwtPublicKey, {
|
|
67
|
+
algorithms: ['RS256'],
|
|
68
|
+
issuer: exports.JWT_ISSUER,
|
|
69
|
+
audience: exports.JWT_AUDIENCE,
|
|
70
|
+
clockTolerance: 30,
|
|
71
|
+
});
|
|
72
|
+
if (payload.typ !== exports.TYP_USER) {
|
|
73
|
+
throw new Error('Wrong token class for user verifier');
|
|
74
|
+
}
|
|
75
|
+
return payloadToAuthUser(payload);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Verify an internal-service JWT (RS256). CRITICAL: rejects tokens with
|
|
79
|
+
* typ != "internal".
|
|
80
|
+
*/
|
|
81
|
+
function verifyInternalJwt(token) {
|
|
82
|
+
const config = getConfig();
|
|
83
|
+
if (!config.jwtPublicKey) {
|
|
84
|
+
throw new Error('jwtPublicKey not configured');
|
|
85
|
+
}
|
|
86
|
+
if (!token || token.split('.').length !== 3) {
|
|
87
|
+
throw new Error('Invalid token format');
|
|
88
|
+
}
|
|
89
|
+
const payload = jsonwebtoken_1.default.verify(token, config.jwtPublicKey, {
|
|
90
|
+
algorithms: ['RS256'],
|
|
91
|
+
issuer: exports.JWT_ISSUER,
|
|
92
|
+
audience: exports.JWT_AUDIENCE,
|
|
93
|
+
clockTolerance: 30,
|
|
94
|
+
});
|
|
95
|
+
if (payload.typ !== exports.TYP_INTERNAL) {
|
|
96
|
+
throw new Error('Wrong token class for internal verifier');
|
|
97
|
+
}
|
|
98
|
+
return payloadToAuthUser(payload);
|
|
99
|
+
}
|
|
33
100
|
function verifyHmac(userValue, signature) {
|
|
34
101
|
const config = getConfig();
|
|
102
|
+
if (!config.hmacSecret) {
|
|
103
|
+
throw new Error('HMAC not configured. Set hmacSecret in configureAuth().');
|
|
104
|
+
}
|
|
35
105
|
const expected = crypto_1.default
|
|
36
|
-
.createHmac('sha256', config.
|
|
106
|
+
.createHmac('sha256', config.hmacSecret)
|
|
37
107
|
.update(userValue)
|
|
38
108
|
.digest('hex');
|
|
39
|
-
|
|
109
|
+
const expectedBuf = Buffer.from(expected);
|
|
110
|
+
const actualBuf = Buffer.from(signature);
|
|
111
|
+
if (expectedBuf.length !== actualBuf.length)
|
|
112
|
+
return false;
|
|
113
|
+
return crypto_1.default.timingSafeEqual(expectedBuf, actualBuf);
|
|
40
114
|
}
|
|
41
115
|
/**
|
|
42
116
|
* Compute an HMAC signature for service-to-service calls. Pair the returned
|
|
@@ -44,47 +118,54 @@ function verifyHmac(userValue, signature) {
|
|
|
44
118
|
* the receiving side calls `verifyHmac` with the same pair.
|
|
45
119
|
*/
|
|
46
120
|
function signHmac(userValue, secret) {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
121
|
+
const hmacSecret = secret ?? getConfig().hmacSecret;
|
|
122
|
+
if (!hmacSecret) {
|
|
123
|
+
throw new Error('HMAC not configured. Set hmacSecret in configureAuth().');
|
|
124
|
+
}
|
|
125
|
+
return crypto_1.default.createHmac('sha256', hmacSecret).update(userValue).digest('hex');
|
|
52
126
|
}
|
|
53
127
|
function authenticateRequest(request) {
|
|
54
|
-
// Try JWT from Authorization header
|
|
128
|
+
// Try JWT from Authorization header (user session)
|
|
55
129
|
const authHeader = request.headers.get('authorization');
|
|
56
130
|
if (authHeader?.startsWith('Bearer ')) {
|
|
57
131
|
try {
|
|
58
|
-
return
|
|
132
|
+
return verifyUserJwt(authHeader.slice(7));
|
|
59
133
|
}
|
|
60
134
|
catch {
|
|
61
135
|
return null;
|
|
62
136
|
}
|
|
63
137
|
}
|
|
64
|
-
// Try JWT from cookie
|
|
138
|
+
// Try JWT from cookie (Remix/SSR path)
|
|
65
139
|
const cookies = request.headers.get('cookie') || '';
|
|
66
140
|
const authCookie = cookies.split(';').find(c => c.trim().startsWith('auth-token='));
|
|
67
141
|
if (authCookie) {
|
|
68
142
|
const token = authCookie.split('=')[1]?.trim();
|
|
69
143
|
if (token) {
|
|
70
144
|
try {
|
|
71
|
-
return
|
|
145
|
+
return verifyUserJwt(token);
|
|
72
146
|
}
|
|
73
147
|
catch {
|
|
74
148
|
return null;
|
|
75
149
|
}
|
|
76
150
|
}
|
|
77
151
|
}
|
|
78
|
-
// Try HMAC (service-to-service)
|
|
152
|
+
// Try HMAC (service-to-service). Only if hmacSecret is configured.
|
|
79
153
|
const internalUser = request.headers.get('x-internal-user');
|
|
80
154
|
const internalSig = request.headers.get('x-internal-signature');
|
|
81
|
-
if (internalUser && internalSig
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
155
|
+
if (internalUser && internalSig) {
|
|
156
|
+
try {
|
|
157
|
+
if (verifyHmac(internalUser, internalSig)) {
|
|
158
|
+
return {
|
|
159
|
+
id: 'internal',
|
|
160
|
+
email: internalUser,
|
|
161
|
+
name: 'Internal Service',
|
|
162
|
+
tenantId: request.headers.get('x-tenant-id') || 'default',
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// hmacSecret not configured — fall through
|
|
168
|
+
}
|
|
88
169
|
}
|
|
89
170
|
return null;
|
|
90
171
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CachedBootstrap } from './types.js';
|
|
2
|
+
export declare function readCache(cacheDir: string, appId: string): Promise<CachedBootstrap | null>;
|
|
3
|
+
export declare function writeCache(cacheDir: string, appId: string, entry: CachedBootstrap): Promise<void>;
|
|
4
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/bootstrap/cache.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAuBlD,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAkBjC;AAED,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,IAAI,CAAC,CAOf"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readCache = readCache;
|
|
4
|
+
exports.writeCache = writeCache;
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
/**
|
|
8
|
+
* Disk cache for the bootstrap discovery response. Used to make cold
|
|
9
|
+
* starts resilient when the platform discovery endpoint is briefly
|
|
10
|
+
* unreachable.
|
|
11
|
+
*
|
|
12
|
+
* Cache is per-app (keyed by appId so multiple apps in the same workdir
|
|
13
|
+
* don't collide). Atomic write via temp file + rename. File mode 0600 so
|
|
14
|
+
* the cache file is owner-only on POSIX systems.
|
|
15
|
+
*
|
|
16
|
+
* Format: JSON. Contains the discovery response and the auth public key
|
|
17
|
+
* PEM. Does NOT contain the per-app private key — that comes from the
|
|
18
|
+
* connection-string token at every boot.
|
|
19
|
+
*/
|
|
20
|
+
function cacheFilePath(cacheDir, appId) {
|
|
21
|
+
// Sanitize appId for filename safety: keep alphanumerics + dashes + dots,
|
|
22
|
+
// replace everything else with underscore.
|
|
23
|
+
const safeId = appId.replace(/[^a-zA-Z0-9.\-_]/g, '_');
|
|
24
|
+
return (0, node_path_1.join)(cacheDir, `bootstrap-${safeId}.json`);
|
|
25
|
+
}
|
|
26
|
+
async function readCache(cacheDir, appId) {
|
|
27
|
+
try {
|
|
28
|
+
const path = cacheFilePath(cacheDir, appId);
|
|
29
|
+
const raw = await node_fs_1.promises.readFile(path, 'utf-8');
|
|
30
|
+
const parsed = JSON.parse(raw);
|
|
31
|
+
if (typeof parsed?.fetchedAt !== 'string' ||
|
|
32
|
+
typeof parsed?.staleAt !== 'string' ||
|
|
33
|
+
!parsed?.discovery?.endpoints ||
|
|
34
|
+
typeof parsed?.authPublicKeyPem !== 'string') {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
return parsed;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// ENOENT, parse error, anything — fall back to fresh fetch
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function writeCache(cacheDir, appId, entry) {
|
|
45
|
+
const path = cacheFilePath(cacheDir, appId);
|
|
46
|
+
await node_fs_1.promises.mkdir((0, node_path_1.dirname)(path), { recursive: true });
|
|
47
|
+
// Atomic write: stage to temp, rename. Rename is atomic on POSIX.
|
|
48
|
+
const tmp = `${path}.tmp.${process.pid}`;
|
|
49
|
+
await node_fs_1.promises.writeFile(tmp, JSON.stringify(entry, null, 2), { mode: 0o600 });
|
|
50
|
+
await node_fs_1.promises.rename(tmp, path);
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/bootstrap/cache.ts"],"names":[],"mappings":";;AAyBA,8BAqBC;AAED,gCAWC;AA3DD,qCAAyC;AACzC,yCAA0C;AAG1C;;;;;;;;;;;;GAYG;AAEH,SAAS,aAAa,CAAC,QAAgB,EAAE,KAAa;IACpD,0EAA0E;IAC1E,2CAA2C;IAC3C,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;IACvD,OAAO,IAAA,gBAAI,EAAC,QAAQ,EAAE,aAAa,MAAM,OAAO,CAAC,CAAC;AACpD,CAAC;AAEM,KAAK,UAAU,SAAS,CAC7B,QAAgB,EAChB,KAAa;IAEb,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,MAAM,kBAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAC;QAClD,IACE,OAAO,MAAM,EAAE,SAAS,KAAK,QAAQ;YACrC,OAAO,MAAM,EAAE,OAAO,KAAK,QAAQ;YACnC,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS;YAC7B,OAAO,MAAM,EAAE,gBAAgB,KAAK,QAAQ,EAC5C,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,2DAA2D;QAC3D,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,UAAU,CAC9B,QAAgB,EAChB,KAAa,EACb,KAAsB;IAEtB,MAAM,IAAI,GAAG,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC5C,MAAM,kBAAE,CAAC,KAAK,CAAC,IAAA,mBAAO,EAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,kEAAkE;IAClE,MAAM,GAAG,GAAG,GAAG,IAAI,QAAQ,OAAO,CAAC,GAAG,EAAE,CAAC;IACzC,MAAM,kBAAE,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACzE,MAAM,kBAAE,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Third-party app bootstrap (PLAN-app-bootstrap.md PR2).
|
|
3
|
+
*
|
|
4
|
+
* `bootstrapFromToken({ appToken })` is the SINGLE platform-init call a
|
|
5
|
+
* third-party app needs at boot. Given a connection-string token, it:
|
|
6
|
+
*
|
|
7
|
+
* 1. Parses the token (sync, no network) → appId, platformUrl, privateKey
|
|
8
|
+
* 2. Fetches GET ${platformUrl}/registry/discovery (cached on success)
|
|
9
|
+
* 3. Fetches GET ${endpoints.authPublicKeyUrl} (the user JWT verification key)
|
|
10
|
+
* 4. Configures the SDK's auth, platform, and entity-identity layers
|
|
11
|
+
* 5. Schedules a background refresh at 80% of cacheTtlSeconds
|
|
12
|
+
*
|
|
13
|
+
* After this returns, the app can use `requireAuth()`, `verifyUserJwt()`,
|
|
14
|
+
* `publishEvent()`, the entity client, etc. exactly as if it had been
|
|
15
|
+
* configured via the legacy env-based path.
|
|
16
|
+
*
|
|
17
|
+
* Cache: discovery is cached to disk so cold starts survive a brief
|
|
18
|
+
* registry outage. The token itself is NOT cached — it lives in the env
|
|
19
|
+
* var. Cached entries are per-app and contain only public information
|
|
20
|
+
* (URLs and the auth public key PEM, no secrets).
|
|
21
|
+
*/
|
|
22
|
+
import { ANBY_TOKEN_PREFIX, type AnbyAppToken, type DiscoveryResponse } from './types.js';
|
|
23
|
+
export { ANBY_TOKEN_PREFIX, type AnbyAppToken, type DiscoveryResponse };
|
|
24
|
+
/** For tests: clears the module-level bootstrap state so a fresh
|
|
25
|
+
* bootstrapFromToken call re-runs from scratch. Not exported from the
|
|
26
|
+
* root barrel. */
|
|
27
|
+
export declare function _resetBootstrapForTests(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Returns the discovery response cached by the most recent successful
|
|
30
|
+
* bootstrapFromToken call. Throws if bootstrap has not yet started.
|
|
31
|
+
*
|
|
32
|
+
* Resolves the in-progress promise if bootstrap is still in flight, so
|
|
33
|
+
* callers can `await getDiscoveredEndpoints()` from anywhere safely.
|
|
34
|
+
*/
|
|
35
|
+
export declare function getDiscoveredEndpoints(): Promise<DiscoveryResponse['endpoints']>;
|
|
36
|
+
/**
|
|
37
|
+
* Returns the registry HOST root (e.g. "http://localhost:3003"), without
|
|
38
|
+
* the /registry path suffix. Use this for callers that already append
|
|
39
|
+
* /registry/... themselves (autoPublishOnBoot, RegistryPublicKeyVerifier).
|
|
40
|
+
*
|
|
41
|
+
* Falls back to discovery.endpoints.registryUrl with /registry stripped
|
|
42
|
+
* if the registryBaseUrl field is missing (older registries that haven't
|
|
43
|
+
* deployed PR3 yet).
|
|
44
|
+
*/
|
|
45
|
+
export declare function getDiscoveredRegistryBaseUrl(): Promise<string>;
|
|
46
|
+
export interface BootstrapOptions {
|
|
47
|
+
appToken: string;
|
|
48
|
+
/** Where to write the disk cache. Default: process.cwd() + "/.anby-cache". */
|
|
49
|
+
cacheDir?: string;
|
|
50
|
+
/** Override the discovery fetch (for tests). */
|
|
51
|
+
fetchImpl?: typeof fetch;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Parse an `anby_v1_<base64json>` token. Throws on malformed input.
|
|
55
|
+
*
|
|
56
|
+
* Sync, no network. Validates structure but does NOT verify the
|
|
57
|
+
* Ed25519 private key against any server — that happens later when the
|
|
58
|
+
* SDK tries to mint a scoped-token.
|
|
59
|
+
*/
|
|
60
|
+
export declare function parseAppToken(token: string): AnbyAppToken;
|
|
61
|
+
/**
|
|
62
|
+
* The single bootstrap entrypoint a third-party app calls at boot.
|
|
63
|
+
*
|
|
64
|
+
* Idempotent: if called multiple times in the same process (e.g. once
|
|
65
|
+
* from entry.server.tsx and again from a refresh timer), the second call
|
|
66
|
+
* returns the same in-flight promise instead of starting a parallel
|
|
67
|
+
* bootstrap.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* import { bootstrapFromToken, requireAuth } from '@anby/platform-sdk';
|
|
72
|
+
*
|
|
73
|
+
* await bootstrapFromToken({ appToken: process.env.ANBY_APP_TOKEN! });
|
|
74
|
+
*
|
|
75
|
+
* app.get('/api/widgets', requireAuth(), handler);
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export declare function bootstrapFromToken(opts: BootstrapOptions): Promise<void>;
|
|
79
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/bootstrap/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAQH,OAAO,EACL,iBAAiB,EACjB,KAAK,YAAY,EAEjB,KAAK,iBAAiB,EACvB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAE,CAAC;AAiBxE;;mBAEmB;AACnB,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CACrD,iBAAiB,CAAC,WAAW,CAAC,CAC/B,CAWA;AAED;;;;;;;;GAQG;AACH,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,MAAM,CAAC,CAKpE;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAkDzD;AA2CD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAaxE"}
|