latchkey 3.2.2 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/src/cliCommands.d.ts.map +1 -1
- package/dist/src/cliCommands.js +91 -7
- package/dist/src/cliCommands.js.map +1 -1
- package/dist/src/configDataStore.d.ts +18 -0
- package/dist/src/configDataStore.d.ts.map +1 -1
- package/dist/src/configDataStore.js +10 -0
- package/dist/src/configDataStore.js.map +1 -1
- package/dist/src/serviceRegistry.d.ts.map +1 -1
- package/dist/src/serviceRegistry.js +25 -2
- package/dist/src/serviceRegistry.js.map +1 -1
- package/dist/src/services/core/base.d.ts +25 -3
- package/dist/src/services/core/base.d.ts.map +1 -1
- package/dist/src/services/core/base.js +32 -10
- package/dist/src/services/core/base.js.map +1 -1
- package/dist/src/services/core/loginFlows/base.d.ts +75 -0
- package/dist/src/services/core/loginFlows/base.d.ts.map +1 -0
- package/dist/src/services/core/loginFlows/base.js +47 -0
- package/dist/src/services/core/loginFlows/base.js.map +1 -0
- package/dist/src/services/core/loginFlows/cookieCapture.d.ts +55 -0
- package/dist/src/services/core/loginFlows/cookieCapture.d.ts.map +1 -0
- package/dist/src/services/core/loginFlows/cookieCapture.js +244 -0
- package/dist/src/services/core/loginFlows/cookieCapture.js.map +1 -0
- package/dist/src/services/core/loginFlows/registry.d.ts +30 -0
- package/dist/src/services/core/loginFlows/registry.d.ts.map +1 -0
- package/dist/src/services/core/loginFlows/registry.js +56 -0
- package/dist/src/services/core/loginFlows/registry.js.map +1 -0
- package/dist/src/services/core/registered.d.ts +38 -2
- package/dist/src/services/core/registered.d.ts.map +1 -1
- package/dist/src/services/core/registered.js +37 -2
- package/dist/src/services/core/registered.js.map +1 -1
- package/dist/src/services/index.d.ts +3 -0
- package/dist/src/services/index.d.ts.map +1 -1
- package/dist/src/services/index.js +3 -0
- package/dist/src/services/index.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/tests/cli.test.js +178 -2
- package/dist/tests/cli.test.js.map +1 -1
- package/dist/tests/cookieCapture.test.d.ts +10 -0
- package/dist/tests/cookieCapture.test.d.ts.map +1 -0
- package/dist/tests/cookieCapture.test.js +221 -0
- package/dist/tests/cookieCapture.test.js.map +1 -0
- package/dist/tests/serviceRegistry.test.js +29 -8
- package/dist/tests/serviceRegistry.test.js.map +1 -1
- package/dist/tests/servicesAgainstRecordings.test.js +5 -9
- package/dist/tests/servicesAgainstRecordings.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -55,16 +55,22 @@ export class PrepareInputInvalidError extends Error {
|
|
|
55
55
|
export function buildPreparedCredentials(serviceName, schema, parsedJson, build) {
|
|
56
56
|
const result = schema.safeParse(parsedJson);
|
|
57
57
|
if (!result.success) {
|
|
58
|
-
|
|
59
|
-
.map((issue) => {
|
|
60
|
-
const path = issue.path.join('.');
|
|
61
|
-
return path ? `${path}: ${issue.message}` : issue.message;
|
|
62
|
-
})
|
|
63
|
-
.join('; ');
|
|
64
|
-
throw new PrepareInputInvalidError(serviceName, detail);
|
|
58
|
+
throw new PrepareInputInvalidError(serviceName, describeSchemaIssues(result.error));
|
|
65
59
|
}
|
|
66
60
|
return build(result.data);
|
|
67
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Render the failing fields of a schema mismatch as a single line, so every
|
|
64
|
+
* command that validates JSON input reports problems the same way.
|
|
65
|
+
*/
|
|
66
|
+
export function describeSchemaIssues(error) {
|
|
67
|
+
return error.issues
|
|
68
|
+
.map((issue) => {
|
|
69
|
+
const path = issue.path.join('.');
|
|
70
|
+
return path ? `${path}: ${issue.message}` : issue.message;
|
|
71
|
+
})
|
|
72
|
+
.join('; ');
|
|
73
|
+
}
|
|
68
74
|
export function isBrowserClosedError(error) {
|
|
69
75
|
const message = error.message.toLowerCase();
|
|
70
76
|
return (message.includes('target closed') ||
|
|
@@ -191,7 +197,7 @@ export class ServiceSession {
|
|
|
191
197
|
return withTempBrowserContext(encryptedStorage, launchOptions, async ({ browser, context }) => {
|
|
192
198
|
const page = await context.newPage();
|
|
193
199
|
context.on('response', (response) => {
|
|
194
|
-
this.onResponse(response);
|
|
200
|
+
void this.onResponse(response);
|
|
195
201
|
});
|
|
196
202
|
try {
|
|
197
203
|
await page.goto(this.service.loginUrl);
|
|
@@ -235,12 +241,28 @@ export class ServiceSession {
|
|
|
235
241
|
*/
|
|
236
242
|
export class SimpleServiceSession extends ServiceSession {
|
|
237
243
|
apiCredentials = null;
|
|
244
|
+
/**
|
|
245
|
+
* What the session has extracted so far, or null while the login phase is
|
|
246
|
+
* still going.
|
|
247
|
+
*
|
|
248
|
+
* Exists for the tests, and they are its only callers: a real login goes
|
|
249
|
+
* through {@link login}, which returns the credentials once the phase
|
|
250
|
+
* completes. It is public rather than protected because the alternative is
|
|
251
|
+
* what the tests did before — casting past `protected` to read the field —
|
|
252
|
+
* which typechecks forever and quietly stops meaning anything the moment the
|
|
253
|
+
* internals change.
|
|
254
|
+
*/
|
|
255
|
+
get capturedCredentials() {
|
|
256
|
+
return this.apiCredentials;
|
|
257
|
+
}
|
|
238
258
|
onResponse(response) {
|
|
239
259
|
if (this.apiCredentials !== null) {
|
|
240
|
-
return;
|
|
260
|
+
return Promise.resolve();
|
|
241
261
|
}
|
|
242
|
-
this.getApiCredentialsFromResponse(response)
|
|
262
|
+
return this.getApiCredentialsFromResponse(response)
|
|
243
263
|
.then((credentials) => {
|
|
264
|
+
// Another response may have produced credentials while this one was
|
|
265
|
+
// being read.
|
|
244
266
|
if (this.apiCredentials === null && credentials !== null) {
|
|
245
267
|
this.apiCredentials = credentials;
|
|
246
268
|
}
|
|
@@ -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,GAEvB,MAAM,0BAA0B,CAAC;AAElC,MAAM,OAAO,kCAAmC,SAAQ,KAAK;IAC3D,YAAY,WAAmB;QAC7B,KAAK,CAAC,YAAY,WAAW,4CAA4C,CAAC,CAAC;QAC3E,IAAI,CAAC,IAAI,GAAG,oCAAoC,CAAC;IACnD,CAAC;CACF;AAED,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,OAAO,GAAG,qDAAqD;QACzE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACzC,YAAY,OAAO,GAAG,8CAA8C;QAClE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACjD,YAAY,WAAmB;QAC7B,KAAK,CACH,YAAY,WAAW,8CAA8C;YACnE,+BAA+B,WAAW,+BAA+B,CAC5E,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACjD,YAAY,WAAmB,EAAE,MAAc;QAC7C,KAAK,CAAC,8BAA8B,WAAW,MAAM,MAAM,EAAE,CAAC,CAAC;QAC/D,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CACtC,WAAmB,EACnB,MAAc,EACd,UAAmB,EACnB,KAA0D;IAE1D,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC5C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,
|
|
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,GAEvB,MAAM,0BAA0B,CAAC;AAElC,MAAM,OAAO,kCAAmC,SAAQ,KAAK;IAC3D,YAAY,WAAmB;QAC7B,KAAK,CAAC,YAAY,WAAW,4CAA4C,CAAC,CAAC;QAC3E,IAAI,CAAC,IAAI,GAAG,oCAAoC,CAAC;IACnD,CAAC;CACF;AAED,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,OAAO,GAAG,qDAAqD;QACzE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACzC,YAAY,OAAO,GAAG,8CAA8C;QAClE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACjD,YAAY,WAAmB;QAC7B,KAAK,CACH,YAAY,WAAW,8CAA8C;YACnE,+BAA+B,WAAW,+BAA+B,CAC5E,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACjD,YAAY,WAAmB,EAAE,MAAc;QAC7C,KAAK,CAAC,8BAA8B,WAAW,MAAM,MAAM,EAAE,CAAC,CAAC;QAC/D,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CACtC,WAAmB,EACnB,MAAc,EACd,UAAmB,EACnB,KAA0D;IAE1D,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC5C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,wBAAwB,CAAC,WAAW,EAAE,oBAAoB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,CAAC,IAAuB,CAAC,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAe;IAClD,OAAO,KAAK,CAAC,MAAM;SAChB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACb,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;IAC5D,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAiBD,MAAM,UAAU,oBAAoB,CAAC,KAAY;IAC/C,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IAC5C,OAAO,CACL,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;QACjC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QAClC,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAC;QAC3C,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAC;QAC3C,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACxC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CACrC,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,8BAA8B,CAAC,KAAY;IACzD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IAC5C,OAAO,CACL,OAAO,CAAC,QAAQ,CAAC,mCAAmC,CAAC;QACrD,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAC5C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAY;IACzC,OAAO,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,MAAM,OAAgB,OAAO;IAyB3B;;;;;;;OAOG;IACH,KAAK,CAAC,mBAAmB,CAAC,cAA8B;QACtD,IAAI,WAA8B,CAAC;QACnC,IAAI,CAAC;YACH,WAAW,GAAG,MAAM,cAAc,CAAC,kBAAkB,CAAC;gBACpD,IAAI;gBACJ,IAAI;gBACJ,gBAAgB;gBAChB,GAAG,IAAI,CAAC,4BAA4B;aACrC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,wBAAwB,EAAE,CAAC;gBAC9C,OAAO,mBAAmB,CAAC,OAAO,CAAC;YACrC,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAEvD,uEAAuE;QACvE,2DAA2D;QAC3D,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACvD,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACtE,MAAM,YAAY,GAAG,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;QAEzF,IAAI,CAAC,IAAI,CAAC,8BAA8B,CAAC,cAAc,EAAE,YAAY,CAAC,EAAE,CAAC;YACvE,OAAO,mBAAmB,CAAC,OAAO,CAAC;QACrC,CAAC;QACD,OAAO,mBAAmB,CAAC,KAAK,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACO,8BAA8B,CAAC,cAAsB,EAAE,aAAqB;QACpF,OAAO,cAAc,KAAK,KAAK,CAAC;IAClC,CAAC;IAuBD;;;OAGG;IACH,oBAAoB,CAAC,UAA6B;QAChD,MAAM,IAAI,kCAAkC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1D,CAAC;CA4BF;AAED;;;GAGG;AACH,MAAM,OAAgB,cAAc;IACzB,OAAO,CAAU;IACP,aAAa,CAAS;IAEzC,YAAY,OAAgB,EAAE,aAAqB;QACjD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACrC,CAAC;IAED;;OAEG;IACO,eAAe,CAAC,MAAe;QACvC,OAAO,uBAAuB,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAC7D,CAAC;IA8BD;;OAEG;IACK,KAAK,CAAC,oBAAoB,CAAC,IAAU;QAC3C,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC/B,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACO,oBAAoB,CAC5B,QAAwB,EACxB,cAAqB;QAErB,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAeD;;;;;OAKG;IACH,KAAK,CAAC,KAAK,CACT,gBAAkC,EAClC,gBAAsC,EAAE,EACxC,cAA+B;QAE/B,OAAO,sBAAsB,CAAC,gBAAgB,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE;YAC5F,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;YAErC,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,EAAE;gBAClC,KAAK,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YACjC,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBACvC,MAAM,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;YACxC,CAAC;YAAC,OAAO,KAAc,EAAE,CAAC;gBACxB,IAAI,KAAK,YAAY,KAAK,IAAI,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC1D,MAAM,IAAI,mBAAmB,EAAE,CAAC;gBAClC,CAAC;gBACD,MAAM,KAAK,CAAC;YACd,CAAC;YAED,IAAI,cAAqC,CAAC;YAC1C,IAAI,CAAC;gBACH,cAAc,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;YACpF,CAAC;YAAC,OAAO,KAAc,EAAE,CAAC;gBACxB,IAAI,KAAK,YAAY,KAAK,IAAI,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC1D,MAAM,IAAI,mBAAmB,EAAE,CAAC;gBAClC,CAAC;gBACD,IAAI,KAAK,YAAY,KAAK,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;oBACpD,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;oBACvE,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;wBAC5B,MAAM,cAAc,CAAC;oBACvB,CAAC;oBACD,MAAM,IAAI,gBAAgB,CAAC,iBAAiB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC/D,CAAC;gBACD,MAAM,KAAK,CAAC;YACd,CAAC;YAED,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;gBAC5B,MAAM,IAAI,gBAAgB,EAAE,CAAC;YAC/B,CAAC;YAED,iEAAiE;YACjE,+CAA+C;YAC/C,MAAM,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,IAAI,eAAe,CAAC;YACnF,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC;QAClD,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAgB,oBAAqB,SAAQ,cAAc;IACrD,cAAc,GAA0B,IAAI,CAAC;IAEvD;;;;;;;;;;OAUG;IACH,IAAI,mBAAmB;QACrB,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IASD,UAAU,CAAC,QAAkB;QAC3B,IAAI,IAAI,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;YACjC,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC;QACD,OAAO,IAAI,CAAC,6BAA6B,CAAC,QAAQ,CAAC;aAChD,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE;YACpB,oEAAoE;YACpE,cAAc;YACd,IAAI,IAAI,CAAC,cAAc,KAAK,IAAI,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;gBACzD,IAAI,CAAC,cAAc,GAAG,WAAW,CAAC;YACpC,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,uCAAuC;QACzC,CAAC,CAAC,CAAC;IACP,CAAC;IAES,eAAe;QACvB,OAAO,IAAI,CAAC,cAAc,KAAK,IAAI,CAAC;IACtC,CAAC;IAES,mBAAmB,CAC3B,QAAiB,EACjB,QAAwB,EACxB,eAAgC;QAEhC,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC9C,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,CAAN,IAAY,YAIX;AAJD,WAAY,YAAY;IACtB,2DAA2C,CAAA;IAC3C,gDAAgC,CAAA;IAChC,kEAAkD,CAAA;AACpD,CAAC,EAJW,YAAY,KAAZ,YAAY,QAIvB;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CACzC,WAAmB,EACnB,YAA0B,EAC1B,gBAAgB,GAAG,wBAAwB;IAE3C,OAAO,CACL,GAAG,YAAY,SAAS,WAAW,aAAa,gBAAgB,GAAG;QACnE,2FAA2F,CAC5F,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAgB,6BAA8B,SAAQ,cAAc;IAChE,mBAAmB,GAAgB,IAAI,CAAC;IAKhD;;;;;OAKG;IACH,IAAc,WAAW;QACvB,OAAO,IAAI,CAAC,mBAAmB,CAAC;IAClC,CAAC;IAakB,KAAK,CAAC,mBAAmB,CAC1C,QAAiB,EACjB,OAAuB,EACvB,cAA+B;QAE/B,IAAI,CAAC,mBAAmB,GAAG,MAAM,eAAe,CAC9C,OAAO,EACP,cAAc,IAAI,CAAC,OAAO,CAAC,WAAW,WAAW,EACjD,2BAA2B,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,CACzE,CAAC;QACF,OAAO,IAAI,CAAC,sBAAsB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IAC9D,CAAC;CACF"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a generic browser login flow is, and how its parameters are read.
|
|
3
|
+
*
|
|
4
|
+
* A built-in service implements its login in code. A registered service picks a
|
|
5
|
+
* flow by name and supplies parameters as JSON, so new flows become available to
|
|
6
|
+
* every registered service without the CLI knowing anything about them.
|
|
7
|
+
*
|
|
8
|
+
* Three things are involved, and they are deliberately distinct:
|
|
9
|
+
*
|
|
10
|
+
* - a **flow class** is a kind of automation, with a name and a parameter
|
|
11
|
+
* schema — {@link LoginFlowClass};
|
|
12
|
+
* - a **flow** is one configuration of that kind, holding validated parameters
|
|
13
|
+
* and able to create sessions — {@link LoginFlow};
|
|
14
|
+
* - a **session** is a single run of one, created per login and discarded
|
|
15
|
+
* afterwards — `ServiceSession`.
|
|
16
|
+
*
|
|
17
|
+
* The parameters are validated long before a login happens (when a service is
|
|
18
|
+
* registered, or when config.json is read), which is why a flow rather than a
|
|
19
|
+
* session is what a registered service holds on to.
|
|
20
|
+
*
|
|
21
|
+
* The flows themselves are listed in `registry`, which imports them.
|
|
22
|
+
* Keeping that list out of this module is what lets a flow import from here
|
|
23
|
+
* without the two forming a cycle.
|
|
24
|
+
*/
|
|
25
|
+
import type { ZodType, ZodTypeAny } from 'zod';
|
|
26
|
+
import { Service, type ServiceSession } from '../base.js';
|
|
27
|
+
/**
|
|
28
|
+
* Thrown when the parameters stored for a login flow do not match its schema.
|
|
29
|
+
*/
|
|
30
|
+
export declare class LoginFlowParamsInvalidError extends Error {
|
|
31
|
+
constructor(flowName: string, detail: string);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A generic browser login that a user-registered service can opt into,
|
|
35
|
+
* configured with the parameters that service was registered with.
|
|
36
|
+
*
|
|
37
|
+
* A built-in service implements its login in code. A registered service picks a
|
|
38
|
+
* flow by name and supplies parameters as JSON, so new flows become available to
|
|
39
|
+
* every registered service without the CLI knowing anything about them.
|
|
40
|
+
*/
|
|
41
|
+
export interface LoginFlow {
|
|
42
|
+
/** Sentence describing this configuration, for `services info`. */
|
|
43
|
+
describe(loginUrl: string): string;
|
|
44
|
+
createSession(service: Service, appNamePrefix: string): ServiceSession;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The class side of a flow: the kind of automation, before anyone configures
|
|
48
|
+
* it. Its instances are the configured flows.
|
|
49
|
+
*
|
|
50
|
+
* The metadata has to be static, since flows are listed and described before
|
|
51
|
+
* any parameters exist — and TypeScript has no `abstract static`, so this
|
|
52
|
+
* interface is what holds a flow class to declaring it. A flow states the
|
|
53
|
+
* obligation with `satisfies LoginFlowClass`; the registry checks it again by
|
|
54
|
+
* being typed as an array of these.
|
|
55
|
+
*/
|
|
56
|
+
export interface LoginFlowClass {
|
|
57
|
+
new (params: unknown): LoginFlow;
|
|
58
|
+
/** Value of `--login-flow`. Not `name`, which every class already has. */
|
|
59
|
+
readonly flowName: string;
|
|
60
|
+
/** One-line explanation, listed by the CLI when the flow name is wrong. */
|
|
61
|
+
readonly summary: string;
|
|
62
|
+
/** Reference documentation, shown by `services register --help`. */
|
|
63
|
+
readonly details: string;
|
|
64
|
+
readonly paramsSchema: ZodTypeAny;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Validate the parameters a flow was registered with, against the flow's own
|
|
68
|
+
* schema. Inference gives back the schema's type, so a flow storing the result
|
|
69
|
+
* cannot disagree with the schema it declared.
|
|
70
|
+
*/
|
|
71
|
+
export declare function parseLoginFlowParams<Params>(flowClass: {
|
|
72
|
+
readonly flowName: string;
|
|
73
|
+
readonly paramsSchema: ZodType<Params>;
|
|
74
|
+
}, rawParams: unknown): Params;
|
|
75
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../../src/services/core/loginFlows/base.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAC/C,OAAO,EAAwB,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAEhF;;GAEG;AACH,qBAAa,2BAA4B,SAAQ,KAAK;gBACxC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAI7C;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACxB,mEAAmE;IACnE,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,cAAc,CAAC;CACxE;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,UAAU,CAAC;CACnC;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EACzC,SAAS,EAAE;IAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;CAAE,EAChF,SAAS,EAAE,OAAO,GACjB,MAAM,CAMR"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a generic browser login flow is, and how its parameters are read.
|
|
3
|
+
*
|
|
4
|
+
* A built-in service implements its login in code. A registered service picks a
|
|
5
|
+
* flow by name and supplies parameters as JSON, so new flows become available to
|
|
6
|
+
* every registered service without the CLI knowing anything about them.
|
|
7
|
+
*
|
|
8
|
+
* Three things are involved, and they are deliberately distinct:
|
|
9
|
+
*
|
|
10
|
+
* - a **flow class** is a kind of automation, with a name and a parameter
|
|
11
|
+
* schema — {@link LoginFlowClass};
|
|
12
|
+
* - a **flow** is one configuration of that kind, holding validated parameters
|
|
13
|
+
* and able to create sessions — {@link LoginFlow};
|
|
14
|
+
* - a **session** is a single run of one, created per login and discarded
|
|
15
|
+
* afterwards — `ServiceSession`.
|
|
16
|
+
*
|
|
17
|
+
* The parameters are validated long before a login happens (when a service is
|
|
18
|
+
* registered, or when config.json is read), which is why a flow rather than a
|
|
19
|
+
* session is what a registered service holds on to.
|
|
20
|
+
*
|
|
21
|
+
* The flows themselves are listed in `registry`, which imports them.
|
|
22
|
+
* Keeping that list out of this module is what lets a flow import from here
|
|
23
|
+
* without the two forming a cycle.
|
|
24
|
+
*/
|
|
25
|
+
import { describeSchemaIssues } from '../base.js';
|
|
26
|
+
/**
|
|
27
|
+
* Thrown when the parameters stored for a login flow do not match its schema.
|
|
28
|
+
*/
|
|
29
|
+
export class LoginFlowParamsInvalidError extends Error {
|
|
30
|
+
constructor(flowName, detail) {
|
|
31
|
+
super(`Invalid parameters for login flow '${flowName}': ${detail}`);
|
|
32
|
+
this.name = 'LoginFlowParamsInvalidError';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Validate the parameters a flow was registered with, against the flow's own
|
|
37
|
+
* schema. Inference gives back the schema's type, so a flow storing the result
|
|
38
|
+
* cannot disagree with the schema it declared.
|
|
39
|
+
*/
|
|
40
|
+
export function parseLoginFlowParams(flowClass, rawParams) {
|
|
41
|
+
const result = flowClass.paramsSchema.safeParse(rawParams ?? {});
|
|
42
|
+
if (!result.success) {
|
|
43
|
+
throw new LoginFlowParamsInvalidError(flowClass.flowName, describeSchemaIssues(result.error));
|
|
44
|
+
}
|
|
45
|
+
return result.data;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../../../../src/services/core/loginFlows/base.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,oBAAoB,EAAgC,MAAM,YAAY,CAAC;AAEhF;;GAEG;AACH,MAAM,OAAO,2BAA4B,SAAQ,KAAK;IACpD,YAAY,QAAgB,EAAE,MAAc;QAC1C,KAAK,CAAC,sCAAsC,QAAQ,MAAM,MAAM,EAAE,CAAC,CAAC;QACpE,IAAI,CAAC,IAAI,GAAG,6BAA6B,CAAC;IAC5C,CAAC;CACF;AAqCD;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,SAAgF,EAChF,SAAkB;IAElB,MAAM,MAAM,GAAG,SAAS,CAAC,YAAY,CAAC,SAAS,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IACjE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,2BAA2B,CAAC,SAAS,CAAC,QAAQ,EAAE,oBAAoB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A generic browser login that works for any cookie-authenticated service:
|
|
3
|
+
* open a URL, watch the `Set-Cookie` headers of the responses that follow, and
|
|
4
|
+
* capture named cookies as the credentials.
|
|
5
|
+
*
|
|
6
|
+
* The cookie mechanics — reading `Set-Cookie`, deciding where a cookie applies,
|
|
7
|
+
* writing a `Cookie` header — are RFC 6265 and not specific to this flow, but
|
|
8
|
+
* they stay private to it: nothing else needs them, and behind the LoginFlow
|
|
9
|
+
* interface nobody has to care how this flow works. If cookie handling is ever
|
|
10
|
+
* wanted elsewhere, this is the part to lift back out into a module of its own.
|
|
11
|
+
*
|
|
12
|
+
* The flow interprets the registered parameters; the session it creates holds
|
|
13
|
+
* the cookies of one login.
|
|
14
|
+
*
|
|
15
|
+
* Nothing here is service-specific — the cookie names come from whoever
|
|
16
|
+
* registered the service, as the parameters of the `cookie-capture` login flow.
|
|
17
|
+
*/
|
|
18
|
+
import { z } from 'zod';
|
|
19
|
+
import { Service, type ServiceSession } from '../base.js';
|
|
20
|
+
import { type LoginFlow } from './base.js';
|
|
21
|
+
/**
|
|
22
|
+
* The flow. Its statics are the kind of automation — what `--login-flow`
|
|
23
|
+
* selects — and an instance is that kind configured with one service's
|
|
24
|
+
* parameters, ready to create a session per login.
|
|
25
|
+
*/
|
|
26
|
+
export declare class CookieCaptureLoginFlow implements LoginFlow {
|
|
27
|
+
/** Value of `--login-flow`. Not `name`, which every class already has. */
|
|
28
|
+
static readonly flowName = "cookie-capture";
|
|
29
|
+
static readonly summary = "Open the login URL and capture named session cookies as they are set.";
|
|
30
|
+
static readonly details: string;
|
|
31
|
+
static readonly paramsSchema: z.ZodObject<{
|
|
32
|
+
/** Cookie names to capture. The login completes once all of them exist. */
|
|
33
|
+
cookieKeys: z.ZodArray<z.ZodString, "many">;
|
|
34
|
+
/**
|
|
35
|
+
* URL the cookies must apply to. Defaults to the service's login URL, which
|
|
36
|
+
* is right unless sign-in happens on a different host than the API.
|
|
37
|
+
*/
|
|
38
|
+
cookieUrl: z.ZodOptional<z.ZodString>;
|
|
39
|
+
}, "strict", z.ZodTypeAny, {
|
|
40
|
+
cookieKeys: string[];
|
|
41
|
+
cookieUrl?: string | undefined;
|
|
42
|
+
}, {
|
|
43
|
+
cookieKeys: string[];
|
|
44
|
+
cookieUrl?: string | undefined;
|
|
45
|
+
}>;
|
|
46
|
+
private readonly params;
|
|
47
|
+
constructor(rawParams: unknown);
|
|
48
|
+
describe(loginUrl: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* The cookies are looked for wherever they would be sent: the page the login
|
|
51
|
+
* starts from, unless the parameters name somewhere else.
|
|
52
|
+
*/
|
|
53
|
+
createSession(service: Service, appNamePrefix: string): ServiceSession;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=cookieCapture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookieCapture.d.ts","sourceRoot":"","sources":["../../../../../src/services/core/loginFlows/cookieCapture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAwB,KAAK,SAAS,EAAuB,MAAM,WAAW,CAAC;AA8NtF;;;;GAIG;AACH,qBAAa,sBAAuB,YAAW,SAAS;IACtD,0EAA0E;IAC1E,MAAM,CAAC,QAAQ,CAAC,QAAQ,oBAAoB;IAE5C,MAAM,CAAC,QAAQ,CAAC,OAAO,2EAA2E;IAElG,MAAM,CAAC,QAAQ,CAAC,OAAO,SAoBV;IAEb,MAAM,CAAC,QAAQ,CAAC,YAAY;QAvF1B,2EAA2E;;QAE3E;;;WAGG;;;;;;;;OAkFoD;IAEzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;gBAEjC,SAAS,EAAE,OAAO;IAI9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAQlC;;;OAGG;IACH,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,cAAc;CAQvE"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A generic browser login that works for any cookie-authenticated service:
|
|
3
|
+
* open a URL, watch the `Set-Cookie` headers of the responses that follow, and
|
|
4
|
+
* capture named cookies as the credentials.
|
|
5
|
+
*
|
|
6
|
+
* The cookie mechanics — reading `Set-Cookie`, deciding where a cookie applies,
|
|
7
|
+
* writing a `Cookie` header — are RFC 6265 and not specific to this flow, but
|
|
8
|
+
* they stay private to it: nothing else needs them, and behind the LoginFlow
|
|
9
|
+
* interface nobody has to care how this flow works. If cookie handling is ever
|
|
10
|
+
* wanted elsewhere, this is the part to lift back out into a module of its own.
|
|
11
|
+
*
|
|
12
|
+
* The flow interprets the registered parameters; the session it creates holds
|
|
13
|
+
* the cookies of one login.
|
|
14
|
+
*
|
|
15
|
+
* Nothing here is service-specific — the cookie names come from whoever
|
|
16
|
+
* registered the service, as the parameters of the `cookie-capture` login flow.
|
|
17
|
+
*/
|
|
18
|
+
import { z } from 'zod';
|
|
19
|
+
import { RawCurlCredentials } from '../../../apiCredentials/base.js';
|
|
20
|
+
import { SimpleServiceSession } from '../base.js';
|
|
21
|
+
import { parseLoginFlowParams } from './base.js';
|
|
22
|
+
/**
|
|
23
|
+
* The path a cookie without a `Path` attribute applies to: the directory of the
|
|
24
|
+
* request path (RFC 6265 §5.1.4).
|
|
25
|
+
*/
|
|
26
|
+
function defaultCookiePath(responseUrl) {
|
|
27
|
+
const path = responseUrl.pathname;
|
|
28
|
+
if (!path.startsWith('/')) {
|
|
29
|
+
return '/';
|
|
30
|
+
}
|
|
31
|
+
const lastSeparatorIndex = path.lastIndexOf('/');
|
|
32
|
+
return lastSeparatorIndex === 0 ? '/' : path.slice(0, lastSeparatorIndex);
|
|
33
|
+
}
|
|
34
|
+
function isExpired(expiresAttribute) {
|
|
35
|
+
const expiresAt = Date.parse(expiresAttribute);
|
|
36
|
+
return !Number.isNaN(expiresAt) && expiresAt <= Date.now();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Parse one `Set-Cookie` header value, as sent by the response at
|
|
40
|
+
* `responseUrl`. Returns null when it is not a usable cookie definition at all.
|
|
41
|
+
*/
|
|
42
|
+
function parseSetCookieHeader(headerValue, responseUrl) {
|
|
43
|
+
const [nameValuePair = '', ...attributeParts] = headerValue.split(';');
|
|
44
|
+
const separatorIndex = nameValuePair.indexOf('=');
|
|
45
|
+
if (separatorIndex <= 0) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const name = nameValuePair.slice(0, separatorIndex).trim();
|
|
49
|
+
const value = nameValuePair.slice(separatorIndex + 1).trim();
|
|
50
|
+
let domain = responseUrl.hostname.toLowerCase();
|
|
51
|
+
let path = defaultCookiePath(responseUrl);
|
|
52
|
+
// An empty value is how a cookie is cleared without an explicit expiry.
|
|
53
|
+
let isDeletion = value === '';
|
|
54
|
+
for (const attributePart of attributeParts) {
|
|
55
|
+
const attributeSeparatorIndex = attributePart.indexOf('=');
|
|
56
|
+
const attributeName = (attributeSeparatorIndex === -1
|
|
57
|
+
? attributePart
|
|
58
|
+
: attributePart.slice(0, attributeSeparatorIndex))
|
|
59
|
+
.trim()
|
|
60
|
+
.toLowerCase();
|
|
61
|
+
const attributeValue = attributeSeparatorIndex === -1 ? '' : attributePart.slice(attributeSeparatorIndex + 1).trim();
|
|
62
|
+
if (attributeName === 'domain' && attributeValue !== '') {
|
|
63
|
+
domain = attributeValue.replace(/^\./, '').toLowerCase();
|
|
64
|
+
}
|
|
65
|
+
else if (attributeName === 'path' && attributeValue.startsWith('/')) {
|
|
66
|
+
path = attributeValue;
|
|
67
|
+
}
|
|
68
|
+
else if (attributeName === 'max-age' && Number(attributeValue) <= 0) {
|
|
69
|
+
isDeletion = true;
|
|
70
|
+
}
|
|
71
|
+
else if (attributeName === 'expires' && isExpired(attributeValue)) {
|
|
72
|
+
isDeletion = true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { name, value, domain, path, isDeletion };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Whether a browser would send this cookie to the given URL: the URL's host is
|
|
79
|
+
* the cookie's domain or below it, and its path is under the cookie's path.
|
|
80
|
+
*/
|
|
81
|
+
function doesCookieApplyTo(cookie, url) {
|
|
82
|
+
const host = url.hostname.toLowerCase();
|
|
83
|
+
if (host !== cookie.domain && !host.endsWith(`.${cookie.domain}`)) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
const path = url.pathname === '' ? '/' : url.pathname;
|
|
87
|
+
return path.startsWith(cookie.path);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Identity of a cookie in the jar. The same name can be set more than once
|
|
91
|
+
* under different scopes, and a browser then sends all of them, so a cookie is
|
|
92
|
+
* only superseded by one of matching name, domain and path.
|
|
93
|
+
*/
|
|
94
|
+
function cookieScopeKey(cookie) {
|
|
95
|
+
return `${cookie.name}\n${cookie.domain}\n${cookie.path}`;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* The cookies that would be sent to one URL, built up from the `Set-Cookie`
|
|
99
|
+
* headers of the responses observed so far.
|
|
100
|
+
*
|
|
101
|
+
* Only cookies that apply to the jar's URL are kept, so cookies picked up along
|
|
102
|
+
* the way — from an identity provider on another domain, say — are discarded as
|
|
103
|
+
* they arrive.
|
|
104
|
+
*/
|
|
105
|
+
class CookieJar {
|
|
106
|
+
url;
|
|
107
|
+
cookiesByScope = new Map();
|
|
108
|
+
constructor(url) {
|
|
109
|
+
this.url = url;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Take in the `Set-Cookie` headers of one response: cookies it sets are
|
|
113
|
+
* recorded, and cookies it clears are dropped.
|
|
114
|
+
*/
|
|
115
|
+
accept(setCookieHeaderValues, responseUrl) {
|
|
116
|
+
for (const headerValue of setCookieHeaderValues) {
|
|
117
|
+
const cookie = parseSetCookieHeader(headerValue, responseUrl);
|
|
118
|
+
if (cookie === null || !doesCookieApplyTo(cookie, this.url)) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (cookie.isDeletion) {
|
|
122
|
+
this.cookiesByScope.delete(cookieScopeKey(cookie));
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
this.cookiesByScope.set(cookieScopeKey(cookie), cookie);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
has(name) {
|
|
130
|
+
return [...this.cookiesByScope.values()].some((cookie) => cookie.name === name);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The cookies of the given names. A name can appear more than once — set both
|
|
134
|
+
* host-only and domain-wide, say — and a browser sends every one of them.
|
|
135
|
+
*/
|
|
136
|
+
cookiesNamed(names) {
|
|
137
|
+
return [...this.cookiesByScope.values()]
|
|
138
|
+
.filter((cookie) => names.includes(cookie.name))
|
|
139
|
+
.map((cookie) => ({ name: cookie.name, value: cookie.value }));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Render cookies as the value of a single `Cookie` header.
|
|
144
|
+
*
|
|
145
|
+
* One header carrying every pair separated by `'; '` is the only portable
|
|
146
|
+
* form: RFC 6265 has the user agent send one `Cookie` header, and servers that
|
|
147
|
+
* see several header lines commonly read just the first.
|
|
148
|
+
*/
|
|
149
|
+
function formatCookieHeaderValue(cookies) {
|
|
150
|
+
return cookies.map((cookie) => `${cookie.name}=${cookie.value}`).join('; ');
|
|
151
|
+
}
|
|
152
|
+
const CookieCaptureParamsSchema = z
|
|
153
|
+
.object({
|
|
154
|
+
/** Cookie names to capture. The login completes once all of them exist. */
|
|
155
|
+
cookieKeys: z.array(z.string().min(1)).min(1),
|
|
156
|
+
/**
|
|
157
|
+
* URL the cookies must apply to. Defaults to the service's login URL, which
|
|
158
|
+
* is right unless sign-in happens on a different host than the API.
|
|
159
|
+
*/
|
|
160
|
+
cookieUrl: z.string().url().optional(),
|
|
161
|
+
})
|
|
162
|
+
.strict();
|
|
163
|
+
/** Store captured cookies the way `latchkey auth set -H` would. */
|
|
164
|
+
function buildCookieCredentials(cookies) {
|
|
165
|
+
return new RawCurlCredentials(['-H', `Cookie: ${formatCookieHeaderValue(cookies)}`]);
|
|
166
|
+
}
|
|
167
|
+
function setCookieHeaderValues(headers) {
|
|
168
|
+
return headers
|
|
169
|
+
.filter((header) => header.name.toLowerCase() === 'set-cookie')
|
|
170
|
+
.map((header) => header.value);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* One run of the flow. A jar remembers the cookies as responses arrive; all
|
|
174
|
+
* this adds is which names the service asked for, and the rule that the login
|
|
175
|
+
* is done once every one of them has turned up.
|
|
176
|
+
*/
|
|
177
|
+
class CookieCaptureSession extends SimpleServiceSession {
|
|
178
|
+
jar;
|
|
179
|
+
cookieKeys;
|
|
180
|
+
constructor(service, appNamePrefix, cookieUrl, cookieKeys) {
|
|
181
|
+
super(service, appNamePrefix);
|
|
182
|
+
this.jar = new CookieJar(cookieUrl);
|
|
183
|
+
this.cookieKeys = cookieKeys;
|
|
184
|
+
}
|
|
185
|
+
async getApiCredentialsFromResponse(response) {
|
|
186
|
+
this.jar.accept(setCookieHeaderValues(await response.headersArray()), new URL(response.url()));
|
|
187
|
+
if (!this.cookieKeys.every((cookieKey) => this.jar.has(cookieKey))) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
return buildCookieCredentials(this.jar.cookiesNamed(this.cookieKeys));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* The flow. Its statics are the kind of automation — what `--login-flow`
|
|
195
|
+
* selects — and an instance is that kind configured with one service's
|
|
196
|
+
* parameters, ready to create a session per login.
|
|
197
|
+
*/
|
|
198
|
+
export class CookieCaptureLoginFlow {
|
|
199
|
+
/** Value of `--login-flow`. Not `name`, which every class already has. */
|
|
200
|
+
static flowName = 'cookie-capture';
|
|
201
|
+
static summary = 'Open the login URL and capture named session cookies as they are set.';
|
|
202
|
+
static details = [
|
|
203
|
+
'Parameters:',
|
|
204
|
+
' cookieKeys Names of the cookies to capture. Required, at least one. The',
|
|
205
|
+
' login finishes once every one of them has been set, and they',
|
|
206
|
+
' are stored together as a single "Cookie: a=1; b=2" header.',
|
|
207
|
+
' cookieUrl Full URL, including the scheme, that the cookies must apply',
|
|
208
|
+
' to. Defaults to the login URL. Set it when signing in happens',
|
|
209
|
+
' on a different host than the API.',
|
|
210
|
+
'',
|
|
211
|
+
'The cookies are read from the Set-Cookie headers of the responses that',
|
|
212
|
+
'arrive while the user signs in, so a cookie that only a page script sets is',
|
|
213
|
+
'not seen, and neither is one that an already signed-in session never sends',
|
|
214
|
+
'again.',
|
|
215
|
+
'',
|
|
216
|
+
'Example:',
|
|
217
|
+
' $ latchkey services register my-intranet \\',
|
|
218
|
+
' --base-api-url="https://intranet.example.com/api/" \\',
|
|
219
|
+
' --login-url="https://intranet.example.com/login" \\',
|
|
220
|
+
' --login-flow=cookie-capture \\',
|
|
221
|
+
' --login-flow-params=\'{"cookieKeys": ["sessionid", "csrftoken"]}\'',
|
|
222
|
+
].join('\n');
|
|
223
|
+
static paramsSchema = CookieCaptureParamsSchema;
|
|
224
|
+
params;
|
|
225
|
+
constructor(rawParams) {
|
|
226
|
+
this.params = parseLoginFlowParams(CookieCaptureLoginFlow, rawParams);
|
|
227
|
+
}
|
|
228
|
+
describe(loginUrl) {
|
|
229
|
+
const quotedKeys = this.params.cookieKeys.map((cookieKey) => `'${cookieKey}'`).join(', ');
|
|
230
|
+
return (`\`latchkey auth browser\` opens ${loginUrl} and stores the ${quotedKeys} ` +
|
|
231
|
+
`cookies of ${this.params.cookieUrl ?? loginUrl} as the credentials once they are set.`);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* The cookies are looked for wherever they would be sent: the page the login
|
|
235
|
+
* starts from, unless the parameters name somewhere else.
|
|
236
|
+
*/
|
|
237
|
+
createSession(service, appNamePrefix) {
|
|
238
|
+
return new CookieCaptureSession(service, appNamePrefix, new URL(this.params.cookieUrl ?? service.loginUrl), this.params.cookieKeys);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// TypeScript has no `static implements`, so this is where the class side of the
|
|
242
|
+
// flow is checked. The registry checks it again, but the error lands here.
|
|
243
|
+
CookieCaptureLoginFlow;
|
|
244
|
+
//# sourceMappingURL=cookieCapture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookieCapture.js","sourceRoot":"","sources":["../../../../../src/services/core/loginFlows/cookieCapture.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The list of generic browser login flows, and looking one up by the name
|
|
3
|
+
* `--login-flow` takes.
|
|
4
|
+
*
|
|
5
|
+
* This is the only module that knows which flows exist. What a flow *is* lives
|
|
6
|
+
* in `base`, which the flows themselves import; keeping the list separate is
|
|
7
|
+
* what stops that from being a cycle.
|
|
8
|
+
*/
|
|
9
|
+
import type { LoginFlow, LoginFlowClass } from './base.js';
|
|
10
|
+
export declare const LOGIN_FLOWS: readonly LoginFlowClass[];
|
|
11
|
+
export declare class UnknownLoginFlowError extends Error {
|
|
12
|
+
constructor(name: string);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Look up a flow class by the name `--login-flow` takes, and configure it with
|
|
16
|
+
* the given parameters.
|
|
17
|
+
*
|
|
18
|
+
* Throws {@link UnknownLoginFlowError}, or `LoginFlowParamsInvalidError` from
|
|
19
|
+
* the flow's own validation; callers decide what an unusable flow means for
|
|
20
|
+
* them (the CLI rejects the registration, loading a stored service drops just
|
|
21
|
+
* the flow).
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveLoginFlow(name: string, params: unknown): LoginFlow;
|
|
24
|
+
/**
|
|
25
|
+
* The reference documentation for every registered flow, for
|
|
26
|
+
* `latchkey services register --help`. Generated from the registry, so a flow
|
|
27
|
+
* added later documents itself without the CLI knowing anything about it.
|
|
28
|
+
*/
|
|
29
|
+
export declare function formatLoginFlowsHelp(): string;
|
|
30
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../../../src/services/core/loginFlows/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3D,eAAO,MAAM,WAAW,EAAE,SAAS,cAAc,EAA6B,CAAC;AAE/E,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,IAAI,EAAE,MAAM;CAOzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,SAAS,CAMzE;AASD;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAa7C"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The list of generic browser login flows, and looking one up by the name
|
|
3
|
+
* `--login-flow` takes.
|
|
4
|
+
*
|
|
5
|
+
* This is the only module that knows which flows exist. What a flow *is* lives
|
|
6
|
+
* in `base`, which the flows themselves import; keeping the list separate is
|
|
7
|
+
* what stops that from being a cycle.
|
|
8
|
+
*/
|
|
9
|
+
import { CookieCaptureLoginFlow } from './cookieCapture.js';
|
|
10
|
+
export const LOGIN_FLOWS = [CookieCaptureLoginFlow];
|
|
11
|
+
export class UnknownLoginFlowError extends Error {
|
|
12
|
+
constructor(name) {
|
|
13
|
+
super(`Unknown login flow '${name}'. Available flows: ` +
|
|
14
|
+
`${LOGIN_FLOWS.map((flowClass) => flowClass.flowName).join(', ')}.`);
|
|
15
|
+
this.name = 'UnknownLoginFlowError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Look up a flow class by the name `--login-flow` takes, and configure it with
|
|
20
|
+
* the given parameters.
|
|
21
|
+
*
|
|
22
|
+
* Throws {@link UnknownLoginFlowError}, or `LoginFlowParamsInvalidError` from
|
|
23
|
+
* the flow's own validation; callers decide what an unusable flow means for
|
|
24
|
+
* them (the CLI rejects the registration, loading a stored service drops just
|
|
25
|
+
* the flow).
|
|
26
|
+
*/
|
|
27
|
+
export function resolveLoginFlow(name, params) {
|
|
28
|
+
const flowClass = LOGIN_FLOWS.find((candidate) => candidate.flowName === name);
|
|
29
|
+
if (flowClass === undefined) {
|
|
30
|
+
throw new UnknownLoginFlowError(name);
|
|
31
|
+
}
|
|
32
|
+
return new flowClass(params);
|
|
33
|
+
}
|
|
34
|
+
function indent(text, spaces) {
|
|
35
|
+
return text
|
|
36
|
+
.split('\n')
|
|
37
|
+
.map((line) => (line === '' ? '' : `${spaces}${line}`))
|
|
38
|
+
.join('\n');
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The reference documentation for every registered flow, for
|
|
42
|
+
* `latchkey services register --help`. Generated from the registry, so a flow
|
|
43
|
+
* added later documents itself without the CLI knowing anything about it.
|
|
44
|
+
*/
|
|
45
|
+
export function formatLoginFlowsHelp() {
|
|
46
|
+
const sections = LOGIN_FLOWS.map((flowClass) => ` ${flowClass.flowName}\n${indent(flowClass.summary, ' ')}\n\n` +
|
|
47
|
+
indent(flowClass.details, ' '));
|
|
48
|
+
return [
|
|
49
|
+
'Login flows:',
|
|
50
|
+
' Each login flow is configured by a JSON object supplied by',
|
|
51
|
+
' --login-flow-params.',
|
|
52
|
+
'',
|
|
53
|
+
...sections,
|
|
54
|
+
].join('\n');
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../../../src/services/core/loginFlows/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAG5D,MAAM,CAAC,MAAM,WAAW,GAA8B,CAAC,sBAAsB,CAAC,CAAC;AAE/E,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC9C,YAAY,IAAY;QACtB,KAAK,CACH,uBAAuB,IAAI,sBAAsB;YAC/C,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACtE,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,MAAe;IAC5D,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC;IAC/E,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,MAAM,CAAC,IAAY,EAAE,MAAc;IAC1C,OAAO,IAAI;SACR,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,IAAI,EAAE,CAAC,CAAC;SACtD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAC9B,CAAC,SAAS,EAAE,EAAE,CACZ,KAAK,SAAS,CAAC,QAAQ,KAAK,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM;QACnE,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CACpC,CAAC;IACF,OAAO;QACL,cAAc;QACd,8DAA8D;QAC9D,wBAAwB;QACxB,EAAE;QACF,GAAG,QAAQ;KACZ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|