latchkey 0.1.4 → 1.0.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/LICENSE +1 -1
- package/README.md +93 -56
- package/dist/integrations/SKILL.md +77 -0
- package/dist/package.json +67 -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/src/apiCredentialStore.d.ts +1 -0
- package/dist/src/apiCredentialStore.d.ts.map +1 -1
- package/dist/src/apiCredentialStore.js +12 -0
- package/dist/src/apiCredentialStore.js.map +1 -1
- package/dist/src/apiCredentials.d.ts +116 -1
- package/dist/src/apiCredentials.d.ts.map +1 -1
- package/dist/src/apiCredentials.js +119 -1
- package/dist/src/apiCredentials.js.map +1 -1
- 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.js +5 -3
- package/dist/src/cli.js.map +1 -1
- package/dist/src/cliCommands.d.ts.map +1 -1
- package/dist/src/cliCommands.js +218 -81
- package/dist/src/cliCommands.js.map +1 -1
- package/dist/src/config.d.ts +13 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +50 -4
- package/dist/src/config.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- 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 +49 -0
- package/dist/src/oauthUtils.d.ts.map +1 -0
- package/dist/src/oauthUtils.js +183 -0
- package/dist/src/oauthUtils.js.map +1 -0
- package/dist/src/playwrightUtils.d.ts +14 -1
- package/dist/src/playwrightUtils.d.ts.map +1 -1
- package/dist/src/playwrightUtils.js +37 -8
- package/dist/src/playwrightUtils.js.map +1 -1
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +20 -4
- package/dist/src/registry.js.map +1 -1
- package/dist/src/services/base.d.ts +43 -15
- package/dist/src/services/base.d.ts.map +1 -1
- package/dist/src/services/base.js +49 -9
- package/dist/src/services/base.js.map +1 -1
- package/dist/src/services/discord.d.ts +4 -3
- package/dist/src/services/discord.d.ts.map +1 -1
- package/dist/src/services/discord.js +6 -22
- package/dist/src/services/discord.js.map +1 -1
- package/dist/src/services/dropbox.d.ts +5 -4
- package/dist/src/services/dropbox.d.ts.map +1 -1
- package/dist/src/services/dropbox.js +10 -27
- package/dist/src/services/dropbox.js.map +1 -1
- package/dist/src/services/github.d.ts +5 -4
- package/dist/src/services/github.d.ts.map +1 -1
- package/dist/src/services/github.js +21 -30
- package/dist/src/services/github.js.map +1 -1
- package/dist/src/services/google.d.ts +34 -0
- package/dist/src/services/google.d.ts.map +1 -0
- package/dist/src/services/google.js +336 -0
- package/dist/src/services/google.js.map +1 -0
- package/dist/src/services/index.d.ts +4 -2
- package/dist/src/services/index.d.ts.map +1 -1
- package/dist/src/services/index.js +4 -1
- package/dist/src/services/index.js.map +1 -1
- package/dist/src/services/linear.d.ts +5 -4
- package/dist/src/services/linear.d.ts.map +1 -1
- package/dist/src/services/linear.js +10 -29
- package/dist/src/services/linear.js.map +1 -1
- package/dist/src/services/mailchimp.d.ts +11 -0
- package/dist/src/services/mailchimp.d.ts.map +1 -0
- package/dist/src/services/mailchimp.js +16 -0
- package/dist/src/services/mailchimp.js.map +1 -0
- package/dist/src/services/notion.d.ts +29 -0
- package/dist/src/services/notion.d.ts.map +1 -0
- package/dist/src/services/notion.js +102 -0
- package/dist/src/services/notion.js.map +1 -0
- package/dist/src/services/slack.d.ts +3 -1
- package/dist/src/services/slack.d.ts.map +1 -1
- package/dist/src/services/slack.js +5 -5
- package/dist/src/services/slack.js.map +1 -1
- package/dist/src/skillMd.d.ts +2 -0
- package/dist/src/skillMd.d.ts.map +1 -0
- package/dist/src/skillMd.js +19 -0
- package/dist/src/skillMd.js.map +1 -0
- package/dist/tests/apiCredentials.test.js +59 -1
- package/dist/tests/apiCredentials.test.js.map +1 -1
- package/dist/tests/cli.test.js +283 -104
- package/dist/tests/cli.test.js.map +1 -1
- package/dist/tests/playwrightDownload.test.js +2 -2
- package/dist/tests/playwrightDownload.test.js.map +1 -1
- package/dist/tests/registry.test.js +28 -3
- package/dist/tests/registry.test.js.map +1 -1
- package/dist/tests/servicesAgainstRecordings.test.js +3 -0
- package/dist/tests/servicesAgainstRecordings.test.js.map +1 -1
- package/package.json +6 -6
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Base classes and interfaces for service implementations.
|
|
3
3
|
*/
|
|
4
|
+
import { ApiCredentialStatus, ApiCredentialsUsageError, } from '../apiCredentials.js';
|
|
5
|
+
import { runCaptured } from '../curl.js';
|
|
4
6
|
import { showSpinnerPage, withTempBrowserContext, } from '../playwrightUtils.js';
|
|
5
7
|
export class LoginCancelledError extends Error {
|
|
6
8
|
constructor(message = 'Login was cancelled because the browser was closed.') {
|
|
@@ -14,19 +16,54 @@ export class LoginFailedError extends Error {
|
|
|
14
16
|
this.name = 'LoginFailedError';
|
|
15
17
|
}
|
|
16
18
|
}
|
|
17
|
-
function isBrowserClosedError(error) {
|
|
19
|
+
export function isBrowserClosedError(error) {
|
|
18
20
|
const message = error.message.toLowerCase();
|
|
19
21
|
return (message.includes('target closed') ||
|
|
20
22
|
message.includes('browser closed') ||
|
|
21
23
|
message.includes('browser has been closed') ||
|
|
22
24
|
message.includes('context has been closed') ||
|
|
23
|
-
message.includes('page has been closed')
|
|
25
|
+
message.includes('page has been closed') ||
|
|
26
|
+
message.includes('net::err_aborted'));
|
|
24
27
|
}
|
|
25
28
|
function isTimeoutError(error) {
|
|
26
29
|
return error.name === 'TimeoutError';
|
|
27
30
|
}
|
|
28
31
|
/**
|
|
29
|
-
*
|
|
32
|
+
* Abstract base class for services that latchkey can authenticate with.
|
|
33
|
+
*/
|
|
34
|
+
export class Service {
|
|
35
|
+
/**
|
|
36
|
+
* Check if the given API credentials are valid for this service.
|
|
37
|
+
*/
|
|
38
|
+
checkApiCredentials(apiCredentials) {
|
|
39
|
+
let curlArgs;
|
|
40
|
+
try {
|
|
41
|
+
curlArgs = apiCredentials.asCurlArguments();
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (error instanceof ApiCredentialsUsageError) {
|
|
45
|
+
return ApiCredentialStatus.Missing;
|
|
46
|
+
}
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
const result = runCaptured([
|
|
50
|
+
'-s',
|
|
51
|
+
'-o',
|
|
52
|
+
'/dev/null',
|
|
53
|
+
'-w',
|
|
54
|
+
'%{http_code}',
|
|
55
|
+
...curlArgs,
|
|
56
|
+
...this.credentialCheckCurlArguments,
|
|
57
|
+
], 10);
|
|
58
|
+
if (result.stdout === '200') {
|
|
59
|
+
return ApiCredentialStatus.Valid;
|
|
60
|
+
}
|
|
61
|
+
return ApiCredentialStatus.Invalid;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Base class for service sessions that handle browser-based interactions.
|
|
66
|
+
* This includes login, preparation steps, and any other browser automation.
|
|
30
67
|
*/
|
|
31
68
|
export class ServiceSession {
|
|
32
69
|
service;
|
|
@@ -54,8 +91,11 @@ export class ServiceSession {
|
|
|
54
91
|
}
|
|
55
92
|
/**
|
|
56
93
|
* Perform the login flow and return the extracted credentials.
|
|
94
|
+
* @param encryptedStorage - Storage for managing credentials
|
|
95
|
+
* @param launchOptions - Browser launch options
|
|
96
|
+
* @param oldCredentials - Optional existing credentials to reuse (e.g., client ID/secret)
|
|
57
97
|
*/
|
|
58
|
-
async login(encryptedStorage, launchOptions = {}) {
|
|
98
|
+
async login(encryptedStorage, launchOptions = {}, oldCredentials) {
|
|
59
99
|
return withTempBrowserContext(encryptedStorage, launchOptions, async ({ browser, context }) => {
|
|
60
100
|
const page = await context.newPage();
|
|
61
101
|
page.on('response', (response) => {
|
|
@@ -73,7 +113,7 @@ export class ServiceSession {
|
|
|
73
113
|
}
|
|
74
114
|
let apiCredentials;
|
|
75
115
|
try {
|
|
76
|
-
apiCredentials = await this.finalizeCredentials(browser, context);
|
|
116
|
+
apiCredentials = await this.finalizeCredentials(browser, context, oldCredentials);
|
|
77
117
|
}
|
|
78
118
|
catch (error) {
|
|
79
119
|
if (error instanceof Error && isBrowserClosedError(error)) {
|
|
@@ -117,7 +157,7 @@ export class SimpleServiceSession extends ServiceSession {
|
|
|
117
157
|
isLoginComplete() {
|
|
118
158
|
return this.apiCredentials !== null;
|
|
119
159
|
}
|
|
120
|
-
finalizeCredentials(_browser, _context) {
|
|
160
|
+
finalizeCredentials(_browser, _context, _oldCredentials) {
|
|
121
161
|
return Promise.resolve(this.apiCredentials);
|
|
122
162
|
}
|
|
123
163
|
}
|
|
@@ -129,9 +169,9 @@ export class SimpleServiceSession extends ServiceSession {
|
|
|
129
169
|
* (e.g., navigating to settings and creating an API key).
|
|
130
170
|
*/
|
|
131
171
|
export class BrowserFollowupServiceSession extends ServiceSession {
|
|
132
|
-
async finalizeCredentials(_browser, context) {
|
|
133
|
-
await showSpinnerPage(context, this.service.
|
|
134
|
-
return this.performBrowserFollowup(context);
|
|
172
|
+
async finalizeCredentials(_browser, context, oldCredentials) {
|
|
173
|
+
await showSpinnerPage(context, `Finalizing ${this.service.displayName} login...`);
|
|
174
|
+
return this.performBrowserFollowup(context, oldCredentials);
|
|
135
175
|
}
|
|
136
176
|
}
|
|
137
177
|
//# sourceMappingURL=base.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/services/base.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/services/base.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,18 +2,19 @@
|
|
|
2
2
|
* Discord service implementation.
|
|
3
3
|
*/
|
|
4
4
|
import type { Response } from 'playwright';
|
|
5
|
-
import {
|
|
5
|
+
import { ApiCredentials } from '../apiCredentials.js';
|
|
6
6
|
import { Service, SimpleServiceSession } from './base.js';
|
|
7
7
|
declare class DiscordServiceSession extends SimpleServiceSession {
|
|
8
8
|
protected getApiCredentialsFromResponse(response: Response): Promise<ApiCredentials | null>;
|
|
9
9
|
}
|
|
10
|
-
export declare class Discord
|
|
10
|
+
export declare class Discord extends Service {
|
|
11
11
|
readonly name = "discord";
|
|
12
|
+
readonly displayName = "Discord";
|
|
12
13
|
readonly baseApiUrls: readonly ["https://discord.com/api/"];
|
|
13
14
|
readonly loginUrl = "https://discord.com/login";
|
|
15
|
+
readonly info: string;
|
|
14
16
|
readonly credentialCheckCurlArguments: readonly ["https://discord.com/api/v9/users/@me"];
|
|
15
17
|
getSession(): DiscordServiceSession;
|
|
16
|
-
checkApiCredentials(apiCredentials: ApiCredentials): ApiCredentialStatus;
|
|
17
18
|
}
|
|
18
19
|
export declare const DISCORD: Discord;
|
|
19
20
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discord.d.ts","sourceRoot":"","sources":["../../../src/services/discord.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"discord.d.ts","sourceRoot":"","sources":["../../../src/services/discord.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAqB,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAE1D,cAAM,qBAAsB,SAAQ,oBAAoB;cACtC,6BAA6B,CAC3C,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CAsBlC;AAED,qBAAa,OAAQ,SAAQ,OAAO;IAClC,QAAQ,CAAC,IAAI,aAAa;IAC1B,QAAQ,CAAC,WAAW,aAAa;IACjC,QAAQ,CAAC,WAAW,wCAAyC;IAC7D,QAAQ,CAAC,QAAQ,+BAA+B;IAChD,QAAQ,CAAC,IAAI,SAEyD;IAEtE,QAAQ,CAAC,4BAA4B,oDAAqD;IAEjF,UAAU,IAAI,qBAAqB;CAG7C;AAED,eAAO,MAAM,OAAO,SAAgB,CAAC"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Discord service implementation.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { SimpleServiceSession } from './base.js';
|
|
4
|
+
import { AuthorizationBare } from '../apiCredentials.js';
|
|
5
|
+
import { Service, SimpleServiceSession } from './base.js';
|
|
7
6
|
class DiscordServiceSession extends SimpleServiceSession {
|
|
8
7
|
async getApiCredentialsFromResponse(response) {
|
|
9
8
|
const request = response.request();
|
|
@@ -24,32 +23,17 @@ class DiscordServiceSession extends SimpleServiceSession {
|
|
|
24
23
|
return null;
|
|
25
24
|
}
|
|
26
25
|
}
|
|
27
|
-
export class Discord {
|
|
26
|
+
export class Discord extends Service {
|
|
28
27
|
name = 'discord';
|
|
28
|
+
displayName = 'Discord';
|
|
29
29
|
baseApiUrls = ['https://discord.com/api/'];
|
|
30
30
|
loginUrl = 'https://discord.com/login';
|
|
31
|
+
info = 'https://discord.com/developers/docs/reference. ' +
|
|
32
|
+
'Credentials are extracted from the user session, not a bot token.';
|
|
31
33
|
credentialCheckCurlArguments = ['https://discord.com/api/v9/users/@me'];
|
|
32
34
|
getSession() {
|
|
33
35
|
return new DiscordServiceSession(this);
|
|
34
36
|
}
|
|
35
|
-
checkApiCredentials(apiCredentials) {
|
|
36
|
-
if (!(apiCredentials instanceof AuthorizationBare)) {
|
|
37
|
-
return ApiCredentialStatus.Invalid;
|
|
38
|
-
}
|
|
39
|
-
const result = runCaptured([
|
|
40
|
-
'-s',
|
|
41
|
-
'-o',
|
|
42
|
-
'/dev/null',
|
|
43
|
-
'-w',
|
|
44
|
-
'%{http_code}',
|
|
45
|
-
...apiCredentials.asCurlArguments(),
|
|
46
|
-
...this.credentialCheckCurlArguments,
|
|
47
|
-
], 10);
|
|
48
|
-
if (result.stdout === '200') {
|
|
49
|
-
return ApiCredentialStatus.Valid;
|
|
50
|
-
}
|
|
51
|
-
return ApiCredentialStatus.Invalid;
|
|
52
|
-
}
|
|
53
37
|
}
|
|
54
38
|
export const DISCORD = new Discord();
|
|
55
39
|
//# sourceMappingURL=discord.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discord.js","sourceRoot":"","sources":["../../../src/services/discord.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,
|
|
1
|
+
{"version":3,"file":"discord.js","sourceRoot":"","sources":["../../../src/services/discord.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAkB,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAE1D,MAAM,qBAAsB,SAAQ,oBAAoB;IAC5C,KAAK,CAAC,6BAA6B,CAC3C,QAAkB;QAElB,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAE1B,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,0BAA0B,CAAC,EAAE,CAAC;YAChD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,oEAAoE;QACpE,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;QACjC,IAAI,MAAM,GAAG,GAAG,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;YAClC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;QAC3C,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;QAC5C,IAAI,aAAa,KAAK,SAAS,IAAI,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC/D,OAAO,IAAI,iBAAiB,CAAC,aAAa,CAAC,CAAC;QAC9C,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED,MAAM,OAAO,OAAQ,SAAQ,OAAO;IACzB,IAAI,GAAG,SAAS,CAAC;IACjB,WAAW,GAAG,SAAS,CAAC;IACxB,WAAW,GAAG,CAAC,0BAA0B,CAAU,CAAC;IACpD,QAAQ,GAAG,2BAA2B,CAAC;IACvC,IAAI,GACX,iDAAiD;QACjD,mEAAmE,CAAC;IAE7D,4BAA4B,GAAG,CAAC,sCAAsC,CAAU,CAAC;IAEjF,UAAU;QACjB,OAAO,IAAI,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;CACF;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC"}
|
|
@@ -2,21 +2,22 @@
|
|
|
2
2
|
* Dropbox service implementation.
|
|
3
3
|
*/
|
|
4
4
|
import type { Response, BrowserContext } from 'playwright';
|
|
5
|
-
import {
|
|
5
|
+
import { ApiCredentials } from '../apiCredentials.js';
|
|
6
6
|
import { Service, BrowserFollowupServiceSession } from './base.js';
|
|
7
7
|
declare class DropboxServiceSession extends BrowserFollowupServiceSession {
|
|
8
8
|
private isLoggedIn;
|
|
9
9
|
onResponse(response: Response): void;
|
|
10
10
|
protected isLoginComplete(): boolean;
|
|
11
|
-
protected performBrowserFollowup(context: BrowserContext): Promise<ApiCredentials | null>;
|
|
11
|
+
protected performBrowserFollowup(context: BrowserContext, _oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
12
12
|
}
|
|
13
|
-
export declare class Dropbox
|
|
13
|
+
export declare class Dropbox extends Service {
|
|
14
14
|
readonly name = "dropbox";
|
|
15
|
+
readonly displayName = "Dropbox";
|
|
15
16
|
readonly baseApiUrls: readonly ["https://api.dropboxapi.com/", "https://content.dropboxapi.com/", "https://notify.dropboxapi.com/"];
|
|
16
17
|
readonly loginUrl = "https://www.dropbox.com/login";
|
|
18
|
+
readonly info: string;
|
|
17
19
|
readonly credentialCheckCurlArguments: readonly ["-X", "POST", "https://api.dropboxapi.com/2/users/get_current_account"];
|
|
18
20
|
getSession(): DropboxServiceSession;
|
|
19
|
-
checkApiCredentials(apiCredentials: ApiCredentials): ApiCredentialStatus;
|
|
20
21
|
}
|
|
21
22
|
export declare const DROPBOX: Dropbox;
|
|
22
23
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropbox.d.ts","sourceRoot":"","sources":["../../../src/services/dropbox.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"dropbox.d.ts","sourceRoot":"","sources":["../../../src/services/dropbox.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAuB,MAAM,sBAAsB,CAAC;AAE3E,OAAO,EAAE,OAAO,EAAE,6BAA6B,EAAoB,MAAM,WAAW,CAAC;AAIrF,cAAM,qBAAsB,SAAQ,6BAA6B;IAC/D,OAAO,CAAC,UAAU,CAAS;IAE3B,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IA0BpC,SAAS,CAAC,eAAe,IAAI,OAAO;cAIpB,sBAAsB,CACpC,OAAO,EAAE,cAAc,EACvB,eAAe,CAAC,EAAE,cAAc,GAC/B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CAgFlC;AAED,qBAAa,OAAQ,SAAQ,OAAO;IAClC,QAAQ,CAAC,IAAI,aAAa;IAC1B,QAAQ,CAAC,WAAW,aAAa;IACjC,QAAQ,CAAC,WAAW,gHAIT;IACX,QAAQ,CAAC,QAAQ,mCAAmC;IACpD,QAAQ,CAAC,IAAI,SAE8F;IAE3G,QAAQ,CAAC,4BAA4B,oFAI1B;IAEF,UAAU,IAAI,qBAAqB;CAG7C;AAED,eAAO,MAAM,OAAO,SAAgB,CAAC"}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Dropbox service implementation.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { typeLikeHuman } from '../playwrightUtils.js';
|
|
8
|
-
import { BrowserFollowupServiceSession, LoginFailedError } from './base.js';
|
|
4
|
+
import { AuthorizationBearer } from '../apiCredentials.js';
|
|
5
|
+
import { generateLatchkeyAppName, typeLikeHuman } from '../playwrightUtils.js';
|
|
6
|
+
import { Service, BrowserFollowupServiceSession, LoginFailedError } from './base.js';
|
|
9
7
|
const DEFAULT_TIMEOUT_MS = 8000;
|
|
10
8
|
class DropboxServiceSession extends BrowserFollowupServiceSession {
|
|
11
9
|
isLoggedIn = false;
|
|
@@ -33,7 +31,7 @@ class DropboxServiceSession extends BrowserFollowupServiceSession {
|
|
|
33
31
|
isLoginComplete() {
|
|
34
32
|
return this.isLoggedIn;
|
|
35
33
|
}
|
|
36
|
-
async performBrowserFollowup(context) {
|
|
34
|
+
async performBrowserFollowup(context, _oldCredentials) {
|
|
37
35
|
const page = context.pages()[0];
|
|
38
36
|
if (!page) {
|
|
39
37
|
throw new LoginFailedError('No page available in browser context.');
|
|
@@ -45,11 +43,11 @@ class DropboxServiceSession extends BrowserFollowupServiceSession {
|
|
|
45
43
|
const fullPermissionsInput = page.locator('input#full_permissions');
|
|
46
44
|
await fullPermissionsInput.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
47
45
|
await fullPermissionsInput.click();
|
|
48
|
-
const appName =
|
|
46
|
+
const appName = generateLatchkeyAppName();
|
|
49
47
|
const appNameInput = page.locator('input#app-name');
|
|
50
48
|
await appNameInput.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
51
49
|
await typeLikeHuman(page, appNameInput, appName);
|
|
52
|
-
const createButton = page.
|
|
50
|
+
const createButton = page.locator('//*[@id="create-button" and not(@disabled)]');
|
|
53
51
|
await createButton.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
54
52
|
await createButton.click();
|
|
55
53
|
await page.waitForURL(/https:\/\/www\.dropbox\.com\/developers\/apps\/info\//, {
|
|
@@ -97,14 +95,17 @@ class DropboxServiceSession extends BrowserFollowupServiceSession {
|
|
|
97
95
|
return new AuthorizationBearer(token);
|
|
98
96
|
}
|
|
99
97
|
}
|
|
100
|
-
export class Dropbox {
|
|
98
|
+
export class Dropbox extends Service {
|
|
101
99
|
name = 'dropbox';
|
|
100
|
+
displayName = 'Dropbox';
|
|
102
101
|
baseApiUrls = [
|
|
103
102
|
'https://api.dropboxapi.com/',
|
|
104
103
|
'https://content.dropboxapi.com/',
|
|
105
104
|
'https://notify.dropboxapi.com/',
|
|
106
105
|
];
|
|
107
106
|
loginUrl = 'https://www.dropbox.com/login';
|
|
107
|
+
info = 'https://www.dropbox.com/developers/documentation/http/documentation. ' +
|
|
108
|
+
'Use api.dropboxapi.com for RPC-style endpoints and content.dropboxapi.com for content upload/download.';
|
|
108
109
|
credentialCheckCurlArguments = [
|
|
109
110
|
'-X',
|
|
110
111
|
'POST',
|
|
@@ -113,24 +114,6 @@ export class Dropbox {
|
|
|
113
114
|
getSession() {
|
|
114
115
|
return new DropboxServiceSession(this);
|
|
115
116
|
}
|
|
116
|
-
checkApiCredentials(apiCredentials) {
|
|
117
|
-
if (!(apiCredentials instanceof AuthorizationBearer)) {
|
|
118
|
-
return ApiCredentialStatus.Invalid;
|
|
119
|
-
}
|
|
120
|
-
const result = runCaptured([
|
|
121
|
-
'-s',
|
|
122
|
-
'-o',
|
|
123
|
-
'/dev/null',
|
|
124
|
-
'-w',
|
|
125
|
-
'%{http_code}',
|
|
126
|
-
...apiCredentials.asCurlArguments(),
|
|
127
|
-
...this.credentialCheckCurlArguments,
|
|
128
|
-
], 10);
|
|
129
|
-
if (result.stdout === '200') {
|
|
130
|
-
return ApiCredentialStatus.Valid;
|
|
131
|
-
}
|
|
132
|
-
return ApiCredentialStatus.Invalid;
|
|
133
|
-
}
|
|
134
117
|
}
|
|
135
118
|
export const DROPBOX = new Dropbox();
|
|
136
119
|
//# sourceMappingURL=dropbox.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropbox.js","sourceRoot":"","sources":["../../../src/services/dropbox.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"dropbox.js","sourceRoot":"","sources":["../../../src/services/dropbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,21 +2,22 @@
|
|
|
2
2
|
* GitHub service implementation.
|
|
3
3
|
*/
|
|
4
4
|
import type { Response, BrowserContext } from 'playwright';
|
|
5
|
-
import {
|
|
5
|
+
import { ApiCredentials } from '../apiCredentials.js';
|
|
6
6
|
import { Service, BrowserFollowupServiceSession } from './base.js';
|
|
7
7
|
declare class GithubServiceSession extends BrowserFollowupServiceSession {
|
|
8
8
|
private isLoggedIn;
|
|
9
9
|
onResponse(response: Response): void;
|
|
10
10
|
protected isLoginComplete(): boolean;
|
|
11
|
-
protected performBrowserFollowup(context: BrowserContext): Promise<ApiCredentials | null>;
|
|
11
|
+
protected performBrowserFollowup(context: BrowserContext, _oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
12
12
|
}
|
|
13
|
-
export declare class Github
|
|
13
|
+
export declare class Github extends Service {
|
|
14
14
|
readonly name = "github";
|
|
15
|
+
readonly displayName = "GitHub";
|
|
15
16
|
readonly baseApiUrls: readonly ["https://api.github.com/"];
|
|
16
17
|
readonly loginUrl = "https://github.com/settings/tokens/new";
|
|
18
|
+
readonly info: string;
|
|
17
19
|
readonly credentialCheckCurlArguments: readonly ["https://api.github.com/user"];
|
|
18
20
|
getSession(): GithubServiceSession;
|
|
19
|
-
checkApiCredentials(apiCredentials: ApiCredentials): ApiCredentialStatus;
|
|
20
21
|
}
|
|
21
22
|
export declare const GITHUB: Github;
|
|
22
23
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../../src/services/github.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../../src/services/github.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAuB,MAAM,sBAAsB,CAAC;AAE3E,OAAO,EAAE,OAAO,EAAE,6BAA6B,EAAoB,MAAM,WAAW,CAAC;AA6BrF,cAAM,oBAAqB,SAAQ,6BAA6B;IAC9D,OAAO,CAAC,UAAU,CAAS;IAE3B,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAqBpC,SAAS,CAAC,eAAe,IAAI,OAAO;cAIpB,sBAAsB,CACpC,OAAO,EAAE,cAAc,EACvB,eAAe,CAAC,EAAE,cAAc,GAC/B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CAwClC;AAED,qBAAa,MAAO,SAAQ,OAAO;IACjC,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,WAAW,YAAY;IAChC,QAAQ,CAAC,WAAW,uCAAwC;IAC5D,QAAQ,CAAC,QAAQ,4CAAwB;IACzC,QAAQ,CAAC,IAAI,SAE+D;IAE5E,QAAQ,CAAC,4BAA4B,2CAA4C;IAExE,UAAU,IAAI,oBAAoB;CAG5C;AAED,eAAO,MAAM,MAAM,QAAe,CAAC"}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* GitHub service implementation.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { typeLikeHuman } from '../playwrightUtils.js';
|
|
8
|
-
import { BrowserFollowupServiceSession, LoginFailedError } from './base.js';
|
|
4
|
+
import { AuthorizationBearer } from '../apiCredentials.js';
|
|
5
|
+
import { generateLatchkeyAppName, typeLikeHuman } from '../playwrightUtils.js';
|
|
6
|
+
import { Service, BrowserFollowupServiceSession, LoginFailedError } from './base.js';
|
|
9
7
|
const DEFAULT_TIMEOUT_MS = 8000;
|
|
10
8
|
// URL for creating a new personal access token (also used as login URL to trigger sudo)
|
|
11
9
|
const GITHUB_NEW_TOKEN_URL = 'https://github.com/settings/tokens/new';
|
|
@@ -38,16 +36,23 @@ class GithubServiceSession extends BrowserFollowupServiceSession {
|
|
|
38
36
|
}
|
|
39
37
|
const request = response.request();
|
|
40
38
|
// Detect login (and github's sudo) by seeing if github allows us to access the new token page.
|
|
41
|
-
if (request.url()
|
|
42
|
-
|
|
39
|
+
if (request.url() != GITHUB_NEW_TOKEN_URL) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (response.status() != 200) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Make sure the content returned is actually the correct page, not just the sudo page.
|
|
46
|
+
void response.text().then((text) => {
|
|
47
|
+
if (text.includes('<p id="settings_user_tokens_note">')) {
|
|
43
48
|
this.isLoggedIn = true;
|
|
44
49
|
}
|
|
45
|
-
}
|
|
50
|
+
});
|
|
46
51
|
}
|
|
47
52
|
isLoginComplete() {
|
|
48
53
|
return this.isLoggedIn;
|
|
49
54
|
}
|
|
50
|
-
async performBrowserFollowup(context) {
|
|
55
|
+
async performBrowserFollowup(context, _oldCredentials) {
|
|
51
56
|
const page = context.pages()[0];
|
|
52
57
|
if (!page) {
|
|
53
58
|
throw new LoginFailedError('No page available in browser context.');
|
|
@@ -56,7 +61,7 @@ class GithubServiceSession extends BrowserFollowupServiceSession {
|
|
|
56
61
|
// Add a note for the token
|
|
57
62
|
const noteInput = page.locator('//*[@id="oauth_access_description"]');
|
|
58
63
|
await noteInput.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
59
|
-
await typeLikeHuman(page, noteInput,
|
|
64
|
+
await typeLikeHuman(page, noteInput, generateLatchkeyAppName());
|
|
60
65
|
// Enable all necessary scopes
|
|
61
66
|
for (const scope of GITHUB_TOKEN_SCOPES) {
|
|
62
67
|
const checkbox = page.locator(`input[name="oauth_access[scopes][]"][value="${scope}"]`);
|
|
@@ -65,7 +70,8 @@ class GithubServiceSession extends BrowserFollowupServiceSession {
|
|
|
65
70
|
}
|
|
66
71
|
}
|
|
67
72
|
// Click the Generate Token button
|
|
68
|
-
|
|
73
|
+
// Get me button with type="submit" that's somewhere under a form with id="new_oauth_access".
|
|
74
|
+
const generateButton = page.locator('form#new_oauth_access button[type="submit"]');
|
|
69
75
|
await generateButton.waitFor({ timeout: DEFAULT_TIMEOUT_MS });
|
|
70
76
|
await generateButton.click();
|
|
71
77
|
// Wait for the page to load and retrieve the generated token
|
|
@@ -79,32 +85,17 @@ class GithubServiceSession extends BrowserFollowupServiceSession {
|
|
|
79
85
|
return new AuthorizationBearer(token);
|
|
80
86
|
}
|
|
81
87
|
}
|
|
82
|
-
export class Github {
|
|
88
|
+
export class Github extends Service {
|
|
83
89
|
name = 'github';
|
|
90
|
+
displayName = 'GitHub';
|
|
84
91
|
baseApiUrls = ['https://api.github.com/'];
|
|
85
92
|
loginUrl = GITHUB_NEW_TOKEN_URL;
|
|
93
|
+
info = 'https://docs.github.com/en/rest. ' +
|
|
94
|
+
'A personal access token with broad permissions is created during login.';
|
|
86
95
|
credentialCheckCurlArguments = ['https://api.github.com/user'];
|
|
87
96
|
getSession() {
|
|
88
97
|
return new GithubServiceSession(this);
|
|
89
98
|
}
|
|
90
|
-
checkApiCredentials(apiCredentials) {
|
|
91
|
-
if (!(apiCredentials instanceof AuthorizationBearer)) {
|
|
92
|
-
return ApiCredentialStatus.Invalid;
|
|
93
|
-
}
|
|
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
99
|
}
|
|
109
100
|
export const GITHUB = new Github();
|
|
110
101
|
//# sourceMappingURL=github.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../../src/services/github.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../../src/services/github.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google service implementation with OAuth flow.
|
|
3
|
+
*/
|
|
4
|
+
import type { Browser, BrowserContext, Response } from 'playwright';
|
|
5
|
+
import { ApiCredentials } from '../apiCredentials.js';
|
|
6
|
+
import { type BrowserLaunchOptions } from '../playwrightUtils.js';
|
|
7
|
+
import { Service, BrowserFollowupServiceSession } from './base.js';
|
|
8
|
+
import type { EncryptedStorage } from '../encryptedStorage.js';
|
|
9
|
+
declare class GoogleServiceSession extends BrowserFollowupServiceSession {
|
|
10
|
+
private readonly loginDetector;
|
|
11
|
+
onResponse(response: Response): void;
|
|
12
|
+
protected isLoginComplete(): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Override to skip the spinner page since the OAuth flow requires user interaction
|
|
15
|
+
* (granting consent on Google's authorization page).
|
|
16
|
+
*/
|
|
17
|
+
protected finalizeCredentials(_browser: Browser, context: BrowserContext, oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
18
|
+
protected performBrowserFollowup(context: BrowserContext, oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
19
|
+
prepare(encryptedStorage: EncryptedStorage, launchOptions?: BrowserLaunchOptions): Promise<ApiCredentials>;
|
|
20
|
+
private performOAuthFlow;
|
|
21
|
+
}
|
|
22
|
+
export declare class Google extends Service {
|
|
23
|
+
readonly name = "google";
|
|
24
|
+
readonly displayName = "Google Workspace";
|
|
25
|
+
readonly baseApiUrls: readonly ["https://www.googleapis.com/"];
|
|
26
|
+
readonly loginUrl = "https://console.cloud.google.com/";
|
|
27
|
+
readonly info: string;
|
|
28
|
+
readonly credentialCheckCurlArguments: readonly ["https://www.googleapis.com/oauth2/v1/userinfo"];
|
|
29
|
+
getSession(): GoogleServiceSession;
|
|
30
|
+
refreshCredentials(apiCredentials: ApiCredentials): Promise<ApiCredentials | null>;
|
|
31
|
+
}
|
|
32
|
+
export declare const GOOGLE: Google;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=google.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../../src/services/google.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAQ,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAoB,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAIL,KAAK,oBAAoB,EAC1B,MAAM,uBAAuB,CAAC;AAM/B,OAAO,EACL,OAAO,EACP,6BAA6B,EAI9B,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAqQ/D,cAAM,oBAAqB,SAAQ,6BAA6B;IAC9D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAyB;IAEvD,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAIpC,SAAS,CAAC,eAAe,IAAI,OAAO;IAIpC;;;OAGG;cACgB,mBAAmB,CACpC,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,cAAc,EACvB,cAAc,CAAC,EAAE,cAAc,GAC9B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;cAIjB,sBAAsB,CACpC,OAAO,EAAE,cAAc,EACvB,cAAc,CAAC,EAAE,cAAc,GAC9B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAgClB,OAAO,CACpB,gBAAgB,EAAE,gBAAgB,EAClC,aAAa,CAAC,EAAE,oBAAoB,GACnC,OAAO,CAAC,cAAc,CAAC;YAmBZ,gBAAgB;CAqE/B;AAED,qBAAa,MAAO,SAAQ,OAAO;IACjC,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,WAAW,sBAAsB;IAC1C,QAAQ,CAAC,WAAW,2CAA4C;IAChE,QAAQ,CAAC,QAAQ,uCAAuC;IACxD,QAAQ,CAAC,IAAI,SAG0D;IAEvE,QAAQ,CAAC,4BAA4B,6DAE1B;IAEF,UAAU,IAAI,oBAAoB;IAIlC,kBAAkB,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CAoC5F;AAED,eAAO,MAAM,MAAM,QAAe,CAAC"}
|