agent-messenger 2.7.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/.github/workflows/ci.yml +6 -0
- package/.oxfmtrc.json +13 -1
- package/.oxlintrc.json +10 -1
- package/README.md +1 -1
- package/dist/package.json +59 -58
- package/dist/src/platforms/channeltalk/client.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/client.js +2 -2
- package/dist/src/platforms/channeltalk/client.js.map +1 -1
- package/dist/src/platforms/channeltalk/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/commands/auth.js.map +1 -1
- package/dist/src/platforms/channeltalk/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/commands/message.js.map +1 -1
- package/dist/src/platforms/channeltalk/commands/snapshot.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/commands/snapshot.js.map +1 -1
- package/dist/src/platforms/channeltalk/ensure-auth.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/ensure-auth.js.map +1 -1
- package/dist/src/platforms/channeltalk/token-extractor.d.ts +9 -23
- package/dist/src/platforms/channeltalk/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/token-extractor.js +109 -341
- package/dist/src/platforms/channeltalk/token-extractor.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/client.d.ts +1 -1
- package/dist/src/platforms/channeltalkbot/client.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/client.js +4 -4
- package/dist/src/platforms/channeltalkbot/client.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/auth.js +4 -1
- package/dist/src/platforms/channeltalkbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/shared.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/shared.js.map +1 -1
- package/dist/src/platforms/discord/commands/auth.js.map +1 -1
- package/dist/src/platforms/discord/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/whoami.js.map +1 -1
- package/dist/src/platforms/discord/token-extractor.d.ts +2 -10
- package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/discord/token-extractor.js +38 -172
- package/dist/src/platforms/discord/token-extractor.js.map +1 -1
- package/dist/src/platforms/discordbot/client.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/client.js.map +1 -1
- package/dist/src/platforms/instagram/cli.d.ts.map +1 -1
- package/dist/src/platforms/instagram/cli.js +1 -4
- package/dist/src/platforms/instagram/cli.js.map +1 -1
- package/dist/src/platforms/instagram/client.d.ts.map +1 -1
- package/dist/src/platforms/instagram/client.js +8 -7
- package/dist/src/platforms/instagram/client.js.map +1 -1
- package/dist/src/platforms/instagram/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/instagram/commands/auth.js.map +1 -1
- package/dist/src/platforms/instagram/commands/chat.d.ts.map +1 -1
- package/dist/src/platforms/instagram/commands/chat.js.map +1 -1
- package/dist/src/platforms/instagram/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/instagram/commands/message.js.map +1 -1
- package/dist/src/platforms/instagram/commands/shared.d.ts.map +1 -1
- package/dist/src/platforms/instagram/commands/shared.js.map +1 -1
- package/dist/src/platforms/instagram/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/instagram/credential-manager.js +1 -1
- package/dist/src/platforms/instagram/credential-manager.js.map +1 -1
- package/dist/src/platforms/instagram/ensure-auth.d.ts.map +1 -1
- package/dist/src/platforms/instagram/ensure-auth.js.map +1 -1
- package/dist/src/platforms/instagram/token-extractor.d.ts +7 -19
- package/dist/src/platforms/instagram/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/instagram/token-extractor.js +44 -270
- package/dist/src/platforms/instagram/token-extractor.js.map +1 -1
- package/dist/src/platforms/instagram/types.d.ts.map +1 -1
- package/dist/src/platforms/instagram/types.js +4 -2
- package/dist/src/platforms/instagram/types.js.map +1 -1
- package/dist/src/platforms/kakaotalk/auth/kakao-login.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/auth/kakao-login.js +18 -4
- package/dist/src/platforms/kakaotalk/auth/kakao-login.js.map +1 -1
- package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/client.js +3 -3
- package/dist/src/platforms/kakaotalk/client.js.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/auth.js +15 -9
- package/dist/src/platforms/kakaotalk/commands/auth.js.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/shared.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/shared.js.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/connection.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/connection.js.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/crypto.js +1 -1
- package/dist/src/platforms/kakaotalk/protocol/crypto.js.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/session.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/session.js +1 -3
- package/dist/src/platforms/kakaotalk/protocol/session.js.map +1 -1
- package/dist/src/platforms/kakaotalk/token-extractor.js +5 -2
- package/dist/src/platforms/kakaotalk/token-extractor.js.map +1 -1
- package/dist/src/platforms/kakaotalk/types.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/types.js +4 -2
- package/dist/src/platforms/kakaotalk/types.js.map +1 -1
- package/dist/src/platforms/line/cli.d.ts.map +1 -1
- package/dist/src/platforms/line/cli.js +1 -4
- package/dist/src/platforms/line/cli.js.map +1 -1
- package/dist/src/platforms/line/client.d.ts.map +1 -1
- package/dist/src/platforms/line/client.js +5 -13
- package/dist/src/platforms/line/client.js.map +1 -1
- package/dist/src/platforms/line/commands/chat.d.ts.map +1 -1
- package/dist/src/platforms/line/commands/chat.js.map +1 -1
- package/dist/src/platforms/line/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/line/commands/message.js.map +1 -1
- package/dist/src/platforms/line/listener.js +1 -1
- package/dist/src/platforms/line/listener.js.map +1 -1
- package/dist/src/platforms/slack/cli.d.ts.map +1 -1
- package/dist/src/platforms/slack/cli.js.map +1 -1
- package/dist/src/platforms/slack/client-mappers.d.ts +14 -0
- package/dist/src/platforms/slack/client-mappers.d.ts.map +1 -0
- package/dist/src/platforms/slack/client-mappers.js +245 -0
- package/dist/src/platforms/slack/client-mappers.js.map +1 -0
- package/dist/src/platforms/slack/client.d.ts +0 -1
- package/dist/src/platforms/slack/client.d.ts.map +1 -1
- package/dist/src/platforms/slack/client.js +41 -455
- package/dist/src/platforms/slack/client.js.map +1 -1
- package/dist/src/platforms/slack/commands/channel.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/channel.js.map +1 -1
- package/dist/src/platforms/slack/commands/emoji.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/emoji.js +1 -3
- package/dist/src/platforms/slack/commands/emoji.js.map +1 -1
- package/dist/src/platforms/slack/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/message.js.map +1 -1
- package/dist/src/platforms/slack/commands/reminder.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/reminder.js.map +1 -1
- package/dist/src/platforms/slack/commands/user.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/user.js.map +1 -1
- package/dist/src/platforms/slack/commands/usergroup.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/usergroup.js.map +1 -1
- package/dist/src/platforms/slack/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/whoami.js.map +1 -1
- package/dist/src/platforms/slack/token-extractor.d.ts +2 -6
- package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/slack/token-extractor.js +35 -229
- 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 +1 -1
- package/dist/src/platforms/slackbot/cli.js.map +1 -1
- package/dist/src/platforms/teams/client.d.ts.map +1 -1
- package/dist/src/platforms/teams/client.js +1 -1
- package/dist/src/platforms/teams/client.js.map +1 -1
- package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/auth.js +4 -1
- package/dist/src/platforms/teams/commands/auth.js.map +1 -1
- package/dist/src/platforms/teams/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/whoami.js.map +1 -1
- package/dist/src/platforms/teams/token-extractor.d.ts +6 -18
- package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/teams/token-extractor.js +71 -324
- package/dist/src/platforms/teams/token-extractor.js.map +1 -1
- package/dist/src/platforms/telegram/cli.d.ts.map +1 -1
- package/dist/src/platforms/telegram/cli.js +1 -4
- package/dist/src/platforms/telegram/cli.js.map +1 -1
- package/dist/src/platforms/telegram/client.d.ts.map +1 -1
- package/dist/src/platforms/telegram/client.js.map +1 -1
- package/dist/src/platforms/telegram/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/telegram/commands/auth.js +1 -1
- package/dist/src/platforms/telegram/commands/auth.js.map +1 -1
- package/dist/src/platforms/telegram/commands/chat.d.ts.map +1 -1
- package/dist/src/platforms/telegram/commands/chat.js.map +1 -1
- package/dist/src/platforms/telegram/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/telegram/commands/message.js.map +1 -1
- package/dist/src/platforms/telegram/commands/whoami.js +1 -1
- package/dist/src/platforms/telegram/commands/whoami.js.map +1 -1
- package/dist/src/platforms/telegram/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/telegram/credential-manager.js +6 -2
- package/dist/src/platforms/telegram/credential-manager.js.map +1 -1
- package/dist/src/platforms/telegram/my-telegram-org.js.map +1 -1
- package/dist/src/platforms/webex/cli.d.ts.map +1 -1
- package/dist/src/platforms/webex/cli.js +1 -4
- package/dist/src/platforms/webex/cli.js.map +1 -1
- package/dist/src/platforms/webex/client.d.ts.map +1 -1
- package/dist/src/platforms/webex/client.js +3 -7
- package/dist/src/platforms/webex/client.js.map +1 -1
- package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/auth.js +1 -3
- package/dist/src/platforms/webex/commands/auth.js.map +1 -1
- package/dist/src/platforms/webex/commands/member.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/member.js +1 -3
- package/dist/src/platforms/webex/commands/member.js.map +1 -1
- package/dist/src/platforms/webex/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/message.js.map +1 -1
- package/dist/src/platforms/webex/commands/snapshot.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/snapshot.js.map +1 -1
- package/dist/src/platforms/webex/commands/space.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/space.js.map +1 -1
- package/dist/src/platforms/webex/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/whoami.js.map +1 -1
- package/dist/src/platforms/webex/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/webex/credential-manager.js.map +1 -1
- package/dist/src/platforms/webex/ensure-auth.d.ts.map +1 -1
- package/dist/src/platforms/webex/ensure-auth.js +1 -3
- package/dist/src/platforms/webex/ensure-auth.js.map +1 -1
- package/dist/src/platforms/webex/index.d.ts +1 -1
- package/dist/src/platforms/webex/index.d.ts.map +1 -1
- package/dist/src/platforms/webex/index.js.map +1 -1
- package/dist/src/platforms/webex/markdown-to-html.js.map +1 -1
- package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/webex/token-extractor.js +5 -14
- package/dist/src/platforms/webex/token-extractor.js.map +1 -1
- package/dist/src/platforms/wechatbot/client.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/client.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/message.js.map +1 -1
- package/dist/src/platforms/whatsapp/cli.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/cli.js +1 -4
- package/dist/src/platforms/whatsapp/cli.js.map +1 -1
- package/dist/src/platforms/whatsapp/commands/chat.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/commands/chat.js.map +1 -1
- package/dist/src/platforms/whatsapp/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/commands/message.js.map +1 -1
- package/dist/src/platforms/whatsapp/commands/shared.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/commands/shared.js.map +1 -1
- package/dist/src/platforms/whatsapp/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/credential-manager.js +1 -1
- package/dist/src/platforms/whatsapp/credential-manager.js.map +1 -1
- package/dist/src/platforms/whatsapp/ensure-auth.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/ensure-auth.js.map +1 -1
- package/dist/src/platforms/whatsappbot/client.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/client.js +2 -2
- package/dist/src/platforms/whatsappbot/client.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/auth.js +4 -1
- 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.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/shared.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/shared.js.map +1 -1
- package/dist/src/shared/chromium/browsers.d.ts +7 -0
- package/dist/src/shared/chromium/browsers.d.ts.map +1 -0
- package/dist/src/shared/chromium/browsers.js +89 -0
- package/dist/src/shared/chromium/browsers.js.map +1 -0
- package/dist/src/shared/chromium/cookie-reader.d.ts +20 -0
- package/dist/src/shared/chromium/cookie-reader.d.ts.map +1 -0
- package/dist/src/shared/chromium/cookie-reader.js +99 -0
- package/dist/src/shared/chromium/cookie-reader.js.map +1 -0
- package/dist/src/shared/chromium/decryptor.d.ts +42 -0
- package/dist/src/shared/chromium/decryptor.d.ts.map +1 -0
- package/dist/src/shared/chromium/decryptor.js +205 -0
- package/dist/src/shared/chromium/decryptor.js.map +1 -0
- package/dist/src/shared/chromium/index.d.ts +6 -0
- package/dist/src/shared/chromium/index.d.ts.map +1 -0
- package/dist/src/shared/chromium/index.js +4 -0
- package/dist/src/shared/chromium/index.js.map +1 -0
- package/dist/src/shared/chromium/types.d.ts +11 -0
- package/dist/src/shared/chromium/types.d.ts.map +1 -0
- package/dist/src/shared/chromium/types.js +2 -0
- package/dist/src/shared/chromium/types.js.map +1 -0
- package/dist/src/shared/utils/derived-key-cache.d.ts +1 -1
- package/dist/src/shared/utils/derived-key-cache.d.ts.map +1 -1
- package/dist/src/shared/utils/linux-keyring.js +4 -1
- package/dist/src/shared/utils/linux-keyring.js.map +1 -1
- package/dist/src/tui/adapters/kakaotalk-adapter.d.ts.map +1 -1
- package/dist/src/tui/adapters/kakaotalk-adapter.js +6 -1
- package/dist/src/tui/adapters/kakaotalk-adapter.js.map +1 -1
- package/dist/src/tui/adapters/telegram-adapter.js +1 -1
- package/dist/src/tui/adapters/telegram-adapter.js.map +1 -1
- package/dist/src/tui/adapters/webex-adapter.js +1 -1
- package/dist/src/tui/adapters/webex-adapter.js.map +1 -1
- package/dist/src/tui/app.d.ts.map +1 -1
- package/dist/src/tui/app.js +112 -23
- package/dist/src/tui/app.js.map +1 -1
- package/dist/src/tui/utils.d.ts.map +1 -1
- package/dist/src/tui/utils.js +11 -13
- package/dist/src/tui/utils.js.map +1 -1
- package/dist/src/tui/views/channel-picker.d.ts.map +1 -1
- package/dist/src/tui/views/channel-picker.js.map +1 -1
- package/dist/src/tui/views/workspace-picker.d.ts.map +1 -1
- package/dist/src/tui/views/workspace-picker.js.map +1 -1
- package/docs/content/docs/cli/channeltalk.mdx +24 -22
- package/docs/content/docs/cli/channeltalkbot.mdx +7 -7
- package/docs/content/docs/cli/instagram.mdx +4 -4
- package/docs/content/docs/cli/kakaotalk.mdx +9 -8
- package/docs/content/docs/cli/line.mdx +14 -14
- package/docs/content/docs/cli/webex.mdx +19 -19
- package/docs/content/docs/cli/wechatbot.mdx +12 -11
- package/docs/content/docs/cli/whatsapp.mdx +5 -4
- package/docs/content/docs/cli/whatsappbot.mdx +11 -11
- package/docs/content/docs/index.mdx +7 -7
- package/docs/content/docs/meta.json +1 -9
- package/docs/content/docs/sdk/channeltalk.mdx +5 -6
- package/docs/content/docs/sdk/channeltalkbot.mdx +6 -12
- package/docs/content/docs/sdk/discord.mdx +36 -43
- package/docs/content/docs/sdk/instagram.mdx +18 -18
- package/docs/content/docs/sdk/kakaotalk.mdx +27 -18
- package/docs/content/docs/sdk/line.mdx +8 -13
- package/docs/content/docs/sdk/meta.json +14 -1
- package/docs/content/docs/sdk/slack.mdx +36 -42
- package/docs/content/docs/sdk/teams.mdx +2 -8
- package/docs/content/docs/sdk/webex.mdx +2 -12
- package/docs/content/docs/sdk/wechatbot.mdx +1 -5
- package/docs/content/docs/sdk/whatsapp.mdx +10 -19
- package/docs/content/docs/sdk/whatsappbot.mdx +2 -10
- package/docs/content/docs/tui.mdx +23 -23
- package/docs/src/app/page.tsx +353 -108
- package/e2e/channeltalkbot.e2e.test.ts +1 -5
- package/e2e/config.ts +6 -2
- package/package.json +59 -58
- package/scripts/prepublish.ts +1 -3
- package/skills/agent-channeltalk/SKILL.md +1 -1
- package/skills/agent-channeltalkbot/SKILL.md +1 -1
- package/skills/agent-discord/SKILL.md +1 -1
- package/skills/agent-discordbot/SKILL.md +1 -1
- package/skills/agent-instagram/SKILL.md +1 -1
- package/skills/agent-kakaotalk/SKILL.md +1 -1
- package/skills/agent-line/SKILL.md +1 -1
- package/skills/agent-slack/SKILL.md +1 -1
- package/skills/agent-slackbot/SKILL.md +1 -1
- package/skills/agent-teams/SKILL.md +1 -1
- package/skills/agent-telegram/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +1 -1
- package/skills/agent-wechatbot/SKILL.md +1 -1
- package/skills/agent-whatsapp/SKILL.md +1 -1
- package/skills/agent-whatsappbot/SKILL.md +1 -1
- package/src/platforms/channeltalk/client.test.ts +116 -29
- package/src/platforms/channeltalk/client.ts +26 -6
- package/src/platforms/channeltalk/commands/auth.test.ts +5 -5
- package/src/platforms/channeltalk/commands/auth.ts +19 -5
- package/src/platforms/channeltalk/commands/message.test.ts +2 -6
- package/src/platforms/channeltalk/commands/message.ts +5 -1
- package/src/platforms/channeltalk/commands/snapshot.test.ts +19 -4
- package/src/platforms/channeltalk/commands/snapshot.ts +5 -1
- package/src/platforms/channeltalk/ensure-auth.test.ts +20 -17
- package/src/platforms/channeltalk/ensure-auth.ts +6 -7
- package/src/platforms/channeltalk/index.ts +0 -1
- package/src/platforms/channeltalk/token-extractor.test.ts +33 -25
- package/src/platforms/channeltalk/token-extractor.ts +120 -372
- package/src/platforms/channeltalkbot/client.test.ts +1 -3
- package/src/platforms/channeltalkbot/client.ts +39 -13
- package/src/platforms/channeltalkbot/commands/auth.test.ts +3 -1
- package/src/platforms/channeltalkbot/commands/auth.ts +4 -1
- package/src/platforms/channeltalkbot/commands/bot.test.ts +13 -5
- package/src/platforms/channeltalkbot/commands/message.test.ts +12 -6
- package/src/platforms/channeltalkbot/commands/shared.ts +6 -2
- package/src/platforms/channeltalkbot/commands/snapshot.test.ts +17 -5
- package/src/platforms/channeltalkbot/credential-manager.test.ts +1 -1
- package/src/platforms/channeltalkbot/index.test.ts +0 -2
- package/src/platforms/channeltalkbot/index.ts +0 -1
- package/src/platforms/discord/commands/auth.test.ts +6 -4
- package/src/platforms/discord/commands/auth.ts +14 -14
- package/src/platforms/discord/commands/whoami.test.ts +2 -4
- package/src/platforms/discord/commands/whoami.ts +2 -0
- package/src/platforms/discord/ensure-auth.test.ts +5 -3
- package/src/platforms/discord/index.ts +0 -1
- package/src/platforms/discord/listener.test.ts +7 -1
- package/src/platforms/discord/token-extractor.test.ts +18 -12
- package/src/platforms/discord/token-extractor.ts +46 -190
- package/src/platforms/discordbot/client.ts +1 -4
- package/src/platforms/discordbot/commands/auth.test.ts +3 -1
- package/src/platforms/discordbot/commands/channel.test.ts +3 -1
- package/src/platforms/discordbot/commands/message.test.ts +3 -1
- package/src/platforms/discordbot/commands/server.test.ts +3 -1
- package/src/platforms/discordbot/commands/snapshot.test.ts +3 -1
- package/src/platforms/discordbot/commands/thread.test.ts +3 -1
- package/src/platforms/discordbot/commands/user.test.ts +3 -1
- package/src/platforms/instagram/cli.ts +1 -4
- package/src/platforms/instagram/client.test.ts +3 -8
- package/src/platforms/instagram/client.ts +39 -34
- package/src/platforms/instagram/commands/auth.test.ts +13 -12
- package/src/platforms/instagram/commands/auth.ts +136 -71
- package/src/platforms/instagram/commands/chat.test.ts +21 -24
- package/src/platforms/instagram/commands/chat.ts +2 -0
- package/src/platforms/instagram/commands/message.test.ts +29 -24
- package/src/platforms/instagram/commands/message.ts +3 -4
- package/src/platforms/instagram/commands/shared.ts +2 -5
- package/src/platforms/instagram/commands/whoami.test.ts +4 -6
- package/src/platforms/instagram/credential-manager.ts +2 -6
- package/src/platforms/instagram/ensure-auth.test.ts +1 -4
- package/src/platforms/instagram/ensure-auth.ts +6 -3
- package/src/platforms/instagram/listener.test.ts +7 -3
- package/src/platforms/instagram/token-extractor.test.ts +4 -16
- package/src/platforms/instagram/token-extractor.ts +55 -309
- package/src/platforms/instagram/types.test.ts +2 -6
- package/src/platforms/instagram/types.ts +4 -2
- package/src/platforms/kakaotalk/auth/kakao-login.ts +30 -8
- package/src/platforms/kakaotalk/client.test.ts +37 -25
- package/src/platforms/kakaotalk/client.ts +23 -12
- package/src/platforms/kakaotalk/commands/auth.test.ts +6 -18
- package/src/platforms/kakaotalk/commands/auth.ts +101 -47
- package/src/platforms/kakaotalk/commands/chat.test.ts +8 -11
- package/src/platforms/kakaotalk/commands/message.test.ts +15 -24
- package/src/platforms/kakaotalk/commands/shared.ts +1 -0
- package/src/platforms/kakaotalk/commands/whoami.test.ts +6 -10
- package/src/platforms/kakaotalk/credential-manager.test.ts +1 -4
- package/src/platforms/kakaotalk/index.test.ts +1 -0
- package/src/platforms/kakaotalk/index.ts +0 -2
- package/src/platforms/kakaotalk/listener.test.ts +7 -1
- package/src/platforms/kakaotalk/protocol/connection.ts +4 -1
- package/src/platforms/kakaotalk/protocol/crypto.ts +1 -1
- package/src/platforms/kakaotalk/protocol/session.ts +12 -6
- package/src/platforms/kakaotalk/token-extractor.ts +5 -5
- package/src/platforms/kakaotalk/types.ts +8 -7
- package/src/platforms/line/cli.ts +1 -4
- package/src/platforms/line/client.ts +12 -20
- package/src/platforms/line/commands/auth.test.ts +2 -1
- package/src/platforms/line/commands/chat.test.ts +2 -1
- package/src/platforms/line/commands/chat.ts +1 -4
- package/src/platforms/line/commands/friend.test.ts +2 -1
- package/src/platforms/line/commands/message.test.ts +2 -1
- package/src/platforms/line/commands/message.ts +2 -9
- package/src/platforms/line/commands/whoami.test.ts +2 -1
- package/src/platforms/line/credential-manager.test.ts +1 -2
- package/src/platforms/line/index.test.ts +1 -0
- package/src/platforms/line/listener.ts +1 -1
- package/src/platforms/line/types.test.ts +1 -0
- package/src/platforms/slack/cli.ts +3 -1
- package/src/platforms/slack/client-mappers.ts +297 -0
- package/src/platforms/slack/client.test.ts +532 -17
- package/src/platforms/slack/client.ts +69 -458
- package/src/platforms/slack/commands/channel.ts +1 -4
- package/src/platforms/slack/commands/emoji.test.ts +6 -4
- package/src/platforms/slack/commands/emoji.ts +20 -22
- package/src/platforms/slack/commands/message.ts +6 -1
- package/src/platforms/slack/commands/pin.test.ts +14 -12
- package/src/platforms/slack/commands/reminder.ts +7 -6
- package/src/platforms/slack/commands/user.ts +6 -1
- package/src/platforms/slack/commands/usergroup.test.ts +3 -3
- package/src/platforms/slack/commands/usergroup.ts +10 -7
- package/src/platforms/slack/commands/whoami.test.ts +1 -1
- package/src/platforms/slack/commands/whoami.ts +2 -0
- package/src/platforms/slack/index.ts +0 -2
- package/src/platforms/slack/listener.test.ts +1 -0
- package/src/platforms/slack/token-extractor.test.ts +7 -12
- package/src/platforms/slack/token-extractor.ts +47 -255
- package/src/platforms/slackbot/cli.ts +8 -1
- package/src/platforms/slackbot/commands/auth.test.ts +3 -1
- package/src/platforms/teams/client.ts +1 -1
- package/src/platforms/teams/commands/auth.test.ts +1 -1
- package/src/platforms/teams/commands/auth.ts +4 -1
- package/src/platforms/teams/commands/whoami.test.ts +2 -4
- package/src/platforms/teams/commands/whoami.ts +2 -0
- package/src/platforms/teams/index.ts +0 -1
- package/src/platforms/teams/token-extractor.ts +82 -350
- package/src/platforms/telegram/app-config.test.ts +1 -0
- package/src/platforms/telegram/chat-utils.test.ts +5 -1
- package/src/platforms/telegram/cli.ts +2 -4
- package/src/platforms/telegram/client.test.ts +16 -3
- package/src/platforms/telegram/client.ts +14 -4
- package/src/platforms/telegram/commands/auth.test.ts +1 -0
- package/src/platforms/telegram/commands/auth.ts +3 -4
- package/src/platforms/telegram/commands/chat.test.ts +2 -5
- package/src/platforms/telegram/commands/chat.ts +1 -0
- package/src/platforms/telegram/commands/message.test.ts +2 -5
- package/src/platforms/telegram/commands/message.ts +1 -0
- package/src/platforms/telegram/commands/shared.test.ts +1 -0
- package/src/platforms/telegram/commands/whoami.test.ts +5 -7
- package/src/platforms/telegram/commands/whoami.ts +1 -1
- package/src/platforms/telegram/credential-manager.test.ts +1 -0
- package/src/platforms/telegram/credential-manager.ts +11 -2
- package/src/platforms/telegram/my-telegram-org.ts +6 -2
- package/src/platforms/telegram/types.test.ts +1 -0
- package/src/platforms/webex/app-config.test.ts +1 -0
- package/src/platforms/webex/cli.ts +1 -4
- package/src/platforms/webex/client.test.ts +4 -12
- package/src/platforms/webex/client.ts +14 -52
- package/src/platforms/webex/commands/auth.test.ts +7 -1
- package/src/platforms/webex/commands/auth.ts +12 -15
- package/src/platforms/webex/commands/member.test.ts +1 -3
- package/src/platforms/webex/commands/member.ts +14 -19
- package/src/platforms/webex/commands/message.ts +4 -15
- package/src/platforms/webex/commands/snapshot.test.ts +28 -3
- package/src/platforms/webex/commands/snapshot.ts +3 -3
- package/src/platforms/webex/commands/space.test.ts +3 -3
- package/src/platforms/webex/commands/space.ts +2 -9
- package/src/platforms/webex/commands/whoami.test.ts +12 -5
- package/src/platforms/webex/commands/whoami.ts +2 -0
- package/src/platforms/webex/credential-manager.ts +11 -2
- package/src/platforms/webex/ensure-auth.ts +1 -3
- package/src/platforms/webex/index.ts +1 -7
- package/src/platforms/webex/markdown-to-html.test.ts +6 -18
- package/src/platforms/webex/markdown-to-html.ts +8 -8
- package/src/platforms/webex/token-extractor.ts +6 -29
- package/src/platforms/wechatbot/client.test.ts +6 -2
- package/src/platforms/wechatbot/client.ts +6 -1
- package/src/platforms/wechatbot/commands/auth.test.ts +3 -7
- package/src/platforms/wechatbot/commands/message.test.ts +1 -4
- package/src/platforms/wechatbot/commands/message.ts +5 -1
- package/src/platforms/wechatbot/commands/template.test.ts +1 -4
- package/src/platforms/wechatbot/commands/user.test.ts +2 -7
- package/src/platforms/whatsapp/cli.ts +1 -4
- package/src/platforms/whatsapp/commands/auth.test.ts +19 -22
- package/src/platforms/whatsapp/commands/chat.test.ts +21 -24
- package/src/platforms/whatsapp/commands/chat.ts +2 -0
- package/src/platforms/whatsapp/commands/message.test.ts +22 -24
- package/src/platforms/whatsapp/commands/message.ts +3 -5
- package/src/platforms/whatsapp/commands/shared.ts +2 -5
- package/src/platforms/whatsapp/commands/whoami.test.ts +2 -2
- package/src/platforms/whatsapp/credential-manager.ts +2 -6
- package/src/platforms/whatsapp/ensure-auth.test.ts +1 -4
- package/src/platforms/whatsapp/ensure-auth.ts +14 -6
- package/src/platforms/whatsapp/index.ts +0 -2
- package/src/platforms/whatsappbot/client.test.ts +13 -7
- package/src/platforms/whatsappbot/client.ts +18 -4
- package/src/platforms/whatsappbot/commands/auth.ts +4 -1
- package/src/platforms/whatsappbot/commands/message.test.ts +12 -2
- package/src/platforms/whatsappbot/commands/message.ts +16 -3
- package/src/platforms/whatsappbot/commands/shared.ts +3 -1
- package/src/platforms/whatsappbot/commands/whoami.test.ts +1 -3
- package/src/platforms/whatsappbot/index.ts +0 -2
- package/src/shared/chromium/browsers.test.ts +274 -0
- package/src/shared/chromium/browsers.ts +86 -0
- package/src/shared/chromium/cookie-reader.test.ts +274 -0
- package/src/shared/chromium/cookie-reader.ts +111 -0
- package/src/shared/chromium/decryptor.test.ts +449 -0
- package/src/shared/chromium/decryptor.ts +227 -0
- package/src/shared/chromium/index.ts +11 -0
- package/src/shared/chromium/types.ts +11 -0
- package/src/shared/utils/derived-key-cache.ts +1 -1
- package/src/shared/utils/linux-keyring.ts +4 -4
- package/src/tui/adapters/kakaotalk-adapter.ts +6 -1
- package/src/tui/adapters/telegram-adapter.ts +1 -1
- package/src/tui/adapters/webex-adapter.ts +1 -1
- package/src/tui/app.ts +149 -59
- package/src/tui/utils.test.ts +144 -145
- package/src/tui/utils.ts +27 -29
- package/src/tui/views/channel-picker.ts +1 -1
- package/src/tui/views/workspace-picker.ts +1 -1
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { copyFileSync, existsSync, rmSync } from 'node:fs'
|
|
2
|
+
import { createRequire } from 'node:module'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
4
|
+
import { join } from 'node:path'
|
|
5
|
+
|
|
6
|
+
const require = createRequire(import.meta.url)
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Reads Chromium SQLite cookie databases with Bun/Node dual-runtime support.
|
|
10
|
+
* Copies the database to a temp file to avoid lock contention when the app is running.
|
|
11
|
+
*/
|
|
12
|
+
export class ChromiumCookieReader {
|
|
13
|
+
/**
|
|
14
|
+
* Copy SQLite DB to temp, run query, return all matching rows, cleanup.
|
|
15
|
+
* Returns empty array if db doesn't exist or query fails.
|
|
16
|
+
*/
|
|
17
|
+
async queryAll<T>(dbPath: string, sql: string, params?: unknown[]): Promise<T[]> {
|
|
18
|
+
if (!existsSync(dbPath)) return []
|
|
19
|
+
|
|
20
|
+
const tempPath = this.createTempPath()
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
copyFileSync(dbPath, tempPath)
|
|
24
|
+
} catch {
|
|
25
|
+
return []
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
return this.executeQuery<T>(tempPath, sql, params, 'all')
|
|
30
|
+
} catch {
|
|
31
|
+
return []
|
|
32
|
+
} finally {
|
|
33
|
+
this.cleanupTemp(tempPath)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Copy SQLite DB to temp, run query, return first matching row, cleanup.
|
|
39
|
+
* Returns null if db doesn't exist, no rows match, or query fails.
|
|
40
|
+
*/
|
|
41
|
+
async queryFirst<T>(dbPath: string, sql: string, params?: unknown[]): Promise<T | null> {
|
|
42
|
+
if (!existsSync(dbPath)) return null
|
|
43
|
+
|
|
44
|
+
const tempPath = this.createTempPath()
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
copyFileSync(dbPath, tempPath)
|
|
48
|
+
} catch {
|
|
49
|
+
return null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
return this.executeQuery<T>(tempPath, sql, params, 'first')
|
|
54
|
+
} catch {
|
|
55
|
+
return null
|
|
56
|
+
} finally {
|
|
57
|
+
this.cleanupTemp(tempPath)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private createTempPath(): string {
|
|
62
|
+
return join(tmpdir(), `chromium-cookies-${Date.now()}-${Math.random().toString(36).slice(2)}.db`)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private executeQuery<T>(tempPath: string, sql: string, params: unknown[] | undefined, mode: 'all'): T[]
|
|
66
|
+
private executeQuery<T>(tempPath: string, sql: string, params: unknown[] | undefined, mode: 'first'): T | null
|
|
67
|
+
private executeQuery<T>(
|
|
68
|
+
tempPath: string,
|
|
69
|
+
sql: string,
|
|
70
|
+
params: unknown[] | undefined,
|
|
71
|
+
mode: 'all' | 'first',
|
|
72
|
+
): T[] | T | null {
|
|
73
|
+
if (typeof globalThis.Bun !== 'undefined') {
|
|
74
|
+
const { Database } = require('bun:sqlite')
|
|
75
|
+
const db = new Database(tempPath, { readonly: true })
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
const stmt = db.query(sql)
|
|
79
|
+
if (mode === 'all') {
|
|
80
|
+
return (params ? stmt.all(...params) : stmt.all()) as T[]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return (params ? stmt.get(...params) : stmt.get()) as T | null
|
|
84
|
+
} finally {
|
|
85
|
+
db.close()
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const Database = require('better-sqlite3')
|
|
90
|
+
const db = new Database(tempPath, { readonly: true })
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const stmt = db.prepare(sql)
|
|
94
|
+
if (mode === 'all') {
|
|
95
|
+
return (params ? stmt.all(...params) : stmt.all()) as T[]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return (params ? stmt.get(...params) : stmt.get()) as T | null
|
|
99
|
+
} finally {
|
|
100
|
+
db.close()
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private cleanupTemp(tempPath: string): void {
|
|
105
|
+
try {
|
|
106
|
+
rmSync(tempPath, { force: true })
|
|
107
|
+
} catch {
|
|
108
|
+
// Temp file cleanup failure is non-critical
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, spyOn, test } from 'bun:test'
|
|
2
|
+
import { createCipheriv, pbkdf2Sync, randomBytes } from 'node:crypto'
|
|
3
|
+
|
|
4
|
+
import * as linuxKeyring from '@/shared/utils/linux-keyring'
|
|
5
|
+
|
|
6
|
+
import { BROWSER_KEYCHAIN_VARIANTS } from './browsers'
|
|
7
|
+
import { ChromiumCookieDecryptor } from './decryptor'
|
|
8
|
+
|
|
9
|
+
function encryptAESCBC(value: string, key: Buffer, prefix = 'v10'): Buffer {
|
|
10
|
+
const iv = Buffer.alloc(16, 0x20)
|
|
11
|
+
const cipher = createCipheriv('aes-128-cbc', key, iv)
|
|
12
|
+
const ciphertext = Buffer.concat([cipher.update(value, 'utf8'), cipher.final()])
|
|
13
|
+
return Buffer.concat([Buffer.from(prefix), ciphertext])
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function encryptAESGCM(value: string, key: Buffer, prefix = 'v10'): Buffer {
|
|
17
|
+
const iv = randomBytes(12)
|
|
18
|
+
const cipher = createCipheriv('aes-256-gcm', key, iv)
|
|
19
|
+
const ciphertext = Buffer.concat([cipher.update(value, 'utf8'), cipher.final()])
|
|
20
|
+
const authTag = cipher.getAuthTag()
|
|
21
|
+
return Buffer.concat([Buffer.from(prefix), iv, ciphertext, authTag])
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe('ChromiumCookieDecryptor', () => {
|
|
25
|
+
let peanutsKey: Buffer
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
peanutsKey = pbkdf2Sync('peanuts', 'saltysalt', 1, 16, 'sha1')
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
describe('constructor', () => {
|
|
32
|
+
test('prepends appKeychainVariants before browser variants', () => {
|
|
33
|
+
// given
|
|
34
|
+
const appVariants = [{ service: 'App Safe Storage', account: 'App' }]
|
|
35
|
+
|
|
36
|
+
// when
|
|
37
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'darwin', appKeychainVariants: appVariants })
|
|
38
|
+
|
|
39
|
+
// then
|
|
40
|
+
expect((decryptor as any).keychainVariants).toEqual([...appVariants, ...BROWSER_KEYCHAIN_VARIANTS])
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('uses only browser variants when no appKeychainVariants provided', () => {
|
|
44
|
+
// given
|
|
45
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'darwin' })
|
|
46
|
+
|
|
47
|
+
// then
|
|
48
|
+
expect((decryptor as any).keychainVariants).toEqual(BROWSER_KEYCHAIN_VARIANTS)
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe('isEncryptedValue', () => {
|
|
53
|
+
test('returns true for v10 prefix with sufficient length', () => {
|
|
54
|
+
// given
|
|
55
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
56
|
+
|
|
57
|
+
// when
|
|
58
|
+
const result = decryptor.isEncryptedValue(Buffer.from('v10x'))
|
|
59
|
+
|
|
60
|
+
// then
|
|
61
|
+
expect(result).toBe(true)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('returns true for v11 prefix with sufficient length', () => {
|
|
65
|
+
// given
|
|
66
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
67
|
+
|
|
68
|
+
// when
|
|
69
|
+
const result = decryptor.isEncryptedValue(Buffer.from('v11x'))
|
|
70
|
+
|
|
71
|
+
// then
|
|
72
|
+
expect(result).toBe(true)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
test('returns false for non-v10/v11 prefix', () => {
|
|
76
|
+
// given
|
|
77
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
78
|
+
|
|
79
|
+
// when
|
|
80
|
+
const result = decryptor.isEncryptedValue(Buffer.from('abcde'))
|
|
81
|
+
|
|
82
|
+
// then
|
|
83
|
+
expect(result).toBe(false)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
test('returns false for too-short buffer (< 4 bytes)', () => {
|
|
87
|
+
// given
|
|
88
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
89
|
+
|
|
90
|
+
// when
|
|
91
|
+
const result = decryptor.isEncryptedValue(Buffer.from('v10'))
|
|
92
|
+
|
|
93
|
+
// then
|
|
94
|
+
expect(result).toBe(false)
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
test('returns false for null/empty buffer', () => {
|
|
98
|
+
// given
|
|
99
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
100
|
+
|
|
101
|
+
// when/then
|
|
102
|
+
expect(decryptor.isEncryptedValue(Buffer.alloc(0))).toBe(false)
|
|
103
|
+
expect(decryptor.isEncryptedValue(null as unknown as Buffer)).toBe(false)
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
describe('decryptAESCBC / decryptAESCBCRaw', () => {
|
|
108
|
+
test('decrypts v10-prefixed AES-128-CBC data with correct key', () => {
|
|
109
|
+
// given
|
|
110
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
111
|
+
const encrypted = encryptAESCBC('test-value', peanutsKey)
|
|
112
|
+
|
|
113
|
+
// when
|
|
114
|
+
const result = decryptor.decryptAESCBC(encrypted, peanutsKey)
|
|
115
|
+
|
|
116
|
+
// then
|
|
117
|
+
expect(result).toBe('test-value')
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
test('returns null with wrong key', () => {
|
|
121
|
+
// given
|
|
122
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
123
|
+
const encrypted = encryptAESCBC('test-value', peanutsKey)
|
|
124
|
+
const wrongKey = pbkdf2Sync('wrong-password', 'saltysalt', 1, 16, 'sha1')
|
|
125
|
+
|
|
126
|
+
// when
|
|
127
|
+
const result = decryptor.decryptAESCBC(encrypted, wrongKey)
|
|
128
|
+
|
|
129
|
+
// then
|
|
130
|
+
expect(result).toBeNull()
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
test('returns null for corrupted ciphertext', () => {
|
|
134
|
+
// given
|
|
135
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
136
|
+
const encrypted = encryptAESCBC('test-value', peanutsKey)
|
|
137
|
+
const corrupted = Buffer.from(encrypted)
|
|
138
|
+
corrupted[corrupted.length - 1] ^= 0xff
|
|
139
|
+
|
|
140
|
+
// when
|
|
141
|
+
const result = decryptor.decryptAESCBC(corrupted, peanutsKey)
|
|
142
|
+
|
|
143
|
+
// then
|
|
144
|
+
expect(result).toBeNull()
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
test('decryptAESCBC returns string, decryptAESCBCRaw returns Buffer', () => {
|
|
148
|
+
// given
|
|
149
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
150
|
+
const encrypted = encryptAESCBC('test-value', peanutsKey)
|
|
151
|
+
|
|
152
|
+
// when
|
|
153
|
+
const stringResult = decryptor.decryptAESCBC(encrypted, peanutsKey)
|
|
154
|
+
const rawResult = decryptor.decryptAESCBCRaw(encrypted, peanutsKey)
|
|
155
|
+
|
|
156
|
+
// then
|
|
157
|
+
expect(stringResult).toBe('test-value')
|
|
158
|
+
expect(rawResult).toEqual(Buffer.from('test-value'))
|
|
159
|
+
})
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
describe('decryptAESGCM / decryptAESGCMRaw', () => {
|
|
163
|
+
test('decrypts v10-prefixed AES-256-GCM data with correct key', () => {
|
|
164
|
+
// given
|
|
165
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'win32' })
|
|
166
|
+
const masterKey = randomBytes(32)
|
|
167
|
+
const encrypted = encryptAESGCM('test-value', masterKey)
|
|
168
|
+
|
|
169
|
+
// when
|
|
170
|
+
const result = decryptor.decryptAESGCM(encrypted, masterKey)
|
|
171
|
+
|
|
172
|
+
// then
|
|
173
|
+
expect(result).toBe('test-value')
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
test('returns null with wrong key', () => {
|
|
177
|
+
// given
|
|
178
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'win32' })
|
|
179
|
+
const masterKey = randomBytes(32)
|
|
180
|
+
const encrypted = encryptAESGCM('test-value', masterKey)
|
|
181
|
+
|
|
182
|
+
// when
|
|
183
|
+
const result = decryptor.decryptAESGCM(encrypted, randomBytes(32))
|
|
184
|
+
|
|
185
|
+
// then
|
|
186
|
+
expect(result).toBeNull()
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
test('returns null for data shorter than minimum length (3+12+16 = 31 bytes)', () => {
|
|
190
|
+
// given
|
|
191
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'win32' })
|
|
192
|
+
|
|
193
|
+
// when
|
|
194
|
+
const result = decryptor.decryptAESGCM(Buffer.alloc(30), randomBytes(32))
|
|
195
|
+
|
|
196
|
+
// then
|
|
197
|
+
expect(result).toBeNull()
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
test('decryptAESGCM returns string, decryptAESGCMRaw returns Buffer', () => {
|
|
201
|
+
// given
|
|
202
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'win32' })
|
|
203
|
+
const masterKey = randomBytes(32)
|
|
204
|
+
const encrypted = encryptAESGCM('test-value', masterKey)
|
|
205
|
+
|
|
206
|
+
// when
|
|
207
|
+
const stringResult = decryptor.decryptAESGCM(encrypted, masterKey)
|
|
208
|
+
const rawResult = decryptor.decryptAESGCMRaw(encrypted, masterKey)
|
|
209
|
+
|
|
210
|
+
// then
|
|
211
|
+
expect(stringResult).toBe('test-value')
|
|
212
|
+
expect(rawResult).toEqual(Buffer.from('test-value'))
|
|
213
|
+
})
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
describe('decryptCookie / decryptCookieRaw', () => {
|
|
217
|
+
test('returns plaintext for non-encrypted values (no v10/v11 prefix)', () => {
|
|
218
|
+
// given
|
|
219
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
220
|
+
const plaintext = Buffer.from('plain-cookie')
|
|
221
|
+
|
|
222
|
+
// when
|
|
223
|
+
const stringResult = decryptor.decryptCookie(plaintext)
|
|
224
|
+
const rawResult = decryptor.decryptCookieRaw(plaintext)
|
|
225
|
+
|
|
226
|
+
// then
|
|
227
|
+
expect(stringResult).toBe('plain-cookie')
|
|
228
|
+
expect(rawResult).toEqual(plaintext)
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
test('dispatches to Linux decryption for linux platform with v10 prefix', () => {
|
|
232
|
+
// given
|
|
233
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
234
|
+
const encrypted = Buffer.from('v10cookie')
|
|
235
|
+
const spy = spyOn(decryptor, 'decryptLinuxCookieRaw')
|
|
236
|
+
|
|
237
|
+
// when
|
|
238
|
+
decryptor.decryptCookieRaw(encrypted)
|
|
239
|
+
|
|
240
|
+
// then
|
|
241
|
+
expect(spy).toHaveBeenCalledWith(encrypted)
|
|
242
|
+
spy.mockRestore()
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
test('returns null for unsupported platform (e.g. freebsd)', () => {
|
|
246
|
+
// given
|
|
247
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'freebsd' as NodeJS.Platform })
|
|
248
|
+
|
|
249
|
+
// when
|
|
250
|
+
const result = decryptor.decryptCookie(Buffer.from('v10cookie'))
|
|
251
|
+
|
|
252
|
+
// then
|
|
253
|
+
expect(result).toBeNull()
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
test('decryptCookie returns string, decryptCookieRaw returns Buffer', () => {
|
|
257
|
+
// given
|
|
258
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
259
|
+
const encrypted = encryptAESCBC('test-value', peanutsKey)
|
|
260
|
+
|
|
261
|
+
// when
|
|
262
|
+
const stringResult = decryptor.decryptCookie(encrypted)
|
|
263
|
+
const rawResult = decryptor.decryptCookieRaw(encrypted)
|
|
264
|
+
|
|
265
|
+
// then
|
|
266
|
+
expect(stringResult).toBe('test-value')
|
|
267
|
+
expect(rawResult).toEqual(Buffer.from('test-value'))
|
|
268
|
+
})
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
describe('decryptLinuxCookieRaw', () => {
|
|
272
|
+
test('decrypts v10-prefixed cookie using peanuts key (known key, verifiable)', () => {
|
|
273
|
+
// given
|
|
274
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
275
|
+
const encrypted = encryptAESCBC('linux-cookie', peanutsKey)
|
|
276
|
+
|
|
277
|
+
// when
|
|
278
|
+
const result = decryptor.decryptLinuxCookieRaw(encrypted)
|
|
279
|
+
|
|
280
|
+
// then
|
|
281
|
+
expect(result).toEqual(Buffer.from('linux-cookie'))
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
test('falls back to peanuts key for v11 when no keyring app names configured', () => {
|
|
285
|
+
// given
|
|
286
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
287
|
+
const encrypted = encryptAESCBC('linux-v11-cookie', peanutsKey, 'v11')
|
|
288
|
+
|
|
289
|
+
// when
|
|
290
|
+
const result = decryptor.decryptLinuxCookieRaw(encrypted)
|
|
291
|
+
|
|
292
|
+
// then
|
|
293
|
+
expect(result).toEqual(Buffer.from('linux-v11-cookie'))
|
|
294
|
+
})
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
describe('decryptDPAPI', () => {
|
|
298
|
+
test('returns null on non-win32 platforms', () => {
|
|
299
|
+
// given
|
|
300
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
301
|
+
|
|
302
|
+
// when
|
|
303
|
+
const result = decryptor.decryptDPAPI(Buffer.from('encrypted'))
|
|
304
|
+
|
|
305
|
+
// then
|
|
306
|
+
expect(result).toBeNull()
|
|
307
|
+
})
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
describe('stripIntegrityHash', () => {
|
|
311
|
+
test('returns input unchanged when length <= 32', () => {
|
|
312
|
+
// given
|
|
313
|
+
const decrypted = Buffer.alloc(32, 0x41)
|
|
314
|
+
|
|
315
|
+
// when
|
|
316
|
+
const result = ChromiumCookieDecryptor.stripIntegrityHash(decrypted)
|
|
317
|
+
|
|
318
|
+
// then
|
|
319
|
+
expect(result).toEqual(decrypted)
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
test('strips first 32 bytes when they contain non-printable characters', () => {
|
|
323
|
+
// given
|
|
324
|
+
const hash = Buffer.concat([Buffer.from([0x00, 0x1f, 0xff]), Buffer.alloc(29, 0x01)])
|
|
325
|
+
const value = Buffer.from('cookie-value')
|
|
326
|
+
|
|
327
|
+
// when
|
|
328
|
+
const result = ChromiumCookieDecryptor.stripIntegrityHash(Buffer.concat([hash, value]))
|
|
329
|
+
|
|
330
|
+
// then
|
|
331
|
+
expect(result).toEqual(value)
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
test('returns input unchanged when first 32 bytes are all printable ASCII', () => {
|
|
335
|
+
// given
|
|
336
|
+
const printablePrefix = Buffer.from('12345678901234567890123456789012')
|
|
337
|
+
const decrypted = Buffer.concat([printablePrefix, Buffer.from('cookie-value')])
|
|
338
|
+
|
|
339
|
+
// when
|
|
340
|
+
const result = ChromiumCookieDecryptor.stripIntegrityHash(decrypted)
|
|
341
|
+
|
|
342
|
+
// then
|
|
343
|
+
expect(result).toEqual(decrypted)
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
test('correctly strips binary hash prefix followed by readable cookie value', () => {
|
|
347
|
+
// given
|
|
348
|
+
const hash = randomBytes(32)
|
|
349
|
+
const value = Buffer.from('readable-cookie-value')
|
|
350
|
+
|
|
351
|
+
// when
|
|
352
|
+
const result = ChromiumCookieDecryptor.stripIntegrityHash(Buffer.concat([hash, value]))
|
|
353
|
+
|
|
354
|
+
// then
|
|
355
|
+
expect(result).toEqual(value)
|
|
356
|
+
})
|
|
357
|
+
|
|
358
|
+
test('handles non-printable bytes that would be mangled by UTF-8 conversion (the v130+ fix)', () => {
|
|
359
|
+
// given
|
|
360
|
+
const binaryPrefix = Buffer.from([
|
|
361
|
+
...Array.from({ length: 16 }, (_, i) => i),
|
|
362
|
+
...Array.from({ length: 16 }, (_, i) => 0x80 + i),
|
|
363
|
+
])
|
|
364
|
+
const value = Buffer.from('v130-cookie-value')
|
|
365
|
+
|
|
366
|
+
// when
|
|
367
|
+
const result = ChromiumCookieDecryptor.stripIntegrityHash(Buffer.concat([binaryPrefix, value]))
|
|
368
|
+
|
|
369
|
+
// then
|
|
370
|
+
expect(result).toEqual(value)
|
|
371
|
+
})
|
|
372
|
+
})
|
|
373
|
+
|
|
374
|
+
describe('loadCachedKey / clearKeyCache', () => {
|
|
375
|
+
test('loadCachedKey is no-op on non-darwin platform', async () => {
|
|
376
|
+
// given
|
|
377
|
+
const keyCache = {
|
|
378
|
+
get: async () => Buffer.from('should-not-be-used'),
|
|
379
|
+
clear: async () => {},
|
|
380
|
+
}
|
|
381
|
+
const decryptor = new ChromiumCookieDecryptor({
|
|
382
|
+
platform: 'linux',
|
|
383
|
+
keyCache: keyCache as any,
|
|
384
|
+
keyCachePlatform: 'slack',
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
// when
|
|
388
|
+
await decryptor.loadCachedKey()
|
|
389
|
+
|
|
390
|
+
// then
|
|
391
|
+
expect((decryptor as any).cachedKey).toBeNull()
|
|
392
|
+
expect((decryptor as any).usedCachedKey).toBe(false)
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
test('loadCachedKey is no-op when no keyCache configured', async () => {
|
|
396
|
+
// given
|
|
397
|
+
const decryptor = new ChromiumCookieDecryptor({ platform: 'darwin', keyCachePlatform: 'slack' })
|
|
398
|
+
|
|
399
|
+
// when
|
|
400
|
+
await decryptor.loadCachedKey()
|
|
401
|
+
|
|
402
|
+
// then
|
|
403
|
+
expect((decryptor as any).cachedKey).toBeNull()
|
|
404
|
+
expect((decryptor as any).usedCachedKey).toBe(false)
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
test('clearKeyCache resets cached key state', async () => {
|
|
408
|
+
// given
|
|
409
|
+
const clear = async () => {}
|
|
410
|
+
const keyCache = { get: async () => null, clear }
|
|
411
|
+
const decryptor = new ChromiumCookieDecryptor({
|
|
412
|
+
platform: 'darwin',
|
|
413
|
+
keyCache: keyCache as any,
|
|
414
|
+
keyCachePlatform: 'slack',
|
|
415
|
+
})
|
|
416
|
+
;(decryptor as any).cachedKey = Buffer.from('cached-key')
|
|
417
|
+
;(decryptor as any).usedCachedKey = true
|
|
418
|
+
|
|
419
|
+
// when
|
|
420
|
+
await decryptor.clearKeyCache()
|
|
421
|
+
|
|
422
|
+
// then
|
|
423
|
+
expect((decryptor as any).cachedKey).toBeNull()
|
|
424
|
+
expect((decryptor as any).usedCachedKey).toBe(false)
|
|
425
|
+
})
|
|
426
|
+
})
|
|
427
|
+
|
|
428
|
+
describe('linux v11 keyring behavior', () => {
|
|
429
|
+
test('uses configured keyring password before falling back', () => {
|
|
430
|
+
// given
|
|
431
|
+
const password = 'secret-from-keyring'
|
|
432
|
+
const key = pbkdf2Sync(password, 'saltysalt', 1, 16, 'sha1')
|
|
433
|
+
const spy = spyOn(linuxKeyring, 'lookupLinuxKeyringPassword').mockImplementation(() => password)
|
|
434
|
+
const decryptor = new ChromiumCookieDecryptor({
|
|
435
|
+
platform: 'linux',
|
|
436
|
+
linuxKeyringAppNames: ['Discord'],
|
|
437
|
+
})
|
|
438
|
+
const encrypted = encryptAESCBC('linux-keyring-cookie', key, 'v11')
|
|
439
|
+
|
|
440
|
+
// when
|
|
441
|
+
const result = decryptor.decryptLinuxCookieRaw(encrypted)
|
|
442
|
+
|
|
443
|
+
// then
|
|
444
|
+
expect(spy).toHaveBeenCalledWith('Discord')
|
|
445
|
+
expect(result).toEqual(Buffer.from('linux-keyring-cookie'))
|
|
446
|
+
spy.mockRestore()
|
|
447
|
+
})
|
|
448
|
+
})
|
|
449
|
+
})
|