slack-term 1.21.0 → 1.21.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.
- package/dist/cli.js +67 -58
- package/package.json +1 -1
- package/ts/auth.ts +23 -0
- package/ts/cli.ts +15 -0
- package/ts/slack-app.ts +27 -4
- package/ts/slack.ts +13 -0
package/package.json
CHANGED
package/ts/auth.ts
CHANGED
|
@@ -263,6 +263,29 @@ export async function cmdAuthChrome(opts: { workspace?: string } = {}): Promise<
|
|
|
263
263
|
}
|
|
264
264
|
}
|
|
265
265
|
|
|
266
|
+
// A Chrome xoxd session cookie only augments a desktop *user* session token (xoxc-); it has
|
|
267
|
+
// no effect on a bot token (xoxb-). Attaching it to a bot profile silently does nothing and
|
|
268
|
+
// user-level actions (tail @user, DMs, users.list) still fail with missing_scope /
|
|
269
|
+
// cannot_dm_bot. Stop early with a pointer to a user-token workspace instead.
|
|
270
|
+
const selected = profiles.find((p) => p.name === profileName)!;
|
|
271
|
+
if (selected.profile.token.startsWith("xoxb-")) {
|
|
272
|
+
console.error(
|
|
273
|
+
`\nWorkspace "${profileName}" uses a bot token (xoxb-). A Chrome session cookie only\n` +
|
|
274
|
+
`augments a user session token (xoxc-) — it has no effect on a bot token, so user-level\n` +
|
|
275
|
+
`actions (tail @user, DMs, listing users) would still fail.`,
|
|
276
|
+
);
|
|
277
|
+
const userProfiles = profiles.filter(
|
|
278
|
+
(p) => p.profile.token.startsWith("xoxc-") || p.profile.token.startsWith("xoxp-"),
|
|
279
|
+
);
|
|
280
|
+
if (userProfiles.length > 0) {
|
|
281
|
+
console.error(` Target a user-token workspace instead: ${userProfiles.map((p) => p.name).join(", ")}`);
|
|
282
|
+
console.error(` slack auth chrome -w ${userProfiles[0]!.name}`);
|
|
283
|
+
} else {
|
|
284
|
+
console.error(` Import your Slack desktop user session instead: slack workspace import`);
|
|
285
|
+
}
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
|
|
266
289
|
console.log("Scanning Chrome profiles for Slack session...");
|
|
267
290
|
console.log("macOS may show a dialog asking for your login password — click Allow.");
|
|
268
291
|
|
package/ts/cli.ts
CHANGED
|
@@ -1297,6 +1297,21 @@ async function main(): Promise<void> {
|
|
|
1297
1297
|
|
|
1298
1298
|
await yargs(hideBin(process.argv))
|
|
1299
1299
|
.scriptName("slack")
|
|
1300
|
+
// A thrown handler error (e.g. a Slack API failure) is a runtime error, not a usage
|
|
1301
|
+
// mistake — print just the clean one-line message, never the command's --help block or a
|
|
1302
|
+
// minified source stack. Reserve the usage/help output for actual argument-parse errors
|
|
1303
|
+
// (err is undefined then). showHelpOnFail(false) stops yargs' default help dump.
|
|
1304
|
+
.showHelpOnFail(false)
|
|
1305
|
+
.fail((msg, err, y) => {
|
|
1306
|
+
if (err) {
|
|
1307
|
+
console.error(err.message);
|
|
1308
|
+
process.exit(1);
|
|
1309
|
+
}
|
|
1310
|
+
console.error(msg);
|
|
1311
|
+
console.error("");
|
|
1312
|
+
y.showHelp();
|
|
1313
|
+
process.exit(1);
|
|
1314
|
+
})
|
|
1300
1315
|
.option("workspace", { alias: "w", type: "string", describe: "Workspace name" })
|
|
1301
1316
|
.middleware(async (argv) => {
|
|
1302
1317
|
const cmd = String((argv._ ?? [])[0] ?? "");
|
package/ts/slack-app.ts
CHANGED
|
@@ -271,16 +271,39 @@ export type ChromeCookieCandidate = {
|
|
|
271
271
|
cookie: string; // decrypted xoxd-...
|
|
272
272
|
};
|
|
273
273
|
|
|
274
|
-
/**
|
|
274
|
+
/**
|
|
275
|
+
* Read a human-friendly display name (nickname + email) for a Chrome profile so a bare
|
|
276
|
+
* "Default"/"Profile N" is never shown alone.
|
|
277
|
+
*
|
|
278
|
+
* Prefers Chrome's `Local State` → profile.info_cache, which reliably carries both the
|
|
279
|
+
* nickname (`name`) and account email (`user_name`); the per-profile Preferences file
|
|
280
|
+
* often has neither. Only nickname + email are surfaced — the gaia real name is never read.
|
|
281
|
+
*/
|
|
275
282
|
function chromeProfileName(userDataDir: string, profileDir: string): string {
|
|
283
|
+
const label = (name: string, email: string): string => {
|
|
284
|
+
if (name && email) return `${name} (${email})`;
|
|
285
|
+
return name || email || profileDir;
|
|
286
|
+
};
|
|
287
|
+
try {
|
|
288
|
+
const localState = JSON.parse(
|
|
289
|
+
readFileSync(join(userDataDir, "Local State"), "utf8"),
|
|
290
|
+
) as { profile?: { info_cache?: Record<string, { name?: string; user_name?: string }> } };
|
|
291
|
+
const info = localState.profile?.info_cache?.[profileDir];
|
|
292
|
+
if (info && (info.name || info.user_name)) {
|
|
293
|
+
return label(info.name ?? "", info.user_name ?? "");
|
|
294
|
+
}
|
|
295
|
+
} catch {
|
|
296
|
+
// fall through to Preferences
|
|
297
|
+
}
|
|
276
298
|
try {
|
|
277
299
|
const prefs = JSON.parse(
|
|
278
300
|
readFileSync(join(userDataDir, profileDir, "Preferences"), "utf8"),
|
|
279
301
|
) as Record<string, unknown>;
|
|
280
302
|
const profile = prefs.profile as Record<string, unknown> | undefined;
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
303
|
+
return label(
|
|
304
|
+
(profile?.name as string | undefined) ?? "",
|
|
305
|
+
(profile?.user_name as string | undefined) ?? "",
|
|
306
|
+
);
|
|
284
307
|
} catch {
|
|
285
308
|
return profileDir;
|
|
286
309
|
}
|
package/ts/slack.ts
CHANGED
|
@@ -47,6 +47,19 @@ async function call(token: string, method: string, init: RequestInit, cookie?: s
|
|
|
47
47
|
` slack workspace set-token <name> <xoxp-token>`,
|
|
48
48
|
);
|
|
49
49
|
}
|
|
50
|
+
// Bot tokens (xoxb-) can't act as a user: they lack user scopes (missing_scope) and can't
|
|
51
|
+
// open a DM with themselves (cannot_dm_bot, e.g. `tail @you`). Point at a user-token workspace.
|
|
52
|
+
if ((err === "missing_scope" || err === "cannot_dm_bot") && token.startsWith("xoxb-")) {
|
|
53
|
+
const why = err === "cannot_dm_bot"
|
|
54
|
+
? `you're authenticated as a bot, so "@you" is the bot itself and it can't DM itself`
|
|
55
|
+
: `this bot token lacks the user scope this action needs`;
|
|
56
|
+
throw new Error(
|
|
57
|
+
`Slack error on ${method}: ${err} — ${why}.\n` +
|
|
58
|
+
`Tailing/DMing people and listing users need a user session, not a bot token.\n` +
|
|
59
|
+
` Switch workspace: slack workspace ls then slack workspace use <name>\n` +
|
|
60
|
+
` Or import your Slack desktop session: slack workspace import`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
50
63
|
throw new Error(`Slack error on ${method}: ${err}`);
|
|
51
64
|
}
|
|
52
65
|
return body as Json;
|