latchkey 2.8.0 → 2.9.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/README.md +6 -0
- package/dist/src/cli.js +0 -0
- package/dist/src/cliCommands.d.ts +1 -1
- package/dist/src/cliCommands.d.ts.map +1 -1
- package/dist/src/config.d.ts +5 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +8 -0
- package/dist/src/config.js.map +1 -1
- package/dist/src/curlInjection.d.ts +1 -1
- package/dist/src/curlInjection.d.ts.map +1 -1
- package/dist/src/curlInjection.js +16 -1
- package/dist/src/curlInjection.js.map +1 -1
- package/dist/src/gateway/extensions.d.ts +59 -0
- package/dist/src/gateway/extensions.d.ts.map +1 -0
- package/dist/src/gateway/extensions.js +170 -0
- package/dist/src/gateway/extensions.js.map +1 -0
- package/dist/src/gateway/gatewayEndpoint.d.ts +11 -1
- package/dist/src/gateway/gatewayEndpoint.d.ts.map +1 -1
- package/dist/src/gateway/gatewayEndpoint.js +40 -39
- package/dist/src/gateway/gatewayEndpoint.js.map +1 -1
- package/dist/src/gateway/permissionsOverride.d.ts +9 -0
- package/dist/src/gateway/permissionsOverride.d.ts.map +1 -1
- package/dist/src/gateway/permissionsOverride.js +14 -0
- package/dist/src/gateway/permissionsOverride.js.map +1 -1
- package/dist/src/gateway/server.d.ts.map +1 -1
- package/dist/src/gateway/server.js +66 -14
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/permissions.d.ts +3 -6
- package/dist/src/permissions.d.ts.map +1 -1
- package/dist/src/permissions.js +6 -13
- package/dist/src/permissions.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/tests/cli.test.js +3 -0
- package/dist/tests/cli.test.js.map +1 -1
- package/dist/tests/gateway.test.js +14 -0
- package/dist/tests/gateway.test.js.map +1 -1
- package/dist/tests/gatewayExtensions.test.d.ts +2 -0
- package/dist/tests/gatewayExtensions.test.d.ts.map +1 -0
- package/dist/tests/gatewayExtensions.test.js +398 -0
- package/dist/tests/gatewayExtensions.test.js.map +1 -0
- package/dist/tests/permissions.test.js +14 -10
- package/dist/tests/permissions.test.js.map +1 -1
- package/package.json +1 -1
- package/dist/src/gateway/permissionPointer.d.ts +0 -56
- package/dist/src/gateway/permissionPointer.d.ts.map +0 -1
- package/dist/src/gateway/permissionPointer.js +0 -171
- package/dist/src/gateway/permissionPointer.js.map +0 -1
- package/dist/tests/encryptedStorageKeyGeneration.test.d.ts +0 -2
- package/dist/tests/encryptedStorageKeyGeneration.test.d.ts.map +0 -1
- package/dist/tests/encryptedStorageKeyGeneration.test.js +0 -23
- package/dist/tests/encryptedStorageKeyGeneration.test.js.map +0 -1
- package/dist/tests/permissionPointer.test.d.ts +0 -2
- package/dist/tests/permissionPointer.test.d.ts.map +0 -1
- package/dist/tests/permissionPointer.test.js +0 -152
- package/dist/tests/permissionPointer.test.js.map +0 -1
package/README.md
CHANGED
|
@@ -360,6 +360,12 @@ to the JWT and the CLI will attach it to every outgoing gateway
|
|
|
360
360
|
request automatically (analogous to `LATCHKEY_GATEWAY_PASSWORD`).
|
|
361
361
|
|
|
362
362
|
|
|
363
|
+
#### Extensions
|
|
364
|
+
|
|
365
|
+
You can extend the gateway with your own HTTP endpoints. For
|
|
366
|
+
details, see the [extensions docs](./docs/extensions.md).
|
|
367
|
+
|
|
368
|
+
|
|
363
369
|
### Other configuration
|
|
364
370
|
|
|
365
371
|
You can set these environment variables to override certain
|
package/dist/src/cli.js
CHANGED
|
File without changes
|
|
@@ -20,7 +20,7 @@ export interface CliDependencies {
|
|
|
20
20
|
readonly config: Config;
|
|
21
21
|
readonly runCurl: (args: readonly string[]) => CurlResult;
|
|
22
22
|
readonly runCurlAsync: typeof curlRunAsync;
|
|
23
|
-
readonly checkPermission: (
|
|
23
|
+
readonly checkPermission: (request: Request, configPath: string, doNotUseBuiltinSchemas: boolean) => Promise<boolean>;
|
|
24
24
|
readonly confirm: (message: string) => Promise<boolean>;
|
|
25
25
|
readonly exit: (code: number) => never;
|
|
26
26
|
readonly log: (message: string) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cliCommands.d.ts","sourceRoot":"","sources":["../../src/cliCommands.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoBzC,OAAO,EAAE,MAAM,EAAU,MAAM,aAAa,CAAC;AAQ7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAG5C,OAAO,EAGL,eAAe,EAGhB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,EAIL,QAAQ,IAAI,YAAY,EACzB,MAAM,WAAW,CAAC;AA8BnB;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,UAAU,CAAC;IAC1D,QAAQ,CAAC,YAAY,EAAE,OAAO,YAAY,CAAC;IAC3C,QAAQ,CAAC,eAAe,EAAE,CACxB,
|
|
1
|
+
{"version":3,"file":"cliCommands.d.ts","sourceRoot":"","sources":["../../src/cliCommands.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoBzC,OAAO,EAAE,MAAM,EAAU,MAAM,aAAa,CAAC;AAQ7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAG5C,OAAO,EAGL,eAAe,EAGhB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,EAIL,QAAQ,IAAI,YAAY,EACzB,MAAM,WAAW,CAAC;AA8BnB;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,UAAU,CAAC;IAC1D,QAAQ,CAAC,YAAY,EAAE,OAAO,YAAY,CAAC;IAC3C,QAAQ,CAAC,eAAe,EAAE,CACxB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,EAClB,sBAAsB,EAAE,OAAO,KAC5B,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC;IACvC,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,eAAe,CAiB3D;AAmID;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,GAAG,IAAI,CA8rB9E"}
|
package/dist/src/config.d.ts
CHANGED
|
@@ -105,6 +105,11 @@ export declare class Config {
|
|
|
105
105
|
get browserStatePath(): string;
|
|
106
106
|
get configPath(): string;
|
|
107
107
|
get permissionsConfigPath(): string;
|
|
108
|
+
/**
|
|
109
|
+
* Directory the gateway scans for extension modules at startup.
|
|
110
|
+
* See `src/gateway/extensions.ts`.
|
|
111
|
+
*/
|
|
112
|
+
get extensionsDirectoryPath(): string;
|
|
108
113
|
/**
|
|
109
114
|
* Check that sensitive files have secure permissions.
|
|
110
115
|
* Throws InsecureFilePermissionsError if any file is readable by group or others.
|
package/dist/src/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEnE,qBAAa,4BAA6B,SAAQ,KAAK;gBACzC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;CAOlD;AAED,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,6BAA8B,SAAQ,KAAK;gBAC1C,QAAQ,EAAE,MAAM;CAM7B;AAoBD,eAAO,MAAM,4BAA4B,aAAa,CAAC;AACvD,eAAO,MAAM,4BAA4B,mBAAmB,CAAC;AAC7D,eAAO,MAAM,2BAA2B,cAAc,CAAC;AACvD,eAAO,MAAM,2BAA2B,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEnE,qBAAa,4BAA6B,SAAQ,KAAK;gBACzC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;CAOlD;AAED,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,6BAA8B,SAAQ,KAAK;gBAC1C,QAAQ,EAAE,MAAM;CAM7B;AAoBD,eAAO,MAAM,4BAA4B,aAAa,CAAC;AACvD,eAAO,MAAM,4BAA4B,mBAAmB,CAAC;AAC7D,eAAO,MAAM,2BAA2B,cAAc,CAAC;AACvD,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAsGhD;;;;GAIG;AACH,qBAAa,MAAM;IACjB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC;;OAEG;IACH,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,yBAAyB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClD;;OAEG;IACH,QAAQ,CAAC,iCAAiC,EAAE,OAAO,CAAC;IACpD;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC;;;;OAIG;IACH,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC;;;;;;;;OAQG;IACH,QAAQ,CAAC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C;;;;;;;;OAQG;IACH,QAAQ,CAAC,0BAA0B,EAAE,MAAM,GAAG,IAAI,CAAC;gBAGjD,MAAM,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAuC,EAC1E,oBAAoB,GAAE,CAAC,UAAU,EAAE,MAAM,KAAK,QAAuB;IA2EvE,IAAI,mBAAmB,IAAI,MAAM,CAEhC;IAED,IAAI,gBAAgB,IAAI,MAAM,CAE7B;IAED,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,IAAI,qBAAqB,IAAI,MAAM,CAElC;IAED;;;OAGG;IACH,IAAI,uBAAuB,IAAI,MAAM,CAEpC;IAED;;;OAGG;IACH,6BAA6B,IAAI,IAAI;IAoBrC;;;OAGG;IACH,wBAAwB,IAAI,IAAI;CAKjC;AAED;;GAEG;AACH,eAAO,MAAM,MAAM,QAAe,CAAC"}
|
package/dist/src/config.js
CHANGED
|
@@ -49,6 +49,7 @@ const CREDENTIAL_STORE_FILENAME = 'credentials.json.enc';
|
|
|
49
49
|
const BROWSER_STATE_FILENAME = 'browser_state.json.enc';
|
|
50
50
|
const CONFIG_FILENAME = 'config.json';
|
|
51
51
|
const PERMISSIONS_CONFIG_FILENAME = 'permissions.json';
|
|
52
|
+
const EXTENSIONS_DIRECTORY_NAME = 'extensions';
|
|
52
53
|
function resolvePathWithTildeExpansion(path) {
|
|
53
54
|
if (path.startsWith('~')) {
|
|
54
55
|
return resolve(homedir(), path.slice(2));
|
|
@@ -260,6 +261,13 @@ export class Config {
|
|
|
260
261
|
get permissionsConfigPath() {
|
|
261
262
|
return this.permissionsConfigOverride ?? join(this.directory, PERMISSIONS_CONFIG_FILENAME);
|
|
262
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* Directory the gateway scans for extension modules at startup.
|
|
266
|
+
* See `src/gateway/extensions.ts`.
|
|
267
|
+
*/
|
|
268
|
+
get extensionsDirectoryPath() {
|
|
269
|
+
return join(this.directory, EXTENSIONS_DIRECTORY_NAME);
|
|
270
|
+
}
|
|
263
271
|
/**
|
|
264
272
|
* Check that sensitive files have secure permissions.
|
|
265
273
|
* Throws InsecureFilePermissionsError if any file is readable by group or others.
|
package/dist/src/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAAE,YAAY,EAAiB,MAAM,sBAAsB,CAAC;AAEnE,MAAM,OAAO,4BAA6B,SAAQ,KAAK;IACrD,YAAY,QAAgB,EAAE,WAAmB;QAC/C,MAAM,gBAAgB,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAClE,KAAK,CACH,QAAQ,QAAQ,8BAA8B,gBAAgB,qBAAqB,QAAQ,EAAE,CAC9F,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;IAC7C,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,WAAmB;QAC7B,KAAK,CAAC,IAAI,WAAW,0CAA0C,CAAC,CAAC;QACjE,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,MAAM,OAAO,6BAA8B,SAAQ,KAAK;IACtD,YAAY,QAAgB;QAC1B,KAAK,CACH,+CAA+C,QAAQ,4CAA4C,CACpG,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,+BAA+B,CAAC;IAC9C,CAAC;CACF;AAED,MAAM,0BAA0B,GAAG,oBAAoB,CAAC;AACxD,MAAM,qBAAqB,GAAG,eAAe,CAAC;AAC9C,MAAM,+BAA+B,GAAG,yBAAyB,CAAC;AAClE,MAAM,qCAAqC,GAAG,+BAA+B,CAAC;AAC9E,MAAM,qCAAqC,GAAG,+BAA+B,CAAC;AAC9E,MAAM,gCAAgC,GAAG,0BAA0B,CAAC;AACpE,MAAM,iCAAiC,GAAG,2BAA2B,CAAC;AACtE,MAAM,mCAAmC,GAAG,6BAA6B,CAAC;AAC1E,MAAM,uDAAuD,GAC3D,iDAAiD,CAAC;AACpD,MAAM,oCAAoC,GAAG,8BAA8B,CAAC;AAC5E,MAAM,wBAAwB,GAAG,kBAAkB,CAAC;AACpD,MAAM,oCAAoC,GAAG,8BAA8B,CAAC;AAC5E,MAAM,oCAAoC,GAAG,8BAA8B,CAAC;AAC5E,MAAM,iCAAiC,GAAG,2BAA2B,CAAC;AACtE,MAAM,wCAAwC,GAAG,kCAAkC,CAAC;AACpF,MAAM,6CAA6C,GAAG,uCAAuC,CAAC;AAE9F,MAAM,CAAC,MAAM,4BAA4B,GAAG,UAAU,CAAC;AACvD,MAAM,CAAC,MAAM,4BAA4B,GAAG,gBAAgB,CAAC;AAC7D,MAAM,CAAC,MAAM,2BAA2B,GAAG,WAAW,CAAC;AACvD,MAAM,CAAC,MAAM,2BAA2B,GAAG,IAAI,CAAC;AAEhD,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;AAEvD,MAAM,yBAAyB,GAAG,sBAAsB,CAAC;AACzD,MAAM,sBAAsB,GAAG,wBAAwB,CAAC;AACxD,MAAM,eAAe,GAAG,aAAa,CAAC;AACtC,MAAM,2BAA2B,GAAG,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,7 +31,7 @@ export declare class CredentialsExpiredError extends Error {
|
|
|
31
31
|
}
|
|
32
32
|
export interface CurlInjectionDependencies {
|
|
33
33
|
readonly registry: ServiceRegistry;
|
|
34
|
-
readonly checkPermission: (
|
|
34
|
+
readonly checkPermission: (request: Request, configPath: string, doNotUseBuiltinSchemas: boolean) => Promise<boolean>;
|
|
35
35
|
readonly permissionsConfigPath: string;
|
|
36
36
|
readonly permissionsDoNotUseBuiltinSchemas: boolean;
|
|
37
37
|
readonly passthroughUnknown: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"curlInjection.d.ts","sourceRoot":"","sources":["../../src/curlInjection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"curlInjection.d.ts","sourceRoot":"","sources":["../../src/curlInjection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAKpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,qBAAa,wBAAyB,SAAQ,KAAK;;CAKlD;AAED,qBAAa,wBAAyB,SAAQ,KAAK;gBACrC,MAAM,CAAC,EAAE,MAAM;CAQ5B;AAED,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;gBAET,GAAG,EAAE,MAAM;CAKxB;AAED,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;gBAEjB,WAAW,EAAE,MAAM;CAKhC;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;gBAEjB,WAAW,EAAE,MAAM;CAKhC;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,eAAe,EAAE,CACxB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,EAClB,sBAAsB,EAAE,OAAO,KAC5B,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC;IACvC,QAAQ,CAAC,iCAAiC,EAAE,OAAO,CAAC;IACpD,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;CACtC;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,kBAAkB,EAAE,kBAAkB,EACtC,YAAY,EAAE,yBAAyB,GACtC,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CA4D5B"}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { maybeRefreshCredentials } from './apiCredentials/utils.js';
|
|
13
13
|
import { CurlParseError, extractUrlFromCurlArguments } from './curl.js';
|
|
14
|
+
import { parseCurlArgs } from '@imbue-ai/detent';
|
|
14
15
|
import { ErrorMessages } from './errorMessages.js';
|
|
15
16
|
export class RequestNotPermittedError extends Error {
|
|
16
17
|
constructor() {
|
|
@@ -57,7 +58,21 @@ export class CredentialsExpiredError extends Error {
|
|
|
57
58
|
* underlying permission check).
|
|
58
59
|
*/
|
|
59
60
|
export async function prepareCurlInvocation(curlArguments, apiCredentialStore, dependencies) {
|
|
60
|
-
|
|
61
|
+
// Parse the curl arguments once for the permission check. A parse failure
|
|
62
|
+
// here means the user's curl invocation is malformed, which is treated as
|
|
63
|
+
// a URL-extraction failure (the same category as the second parse below),
|
|
64
|
+
// not a permission-check failure.
|
|
65
|
+
let parsedRequest;
|
|
66
|
+
try {
|
|
67
|
+
parsedRequest = parseCurlArgs(curlArguments);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (error instanceof CurlParseError) {
|
|
71
|
+
throw new UrlExtractionFailedError(error.message);
|
|
72
|
+
}
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
const allowed = await dependencies.checkPermission(parsedRequest, dependencies.permissionsConfigPath, dependencies.permissionsDoNotUseBuiltinSchemas);
|
|
61
76
|
if (!allowed) {
|
|
62
77
|
throw new RequestNotPermittedError();
|
|
63
78
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"curlInjection.js","sourceRoot":"","sources":["../../src/curlInjection.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"curlInjection.js","sourceRoot":"","sources":["../../src/curlInjection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,2BAA2B,EAAE,MAAM,WAAW,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACjD;QACE,KAAK,CAAC,aAAa,CAAC,mBAAmB,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACjD,YAAY,MAAe;QACzB,KAAK,CACH,MAAM,KAAK,SAAS;YAClB,CAAC,CAAC,aAAa,CAAC,kBAAkB;YAClC,CAAC,CAAC,GAAG,aAAa,CAAC,uBAAuB,IAAI,MAAM,EAAE,CACzD,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IACpC,GAAG,CAAS;IAErB,YAAY,GAAW;QACrB,KAAK,CAAC,aAAa,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;CACF;AAED,MAAM,OAAO,4BAA6B,SAAQ,KAAK;IAC5C,WAAW,CAAS;IAE7B,YAAY,WAAmB;QAC7B,KAAK,CAAC,aAAa,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC,CAAC;QACrD,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;QAC3C,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;CACF;AAED,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IACvC,WAAW,CAAS;IAE7B,YAAY,WAAmB;QAC7B,KAAK,CAAC,aAAa,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC,CAAC;QACrD,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;QACtC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;CACF;AAcD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,aAAgC,EAChC,kBAAsC,EACtC,YAAuC;IAEvC,0EAA0E;IAC1E,0EAA0E;IAC1E,0EAA0E;IAC1E,kCAAkC;IAClC,IAAI,aAAsB,CAAC;IAC3B,IAAI,CAAC;QACH,aAAa,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,cAAc,EAAE,CAAC;YACpC,MAAM,IAAI,wBAAwB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACpD,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,eAAe,CAChD,aAAa,EACb,YAAY,CAAC,qBAAqB,EAClC,YAAY,CAAC,iCAAiC,CAC/C,CAAC;IACF,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,wBAAwB,EAAE,CAAC;IACvC,CAAC;IAED,IAAI,GAAkB,CAAC;IACvB,IAAI,CAAC;QACH,GAAG,GAAG,2BAA2B,CAAC,aAAa,CAAC,CAAC;IACnD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,cAAc,EAAE,CAAC;YACpC,MAAM,IAAI,wBAAwB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACpD,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IACD,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACjB,MAAM,IAAI,wBAAwB,EAAE,CAAC;IACvC,CAAC;IAED,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACpD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,IAAI,YAAY,CAAC,kBAAkB,EAAE,CAAC;YACpC,OAAO,CAAC,GAAG,aAAa,CAAC,CAAC;QAC5B,CAAC;QACD,MAAM,IAAI,oBAAoB,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,cAAc,GAA0B,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjF,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;QAC5B,IAAI,YAAY,CAAC,kBAAkB,EAAE,CAAC;YACpC,OAAO,CAAC,GAAG,aAAa,CAAC,CAAC;QAC5B,CAAC;QACD,MAAM,IAAI,4BAA4B,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,cAAc,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE,CAAC;QACxC,cAAc,GAAG,MAAM,uBAAuB,CAAC,OAAO,EAAE,cAAc,EAAE,kBAAkB,CAAC,CAAC;QAC5F,IAAI,cAAc,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE,CAAC;YACxC,MAAM,IAAI,uBAAuB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,OAAO,MAAM,cAAc,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extensions: user-supplied HTTP handlers mounted on the gateway.
|
|
3
|
+
*
|
|
4
|
+
* The gateway scans `extensionsDirectory` for `*.mjs` files at startup
|
|
5
|
+
* and dynamically imports each one. Each module's default export must be
|
|
6
|
+
* a function `(request, response) => boolean | Promise<boolean>`:
|
|
7
|
+
*
|
|
8
|
+
* - return `true` when the extension has handled the request (i.e. it
|
|
9
|
+
* has written / will write the response). The gateway will not consult
|
|
10
|
+
* any further extensions.
|
|
11
|
+
* - return `false` to defer to the next extension. The handler must not
|
|
12
|
+
* touch the response in this case.
|
|
13
|
+
*
|
|
14
|
+
* Extensions only see Node's raw HTTP request / response. They do NOT have
|
|
15
|
+
* access to credential storage, the curl-injection pipeline, or the service
|
|
16
|
+
* registry. Each extension request is run through the same
|
|
17
|
+
* `permissions.json` machinery as `/gateway/...` proxy requests, by
|
|
18
|
+
* synthesising a request whose URL uses fixed placeholder values
|
|
19
|
+
* (representing "this gateway") while preserving the inbound method, path,
|
|
20
|
+
* and headers.
|
|
21
|
+
*/
|
|
22
|
+
import * as http from 'node:http';
|
|
23
|
+
import type { CliDependencies } from '../cliCommands.js';
|
|
24
|
+
/**
|
|
25
|
+
* Placeholder URL parts that stand in for "this gateway" when extension
|
|
26
|
+
* requests are run through the permission check. They use RFC 2606's
|
|
27
|
+
* reserved `.invalid` TLD so the synthetic URL is guaranteed never to
|
|
28
|
+
* resolve to a real host. Detent schemas matching extension routes should
|
|
29
|
+
* key on these exact values.
|
|
30
|
+
*/
|
|
31
|
+
export declare const EXTENSION_PLACEHOLDER_SCHEME = "https";
|
|
32
|
+
export declare const EXTENSION_PLACEHOLDER_HOST = "latchkey-self.invalid";
|
|
33
|
+
export declare const EXTENSION_PLACEHOLDER_PORT = 1;
|
|
34
|
+
export type ExtensionHandler = (request: http.IncomingMessage, response: http.ServerResponse) => boolean | Promise<boolean>;
|
|
35
|
+
export interface LoadedExtension {
|
|
36
|
+
readonly handler: ExtensionHandler;
|
|
37
|
+
/** Absolute path of the file the handler was loaded from. */
|
|
38
|
+
readonly sourceFile: string;
|
|
39
|
+
}
|
|
40
|
+
export declare class ExtensionLoadError extends Error {
|
|
41
|
+
constructor(message: string);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Load every extension module in `directory` and return the resulting
|
|
45
|
+
* ordered list. Extensions are tried in alphabetical order of filename, so
|
|
46
|
+
* the loader returns them in that order. Returns an empty list if the
|
|
47
|
+
* directory does not exist. Throws `ExtensionLoadError` on the first file
|
|
48
|
+
* that fails to import or has the wrong shape.
|
|
49
|
+
*/
|
|
50
|
+
export declare function loadExtensions(directory: string): Promise<readonly LoadedExtension[]>;
|
|
51
|
+
/**
|
|
52
|
+
* Run the permission check for an inbound extension request and offer it to
|
|
53
|
+
* each loaded extension in order. Returns true when an extension claimed
|
|
54
|
+
* the request (i.e. responded or threw). When false, no extension touched
|
|
55
|
+
* the response and the caller is responsible for sending a fallback
|
|
56
|
+
* (typically `404`).
|
|
57
|
+
*/
|
|
58
|
+
export declare function dispatchExtensionRequest(request: http.IncomingMessage, response: http.ServerResponse, extensions: readonly LoadedExtension[], deps: CliDependencies, permissionsConfigPath: string): Promise<boolean>;
|
|
59
|
+
//# sourceMappingURL=extensions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extensions.d.ts","sourceRoot":"","sources":["../../../src/gateway/extensions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAIlC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAKzD;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,UAAU,CAAC;AACpD,eAAO,MAAM,0BAA0B,0BAA0B,CAAC;AAClE,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAI5C,MAAM,MAAM,gBAAgB,GAAG,CAC7B,OAAO,EAAE,IAAI,CAAC,eAAe,EAC7B,QAAQ,EAAE,IAAI,CAAC,cAAc,KAC1B,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,6DAA6D;IAC7D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAMD,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAWD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC,CAiC3F;AA0CD;;;;;;GAMG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,IAAI,CAAC,eAAe,EAC7B,QAAQ,EAAE,IAAI,CAAC,cAAc,EAC7B,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,IAAI,EAAE,eAAe,EACrB,qBAAqB,EAAE,MAAM,GAC5B,OAAO,CAAC,OAAO,CAAC,CA6ClB"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extensions: user-supplied HTTP handlers mounted on the gateway.
|
|
3
|
+
*
|
|
4
|
+
* The gateway scans `extensionsDirectory` for `*.mjs` files at startup
|
|
5
|
+
* and dynamically imports each one. Each module's default export must be
|
|
6
|
+
* a function `(request, response) => boolean | Promise<boolean>`:
|
|
7
|
+
*
|
|
8
|
+
* - return `true` when the extension has handled the request (i.e. it
|
|
9
|
+
* has written / will write the response). The gateway will not consult
|
|
10
|
+
* any further extensions.
|
|
11
|
+
* - return `false` to defer to the next extension. The handler must not
|
|
12
|
+
* touch the response in this case.
|
|
13
|
+
*
|
|
14
|
+
* Extensions only see Node's raw HTTP request / response. They do NOT have
|
|
15
|
+
* access to credential storage, the curl-injection pipeline, or the service
|
|
16
|
+
* registry. Each extension request is run through the same
|
|
17
|
+
* `permissions.json` machinery as `/gateway/...` proxy requests, by
|
|
18
|
+
* synthesising a request whose URL uses fixed placeholder values
|
|
19
|
+
* (representing "this gateway") while preserving the inbound method, path,
|
|
20
|
+
* and headers.
|
|
21
|
+
*/
|
|
22
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
23
|
+
import { join } from 'node:path';
|
|
24
|
+
import { pathToFileURL } from 'node:url';
|
|
25
|
+
import { PermissionCheckError } from '../permissions.js';
|
|
26
|
+
import { RequestNotPermittedError } from '../curlInjection.js';
|
|
27
|
+
import { GATEWAY_INTERNAL_HEADERS, HOP_BY_HOP_HEADERS } from './gatewayEndpoint.js';
|
|
28
|
+
/**
|
|
29
|
+
* Placeholder URL parts that stand in for "this gateway" when extension
|
|
30
|
+
* requests are run through the permission check. They use RFC 2606's
|
|
31
|
+
* reserved `.invalid` TLD so the synthetic URL is guaranteed never to
|
|
32
|
+
* resolve to a real host. Detent schemas matching extension routes should
|
|
33
|
+
* key on these exact values.
|
|
34
|
+
*/
|
|
35
|
+
export const EXTENSION_PLACEHOLDER_SCHEME = 'https';
|
|
36
|
+
export const EXTENSION_PLACEHOLDER_HOST = 'latchkey-self.invalid';
|
|
37
|
+
export const EXTENSION_PLACEHOLDER_PORT = 1;
|
|
38
|
+
const EXTENSION_FILE_SUFFIX = '.mjs';
|
|
39
|
+
export class ExtensionLoadError extends Error {
|
|
40
|
+
constructor(message) {
|
|
41
|
+
super(message);
|
|
42
|
+
this.name = 'ExtensionLoadError';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function isExtensionModuleShape(value) {
|
|
46
|
+
return (typeof value === 'object' &&
|
|
47
|
+
value !== null &&
|
|
48
|
+
'default' in value &&
|
|
49
|
+
typeof value.default === 'function');
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Load every extension module in `directory` and return the resulting
|
|
53
|
+
* ordered list. Extensions are tried in alphabetical order of filename, so
|
|
54
|
+
* the loader returns them in that order. Returns an empty list if the
|
|
55
|
+
* directory does not exist. Throws `ExtensionLoadError` on the first file
|
|
56
|
+
* that fails to import or has the wrong shape.
|
|
57
|
+
*/
|
|
58
|
+
export async function loadExtensions(directory) {
|
|
59
|
+
if (!existsSync(directory)) {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
if (!statSync(directory).isDirectory()) {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
const fileNames = readdirSync(directory, { withFileTypes: true })
|
|
66
|
+
.filter((entry) => entry.isFile())
|
|
67
|
+
.filter((entry) => entry.name.endsWith(EXTENSION_FILE_SUFFIX))
|
|
68
|
+
.map((entry) => entry.name)
|
|
69
|
+
.sort();
|
|
70
|
+
const extensions = [];
|
|
71
|
+
for (const fileName of fileNames) {
|
|
72
|
+
const filePath = join(directory, fileName);
|
|
73
|
+
let importedModule;
|
|
74
|
+
try {
|
|
75
|
+
importedModule = (await import(pathToFileURL(filePath).href));
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
79
|
+
throw new ExtensionLoadError(`Failed to load extension '${filePath}': ${message}`);
|
|
80
|
+
}
|
|
81
|
+
if (!isExtensionModuleShape(importedModule)) {
|
|
82
|
+
throw new ExtensionLoadError(`Extension '${filePath}' must export a default function ` +
|
|
83
|
+
`(request, response) => boolean | Promise<boolean>.`);
|
|
84
|
+
}
|
|
85
|
+
extensions.push({ handler: importedModule.default, sourceFile: filePath });
|
|
86
|
+
}
|
|
87
|
+
return extensions;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Build the synthetic `Request` fed to the permission check. The URL uses
|
|
91
|
+
* fixed placeholder values for protocol/host/port (representing "this
|
|
92
|
+
* gateway") with the inbound path and query string preserved verbatim. The
|
|
93
|
+
* inbound method and headers are forwarded, minus hop-by-hop and
|
|
94
|
+
* gateway-internal headers (so the password and permissions-override
|
|
95
|
+
* headers cannot influence schema matching). The body is intentionally
|
|
96
|
+
* omitted: the permission check operates on URL/method/headers only.
|
|
97
|
+
*/
|
|
98
|
+
function buildExtensionPermissionCheckRequest(request) {
|
|
99
|
+
const url = `${EXTENSION_PLACEHOLDER_SCHEME}://${EXTENSION_PLACEHOLDER_HOST}` +
|
|
100
|
+
`:${String(EXTENSION_PLACEHOLDER_PORT)}${request.url ?? ''}`;
|
|
101
|
+
const headers = new Headers();
|
|
102
|
+
const rawHeaders = request.rawHeaders;
|
|
103
|
+
for (let index = 0; index < rawHeaders.length; index += 2) {
|
|
104
|
+
const name = rawHeaders[index];
|
|
105
|
+
const value = rawHeaders[index + 1];
|
|
106
|
+
const lowerName = name.toLowerCase();
|
|
107
|
+
if (HOP_BY_HOP_HEADERS.has(lowerName) || GATEWAY_INTERNAL_HEADERS.has(lowerName)) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
headers.append(name, value);
|
|
111
|
+
}
|
|
112
|
+
return new Request(url, {
|
|
113
|
+
method: (request.method ?? 'GET').toUpperCase(),
|
|
114
|
+
headers,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
function sendErrorResponse(response, statusCode, message) {
|
|
118
|
+
if (response.headersSent)
|
|
119
|
+
return;
|
|
120
|
+
response.writeHead(statusCode, { 'Content-Type': 'application/json' });
|
|
121
|
+
response.end(JSON.stringify({ error: message }));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Run the permission check for an inbound extension request and offer it to
|
|
125
|
+
* each loaded extension in order. Returns true when an extension claimed
|
|
126
|
+
* the request (i.e. responded or threw). When false, no extension touched
|
|
127
|
+
* the response and the caller is responsible for sending a fallback
|
|
128
|
+
* (typically `404`).
|
|
129
|
+
*/
|
|
130
|
+
export async function dispatchExtensionRequest(request, response, extensions, deps, permissionsConfigPath) {
|
|
131
|
+
const method = (request.method ?? 'GET').toUpperCase();
|
|
132
|
+
const pathAndQuery = request.url ?? '';
|
|
133
|
+
let allowed;
|
|
134
|
+
try {
|
|
135
|
+
allowed = await deps.checkPermission(buildExtensionPermissionCheckRequest(request), permissionsConfigPath, deps.config.permissionsDoNotUseBuiltinSchemas);
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
if (error instanceof PermissionCheckError) {
|
|
139
|
+
deps.log(`${method} ${pathAndQuery} -> 403 (extension)`);
|
|
140
|
+
sendErrorResponse(response, 403, `Error: ${error.message}`);
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
if (!allowed) {
|
|
146
|
+
const notPermitted = new RequestNotPermittedError();
|
|
147
|
+
deps.log(`${method} ${pathAndQuery} -> 403 (extension)`);
|
|
148
|
+
sendErrorResponse(response, 403, notPermitted.message);
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
for (const extension of extensions) {
|
|
152
|
+
let handled;
|
|
153
|
+
try {
|
|
154
|
+
handled = await extension.handler(request, response);
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
158
|
+
deps.errorLog(`Unexpected error in extension '${extension.sourceFile}' ` +
|
|
159
|
+
`(${method} ${pathAndQuery}): ${message}`);
|
|
160
|
+
sendErrorResponse(response, 500, 'Internal error');
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
if (handled) {
|
|
164
|
+
deps.log(`${method} ${pathAndQuery} -> ${String(response.statusCode)} (extension)`);
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=extensions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extensions.js","sourceRoot":"","sources":["../../../src/gateway/extensions.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,15 @@
|
|
|
8
8
|
import * as http from 'node:http';
|
|
9
9
|
import type { ApiCredentialStore } from '../apiCredentials/store.js';
|
|
10
10
|
import type { CliDependencies } from '../cliCommands.js';
|
|
11
|
+
/**
|
|
12
|
+
* Headers that should not be forwarded between client and upstream (hop-by-hop).
|
|
13
|
+
*/
|
|
14
|
+
export declare const HOP_BY_HOP_HEADERS: ReadonlySet<string>;
|
|
15
|
+
/**
|
|
16
|
+
* Headers that the gateway consumes itself and must not forward to upstream
|
|
17
|
+
* (in addition to hop-by-hop headers).
|
|
18
|
+
*/
|
|
19
|
+
export declare const GATEWAY_INTERNAL_HEADERS: ReadonlySet<string>;
|
|
11
20
|
export declare const GATEWAY_PATH_PREFIX = "/gateway/";
|
|
12
21
|
export declare class BodyTooLargeError extends Error {
|
|
13
22
|
constructor();
|
|
@@ -36,7 +45,8 @@ export interface GatewayOptions {
|
|
|
36
45
|
export declare function extractTargetUrl(rawUrl: string): string | null;
|
|
37
46
|
/**
|
|
38
47
|
* Build curl arguments from an HTTP request's components.
|
|
39
|
-
*
|
|
48
|
+
*
|
|
49
|
+
* Hop-by-hop headers and gateway-internal headers are stripped.
|
|
40
50
|
*/
|
|
41
51
|
export declare function buildCurlArguments(method: string, headers: ReadonlyMap<string, string>, targetUrl: string, hasBody: boolean): readonly string[];
|
|
42
52
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gatewayEndpoint.d.ts","sourceRoot":"","sources":["../../../src/gateway/gatewayEndpoint.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAIlC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAErE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"gatewayEndpoint.d.ts","sourceRoot":"","sources":["../../../src/gateway/gatewayEndpoint.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAIlC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAErE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAmBzD;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAUjD,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,wBAAwB,EAAE,WAAW,CAAC,MAAM,CAGvD,CAAC;AAEH,eAAO,MAAM,mBAAmB,cAAc,CAAC;AAE/C,qBAAa,iBAAkB,SAAQ,KAAK;;CAK3C;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,6BAA6B,EAAE,MAAM,CAAC;CAChD;AAwBD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAU9D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,GACf,SAAS,MAAM,EAAE,CAsBnB;AAcD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG;IACxD,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;CACjD,CAiCA;AAkED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,IAAI,CAAC,eAAe,EAC7B,QAAQ,EAAE,IAAI,CAAC,cAAc,EAC7B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,eAAe,EACrB,kBAAkB,EAAE,kBAAkB,EACtC,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CAmJf"}
|
|
@@ -12,11 +12,11 @@ import { CredentialsExpiredError, NoCredentialsForServiceError, NoServiceForUrlE
|
|
|
12
12
|
import { PermissionCheckError } from '../permissions.js';
|
|
13
13
|
import { ErrorMessages } from '../errorMessages.js';
|
|
14
14
|
import { GATEWAY_PASSWORD_HEADER } from './password.js';
|
|
15
|
-
import { InvalidPermissionsOverrideError, PERMISSIONS_OVERRIDE_HEADER, PermissionsOverrideFileMissingError,
|
|
15
|
+
import { InvalidPermissionsOverrideError, PERMISSIONS_OVERRIDE_HEADER, PermissionsOverrideFileMissingError, resolveRequestPermissionsConfig, } from './permissionsOverride.js';
|
|
16
16
|
/**
|
|
17
17
|
* Headers that should not be forwarded between client and upstream (hop-by-hop).
|
|
18
18
|
*/
|
|
19
|
-
const HOP_BY_HOP_HEADERS = new Set([
|
|
19
|
+
export const HOP_BY_HOP_HEADERS = new Set([
|
|
20
20
|
'connection',
|
|
21
21
|
'keep-alive',
|
|
22
22
|
'proxy-authenticate',
|
|
@@ -31,7 +31,10 @@ const HOP_BY_HOP_HEADERS = new Set([
|
|
|
31
31
|
* Headers that the gateway consumes itself and must not forward to upstream
|
|
32
32
|
* (in addition to hop-by-hop headers).
|
|
33
33
|
*/
|
|
34
|
-
const GATEWAY_INTERNAL_HEADERS = new Set([
|
|
34
|
+
export const GATEWAY_INTERNAL_HEADERS = new Set([
|
|
35
|
+
GATEWAY_PASSWORD_HEADER,
|
|
36
|
+
PERMISSIONS_OVERRIDE_HEADER,
|
|
37
|
+
]);
|
|
35
38
|
export const GATEWAY_PATH_PREFIX = '/gateway/';
|
|
36
39
|
export class BodyTooLargeError extends Error {
|
|
37
40
|
constructor() {
|
|
@@ -73,7 +76,8 @@ export function extractTargetUrl(rawUrl) {
|
|
|
73
76
|
}
|
|
74
77
|
/**
|
|
75
78
|
* Build curl arguments from an HTTP request's components.
|
|
76
|
-
*
|
|
79
|
+
*
|
|
80
|
+
* Hop-by-hop headers and gateway-internal headers are stripped.
|
|
77
81
|
*/
|
|
78
82
|
export function buildCurlArguments(method, headers, targetUrl, hasBody) {
|
|
79
83
|
const args = [];
|
|
@@ -81,7 +85,8 @@ export function buildCurlArguments(method, headers, targetUrl, hasBody) {
|
|
|
81
85
|
args.push('-X', method);
|
|
82
86
|
}
|
|
83
87
|
for (const [name, value] of headers) {
|
|
84
|
-
|
|
88
|
+
const lowerName = name.toLowerCase();
|
|
89
|
+
if (HOP_BY_HOP_HEADERS.has(lowerName) || GATEWAY_INTERNAL_HEADERS.has(lowerName)) {
|
|
85
90
|
continue;
|
|
86
91
|
}
|
|
87
92
|
args.push('-H', `${name}: ${value}`);
|
|
@@ -92,6 +97,17 @@ export function buildCurlArguments(method, headers, targetUrl, hasBody) {
|
|
|
92
97
|
args.push(targetUrl);
|
|
93
98
|
return args;
|
|
94
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Build a `Map<string, string>` view of an `IncomingMessage`'s `rawHeaders`,
|
|
102
|
+
* preserving original case.
|
|
103
|
+
*/
|
|
104
|
+
function rawHeadersToMap(rawHeaders) {
|
|
105
|
+
const map = new Map();
|
|
106
|
+
for (let index = 0; index < rawHeaders.length; index += 2) {
|
|
107
|
+
map.set(rawHeaders[index], rawHeaders[index + 1]);
|
|
108
|
+
}
|
|
109
|
+
return map;
|
|
110
|
+
}
|
|
95
111
|
/**
|
|
96
112
|
* Parse response headers from curl's -D output.
|
|
97
113
|
* Returns the status code from the last status line and all response headers.
|
|
@@ -187,27 +203,23 @@ export async function handleGatewayRequest(request, response, targetUrl, deps, a
|
|
|
187
203
|
// Resolve the permissions config for this request. When the client
|
|
188
204
|
// supplied a permissions-override JWT, validate it and use the referenced
|
|
189
205
|
// file; otherwise fall back to the gateway's default config path.
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
206
|
+
let permissionsConfigPath;
|
|
207
|
+
try {
|
|
208
|
+
permissionsConfigPath = resolveRequestPermissionsConfig(request.headers, deps.config.permissionsConfigPath, options.permissionsOverrideSigningKey);
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
const method = request.method ?? 'UNKNOWN';
|
|
212
|
+
if (error instanceof InvalidPermissionsOverrideError) {
|
|
213
|
+
deps.log(`${method} ${targetUrl} -> 401 (permissions override)`);
|
|
214
|
+
sendErrorResponse(response, 401, error.message);
|
|
215
|
+
return;
|
|
196
216
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
sendErrorResponse(response, 401, error.message);
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
if (error instanceof PermissionsOverrideFileMissingError) {
|
|
205
|
-
deps.log(`${method} ${targetUrl} -> 400 (permissions override)`);
|
|
206
|
-
sendErrorResponse(response, 400, error.message);
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
throw error;
|
|
217
|
+
if (error instanceof PermissionsOverrideFileMissingError) {
|
|
218
|
+
deps.log(`${method} ${targetUrl} -> 400 (permissions override)`);
|
|
219
|
+
sendErrorResponse(response, 400, error.message);
|
|
220
|
+
return;
|
|
210
221
|
}
|
|
222
|
+
throw error;
|
|
211
223
|
}
|
|
212
224
|
// Read body
|
|
213
225
|
let body;
|
|
@@ -223,22 +235,11 @@ export async function handleGatewayRequest(request, response, targetUrl, deps, a
|
|
|
223
235
|
}
|
|
224
236
|
throw error;
|
|
225
237
|
}
|
|
226
|
-
// Build curl arguments from the incoming request
|
|
227
|
-
//
|
|
228
|
-
// the
|
|
238
|
+
// Build curl arguments from the incoming request. `buildCurlArguments`
|
|
239
|
+
// strips hop-by-hop and gateway-internal headers itself, so we just hand
|
|
240
|
+
// it the raw header map.
|
|
229
241
|
const method = request.method ?? 'GET';
|
|
230
|
-
const
|
|
231
|
-
const rawHeaders = request.rawHeaders;
|
|
232
|
-
for (let i = 0; i < rawHeaders.length; i += 2) {
|
|
233
|
-
const name = rawHeaders[i];
|
|
234
|
-
const value = rawHeaders[i + 1];
|
|
235
|
-
const lowerName = name.toLowerCase();
|
|
236
|
-
if (HOP_BY_HOP_HEADERS.has(lowerName) || GATEWAY_INTERNAL_HEADERS.has(lowerName)) {
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
headerMap.set(name, value);
|
|
240
|
-
}
|
|
241
|
-
const curlArguments = buildCurlArguments(method, headerMap, targetUrl, body !== null);
|
|
242
|
+
const curlArguments = buildCurlArguments(method, rawHeadersToMap(request.rawHeaders), targetUrl, body !== null);
|
|
242
243
|
let allArguments;
|
|
243
244
|
try {
|
|
244
245
|
allArguments = await prepareCurlInvocation(curlArguments, apiCredentialStore, {
|