latchkey 3.11.0 → 3.11.1

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.
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Slack service implementation.
3
3
  */
4
- import type { Response } from 'playwright';
4
+ import type { Page, Response } from 'playwright';
5
5
  import { z } from 'zod';
6
6
  import type { ApiCredentials } from '../apiCredentials/base.js';
7
- import { Service, SimpleServiceSession } from './core/base.js';
7
+ import { LoginFailedError, Service, SimpleServiceSession } from './core/base.js';
8
8
  /**
9
9
  * Slack-specific credentials (token + d cookie).
10
10
  */
@@ -32,9 +32,41 @@ export declare class SlackApiCredentials implements ApiCredentials {
32
32
  toJSON(): SlackApiCredentialsData;
33
33
  static fromJSON(data: SlackApiCredentialsData): SlackApiCredentials;
34
34
  }
35
+ /**
36
+ * Slack signed the user in but the browser has no `d` session cookie, which the
37
+ * API needs alongside the token. Observed after "Reject cookies" in Slack's
38
+ * cookie dialog.
39
+ */
40
+ export declare class SlackSessionCookieMissingError extends LoginFailedError {
41
+ constructor();
42
+ }
43
+ /**
44
+ * The Slack client loaded, so the user is signed in, but none of its responses
45
+ * carried a session token.
46
+ */
47
+ export declare class SlackTokenMissingError extends LoginFailedError {
48
+ constructor();
49
+ }
35
50
  declare class SlackServiceSession extends SimpleServiceSession {
36
- private pendingDCookie;
51
+ /** Token seen in a response that did not carry the `d` cookie. */
52
+ private pendingToken;
53
+ /** When the Slack client was first seen fully loaded, or null until then. */
54
+ private clientLoadedAt;
37
55
  protected getApiCredentialsFromResponse(response: Response): Promise<ApiCredentials | null>;
56
+ /**
57
+ * Notice a login that is stuck: Slack has signed the user in, yet the two
58
+ * things the credentials are made of have not both turned up.
59
+ *
60
+ * A token whose request did not carry the `d` cookie is paired with the
61
+ * cookie from the browser's jar. If the jar has none either, the login is
62
+ * given up on at once: the cookie is set at sign-in, before Slack serves
63
+ * anything containing a token, so it is not still coming.
64
+ *
65
+ * Without a token, the login is given up on once the client has finished
66
+ * loading and has then had ample time to make its own requests without any
67
+ * of them carrying one.
68
+ */
69
+ whileWaitingForLogin(page: Page): Promise<void>;
38
70
  }
39
71
  export declare class Slack extends Service {
40
72
  readonly name = "slack";
@@ -1 +1 @@
1
- {"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../../src/services/slack.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAG/D;;GAEG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;EAIpC,CAAC;AAEH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAEhF,qBAAa,mBAAoB,YAAW,cAAc;IACxD,QAAQ,CAAC,UAAU,EAAG,OAAO,CAAU;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEb,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAK1C,kBAAkB,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC;IAUhF,SAAS,IAAI,OAAO,GAAG,SAAS;IAIhC,MAAM,IAAI,uBAAuB;IAQjC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,uBAAuB,GAAG,mBAAmB;CAGpE;AAED,cAAM,mBAAoB,SAAQ,oBAAoB;IACpD,OAAO,CAAC,cAAc,CAAuB;cAE7B,6BAA6B,CAC3C,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CAmClC;AAED,qBAAa,KAAM,SAAQ,OAAO;IAChC,QAAQ,CAAC,IAAI,WAAW;IACxB,QAAQ,CAAC,WAAW,WAAW;IAC/B,QAAQ,CAAC,WAAW,kEAAmE;IACvF,QAAQ,CAAC,QAAQ,8BAA8B;IAC/C,QAAQ,CAAC,IAAI,SAEyD;IAEtE,QAAQ,CAAC,4BAA4B,+CAAgD;IAErF,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAIzC,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,mBAAmB;cAM5C,8BAA8B,CAC/C,eAAe,EAAE,MAAM,EACvB,YAAY,EAAE,MAAM,GACnB,OAAO;IAKD,UAAU,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAuB5E;AAED,eAAO,MAAM,KAAK,OAAc,CAAC"}
1
+ {"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../../src/services/slack.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAGjF;;GAEG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;EAIpC,CAAC;AAEH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAEhF,qBAAa,mBAAoB,YAAW,cAAc;IACxD,QAAQ,CAAC,UAAU,EAAG,OAAO,CAAU;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEb,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAK1C,kBAAkB,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC;IAUhF,SAAS,IAAI,OAAO,GAAG,SAAS;IAIhC,MAAM,IAAI,uBAAuB;IAQjC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,uBAAuB,GAAG,mBAAmB;CAGpE;AAwBD;;;;GAIG;AACH,qBAAa,8BAA+B,SAAQ,gBAAgB;;CAQnE;AAED;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,gBAAgB;;CAK3D;AA2BD,cAAM,mBAAoB,SAAQ,oBAAoB;IACpD,kEAAkE;IAClE,OAAO,CAAC,YAAY,CAAuB;IAE3C,6EAA6E;IAC7E,OAAO,CAAC,cAAc,CAAuB;cAE7B,6BAA6B,CAC3C,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IA2BjC;;;;;;;;;;;;OAYG;IACY,oBAAoB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CAwB/D;AAED,qBAAa,KAAM,SAAQ,OAAO;IAChC,QAAQ,CAAC,IAAI,WAAW;IACxB,QAAQ,CAAC,WAAW,WAAW;IAC/B,QAAQ,CAAC,WAAW,kEAAmE;IACvF,QAAQ,CAAC,QAAQ,8BAA8B;IAC/C,QAAQ,CAAC,IAAI,SAEyD;IAEtE,QAAQ,CAAC,4BAA4B,+CAAgD;IAErF,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAIzC,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,mBAAmB;cAM5C,8BAA8B,CAC/C,eAAe,EAAE,MAAM,EACvB,YAAY,EAAE,MAAM,GACnB,OAAO;IAKD,UAAU,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAuB5E;AAED,eAAO,MAAM,KAAK,OAAc,CAAC"}
@@ -2,7 +2,7 @@
2
2
  * Slack service implementation.
3
3
  */
4
4
  import { z } from 'zod';
5
- import { Service, SimpleServiceSession } from './core/base.js';
5
+ import { LoginFailedError, Service, SimpleServiceSession } from './core/base.js';
6
6
  import { fetchAccountFromEndpoint, tryParseJson } from '../apiCredentials/account.js';
7
7
  /**
8
8
  * Slack-specific credentials (token + d cookie).
@@ -43,38 +43,129 @@ export class SlackApiCredentials {
43
43
  return new SlackApiCredentials(data.token, data.dCookie);
44
44
  }
45
45
  }
46
+ /**
47
+ * Any host under slack.com. Enterprise Grid workspaces live two labels deep
48
+ * (`<workspace>.enterprise.slack.com`), so a single optional label is not enough.
49
+ */
50
+ const SLACK_URL_PATTERN = /^https:\/\/([a-z0-9-]+\.)*slack\.com\//;
51
+ /** Where the browser ends up once Slack considers the user signed in. */
52
+ const SLACK_CLIENT_URL_PATTERN = /^https:\/\/app\.slack\.com\/client(\/|$)/;
53
+ /** The session token, as embedded in the client's HTML or in raw JSON. */
54
+ const API_TOKEN_PATTERN = /"api_token":"(xoxc-[a-zA-Z0-9-]+)"/;
55
+ const D_COOKIE_HEADER_PATTERN = /\bd=([^;]+)/;
56
+ /**
57
+ * How long after the Slack client has finished loading a token is still waited
58
+ * for. The token may arrive in the client's HTML or in a request the client
59
+ * makes afterwards, so this is deliberately generous: it only delays the
60
+ * failure message, never a login that is going to succeed.
61
+ */
62
+ const TOKEN_SETTLE_PERIOD_MS = 5_000;
63
+ /**
64
+ * Slack signed the user in but the browser has no `d` session cookie, which the
65
+ * API needs alongside the token. Observed after "Reject cookies" in Slack's
66
+ * cookie dialog.
67
+ */
68
+ export class SlackSessionCookieMissingError extends LoginFailedError {
69
+ constructor() {
70
+ super('Login failed: The browser holds no "d" session cookie. ' +
71
+ "Maybe you rejected cookies in Slack's cookie dialog?");
72
+ this.name = 'SlackSessionCookieMissingError';
73
+ }
74
+ }
75
+ /**
76
+ * The Slack client loaded, so the user is signed in, but none of its responses
77
+ * carried a session token.
78
+ */
79
+ export class SlackTokenMissingError extends LoginFailedError {
80
+ constructor() {
81
+ super('Login failed: No session token was found.');
82
+ this.name = 'SlackTokenMissingError';
83
+ }
84
+ }
85
+ async function readDCookieFromJar(page) {
86
+ const cookies = await page.context().cookies();
87
+ const dCookie = cookies.find((cookie) => cookie.name === 'd' && /(^|\.)slack\.com$/.test(cookie.domain));
88
+ return dCookie?.value ?? null;
89
+ }
90
+ /**
91
+ * Whether the browser sits on a fully loaded Slack client. Loading counts
92
+ * subresources too, so on a slow connection this simply takes longer to become
93
+ * true. A page mid-navigation cannot be asked and counts as not loaded.
94
+ */
95
+ async function isSlackClientLoaded(page) {
96
+ if (!SLACK_CLIENT_URL_PATTERN.test(page.url())) {
97
+ return false;
98
+ }
99
+ try {
100
+ const readyState = await page.evaluate('document.readyState');
101
+ return readyState === 'complete';
102
+ }
103
+ catch {
104
+ return false;
105
+ }
106
+ }
46
107
  class SlackServiceSession extends SimpleServiceSession {
47
- pendingDCookie = null;
108
+ /** Token seen in a response that did not carry the `d` cookie. */
109
+ pendingToken = null;
110
+ /** When the Slack client was first seen fully loaded, or null until then. */
111
+ clientLoadedAt = null;
48
112
  async getApiCredentialsFromResponse(response) {
49
113
  const request = response.request();
50
- const url = request.url();
51
- // Check if the domain is under slack.com
52
- if (!/^https:\/\/([a-z0-9-]+\.)?slack\.com\//.test(url)) {
114
+ if (!SLACK_URL_PATTERN.test(request.url())) {
53
115
  return null;
54
116
  }
55
- const headers = await request.allHeaders();
56
- const cookieHeader = headers.cookie;
57
- if (cookieHeader === undefined) {
117
+ let responseBody;
118
+ try {
119
+ responseBody = await response.text();
120
+ }
121
+ catch {
122
+ // The body is no longer retrievable (a redirect, or a page that has
123
+ // navigated on); other responses get their chance.
58
124
  return null;
59
125
  }
60
- const cookieMatch = /\bd=([^;]+)/.exec(cookieHeader);
61
- if (!cookieMatch?.[1]) {
126
+ const token = API_TOKEN_PATTERN.exec(responseBody)?.[1];
127
+ if (token === undefined) {
62
128
  return null;
63
129
  }
64
- const dCookie = cookieMatch[1];
65
- this.pendingDCookie = dCookie;
66
- // Extract token from response body (JSON embedded in HTML or raw JSON)
67
- try {
68
- const responseBody = await response.text();
69
- const tokenMatch = /"api_token":"(xoxc-[a-zA-Z0-9-]+)"/.exec(responseBody);
70
- if (tokenMatch?.[1]) {
71
- return new SlackApiCredentials(tokenMatch[1], dCookie);
130
+ this.pendingToken = token;
131
+ const cookieHeader = (await request.allHeaders()).cookie;
132
+ const dCookie = cookieHeader === undefined ? undefined : D_COOKIE_HEADER_PATTERN.exec(cookieHeader)?.[1];
133
+ return dCookie === undefined ? null : new SlackApiCredentials(token, dCookie);
134
+ }
135
+ /**
136
+ * Notice a login that is stuck: Slack has signed the user in, yet the two
137
+ * things the credentials are made of have not both turned up.
138
+ *
139
+ * A token whose request did not carry the `d` cookie is paired with the
140
+ * cookie from the browser's jar. If the jar has none either, the login is
141
+ * given up on at once: the cookie is set at sign-in, before Slack serves
142
+ * anything containing a token, so it is not still coming.
143
+ *
144
+ * Without a token, the login is given up on once the client has finished
145
+ * loading and has then had ample time to make its own requests without any
146
+ * of them carrying one.
147
+ */
148
+ async whileWaitingForLogin(page) {
149
+ if (this.apiCredentials !== null) {
150
+ return;
151
+ }
152
+ if (this.pendingToken !== null) {
153
+ const dCookie = await readDCookieFromJar(page);
154
+ if (dCookie === null) {
155
+ throw new SlackSessionCookieMissingError();
72
156
  }
157
+ this.apiCredentials = new SlackApiCredentials(this.pendingToken, dCookie);
158
+ return;
73
159
  }
74
- catch {
75
- // Ignore errors reading response body
160
+ if (this.clientLoadedAt === null) {
161
+ if (await isSlackClientLoaded(page)) {
162
+ this.clientLoadedAt = Date.now();
163
+ }
164
+ return;
165
+ }
166
+ if (Date.now() - this.clientLoadedAt >= TOKEN_SETTLE_PERIOD_MS) {
167
+ throw new SlackTokenMissingError();
76
168
  }
77
- return null;
78
169
  }
79
170
  }
80
171
  export class Slack extends Service {
@@ -1 +1 @@
1
- {"version":3,"file":"slack.js","sourceRoot":"","sources":["../../../src/services/slack.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEtF;;GAEG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;CACpB,CAAC,CAAC;AAIH,MAAM,OAAO,mBAAmB;IACrB,UAAU,GAAG,OAAgB,CAAC;IAC9B,KAAK,CAAS;IACd,OAAO,CAAS;IAEzB,YAAY,KAAa,EAAE,OAAe;QACxC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,kBAAkB,CAAC,aAAgC;QACjD,OAAO,OAAO,CAAC,OAAO,CAAC;YACrB,IAAI;YACJ,yBAAyB,IAAI,CAAC,KAAK,EAAE;YACrC,IAAI;YACJ,aAAa,IAAI,CAAC,OAAO,EAAE;YAC3B,GAAG,aAAa;SACjB,CAAC,CAAC;IACL,CAAC;IAED,SAAS;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM;QACJ,OAAO;YACL,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,IAA6B;QAC3C,OAAO,IAAI,mBAAmB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3D,CAAC;CACF;AAED,MAAM,mBAAoB,SAAQ,oBAAoB;IAC5C,cAAc,GAAkB,IAAI,CAAC;IAEnC,KAAK,CAAC,6BAA6B,CAC3C,QAAkB;QAElB,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAE1B,yCAAyC;QACzC,IAAI,CAAC,wCAAwC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACxD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;QAC3C,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;QACpC,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACrD,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC;QAE9B,uEAAuE;QACvE,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC3C,MAAM,UAAU,GAAG,oCAAoC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC3E,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpB,OAAO,IAAI,mBAAmB,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,sCAAsC;QACxC,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED,MAAM,OAAO,KAAM,SAAQ,OAAO;IACvB,IAAI,GAAG,OAAO,CAAC;IACf,WAAW,GAAG,OAAO,CAAC;IACtB,WAAW,GAAG,CAAC,wBAAwB,EAAE,0BAA0B,CAAU,CAAC;IAC9E,QAAQ,GAAG,0BAA0B,CAAC;IACtC,IAAI,GACX,wCAAwC;QACxC,mEAAmE,CAAC;IAE7D,4BAA4B,GAAG,CAAC,iCAAiC,CAAU,CAAC;IAErF,qBAAqB,CAAC,WAAmB;QACvC,OAAO,qBAAqB,WAAW,6CAA6C,CAAC;IACvF,CAAC;IAEQ,UAAU,CAAC,aAAqB;QACvC,OAAO,IAAI,mBAAmB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IACtD,CAAC;IAED,0EAA0E;IAC1E,+DAA+D;IAC5C,8BAA8B,CAC/C,eAAuB,EACvB,YAAoB;QAEpB,MAAM,IAAI,GAAG,YAAY,CAAC,YAAY,CAA4B,CAAC;QACnE,OAAO,IAAI,EAAE,EAAE,KAAK,IAAI,CAAC;IAC3B,CAAC;IAEQ,UAAU,CAAC,cAA8B;QAChD,OAAO,wBAAwB,CAC7B,cAAc,EACd,IAAI,CAAC,4BAA4B,EACjC,CAAC,YAAY,EAAE,EAAE;YACf,MAAM,IAAI,GAAG,YAAY,CAAC,YAAY,CAI9B,CAAC;YACT,IAAI,IAAI,EAAE,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC7B,OAAO,IAAI,CAAC;YACd,CAAC;YACD,uEAAuE;YACvE,yEAAyE;YACzE,yCAAyC;YACzC,MAAM,cAAc,GAClB,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACzE,MAAM,SAAS,GAAG,cAAc,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC;YACnD,OAAO,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,SAAS,EAAE,CAAC;QAC3E,CAAC,CACF,CAAC;IACJ,CAAC;CACF;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"slack.js","sourceRoot":"","sources":["../../../src/services/slack.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "3.11.0";
1
+ export declare const VERSION = "3.11.1";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,4 +1,4 @@
1
1
  // Auto-generated from package.json by scripts/generateVersion.js.
2
2
  // Do not edit by hand; run `node scripts/generateVersion.js` to refresh.
3
- export const VERSION = "3.11.0";
3
+ export const VERSION = "3.11.1";
4
4
  //# sourceMappingURL=version.js.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Tests for the Slack browser login, with responses and the browser's state fed
3
+ * in by hand instead of by a browser.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=slack.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack.test.d.ts","sourceRoot":"","sources":["../../tests/slack.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Tests for the Slack browser login, with responses and the browser's state fed
3
+ * in by hand instead of by a browser.
4
+ */
5
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
6
+ import { SLACK, SlackApiCredentials, SlackSessionCookieMissingError, SlackTokenMissingError, } from '../src/services/slack.js';
7
+ const CLIENT_URL = 'https://app.slack.com/client/T123/C456';
8
+ const SIGNIN_URL = 'https://slack.com/signin';
9
+ const CLIENT_BODY_WITH_TOKEN = '<html><script>{"api_token":"xoxc-123-abc","x":1}</script></html>';
10
+ const START_TIME = new Date('2026-01-01T00:00:00Z').getTime();
11
+ // Comfortably past the settle period, whatever it is set to.
12
+ const WELL_PAST_THE_SETTLE_PERIOD_MS = 60_000;
13
+ function responseWith(params) {
14
+ const headers = params.cookieHeader === undefined ? {} : { cookie: params.cookieHeader };
15
+ return {
16
+ request: () => ({
17
+ url: () => params.url ?? CLIENT_URL,
18
+ allHeaders: () => Promise.resolve(headers),
19
+ }),
20
+ text: () => Promise.resolve(params.body ?? CLIENT_BODY_WITH_TOKEN),
21
+ };
22
+ }
23
+ /**
24
+ * A browser parked at `pageUrl` whose jar holds the given cookies, with the page
25
+ * either fully loaded or still loading.
26
+ */
27
+ function pageAt(pageUrl, params = {}) {
28
+ return {
29
+ url: () => pageUrl,
30
+ context: () => ({ cookies: () => Promise.resolve(params.cookies ?? []) }),
31
+ evaluate: (expression) => {
32
+ if (expression !== 'document.readyState') {
33
+ throw new TypeError(`unexpected evaluation: ${expression}`);
34
+ }
35
+ return Promise.resolve(params.readyState ?? 'complete');
36
+ },
37
+ };
38
+ }
39
+ function startLogin() {
40
+ return SLACK.getSession('latchkey');
41
+ }
42
+ function capturedOf(session) {
43
+ const credentials = session.capturedCredentials;
44
+ if (credentials === null) {
45
+ return null;
46
+ }
47
+ if (!(credentials instanceof SlackApiCredentials)) {
48
+ throw new TypeError('the Slack session should capture Slack credentials');
49
+ }
50
+ return { token: credentials.token, dCookie: credentials.dCookie };
51
+ }
52
+ describe('slack login from responses', () => {
53
+ it('captures the token and the d cookie from one response', async () => {
54
+ const session = startLogin();
55
+ await session.onResponse(responseWith({ cookieHeader: 'b=1; d=the-d-cookie; x=2' }));
56
+ expect(capturedOf(session)).toEqual({ token: 'xoxc-123-abc', dCookie: 'the-d-cookie' });
57
+ });
58
+ // Enterprise Grid workspaces sit two labels deep, behind an SSO callback.
59
+ it('captures from an Enterprise Grid workspace host', async () => {
60
+ const session = startLogin();
61
+ await session.onResponse(responseWith({
62
+ url: 'https://canva.enterprise.slack.com/api/client.boot',
63
+ cookieHeader: 'd=enterprise-cookie',
64
+ }));
65
+ expect(capturedOf(session)).toEqual({ token: 'xoxc-123-abc', dCookie: 'enterprise-cookie' });
66
+ });
67
+ it('ignores responses from outside slack.com', async () => {
68
+ const session = startLogin();
69
+ await session.onResponse(responseWith({ url: 'https://evil.example.com/slack.com/', cookieHeader: 'd=nope' }));
70
+ await session.onResponse(responseWith({ url: 'https://notslack.com/client', cookieHeader: 'd=nope' }));
71
+ expect(capturedOf(session)).toBeNull();
72
+ });
73
+ it('is not complete while responses carry no token', async () => {
74
+ const session = startLogin();
75
+ await session.onResponse(responseWith({ body: '<html>signin</html>', cookieHeader: 'd=c' }));
76
+ expect(capturedOf(session)).toBeNull();
77
+ });
78
+ it('is not complete from a token whose request carried no d cookie', async () => {
79
+ const session = startLogin();
80
+ await session.onResponse(responseWith({ cookieHeader: 'other=1' }));
81
+ await session.onResponse(responseWith({}));
82
+ expect(capturedOf(session)).toBeNull();
83
+ });
84
+ });
85
+ describe('slack login that is stuck', () => {
86
+ beforeEach(() => {
87
+ vi.useFakeTimers();
88
+ vi.setSystemTime(START_TIME);
89
+ });
90
+ afterEach(() => {
91
+ vi.useRealTimers();
92
+ });
93
+ it('does nothing while the user is still signing in', async () => {
94
+ const session = startLogin();
95
+ await session.whileWaitingForLogin(pageAt(SIGNIN_URL));
96
+ vi.setSystemTime(START_TIME + WELL_PAST_THE_SETTLE_PERIOD_MS);
97
+ await session.whileWaitingForLogin(pageAt(SIGNIN_URL));
98
+ expect(capturedOf(session)).toBeNull();
99
+ });
100
+ // The request may not have carried the cookie, but the browser may well have it.
101
+ it('takes the d cookie from the browser when the request did not carry it', async () => {
102
+ const session = startLogin();
103
+ await session.onResponse(responseWith({}));
104
+ await session.whileWaitingForLogin(pageAt(CLIENT_URL, {
105
+ cookies: [
106
+ { name: 'd', value: 'from-the-jar', domain: '.slack.com' },
107
+ { name: 'd', value: 'unrelated', domain: 'example.com' },
108
+ ],
109
+ }));
110
+ expect(capturedOf(session)).toEqual({ token: 'xoxc-123-abc', dCookie: 'from-the-jar' });
111
+ });
112
+ // The cookie is set at sign-in, before anything carrying a token is served, so
113
+ // a token without it is conclusive and nothing is gained by waiting.
114
+ it('gives up at once on a token without a d cookie anywhere', async () => {
115
+ const session = startLogin();
116
+ await session.onResponse(responseWith({}));
117
+ await expect(session.whileWaitingForLogin(pageAt(CLIENT_URL, {
118
+ cookies: [{ name: 'd', value: 'unrelated', domain: 'example.com' }],
119
+ readyState: 'loading',
120
+ }))).rejects.toBeInstanceOf(SlackSessionCookieMissingError);
121
+ });
122
+ it('keeps waiting for a token while the Slack client is loading', async () => {
123
+ const session = startLogin();
124
+ const loadingClient = pageAt(CLIENT_URL, { readyState: 'loading' });
125
+ await session.whileWaitingForLogin(loadingClient);
126
+ vi.setSystemTime(START_TIME + WELL_PAST_THE_SETTLE_PERIOD_MS);
127
+ await expect(session.whileWaitingForLogin(loadingClient)).resolves.toBeUndefined();
128
+ });
129
+ it('keeps waiting for a token briefly after the Slack client has loaded', async () => {
130
+ const session = startLogin();
131
+ await session.whileWaitingForLogin(pageAt(CLIENT_URL));
132
+ vi.setSystemTime(START_TIME + 100);
133
+ await expect(session.whileWaitingForLogin(pageAt(CLIENT_URL))).resolves.toBeUndefined();
134
+ });
135
+ it('gives up on a loaded Slack client that yielded no token', async () => {
136
+ const session = startLogin();
137
+ await session.whileWaitingForLogin(pageAt(CLIENT_URL));
138
+ vi.setSystemTime(START_TIME + WELL_PAST_THE_SETTLE_PERIOD_MS);
139
+ await expect(session.whileWaitingForLogin(pageAt(CLIENT_URL))).rejects.toBeInstanceOf(SlackTokenMissingError);
140
+ });
141
+ // A token that arrives during the settle period completes the login as usual.
142
+ it('completes from a token arriving after the client has loaded', async () => {
143
+ const session = startLogin();
144
+ await session.whileWaitingForLogin(pageAt(CLIENT_URL));
145
+ await session.onResponse(responseWith({ cookieHeader: 'd=late-but-fine' }));
146
+ vi.setSystemTime(START_TIME + WELL_PAST_THE_SETTLE_PERIOD_MS);
147
+ await expect(session.whileWaitingForLogin(pageAt(CLIENT_URL))).resolves.toBeUndefined();
148
+ expect(capturedOf(session)).toEqual({ token: 'xoxc-123-abc', dCookie: 'late-but-fine' });
149
+ });
150
+ it('leaves credentials already captured alone', async () => {
151
+ const session = startLogin();
152
+ await session.onResponse(responseWith({ cookieHeader: 'd=from-response' }));
153
+ await session.whileWaitingForLogin(pageAt(CLIENT_URL, {
154
+ cookies: [{ name: 'd', value: 'from-the-jar', domain: '.slack.com' }],
155
+ }));
156
+ expect(capturedOf(session)).toEqual({ token: 'xoxc-123-abc', dCookie: 'from-response' });
157
+ });
158
+ });
159
+ //# sourceMappingURL=slack.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack.test.js","sourceRoot":"","sources":["../../tests/slack.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "latchkey",
3
- "version": "3.11.0",
3
+ "version": "3.11.1",
4
4
  "description": "A CLI tool that injects API credentials into curl requests to third-party services",
5
5
  "author": "Imbue <hynek@imbue.com>",
6
6
  "repository": {
@@ -81,5 +81,8 @@
81
81
  "./dist/skills/generic"
82
82
  ],
83
83
  "video": "https://github.com/imbue-ai/latchkey/releases/download/2.5.4/demo.mp4"
84
+ },
85
+ "allowScripts": {
86
+ "esbuild@0.28.2": true
84
87
  }
85
88
  }