latchkey 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.nvmrc +1 -0
- package/.pre-commit-config.yaml +22 -0
- package/.prettierignore +4 -0
- package/.prettierrc +7 -0
- package/CLAUDE.md +13 -0
- package/LICENSE +7 -0
- package/README.md +167 -0
- package/dist/scripts/cryptFile.d.ts +21 -0
- package/dist/scripts/cryptFile.d.ts.map +1 -0
- package/dist/scripts/cryptFile.js +106 -0
- package/dist/scripts/cryptFile.js.map +1 -0
- package/dist/scripts/encryptFile.d.ts +21 -0
- package/dist/scripts/encryptFile.d.ts.map +1 -0
- package/dist/scripts/encryptFile.js +101 -0
- package/dist/scripts/encryptFile.js.map +1 -0
- package/dist/scripts/recordBrowserSession.d.ts +18 -0
- package/dist/scripts/recordBrowserSession.d.ts.map +1 -0
- package/dist/scripts/recordBrowserSession.js +213 -0
- package/dist/scripts/recordBrowserSession.js.map +1 -0
- package/dist/src/apiCredentialStore.d.ts +19 -0
- package/dist/src/apiCredentialStore.d.ts.map +1 -0
- package/dist/src/apiCredentialStore.js +65 -0
- package/dist/src/apiCredentialStore.js.map +1 -0
- package/dist/src/apiCredentials.d.ts +134 -0
- package/dist/src/apiCredentials.d.ts.map +1 -0
- package/dist/src/apiCredentials.js +139 -0
- package/dist/src/apiCredentials.js.map +1 -0
- package/dist/src/browserConfig.d.ts +90 -0
- package/dist/src/browserConfig.d.ts.map +1 -0
- package/dist/src/browserConfig.js +259 -0
- package/dist/src/browserConfig.js.map +1 -0
- package/dist/src/browserState.d.ts +8 -0
- package/dist/src/browserState.d.ts.map +1 -0
- package/dist/src/browserState.js +21 -0
- package/dist/src/browserState.js.map +1 -0
- package/dist/src/cli.d.ts +6 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +25 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/cliCommands.d.ts +29 -0
- package/dist/src/cliCommands.d.ts.map +1 -0
- package/dist/src/cliCommands.js +264 -0
- package/dist/src/cliCommands.js.map +1 -0
- package/dist/src/config.d.ts +35 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +96 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/curl.d.ts +29 -0
- package/dist/src/curl.d.ts.map +1 -0
- package/dist/src/curl.js +53 -0
- package/dist/src/curl.js.map +1 -0
- package/dist/src/encryptedStorage.d.ts +39 -0
- package/dist/src/encryptedStorage.d.ts.map +1 -0
- package/dist/src/encryptedStorage.js +128 -0
- package/dist/src/encryptedStorage.js.map +1 -0
- package/dist/src/encryption.d.ts +28 -0
- package/dist/src/encryption.d.ts.map +1 -0
- package/dist/src/encryption.js +86 -0
- package/dist/src/encryption.js.map +1 -0
- package/dist/src/index.d.ts +14 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +17 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/keychain.d.ts +33 -0
- package/dist/src/keychain.d.ts.map +1 -0
- package/dist/src/keychain.js +94 -0
- package/dist/src/keychain.js.map +1 -0
- package/dist/src/playwrightUtils.d.ts +27 -0
- package/dist/src/playwrightUtils.d.ts.map +1 -0
- package/dist/src/playwrightUtils.js +122 -0
- package/dist/src/playwrightUtils.js.map +1 -0
- package/dist/src/registry.d.ts +12 -0
- package/dist/src/registry.d.ts.map +1 -0
- package/dist/src/registry.js +30 -0
- package/dist/src/registry.js.map +1 -0
- package/dist/src/services/base.d.ts +98 -0
- package/dist/src/services/base.d.ts.map +1 -0
- package/dist/src/services/base.js +137 -0
- package/dist/src/services/base.js.map +1 -0
- package/dist/src/services/discord.d.ts +20 -0
- package/dist/src/services/discord.d.ts.map +1 -0
- package/dist/src/services/discord.js +55 -0
- package/dist/src/services/discord.js.map +1 -0
- package/dist/src/services/dropbox.d.ts +23 -0
- package/dist/src/services/dropbox.d.ts.map +1 -0
- package/dist/src/services/dropbox.js +136 -0
- package/dist/src/services/dropbox.js.map +1 -0
- package/dist/src/services/github.d.ts +23 -0
- package/dist/src/services/github.d.ts.map +1 -0
- package/dist/src/services/github.js +110 -0
- package/dist/src/services/github.js.map +1 -0
- package/dist/src/services/index.d.ts +12 -0
- package/dist/src/services/index.d.ts.map +1 -0
- package/dist/src/services/index.js +11 -0
- package/dist/src/services/index.js.map +1 -0
- package/dist/src/services/linear.d.ts +23 -0
- package/dist/src/services/linear.d.ts.map +1 -0
- package/dist/src/services/linear.js +110 -0
- package/dist/src/services/linear.js.map +1 -0
- package/dist/src/services/slack.d.ts +21 -0
- package/dist/src/services/slack.d.ts.map +1 -0
- package/dist/src/services/slack.js +67 -0
- package/dist/src/services/slack.js.map +1 -0
- package/dist/tests/apiCredentialStore.test.d.ts +2 -0
- package/dist/tests/apiCredentialStore.test.d.ts.map +1 -0
- package/dist/tests/apiCredentialStore.test.js +130 -0
- package/dist/tests/apiCredentialStore.test.js.map +1 -0
- package/dist/tests/apiCredentials.test.d.ts +2 -0
- package/dist/tests/apiCredentials.test.d.ts.map +1 -0
- package/dist/tests/apiCredentials.test.js +169 -0
- package/dist/tests/apiCredentials.test.js.map +1 -0
- package/dist/tests/cli.test.d.ts +2 -0
- package/dist/tests/cli.test.d.ts.map +1 -0
- package/dist/tests/cli.test.js +584 -0
- package/dist/tests/cli.test.js.map +1 -0
- package/dist/tests/encryptedStorage.test.d.ts +2 -0
- package/dist/tests/encryptedStorage.test.d.ts.map +1 -0
- package/dist/tests/encryptedStorage.test.js +126 -0
- package/dist/tests/encryptedStorage.test.js.map +1 -0
- package/dist/tests/encryption.test.d.ts +2 -0
- package/dist/tests/encryption.test.d.ts.map +1 -0
- package/dist/tests/encryption.test.js +121 -0
- package/dist/tests/encryption.test.js.map +1 -0
- package/dist/tests/lint.test.d.ts +2 -0
- package/dist/tests/lint.test.d.ts.map +1 -0
- package/dist/tests/lint.test.js +18 -0
- package/dist/tests/lint.test.js.map +1 -0
- package/dist/tests/registry.test.d.ts +2 -0
- package/dist/tests/registry.test.d.ts.map +1 -0
- package/dist/tests/registry.test.js +85 -0
- package/dist/tests/registry.test.js.map +1 -0
- package/dist/tests/servicesAgainstRecordings.test.d.ts +20 -0
- package/dist/tests/servicesAgainstRecordings.test.d.ts.map +1 -0
- package/dist/tests/servicesAgainstRecordings.test.js +157 -0
- package/dist/tests/servicesAgainstRecordings.test.js.map +1 -0
- package/dist/tests/typecheck.test.d.ts +2 -0
- package/dist/tests/typecheck.test.d.ts.map +1 -0
- package/dist/tests/typecheck.test.js +18 -0
- package/dist/tests/typecheck.test.js.map +1 -0
- package/docs/development.md +94 -0
- package/eslint.config.js +30 -0
- package/integrations/SKILL.md +62 -0
- package/package.json +68 -0
- package/scripts/cryptFile.ts +123 -0
- package/scripts/recordBrowserSession.ts +280 -0
- package/scripts/tsconfig.json +10 -0
- package/src/apiCredentialStore.ts +87 -0
- package/src/apiCredentials.ts +180 -0
- package/src/cli.ts +32 -0
- package/src/cliCommands.ts +321 -0
- package/src/config.ts +115 -0
- package/src/curl.ts +78 -0
- package/src/encryptedStorage.ts +161 -0
- package/src/encryption.ts +106 -0
- package/src/index.ts +65 -0
- package/src/keychain.ts +105 -0
- package/src/playwrightUtils.ts +143 -0
- package/src/registry.ts +35 -0
- package/src/services/base.ts +234 -0
- package/src/services/discord.ts +73 -0
- package/src/services/dropbox.ts +173 -0
- package/src/services/github.ts +139 -0
- package/src/services/index.ts +13 -0
- package/src/services/linear.ts +134 -0
- package/src/services/slack.ts +85 -0
- package/tests/apiCredentialStore.test.ts +162 -0
- package/tests/apiCredentials.test.ts +195 -0
- package/tests/cli.test.ts +798 -0
- package/tests/encryptedStorage.test.ts +173 -0
- package/tests/encryption.test.ts +169 -0
- package/tests/lint.test.ts +19 -0
- package/tests/registry.test.ts +103 -0
- package/tests/servicesAgainstRecordings.test.ts +230 -0
- package/tests/typecheck.test.ts +19 -0
- package/tsconfig.json +24 -0
- package/vitest.config.ts +13 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../../src/services/github.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-export all services.
|
|
3
|
+
*/
|
|
4
|
+
export type { Service } from './base.js';
|
|
5
|
+
export { ServiceSession, SimpleServiceSession, BrowserFollowupServiceSession } from './base.js';
|
|
6
|
+
export { LoginCancelledError, LoginFailedError } from './base.js';
|
|
7
|
+
export { Slack, SLACK } from './slack.js';
|
|
8
|
+
export { Discord, DISCORD } from './discord.js';
|
|
9
|
+
export { Github, GITHUB } from './github.js';
|
|
10
|
+
export { Dropbox, DROPBOX } from './dropbox.js';
|
|
11
|
+
export { Linear, LINEAR } from './linear.js';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,6BAA6B,EAAE,MAAM,WAAW,CAAC;AAChG,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAElE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-export all services.
|
|
3
|
+
*/
|
|
4
|
+
export { ServiceSession, SimpleServiceSession, BrowserFollowupServiceSession } from './base.js';
|
|
5
|
+
export { LoginCancelledError, LoginFailedError } from './base.js';
|
|
6
|
+
export { Slack, SLACK } from './slack.js';
|
|
7
|
+
export { Discord, DISCORD } from './discord.js';
|
|
8
|
+
export { Github, GITHUB } from './github.js';
|
|
9
|
+
export { Dropbox, DROPBOX } from './dropbox.js';
|
|
10
|
+
export { Linear, LINEAR } from './linear.js';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,6BAA6B,EAAE,MAAM,WAAW,CAAC;AAChG,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAElE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linear service implementation.
|
|
3
|
+
*/
|
|
4
|
+
import type { Response, BrowserContext } from 'playwright';
|
|
5
|
+
import { ApiCredentialStatus, ApiCredentials } from '../apiCredentials.js';
|
|
6
|
+
import { Service, BrowserFollowupServiceSession } from './base.js';
|
|
7
|
+
declare class LinearServiceSession extends BrowserFollowupServiceSession {
|
|
8
|
+
private isLoggedIn;
|
|
9
|
+
onResponse(response: Response): void;
|
|
10
|
+
protected isLoginComplete(): boolean;
|
|
11
|
+
protected performBrowserFollowup(context: BrowserContext): Promise<ApiCredentials | null>;
|
|
12
|
+
}
|
|
13
|
+
export declare class Linear implements Service {
|
|
14
|
+
readonly name = "linear";
|
|
15
|
+
readonly baseApiUrls: readonly ["https://api.linear.app/"];
|
|
16
|
+
readonly loginUrl = "https://linear.app/imbue/settings/account/security/api-keys/new";
|
|
17
|
+
readonly credentialCheckCurlArguments: readonly ["-X", "POST", "-H", "Content-Type: application/json", "-d", "{\"query\": \"{ viewer { id } }\"}", "https://api.linear.app/graphql"];
|
|
18
|
+
getSession(): LinearServiceSession;
|
|
19
|
+
checkApiCredentials(apiCredentials: ApiCredentials): ApiCredentialStatus;
|
|
20
|
+
}
|
|
21
|
+
export declare const LINEAR: Linear;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=linear.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linear.d.ts","sourceRoot":"","sources":["../../../src/services/linear.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAqB,MAAM,sBAAsB,CAAC;AAG9F,OAAO,EAAE,OAAO,EAAE,6BAA6B,EAAoB,MAAM,WAAW,CAAC;AAOrF,cAAM,oBAAqB,SAAQ,6BAA6B;IAC9D,OAAO,CAAC,UAAU,CAAS;IAE3B,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IA+BpC,SAAS,CAAC,eAAe,IAAI,OAAO;cAIpB,sBAAsB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CAgChG;AAED,qBAAa,MAAO,YAAW,OAAO;IACpC,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,WAAW,uCAAwC;IAC5D,QAAQ,CAAC,QAAQ,qEAA0B;IAE3C,QAAQ,CAAC,4BAA4B,gJAQ1B;IAEX,UAAU,IAAI,oBAAoB;IAIlC,mBAAmB,CAAC,cAAc,EAAE,cAAc,GAAG,mBAAmB;CAwBzE;AAED,eAAO,MAAM,MAAM,QAAe,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linear service implementation.
|
|
3
|
+
*/
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
5
|
+
import { ApiCredentialStatus, AuthorizationBare } from '../apiCredentials.js';
|
|
6
|
+
import { runCaptured } from '../curl.js';
|
|
7
|
+
import { typeLikeHuman } from '../playwrightUtils.js';
|
|
8
|
+
import { BrowserFollowupServiceSession, LoginFailedError } from './base.js';
|
|
9
|
+
const DEFAULT_TIMEOUT_MS = 8000;
|
|
10
|
+
// URL for creating a new personal API key (also used as login URL)
|
|
11
|
+
const LINEAR_NEW_API_KEY_URL = 'https://linear.app/imbue/settings/account/security/api-keys/new';
|
|
12
|
+
class LinearServiceSession extends BrowserFollowupServiceSession {
|
|
13
|
+
isLoggedIn = false;
|
|
14
|
+
onResponse(response) {
|
|
15
|
+
if (this.isLoggedIn) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const request = response.request();
|
|
19
|
+
// Empirically, Linear always sends this request. When not logged in,
|
|
20
|
+
// the response only contains "data.organizationMeta". Otherwise it can
|
|
21
|
+
// contain different things based on how exactly the user authenticated.
|
|
22
|
+
if (request.url() === 'https://client-api.linear.app/graphql' && request.method() === 'POST') {
|
|
23
|
+
if (response.status() === 200) {
|
|
24
|
+
try {
|
|
25
|
+
// Note: response.json() returns a Promise in Playwright
|
|
26
|
+
response
|
|
27
|
+
.json()
|
|
28
|
+
.then((jsonData) => {
|
|
29
|
+
const data = jsonData.data ?? {};
|
|
30
|
+
if (Object.keys(data).some((key) => key !== 'organizationMeta')) {
|
|
31
|
+
this.isLoggedIn = true;
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
.catch(() => {
|
|
35
|
+
// Ignore JSON parse errors
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Ignore errors
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
isLoginComplete() {
|
|
45
|
+
return this.isLoggedIn;
|
|
46
|
+
}
|
|
47
|
+
async performBrowserFollowup(context) {
|
|
48
|
+
const page = context.pages()[0];
|
|
49
|
+
if (!page) {
|
|
50
|
+
throw new LoginFailedError('No page available in browser context.');
|
|
51
|
+
}
|
|
52
|
+
await page.goto(LINEAR_NEW_API_KEY_URL);
|
|
53
|
+
// Fill in the key name
|
|
54
|
+
const keyName = `Latchkey-${randomUUID().slice(0, 8)}`;
|
|
55
|
+
const keyNameInput = page.getByRole('textbox', { name: 'Key name' });
|
|
56
|
+
await keyNameInput.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
57
|
+
await typeLikeHuman(page, keyNameInput, keyName);
|
|
58
|
+
// Click the Create button
|
|
59
|
+
const createButton = page.getByRole('button', { name: 'Create' });
|
|
60
|
+
await createButton.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
61
|
+
await createButton.click();
|
|
62
|
+
// Wait for and extract the token from span element containing lin_api_ prefix
|
|
63
|
+
const tokenElement = page.locator("span:text-matches('^lin_api_')");
|
|
64
|
+
await tokenElement.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
65
|
+
const token = await tokenElement.textContent();
|
|
66
|
+
if (token === null || token === '') {
|
|
67
|
+
throw new LoginFailedError('Failed to extract token from Linear.');
|
|
68
|
+
}
|
|
69
|
+
await page.close();
|
|
70
|
+
return new AuthorizationBare(token);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export class Linear {
|
|
74
|
+
name = 'linear';
|
|
75
|
+
baseApiUrls = ['https://api.linear.app/'];
|
|
76
|
+
loginUrl = LINEAR_NEW_API_KEY_URL;
|
|
77
|
+
credentialCheckCurlArguments = [
|
|
78
|
+
'-X',
|
|
79
|
+
'POST',
|
|
80
|
+
'-H',
|
|
81
|
+
'Content-Type: application/json',
|
|
82
|
+
'-d',
|
|
83
|
+
'{"query": "{ viewer { id } }"}',
|
|
84
|
+
'https://api.linear.app/graphql',
|
|
85
|
+
];
|
|
86
|
+
getSession() {
|
|
87
|
+
return new LinearServiceSession(this);
|
|
88
|
+
}
|
|
89
|
+
checkApiCredentials(apiCredentials) {
|
|
90
|
+
if (!(apiCredentials instanceof AuthorizationBare)) {
|
|
91
|
+
return ApiCredentialStatus.Invalid;
|
|
92
|
+
}
|
|
93
|
+
// Linear uses GraphQL API - check credentials with a simple query
|
|
94
|
+
const result = runCaptured([
|
|
95
|
+
'-s',
|
|
96
|
+
'-o',
|
|
97
|
+
'/dev/null',
|
|
98
|
+
'-w',
|
|
99
|
+
'%{http_code}',
|
|
100
|
+
...apiCredentials.asCurlArguments(),
|
|
101
|
+
...this.credentialCheckCurlArguments,
|
|
102
|
+
], 10);
|
|
103
|
+
if (result.stdout === '200') {
|
|
104
|
+
return ApiCredentialStatus.Valid;
|
|
105
|
+
}
|
|
106
|
+
return ApiCredentialStatus.Invalid;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export const LINEAR = new Linear();
|
|
110
|
+
//# sourceMappingURL=linear.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linear.js","sourceRoot":"","sources":["../../../src/services/linear.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack service implementation.
|
|
3
|
+
*/
|
|
4
|
+
import type { Response } from 'playwright';
|
|
5
|
+
import { ApiCredentialStatus, ApiCredentials } from '../apiCredentials.js';
|
|
6
|
+
import { Service, SimpleServiceSession } from './base.js';
|
|
7
|
+
declare class SlackServiceSession extends SimpleServiceSession {
|
|
8
|
+
private pendingDCookie;
|
|
9
|
+
protected getApiCredentialsFromResponse(response: Response): Promise<ApiCredentials | null>;
|
|
10
|
+
}
|
|
11
|
+
export declare class Slack implements Service {
|
|
12
|
+
readonly name = "slack";
|
|
13
|
+
readonly baseApiUrls: readonly ["https://slack.com/api/"];
|
|
14
|
+
readonly loginUrl = "https://slack.com/signin";
|
|
15
|
+
readonly credentialCheckCurlArguments: readonly ["https://slack.com/api/auth.test"];
|
|
16
|
+
getSession(): SlackServiceSession;
|
|
17
|
+
checkApiCredentials(apiCredentials: ApiCredentials): ApiCredentialStatus;
|
|
18
|
+
}
|
|
19
|
+
export declare const SLACK: Slack;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=slack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../../src/services/slack.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAuB,MAAM,sBAAsB,CAAC;AAEhG,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAE1D,cAAM,mBAAoB,SAAQ,oBAAoB;IACpD,OAAO,CAAC,cAAc,CAAuB;cAE7B,6BAA6B,CAC3C,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CAmClC;AAED,qBAAa,KAAM,YAAW,OAAO;IACnC,QAAQ,CAAC,IAAI,WAAW;IACxB,QAAQ,CAAC,WAAW,sCAAuC;IAC3D,QAAQ,CAAC,QAAQ,8BAA8B;IAE/C,QAAQ,CAAC,4BAA4B,+CAAgD;IAErF,UAAU,IAAI,mBAAmB;IAIjC,mBAAmB,CAAC,cAAc,EAAE,cAAc,GAAG,mBAAmB;CAoBzE;AAED,eAAO,MAAM,KAAK,OAAc,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack service implementation.
|
|
3
|
+
*/
|
|
4
|
+
import { ApiCredentialStatus, SlackApiCredentials } from '../apiCredentials.js';
|
|
5
|
+
import { runCaptured } from '../curl.js';
|
|
6
|
+
import { SimpleServiceSession } from './base.js';
|
|
7
|
+
class SlackServiceSession extends SimpleServiceSession {
|
|
8
|
+
pendingDCookie = null;
|
|
9
|
+
async getApiCredentialsFromResponse(response) {
|
|
10
|
+
const request = response.request();
|
|
11
|
+
const url = request.url();
|
|
12
|
+
// Check if the domain is under slack.com
|
|
13
|
+
if (!/^https:\/\/([a-z0-9-]+\.)?slack\.com\//.test(url)) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const headers = await request.allHeaders();
|
|
17
|
+
const cookieHeader = headers.cookie;
|
|
18
|
+
if (cookieHeader === undefined) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const cookieMatch = /\bd=([^;]+)/.exec(cookieHeader);
|
|
22
|
+
if (!cookieMatch?.[1]) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const dCookie = cookieMatch[1];
|
|
26
|
+
this.pendingDCookie = dCookie;
|
|
27
|
+
// Extract token from response body (JSON embedded in HTML or raw JSON)
|
|
28
|
+
try {
|
|
29
|
+
const responseBody = await response.text();
|
|
30
|
+
const tokenMatch = /"api_token":"(xoxc-[a-zA-Z0-9-]+)"/.exec(responseBody);
|
|
31
|
+
if (tokenMatch?.[1]) {
|
|
32
|
+
return new SlackApiCredentials(tokenMatch[1], dCookie);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Ignore errors reading response body
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export class Slack {
|
|
42
|
+
name = 'slack';
|
|
43
|
+
baseApiUrls = ['https://slack.com/api/'];
|
|
44
|
+
loginUrl = 'https://slack.com/signin';
|
|
45
|
+
credentialCheckCurlArguments = ['https://slack.com/api/auth.test'];
|
|
46
|
+
getSession() {
|
|
47
|
+
return new SlackServiceSession(this);
|
|
48
|
+
}
|
|
49
|
+
checkApiCredentials(apiCredentials) {
|
|
50
|
+
if (!(apiCredentials instanceof SlackApiCredentials)) {
|
|
51
|
+
return ApiCredentialStatus.Invalid;
|
|
52
|
+
}
|
|
53
|
+
const result = runCaptured(['-s', ...apiCredentials.asCurlArguments(), ...this.credentialCheckCurlArguments], 10);
|
|
54
|
+
try {
|
|
55
|
+
const data = JSON.parse(result.stdout);
|
|
56
|
+
if (data.ok) {
|
|
57
|
+
return ApiCredentialStatus.Valid;
|
|
58
|
+
}
|
|
59
|
+
return ApiCredentialStatus.Invalid;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return ApiCredentialStatus.Invalid;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export const SLACK = new Slack();
|
|
67
|
+
//# sourceMappingURL=slack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack.js","sourceRoot":"","sources":["../../../src/services/slack.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,mBAAmB,EAAkB,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAChG,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAW,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAE1D,MAAM,mBAAoB,SAAQ,oBAAoB;IAC5C,cAAc,GAAkB,IAAI,CAAC;IAEnC,KAAK,CAAC,6BAA6B,CAC3C,QAAkB;QAElB,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAE1B,yCAAyC;QACzC,IAAI,CAAC,wCAAwC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACxD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;QAC3C,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;QACpC,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACrD,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC;QAE9B,uEAAuE;QACvE,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC3C,MAAM,UAAU,GAAG,oCAAoC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC3E,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpB,OAAO,IAAI,mBAAmB,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,sCAAsC;QACxC,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED,MAAM,OAAO,KAAK;IACP,IAAI,GAAG,OAAO,CAAC;IACf,WAAW,GAAG,CAAC,wBAAwB,CAAU,CAAC;IAClD,QAAQ,GAAG,0BAA0B,CAAC;IAEtC,4BAA4B,GAAG,CAAC,iCAAiC,CAAU,CAAC;IAErF,UAAU;QACR,OAAO,IAAI,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC;IAED,mBAAmB,CAAC,cAA8B;QAChD,IAAI,CAAC,CAAC,cAAc,YAAY,mBAAmB,CAAC,EAAE,CAAC;YACrD,OAAO,mBAAmB,CAAC,OAAO,CAAC;QACrC,CAAC;QAED,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,IAAI,EAAE,GAAG,cAAc,CAAC,eAAe,EAAE,EAAE,GAAG,IAAI,CAAC,4BAA4B,CAAC,EACjF,EAAE,CACH,CAAC;QAEF,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAqB,CAAC;YAC3D,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;gBACZ,OAAO,mBAAmB,CAAC,KAAK,CAAC;YACnC,CAAC;YACD,OAAO,mBAAmB,CAAC,OAAO,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,mBAAmB,CAAC,OAAO,CAAC;QACrC,CAAC;IACH,CAAC;CACF;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiCredentialStore.test.d.ts","sourceRoot":"","sources":["../../tests/apiCredentialStore.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { mkdtempSync, rmSync, existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { ApiCredentialStore } from '../src/apiCredentialStore.js';
|
|
6
|
+
import { AuthorizationBearer, AuthorizationBare, SlackApiCredentials, } from '../src/apiCredentials.js';
|
|
7
|
+
import { EncryptedStorage } from '../src/encryptedStorage.js';
|
|
8
|
+
import { generateKey } from '../src/encryption.js';
|
|
9
|
+
describe('ApiCredentialStore', () => {
|
|
10
|
+
let tempDir;
|
|
11
|
+
let storePath;
|
|
12
|
+
let encryptedStorage;
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
tempDir = mkdtempSync(join(tmpdir(), 'latchkey-test-'));
|
|
15
|
+
storePath = join(tempDir, 'credentials.json');
|
|
16
|
+
encryptedStorage = new EncryptedStorage({ encryptionKeyOverride: generateKey() });
|
|
17
|
+
});
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
20
|
+
});
|
|
21
|
+
describe('get', () => {
|
|
22
|
+
it('should return null for non-existent store file', () => {
|
|
23
|
+
const store = new ApiCredentialStore(storePath, encryptedStorage);
|
|
24
|
+
expect(store.get('slack')).toBeNull();
|
|
25
|
+
});
|
|
26
|
+
it('should return null for non-existent service', () => {
|
|
27
|
+
const store = new ApiCredentialStore(storePath, encryptedStorage);
|
|
28
|
+
store.save('discord', new AuthorizationBare('token'));
|
|
29
|
+
expect(store.get('slack')).toBeNull();
|
|
30
|
+
});
|
|
31
|
+
it('should retrieve saved AuthorizationBearer credentials', () => {
|
|
32
|
+
const store = new ApiCredentialStore(storePath, encryptedStorage);
|
|
33
|
+
const credentials = new AuthorizationBearer('test-token');
|
|
34
|
+
store.save('github', credentials);
|
|
35
|
+
const retrieved = store.get('github');
|
|
36
|
+
expect(retrieved).toBeInstanceOf(AuthorizationBearer);
|
|
37
|
+
expect(retrieved.token).toBe('test-token');
|
|
38
|
+
});
|
|
39
|
+
it('should retrieve saved AuthorizationBare credentials', () => {
|
|
40
|
+
const store = new ApiCredentialStore(storePath, encryptedStorage);
|
|
41
|
+
const credentials = new AuthorizationBare('discord-token');
|
|
42
|
+
store.save('discord', credentials);
|
|
43
|
+
const retrieved = store.get('discord');
|
|
44
|
+
expect(retrieved).toBeInstanceOf(AuthorizationBare);
|
|
45
|
+
expect(retrieved.token).toBe('discord-token');
|
|
46
|
+
});
|
|
47
|
+
it('should retrieve saved SlackApiCredentials', () => {
|
|
48
|
+
const store = new ApiCredentialStore(storePath, encryptedStorage);
|
|
49
|
+
const credentials = new SlackApiCredentials('xoxc-token', 'd-cookie');
|
|
50
|
+
store.save('slack', credentials);
|
|
51
|
+
const retrieved = store.get('slack');
|
|
52
|
+
expect(retrieved).toBeInstanceOf(SlackApiCredentials);
|
|
53
|
+
expect(retrieved.token).toBe('xoxc-token');
|
|
54
|
+
expect(retrieved.dCookie).toBe('d-cookie');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe('save', () => {
|
|
58
|
+
it('should create the store file if it does not exist', () => {
|
|
59
|
+
const store = new ApiCredentialStore(storePath, encryptedStorage);
|
|
60
|
+
store.save('github', new AuthorizationBearer('token'));
|
|
61
|
+
expect(existsSync(storePath)).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
it('should create parent directories if they do not exist', () => {
|
|
64
|
+
const nestedPath = join(tempDir, 'nested', 'deep', 'credentials.json');
|
|
65
|
+
const store = new ApiCredentialStore(nestedPath, encryptedStorage);
|
|
66
|
+
store.save('github', new AuthorizationBearer('token'));
|
|
67
|
+
expect(existsSync(nestedPath)).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
it('should overwrite existing credentials for the same service', () => {
|
|
70
|
+
const store = new ApiCredentialStore(storePath, encryptedStorage);
|
|
71
|
+
store.save('github', new AuthorizationBearer('old-token'));
|
|
72
|
+
store.save('github', new AuthorizationBearer('new-token'));
|
|
73
|
+
const retrieved = store.get('github');
|
|
74
|
+
expect(retrieved.token).toBe('new-token');
|
|
75
|
+
});
|
|
76
|
+
it('should preserve other services when saving', () => {
|
|
77
|
+
const store = new ApiCredentialStore(storePath, encryptedStorage);
|
|
78
|
+
store.save('github', new AuthorizationBearer('github-token'));
|
|
79
|
+
store.save('discord', new AuthorizationBare('discord-token'));
|
|
80
|
+
expect(store.get('github')).not.toBeNull();
|
|
81
|
+
expect(store.get('discord')).not.toBeNull();
|
|
82
|
+
});
|
|
83
|
+
it('should write valid JSON (encrypted)', () => {
|
|
84
|
+
const store = new ApiCredentialStore(storePath, encryptedStorage);
|
|
85
|
+
store.save('github', new AuthorizationBearer('token'));
|
|
86
|
+
const content = readFileSync(storePath, 'utf-8');
|
|
87
|
+
// When encrypted, content starts with prefix, followed by encrypted JSON
|
|
88
|
+
expect(content.startsWith('LATCHKEY_ENCRYPTED:')).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
describe('delete', () => {
|
|
92
|
+
it('should return false for non-existent service', () => {
|
|
93
|
+
const store = new ApiCredentialStore(storePath, encryptedStorage);
|
|
94
|
+
expect(store.delete('github')).toBe(false);
|
|
95
|
+
});
|
|
96
|
+
it('should return false for non-existent store file', () => {
|
|
97
|
+
const store = new ApiCredentialStore(storePath, encryptedStorage);
|
|
98
|
+
expect(store.delete('github')).toBe(false);
|
|
99
|
+
});
|
|
100
|
+
it('should delete existing credentials and return true', () => {
|
|
101
|
+
const store = new ApiCredentialStore(storePath, encryptedStorage);
|
|
102
|
+
store.save('github', new AuthorizationBearer('token'));
|
|
103
|
+
expect(store.delete('github')).toBe(true);
|
|
104
|
+
expect(store.get('github')).toBeNull();
|
|
105
|
+
});
|
|
106
|
+
it('should preserve other services when deleting', () => {
|
|
107
|
+
const store = new ApiCredentialStore(storePath, encryptedStorage);
|
|
108
|
+
store.save('github', new AuthorizationBearer('github-token'));
|
|
109
|
+
store.save('discord', new AuthorizationBare('discord-token'));
|
|
110
|
+
store.delete('github');
|
|
111
|
+
expect(store.get('github')).toBeNull();
|
|
112
|
+
expect(store.get('discord')).not.toBeNull();
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
describe('multiple credential types', () => {
|
|
116
|
+
it('should store and retrieve different credential types', () => {
|
|
117
|
+
const store = new ApiCredentialStore(storePath, encryptedStorage);
|
|
118
|
+
store.save('github', new AuthorizationBearer('github-token'));
|
|
119
|
+
store.save('discord', new AuthorizationBare('discord-token'));
|
|
120
|
+
store.save('slack', new SlackApiCredentials('slack-token', 'slack-cookie'));
|
|
121
|
+
const github = store.get('github');
|
|
122
|
+
const discord = store.get('discord');
|
|
123
|
+
const slack = store.get('slack');
|
|
124
|
+
expect(github).toBeInstanceOf(AuthorizationBearer);
|
|
125
|
+
expect(discord).toBeInstanceOf(AuthorizationBare);
|
|
126
|
+
expect(slack).toBeInstanceOf(SlackApiCredentials);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
//# sourceMappingURL=apiCredentialStore.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiCredentialStore.test.js","sourceRoot":"","sources":["../../tests/apiCredentialStore.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiCredentials.test.d.ts","sourceRoot":"","sources":["../../tests/apiCredentials.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { AuthorizationBearer, AuthorizationBare, SlackApiCredentials, deserializeCredentials, serializeCredentials, ApiCredentialsSchema, } from '../src/apiCredentials.js';
|
|
3
|
+
describe('AuthorizationBearer', () => {
|
|
4
|
+
it('should generate correct curl arguments', () => {
|
|
5
|
+
const credentials = new AuthorizationBearer('test-token-123');
|
|
6
|
+
expect(credentials.asCurlArguments()).toEqual(['-H', 'Authorization: Bearer test-token-123']);
|
|
7
|
+
});
|
|
8
|
+
it('should serialize to JSON', () => {
|
|
9
|
+
const credentials = new AuthorizationBearer('test-token-123');
|
|
10
|
+
expect(credentials.toJSON()).toEqual({
|
|
11
|
+
objectType: 'authorizationBearer',
|
|
12
|
+
token: 'test-token-123',
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
it('should deserialize from JSON', () => {
|
|
16
|
+
const data = {
|
|
17
|
+
objectType: 'authorizationBearer',
|
|
18
|
+
token: 'test-token-123',
|
|
19
|
+
};
|
|
20
|
+
const credentials = AuthorizationBearer.fromJSON(data);
|
|
21
|
+
expect(credentials.token).toBe('test-token-123');
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe('AuthorizationBare', () => {
|
|
25
|
+
it('should generate correct curl arguments', () => {
|
|
26
|
+
const credentials = new AuthorizationBare('raw-token-456');
|
|
27
|
+
expect(credentials.asCurlArguments()).toEqual(['-H', 'Authorization: raw-token-456']);
|
|
28
|
+
});
|
|
29
|
+
it('should serialize to JSON', () => {
|
|
30
|
+
const credentials = new AuthorizationBare('raw-token-456');
|
|
31
|
+
expect(credentials.toJSON()).toEqual({
|
|
32
|
+
objectType: 'authorizationBare',
|
|
33
|
+
token: 'raw-token-456',
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
it('should deserialize from JSON', () => {
|
|
37
|
+
const data = {
|
|
38
|
+
objectType: 'authorizationBare',
|
|
39
|
+
token: 'raw-token-456',
|
|
40
|
+
};
|
|
41
|
+
const credentials = AuthorizationBare.fromJSON(data);
|
|
42
|
+
expect(credentials.token).toBe('raw-token-456');
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe('SlackApiCredentials', () => {
|
|
46
|
+
it('should generate correct curl arguments with token and cookie', () => {
|
|
47
|
+
const credentials = new SlackApiCredentials('xoxc-token', 'd-cookie-value');
|
|
48
|
+
expect(credentials.asCurlArguments()).toEqual([
|
|
49
|
+
'-H',
|
|
50
|
+
'Authorization: Bearer xoxc-token',
|
|
51
|
+
'-H',
|
|
52
|
+
'Cookie: d=d-cookie-value',
|
|
53
|
+
]);
|
|
54
|
+
});
|
|
55
|
+
it('should serialize to JSON', () => {
|
|
56
|
+
const credentials = new SlackApiCredentials('xoxc-token', 'd-cookie-value');
|
|
57
|
+
expect(credentials.toJSON()).toEqual({
|
|
58
|
+
objectType: 'slack',
|
|
59
|
+
token: 'xoxc-token',
|
|
60
|
+
dCookie: 'd-cookie-value',
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
it('should deserialize from JSON', () => {
|
|
64
|
+
const data = {
|
|
65
|
+
objectType: 'slack',
|
|
66
|
+
token: 'xoxc-token',
|
|
67
|
+
dCookie: 'd-cookie-value',
|
|
68
|
+
};
|
|
69
|
+
const credentials = SlackApiCredentials.fromJSON(data);
|
|
70
|
+
expect(credentials.token).toBe('xoxc-token');
|
|
71
|
+
expect(credentials.dCookie).toBe('d-cookie-value');
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
describe('deserializeCredentials', () => {
|
|
75
|
+
it('should deserialize AuthorizationBearer', () => {
|
|
76
|
+
const data = {
|
|
77
|
+
objectType: 'authorizationBearer',
|
|
78
|
+
token: 'bearer-token',
|
|
79
|
+
};
|
|
80
|
+
const credentials = deserializeCredentials(data);
|
|
81
|
+
expect(credentials).toBeInstanceOf(AuthorizationBearer);
|
|
82
|
+
expect(credentials.token).toBe('bearer-token');
|
|
83
|
+
});
|
|
84
|
+
it('should deserialize AuthorizationBare', () => {
|
|
85
|
+
const data = {
|
|
86
|
+
objectType: 'authorizationBare',
|
|
87
|
+
token: 'bare-token',
|
|
88
|
+
};
|
|
89
|
+
const credentials = deserializeCredentials(data);
|
|
90
|
+
expect(credentials).toBeInstanceOf(AuthorizationBare);
|
|
91
|
+
expect(credentials.token).toBe('bare-token');
|
|
92
|
+
});
|
|
93
|
+
it('should deserialize SlackApiCredentials', () => {
|
|
94
|
+
const data = {
|
|
95
|
+
objectType: 'slack',
|
|
96
|
+
token: 'slack-token',
|
|
97
|
+
dCookie: 'slack-cookie',
|
|
98
|
+
};
|
|
99
|
+
const credentials = deserializeCredentials(data);
|
|
100
|
+
expect(credentials).toBeInstanceOf(SlackApiCredentials);
|
|
101
|
+
expect(credentials.token).toBe('slack-token');
|
|
102
|
+
expect(credentials.dCookie).toBe('slack-cookie');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
describe('serializeCredentials', () => {
|
|
106
|
+
it('should serialize AuthorizationBearer', () => {
|
|
107
|
+
const credentials = new AuthorizationBearer('test-token');
|
|
108
|
+
const data = serializeCredentials(credentials);
|
|
109
|
+
expect(data).toEqual({
|
|
110
|
+
objectType: 'authorizationBearer',
|
|
111
|
+
token: 'test-token',
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
it('should serialize AuthorizationBare', () => {
|
|
115
|
+
const credentials = new AuthorizationBare('test-token');
|
|
116
|
+
const data = serializeCredentials(credentials);
|
|
117
|
+
expect(data).toEqual({
|
|
118
|
+
objectType: 'authorizationBare',
|
|
119
|
+
token: 'test-token',
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
it('should serialize SlackApiCredentials', () => {
|
|
123
|
+
const credentials = new SlackApiCredentials('token', 'cookie');
|
|
124
|
+
const data = serializeCredentials(credentials);
|
|
125
|
+
expect(data).toEqual({
|
|
126
|
+
objectType: 'slack',
|
|
127
|
+
token: 'token',
|
|
128
|
+
dCookie: 'cookie',
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
describe('ApiCredentialsSchema', () => {
|
|
133
|
+
it('should validate AuthorizationBearer', () => {
|
|
134
|
+
const result = ApiCredentialsSchema.safeParse({
|
|
135
|
+
objectType: 'authorizationBearer',
|
|
136
|
+
token: 'test',
|
|
137
|
+
});
|
|
138
|
+
expect(result.success).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
it('should validate AuthorizationBare', () => {
|
|
141
|
+
const result = ApiCredentialsSchema.safeParse({
|
|
142
|
+
objectType: 'authorizationBare',
|
|
143
|
+
token: 'test',
|
|
144
|
+
});
|
|
145
|
+
expect(result.success).toBe(true);
|
|
146
|
+
});
|
|
147
|
+
it('should validate SlackApiCredentials', () => {
|
|
148
|
+
const result = ApiCredentialsSchema.safeParse({
|
|
149
|
+
objectType: 'slack',
|
|
150
|
+
token: 'test',
|
|
151
|
+
dCookie: 'cookie',
|
|
152
|
+
});
|
|
153
|
+
expect(result.success).toBe(true);
|
|
154
|
+
});
|
|
155
|
+
it('should reject invalid object type', () => {
|
|
156
|
+
const result = ApiCredentialsSchema.safeParse({
|
|
157
|
+
objectType: 'invalid',
|
|
158
|
+
token: 'test',
|
|
159
|
+
});
|
|
160
|
+
expect(result.success).toBe(false);
|
|
161
|
+
});
|
|
162
|
+
it('should reject missing token', () => {
|
|
163
|
+
const result = ApiCredentialsSchema.safeParse({
|
|
164
|
+
objectType: 'authorizationBearer',
|
|
165
|
+
});
|
|
166
|
+
expect(result.success).toBe(false);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
//# sourceMappingURL=apiCredentials.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiCredentials.test.js","sourceRoot":"","sources":["../../tests/apiCredentials.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.test.d.ts","sourceRoot":"","sources":["../../tests/cli.test.ts"],"names":[],"mappings":""}
|