agent-messenger 2.10.2 → 2.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.
- package/.claude-plugin/plugin.json +1 -1
- package/.env.template +4 -1
- package/README.md +77 -27
- package/bun.lock +26 -0
- package/dist/package.json +21 -1
- package/dist/src/platforms/channeltalk/commands/auth.d.ts +2 -1
- package/dist/src/platforms/channeltalk/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/commands/auth.js +5 -3
- package/dist/src/platforms/channeltalk/commands/auth.js.map +1 -1
- package/dist/src/platforms/channeltalk/token-extractor.d.ts +2 -1
- package/dist/src/platforms/channeltalk/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/token-extractor.js +22 -6
- package/dist/src/platforms/channeltalk/token-extractor.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/cli.js +11 -1
- package/dist/src/platforms/channeltalkbot/cli.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/auth.js +1 -5
- package/dist/src/platforms/channeltalkbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/bot.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/bot.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/bot.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/chat.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/chat.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/chat.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/group.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/group.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/group.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/manager.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/manager.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/manager.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/message.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/message.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/whoami.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/credential-manager.d.ts +5 -0
- package/dist/src/platforms/channeltalkbot/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/credential-manager.js +34 -4
- package/dist/src/platforms/channeltalkbot/credential-manager.js.map +1 -1
- package/dist/src/platforms/discord/commands/auth.d.ts +1 -0
- package/dist/src/platforms/discord/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/auth.js +3 -1
- package/dist/src/platforms/discord/commands/auth.js.map +1 -1
- package/dist/src/platforms/discord/listener.d.ts +2 -0
- package/dist/src/platforms/discord/listener.d.ts.map +1 -1
- package/dist/src/platforms/discord/listener.js +51 -21
- package/dist/src/platforms/discord/listener.js.map +1 -1
- package/dist/src/platforms/discord/token-extractor.d.ts +2 -1
- package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/discord/token-extractor.js +21 -6
- package/dist/src/platforms/discord/token-extractor.js.map +1 -1
- package/dist/src/platforms/discordbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/cli.js +12 -1
- package/dist/src/platforms/discordbot/cli.js.map +1 -1
- package/dist/src/platforms/discordbot/client.d.ts +3 -0
- package/dist/src/platforms/discordbot/client.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/client.js +3 -0
- package/dist/src/platforms/discordbot/client.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/auth.js +1 -5
- package/dist/src/platforms/discordbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/message.js +1 -6
- package/dist/src/platforms/discordbot/commands/message.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/server.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/server.js +1 -4
- package/dist/src/platforms/discordbot/commands/server.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/whoami.js +1 -6
- package/dist/src/platforms/discordbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/discordbot/index.d.ts +3 -1
- package/dist/src/platforms/discordbot/index.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/index.js +2 -1
- package/dist/src/platforms/discordbot/index.js.map +1 -1
- package/dist/src/platforms/discordbot/listener.d.ts +43 -0
- package/dist/src/platforms/discordbot/listener.d.ts.map +1 -0
- package/dist/src/platforms/discordbot/listener.js +292 -0
- package/dist/src/platforms/discordbot/listener.js.map +1 -0
- package/dist/src/platforms/discordbot/types.d.ts +161 -0
- package/dist/src/platforms/discordbot/types.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/types.js +34 -0
- package/dist/src/platforms/discordbot/types.js.map +1 -1
- package/dist/src/platforms/instagram/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/instagram/commands/auth.js +3 -1
- package/dist/src/platforms/instagram/commands/auth.js.map +1 -1
- package/dist/src/platforms/instagram/token-extractor.d.ts +2 -1
- package/dist/src/platforms/instagram/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/instagram/token-extractor.js +11 -2
- package/dist/src/platforms/instagram/token-extractor.js.map +1 -1
- package/dist/src/platforms/slack/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/auth.js +4 -2
- package/dist/src/platforms/slack/commands/auth.js.map +1 -1
- package/dist/src/platforms/slack/token-extractor.d.ts +4 -1
- package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/slack/token-extractor.js +64 -15
- package/dist/src/platforms/slack/token-extractor.js.map +1 -1
- package/dist/src/platforms/slackbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/cli.js +15 -3
- package/dist/src/platforms/slackbot/cli.js.map +1 -1
- package/dist/src/platforms/slackbot/client.d.ts +22 -1
- package/dist/src/platforms/slackbot/client.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/client.js +104 -1
- package/dist/src/platforms/slackbot/client.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/auth.js +1 -5
- package/dist/src/platforms/slackbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/file.d.ts +3 -0
- package/dist/src/platforms/slackbot/commands/file.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/commands/file.js +164 -0
- package/dist/src/platforms/slackbot/commands/file.js.map +1 -0
- package/dist/src/platforms/slackbot/commands/index.d.ts +1 -0
- package/dist/src/platforms/slackbot/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/index.js +1 -0
- package/dist/src/platforms/slackbot/commands/index.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/message.js +19 -0
- package/dist/src/platforms/slackbot/commands/message.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/whoami.js +1 -6
- package/dist/src/platforms/slackbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/slackbot/credential-manager.d.ts +1 -0
- package/dist/src/platforms/slackbot/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/credential-manager.js +30 -2
- package/dist/src/platforms/slackbot/credential-manager.js.map +1 -1
- package/dist/src/platforms/slackbot/index.d.ts +4 -1
- package/dist/src/platforms/slackbot/index.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/index.js +1 -0
- package/dist/src/platforms/slackbot/index.js.map +1 -1
- package/dist/src/platforms/slackbot/listener.d.ts +44 -0
- package/dist/src/platforms/slackbot/listener.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/listener.js +313 -0
- package/dist/src/platforms/slackbot/listener.js.map +1 -0
- package/dist/src/platforms/slackbot/types.d.ts +196 -1
- package/dist/src/platforms/slackbot/types.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/types.js +4 -1
- package/dist/src/platforms/slackbot/types.js.map +1 -1
- package/dist/src/platforms/teams/commands/auth.d.ts +1 -0
- package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/auth.js +37 -6
- package/dist/src/platforms/teams/commands/auth.js.map +1 -1
- package/dist/src/platforms/teams/ensure-auth.js +31 -9
- package/dist/src/platforms/teams/ensure-auth.js.map +1 -1
- package/dist/src/platforms/teams/token-extractor.d.ts +4 -1
- package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/teams/token-extractor.js +71 -29
- package/dist/src/platforms/teams/token-extractor.js.map +1 -1
- package/dist/src/platforms/webex/commands/auth.d.ts +1 -0
- package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/auth.js +3 -1
- package/dist/src/platforms/webex/commands/auth.js.map +1 -1
- package/dist/src/platforms/webex/token-extractor.d.ts +3 -1
- package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/webex/token-extractor.js +16 -2
- package/dist/src/platforms/webex/token-extractor.js.map +1 -1
- package/dist/src/platforms/wechatbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/cli.js +11 -1
- package/dist/src/platforms/wechatbot/cli.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/auth.js +1 -5
- package/dist/src/platforms/wechatbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/message.js +1 -6
- package/dist/src/platforms/wechatbot/commands/message.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/template.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/template.js +1 -6
- package/dist/src/platforms/wechatbot/commands/template.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/user.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/user.js +1 -6
- package/dist/src/platforms/wechatbot/commands/user.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/whoami.js +1 -6
- package/dist/src/platforms/wechatbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/whatsappbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/cli.js +11 -1
- package/dist/src/platforms/whatsappbot/cli.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/auth.js +1 -5
- package/dist/src/platforms/whatsappbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/message.js +1 -6
- package/dist/src/platforms/whatsappbot/commands/message.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/template.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/template.js +1 -6
- package/dist/src/platforms/whatsappbot/commands/template.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/whoami.js +1 -6
- package/dist/src/platforms/whatsappbot/commands/whoami.js.map +1 -1
- package/dist/src/shared/chromium/browsers.d.ts +8 -0
- package/dist/src/shared/chromium/browsers.d.ts.map +1 -1
- package/dist/src/shared/chromium/browsers.js +58 -3
- package/dist/src/shared/chromium/browsers.js.map +1 -1
- package/dist/src/shared/chromium/cli-options.d.ts +5 -0
- package/dist/src/shared/chromium/cli-options.d.ts.map +1 -0
- package/dist/src/shared/chromium/cli-options.js +8 -0
- package/dist/src/shared/chromium/cli-options.js.map +1 -0
- package/dist/src/shared/chromium/index.d.ts +3 -1
- package/dist/src/shared/chromium/index.d.ts.map +1 -1
- package/dist/src/shared/chromium/index.js +2 -1
- package/dist/src/shared/chromium/index.js.map +1 -1
- package/dist/src/shared/utils/cli-output.d.ts +7 -0
- package/dist/src/shared/utils/cli-output.d.ts.map +1 -0
- package/dist/src/shared/utils/cli-output.js +7 -0
- package/dist/src/shared/utils/cli-output.js.map +1 -0
- package/dist/src/tui/app.d.ts.map +1 -1
- package/dist/src/tui/app.js +73 -20
- package/dist/src/tui/app.js.map +1 -1
- package/docs/content/docs/cli/channeltalk.mdx +4 -0
- package/docs/content/docs/cli/discord.mdx +5 -0
- package/docs/content/docs/cli/instagram.mdx +3 -0
- package/docs/content/docs/cli/slack.mdx +5 -0
- package/docs/content/docs/cli/slackbot.mdx +60 -22
- package/docs/content/docs/cli/teams.mdx +5 -0
- package/docs/content/docs/cli/webex.mdx +3 -0
- package/docs/content/docs/sdk/channeltalkbot.mdx +38 -1
- package/docs/content/docs/sdk/discordbot.mdx +501 -0
- package/docs/content/docs/sdk/meta.json +2 -0
- package/docs/content/docs/sdk/slackbot.mdx +576 -0
- package/e2e/README.md +1 -1
- package/e2e/config.ts +9 -4
- package/examples/discordbot-listen.ts +65 -0
- package/examples/slackbot-listen.ts +65 -0
- package/package.json +21 -1
- package/skills/agent-channeltalk/SKILL.md +5 -1
- package/skills/agent-channeltalk/references/authentication.md +5 -1
- package/skills/agent-channeltalkbot/SKILL.md +17 -3
- package/skills/agent-channeltalkbot/references/authentication.md +7 -5
- package/skills/agent-discord/SKILL.md +5 -1
- package/skills/agent-discord/references/authentication.md +7 -1
- package/skills/agent-discordbot/SKILL.md +13 -2
- package/skills/agent-discordbot/references/common-patterns.md +1 -1
- package/skills/agent-instagram/SKILL.md +7 -1
- package/skills/agent-instagram/references/authentication.md +6 -0
- package/skills/agent-kakaotalk/SKILL.md +1 -1
- package/skills/agent-line/SKILL.md +1 -1
- package/skills/agent-slack/SKILL.md +5 -1
- package/skills/agent-slack/references/authentication.md +7 -1
- package/skills/agent-slackbot/SKILL.md +56 -4
- package/skills/agent-slackbot/references/authentication.md +4 -0
- package/skills/agent-teams/SKILL.md +5 -1
- package/skills/agent-teams/references/authentication.md +7 -1
- package/skills/agent-telegram/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +7 -1
- package/skills/agent-webex/references/authentication.md +6 -0
- package/skills/agent-wechatbot/SKILL.md +16 -1
- package/skills/agent-wechatbot/references/authentication.md +219 -0
- package/skills/agent-wechatbot/references/common-patterns.md +358 -0
- package/skills/agent-wechatbot/templates/account-summary.sh +122 -0
- package/skills/agent-wechatbot/templates/post-message.sh +122 -0
- package/skills/agent-wechatbot/templates/send-template.sh +152 -0
- package/skills/agent-whatsapp/SKILL.md +1 -1
- package/skills/agent-whatsappbot/SKILL.md +30 -1
- package/src/platforms/channeltalk/commands/auth.test.ts +15 -3
- package/src/platforms/channeltalk/commands/auth.ts +15 -5
- package/src/platforms/channeltalk/token-extractor.ts +24 -5
- package/src/platforms/channeltalkbot/cli.ts +9 -0
- package/src/platforms/channeltalkbot/commands/auth.ts +1 -5
- package/src/platforms/channeltalkbot/commands/bot.ts +1 -6
- package/src/platforms/channeltalkbot/commands/chat.ts +1 -6
- package/src/platforms/channeltalkbot/commands/group.ts +1 -6
- package/src/platforms/channeltalkbot/commands/manager.ts +1 -6
- package/src/platforms/channeltalkbot/commands/message.ts +1 -6
- package/src/platforms/channeltalkbot/commands/whoami.test.ts +2 -0
- package/src/platforms/channeltalkbot/commands/whoami.ts +1 -6
- package/src/platforms/channeltalkbot/credential-manager.test.ts +96 -2
- package/src/platforms/channeltalkbot/credential-manager.ts +37 -4
- package/src/platforms/discord/commands/auth.ts +13 -2
- package/src/platforms/discord/listener.test.ts +59 -1
- package/src/platforms/discord/listener.ts +43 -19
- package/src/platforms/discord/token-extractor.ts +30 -6
- package/src/platforms/discordbot/cli.ts +10 -0
- package/src/platforms/discordbot/client.ts +4 -0
- package/src/platforms/discordbot/commands/auth.ts +1 -5
- package/src/platforms/discordbot/commands/message.ts +1 -6
- package/src/platforms/discordbot/commands/server.ts +1 -5
- package/src/platforms/discordbot/commands/whoami.ts +1 -6
- package/src/platforms/discordbot/index.test.ts +82 -0
- package/src/platforms/discordbot/index.ts +27 -9
- package/src/platforms/discordbot/listener.test.ts +1002 -0
- package/src/platforms/discordbot/listener.ts +321 -0
- package/src/platforms/discordbot/types.ts +163 -0
- package/src/platforms/instagram/commands/auth.ts +9 -1
- package/src/platforms/instagram/token-extractor.ts +13 -1
- package/src/platforms/slack/commands/auth.ts +11 -2
- package/src/platforms/slack/token-extractor.test.ts +96 -0
- package/src/platforms/slack/token-extractor.ts +76 -13
- package/src/platforms/slackbot/cli.ts +13 -1
- package/src/platforms/slackbot/client.test.ts +274 -0
- package/src/platforms/slackbot/client.ts +130 -2
- package/src/platforms/slackbot/commands/auth.ts +1 -5
- package/src/platforms/slackbot/commands/file.test.ts +201 -0
- package/src/platforms/slackbot/commands/file.ts +212 -0
- package/src/platforms/slackbot/commands/index.ts +1 -0
- package/src/platforms/slackbot/commands/message.ts +22 -0
- package/src/platforms/slackbot/commands/whoami.ts +1 -6
- package/src/platforms/slackbot/credential-manager.test.ts +62 -2
- package/src/platforms/slackbot/credential-manager.ts +32 -2
- package/src/platforms/slackbot/index.test.ts +59 -0
- package/src/platforms/slackbot/index.ts +31 -7
- package/src/platforms/slackbot/listener.test.ts +1012 -0
- package/src/platforms/slackbot/listener.ts +362 -0
- package/src/platforms/slackbot/types.ts +224 -1
- package/src/platforms/teams/commands/auth.test.ts +1 -1
- package/src/platforms/teams/commands/auth.ts +66 -7
- package/src/platforms/teams/ensure-auth.test.ts +56 -5
- package/src/platforms/teams/ensure-auth.ts +39 -11
- package/src/platforms/teams/token-extractor.test.ts +146 -24
- package/src/platforms/teams/token-extractor.ts +87 -29
- package/src/platforms/webex/commands/auth.ts +13 -2
- package/src/platforms/webex/token-extractor.ts +25 -3
- package/src/platforms/wechatbot/cli.ts +9 -0
- package/src/platforms/wechatbot/commands/auth.ts +1 -5
- package/src/platforms/wechatbot/commands/message.ts +1 -6
- package/src/platforms/wechatbot/commands/template.ts +1 -6
- package/src/platforms/wechatbot/commands/user.ts +1 -6
- package/src/platforms/wechatbot/commands/whoami.ts +1 -6
- package/src/platforms/whatsappbot/cli.ts +9 -0
- package/src/platforms/whatsappbot/commands/auth.ts +1 -5
- package/src/platforms/whatsappbot/commands/message.ts +1 -6
- package/src/platforms/whatsappbot/commands/template.ts +1 -6
- package/src/platforms/whatsappbot/commands/whoami.ts +1 -6
- package/src/shared/chromium/browsers.test.ts +80 -0
- package/src/shared/chromium/browsers.ts +72 -3
- package/src/shared/chromium/cli-options.test.ts +22 -0
- package/src/shared/chromium/cli-options.ts +12 -0
- package/src/shared/chromium/index.ts +3 -0
- package/src/shared/utils/cli-output.test.ts +57 -0
- package/src/shared/utils/cli-output.ts +8 -0
- package/src/tui/app.ts +129 -20
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
2
|
|
|
3
|
+
import { collectBrowserProfileOption } from '@/shared/chromium'
|
|
3
4
|
import { handleError } from '@/shared/utils/error-handler'
|
|
4
5
|
import { formatOutput } from '@/shared/utils/output'
|
|
5
6
|
import { debug } from '@/shared/utils/stderr'
|
|
@@ -9,7 +10,46 @@ import { TeamsCredentialManager } from '../credential-manager'
|
|
|
9
10
|
import { TeamsTokenExtractor } from '../token-extractor'
|
|
10
11
|
import type { TeamsAccount, TeamsAccountType, TeamsConfig } from '../types'
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
interface ValidatedTeamsToken {
|
|
14
|
+
client: TeamsClient
|
|
15
|
+
accountType: TeamsAccountType
|
|
16
|
+
authInfo: { id: string; displayName: string }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function validateTokenWithProbe(
|
|
20
|
+
token: string,
|
|
21
|
+
accountType: TeamsAccountType,
|
|
22
|
+
accountTypeKnown: boolean,
|
|
23
|
+
debugLog?: (msg: string) => void,
|
|
24
|
+
): Promise<ValidatedTeamsToken> {
|
|
25
|
+
const primaryTypes: TeamsAccountType[] = [accountType]
|
|
26
|
+
if (!accountTypeKnown) {
|
|
27
|
+
primaryTypes.push(accountType === 'work' ? 'personal' : 'work')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let lastError: Error | null = null
|
|
31
|
+
for (const candidateType of primaryTypes) {
|
|
32
|
+
try {
|
|
33
|
+
const client = await new TeamsClient().login({ token, accountType: candidateType })
|
|
34
|
+
const authInfo = await client.testAuth()
|
|
35
|
+
if (candidateType !== accountType) {
|
|
36
|
+
debugLog?.(`[debug] Reclassified ${accountType} → ${candidateType} via API probe`)
|
|
37
|
+
}
|
|
38
|
+
return { client, accountType: candidateType, authInfo }
|
|
39
|
+
} catch (error) {
|
|
40
|
+
lastError = error as Error
|
|
41
|
+
debugLog?.(`[debug] Probe ${candidateType} failed: ${lastError.message}`)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
throw lastError ?? new Error('Token validation failed')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function extractAction(options: {
|
|
48
|
+
pretty?: boolean
|
|
49
|
+
debug?: boolean
|
|
50
|
+
token?: string
|
|
51
|
+
browserProfile?: string[]
|
|
52
|
+
}): Promise<void> {
|
|
13
53
|
try {
|
|
14
54
|
if (options.token) {
|
|
15
55
|
await extractManualToken(options.token, options)
|
|
@@ -17,7 +57,7 @@ export async function extractAction(options: { pretty?: boolean; debug?: boolean
|
|
|
17
57
|
}
|
|
18
58
|
|
|
19
59
|
const debugLog = options.debug ? (msg: string) => debug(`[debug] ${msg}`) : undefined
|
|
20
|
-
const extractor = new TeamsTokenExtractor(undefined, undefined, debugLog)
|
|
60
|
+
const extractor = new TeamsTokenExtractor(undefined, undefined, debugLog, options.browserProfile)
|
|
21
61
|
|
|
22
62
|
if (process.platform === 'darwin') {
|
|
23
63
|
console.log('')
|
|
@@ -67,20 +107,33 @@ export async function extractAction(options: { pretty?: boolean; debug?: boolean
|
|
|
67
107
|
teams: string[]
|
|
68
108
|
}> = []
|
|
69
109
|
|
|
70
|
-
for (const { token, accountType } of extracted) {
|
|
110
|
+
for (const { token, accountType: extractedType, accountTypeKnown } of extracted) {
|
|
71
111
|
if (options.debug) {
|
|
72
|
-
|
|
112
|
+
const label = accountTypeKnown ? extractedType : `${extractedType} (probing)`
|
|
113
|
+
debug(`[debug] Validating ${label} account token...`)
|
|
73
114
|
}
|
|
74
115
|
|
|
75
116
|
try {
|
|
76
|
-
const
|
|
77
|
-
const authInfo = await
|
|
117
|
+
const debugLog = options.debug ? (msg: string) => debug(msg) : undefined
|
|
118
|
+
const { client, accountType, authInfo } = await validateTokenWithProbe(
|
|
119
|
+
token,
|
|
120
|
+
extractedType,
|
|
121
|
+
accountTypeKnown,
|
|
122
|
+
debugLog,
|
|
123
|
+
)
|
|
78
124
|
const teams = await client.listTeams()
|
|
79
125
|
|
|
80
126
|
if (options.debug) {
|
|
81
127
|
debug(`[debug] ✓ ${accountType}: ${authInfo.displayName} (${teams.length} team(s))`)
|
|
82
128
|
}
|
|
83
129
|
|
|
130
|
+
if (config.accounts[accountType]) {
|
|
131
|
+
if (options.debug) {
|
|
132
|
+
debug(`[debug] Skipping duplicate ${accountType} account`)
|
|
133
|
+
}
|
|
134
|
+
continue
|
|
135
|
+
}
|
|
136
|
+
|
|
84
137
|
const teamMap: Record<string, { team_id: string; team_name: string }> = {}
|
|
85
138
|
for (const team of teams) {
|
|
86
139
|
teamMap[team.id] = { team_id: team.id, team_name: team.name }
|
|
@@ -110,7 +163,7 @@ export async function extractAction(options: { pretty?: boolean; debug?: boolean
|
|
|
110
163
|
const errorMessage = (error as Error).message
|
|
111
164
|
const is401 = errorMessage.includes('401') || errorMessage.includes('Unauthorized')
|
|
112
165
|
if (options.debug) {
|
|
113
|
-
debug(`[debug] ✗ ${
|
|
166
|
+
debug(`[debug] ✗ ${extractedType}: ${errorMessage}`)
|
|
114
167
|
}
|
|
115
168
|
if (extracted.length === 1) {
|
|
116
169
|
console.log(
|
|
@@ -380,6 +433,12 @@ export const authCommand = new Command('auth')
|
|
|
380
433
|
.option('--pretty', 'Pretty print JSON output')
|
|
381
434
|
.option('--debug', 'Show debug output for troubleshooting')
|
|
382
435
|
.option('--token <token>', 'Manually provide a token (bypasses auto-extraction)')
|
|
436
|
+
.option(
|
|
437
|
+
'--browser-profile <path>',
|
|
438
|
+
'Additional Chromium profile/user-data directory to scan (repeatable, comma-separated supported)',
|
|
439
|
+
collectBrowserProfileOption,
|
|
440
|
+
[],
|
|
441
|
+
)
|
|
383
442
|
.action(extractAction),
|
|
384
443
|
)
|
|
385
444
|
.addCommand(
|
|
@@ -16,7 +16,7 @@ beforeEach(() => {
|
|
|
16
16
|
loadConfigSpy = spyOn(TeamsCredentialManager.prototype, 'loadConfig').mockResolvedValue(null)
|
|
17
17
|
|
|
18
18
|
extractSpy = spyOn(TeamsTokenExtractor.prototype, 'extract').mockResolvedValue([
|
|
19
|
-
{ token: 'test-teams-token', accountType: 'work' },
|
|
19
|
+
{ token: 'test-teams-token', accountType: 'work', accountTypeKnown: true },
|
|
20
20
|
])
|
|
21
21
|
|
|
22
22
|
testAuthSpy = spyOn(TeamsClient.prototype, 'testAuth').mockResolvedValue({
|
|
@@ -199,8 +199,8 @@ describe('ensureTeamsAuth', () => {
|
|
|
199
199
|
it('extracts and saves multiple accounts', async () => {
|
|
200
200
|
// given
|
|
201
201
|
extractSpy.mockResolvedValue([
|
|
202
|
-
{ token: 'work-token', accountType: 'work' },
|
|
203
|
-
{ token: 'personal-token', accountType: 'personal' },
|
|
202
|
+
{ token: 'work-token', accountType: 'work', accountTypeKnown: true },
|
|
203
|
+
{ token: 'personal-token', accountType: 'personal', accountTypeKnown: true },
|
|
204
204
|
])
|
|
205
205
|
|
|
206
206
|
testAuthSpy
|
|
@@ -229,8 +229,8 @@ describe('ensureTeamsAuth', () => {
|
|
|
229
229
|
it('skips failed account but saves successful ones', async () => {
|
|
230
230
|
// given
|
|
231
231
|
extractSpy.mockResolvedValue([
|
|
232
|
-
{ token: 'work-token', accountType: 'work' },
|
|
233
|
-
{ token: 'bad-token', accountType: 'personal' },
|
|
232
|
+
{ token: 'work-token', accountType: 'work', accountTypeKnown: true },
|
|
233
|
+
{ token: 'bad-token', accountType: 'personal', accountTypeKnown: true },
|
|
234
234
|
])
|
|
235
235
|
|
|
236
236
|
testAuthSpy
|
|
@@ -248,6 +248,57 @@ describe('ensureTeamsAuth', () => {
|
|
|
248
248
|
expect(savedConfig.accounts.personal).toBeUndefined()
|
|
249
249
|
})
|
|
250
250
|
|
|
251
|
+
// Regression for #163: browser-sourced tokens arrive with accountTypeKnown=false and
|
|
252
|
+
// a guessed accountType of 'work'. If the work endpoint rejects them, we must probe
|
|
253
|
+
// the personal endpoint before giving up — otherwise personal accounts logged in via
|
|
254
|
+
// browser would always fail validation.
|
|
255
|
+
it('reclassifies browser-sourced token from work to personal when work probe fails', async () => {
|
|
256
|
+
// given: extractor returns a token guessed as work but with unknown flag
|
|
257
|
+
extractSpy.mockResolvedValue([{ token: 'browser-token', accountType: 'work', accountTypeKnown: false }])
|
|
258
|
+
|
|
259
|
+
// first testAuth call (work) fails, second (personal) succeeds
|
|
260
|
+
testAuthSpy
|
|
261
|
+
.mockRejectedValueOnce(new Error('HTTP 403'))
|
|
262
|
+
.mockResolvedValueOnce({ id: 'user-p', displayName: 'Personal User' })
|
|
263
|
+
|
|
264
|
+
listTeamsSpy.mockResolvedValueOnce([{ id: 'team-p', name: 'Personal Chat' }])
|
|
265
|
+
|
|
266
|
+
// when
|
|
267
|
+
await ensureTeamsAuth()
|
|
268
|
+
|
|
269
|
+
// then: saved under 'personal', not 'work'
|
|
270
|
+
const savedConfig = saveConfigSpy.mock.calls[0][0]
|
|
271
|
+
expect(savedConfig.accounts.personal).toBeDefined()
|
|
272
|
+
expect(savedConfig.accounts.personal.account_type).toBe('personal')
|
|
273
|
+
expect(savedConfig.accounts.personal.token).toBe('browser-token')
|
|
274
|
+
expect(savedConfig.accounts.work).toBeUndefined()
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
// Regression for #163: when a known-type desktop token and an unknown-type browser
|
|
278
|
+
// token are both extracted, the loop must not overwrite the desktop account's data.
|
|
279
|
+
it('does not overwrite existing account when a later token reclassifies to same type', async () => {
|
|
280
|
+
// given: desktop personal token and browser token that probes to personal
|
|
281
|
+
extractSpy.mockResolvedValue([
|
|
282
|
+
{ token: 'desktop-personal-token', accountType: 'personal', accountTypeKnown: true },
|
|
283
|
+
{ token: 'browser-token', accountType: 'work', accountTypeKnown: false },
|
|
284
|
+
])
|
|
285
|
+
|
|
286
|
+
testAuthSpy
|
|
287
|
+
.mockResolvedValueOnce({ id: 'user-p', displayName: 'Desktop Personal' })
|
|
288
|
+
.mockRejectedValueOnce(new Error('HTTP 403'))
|
|
289
|
+
.mockResolvedValueOnce({ id: 'user-p', displayName: 'Browser Personal' })
|
|
290
|
+
|
|
291
|
+
listTeamsSpy.mockResolvedValueOnce([{ id: 'team-p', name: 'Personal' }])
|
|
292
|
+
|
|
293
|
+
// when
|
|
294
|
+
await ensureTeamsAuth()
|
|
295
|
+
|
|
296
|
+
// then: desktop token wins; browser token is skipped because personal already exists
|
|
297
|
+
const savedConfig = saveConfigSpy.mock.calls[0][0]
|
|
298
|
+
expect(savedConfig.accounts.personal.token).toBe('desktop-personal-token')
|
|
299
|
+
expect(savedConfig.accounts.work).toBeUndefined()
|
|
300
|
+
})
|
|
301
|
+
|
|
251
302
|
it('re-extracts when token is empty string', async () => {
|
|
252
303
|
// given
|
|
253
304
|
loadConfigSpy.mockResolvedValue({
|
|
@@ -3,7 +3,7 @@ import { warn } from '@/shared/utils/stderr'
|
|
|
3
3
|
import { TeamsClient } from './client'
|
|
4
4
|
import { TeamsCredentialManager } from './credential-manager'
|
|
5
5
|
import { TeamsTokenExtractor } from './token-extractor'
|
|
6
|
-
import type { TeamsAccount, TeamsConfig } from './types'
|
|
6
|
+
import type { TeamsAccount, TeamsAccountType, TeamsConfig } from './types'
|
|
7
7
|
|
|
8
8
|
export async function ensureTeamsAuth(): Promise<void> {
|
|
9
9
|
try {
|
|
@@ -20,15 +20,14 @@ export async function ensureTeamsAuth(): Promise<void> {
|
|
|
20
20
|
current_account: config?.current_account ?? null,
|
|
21
21
|
accounts: { ...config?.accounts },
|
|
22
22
|
}
|
|
23
|
+
const addedTypes = new Set<TeamsAccountType>()
|
|
23
24
|
|
|
24
|
-
for (const { token, accountType } of extracted) {
|
|
25
|
+
for (const { token, accountType: extractedType, accountTypeKnown } of extracted) {
|
|
25
26
|
try {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
})
|
|
31
|
-
await client.testAuth()
|
|
27
|
+
const resolved = await resolveAccountType(token, extractedType, accountTypeKnown, config)
|
|
28
|
+
const { client, accountType } = resolved
|
|
29
|
+
|
|
30
|
+
if (addedTypes.has(accountType)) continue
|
|
32
31
|
|
|
33
32
|
const teams = await client.listTeams()
|
|
34
33
|
if (accountType !== 'personal' && teams.length === 0) continue
|
|
@@ -38,23 +37,24 @@ export async function ensureTeamsAuth(): Promise<void> {
|
|
|
38
37
|
teamMap[team.id] = { team_id: team.id, team_name: team.name }
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
const existing = newConfig.accounts[accountType]
|
|
40
|
+
const existing: TeamsAccount | undefined = newConfig.accounts[accountType]
|
|
42
41
|
const account: TeamsAccount = {
|
|
43
42
|
token,
|
|
44
43
|
token_expires_at: new Date(Date.now() + 60 * 60 * 1000).toISOString(),
|
|
45
44
|
region: client.getRegion(),
|
|
46
45
|
account_type: accountType,
|
|
47
46
|
user_name: existing?.user_name,
|
|
48
|
-
current_team: existing?.current_team ?? teams[0]
|
|
47
|
+
current_team: existing?.current_team ?? teams[0]?.id ?? null,
|
|
49
48
|
teams: teamMap,
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
newConfig.accounts[accountType] = account
|
|
52
|
+
addedTypes.add(accountType)
|
|
53
53
|
if (!newConfig.current_account) {
|
|
54
54
|
newConfig.current_account = accountType
|
|
55
55
|
}
|
|
56
56
|
} catch (error) {
|
|
57
|
-
warn(`[agent-teams] Skipping ${
|
|
57
|
+
warn(`[agent-teams] Skipping ${extractedType} account: ${(error as Error).message}`)
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -64,6 +64,34 @@ export async function ensureTeamsAuth(): Promise<void> {
|
|
|
64
64
|
} catch {}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
async function resolveAccountType(
|
|
68
|
+
token: string,
|
|
69
|
+
extractedType: TeamsAccountType,
|
|
70
|
+
accountTypeKnown: boolean,
|
|
71
|
+
config: TeamsConfig | null,
|
|
72
|
+
): Promise<{ client: TeamsClient; accountType: TeamsAccountType }> {
|
|
73
|
+
const candidates: TeamsAccountType[] = [extractedType]
|
|
74
|
+
if (!accountTypeKnown) {
|
|
75
|
+
candidates.push(extractedType === 'work' ? 'personal' : 'work')
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let lastError: Error | null = null
|
|
79
|
+
for (const candidate of candidates) {
|
|
80
|
+
try {
|
|
81
|
+
const client = await new TeamsClient().login({
|
|
82
|
+
token,
|
|
83
|
+
accountType: candidate,
|
|
84
|
+
region: config?.accounts[candidate]?.region,
|
|
85
|
+
})
|
|
86
|
+
await client.testAuth()
|
|
87
|
+
return { client, accountType: candidate }
|
|
88
|
+
} catch (error) {
|
|
89
|
+
lastError = error as Error
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
throw lastError ?? new Error('Token validation failed')
|
|
93
|
+
}
|
|
94
|
+
|
|
67
95
|
function hasValidToken(config: TeamsConfig): boolean {
|
|
68
96
|
const key = TeamsCredentialManager.accountOverride ?? config.current_account
|
|
69
97
|
if (!key) return false
|
|
@@ -30,15 +30,28 @@ describe('TeamsTokenExtractor', () => {
|
|
|
30
30
|
'EBWebView',
|
|
31
31
|
)
|
|
32
32
|
expect(paths).toEqual([
|
|
33
|
-
{ path: join(darwinEbWebView, 'WV2Profile_tfw', 'Cookies'), accountType: 'work' },
|
|
34
|
-
{
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
{ path: join(darwinEbWebView, 'WV2Profile_tfw', 'Cookies'), accountType: 'work', accountTypeKnown: true },
|
|
34
|
+
{
|
|
35
|
+
path: join(darwinEbWebView, 'WV2Profile_tfw', 'Network', 'Cookies'),
|
|
36
|
+
accountType: 'work',
|
|
37
|
+
accountTypeKnown: true,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
path: join(darwinEbWebView, 'WV2Profile_tfl', 'Cookies'),
|
|
41
|
+
accountType: 'personal',
|
|
42
|
+
accountTypeKnown: true,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
path: join(darwinEbWebView, 'WV2Profile_tfl', 'Network', 'Cookies'),
|
|
46
|
+
accountType: 'personal',
|
|
47
|
+
accountTypeKnown: true,
|
|
48
|
+
},
|
|
49
|
+
{ path: join(darwinEbWebView, 'Default', 'Cookies'), accountType: 'work', accountTypeKnown: false },
|
|
50
|
+
{ path: join(darwinEbWebView, 'Default', 'Network', 'Cookies'), accountType: 'work', accountTypeKnown: false },
|
|
39
51
|
{
|
|
40
52
|
path: join(homedir(), 'Library', 'Application Support', 'Microsoft', 'Teams', 'Cookies'),
|
|
41
53
|
accountType: 'work',
|
|
54
|
+
accountTypeKnown: false,
|
|
42
55
|
},
|
|
43
56
|
])
|
|
44
57
|
})
|
|
@@ -51,6 +64,7 @@ describe('TeamsTokenExtractor', () => {
|
|
|
51
64
|
{
|
|
52
65
|
path: join(homedir(), '.config', 'Microsoft', 'Microsoft Teams', 'Cookies'),
|
|
53
66
|
accountType: 'work',
|
|
67
|
+
accountTypeKnown: false,
|
|
54
68
|
},
|
|
55
69
|
])
|
|
56
70
|
})
|
|
@@ -71,13 +85,21 @@ describe('TeamsTokenExtractor', () => {
|
|
|
71
85
|
'EBWebView',
|
|
72
86
|
)
|
|
73
87
|
expect(paths).toEqual([
|
|
74
|
-
{ path: join(winEbWebView, 'WV2Profile_tfw', 'Cookies'), accountType: 'work' },
|
|
75
|
-
{
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
{ path: join(
|
|
88
|
+
{ path: join(winEbWebView, 'WV2Profile_tfw', 'Cookies'), accountType: 'work', accountTypeKnown: true },
|
|
89
|
+
{
|
|
90
|
+
path: join(winEbWebView, 'WV2Profile_tfw', 'Network', 'Cookies'),
|
|
91
|
+
accountType: 'work',
|
|
92
|
+
accountTypeKnown: true,
|
|
93
|
+
},
|
|
94
|
+
{ path: join(winEbWebView, 'WV2Profile_tfl', 'Cookies'), accountType: 'personal', accountTypeKnown: true },
|
|
95
|
+
{
|
|
96
|
+
path: join(winEbWebView, 'WV2Profile_tfl', 'Network', 'Cookies'),
|
|
97
|
+
accountType: 'personal',
|
|
98
|
+
accountTypeKnown: true,
|
|
99
|
+
},
|
|
100
|
+
{ path: join(winEbWebView, 'Default', 'Cookies'), accountType: 'work', accountTypeKnown: false },
|
|
101
|
+
{ path: join(winEbWebView, 'Default', 'Network', 'Cookies'), accountType: 'work', accountTypeKnown: false },
|
|
102
|
+
{ path: join(appdata, 'Microsoft', 'Teams', 'Cookies'), accountType: 'work', accountTypeKnown: false },
|
|
81
103
|
])
|
|
82
104
|
})
|
|
83
105
|
|
|
@@ -96,10 +118,12 @@ describe('TeamsTokenExtractor', () => {
|
|
|
96
118
|
expect(paths).toContainEqual({
|
|
97
119
|
path: join(chromeBase, 'Default', 'Cookies'),
|
|
98
120
|
accountType: 'work',
|
|
121
|
+
accountTypeKnown: false,
|
|
99
122
|
})
|
|
100
123
|
expect(paths).toContainEqual({
|
|
101
124
|
path: join(chromeBase, 'Default', 'Network', 'Cookies'),
|
|
102
125
|
accountType: 'work',
|
|
126
|
+
accountTypeKnown: false,
|
|
103
127
|
})
|
|
104
128
|
})
|
|
105
129
|
|
|
@@ -111,6 +135,7 @@ describe('TeamsTokenExtractor', () => {
|
|
|
111
135
|
expect(paths).toContainEqual({
|
|
112
136
|
path: join(chromeBase, 'Default', 'Cookies'),
|
|
113
137
|
accountType: 'work',
|
|
138
|
+
accountTypeKnown: false,
|
|
114
139
|
})
|
|
115
140
|
})
|
|
116
141
|
|
|
@@ -123,6 +148,7 @@ describe('TeamsTokenExtractor', () => {
|
|
|
123
148
|
expect(paths).toContainEqual({
|
|
124
149
|
path: join(chromeBase, 'Default', 'Cookies'),
|
|
125
150
|
accountType: 'work',
|
|
151
|
+
accountTypeKnown: false,
|
|
126
152
|
})
|
|
127
153
|
})
|
|
128
154
|
|
|
@@ -131,10 +157,14 @@ describe('TeamsTokenExtractor', () => {
|
|
|
131
157
|
expect(unsupportedExtractor.getBrowserCookiesPaths()).toEqual([])
|
|
132
158
|
})
|
|
133
159
|
|
|
134
|
-
|
|
160
|
+
// Regression for #163: browser paths must not assert accountType confidently because
|
|
161
|
+
// Chromium profile paths don't encode work vs personal. Desktop WV2Profile_tfw/_tfl
|
|
162
|
+
// paths are authoritative; browsers must be probed at validation time.
|
|
163
|
+
it('browser paths have accountTypeKnown=false so they get probed at validation', () => {
|
|
135
164
|
const darwinExtractor = new TeamsTokenExtractor('darwin')
|
|
136
165
|
const paths = darwinExtractor.getBrowserCookiesPaths()
|
|
137
|
-
expect(paths.
|
|
166
|
+
expect(paths.length).toBeGreaterThan(0)
|
|
167
|
+
expect(paths.every((p) => p.accountTypeKnown === false)).toBe(true)
|
|
138
168
|
})
|
|
139
169
|
})
|
|
140
170
|
|
|
@@ -166,6 +196,7 @@ describe('TeamsTokenExtractor', () => {
|
|
|
166
196
|
{
|
|
167
197
|
path: join(homedir(), '.config', 'Microsoft', 'Microsoft Teams', 'Cookies'),
|
|
168
198
|
accountType: 'work',
|
|
199
|
+
accountTypeKnown: false,
|
|
169
200
|
},
|
|
170
201
|
])
|
|
171
202
|
expect(paths.length).toBeGreaterThan(desktopPaths.length)
|
|
@@ -338,7 +369,7 @@ describe('TeamsTokenExtractor', () => {
|
|
|
338
369
|
|
|
339
370
|
const linuxExtractor = new TeamsTokenExtractor('linux')
|
|
340
371
|
const extractFromCookiesDBSpy = spyOn(linuxExtractor as any, 'extractFromCookiesDB').mockResolvedValue([
|
|
341
|
-
{ token: mockToken, accountType: 'work' },
|
|
372
|
+
{ token: mockToken, accountType: 'work', accountTypeKnown: true },
|
|
342
373
|
])
|
|
343
374
|
|
|
344
375
|
const result = await linuxExtractor.extract()
|
|
@@ -382,8 +413,8 @@ describe('TeamsTokenExtractor', () => {
|
|
|
382
413
|
|
|
383
414
|
const winExtractor = new TeamsTokenExtractor('win32')
|
|
384
415
|
const getPathsSpy = spyOn(winExtractor, 'getTeamsCookiesPaths').mockReturnValue([
|
|
385
|
-
{ path: cookiesPath, accountType: 'personal' },
|
|
386
|
-
{ path: networkCookiesPath, accountType: 'personal' },
|
|
416
|
+
{ path: cookiesPath, accountType: 'personal', accountTypeKnown: true },
|
|
417
|
+
{ path: networkCookiesPath, accountType: 'personal', accountTypeKnown: true },
|
|
387
418
|
])
|
|
388
419
|
const tried: string[] = []
|
|
389
420
|
const copyAndExtractSpy = spyOn(winExtractor as any, 'copyAndExtract').mockImplementation(async (...args) => {
|
|
@@ -398,7 +429,7 @@ describe('TeamsTokenExtractor', () => {
|
|
|
398
429
|
// then: the Cookies path was skipped (never passed to copyAndExtract),
|
|
399
430
|
// the Network/Cookies sibling was tried, and the token was returned.
|
|
400
431
|
expect(tried).toEqual([networkCookiesPath])
|
|
401
|
-
expect(results).toEqual([{ token: mockToken, accountType: 'personal' }])
|
|
432
|
+
expect(results).toEqual([{ token: mockToken, accountType: 'personal', accountTypeKnown: true }])
|
|
402
433
|
|
|
403
434
|
getPathsSpy.mockRestore()
|
|
404
435
|
copyAndExtractSpy.mockRestore()
|
|
@@ -419,8 +450,8 @@ describe('TeamsTokenExtractor', () => {
|
|
|
419
450
|
const firstPath = join(workDir, 'WV2Profile_tfw', 'Cookies')
|
|
420
451
|
const secondPath = join(workDir, 'Default', 'Network', 'Cookies')
|
|
421
452
|
const getPathsSpy = spyOn(winExtractor, 'getTeamsCookiesPaths').mockReturnValue([
|
|
422
|
-
{ path: firstPath, accountType: 'work' },
|
|
423
|
-
{ path: secondPath, accountType: 'work' },
|
|
453
|
+
{ path: firstPath, accountType: 'work', accountTypeKnown: true },
|
|
454
|
+
{ path: secondPath, accountType: 'work', accountTypeKnown: true },
|
|
424
455
|
])
|
|
425
456
|
mkdirSync(join(workDir, 'WV2Profile_tfw'), { recursive: true })
|
|
426
457
|
mkdirSync(join(workDir, 'Default', 'Network'), { recursive: true })
|
|
@@ -436,7 +467,98 @@ describe('TeamsTokenExtractor', () => {
|
|
|
436
467
|
|
|
437
468
|
// then: garbage was rejected, loop continued to the real token
|
|
438
469
|
expect(copyAndExtractSpy).toHaveBeenCalledTimes(2)
|
|
439
|
-
expect(results).toEqual([{ token: realToken, accountType: 'work' }])
|
|
470
|
+
expect(results).toEqual([{ token: realToken, accountType: 'work', accountTypeKnown: true }])
|
|
471
|
+
|
|
472
|
+
getPathsSpy.mockRestore()
|
|
473
|
+
copyAndExtractSpy.mockRestore()
|
|
474
|
+
cleanup()
|
|
475
|
+
})
|
|
476
|
+
|
|
477
|
+
// Regression for #163: browser-sourced tokens carry accountTypeKnown=false so that
|
|
478
|
+
// the auth command can probe both endpoints. The extraction loop must preserve the
|
|
479
|
+
// flag and must not dedupe an unknown-type browser token by its guessed accountType.
|
|
480
|
+
it('propagates accountTypeKnown=false for browser-sourced tokens', async () => {
|
|
481
|
+
// given: a browser Cookies path returning a valid token, guessed as work
|
|
482
|
+
const browserPath = join(workDir, 'Chrome', 'Default', 'Cookies')
|
|
483
|
+
mkdirSync(join(workDir, 'Chrome', 'Default'), { recursive: true })
|
|
484
|
+
writeFileSync(browserPath, '')
|
|
485
|
+
|
|
486
|
+
const winExtractor = new TeamsTokenExtractor('win32')
|
|
487
|
+
const getPathsSpy = spyOn(winExtractor, 'getTeamsCookiesPaths').mockReturnValue([
|
|
488
|
+
{ path: browserPath, accountType: 'work', accountTypeKnown: false },
|
|
489
|
+
])
|
|
490
|
+
const copyAndExtractSpy = spyOn(winExtractor as any, 'copyAndExtract').mockResolvedValue(mockToken)
|
|
491
|
+
|
|
492
|
+
// when
|
|
493
|
+
const results = await (winExtractor as any).extractFromCookiesDB()
|
|
494
|
+
|
|
495
|
+
// then: the flag is passed through so callers can probe
|
|
496
|
+
expect(results).toEqual([{ token: mockToken, accountType: 'work', accountTypeKnown: false }])
|
|
497
|
+
|
|
498
|
+
getPathsSpy.mockRestore()
|
|
499
|
+
copyAndExtractSpy.mockRestore()
|
|
500
|
+
cleanup()
|
|
501
|
+
})
|
|
502
|
+
|
|
503
|
+
// Regression for #163: when a desktop path (known=true) for 'work' already succeeded,
|
|
504
|
+
// a subsequent browser path (known=false) guessed as 'work' must still be explored —
|
|
505
|
+
// it might be a personal account misguessed as work. The dedup only kicks in for
|
|
506
|
+
// confidently labeled paths.
|
|
507
|
+
it('does not skip unknown-type path just because a known-type same-label succeeded', async () => {
|
|
508
|
+
const desktopPath = join(workDir, 'WV2Profile_tfw', 'Network', 'Cookies')
|
|
509
|
+
const browserPath = join(workDir, 'Chrome', 'Default', 'Cookies')
|
|
510
|
+
mkdirSync(join(workDir, 'WV2Profile_tfw', 'Network'), { recursive: true })
|
|
511
|
+
mkdirSync(join(workDir, 'Chrome', 'Default'), { recursive: true })
|
|
512
|
+
writeFileSync(desktopPath, '')
|
|
513
|
+
writeFileSync(browserPath, '')
|
|
514
|
+
|
|
515
|
+
const desktopToken = mockToken
|
|
516
|
+
const browserToken = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJicm93c2VyIn0.different_signature_here_abc'
|
|
517
|
+
|
|
518
|
+
const winExtractor = new TeamsTokenExtractor('win32')
|
|
519
|
+
const getPathsSpy = spyOn(winExtractor, 'getTeamsCookiesPaths').mockReturnValue([
|
|
520
|
+
{ path: desktopPath, accountType: 'work', accountTypeKnown: true },
|
|
521
|
+
{ path: browserPath, accountType: 'work', accountTypeKnown: false },
|
|
522
|
+
])
|
|
523
|
+
const copyAndExtractSpy = spyOn(winExtractor as any, 'copyAndExtract')
|
|
524
|
+
.mockResolvedValueOnce(desktopToken)
|
|
525
|
+
.mockResolvedValueOnce(browserToken)
|
|
526
|
+
|
|
527
|
+
// when
|
|
528
|
+
const results = await (winExtractor as any).extractFromCookiesDB()
|
|
529
|
+
|
|
530
|
+
// then: both tokens returned; browser token keeps accountTypeKnown=false for probing
|
|
531
|
+
expect(results).toEqual([
|
|
532
|
+
{ token: desktopToken, accountType: 'work', accountTypeKnown: true },
|
|
533
|
+
{ token: browserToken, accountType: 'work', accountTypeKnown: false },
|
|
534
|
+
])
|
|
535
|
+
|
|
536
|
+
getPathsSpy.mockRestore()
|
|
537
|
+
copyAndExtractSpy.mockRestore()
|
|
538
|
+
cleanup()
|
|
539
|
+
})
|
|
540
|
+
|
|
541
|
+
it('dedupes identical tokens extracted from multiple paths', async () => {
|
|
542
|
+
const path1 = join(workDir, 'Chrome', 'Default', 'Cookies')
|
|
543
|
+
const path2 = join(workDir, 'Edge', 'Default', 'Cookies')
|
|
544
|
+
mkdirSync(join(workDir, 'Chrome', 'Default'), { recursive: true })
|
|
545
|
+
mkdirSync(join(workDir, 'Edge', 'Default'), { recursive: true })
|
|
546
|
+
writeFileSync(path1, '')
|
|
547
|
+
writeFileSync(path2, '')
|
|
548
|
+
|
|
549
|
+
const winExtractor = new TeamsTokenExtractor('win32')
|
|
550
|
+
const getPathsSpy = spyOn(winExtractor, 'getTeamsCookiesPaths').mockReturnValue([
|
|
551
|
+
{ path: path1, accountType: 'work', accountTypeKnown: false },
|
|
552
|
+
{ path: path2, accountType: 'work', accountTypeKnown: false },
|
|
553
|
+
])
|
|
554
|
+
const copyAndExtractSpy = spyOn(winExtractor as any, 'copyAndExtract').mockResolvedValue(mockToken)
|
|
555
|
+
|
|
556
|
+
// when
|
|
557
|
+
const results = await (winExtractor as any).extractFromCookiesDB()
|
|
558
|
+
|
|
559
|
+
// then: only one result despite two paths returning the same token
|
|
560
|
+
expect(results).toHaveLength(1)
|
|
561
|
+
expect(results[0].token).toBe(mockToken)
|
|
440
562
|
|
|
441
563
|
getPathsSpy.mockRestore()
|
|
442
564
|
copyAndExtractSpy.mockRestore()
|
|
@@ -454,8 +576,8 @@ describe('TeamsTokenExtractor', () => {
|
|
|
454
576
|
|
|
455
577
|
const winExtractor = new TeamsTokenExtractor('win32')
|
|
456
578
|
const getPathsSpy = spyOn(winExtractor, 'getTeamsCookiesPaths').mockReturnValue([
|
|
457
|
-
{ path: workCookies, accountType: 'work' },
|
|
458
|
-
{ path: workNetworkCookies, accountType: 'work' },
|
|
579
|
+
{ path: workCookies, accountType: 'work', accountTypeKnown: true },
|
|
580
|
+
{ path: workNetworkCookies, accountType: 'work', accountTypeKnown: true },
|
|
459
581
|
])
|
|
460
582
|
const copyAndExtractSpy = spyOn(winExtractor as any, 'copyAndExtract').mockResolvedValue(mockToken)
|
|
461
583
|
|