latchkey 2.7.3 → 2.8.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 +49 -5
- package/dist/scripts/cryptFile.js +2 -2
- package/dist/scripts/cryptFile.js.map +1 -1
- package/dist/scripts/recordBrowserSession.js +3 -2
- package/dist/scripts/recordBrowserSession.js.map +1 -1
- package/dist/src/cli.js +5 -4
- package/dist/src/cli.js.map +1 -1
- package/dist/src/cliCommands.d.ts.map +1 -1
- package/dist/src/cliCommands.js +44 -6
- package/dist/src/cliCommands.js.map +1 -1
- package/dist/src/config.d.ts +29 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +45 -0
- package/dist/src/config.js.map +1 -1
- package/dist/src/encryptedStorage.d.ts +9 -25
- package/dist/src/encryptedStorage.d.ts.map +1 -1
- package/dist/src/encryptedStorage.js +9 -52
- package/dist/src/encryptedStorage.js.map +1 -1
- package/dist/src/encryption.d.ts +45 -0
- package/dist/src/encryption.d.ts.map +1 -1
- package/dist/src/encryption.js +69 -0
- package/dist/src/encryption.js.map +1 -1
- package/dist/src/gateway/client.d.ts +12 -2
- package/dist/src/gateway/client.d.ts.map +1 -1
- package/dist/src/gateway/client.js +31 -4
- package/dist/src/gateway/client.js.map +1 -1
- package/dist/src/gateway/gatewayEndpoint.d.ts +11 -0
- package/dist/src/gateway/gatewayEndpoint.d.ts.map +1 -1
- package/dist/src/gateway/gatewayEndpoint.js +40 -4
- package/dist/src/gateway/gatewayEndpoint.js.map +1 -1
- package/dist/src/gateway/password.d.ts +16 -0
- package/dist/src/gateway/password.d.ts.map +1 -0
- package/dist/src/gateway/password.js +24 -0
- package/dist/src/gateway/password.js.map +1 -0
- package/dist/src/gateway/permissionPointer.d.ts +56 -0
- package/dist/src/gateway/permissionPointer.d.ts.map +1 -0
- package/dist/src/gateway/permissionPointer.js +171 -0
- package/dist/src/gateway/permissionPointer.js.map +1 -0
- package/dist/src/gateway/permissionsOverride.d.ts +56 -0
- package/dist/src/gateway/permissionsOverride.d.ts.map +1 -0
- package/dist/src/gateway/permissionsOverride.js +157 -0
- package/dist/src/gateway/permissionsOverride.js.map +1 -0
- package/dist/src/gateway/server.d.ts.map +1 -1
- package/dist/src/gateway/server.js +34 -1
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/oauthUtils.d.ts +11 -2
- package/dist/src/oauthUtils.d.ts.map +1 -1
- package/dist/src/oauthUtils.js +25 -4
- package/dist/src/oauthUtils.js.map +1 -1
- package/dist/src/serviceRegistry.d.ts.map +1 -1
- package/dist/src/serviceRegistry.js +2 -1
- package/dist/src/serviceRegistry.js.map +1 -1
- package/dist/src/services/index.d.ts +1 -0
- package/dist/src/services/index.d.ts.map +1 -1
- package/dist/src/services/index.js +1 -0
- package/dist/src/services/index.js.map +1 -1
- package/dist/src/services/notion-mcp.d.ts +29 -0
- package/dist/src/services/notion-mcp.d.ts.map +1 -0
- package/dist/src/services/notion-mcp.js +156 -0
- package/dist/src/services/notion-mcp.js.map +1 -0
- package/dist/src/services/notion.d.ts.map +1 -1
- package/dist/src/services/notion.js +3 -2
- package/dist/src/services/notion.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/tests/apiCredentialStore.test.js +2 -2
- package/dist/tests/apiCredentialStore.test.js.map +1 -1
- package/dist/tests/cli.test.js +95 -53
- package/dist/tests/cli.test.js.map +1 -1
- package/dist/tests/config.test.js +37 -0
- package/dist/tests/config.test.js.map +1 -1
- package/dist/tests/encryptedStorage.test.js +19 -39
- package/dist/tests/encryptedStorage.test.js.map +1 -1
- package/dist/tests/encryptedStorageKeyGeneration.test.js +2 -1
- package/dist/tests/encryptedStorageKeyGeneration.test.js.map +1 -1
- package/dist/tests/gateway.test.js +170 -7
- package/dist/tests/gateway.test.js.map +1 -1
- package/dist/tests/gatewayClient.test.js +74 -0
- package/dist/tests/gatewayClient.test.js.map +1 -1
- package/dist/tests/latchkeyEndpoint.test.js +7 -6
- package/dist/tests/latchkeyEndpoint.test.js.map +1 -1
- package/dist/tests/migrations.test.js +2 -2
- package/dist/tests/migrations.test.js.map +1 -1
- package/dist/tests/oauthUtils.test.d.ts +2 -0
- package/dist/tests/oauthUtils.test.d.ts.map +1 -0
- package/dist/tests/oauthUtils.test.js +63 -0
- package/dist/tests/oauthUtils.test.js.map +1 -0
- package/dist/tests/permissionPointer.test.d.ts +2 -0
- package/dist/tests/permissionPointer.test.d.ts.map +1 -0
- package/dist/tests/permissionPointer.test.js +152 -0
- package/dist/tests/permissionPointer.test.js.map +1 -0
- package/dist/tests/permissionsOverride.test.d.ts +2 -0
- package/dist/tests/permissionsOverride.test.d.ts.map +1 -0
- package/dist/tests/permissionsOverride.test.js +136 -0
- package/dist/tests/permissionsOverride.test.js.map +1 -0
- package/dist/tests/resolveEncryptionKey.test.d.ts +2 -0
- package/dist/tests/resolveEncryptionKey.test.d.ts.map +1 -0
- package/dist/tests/resolveEncryptionKey.test.js +26 -0
- package/dist/tests/resolveEncryptionKey.test.js.map +1 -0
- package/dist/tests/sharedOperations.test.js +34 -50
- package/dist/tests/sharedOperations.test.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared definitions for the optional gateway password used to authenticate
|
|
3
|
+
* requests between the latchkey CLI (in gateway mode) and the `latchkey
|
|
4
|
+
* gateway` server.
|
|
5
|
+
*/
|
|
6
|
+
import { timingSafeEqual } from 'node:crypto';
|
|
7
|
+
/**
|
|
8
|
+
* HTTP header used to carry the shared secret. Lowercased to match how
|
|
9
|
+
* Node's `http.IncomingMessage.headers` exposes header names.
|
|
10
|
+
*/
|
|
11
|
+
export const GATEWAY_PASSWORD_HEADER = 'x-latchkey-gateway-password';
|
|
12
|
+
/**
|
|
13
|
+
* Compare two passwords in constant time relative to their length.
|
|
14
|
+
* Returns false when the values differ in length or contents.
|
|
15
|
+
*/
|
|
16
|
+
export function passwordsMatch(expected, provided) {
|
|
17
|
+
const expectedBytes = Buffer.from(expected, 'utf-8');
|
|
18
|
+
const providedBytes = Buffer.from(provided, 'utf-8');
|
|
19
|
+
if (expectedBytes.length !== providedBytes.length) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return timingSafeEqual(expectedBytes, providedBytes);
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=password.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password.js","sourceRoot":"","sources":["../../../src/gateway/password.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,6BAA6B,CAAC;AAErE;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,QAAgB;IAC/D,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACrD,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACrD,IAAI,aAAa,CAAC,MAAM,KAAK,aAAa,CAAC,MAAM,EAAE,CAAC;QAClD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,eAAe,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional `x-latchkey-gateway-permission-pointer` header support.
|
|
3
|
+
*
|
|
4
|
+
* The header carries a minimal HS256 JWT whose only payload field is
|
|
5
|
+
* `permissionsConfig`, an absolute path to a `permissions.json` file.
|
|
6
|
+
* When the gateway receives such a header on a `/gateway/...` request and
|
|
7
|
+
* the JWT is valid, it uses the referenced permissions config instead of
|
|
8
|
+
* the default one for that single request.
|
|
9
|
+
*
|
|
10
|
+
* The signing key is derived from the Latchkey encryption key via HKDF-like
|
|
11
|
+
* HMAC-SHA256 with a domain-separation label, so the encryption key itself
|
|
12
|
+
* is never used to sign or verify these JWTs directly.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* HTTP header used to carry the permission-pointer JWT. Lowercased to match
|
|
16
|
+
* how Node's `http.IncomingMessage.headers` exposes header names.
|
|
17
|
+
*/
|
|
18
|
+
export declare const PERMISSION_POINTER_HEADER = "x-latchkey-gateway-permission-pointer";
|
|
19
|
+
export declare class InvalidPermissionPointerError extends Error {
|
|
20
|
+
constructor(message: string);
|
|
21
|
+
}
|
|
22
|
+
export declare class PermissionPointerFileMissingError extends Error {
|
|
23
|
+
constructor(filePath: string);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Derive the HS256 signing key used for permission-pointer JWTs from the
|
|
27
|
+
* Latchkey encryption key. The encryption key is base64-encoded; the
|
|
28
|
+
* derived key is the raw HMAC-SHA256 output (32 bytes).
|
|
29
|
+
*/
|
|
30
|
+
export declare function derivePermissionPointerSigningKey(encryptionKeyBase64: string): Buffer;
|
|
31
|
+
/**
|
|
32
|
+
* Build a permission-pointer JWT for the given absolute path. The path is
|
|
33
|
+
* not validated here; callers that want to ensure the file exists must do
|
|
34
|
+
* so before calling this function.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createPermissionPointerJwt(permissionsConfigPath: string, signingKey: Buffer): string;
|
|
37
|
+
interface PermissionPointerPayload {
|
|
38
|
+
readonly permissionsConfig: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Verify a permission-pointer JWT and return its payload. Throws
|
|
42
|
+
* `InvalidPermissionPointerError` on any structural, signature, or content
|
|
43
|
+
* issue (i.e. anything that should be reported as "the JWT is invalid").
|
|
44
|
+
*
|
|
45
|
+
* This intentionally does not check that the referenced file exists; that
|
|
46
|
+
* concern is handled by `resolvePermissionPointer` so that file-system
|
|
47
|
+
* errors can be reported separately from JWT errors.
|
|
48
|
+
*/
|
|
49
|
+
export declare function verifyPermissionPointerJwt(token: string, signingKey: Buffer): PermissionPointerPayload;
|
|
50
|
+
/**
|
|
51
|
+
* Verify a permission-pointer JWT and additionally require the referenced
|
|
52
|
+
* file to exist as a regular file. Returns the absolute path on success.
|
|
53
|
+
*/
|
|
54
|
+
export declare function resolvePermissionPointer(token: string, signingKey: Buffer): string;
|
|
55
|
+
export {};
|
|
56
|
+
//# sourceMappingURL=permissionPointer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissionPointer.d.ts","sourceRoot":"","sources":["../../../src/gateway/permissionPointer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH;;;GAGG;AACH,eAAO,MAAM,yBAAyB,0CAA0C,CAAC;AAYjF,qBAAa,6BAA8B,SAAQ,KAAK;gBAC1C,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,iCAAkC,SAAQ,KAAK;gBAC9C,QAAQ,EAAE,MAAM;CAI7B;AAkBD;;;;GAIG;AACH,wBAAgB,iCAAiC,CAAC,mBAAmB,EAAE,MAAM,GAAG,MAAM,CAGrF;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,qBAAqB,EAAE,MAAM,EAC7B,UAAU,EAAE,MAAM,GACjB,MAAM,CAWR;AAED,UAAU,wBAAwB;IAChC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;CACpC;AAsCD;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,GACjB,wBAAwB,CAqD1B;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAMlF"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional `x-latchkey-gateway-permission-pointer` header support.
|
|
3
|
+
*
|
|
4
|
+
* The header carries a minimal HS256 JWT whose only payload field is
|
|
5
|
+
* `permissionsConfig`, an absolute path to a `permissions.json` file.
|
|
6
|
+
* When the gateway receives such a header on a `/gateway/...` request and
|
|
7
|
+
* the JWT is valid, it uses the referenced permissions config instead of
|
|
8
|
+
* the default one for that single request.
|
|
9
|
+
*
|
|
10
|
+
* The signing key is derived from the Latchkey encryption key via HKDF-like
|
|
11
|
+
* HMAC-SHA256 with a domain-separation label, so the encryption key itself
|
|
12
|
+
* is never used to sign or verify these JWTs directly.
|
|
13
|
+
*/
|
|
14
|
+
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
15
|
+
import { existsSync, statSync } from 'node:fs';
|
|
16
|
+
import { isAbsolute } from 'node:path';
|
|
17
|
+
/**
|
|
18
|
+
* HTTP header used to carry the permission-pointer JWT. Lowercased to match
|
|
19
|
+
* how Node's `http.IncomingMessage.headers` exposes header names.
|
|
20
|
+
*/
|
|
21
|
+
export const PERMISSION_POINTER_HEADER = 'x-latchkey-gateway-permission-pointer';
|
|
22
|
+
/**
|
|
23
|
+
* Domain-separation label mixed into the HMAC that derives the JWT signing
|
|
24
|
+
* key from the Latchkey encryption key. Changing this value invalidates all
|
|
25
|
+
* previously issued tokens.
|
|
26
|
+
*/
|
|
27
|
+
const SIGNING_KEY_DERIVATION_LABEL = 'latchkey:gateway:permission-pointer:v1';
|
|
28
|
+
const JWT_HEADER = { alg: 'HS256', typ: 'JWT' };
|
|
29
|
+
const JWT_HEADER_ENCODED = base64UrlEncode(Buffer.from(JSON.stringify(JWT_HEADER), 'utf-8'));
|
|
30
|
+
export class InvalidPermissionPointerError extends Error {
|
|
31
|
+
constructor(message) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = 'InvalidPermissionPointerError';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export class PermissionPointerFileMissingError extends Error {
|
|
37
|
+
constructor(filePath) {
|
|
38
|
+
super(`Permission pointer references missing or invalid file: ${filePath}`);
|
|
39
|
+
this.name = 'PermissionPointerFileMissingError';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function base64UrlEncode(buffer) {
|
|
43
|
+
return buffer
|
|
44
|
+
.toString('base64')
|
|
45
|
+
.replace(/\+/g, '-')
|
|
46
|
+
.replace(/\//g, '_')
|
|
47
|
+
.replace(/=+$/, '');
|
|
48
|
+
}
|
|
49
|
+
function base64UrlDecode(value) {
|
|
50
|
+
const padded = value
|
|
51
|
+
.replace(/-/g, '+')
|
|
52
|
+
.replace(/_/g, '/')
|
|
53
|
+
.padEnd(value.length + ((4 - (value.length % 4)) % 4), '=');
|
|
54
|
+
return Buffer.from(padded, 'base64');
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Derive the HS256 signing key used for permission-pointer JWTs from the
|
|
58
|
+
* Latchkey encryption key. The encryption key is base64-encoded; the
|
|
59
|
+
* derived key is the raw HMAC-SHA256 output (32 bytes).
|
|
60
|
+
*/
|
|
61
|
+
export function derivePermissionPointerSigningKey(encryptionKeyBase64) {
|
|
62
|
+
const masterKey = Buffer.from(encryptionKeyBase64, 'base64');
|
|
63
|
+
return createHmac('sha256', masterKey).update(SIGNING_KEY_DERIVATION_LABEL).digest();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Build a permission-pointer JWT for the given absolute path. The path is
|
|
67
|
+
* not validated here; callers that want to ensure the file exists must do
|
|
68
|
+
* so before calling this function.
|
|
69
|
+
*/
|
|
70
|
+
export function createPermissionPointerJwt(permissionsConfigPath, signingKey) {
|
|
71
|
+
if (!isAbsolute(permissionsConfigPath)) {
|
|
72
|
+
throw new InvalidPermissionPointerError(`permissionsConfig path must be absolute: ${permissionsConfigPath}`);
|
|
73
|
+
}
|
|
74
|
+
const payload = { permissionsConfig: permissionsConfigPath };
|
|
75
|
+
const payloadEncoded = base64UrlEncode(Buffer.from(JSON.stringify(payload), 'utf-8'));
|
|
76
|
+
const signingInput = `${JWT_HEADER_ENCODED}.${payloadEncoded}`;
|
|
77
|
+
const signature = createHmac('sha256', signingKey).update(signingInput).digest();
|
|
78
|
+
return `${signingInput}.${base64UrlEncode(signature)}`;
|
|
79
|
+
}
|
|
80
|
+
function parsePayload(payloadEncoded) {
|
|
81
|
+
let payloadJson;
|
|
82
|
+
try {
|
|
83
|
+
payloadJson = base64UrlDecode(payloadEncoded).toString('utf-8');
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
throw new InvalidPermissionPointerError('Permission pointer payload is not valid base64url.');
|
|
87
|
+
}
|
|
88
|
+
let payload;
|
|
89
|
+
try {
|
|
90
|
+
payload = JSON.parse(payloadJson);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
throw new InvalidPermissionPointerError('Permission pointer payload is not valid JSON.');
|
|
94
|
+
}
|
|
95
|
+
if (typeof payload !== 'object' ||
|
|
96
|
+
payload === null ||
|
|
97
|
+
!('permissionsConfig' in payload) ||
|
|
98
|
+
typeof payload.permissionsConfig !== 'string') {
|
|
99
|
+
throw new InvalidPermissionPointerError("Permission pointer payload must contain a string 'permissionsConfig' field.");
|
|
100
|
+
}
|
|
101
|
+
const permissionsConfig = payload.permissionsConfig;
|
|
102
|
+
if (!isAbsolute(permissionsConfig)) {
|
|
103
|
+
throw new InvalidPermissionPointerError(`Permission pointer 'permissionsConfig' must be an absolute path: ${permissionsConfig}`);
|
|
104
|
+
}
|
|
105
|
+
return { permissionsConfig };
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Verify a permission-pointer JWT and return its payload. Throws
|
|
109
|
+
* `InvalidPermissionPointerError` on any structural, signature, or content
|
|
110
|
+
* issue (i.e. anything that should be reported as "the JWT is invalid").
|
|
111
|
+
*
|
|
112
|
+
* This intentionally does not check that the referenced file exists; that
|
|
113
|
+
* concern is handled by `resolvePermissionPointer` so that file-system
|
|
114
|
+
* errors can be reported separately from JWT errors.
|
|
115
|
+
*/
|
|
116
|
+
export function verifyPermissionPointerJwt(token, signingKey) {
|
|
117
|
+
const segments = token.split('.');
|
|
118
|
+
if (segments.length !== 3) {
|
|
119
|
+
throw new InvalidPermissionPointerError('Permission pointer JWT must have three dot-separated segments.');
|
|
120
|
+
}
|
|
121
|
+
const headerEncoded = segments[0];
|
|
122
|
+
const payloadEncoded = segments[1];
|
|
123
|
+
const signatureEncoded = segments[2];
|
|
124
|
+
let headerJson;
|
|
125
|
+
try {
|
|
126
|
+
headerJson = base64UrlDecode(headerEncoded).toString('utf-8');
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
throw new InvalidPermissionPointerError('Permission pointer header is not valid base64url.');
|
|
130
|
+
}
|
|
131
|
+
let header;
|
|
132
|
+
try {
|
|
133
|
+
header = JSON.parse(headerJson);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
throw new InvalidPermissionPointerError('Permission pointer header is not valid JSON.');
|
|
137
|
+
}
|
|
138
|
+
if (typeof header !== 'object' ||
|
|
139
|
+
header === null ||
|
|
140
|
+
header.alg !== 'HS256' ||
|
|
141
|
+
header.typ !== 'JWT') {
|
|
142
|
+
throw new InvalidPermissionPointerError("Permission pointer header must declare alg='HS256' and typ='JWT'.");
|
|
143
|
+
}
|
|
144
|
+
let providedSignature;
|
|
145
|
+
try {
|
|
146
|
+
providedSignature = base64UrlDecode(signatureEncoded);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
throw new InvalidPermissionPointerError('Permission pointer signature is not valid base64url.');
|
|
150
|
+
}
|
|
151
|
+
const expectedSignature = createHmac('sha256', signingKey)
|
|
152
|
+
.update(`${headerEncoded}.${payloadEncoded}`)
|
|
153
|
+
.digest();
|
|
154
|
+
if (providedSignature.length !== expectedSignature.length ||
|
|
155
|
+
!timingSafeEqual(providedSignature, expectedSignature)) {
|
|
156
|
+
throw new InvalidPermissionPointerError('Permission pointer signature is invalid.');
|
|
157
|
+
}
|
|
158
|
+
return parsePayload(payloadEncoded);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Verify a permission-pointer JWT and additionally require the referenced
|
|
162
|
+
* file to exist as a regular file. Returns the absolute path on success.
|
|
163
|
+
*/
|
|
164
|
+
export function resolvePermissionPointer(token, signingKey) {
|
|
165
|
+
const { permissionsConfig } = verifyPermissionPointerJwt(token, signingKey);
|
|
166
|
+
if (!existsSync(permissionsConfig) || !statSync(permissionsConfig).isFile()) {
|
|
167
|
+
throw new PermissionPointerFileMissingError(permissionsConfig);
|
|
168
|
+
}
|
|
169
|
+
return permissionsConfig;
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=permissionPointer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissionPointer.js","sourceRoot":"","sources":["../../../src/gateway/permissionPointer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional `x-latchkey-gateway-permissions-override` header support.
|
|
3
|
+
*
|
|
4
|
+
* The header carries a minimal HS256 JWT whose only payload field is
|
|
5
|
+
* `permissionsConfig`, an absolute path to a `permissions.json` file.
|
|
6
|
+
* When the gateway receives such a header on a `/gateway/...` request and
|
|
7
|
+
* the JWT is valid, it uses the referenced permissions config instead of
|
|
8
|
+
* the default one for that single request.
|
|
9
|
+
*
|
|
10
|
+
* The signing key is derived from the Latchkey encryption key via HKDF-like
|
|
11
|
+
* HMAC-SHA256 with a domain-separation label, so the encryption key itself
|
|
12
|
+
* is never used to sign or verify these JWTs directly.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* HTTP header used to carry the permissions-override JWT. Lowercased to match
|
|
16
|
+
* how Node's `http.IncomingMessage.headers` exposes header names.
|
|
17
|
+
*/
|
|
18
|
+
export declare const PERMISSIONS_OVERRIDE_HEADER = "x-latchkey-gateway-permissions-override";
|
|
19
|
+
export declare class InvalidPermissionsOverrideError extends Error {
|
|
20
|
+
constructor(message: string);
|
|
21
|
+
}
|
|
22
|
+
export declare class PermissionsOverrideFileMissingError extends Error {
|
|
23
|
+
constructor(filePath: string);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Derive the HS256 signing key used for permissions-override JWTs from the
|
|
27
|
+
* Latchkey encryption key. The encryption key is base64-encoded; the
|
|
28
|
+
* derived key is the raw HMAC-SHA256 output (32 bytes).
|
|
29
|
+
*/
|
|
30
|
+
export declare function derivePermissionsOverrideSigningKey(encryptionKeyBase64: string): Buffer;
|
|
31
|
+
/**
|
|
32
|
+
* Build a permissions-override JWT for the given absolute path. The path is
|
|
33
|
+
* not validated here; callers that want to ensure the file exists must do
|
|
34
|
+
* so before calling this function.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createPermissionsOverrideJwt(permissionsConfigPath: string, signingKey: Buffer): string;
|
|
37
|
+
interface PermissionsOverridePayload {
|
|
38
|
+
readonly permissionsConfig: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Verify a permissions-override JWT and return its payload. Throws
|
|
42
|
+
* `InvalidPermissionsOverrideError` on any structural, signature, or content
|
|
43
|
+
* issue (i.e. anything that should be reported as "the JWT is invalid").
|
|
44
|
+
*
|
|
45
|
+
* This intentionally does not check that the referenced file exists; that
|
|
46
|
+
* concern is handled by `resolvePermissionsOverride` so that file-system
|
|
47
|
+
* errors can be reported separately from JWT errors.
|
|
48
|
+
*/
|
|
49
|
+
export declare function verifyPermissionsOverrideJwt(token: string, signingKey: Buffer): PermissionsOverridePayload;
|
|
50
|
+
/**
|
|
51
|
+
* Verify a permissions-override JWT and additionally require the referenced
|
|
52
|
+
* file to exist as a regular file. Returns the absolute path on success.
|
|
53
|
+
*/
|
|
54
|
+
export declare function resolvePermissionsOverride(token: string, signingKey: Buffer): string;
|
|
55
|
+
export {};
|
|
56
|
+
//# sourceMappingURL=permissionsOverride.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissionsOverride.d.ts","sourceRoot":"","sources":["../../../src/gateway/permissionsOverride.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH;;;GAGG;AACH,eAAO,MAAM,2BAA2B,4CAA4C,CAAC;AAYrF,qBAAa,+BAAgC,SAAQ,KAAK;gBAC5C,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,mCAAoC,SAAQ,KAAK;gBAChD,QAAQ,EAAE,MAAM;CAI7B;AAED;;;;GAIG;AACH,wBAAgB,mCAAmC,CAAC,mBAAmB,EAAE,MAAM,GAAG,MAAM,CAGvF;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,qBAAqB,EAAE,MAAM,EAC7B,UAAU,EAAE,MAAM,GACjB,MAAM,CAWR;AAED,UAAU,0BAA0B;IAClC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;CACpC;AAwCD;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,GACjB,0BAA0B,CAyD5B;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAMpF"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional `x-latchkey-gateway-permissions-override` header support.
|
|
3
|
+
*
|
|
4
|
+
* The header carries a minimal HS256 JWT whose only payload field is
|
|
5
|
+
* `permissionsConfig`, an absolute path to a `permissions.json` file.
|
|
6
|
+
* When the gateway receives such a header on a `/gateway/...` request and
|
|
7
|
+
* the JWT is valid, it uses the referenced permissions config instead of
|
|
8
|
+
* the default one for that single request.
|
|
9
|
+
*
|
|
10
|
+
* The signing key is derived from the Latchkey encryption key via HKDF-like
|
|
11
|
+
* HMAC-SHA256 with a domain-separation label, so the encryption key itself
|
|
12
|
+
* is never used to sign or verify these JWTs directly.
|
|
13
|
+
*/
|
|
14
|
+
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
15
|
+
import { existsSync, statSync } from 'node:fs';
|
|
16
|
+
import { isAbsolute } from 'node:path';
|
|
17
|
+
/**
|
|
18
|
+
* HTTP header used to carry the permissions-override JWT. Lowercased to match
|
|
19
|
+
* how Node's `http.IncomingMessage.headers` exposes header names.
|
|
20
|
+
*/
|
|
21
|
+
export const PERMISSIONS_OVERRIDE_HEADER = 'x-latchkey-gateway-permissions-override';
|
|
22
|
+
/**
|
|
23
|
+
* Domain-separation label mixed into the HMAC that derives the JWT signing
|
|
24
|
+
* key from the Latchkey encryption key. Changing this value invalidates all
|
|
25
|
+
* previously issued tokens.
|
|
26
|
+
*/
|
|
27
|
+
const SIGNING_KEY_DERIVATION_LABEL = 'latchkey:gateway:permissions-override:v1';
|
|
28
|
+
const JWT_HEADER = { alg: 'HS256', typ: 'JWT' };
|
|
29
|
+
const JWT_HEADER_ENCODED = Buffer.from(JSON.stringify(JWT_HEADER), 'utf-8').toString('base64url');
|
|
30
|
+
export class InvalidPermissionsOverrideError extends Error {
|
|
31
|
+
constructor(message) {
|
|
32
|
+
super(`Latchkey: ${message}`);
|
|
33
|
+
this.name = 'InvalidPermissionsOverrideError';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export class PermissionsOverrideFileMissingError extends Error {
|
|
37
|
+
constructor(filePath) {
|
|
38
|
+
super(`Permissions override references missing or invalid file: ${filePath}`);
|
|
39
|
+
this.name = 'PermissionsOverrideFileMissingError';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Derive the HS256 signing key used for permissions-override JWTs from the
|
|
44
|
+
* Latchkey encryption key. The encryption key is base64-encoded; the
|
|
45
|
+
* derived key is the raw HMAC-SHA256 output (32 bytes).
|
|
46
|
+
*/
|
|
47
|
+
export function derivePermissionsOverrideSigningKey(encryptionKeyBase64) {
|
|
48
|
+
const masterKey = Buffer.from(encryptionKeyBase64, 'base64');
|
|
49
|
+
return createHmac('sha256', masterKey).update(SIGNING_KEY_DERIVATION_LABEL).digest();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Build a permissions-override JWT for the given absolute path. The path is
|
|
53
|
+
* not validated here; callers that want to ensure the file exists must do
|
|
54
|
+
* so before calling this function.
|
|
55
|
+
*/
|
|
56
|
+
export function createPermissionsOverrideJwt(permissionsConfigPath, signingKey) {
|
|
57
|
+
if (!isAbsolute(permissionsConfigPath)) {
|
|
58
|
+
throw new InvalidPermissionsOverrideError(`permissionsConfig path must be absolute: ${permissionsConfigPath}`);
|
|
59
|
+
}
|
|
60
|
+
const payload = { permissionsConfig: permissionsConfigPath };
|
|
61
|
+
const payloadEncoded = Buffer.from(JSON.stringify(payload), 'utf-8').toString('base64url');
|
|
62
|
+
const signingInput = `${JWT_HEADER_ENCODED}.${payloadEncoded}`;
|
|
63
|
+
const signature = createHmac('sha256', signingKey).update(signingInput).digest('base64url');
|
|
64
|
+
return `${signingInput}.${signature}`;
|
|
65
|
+
}
|
|
66
|
+
function parsePayload(payloadEncoded) {
|
|
67
|
+
let payloadJson;
|
|
68
|
+
try {
|
|
69
|
+
payloadJson = Buffer.from(payloadEncoded, 'base64url').toString('utf-8');
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
throw new InvalidPermissionsOverrideError('Permissions override payload is not valid base64url.');
|
|
73
|
+
}
|
|
74
|
+
let payload;
|
|
75
|
+
try {
|
|
76
|
+
payload = JSON.parse(payloadJson);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
throw new InvalidPermissionsOverrideError('Permissions override payload is not valid JSON.');
|
|
80
|
+
}
|
|
81
|
+
if (typeof payload !== 'object' ||
|
|
82
|
+
payload === null ||
|
|
83
|
+
!('permissionsConfig' in payload) ||
|
|
84
|
+
typeof payload.permissionsConfig !== 'string') {
|
|
85
|
+
throw new InvalidPermissionsOverrideError("Permissions override payload must contain a string 'permissionsConfig' field.");
|
|
86
|
+
}
|
|
87
|
+
const permissionsConfig = payload.permissionsConfig;
|
|
88
|
+
if (!isAbsolute(permissionsConfig)) {
|
|
89
|
+
throw new InvalidPermissionsOverrideError(`Permissions override 'permissionsConfig' must be an absolute path: ${permissionsConfig}`);
|
|
90
|
+
}
|
|
91
|
+
return { permissionsConfig };
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Verify a permissions-override JWT and return its payload. Throws
|
|
95
|
+
* `InvalidPermissionsOverrideError` on any structural, signature, or content
|
|
96
|
+
* issue (i.e. anything that should be reported as "the JWT is invalid").
|
|
97
|
+
*
|
|
98
|
+
* This intentionally does not check that the referenced file exists; that
|
|
99
|
+
* concern is handled by `resolvePermissionsOverride` so that file-system
|
|
100
|
+
* errors can be reported separately from JWT errors.
|
|
101
|
+
*/
|
|
102
|
+
export function verifyPermissionsOverrideJwt(token, signingKey) {
|
|
103
|
+
const segments = token.split('.');
|
|
104
|
+
if (segments.length !== 3) {
|
|
105
|
+
throw new InvalidPermissionsOverrideError('Permissions override JWT must have three dot-separated segments.');
|
|
106
|
+
}
|
|
107
|
+
const headerEncoded = segments[0];
|
|
108
|
+
const payloadEncoded = segments[1];
|
|
109
|
+
const signatureEncoded = segments[2];
|
|
110
|
+
let headerJson;
|
|
111
|
+
try {
|
|
112
|
+
headerJson = Buffer.from(headerEncoded, 'base64url').toString('utf-8');
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
throw new InvalidPermissionsOverrideError('Permissions override header is not valid base64url.');
|
|
116
|
+
}
|
|
117
|
+
let header;
|
|
118
|
+
try {
|
|
119
|
+
header = JSON.parse(headerJson);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
throw new InvalidPermissionsOverrideError('Permissions override header is not valid JSON.');
|
|
123
|
+
}
|
|
124
|
+
if (typeof header !== 'object' ||
|
|
125
|
+
header === null ||
|
|
126
|
+
header.alg !== 'HS256' ||
|
|
127
|
+
header.typ !== 'JWT') {
|
|
128
|
+
throw new InvalidPermissionsOverrideError("Permissions override header must declare alg='HS256' and typ='JWT'.");
|
|
129
|
+
}
|
|
130
|
+
let providedSignature;
|
|
131
|
+
try {
|
|
132
|
+
providedSignature = Buffer.from(signatureEncoded, 'base64url');
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
throw new InvalidPermissionsOverrideError('Permissions override signature is not valid base64url.');
|
|
136
|
+
}
|
|
137
|
+
const expectedSignature = createHmac('sha256', signingKey)
|
|
138
|
+
.update(`${headerEncoded}.${payloadEncoded}`)
|
|
139
|
+
.digest();
|
|
140
|
+
if (providedSignature.length !== expectedSignature.length ||
|
|
141
|
+
!timingSafeEqual(providedSignature, expectedSignature)) {
|
|
142
|
+
throw new InvalidPermissionsOverrideError('Permissions override signature is invalid.');
|
|
143
|
+
}
|
|
144
|
+
return parsePayload(payloadEncoded);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Verify a permissions-override JWT and additionally require the referenced
|
|
148
|
+
* file to exist as a regular file. Returns the absolute path on success.
|
|
149
|
+
*/
|
|
150
|
+
export function resolvePermissionsOverride(token, signingKey) {
|
|
151
|
+
const { permissionsConfig } = verifyPermissionsOverrideJwt(token, signingKey);
|
|
152
|
+
if (!existsSync(permissionsConfig) || !statSync(permissionsConfig).isFile()) {
|
|
153
|
+
throw new PermissionsOverrideFileMissingError(permissionsConfig);
|
|
154
|
+
}
|
|
155
|
+
return permissionsConfig;
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=permissionsOverride.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissionsOverride.js","sourceRoot":"","sources":["../../../src/gateway/permissionsOverride.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/gateway/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/gateway/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;AA8C9B,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,eAAe,EACrB,kBAAkB,EAAE,kBAAkB,EACtC,gBAAgB,EAAE,gBAAgB,EAClC,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,CA0GxB"}
|
|
@@ -8,10 +8,39 @@ import * as http from 'node:http';
|
|
|
8
8
|
import { ErrorMessages } from '../errorMessages.js';
|
|
9
9
|
import { extractTargetUrl, GATEWAY_PATH_PREFIX, handleGatewayRequest, } from './gatewayEndpoint.js';
|
|
10
10
|
import { handleLatchkeyRequest } from './latchkeyEndpoint.js';
|
|
11
|
+
import { GATEWAY_PASSWORD_HEADER, passwordsMatch } from './password.js';
|
|
11
12
|
function sendErrorResponse(response, statusCode, message) {
|
|
12
13
|
response.writeHead(statusCode, { 'Content-Type': 'application/json' });
|
|
13
14
|
response.end(JSON.stringify({ error: message }));
|
|
14
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Read a single header value, treating arrays (which Node returns for some
|
|
18
|
+
* headers) as missing because the password header is not allowed to repeat.
|
|
19
|
+
*/
|
|
20
|
+
function readSingleHeader(request, headerName) {
|
|
21
|
+
const value = request.headers[headerName];
|
|
22
|
+
if (typeof value === 'string')
|
|
23
|
+
return value;
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* If a password is configured, verify that the request presents it in the
|
|
28
|
+
* expected header. Returns true when the request should be allowed to
|
|
29
|
+
* proceed, and writes a 401 response and returns false otherwise.
|
|
30
|
+
*/
|
|
31
|
+
function enforcePassword(request, response, expectedPassword, deps) {
|
|
32
|
+
if (expectedPassword === null)
|
|
33
|
+
return true;
|
|
34
|
+
const provided = readSingleHeader(request, GATEWAY_PASSWORD_HEADER);
|
|
35
|
+
if (provided !== undefined && passwordsMatch(expectedPassword, provided)) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
const method = request.method ?? 'UNKNOWN';
|
|
39
|
+
const path = request.url ?? '';
|
|
40
|
+
deps.log(`${method} ${path} -> 401 (password)`);
|
|
41
|
+
sendErrorResponse(response, 401, 'Unauthorized: invalid or missing Latchkey gateway password.');
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
15
44
|
/**
|
|
16
45
|
* Start the gateway HTTP server.
|
|
17
46
|
*/
|
|
@@ -19,6 +48,9 @@ export function startGateway(deps, apiCredentialStore, encryptedStorage, options
|
|
|
19
48
|
const inFlightRequests = new Set();
|
|
20
49
|
const server = http.createServer((request, response) => {
|
|
21
50
|
const rawUrl = request.url ?? '';
|
|
51
|
+
if (!enforcePassword(request, response, options.password, deps)) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
22
54
|
// Health endpoint
|
|
23
55
|
if (rawUrl === '/' && request.method === 'GET') {
|
|
24
56
|
response.writeHead(200, { 'Content-Type': 'application/json' });
|
|
@@ -82,7 +114,8 @@ export function startGateway(deps, apiCredentialStore, encryptedStorage, options
|
|
|
82
114
|
return new Promise((resolve, reject) => {
|
|
83
115
|
server.on('error', reject);
|
|
84
116
|
server.listen(options.port, options.host, () => {
|
|
85
|
-
|
|
117
|
+
const passwordNote = options.password === null ? '' : ' (password authentication enabled)';
|
|
118
|
+
deps.log(`Latchkey gateway listening on ${options.host}:${String(options.port)}${passwordNote}`);
|
|
86
119
|
resolve({ server, close });
|
|
87
120
|
});
|
|
88
121
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/gateway/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAIlC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,GAErB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/gateway/server.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -6,8 +6,8 @@ export { deserializeCredentials, serializeCredentials } from './apiCredentials/s
|
|
|
6
6
|
export { SlackApiCredentials } from './services/slack.js';
|
|
7
7
|
export { ApiCredentialStore, ApiCredentialStoreError } from './apiCredentials/store.js';
|
|
8
8
|
export { Config, CONFIG, InsecureFilePermissionsError } from './config.js';
|
|
9
|
-
export { encrypt, decrypt, generateKey, EncryptionError, DecryptionError } from './encryption.js';
|
|
10
|
-
export { EncryptedStorage, EncryptedStorageError
|
|
9
|
+
export { encrypt, decrypt, generateKey, resolveEncryptionKey, EncryptionError, DecryptionError, EncryptionKeyError, EncryptionKeyLostError, EncryptionKeyUnavailableError, } from './encryption.js';
|
|
10
|
+
export { EncryptedStorage, EncryptedStorageError } from './encryptedStorage.js';
|
|
11
11
|
export { storeInKeychain, retrieveFromKeychain, deleteFromKeychain, KeychainError, KeychainNotAvailableError, KeychainTimeoutError, } from './keychain.js';
|
|
12
12
|
export { run as runCurl, runCaptured as runCurlCaptured, setSubprocessRunner, resetSubprocessRunner, setCapturingSubprocessRunner, resetCapturingSubprocessRunner, } from './curl.js';
|
|
13
13
|
export { typeLikeHuman, BrowserDisabledError, BrowserFlowsNotSupportedError, } from './playwrightUtils.js';
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACjG,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAExF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAE3E,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACjG,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAExF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAE3E,OAAO,EACL,OAAO,EACP,OAAO,EACP,WAAW,EACX,oBAAoB,EACpB,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,sBAAsB,EACtB,6BAA6B,GAC9B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAEhF,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,GAAG,IAAI,OAAO,EACd,WAAW,IAAI,eAAe,EAC9B,mBAAmB,EACnB,qBAAqB,EACrB,4BAA4B,EAC5B,8BAA8B,GAC/B,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,6BAA6B,GAC9B,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,OAAO,EACP,cAAc,EACd,oBAAoB,EACpB,6BAA6B,EAC7B,mBAAmB,EACnB,gBAAgB,EAChB,KAAK,EACL,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,EACN,MAAM,EACN,OAAO,EACP,OAAO,EACP,MAAM,EACN,MAAM,GACP,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/src/index.js
CHANGED
|
@@ -7,8 +7,8 @@ export { deserializeCredentials, serializeCredentials } from './apiCredentials/s
|
|
|
7
7
|
export { SlackApiCredentials } from './services/slack.js';
|
|
8
8
|
export { ApiCredentialStore, ApiCredentialStoreError } from './apiCredentials/store.js';
|
|
9
9
|
export { Config, CONFIG, InsecureFilePermissionsError } from './config.js';
|
|
10
|
-
export { encrypt, decrypt, generateKey, EncryptionError, DecryptionError } from './encryption.js';
|
|
11
|
-
export { EncryptedStorage, EncryptedStorageError
|
|
10
|
+
export { encrypt, decrypt, generateKey, resolveEncryptionKey, EncryptionError, DecryptionError, EncryptionKeyError, EncryptionKeyLostError, EncryptionKeyUnavailableError, } from './encryption.js';
|
|
11
|
+
export { EncryptedStorage, EncryptedStorageError } from './encryptedStorage.js';
|
|
12
12
|
export { storeInKeychain, retrieveFromKeychain, deleteFromKeychain, KeychainError, KeychainNotAvailableError, KeychainTimeoutError, } from './keychain.js';
|
|
13
13
|
export { run as runCurl, runCaptured as runCurlCaptured, setSubprocessRunner, resetSubprocessRunner, setCapturingSubprocessRunner, resetCapturingSubprocessRunner, } from './curl.js';
|
|
14
14
|
export { typeLikeHuman, BrowserDisabledError, BrowserFlowsNotSupportedError, } from './playwrightUtils.js';
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,2BAA2B;AAC3B,OAAO,EAEL,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACjG,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAExF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAE3E,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,2BAA2B;AAC3B,OAAO,EAEL,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACjG,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAExF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAE3E,OAAO,EACL,OAAO,EACP,OAAO,EACP,WAAW,EACX,oBAAoB,EACpB,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,sBAAsB,EACtB,6BAA6B,GAC9B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAEhF,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,GAAG,IAAI,OAAO,EACd,WAAW,IAAI,eAAe,EAC9B,mBAAmB,EACnB,qBAAqB,EACrB,4BAA4B,EAC5B,8BAA8B,GAC/B,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,6BAA6B,GAC9B,MAAM,sBAAsB,CAAC;AAE9B,WAAW;AACX,OAAO,EACL,OAAO,EACP,cAAc,EACd,oBAAoB,EACpB,6BAA6B,EAC7B,mBAAmB,EACnB,gBAAgB,EAChB,KAAK,EACL,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,EACN,MAAM,EACN,OAAO,EACP,OAAO,EACP,MAAM,EACN,MAAM,GACP,MAAM,qBAAqB,CAAC;AAE7B,kBAAkB;AAClB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC"}
|