latchkey 3.6.0 → 3.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/dist/src/oauthUtils.d.ts +2 -2
- package/dist/src/oauthUtils.d.ts.map +1 -1
- package/dist/src/oauthUtils.js +36 -15
- package/dist/src/oauthUtils.js.map +1 -1
- package/dist/src/playwrightUtils.d.ts +57 -0
- package/dist/src/playwrightUtils.d.ts.map +1 -1
- package/dist/src/playwrightUtils.js +247 -8
- package/dist/src/playwrightUtils.js.map +1 -1
- package/dist/src/serviceRegistry.d.ts.map +1 -1
- package/dist/src/serviceRegistry.js +3 -1
- package/dist/src/serviceRegistry.js.map +1 -1
- package/dist/src/services/core/base.d.ts +55 -16
- package/dist/src/services/core/base.d.ts.map +1 -1
- package/dist/src/services/core/base.js +119 -31
- package/dist/src/services/core/base.js.map +1 -1
- package/dist/src/services/fastmail-dav.d.ts +55 -0
- package/dist/src/services/fastmail-dav.d.ts.map +1 -0
- package/dist/src/services/fastmail-dav.js +98 -0
- package/dist/src/services/fastmail-dav.js.map +1 -0
- package/dist/src/services/fastmail.d.ts +79 -0
- package/dist/src/services/fastmail.d.ts.map +1 -0
- package/dist/src/services/fastmail.js +298 -0
- package/dist/src/services/fastmail.js.map +1 -0
- package/dist/src/services/github.d.ts +2 -1
- package/dist/src/services/github.d.ts.map +1 -1
- package/dist/src/services/github.js +13 -0
- package/dist/src/services/github.js.map +1 -1
- package/dist/src/services/huggingface.d.ts +2 -1
- package/dist/src/services/huggingface.d.ts.map +1 -1
- package/dist/src/services/huggingface.js +13 -0
- package/dist/src/services/huggingface.js.map +1 -1
- package/dist/src/services/index.d.ts +2 -0
- package/dist/src/services/index.d.ts.map +1 -1
- package/dist/src/services/index.js +2 -0
- package/dist/src/services/index.js.map +1 -1
- package/dist/src/services/linear.d.ts +2 -1
- package/dist/src/services/linear.d.ts.map +1 -1
- package/dist/src/services/linear.js +14 -0
- package/dist/src/services/linear.js.map +1 -1
- package/dist/src/services/ngrok.d.ts +2 -1
- package/dist/src/services/ngrok.d.ts.map +1 -1
- package/dist/src/services/ngrok.js +12 -0
- package/dist/src/services/ngrok.js.map +1 -1
- package/dist/src/services/openrouter.d.ts +2 -1
- package/dist/src/services/openrouter.d.ts.map +1 -1
- package/dist/src/services/openrouter.js +12 -0
- package/dist/src/services/openrouter.js.map +1 -1
- package/dist/src/services/tailscale.d.ts +2 -1
- package/dist/src/services/tailscale.d.ts.map +1 -1
- package/dist/src/services/tailscale.js +18 -0
- package/dist/src/services/tailscale.js.map +1 -1
- package/dist/src/services/todoist.d.ts +2 -1
- package/dist/src/services/todoist.d.ts.map +1 -1
- package/dist/src/services/todoist.js +6 -0
- package/dist/src/services/todoist.js.map +1 -1
- package/dist/src/services/zoom.d.ts +2 -1
- package/dist/src/services/zoom.d.ts.map +1 -1
- package/dist/src/services/zoom.js +55 -55
- package/dist/src/services/zoom.js.map +1 -1
- package/dist/src/sharedOperations.d.ts +1 -1
- package/dist/src/sharedOperations.d.ts.map +1 -1
- package/dist/src/sharedOperations.js +12 -1
- package/dist/src/sharedOperations.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/tests/lint.test.js +1 -1
- package/dist/tests/manualCompletion.test.d.ts +10 -0
- package/dist/tests/manualCompletion.test.d.ts.map +1 -0
- package/dist/tests/manualCompletion.test.js +221 -0
- package/dist/tests/manualCompletion.test.js.map +1 -0
- package/dist/tests/manualCredentialForms.test.d.ts +8 -0
- package/dist/tests/manualCredentialForms.test.d.ts.map +1 -0
- package/dist/tests/manualCredentialForms.test.js +64 -0
- package/dist/tests/manualCredentialForms.test.js.map +1 -0
- package/dist/tests/serviceRegistry.test.js +32 -1
- package/dist/tests/serviceRegistry.test.js.map +1 -1
- package/package.json +2 -2
|
@@ -5,7 +5,25 @@ import type { Browser, BrowserContext, Page, Response } from 'playwright';
|
|
|
5
5
|
import type { z, ZodError, ZodTypeAny } from 'zod';
|
|
6
6
|
import { ApiCredentialStatus, ApiCredentials } from '../../apiCredentials/base.js';
|
|
7
7
|
import { EncryptedStorage } from '../../encryptedStorage.js';
|
|
8
|
-
import { type BrowserLaunchOptions } from '../../playwrightUtils.js';
|
|
8
|
+
import { type BrowserLaunchOptions, type CredentialFormField, type CredentialFormValues } from '../../playwrightUtils.js';
|
|
9
|
+
/**
|
|
10
|
+
* Way out of a failed automation: the values the user can produce by hand and
|
|
11
|
+
* paste back, and how to turn them into credentials.
|
|
12
|
+
*
|
|
13
|
+
* The build step only shapes the values; whether they actually work is decided
|
|
14
|
+
* by the service's credential check, which runs before they are accepted.
|
|
15
|
+
*/
|
|
16
|
+
export interface ManualCredentialForm {
|
|
17
|
+
/**
|
|
18
|
+
* What the user can do by hand, e.g. "create a token in Settings →
|
|
19
|
+
* Developer". Shown above the fields, so it should read as instructions
|
|
20
|
+
* rather than as a description. Don't forget that the breakage might have
|
|
21
|
+
* occurred in the middle of the process (not necessarily at the start).
|
|
22
|
+
*/
|
|
23
|
+
readonly instructions: string;
|
|
24
|
+
readonly fields: readonly CredentialFormField[];
|
|
25
|
+
buildCredentials(values: CredentialFormValues): ApiCredentials;
|
|
26
|
+
}
|
|
9
27
|
export declare class NoCurlCredentialsNotSupportedError extends Error {
|
|
10
28
|
constructor(serviceName: string);
|
|
11
29
|
}
|
|
@@ -193,15 +211,6 @@ export declare abstract class ServiceSession {
|
|
|
193
211
|
* Wait until the browser login phase is complete.
|
|
194
212
|
*/
|
|
195
213
|
private waitForLoginComplete;
|
|
196
|
-
/**
|
|
197
|
-
* Optionally diagnose a timeout error that occurred during credential finalization.
|
|
198
|
-
*
|
|
199
|
-
* Services can override this to inspect the page state and return a more
|
|
200
|
-
* specific error (e.g., checking for permission denied messages).
|
|
201
|
-
* If this returns an error, it will be thrown instead of the generic
|
|
202
|
-
* LoginFailedError. If it returns null, the original timeout error message is used.
|
|
203
|
-
*/
|
|
204
|
-
protected diagnoseTimeoutError(_context: BrowserContext, _originalError: Error): Promise<Error | null>;
|
|
205
214
|
/**
|
|
206
215
|
* Optional preparation step before login.
|
|
207
216
|
* Services can override this to perform setup (e.g., creating OAuth clients).
|
|
@@ -270,16 +279,26 @@ export declare function buildFollowupSpinnerDetails(displayName: string, followu
|
|
|
270
279
|
* (e.g., navigating to settings and creating an API key).
|
|
271
280
|
*/
|
|
272
281
|
export declare abstract class BrowserFollowupServiceSession extends ServiceSession {
|
|
273
|
-
private followupSpinnerPage;
|
|
274
282
|
/** What the followup does in the user's account, shown on the spinner page. */
|
|
275
283
|
protected abstract readonly followupWork: FollowupWork;
|
|
276
284
|
/**
|
|
277
|
-
*
|
|
278
|
-
* or
|
|
279
|
-
* a
|
|
280
|
-
*
|
|
285
|
+
* Page hiding the automation from the user, for sessions that show one, or
|
|
286
|
+
* null while none is up (or when the spinner is disabled). It doubles as the
|
|
287
|
+
* place where a failure is explained to the user.
|
|
288
|
+
*
|
|
289
|
+
* Subclasses that temporarily surface a real page to the user (e.g. to have
|
|
290
|
+
* terms accepted) bring this page back to the front afterwards.
|
|
281
291
|
*/
|
|
282
|
-
protected
|
|
292
|
+
protected spinnerPage: Page | null;
|
|
293
|
+
/**
|
|
294
|
+
* Form shown on the failure notice for the user to paste the credentials they
|
|
295
|
+
* created by hand into.
|
|
296
|
+
*
|
|
297
|
+
* Public so the fields and instructions can be inspected without running a
|
|
298
|
+
* browser — which is how the tests check that every session that should offer
|
|
299
|
+
* one does, and that its builder agrees with its field names.
|
|
300
|
+
*/
|
|
301
|
+
readonly manualCredentialForm?: ManualCredentialForm;
|
|
283
302
|
/**
|
|
284
303
|
* Perform actions in the browser to finalize and extract API credentials.
|
|
285
304
|
* This runs in the same browser session used for login.
|
|
@@ -288,5 +307,25 @@ export declare abstract class BrowserFollowupServiceSession extends ServiceSessi
|
|
|
288
307
|
*/
|
|
289
308
|
protected abstract performBrowserFollowup(context: BrowserContext, oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
290
309
|
protected finalizeCredentials(_browser: Browser, context: BrowserContext, oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
310
|
+
/**
|
|
311
|
+
* Turn a failed followup into an error the user can act on, without taking
|
|
312
|
+
* the browser away from them.
|
|
313
|
+
*
|
|
314
|
+
* A broken automation usually means the service changed, which is precisely
|
|
315
|
+
* the situation where the flow is still perfectly doable by hand: the browser
|
|
316
|
+
* is signed in and sitting on the right page. So the spinner is replaced by
|
|
317
|
+
* an explanation of what failed and what to do about it, and the window stays
|
|
318
|
+
* open for a while, waiting for the user to paste the credentials in.
|
|
319
|
+
*
|
|
320
|
+
* This needs somewhere to put them, so sessions without a
|
|
321
|
+
* {@link manualCredentialForm} report the failure straight away rather than
|
|
322
|
+
* asking for work latchkey could not accept.
|
|
323
|
+
*/
|
|
324
|
+
private recoverFromFailedFollowup;
|
|
325
|
+
/**
|
|
326
|
+
* Turn submitted values into credentials, refusing them with a reason the form
|
|
327
|
+
* can show if the service does not accept them.
|
|
328
|
+
*/
|
|
329
|
+
private decideOnSubmittedCredentials;
|
|
291
330
|
}
|
|
292
331
|
//# sourceMappingURL=base.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/services/core/base.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AACnD,OAAO,EACL,mBAAmB,EACnB,cAAc,EAEf,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/services/core/base.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { ApiCredentialStatus, ApiCredentialsUsageError, } from '../../apiCredentials/base.js';
|
|
5
5
|
import { DEFAULT_ACCOUNT } from '../../apiCredentials/account.js';
|
|
6
6
|
import { runCapturedAsync } from '../../curl.js';
|
|
7
|
-
import { generateLatchkeyAppName, showSpinnerPage, withTempBrowserContext, } from '../../playwrightUtils.js';
|
|
7
|
+
import { generateLatchkeyAppName, requestCredentialsFromUser, showSpinnerPage, withTempBrowserContext, } from '../../playwrightUtils.js';
|
|
8
8
|
export class NoCurlCredentialsNotSupportedError extends Error {
|
|
9
9
|
constructor(serviceName) {
|
|
10
10
|
super(`Service '${serviceName}' does not support set-nocurl credentials.`);
|
|
@@ -176,17 +176,6 @@ export class ServiceSession {
|
|
|
176
176
|
await page.waitForTimeout(100);
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
|
-
/**
|
|
180
|
-
* Optionally diagnose a timeout error that occurred during credential finalization.
|
|
181
|
-
*
|
|
182
|
-
* Services can override this to inspect the page state and return a more
|
|
183
|
-
* specific error (e.g., checking for permission denied messages).
|
|
184
|
-
* If this returns an error, it will be thrown instead of the generic
|
|
185
|
-
* LoginFailedError. If it returns null, the original timeout error message is used.
|
|
186
|
-
*/
|
|
187
|
-
diagnoseTimeoutError(_context, _originalError) {
|
|
188
|
-
return Promise.resolve(null);
|
|
189
|
-
}
|
|
190
179
|
/**
|
|
191
180
|
* Perform the login flow and return the extracted credentials.
|
|
192
181
|
* @param encryptedStorage - Storage for managing credentials
|
|
@@ -217,13 +206,6 @@ export class ServiceSession {
|
|
|
217
206
|
if (error instanceof Error && isBrowserClosedError(error)) {
|
|
218
207
|
throw new LoginCancelledError();
|
|
219
208
|
}
|
|
220
|
-
if (error instanceof Error && isTimeoutError(error)) {
|
|
221
|
-
const diagnosedError = await this.diagnoseTimeoutError(context, error);
|
|
222
|
-
if (diagnosedError !== null) {
|
|
223
|
-
throw diagnosedError;
|
|
224
|
-
}
|
|
225
|
-
throw new LoginFailedError(`Login failed: ${error.message}`);
|
|
226
|
-
}
|
|
227
209
|
throw error;
|
|
228
210
|
}
|
|
229
211
|
if (apiCredentials === null) {
|
|
@@ -297,9 +279,22 @@ export var FollowupWork;
|
|
|
297
279
|
* is doing and how to recover when it fails.
|
|
298
280
|
*/
|
|
299
281
|
export function buildFollowupSpinnerDetails(displayName, followupWork, durationSentence = 'This can take a while.') {
|
|
300
|
-
return
|
|
301
|
-
'If the process fails, click the first browser tab in this window to manually complete it.');
|
|
282
|
+
return `${followupWork} your ${displayName} account. ${durationSentence} `;
|
|
302
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* The notice explains what to do, not what went wrong: the automation's error
|
|
286
|
+
* message means nothing to the user, and it is reported on the command line
|
|
287
|
+
* anyway.
|
|
288
|
+
*/
|
|
289
|
+
function buildFailureNoticeDetails(form) {
|
|
290
|
+
return [
|
|
291
|
+
form.instructions,
|
|
292
|
+
'Then paste the credentials into the form below.',
|
|
293
|
+
'Closing this browser window gives up on the login.',
|
|
294
|
+
].join('\n\n');
|
|
295
|
+
}
|
|
296
|
+
/** How long the browser is left open for the user to finish a failed flow. */
|
|
297
|
+
const MANUAL_COMPLETION_LIMIT_MS = 30 * 60_000;
|
|
303
298
|
/**
|
|
304
299
|
* Service session that requires a browser followup to finalize credentials.
|
|
305
300
|
*
|
|
@@ -308,19 +303,112 @@ export function buildFollowupSpinnerDetails(displayName, followupWork, durationS
|
|
|
308
303
|
* (e.g., navigating to settings and creating an API key).
|
|
309
304
|
*/
|
|
310
305
|
export class BrowserFollowupServiceSession extends ServiceSession {
|
|
311
|
-
followupSpinnerPage = null;
|
|
312
306
|
/**
|
|
313
|
-
*
|
|
314
|
-
* or
|
|
315
|
-
* a
|
|
316
|
-
*
|
|
307
|
+
* Page hiding the automation from the user, for sessions that show one, or
|
|
308
|
+
* null while none is up (or when the spinner is disabled). It doubles as the
|
|
309
|
+
* place where a failure is explained to the user.
|
|
310
|
+
*
|
|
311
|
+
* Subclasses that temporarily surface a real page to the user (e.g. to have
|
|
312
|
+
* terms accepted) bring this page back to the front afterwards.
|
|
317
313
|
*/
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
314
|
+
spinnerPage = null;
|
|
315
|
+
/**
|
|
316
|
+
* Form shown on the failure notice for the user to paste the credentials they
|
|
317
|
+
* created by hand into.
|
|
318
|
+
*
|
|
319
|
+
* Public so the fields and instructions can be inspected without running a
|
|
320
|
+
* browser — which is how the tests check that every session that should offer
|
|
321
|
+
* one does, and that its builder agrees with its field names.
|
|
322
|
+
*/
|
|
323
|
+
manualCredentialForm;
|
|
321
324
|
async finalizeCredentials(_browser, context, oldCredentials) {
|
|
322
|
-
this.
|
|
323
|
-
|
|
325
|
+
this.spinnerPage = await showSpinnerPage(context, `Finalizing ${this.service.displayName} login...`, buildFollowupSpinnerDetails(this.service.displayName, this.followupWork));
|
|
326
|
+
try {
|
|
327
|
+
return await this.performBrowserFollowup(context, oldCredentials);
|
|
328
|
+
}
|
|
329
|
+
catch (error) {
|
|
330
|
+
// A browser the user closed is a cancellation, which login() reports;
|
|
331
|
+
// everything else is the automation breaking, which the user may still be
|
|
332
|
+
// able to work around.
|
|
333
|
+
if (!(error instanceof Error) || isBrowserClosedError(error)) {
|
|
334
|
+
throw error;
|
|
335
|
+
}
|
|
336
|
+
return await this.recoverFromFailedFollowup(context, error);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Turn a failed followup into an error the user can act on, without taking
|
|
341
|
+
* the browser away from them.
|
|
342
|
+
*
|
|
343
|
+
* A broken automation usually means the service changed, which is precisely
|
|
344
|
+
* the situation where the flow is still perfectly doable by hand: the browser
|
|
345
|
+
* is signed in and sitting on the right page. So the spinner is replaced by
|
|
346
|
+
* an explanation of what failed and what to do about it, and the window stays
|
|
347
|
+
* open for a while, waiting for the user to paste the credentials in.
|
|
348
|
+
*
|
|
349
|
+
* This needs somewhere to put them, so sessions without a
|
|
350
|
+
* {@link manualCredentialForm} report the failure straight away rather than
|
|
351
|
+
* asking for work latchkey could not accept.
|
|
352
|
+
*/
|
|
353
|
+
async recoverFromFailedFollowup(context, error) {
|
|
354
|
+
// A timeout says nothing beyond "the page did not do what we expected", so
|
|
355
|
+
// it is reported as the login failure it is.
|
|
356
|
+
const failure = isTimeoutError(error)
|
|
357
|
+
? new LoginFailedError(`Login failed: ${error.message}`)
|
|
358
|
+
: error;
|
|
359
|
+
const form = this.manualCredentialForm;
|
|
360
|
+
if (form === undefined) {
|
|
361
|
+
throw failure;
|
|
362
|
+
}
|
|
363
|
+
console.error(`[latchkey] The ${this.service.displayName} login automation failed. The browser ` +
|
|
364
|
+
'window is left open so the credentials can be provided by hand; close it to give up.');
|
|
365
|
+
let credentials;
|
|
366
|
+
try {
|
|
367
|
+
credentials = await requestCredentialsFromUser({
|
|
368
|
+
context,
|
|
369
|
+
spinnerPage: this.spinnerPage,
|
|
370
|
+
message: `${this.service.displayName} credentials could not be retrieved automatically.`,
|
|
371
|
+
details: buildFailureNoticeDetails(form),
|
|
372
|
+
fields: form.fields,
|
|
373
|
+
decide: (values) => this.decideOnSubmittedCredentials(form, values),
|
|
374
|
+
timeoutMs: MANUAL_COMPLETION_LIMIT_MS,
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
catch {
|
|
378
|
+
// The browser is gone; there is nobody left to ask.
|
|
379
|
+
throw failure;
|
|
380
|
+
}
|
|
381
|
+
if (credentials !== null) {
|
|
382
|
+
return credentials;
|
|
383
|
+
}
|
|
384
|
+
// Nothing came of the request, so the automation failure is what gets reported.
|
|
385
|
+
throw failure;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Turn submitted values into credentials, refusing them with a reason the form
|
|
389
|
+
* can show if the service does not accept them.
|
|
390
|
+
*/
|
|
391
|
+
async decideOnSubmittedCredentials(form, values) {
|
|
392
|
+
// A build error is reported to the user as a problem with what they typed:
|
|
393
|
+
// requestCredentialsFromUser turns it into one.
|
|
394
|
+
const built = form.buildCredentials(values);
|
|
395
|
+
// Some pasted values are not usable as they stand — Zoom's server-to-server
|
|
396
|
+
// app credentials have to mint an access token first — so they get the same
|
|
397
|
+
// refresh the stored ones would, or the check below would call a perfectly
|
|
398
|
+
// good app "missing".
|
|
399
|
+
const credentials = built.isExpired() === true && this.service.refreshCredentials
|
|
400
|
+
? ((await this.service.refreshCredentials(built)) ?? built)
|
|
401
|
+
: built;
|
|
402
|
+
// These were pasted by hand, so they are checked before being taken:
|
|
403
|
+
// finding out now beats storing a typo and failing on the next request.
|
|
404
|
+
const status = await this.service.checkApiCredentials(credentials);
|
|
405
|
+
if (status !== ApiCredentialStatus.Valid) {
|
|
406
|
+
return {
|
|
407
|
+
problem: `${this.service.displayName} did not accept these credentials (${status}). ` +
|
|
408
|
+
'Please check them and try again.',
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
return { accepted: credentials };
|
|
324
412
|
}
|
|
325
413
|
}
|
|
326
414
|
//# sourceMappingURL=base.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../../../src/services/core/base.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EACL,mBAAmB,EAEnB,wBAAwB,GACzB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,sBAAsB,
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../../../src/services/core/base.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fastmail CardDAV / CalDAV service implementation.
|
|
3
|
+
*
|
|
4
|
+
* Separate from the `fastmail` service, which speaks JMAP, because the two take
|
|
5
|
+
* different credentials against different hosts. Fastmail's OAuth access tokens
|
|
6
|
+
* are accepted only by the JMAP API; the DAV endpoints refuse them (401 on every
|
|
7
|
+
* collection, including the principal URL) and want an **app password** over
|
|
8
|
+
* HTTP Basic auth instead. Fastmail's own documentation draws the same line: an
|
|
9
|
+
* API token is "for JMAP access", an app password is "for everything else".
|
|
10
|
+
*
|
|
11
|
+
* Splitting by host also keeps URL matching unambiguous. `latchkey curl` picks
|
|
12
|
+
* among services that match a URL by registration order, with no way for a
|
|
13
|
+
* caller to name the one it wants, so two services claiming the same host would
|
|
14
|
+
* be a coin flip. These hosts are disjoint from the JMAP ones.
|
|
15
|
+
*
|
|
16
|
+
* The credential is an app password from Settings → Privacy & Security →
|
|
17
|
+
* "Connected apps & API tokens" → "Manage app passwords and access", used with
|
|
18
|
+
* the account's own e-mail address as the username. Its "DAV" access level is
|
|
19
|
+
* enough.
|
|
20
|
+
*
|
|
21
|
+
* One failure worth recognizing: on an account with no active subscription
|
|
22
|
+
* (observed on a lapsed trial) app passwords appear to be refused for every
|
|
23
|
+
* legacy protocol, and the refusal is a 401 reading "Incorrect username,
|
|
24
|
+
* password or access token" — indistinguishable from a typo — while JMAP over
|
|
25
|
+
* an API token or OAuth keeps working. Subscribing restored DAV with no change
|
|
26
|
+
* to any request. An IMAP login against imap.fastmail.com with the same
|
|
27
|
+
* credential tells the two apart: refused there too points at the account
|
|
28
|
+
* rather than the credential.
|
|
29
|
+
*/
|
|
30
|
+
import type { ApiCredentials } from '../apiCredentials/base.js';
|
|
31
|
+
import { Service } from './core/base.js';
|
|
32
|
+
export declare class FastmailDav extends Service {
|
|
33
|
+
readonly name = "fastmail-dav";
|
|
34
|
+
readonly displayName = "Fastmail (CardDAV/CalDAV)";
|
|
35
|
+
/**
|
|
36
|
+
* Contacts and calendars live on their own hosts, and — unlike the JMAP API —
|
|
37
|
+
* these are not region-sharded: `/.well-known/carddav` redirects within
|
|
38
|
+
* `carddav.fastmail.com` rather than off to a shard. The optional prefix is
|
|
39
|
+
* defensive, so a future shard would not need a new registration.
|
|
40
|
+
*/
|
|
41
|
+
readonly baseApiUrls: readonly [RegExp, RegExp];
|
|
42
|
+
readonly loginUrl = "https://app.fastmail.com/settings/security";
|
|
43
|
+
readonly info: string;
|
|
44
|
+
readonly credentialCheckCurlArguments: readonly ["-X", "PROPFIND", "-H", "Depth: 0", "-H", "Content-Type: application/xml; charset=utf-8", "--data-binary", string, "https://carddav.fastmail.com/dav/principals/"];
|
|
45
|
+
setCredentialsExample(serviceName: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* WebDAV answers a successful PROPFIND with 207 Multi-Status (RFC 4918 §13),
|
|
48
|
+
* so the inherited 200-only check would report every working app password as
|
|
49
|
+
* invalid.
|
|
50
|
+
*/
|
|
51
|
+
protected isCredentialCheckResponseValid(httpStatusCode: string): boolean;
|
|
52
|
+
getAccount(apiCredentials: ApiCredentials): Promise<string | null>;
|
|
53
|
+
}
|
|
54
|
+
export declare const FASTMAIL_DAV: FastmailDav;
|
|
55
|
+
//# sourceMappingURL=fastmail-dav.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastmail-dav.d.ts","sourceRoot":"","sources":["../../../src/services/fastmail-dav.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAoCzC,qBAAa,WAAY,SAAQ,OAAO;IACtC,QAAQ,CAAC,IAAI,kBAAkB;IAC/B,QAAQ,CAAC,WAAW,+BAA+B;IAEnD;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,4BAGT;IAEX,QAAQ,CAAC,QAAQ,gDAAgD;IAEjE,QAAQ,CAAC,IAAI,SAKsB;IAEnC,QAAQ,CAAC,4BAA4B,+KAAkC;IAEvE,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAIlD;;;;OAIG;cACgB,8BAA8B,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO;IAIzE,UAAU,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAO5E;AAED,eAAO,MAAM,YAAY,aAAoB,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fastmail CardDAV / CalDAV service implementation.
|
|
3
|
+
*
|
|
4
|
+
* Separate from the `fastmail` service, which speaks JMAP, because the two take
|
|
5
|
+
* different credentials against different hosts. Fastmail's OAuth access tokens
|
|
6
|
+
* are accepted only by the JMAP API; the DAV endpoints refuse them (401 on every
|
|
7
|
+
* collection, including the principal URL) and want an **app password** over
|
|
8
|
+
* HTTP Basic auth instead. Fastmail's own documentation draws the same line: an
|
|
9
|
+
* API token is "for JMAP access", an app password is "for everything else".
|
|
10
|
+
*
|
|
11
|
+
* Splitting by host also keeps URL matching unambiguous. `latchkey curl` picks
|
|
12
|
+
* among services that match a URL by registration order, with no way for a
|
|
13
|
+
* caller to name the one it wants, so two services claiming the same host would
|
|
14
|
+
* be a coin flip. These hosts are disjoint from the JMAP ones.
|
|
15
|
+
*
|
|
16
|
+
* The credential is an app password from Settings → Privacy & Security →
|
|
17
|
+
* "Connected apps & API tokens" → "Manage app passwords and access", used with
|
|
18
|
+
* the account's own e-mail address as the username. Its "DAV" access level is
|
|
19
|
+
* enough.
|
|
20
|
+
*
|
|
21
|
+
* One failure worth recognizing: on an account with no active subscription
|
|
22
|
+
* (observed on a lapsed trial) app passwords appear to be refused for every
|
|
23
|
+
* legacy protocol, and the refusal is a 401 reading "Incorrect username,
|
|
24
|
+
* password or access token" — indistinguishable from a typo — while JMAP over
|
|
25
|
+
* an API token or OAuth keeps working. Subscribing restored DAV with no change
|
|
26
|
+
* to any request. An IMAP login against imap.fastmail.com with the same
|
|
27
|
+
* credential tells the two apart: refused there too points at the account
|
|
28
|
+
* rather than the credential.
|
|
29
|
+
*/
|
|
30
|
+
import { fetchAccountFromEndpoint } from '../apiCredentials/account.js';
|
|
31
|
+
import { Service } from './core/base.js';
|
|
32
|
+
/**
|
|
33
|
+
* A `current-user-principal` PROPFIND (RFC 5397). Depth 0 keeps it to the
|
|
34
|
+
* collection itself, and the response names the principal of whoever
|
|
35
|
+
* authenticated — which is how this doubles as the account lookup.
|
|
36
|
+
*/
|
|
37
|
+
const PRINCIPAL_PROPFIND_BODY = '<?xml version="1.0" encoding="utf-8"?>' +
|
|
38
|
+
'<D:propfind xmlns:D="DAV:"><D:prop><D:current-user-principal/></D:prop></D:propfind>';
|
|
39
|
+
const PRINCIPAL_CHECK_CURL_ARGUMENTS = [
|
|
40
|
+
'-X',
|
|
41
|
+
'PROPFIND',
|
|
42
|
+
'-H',
|
|
43
|
+
'Depth: 0',
|
|
44
|
+
'-H',
|
|
45
|
+
'Content-Type: application/xml; charset=utf-8',
|
|
46
|
+
'--data-binary',
|
|
47
|
+
PRINCIPAL_PROPFIND_BODY,
|
|
48
|
+
'https://carddav.fastmail.com/dav/principals/',
|
|
49
|
+
];
|
|
50
|
+
/**
|
|
51
|
+
* Pull the account out of a `current-user-principal` response. Fastmail's
|
|
52
|
+
* principal hrefs carry the account's e-mail, e.g.
|
|
53
|
+
* `/dav/principals/user/someone@fastmail.com/`.
|
|
54
|
+
*
|
|
55
|
+
* Matched with a regular expression rather than parsed as XML: latchkey has no
|
|
56
|
+
* XML parser, the shape is fixed by RFC 5397, and the alternative is taking on a
|
|
57
|
+
* dependency to read one href.
|
|
58
|
+
*/
|
|
59
|
+
function parseAccountFromPrincipalResponse(responseBody) {
|
|
60
|
+
return /\/dav\/principals\/user\/([^/<>"]+)/.exec(responseBody)?.[1] ?? null;
|
|
61
|
+
}
|
|
62
|
+
export class FastmailDav extends Service {
|
|
63
|
+
name = 'fastmail-dav';
|
|
64
|
+
displayName = 'Fastmail (CardDAV/CalDAV)';
|
|
65
|
+
/**
|
|
66
|
+
* Contacts and calendars live on their own hosts, and — unlike the JMAP API —
|
|
67
|
+
* these are not region-sharded: `/.well-known/carddav` redirects within
|
|
68
|
+
* `carddav.fastmail.com` rather than off to a shard. The optional prefix is
|
|
69
|
+
* defensive, so a future shard would not need a new registration.
|
|
70
|
+
*/
|
|
71
|
+
baseApiUrls = [
|
|
72
|
+
/^https:\/\/([a-z0-9-]+[.-])?carddav\.fastmail\.com\//,
|
|
73
|
+
/^https:\/\/([a-z0-9-]+[.-])?caldav\.fastmail\.com\//,
|
|
74
|
+
];
|
|
75
|
+
loginUrl = 'https://app.fastmail.com/settings/security';
|
|
76
|
+
info = 'https://www.fastmail.com/dev/ — contacts over CardDAV (RFC 6352) and calendars over ' +
|
|
77
|
+
'CalDAV (RFC 4791), rooted at /dav/addressbooks and /dav/calendars. ' +
|
|
78
|
+
'Credentials are an app password, rather than the OAuth token the `fastmail` service uses. ' +
|
|
79
|
+
'The `fastmail` service can also reach contacts over JMAP, which is the better route unless a ' +
|
|
80
|
+
'caller needs DAV specifically.';
|
|
81
|
+
credentialCheckCurlArguments = PRINCIPAL_CHECK_CURL_ARGUMENTS;
|
|
82
|
+
setCredentialsExample(serviceName) {
|
|
83
|
+
return `latchkey auth set ${serviceName} -u "you@fastmail.com:<app password>"`;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* WebDAV answers a successful PROPFIND with 207 Multi-Status (RFC 4918 §13),
|
|
87
|
+
* so the inherited 200-only check would report every working app password as
|
|
88
|
+
* invalid.
|
|
89
|
+
*/
|
|
90
|
+
isCredentialCheckResponseValid(httpStatusCode) {
|
|
91
|
+
return httpStatusCode === '207' || httpStatusCode === '200';
|
|
92
|
+
}
|
|
93
|
+
getAccount(apiCredentials) {
|
|
94
|
+
return fetchAccountFromEndpoint(apiCredentials, this.credentialCheckCurlArguments, parseAccountFromPrincipalResponse);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export const FASTMAIL_DAV = new FastmailDav();
|
|
98
|
+
//# sourceMappingURL=fastmail-dav.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastmail-dav.js","sourceRoot":"","sources":["../../../src/services/fastmail-dav.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEzC;;;;GAIG;AACH,MAAM,uBAAuB,GAC3B,wCAAwC;IACxC,sFAAsF,CAAC;AAEzF,MAAM,8BAA8B,GAAG;IACrC,IAAI;IACJ,UAAU;IACV,IAAI;IACJ,UAAU;IACV,IAAI;IACJ,8CAA8C;IAC9C,eAAe;IACf,uBAAuB;IACvB,8CAA8C;CACtC,CAAC;AAEX;;;;;;;;GAQG;AACH,SAAS,iCAAiC,CAAC,YAAoB;IAC7D,OAAO,qCAAqC,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC/E,CAAC;AAED,MAAM,OAAO,WAAY,SAAQ,OAAO;IAC7B,IAAI,GAAG,cAAc,CAAC;IACtB,WAAW,GAAG,2BAA2B,CAAC;IAEnD;;;;;OAKG;IACM,WAAW,GAAG;QACrB,sDAAsD;QACtD,qDAAqD;KAC7C,CAAC;IAEF,QAAQ,GAAG,4CAA4C,CAAC;IAExD,IAAI,GACX,sFAAsF;QACtF,qEAAqE;QACrE,4FAA4F;QAC5F,+FAA+F;QAC/F,gCAAgC,CAAC;IAE1B,4BAA4B,GAAG,8BAA8B,CAAC;IAEvE,qBAAqB,CAAC,WAAmB;QACvC,OAAO,qBAAqB,WAAW,uCAAuC,CAAC;IACjF,CAAC;IAED;;;;OAIG;IACgB,8BAA8B,CAAC,cAAsB;QACtE,OAAO,cAAc,KAAK,KAAK,IAAI,cAAc,KAAK,KAAK,CAAC;IAC9D,CAAC;IAEQ,UAAU,CAAC,cAA8B;QAChD,OAAO,wBAAwB,CAC7B,cAAc,EACd,IAAI,CAAC,4BAA4B,EACjC,iCAAiC,CAClC,CAAC;IACJ,CAAC;CACF;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fastmail service implementation.
|
|
3
|
+
*
|
|
4
|
+
* Fastmail's JMAP API is an OAuth 2.1 protected resource: it advertises an
|
|
5
|
+
* authorization server at `https://api.fastmail.com` (RFC 8414 metadata at
|
|
6
|
+
* `/.well-known/oauth-authorization-server`) supporting dynamic client
|
|
7
|
+
* registration, PKCE (S256) and refresh tokens, with public clients
|
|
8
|
+
* (`token_endpoint_auth_method: none`). So no API token has to be created by
|
|
9
|
+
* hand in the account's settings and pasted in — `latchkey auth browser
|
|
10
|
+
* fastmail` is enough.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import type { Browser, BrowserContext, Response } from 'playwright';
|
|
14
|
+
import { type ApiCredentials } from '../apiCredentials/base.js';
|
|
15
|
+
import { Service, ServiceSession, type LoginResult } from './core/base.js';
|
|
16
|
+
/**
|
|
17
|
+
* JSON accepted by `latchkey auth prepare fastmail`: an OAuth client id to
|
|
18
|
+
* reuse instead of registering a new client dynamically. Fastmail issues
|
|
19
|
+
* public clients, so no secret is needed. `.strict()` rejects unknown keys so
|
|
20
|
+
* typos are reported instead of silently ignored.
|
|
21
|
+
*/
|
|
22
|
+
export declare const FastmailPrepareInputSchema: z.ZodObject<{
|
|
23
|
+
clientId: z.ZodString;
|
|
24
|
+
}, "strict", z.ZodTypeAny, {
|
|
25
|
+
clientId: string;
|
|
26
|
+
}, {
|
|
27
|
+
clientId: string;
|
|
28
|
+
}>;
|
|
29
|
+
export type FastmailPrepareInput = z.infer<typeof FastmailPrepareInputSchema>;
|
|
30
|
+
declare class FastmailSession extends ServiceSession {
|
|
31
|
+
onResponse(_response: Response): void;
|
|
32
|
+
protected isLoginComplete(): boolean;
|
|
33
|
+
protected finalizeCredentials(_browser: Browser, _context: BrowserContext, _oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
34
|
+
login(encryptedStorage: import('../encryptedStorage.js').EncryptedStorage, launchOptions?: import('../playwrightUtils.js').BrowserLaunchOptions, oldCredentials?: ApiCredentials): Promise<LoginResult>;
|
|
35
|
+
}
|
|
36
|
+
export declare class Fastmail extends Service {
|
|
37
|
+
readonly name = "fastmail";
|
|
38
|
+
readonly displayName = "Fastmail";
|
|
39
|
+
/**
|
|
40
|
+
* Four host shapes, which is why these are patterns rather than plain
|
|
41
|
+
* prefixes. Session discovery starts at `api.fastmail.com`, but the `apiUrl`
|
|
42
|
+
* and `downloadUrl` it returns point at the shard the account is homed on
|
|
43
|
+
* (`phl.api.fastmail.com`, `phl-www.fastmailusercontent.com`, …). Which
|
|
44
|
+
* shard that is only becomes known after discovery, so the service has to
|
|
45
|
+
* cover them all up front.
|
|
46
|
+
*
|
|
47
|
+
* The blob pattern is anchored on the `www` label rather than accepting any
|
|
48
|
+
* subdomain: the session document only ever names `www.fastmailusercontent.com`
|
|
49
|
+
* or `<shard>-www.…`, and this is the domain Fastmail uses to serve user
|
|
50
|
+
* content, so matching it loosely would offer the access token to hosts the
|
|
51
|
+
* credential has no business reaching.
|
|
52
|
+
*
|
|
53
|
+
* Deliberately NOT covering carddav.fastmail.com / caldav.fastmail.com. Those
|
|
54
|
+
* advertise `WWW-Authenticate: Basic realm=..., Bearer`, so adding them looks
|
|
55
|
+
* right, but Fastmail's OAuth access tokens are refused there (401 on every
|
|
56
|
+
* path tried, including the principal and per-user collections) — the DAV
|
|
57
|
+
* endpoints want an app password over Basic auth, which is a different
|
|
58
|
+
* credential type than this service issues. Contacts and calendars are
|
|
59
|
+
* reachable over JMAP on the hosts below instead.
|
|
60
|
+
*/
|
|
61
|
+
readonly baseApiUrls: readonly [RegExp, RegExp];
|
|
62
|
+
readonly loginUrl = "https://api.fastmail.com/oauth/authorize";
|
|
63
|
+
readonly info: string;
|
|
64
|
+
readonly credentialCheckCurlArguments: readonly ["https://api.fastmail.com/jmap/session"];
|
|
65
|
+
setCredentialsExample(serviceName: string): string;
|
|
66
|
+
/**
|
|
67
|
+
* Fastmail accepts an OAuth client id prepared in advance via
|
|
68
|
+
* `latchkey auth prepare`, stored as token-less OAuth credentials until
|
|
69
|
+
* login. The login flow reuses this client id instead of registering a new
|
|
70
|
+
* client dynamically.
|
|
71
|
+
*/
|
|
72
|
+
prepareFromJson(parsedJson: unknown): ApiCredentials;
|
|
73
|
+
getAccount(apiCredentials: ApiCredentials): Promise<string | null>;
|
|
74
|
+
getSession(appNamePrefix: string): FastmailSession;
|
|
75
|
+
refreshCredentials(apiCredentials: ApiCredentials): Promise<ApiCredentials | null>;
|
|
76
|
+
}
|
|
77
|
+
export declare const FASTMAIL: Fastmail;
|
|
78
|
+
export {};
|
|
79
|
+
//# sourceMappingURL=fastmail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastmail.d.ts","sourceRoot":"","sources":["../../../src/services/fastmail.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,KAAK,cAAc,EAAoB,MAAM,2BAA2B,CAAC;AAclF,OAAO,EACL,OAAO,EACP,cAAc,EACd,KAAK,WAAW,EAKjB,MAAM,gBAAgB,CAAC;AAExB;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B;;;;;;EAI5B,CAAC;AAEZ,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AA8I9E,cAAM,eAAgB,SAAQ,cAAc;IAC1C,UAAU,CAAC,SAAS,EAAE,QAAQ,GAAG,IAAI;IAIrC,SAAS,CAAC,eAAe,IAAI,OAAO;IAKpC,SAAS,CAAC,mBAAmB,CAC3B,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,cAAc,EACxB,eAAe,CAAC,EAAE,cAAc,GAC/B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAKlB,KAAK,CAClB,gBAAgB,EAAE,OAAO,wBAAwB,EAAE,gBAAgB,EACnE,aAAa,GAAE,OAAO,uBAAuB,EAAE,oBAAyB,EACxE,cAAc,CAAC,EAAE,cAAc,GAC9B,OAAO,CAAC,WAAW,CAAC;CAiGxB;AAED,qBAAa,QAAS,SAAQ,OAAO;IACnC,QAAQ,CAAC,IAAI,cAAc;IAC3B,QAAQ,CAAC,WAAW,cAAc;IAElC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,QAAQ,CAAC,WAAW,4BAGT;IAEX,QAAQ,CAAC,QAAQ,8CAA0B;IAE3C,QAAQ,CAAC,IAAI,SAI6D;IAE1E,QAAQ,CAAC,4BAA4B,qDAA+B;IAEpE,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAIlD;;;;;OAKG;IACM,eAAe,CAAC,UAAU,EAAE,OAAO,GAAG,cAAc;IASpD,UAAU,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAQlE,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,eAAe;IAI5C,kBAAkB,CAC/B,cAAc,EAAE,cAAc,GAC7B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CAgClC;AAED,eAAO,MAAM,QAAQ,UAAiB,CAAC"}
|