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.
Files changed (511) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.github/workflows/ci.yml +6 -0
  3. package/.oxfmtrc.json +13 -1
  4. package/.oxlintrc.json +10 -1
  5. package/README.md +1 -1
  6. package/dist/package.json +59 -58
  7. package/dist/src/platforms/channeltalk/client.d.ts.map +1 -1
  8. package/dist/src/platforms/channeltalk/client.js +2 -2
  9. package/dist/src/platforms/channeltalk/client.js.map +1 -1
  10. package/dist/src/platforms/channeltalk/commands/auth.d.ts.map +1 -1
  11. package/dist/src/platforms/channeltalk/commands/auth.js.map +1 -1
  12. package/dist/src/platforms/channeltalk/commands/message.d.ts.map +1 -1
  13. package/dist/src/platforms/channeltalk/commands/message.js.map +1 -1
  14. package/dist/src/platforms/channeltalk/commands/snapshot.d.ts.map +1 -1
  15. package/dist/src/platforms/channeltalk/commands/snapshot.js.map +1 -1
  16. package/dist/src/platforms/channeltalk/ensure-auth.d.ts.map +1 -1
  17. package/dist/src/platforms/channeltalk/ensure-auth.js.map +1 -1
  18. package/dist/src/platforms/channeltalk/token-extractor.d.ts +9 -23
  19. package/dist/src/platforms/channeltalk/token-extractor.d.ts.map +1 -1
  20. package/dist/src/platforms/channeltalk/token-extractor.js +109 -341
  21. package/dist/src/platforms/channeltalk/token-extractor.js.map +1 -1
  22. package/dist/src/platforms/channeltalkbot/client.d.ts +1 -1
  23. package/dist/src/platforms/channeltalkbot/client.d.ts.map +1 -1
  24. package/dist/src/platforms/channeltalkbot/client.js +4 -4
  25. package/dist/src/platforms/channeltalkbot/client.js.map +1 -1
  26. package/dist/src/platforms/channeltalkbot/commands/auth.d.ts.map +1 -1
  27. package/dist/src/platforms/channeltalkbot/commands/auth.js +4 -1
  28. package/dist/src/platforms/channeltalkbot/commands/auth.js.map +1 -1
  29. package/dist/src/platforms/channeltalkbot/commands/shared.d.ts.map +1 -1
  30. package/dist/src/platforms/channeltalkbot/commands/shared.js.map +1 -1
  31. package/dist/src/platforms/discord/commands/auth.js.map +1 -1
  32. package/dist/src/platforms/discord/commands/whoami.d.ts.map +1 -1
  33. package/dist/src/platforms/discord/commands/whoami.js.map +1 -1
  34. package/dist/src/platforms/discord/token-extractor.d.ts +2 -10
  35. package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
  36. package/dist/src/platforms/discord/token-extractor.js +38 -172
  37. package/dist/src/platforms/discord/token-extractor.js.map +1 -1
  38. package/dist/src/platforms/discordbot/client.d.ts.map +1 -1
  39. package/dist/src/platforms/discordbot/client.js.map +1 -1
  40. package/dist/src/platforms/instagram/cli.d.ts.map +1 -1
  41. package/dist/src/platforms/instagram/cli.js +1 -4
  42. package/dist/src/platforms/instagram/cli.js.map +1 -1
  43. package/dist/src/platforms/instagram/client.d.ts.map +1 -1
  44. package/dist/src/platforms/instagram/client.js +8 -7
  45. package/dist/src/platforms/instagram/client.js.map +1 -1
  46. package/dist/src/platforms/instagram/commands/auth.d.ts.map +1 -1
  47. package/dist/src/platforms/instagram/commands/auth.js.map +1 -1
  48. package/dist/src/platforms/instagram/commands/chat.d.ts.map +1 -1
  49. package/dist/src/platforms/instagram/commands/chat.js.map +1 -1
  50. package/dist/src/platforms/instagram/commands/message.d.ts.map +1 -1
  51. package/dist/src/platforms/instagram/commands/message.js.map +1 -1
  52. package/dist/src/platforms/instagram/commands/shared.d.ts.map +1 -1
  53. package/dist/src/platforms/instagram/commands/shared.js.map +1 -1
  54. package/dist/src/platforms/instagram/credential-manager.d.ts.map +1 -1
  55. package/dist/src/platforms/instagram/credential-manager.js +1 -1
  56. package/dist/src/platforms/instagram/credential-manager.js.map +1 -1
  57. package/dist/src/platforms/instagram/ensure-auth.d.ts.map +1 -1
  58. package/dist/src/platforms/instagram/ensure-auth.js.map +1 -1
  59. package/dist/src/platforms/instagram/token-extractor.d.ts +7 -19
  60. package/dist/src/platforms/instagram/token-extractor.d.ts.map +1 -1
  61. package/dist/src/platforms/instagram/token-extractor.js +44 -270
  62. package/dist/src/platforms/instagram/token-extractor.js.map +1 -1
  63. package/dist/src/platforms/instagram/types.d.ts.map +1 -1
  64. package/dist/src/platforms/instagram/types.js +4 -2
  65. package/dist/src/platforms/instagram/types.js.map +1 -1
  66. package/dist/src/platforms/kakaotalk/auth/kakao-login.d.ts.map +1 -1
  67. package/dist/src/platforms/kakaotalk/auth/kakao-login.js +18 -4
  68. package/dist/src/platforms/kakaotalk/auth/kakao-login.js.map +1 -1
  69. package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
  70. package/dist/src/platforms/kakaotalk/client.js +3 -3
  71. package/dist/src/platforms/kakaotalk/client.js.map +1 -1
  72. package/dist/src/platforms/kakaotalk/commands/auth.d.ts.map +1 -1
  73. package/dist/src/platforms/kakaotalk/commands/auth.js +15 -9
  74. package/dist/src/platforms/kakaotalk/commands/auth.js.map +1 -1
  75. package/dist/src/platforms/kakaotalk/commands/shared.d.ts.map +1 -1
  76. package/dist/src/platforms/kakaotalk/commands/shared.js.map +1 -1
  77. package/dist/src/platforms/kakaotalk/protocol/connection.d.ts.map +1 -1
  78. package/dist/src/platforms/kakaotalk/protocol/connection.js.map +1 -1
  79. package/dist/src/platforms/kakaotalk/protocol/crypto.js +1 -1
  80. package/dist/src/platforms/kakaotalk/protocol/crypto.js.map +1 -1
  81. package/dist/src/platforms/kakaotalk/protocol/session.d.ts.map +1 -1
  82. package/dist/src/platforms/kakaotalk/protocol/session.js +1 -3
  83. package/dist/src/platforms/kakaotalk/protocol/session.js.map +1 -1
  84. package/dist/src/platforms/kakaotalk/token-extractor.js +5 -2
  85. package/dist/src/platforms/kakaotalk/token-extractor.js.map +1 -1
  86. package/dist/src/platforms/kakaotalk/types.d.ts.map +1 -1
  87. package/dist/src/platforms/kakaotalk/types.js +4 -2
  88. package/dist/src/platforms/kakaotalk/types.js.map +1 -1
  89. package/dist/src/platforms/line/cli.d.ts.map +1 -1
  90. package/dist/src/platforms/line/cli.js +1 -4
  91. package/dist/src/platforms/line/cli.js.map +1 -1
  92. package/dist/src/platforms/line/client.d.ts.map +1 -1
  93. package/dist/src/platforms/line/client.js +5 -13
  94. package/dist/src/platforms/line/client.js.map +1 -1
  95. package/dist/src/platforms/line/commands/chat.d.ts.map +1 -1
  96. package/dist/src/platforms/line/commands/chat.js.map +1 -1
  97. package/dist/src/platforms/line/commands/message.d.ts.map +1 -1
  98. package/dist/src/platforms/line/commands/message.js.map +1 -1
  99. package/dist/src/platforms/line/listener.js +1 -1
  100. package/dist/src/platforms/line/listener.js.map +1 -1
  101. package/dist/src/platforms/slack/cli.d.ts.map +1 -1
  102. package/dist/src/platforms/slack/cli.js.map +1 -1
  103. package/dist/src/platforms/slack/client-mappers.d.ts +14 -0
  104. package/dist/src/platforms/slack/client-mappers.d.ts.map +1 -0
  105. package/dist/src/platforms/slack/client-mappers.js +245 -0
  106. package/dist/src/platforms/slack/client-mappers.js.map +1 -0
  107. package/dist/src/platforms/slack/client.d.ts +0 -1
  108. package/dist/src/platforms/slack/client.d.ts.map +1 -1
  109. package/dist/src/platforms/slack/client.js +41 -455
  110. package/dist/src/platforms/slack/client.js.map +1 -1
  111. package/dist/src/platforms/slack/commands/channel.d.ts.map +1 -1
  112. package/dist/src/platforms/slack/commands/channel.js.map +1 -1
  113. package/dist/src/platforms/slack/commands/emoji.d.ts.map +1 -1
  114. package/dist/src/platforms/slack/commands/emoji.js +1 -3
  115. package/dist/src/platforms/slack/commands/emoji.js.map +1 -1
  116. package/dist/src/platforms/slack/commands/message.d.ts.map +1 -1
  117. package/dist/src/platforms/slack/commands/message.js.map +1 -1
  118. package/dist/src/platforms/slack/commands/reminder.d.ts.map +1 -1
  119. package/dist/src/platforms/slack/commands/reminder.js.map +1 -1
  120. package/dist/src/platforms/slack/commands/user.d.ts.map +1 -1
  121. package/dist/src/platforms/slack/commands/user.js.map +1 -1
  122. package/dist/src/platforms/slack/commands/usergroup.d.ts.map +1 -1
  123. package/dist/src/platforms/slack/commands/usergroup.js.map +1 -1
  124. package/dist/src/platforms/slack/commands/whoami.d.ts.map +1 -1
  125. package/dist/src/platforms/slack/commands/whoami.js.map +1 -1
  126. package/dist/src/platforms/slack/token-extractor.d.ts +2 -6
  127. package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
  128. package/dist/src/platforms/slack/token-extractor.js +35 -229
  129. package/dist/src/platforms/slack/token-extractor.js.map +1 -1
  130. package/dist/src/platforms/slackbot/cli.d.ts.map +1 -1
  131. package/dist/src/platforms/slackbot/cli.js +1 -1
  132. package/dist/src/platforms/slackbot/cli.js.map +1 -1
  133. package/dist/src/platforms/teams/client.d.ts.map +1 -1
  134. package/dist/src/platforms/teams/client.js +1 -1
  135. package/dist/src/platforms/teams/client.js.map +1 -1
  136. package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
  137. package/dist/src/platforms/teams/commands/auth.js +4 -1
  138. package/dist/src/platforms/teams/commands/auth.js.map +1 -1
  139. package/dist/src/platforms/teams/commands/whoami.d.ts.map +1 -1
  140. package/dist/src/platforms/teams/commands/whoami.js.map +1 -1
  141. package/dist/src/platforms/teams/token-extractor.d.ts +6 -18
  142. package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
  143. package/dist/src/platforms/teams/token-extractor.js +71 -324
  144. package/dist/src/platforms/teams/token-extractor.js.map +1 -1
  145. package/dist/src/platforms/telegram/cli.d.ts.map +1 -1
  146. package/dist/src/platforms/telegram/cli.js +1 -4
  147. package/dist/src/platforms/telegram/cli.js.map +1 -1
  148. package/dist/src/platforms/telegram/client.d.ts.map +1 -1
  149. package/dist/src/platforms/telegram/client.js.map +1 -1
  150. package/dist/src/platforms/telegram/commands/auth.d.ts.map +1 -1
  151. package/dist/src/platforms/telegram/commands/auth.js +1 -1
  152. package/dist/src/platforms/telegram/commands/auth.js.map +1 -1
  153. package/dist/src/platforms/telegram/commands/chat.d.ts.map +1 -1
  154. package/dist/src/platforms/telegram/commands/chat.js.map +1 -1
  155. package/dist/src/platforms/telegram/commands/message.d.ts.map +1 -1
  156. package/dist/src/platforms/telegram/commands/message.js.map +1 -1
  157. package/dist/src/platforms/telegram/commands/whoami.js +1 -1
  158. package/dist/src/platforms/telegram/commands/whoami.js.map +1 -1
  159. package/dist/src/platforms/telegram/credential-manager.d.ts.map +1 -1
  160. package/dist/src/platforms/telegram/credential-manager.js +6 -2
  161. package/dist/src/platforms/telegram/credential-manager.js.map +1 -1
  162. package/dist/src/platforms/telegram/my-telegram-org.js.map +1 -1
  163. package/dist/src/platforms/webex/cli.d.ts.map +1 -1
  164. package/dist/src/platforms/webex/cli.js +1 -4
  165. package/dist/src/platforms/webex/cli.js.map +1 -1
  166. package/dist/src/platforms/webex/client.d.ts.map +1 -1
  167. package/dist/src/platforms/webex/client.js +3 -7
  168. package/dist/src/platforms/webex/client.js.map +1 -1
  169. package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
  170. package/dist/src/platforms/webex/commands/auth.js +1 -3
  171. package/dist/src/platforms/webex/commands/auth.js.map +1 -1
  172. package/dist/src/platforms/webex/commands/member.d.ts.map +1 -1
  173. package/dist/src/platforms/webex/commands/member.js +1 -3
  174. package/dist/src/platforms/webex/commands/member.js.map +1 -1
  175. package/dist/src/platforms/webex/commands/message.d.ts.map +1 -1
  176. package/dist/src/platforms/webex/commands/message.js.map +1 -1
  177. package/dist/src/platforms/webex/commands/snapshot.d.ts.map +1 -1
  178. package/dist/src/platforms/webex/commands/snapshot.js.map +1 -1
  179. package/dist/src/platforms/webex/commands/space.d.ts.map +1 -1
  180. package/dist/src/platforms/webex/commands/space.js.map +1 -1
  181. package/dist/src/platforms/webex/commands/whoami.d.ts.map +1 -1
  182. package/dist/src/platforms/webex/commands/whoami.js.map +1 -1
  183. package/dist/src/platforms/webex/credential-manager.d.ts.map +1 -1
  184. package/dist/src/platforms/webex/credential-manager.js.map +1 -1
  185. package/dist/src/platforms/webex/ensure-auth.d.ts.map +1 -1
  186. package/dist/src/platforms/webex/ensure-auth.js +1 -3
  187. package/dist/src/platforms/webex/ensure-auth.js.map +1 -1
  188. package/dist/src/platforms/webex/index.d.ts +1 -1
  189. package/dist/src/platforms/webex/index.d.ts.map +1 -1
  190. package/dist/src/platforms/webex/index.js.map +1 -1
  191. package/dist/src/platforms/webex/markdown-to-html.js.map +1 -1
  192. package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -1
  193. package/dist/src/platforms/webex/token-extractor.js +5 -14
  194. package/dist/src/platforms/webex/token-extractor.js.map +1 -1
  195. package/dist/src/platforms/wechatbot/client.d.ts.map +1 -1
  196. package/dist/src/platforms/wechatbot/client.js.map +1 -1
  197. package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -1
  198. package/dist/src/platforms/wechatbot/commands/message.js.map +1 -1
  199. package/dist/src/platforms/whatsapp/cli.d.ts.map +1 -1
  200. package/dist/src/platforms/whatsapp/cli.js +1 -4
  201. package/dist/src/platforms/whatsapp/cli.js.map +1 -1
  202. package/dist/src/platforms/whatsapp/commands/chat.d.ts.map +1 -1
  203. package/dist/src/platforms/whatsapp/commands/chat.js.map +1 -1
  204. package/dist/src/platforms/whatsapp/commands/message.d.ts.map +1 -1
  205. package/dist/src/platforms/whatsapp/commands/message.js.map +1 -1
  206. package/dist/src/platforms/whatsapp/commands/shared.d.ts.map +1 -1
  207. package/dist/src/platforms/whatsapp/commands/shared.js.map +1 -1
  208. package/dist/src/platforms/whatsapp/credential-manager.d.ts.map +1 -1
  209. package/dist/src/platforms/whatsapp/credential-manager.js +1 -1
  210. package/dist/src/platforms/whatsapp/credential-manager.js.map +1 -1
  211. package/dist/src/platforms/whatsapp/ensure-auth.d.ts.map +1 -1
  212. package/dist/src/platforms/whatsapp/ensure-auth.js.map +1 -1
  213. package/dist/src/platforms/whatsappbot/client.d.ts.map +1 -1
  214. package/dist/src/platforms/whatsappbot/client.js +2 -2
  215. package/dist/src/platforms/whatsappbot/client.js.map +1 -1
  216. package/dist/src/platforms/whatsappbot/commands/auth.d.ts.map +1 -1
  217. package/dist/src/platforms/whatsappbot/commands/auth.js +4 -1
  218. package/dist/src/platforms/whatsappbot/commands/auth.js.map +1 -1
  219. package/dist/src/platforms/whatsappbot/commands/message.d.ts.map +1 -1
  220. package/dist/src/platforms/whatsappbot/commands/message.js.map +1 -1
  221. package/dist/src/platforms/whatsappbot/commands/shared.d.ts.map +1 -1
  222. package/dist/src/platforms/whatsappbot/commands/shared.js.map +1 -1
  223. package/dist/src/shared/chromium/browsers.d.ts +7 -0
  224. package/dist/src/shared/chromium/browsers.d.ts.map +1 -0
  225. package/dist/src/shared/chromium/browsers.js +89 -0
  226. package/dist/src/shared/chromium/browsers.js.map +1 -0
  227. package/dist/src/shared/chromium/cookie-reader.d.ts +20 -0
  228. package/dist/src/shared/chromium/cookie-reader.d.ts.map +1 -0
  229. package/dist/src/shared/chromium/cookie-reader.js +99 -0
  230. package/dist/src/shared/chromium/cookie-reader.js.map +1 -0
  231. package/dist/src/shared/chromium/decryptor.d.ts +42 -0
  232. package/dist/src/shared/chromium/decryptor.d.ts.map +1 -0
  233. package/dist/src/shared/chromium/decryptor.js +205 -0
  234. package/dist/src/shared/chromium/decryptor.js.map +1 -0
  235. package/dist/src/shared/chromium/index.d.ts +6 -0
  236. package/dist/src/shared/chromium/index.d.ts.map +1 -0
  237. package/dist/src/shared/chromium/index.js +4 -0
  238. package/dist/src/shared/chromium/index.js.map +1 -0
  239. package/dist/src/shared/chromium/types.d.ts +11 -0
  240. package/dist/src/shared/chromium/types.d.ts.map +1 -0
  241. package/dist/src/shared/chromium/types.js +2 -0
  242. package/dist/src/shared/chromium/types.js.map +1 -0
  243. package/dist/src/shared/utils/derived-key-cache.d.ts +1 -1
  244. package/dist/src/shared/utils/derived-key-cache.d.ts.map +1 -1
  245. package/dist/src/shared/utils/linux-keyring.js +4 -1
  246. package/dist/src/shared/utils/linux-keyring.js.map +1 -1
  247. package/dist/src/tui/adapters/kakaotalk-adapter.d.ts.map +1 -1
  248. package/dist/src/tui/adapters/kakaotalk-adapter.js +6 -1
  249. package/dist/src/tui/adapters/kakaotalk-adapter.js.map +1 -1
  250. package/dist/src/tui/adapters/telegram-adapter.js +1 -1
  251. package/dist/src/tui/adapters/telegram-adapter.js.map +1 -1
  252. package/dist/src/tui/adapters/webex-adapter.js +1 -1
  253. package/dist/src/tui/adapters/webex-adapter.js.map +1 -1
  254. package/dist/src/tui/app.d.ts.map +1 -1
  255. package/dist/src/tui/app.js +112 -23
  256. package/dist/src/tui/app.js.map +1 -1
  257. package/dist/src/tui/utils.d.ts.map +1 -1
  258. package/dist/src/tui/utils.js +11 -13
  259. package/dist/src/tui/utils.js.map +1 -1
  260. package/dist/src/tui/views/channel-picker.d.ts.map +1 -1
  261. package/dist/src/tui/views/channel-picker.js.map +1 -1
  262. package/dist/src/tui/views/workspace-picker.d.ts.map +1 -1
  263. package/dist/src/tui/views/workspace-picker.js.map +1 -1
  264. package/docs/content/docs/cli/channeltalk.mdx +24 -22
  265. package/docs/content/docs/cli/channeltalkbot.mdx +7 -7
  266. package/docs/content/docs/cli/instagram.mdx +4 -4
  267. package/docs/content/docs/cli/kakaotalk.mdx +9 -8
  268. package/docs/content/docs/cli/line.mdx +14 -14
  269. package/docs/content/docs/cli/webex.mdx +19 -19
  270. package/docs/content/docs/cli/wechatbot.mdx +12 -11
  271. package/docs/content/docs/cli/whatsapp.mdx +5 -4
  272. package/docs/content/docs/cli/whatsappbot.mdx +11 -11
  273. package/docs/content/docs/index.mdx +7 -7
  274. package/docs/content/docs/meta.json +1 -9
  275. package/docs/content/docs/sdk/channeltalk.mdx +5 -6
  276. package/docs/content/docs/sdk/channeltalkbot.mdx +6 -12
  277. package/docs/content/docs/sdk/discord.mdx +36 -43
  278. package/docs/content/docs/sdk/instagram.mdx +18 -18
  279. package/docs/content/docs/sdk/kakaotalk.mdx +27 -18
  280. package/docs/content/docs/sdk/line.mdx +8 -13
  281. package/docs/content/docs/sdk/meta.json +14 -1
  282. package/docs/content/docs/sdk/slack.mdx +36 -42
  283. package/docs/content/docs/sdk/teams.mdx +2 -8
  284. package/docs/content/docs/sdk/webex.mdx +2 -12
  285. package/docs/content/docs/sdk/wechatbot.mdx +1 -5
  286. package/docs/content/docs/sdk/whatsapp.mdx +10 -19
  287. package/docs/content/docs/sdk/whatsappbot.mdx +2 -10
  288. package/docs/content/docs/tui.mdx +23 -23
  289. package/docs/src/app/page.tsx +353 -108
  290. package/e2e/channeltalkbot.e2e.test.ts +1 -5
  291. package/e2e/config.ts +6 -2
  292. package/package.json +59 -58
  293. package/scripts/prepublish.ts +1 -3
  294. package/skills/agent-channeltalk/SKILL.md +1 -1
  295. package/skills/agent-channeltalkbot/SKILL.md +1 -1
  296. package/skills/agent-discord/SKILL.md +1 -1
  297. package/skills/agent-discordbot/SKILL.md +1 -1
  298. package/skills/agent-instagram/SKILL.md +1 -1
  299. package/skills/agent-kakaotalk/SKILL.md +1 -1
  300. package/skills/agent-line/SKILL.md +1 -1
  301. package/skills/agent-slack/SKILL.md +1 -1
  302. package/skills/agent-slackbot/SKILL.md +1 -1
  303. package/skills/agent-teams/SKILL.md +1 -1
  304. package/skills/agent-telegram/SKILL.md +1 -1
  305. package/skills/agent-webex/SKILL.md +1 -1
  306. package/skills/agent-wechatbot/SKILL.md +1 -1
  307. package/skills/agent-whatsapp/SKILL.md +1 -1
  308. package/skills/agent-whatsappbot/SKILL.md +1 -1
  309. package/src/platforms/channeltalk/client.test.ts +116 -29
  310. package/src/platforms/channeltalk/client.ts +26 -6
  311. package/src/platforms/channeltalk/commands/auth.test.ts +5 -5
  312. package/src/platforms/channeltalk/commands/auth.ts +19 -5
  313. package/src/platforms/channeltalk/commands/message.test.ts +2 -6
  314. package/src/platforms/channeltalk/commands/message.ts +5 -1
  315. package/src/platforms/channeltalk/commands/snapshot.test.ts +19 -4
  316. package/src/platforms/channeltalk/commands/snapshot.ts +5 -1
  317. package/src/platforms/channeltalk/ensure-auth.test.ts +20 -17
  318. package/src/platforms/channeltalk/ensure-auth.ts +6 -7
  319. package/src/platforms/channeltalk/index.ts +0 -1
  320. package/src/platforms/channeltalk/token-extractor.test.ts +33 -25
  321. package/src/platforms/channeltalk/token-extractor.ts +120 -372
  322. package/src/platforms/channeltalkbot/client.test.ts +1 -3
  323. package/src/platforms/channeltalkbot/client.ts +39 -13
  324. package/src/platforms/channeltalkbot/commands/auth.test.ts +3 -1
  325. package/src/platforms/channeltalkbot/commands/auth.ts +4 -1
  326. package/src/platforms/channeltalkbot/commands/bot.test.ts +13 -5
  327. package/src/platforms/channeltalkbot/commands/message.test.ts +12 -6
  328. package/src/platforms/channeltalkbot/commands/shared.ts +6 -2
  329. package/src/platforms/channeltalkbot/commands/snapshot.test.ts +17 -5
  330. package/src/platforms/channeltalkbot/credential-manager.test.ts +1 -1
  331. package/src/platforms/channeltalkbot/index.test.ts +0 -2
  332. package/src/platforms/channeltalkbot/index.ts +0 -1
  333. package/src/platforms/discord/commands/auth.test.ts +6 -4
  334. package/src/platforms/discord/commands/auth.ts +14 -14
  335. package/src/platforms/discord/commands/whoami.test.ts +2 -4
  336. package/src/platforms/discord/commands/whoami.ts +2 -0
  337. package/src/platforms/discord/ensure-auth.test.ts +5 -3
  338. package/src/platforms/discord/index.ts +0 -1
  339. package/src/platforms/discord/listener.test.ts +7 -1
  340. package/src/platforms/discord/token-extractor.test.ts +18 -12
  341. package/src/platforms/discord/token-extractor.ts +46 -190
  342. package/src/platforms/discordbot/client.ts +1 -4
  343. package/src/platforms/discordbot/commands/auth.test.ts +3 -1
  344. package/src/platforms/discordbot/commands/channel.test.ts +3 -1
  345. package/src/platforms/discordbot/commands/message.test.ts +3 -1
  346. package/src/platforms/discordbot/commands/server.test.ts +3 -1
  347. package/src/platforms/discordbot/commands/snapshot.test.ts +3 -1
  348. package/src/platforms/discordbot/commands/thread.test.ts +3 -1
  349. package/src/platforms/discordbot/commands/user.test.ts +3 -1
  350. package/src/platforms/instagram/cli.ts +1 -4
  351. package/src/platforms/instagram/client.test.ts +3 -8
  352. package/src/platforms/instagram/client.ts +39 -34
  353. package/src/platforms/instagram/commands/auth.test.ts +13 -12
  354. package/src/platforms/instagram/commands/auth.ts +136 -71
  355. package/src/platforms/instagram/commands/chat.test.ts +21 -24
  356. package/src/platforms/instagram/commands/chat.ts +2 -0
  357. package/src/platforms/instagram/commands/message.test.ts +29 -24
  358. package/src/platforms/instagram/commands/message.ts +3 -4
  359. package/src/platforms/instagram/commands/shared.ts +2 -5
  360. package/src/platforms/instagram/commands/whoami.test.ts +4 -6
  361. package/src/platforms/instagram/credential-manager.ts +2 -6
  362. package/src/platforms/instagram/ensure-auth.test.ts +1 -4
  363. package/src/platforms/instagram/ensure-auth.ts +6 -3
  364. package/src/platforms/instagram/listener.test.ts +7 -3
  365. package/src/platforms/instagram/token-extractor.test.ts +4 -16
  366. package/src/platforms/instagram/token-extractor.ts +55 -309
  367. package/src/platforms/instagram/types.test.ts +2 -6
  368. package/src/platforms/instagram/types.ts +4 -2
  369. package/src/platforms/kakaotalk/auth/kakao-login.ts +30 -8
  370. package/src/platforms/kakaotalk/client.test.ts +37 -25
  371. package/src/platforms/kakaotalk/client.ts +23 -12
  372. package/src/platforms/kakaotalk/commands/auth.test.ts +6 -18
  373. package/src/platforms/kakaotalk/commands/auth.ts +101 -47
  374. package/src/platforms/kakaotalk/commands/chat.test.ts +8 -11
  375. package/src/platforms/kakaotalk/commands/message.test.ts +15 -24
  376. package/src/platforms/kakaotalk/commands/shared.ts +1 -0
  377. package/src/platforms/kakaotalk/commands/whoami.test.ts +6 -10
  378. package/src/platforms/kakaotalk/credential-manager.test.ts +1 -4
  379. package/src/platforms/kakaotalk/index.test.ts +1 -0
  380. package/src/platforms/kakaotalk/index.ts +0 -2
  381. package/src/platforms/kakaotalk/listener.test.ts +7 -1
  382. package/src/platforms/kakaotalk/protocol/connection.ts +4 -1
  383. package/src/platforms/kakaotalk/protocol/crypto.ts +1 -1
  384. package/src/platforms/kakaotalk/protocol/session.ts +12 -6
  385. package/src/platforms/kakaotalk/token-extractor.ts +5 -5
  386. package/src/platforms/kakaotalk/types.ts +8 -7
  387. package/src/platforms/line/cli.ts +1 -4
  388. package/src/platforms/line/client.ts +12 -20
  389. package/src/platforms/line/commands/auth.test.ts +2 -1
  390. package/src/platforms/line/commands/chat.test.ts +2 -1
  391. package/src/platforms/line/commands/chat.ts +1 -4
  392. package/src/platforms/line/commands/friend.test.ts +2 -1
  393. package/src/platforms/line/commands/message.test.ts +2 -1
  394. package/src/platforms/line/commands/message.ts +2 -9
  395. package/src/platforms/line/commands/whoami.test.ts +2 -1
  396. package/src/platforms/line/credential-manager.test.ts +1 -2
  397. package/src/platforms/line/index.test.ts +1 -0
  398. package/src/platforms/line/listener.ts +1 -1
  399. package/src/platforms/line/types.test.ts +1 -0
  400. package/src/platforms/slack/cli.ts +3 -1
  401. package/src/platforms/slack/client-mappers.ts +297 -0
  402. package/src/platforms/slack/client.test.ts +532 -17
  403. package/src/platforms/slack/client.ts +69 -458
  404. package/src/platforms/slack/commands/channel.ts +1 -4
  405. package/src/platforms/slack/commands/emoji.test.ts +6 -4
  406. package/src/platforms/slack/commands/emoji.ts +20 -22
  407. package/src/platforms/slack/commands/message.ts +6 -1
  408. package/src/platforms/slack/commands/pin.test.ts +14 -12
  409. package/src/platforms/slack/commands/reminder.ts +7 -6
  410. package/src/platforms/slack/commands/user.ts +6 -1
  411. package/src/platforms/slack/commands/usergroup.test.ts +3 -3
  412. package/src/platforms/slack/commands/usergroup.ts +10 -7
  413. package/src/platforms/slack/commands/whoami.test.ts +1 -1
  414. package/src/platforms/slack/commands/whoami.ts +2 -0
  415. package/src/platforms/slack/index.ts +0 -2
  416. package/src/platforms/slack/listener.test.ts +1 -0
  417. package/src/platforms/slack/token-extractor.test.ts +7 -12
  418. package/src/platforms/slack/token-extractor.ts +47 -255
  419. package/src/platforms/slackbot/cli.ts +8 -1
  420. package/src/platforms/slackbot/commands/auth.test.ts +3 -1
  421. package/src/platforms/teams/client.ts +1 -1
  422. package/src/platforms/teams/commands/auth.test.ts +1 -1
  423. package/src/platforms/teams/commands/auth.ts +4 -1
  424. package/src/platforms/teams/commands/whoami.test.ts +2 -4
  425. package/src/platforms/teams/commands/whoami.ts +2 -0
  426. package/src/platforms/teams/index.ts +0 -1
  427. package/src/platforms/teams/token-extractor.ts +82 -350
  428. package/src/platforms/telegram/app-config.test.ts +1 -0
  429. package/src/platforms/telegram/chat-utils.test.ts +5 -1
  430. package/src/platforms/telegram/cli.ts +2 -4
  431. package/src/platforms/telegram/client.test.ts +16 -3
  432. package/src/platforms/telegram/client.ts +14 -4
  433. package/src/platforms/telegram/commands/auth.test.ts +1 -0
  434. package/src/platforms/telegram/commands/auth.ts +3 -4
  435. package/src/platforms/telegram/commands/chat.test.ts +2 -5
  436. package/src/platforms/telegram/commands/chat.ts +1 -0
  437. package/src/platforms/telegram/commands/message.test.ts +2 -5
  438. package/src/platforms/telegram/commands/message.ts +1 -0
  439. package/src/platforms/telegram/commands/shared.test.ts +1 -0
  440. package/src/platforms/telegram/commands/whoami.test.ts +5 -7
  441. package/src/platforms/telegram/commands/whoami.ts +1 -1
  442. package/src/platforms/telegram/credential-manager.test.ts +1 -0
  443. package/src/platforms/telegram/credential-manager.ts +11 -2
  444. package/src/platforms/telegram/my-telegram-org.ts +6 -2
  445. package/src/platforms/telegram/types.test.ts +1 -0
  446. package/src/platforms/webex/app-config.test.ts +1 -0
  447. package/src/platforms/webex/cli.ts +1 -4
  448. package/src/platforms/webex/client.test.ts +4 -12
  449. package/src/platforms/webex/client.ts +14 -52
  450. package/src/platforms/webex/commands/auth.test.ts +7 -1
  451. package/src/platforms/webex/commands/auth.ts +12 -15
  452. package/src/platforms/webex/commands/member.test.ts +1 -3
  453. package/src/platforms/webex/commands/member.ts +14 -19
  454. package/src/platforms/webex/commands/message.ts +4 -15
  455. package/src/platforms/webex/commands/snapshot.test.ts +28 -3
  456. package/src/platforms/webex/commands/snapshot.ts +3 -3
  457. package/src/platforms/webex/commands/space.test.ts +3 -3
  458. package/src/platforms/webex/commands/space.ts +2 -9
  459. package/src/platforms/webex/commands/whoami.test.ts +12 -5
  460. package/src/platforms/webex/commands/whoami.ts +2 -0
  461. package/src/platforms/webex/credential-manager.ts +11 -2
  462. package/src/platforms/webex/ensure-auth.ts +1 -3
  463. package/src/platforms/webex/index.ts +1 -7
  464. package/src/platforms/webex/markdown-to-html.test.ts +6 -18
  465. package/src/platforms/webex/markdown-to-html.ts +8 -8
  466. package/src/platforms/webex/token-extractor.ts +6 -29
  467. package/src/platforms/wechatbot/client.test.ts +6 -2
  468. package/src/platforms/wechatbot/client.ts +6 -1
  469. package/src/platforms/wechatbot/commands/auth.test.ts +3 -7
  470. package/src/platforms/wechatbot/commands/message.test.ts +1 -4
  471. package/src/platforms/wechatbot/commands/message.ts +5 -1
  472. package/src/platforms/wechatbot/commands/template.test.ts +1 -4
  473. package/src/platforms/wechatbot/commands/user.test.ts +2 -7
  474. package/src/platforms/whatsapp/cli.ts +1 -4
  475. package/src/platforms/whatsapp/commands/auth.test.ts +19 -22
  476. package/src/platforms/whatsapp/commands/chat.test.ts +21 -24
  477. package/src/platforms/whatsapp/commands/chat.ts +2 -0
  478. package/src/platforms/whatsapp/commands/message.test.ts +22 -24
  479. package/src/platforms/whatsapp/commands/message.ts +3 -5
  480. package/src/platforms/whatsapp/commands/shared.ts +2 -5
  481. package/src/platforms/whatsapp/commands/whoami.test.ts +2 -2
  482. package/src/platforms/whatsapp/credential-manager.ts +2 -6
  483. package/src/platforms/whatsapp/ensure-auth.test.ts +1 -4
  484. package/src/platforms/whatsapp/ensure-auth.ts +14 -6
  485. package/src/platforms/whatsapp/index.ts +0 -2
  486. package/src/platforms/whatsappbot/client.test.ts +13 -7
  487. package/src/platforms/whatsappbot/client.ts +18 -4
  488. package/src/platforms/whatsappbot/commands/auth.ts +4 -1
  489. package/src/platforms/whatsappbot/commands/message.test.ts +12 -2
  490. package/src/platforms/whatsappbot/commands/message.ts +16 -3
  491. package/src/platforms/whatsappbot/commands/shared.ts +3 -1
  492. package/src/platforms/whatsappbot/commands/whoami.test.ts +1 -3
  493. package/src/platforms/whatsappbot/index.ts +0 -2
  494. package/src/shared/chromium/browsers.test.ts +274 -0
  495. package/src/shared/chromium/browsers.ts +86 -0
  496. package/src/shared/chromium/cookie-reader.test.ts +274 -0
  497. package/src/shared/chromium/cookie-reader.ts +111 -0
  498. package/src/shared/chromium/decryptor.test.ts +449 -0
  499. package/src/shared/chromium/decryptor.ts +227 -0
  500. package/src/shared/chromium/index.ts +11 -0
  501. package/src/shared/chromium/types.ts +11 -0
  502. package/src/shared/utils/derived-key-cache.ts +1 -1
  503. package/src/shared/utils/linux-keyring.ts +4 -4
  504. package/src/tui/adapters/kakaotalk-adapter.ts +6 -1
  505. package/src/tui/adapters/telegram-adapter.ts +1 -1
  506. package/src/tui/adapters/webex-adapter.ts +1 -1
  507. package/src/tui/app.ts +149 -59
  508. package/src/tui/utils.test.ts +144 -145
  509. package/src/tui/utils.ts +27 -29
  510. package/src/tui/views/channel-picker.ts +1 -1
  511. package/src/tui/views/workspace-picker.ts +1 -1
@@ -1,9 +1,17 @@
1
1
  import { execSync, spawn } from 'node:child_process'
2
- import { createDecipheriv, pbkdf2Sync } from 'node:crypto'
2
+ import { pbkdf2Sync } from 'node:crypto'
3
3
  import { existsSync, readdirSync, readFileSync } from 'node:fs'
4
4
  import { homedir } from 'node:os'
5
5
  import { join } from 'node:path'
6
6
 
7
+ import {
8
+ BROWSER_KEYCHAIN_VARIANTS,
9
+ CHROMIUM_BROWSERS,
10
+ ChromiumCookieDecryptor,
11
+ discoverBrowserProfileDirs,
12
+ getBrowserBasePath,
13
+ } from '@/shared/chromium'
14
+ import type { KeychainVariant } from '@/shared/chromium'
7
15
  import { DerivedKeyCache } from '@/shared/utils/derived-key-cache'
8
16
  import { lookupLinuxKeyringPassword } from '@/shared/utils/linux-keyring'
9
17
 
@@ -13,11 +21,6 @@ export interface ExtractedDiscordToken {
13
21
 
14
22
  export type DiscordVariant = 'stable' | 'canary' | 'ptb'
15
23
 
16
- interface KeychainVariant {
17
- service: string
18
- account: string
19
- }
20
-
21
24
  interface CDPTarget {
22
25
  id: string
23
26
  type: string
@@ -34,13 +37,6 @@ interface CDPMessage {
34
37
  error?: { code: number; message: string }
35
38
  }
36
39
 
37
- interface BrowserConfig {
38
- name: string
39
- darwin: string
40
- linux: string
41
- win32: string
42
- }
43
-
44
40
  const TOKEN_REGEX = /[\w-]{24,}\.[\w-]{6}\.[\w-]{25,110}/
45
41
  const MFA_TOKEN_REGEX = /mfa\.[\w-]{84}/
46
42
  const ENCRYPTED_PREFIX = 'dQw4w9WgXcQ:'
@@ -62,49 +58,13 @@ const DISCORD_APP_PATHS: Record<DiscordVariant, { darwin: string }> = {
62
58
  ptb: { darwin: '/Applications/Discord PTB.app/Contents/MacOS/Discord PTB' },
63
59
  }
64
60
 
65
- const BROWSERS: BrowserConfig[] = [
66
- {
67
- name: 'Chrome',
68
- darwin: join('Google', 'Chrome'),
69
- linux: 'google-chrome',
70
- win32: join('Google', 'Chrome', 'User Data'),
71
- },
72
- {
73
- name: 'Chrome Canary',
74
- darwin: join('Google', 'Chrome Canary'),
75
- linux: 'google-chrome-unstable',
76
- win32: join('Google', 'Chrome SxS', 'User Data'),
77
- },
78
- {
79
- name: 'Edge',
80
- darwin: 'Microsoft Edge',
81
- linux: 'microsoft-edge',
82
- win32: join('Microsoft', 'Edge', 'User Data'),
83
- },
84
- {
85
- name: 'Arc',
86
- darwin: join('Arc', 'User Data'),
87
- linux: '',
88
- win32: join('Arc', 'User Data'),
89
- },
90
- {
91
- name: 'Brave',
92
- darwin: join('BraveSoftware', 'Brave-Browser'),
93
- linux: join('BraveSoftware', 'Brave-Browser'),
94
- win32: join('BraveSoftware', 'Brave-Browser', 'User Data'),
95
- },
96
- {
97
- name: 'Vivaldi',
98
- darwin: 'Vivaldi',
99
- linux: 'vivaldi',
100
- win32: join('Vivaldi', 'User Data'),
101
- },
102
- {
103
- name: 'Chromium',
104
- darwin: 'Chromium',
105
- linux: 'chromium',
106
- win32: join('Chromium', 'User Data'),
107
- },
61
+ const DISCORD_APP_KEYCHAIN_VARIANTS: KeychainVariant[] = [
62
+ { service: 'discord Safe Storage', account: 'discord Key' },
63
+ { service: 'discordcanary Safe Storage', account: 'discordcanary Key' },
64
+ { service: 'discordptb Safe Storage', account: 'discordptb Key' },
65
+ { service: 'Discord Safe Storage', account: 'Discord' },
66
+ { service: 'Discord Canary Safe Storage', account: 'Discord Canary' },
67
+ { service: 'Discord PTB Safe Storage', account: 'Discord PTB' },
108
68
  ]
109
69
 
110
70
  export class DiscordTokenExtractor {
@@ -113,12 +73,20 @@ export class DiscordTokenExtractor {
113
73
  private killWait: number
114
74
  private keyCache: DerivedKeyCache
115
75
  private cachedKey: Buffer | null = null
76
+ private decryptor: ChromiumCookieDecryptor
116
77
 
117
78
  constructor(platform?: NodeJS.Platform, startupWait?: number, killWait?: number, keyCache?: DerivedKeyCache) {
118
79
  this.platform = platform ?? process.platform
119
80
  this.startupWait = startupWait ?? DISCORD_STARTUP_WAIT
120
81
  this.killWait = killWait ?? 1000
121
82
  this.keyCache = keyCache ?? new DerivedKeyCache()
83
+ this.decryptor = new ChromiumCookieDecryptor({
84
+ platform: this.platform,
85
+ appKeychainVariants: DISCORD_APP_KEYCHAIN_VARIANTS,
86
+ keyCache: this.keyCache,
87
+ keyCachePlatform: 'discord',
88
+ linuxKeyringAppNames: ['discord', 'Discord'],
89
+ })
122
90
  }
123
91
 
124
92
  getDiscordDirs(): string[] {
@@ -147,11 +115,11 @@ export class DiscordTokenExtractor {
147
115
  getBrowserLevelDBDirs(): string[] {
148
116
  const dirs: string[] = []
149
117
 
150
- for (const browser of BROWSERS) {
151
- const browserBase = this.getBrowserBasePath(browser)
118
+ for (const browser of CHROMIUM_BROWSERS) {
119
+ const browserBase = getBrowserBasePath(browser, this.platform)
152
120
  if (!browserBase) continue
153
121
 
154
- const profileDirs = this.discoverProfileDirs(browserBase)
122
+ const profileDirs = discoverBrowserProfileDirs(browserBase)
155
123
  for (const profileDir of profileDirs) {
156
124
  dirs.push(join(profileDir, 'Local Storage', 'leveldb'))
157
125
  }
@@ -160,49 +128,6 @@ export class DiscordTokenExtractor {
160
128
  return dirs
161
129
  }
162
130
 
163
- private getBrowserBasePath(browser: BrowserConfig): string | null {
164
- let relative: string
165
-
166
- switch (this.platform) {
167
- case 'darwin':
168
- relative = browser.darwin
169
- if (!relative) return null
170
- return join(homedir(), 'Library', 'Application Support', relative)
171
- case 'linux':
172
- relative = browser.linux
173
- if (!relative) return null
174
- return join(homedir(), '.config', relative)
175
- case 'win32':
176
- relative = browser.win32
177
- if (!relative) return null
178
- return join(
179
- process.env.LOCALAPPDATA || join(homedir(), 'AppData', 'Local'),
180
- relative,
181
- )
182
- default:
183
- return null
184
- }
185
- }
186
-
187
- private discoverProfileDirs(browserBase: string): string[] {
188
- const dirs: string[] = []
189
-
190
- dirs.push(join(browserBase, 'Default'))
191
-
192
- if (!existsSync(browserBase)) return dirs
193
-
194
- try {
195
- const entries = readdirSync(browserBase, { withFileTypes: true })
196
- for (const entry of entries) {
197
- if (!entry.isDirectory()) continue
198
- if (!/^Profile \d+$/i.test(entry.name)) continue
199
- dirs.push(join(browserBase, entry.name))
200
- }
201
- } catch {}
202
-
203
- return dirs
204
- }
205
-
206
131
  private findBrowserBaseDirForPath(path: string): string | null {
207
132
  const parts = path.split(/[/\\]/)
208
133
  for (let levels = 2; levels <= 5; levels++) {
@@ -214,24 +139,7 @@ export class DiscordTokenExtractor {
214
139
  }
215
140
 
216
141
  getKeychainVariants(): KeychainVariant[] {
217
- return [
218
- // Modern Discord (lowercase)
219
- { service: 'discord Safe Storage', account: 'discord Key' },
220
- { service: 'discordcanary Safe Storage', account: 'discordcanary Key' },
221
- { service: 'discordptb Safe Storage', account: 'discordptb Key' },
222
- // Legacy Discord (capitalized)
223
- { service: 'Discord Safe Storage', account: 'Discord' },
224
- { service: 'Discord Canary Safe Storage', account: 'Discord Canary' },
225
- { service: 'Discord PTB Safe Storage', account: 'Discord PTB' },
226
- // Browser keychain entries for fallback
227
- { service: 'Chrome Safe Storage', account: 'Chrome' },
228
- { service: 'Chrome Canary Safe Storage', account: 'Chrome Canary' },
229
- { service: 'Microsoft Edge Safe Storage', account: 'Microsoft Edge' },
230
- { service: 'Arc Safe Storage', account: 'Arc' },
231
- { service: 'Brave Safe Storage', account: 'Brave' },
232
- { service: 'Vivaldi Safe Storage', account: 'Vivaldi' },
233
- { service: 'Chromium Safe Storage', account: 'Chromium' },
234
- ]
142
+ return [...DISCORD_APP_KEYCHAIN_VARIANTS, ...BROWSER_KEYCHAIN_VARIANTS]
235
143
  }
236
144
 
237
145
  getVariantFromPath(path: string): DiscordVariant {
@@ -283,6 +191,8 @@ export class DiscordTokenExtractor {
283
191
  private async loadCachedKey(): Promise<void> {
284
192
  if (this.platform !== 'darwin') return
285
193
 
194
+ await this.decryptor.loadCachedKey()
195
+
286
196
  const cached = await this.keyCache.get('discord')
287
197
  if (cached) {
288
198
  this.cachedKey = cached
@@ -290,7 +200,7 @@ export class DiscordTokenExtractor {
290
200
  }
291
201
 
292
202
  async clearKeyCache(): Promise<void> {
293
- await this.keyCache.clear('discord')
203
+ await this.decryptor.clearKeyCache()
294
204
  this.cachedKey = null
295
205
  }
296
206
 
@@ -445,27 +355,10 @@ export class DiscordTokenExtractor {
445
355
  const encryptedKey = Buffer.from(localState.os_crypt.encrypted_key, 'base64')
446
356
 
447
357
  const dpapiBlobKey = encryptedKey.subarray(5)
448
- const masterKey = this.decryptDPAPI(dpapiBlobKey)
358
+ const masterKey = this.decryptor.decryptDPAPI(dpapiBlobKey)
449
359
  if (!masterKey) return null
450
360
 
451
- return this.decryptAESGCM(encryptedData, masterKey)
452
- } catch {
453
- return null
454
- }
455
- }
456
-
457
- private decryptDPAPI(encryptedBlob: Buffer): Buffer | null {
458
- try {
459
- const b64 = encryptedBlob.toString('base64')
460
- const psScript = `
461
- Add-Type -AssemblyName System.Security
462
- $bytes = [Convert]::FromBase64String('${b64}')
463
- $decrypted = [Security.Cryptography.ProtectedData]::Unprotect($bytes, $null, 'CurrentUser')
464
- [Convert]::ToBase64String($decrypted)
465
- `.replace(/\n/g, ' ')
466
-
467
- const result = execSync(`powershell -Command "${psScript}"`, { encoding: 'utf8' })
468
- return Buffer.from(result.trim(), 'base64')
361
+ return this.decryptor.decryptAESGCM(encryptedData, masterKey)
469
362
  } catch {
470
363
  return null
471
364
  }
@@ -473,7 +366,7 @@ export class DiscordTokenExtractor {
473
366
 
474
367
  private decryptMacToken(encryptedData: Buffer, discordDir: string): string | null {
475
368
  if (this.cachedKey) {
476
- const decrypted = this.decryptAESCBC(encryptedData, this.cachedKey)
369
+ const decrypted = this.decryptor.decryptAESCBC(encryptedData, this.cachedKey)
477
370
  if (decrypted && this.isValidToken(decrypted)) return decrypted
478
371
  }
479
372
 
@@ -500,7 +393,7 @@ export class DiscordTokenExtractor {
500
393
  ).trim()
501
394
 
502
395
  const key = pbkdf2Sync(password, 'saltysalt', 1003, 16, 'sha1')
503
- const decrypted = this.decryptAESCBC(encryptedData, key)
396
+ const decrypted = this.decryptor.decryptAESCBC(encryptedData, key)
504
397
  if (decrypted && this.isValidToken(decrypted)) {
505
398
  this.cachedKey = key
506
399
  this.keyCache.set('discord', key).catch(() => {})
@@ -514,63 +407,26 @@ export class DiscordTokenExtractor {
514
407
 
515
408
  private decryptLinuxToken(encryptedData: Buffer): string | null {
516
409
  const prefix = encryptedData.subarray(0, 3).toString()
410
+
517
411
  if (prefix === 'v11') {
518
- const result = this.decryptV11LinuxToken(encryptedData)
519
- if (result) return result
412
+ for (const appName of ['discord', 'Discord']) {
413
+ try {
414
+ const keyringPassword = this.getLinuxKeyringPassword(appName)
415
+ const key = pbkdf2Sync(keyringPassword, 'saltysalt', 1, 16, 'sha1')
416
+ const decrypted = this.decryptor.decryptAESCBC(encryptedData, key)
417
+ if (decrypted) return decrypted
418
+ } catch {}
419
+ }
520
420
  }
521
- // v10 or fallback
421
+
522
422
  const key = pbkdf2Sync('peanuts', 'saltysalt', 1, 16, 'sha1')
523
- return this.decryptAESCBC(encryptedData, key)
423
+ return this.decryptor.decryptAESCBC(encryptedData, key)
524
424
  }
525
425
 
526
426
  private getLinuxKeyringPassword(appName: string): string {
527
427
  return lookupLinuxKeyringPassword(appName)
528
428
  }
529
429
 
530
- private decryptV11LinuxToken(encryptedData: Buffer): string | null {
531
- const appNames = ['discord', 'Discord']
532
- for (const appName of appNames) {
533
- try {
534
- const keyringPassword = this.getLinuxKeyringPassword(appName)
535
- const key = pbkdf2Sync(keyringPassword, 'saltysalt', 1, 16, 'sha1')
536
- const result = this.decryptAESCBC(encryptedData, key)
537
- if (result) return result
538
- } catch {}
539
- }
540
- return null
541
- }
542
-
543
- private decryptAESCBC(encryptedData: Buffer, key: Buffer): string | null {
544
- try {
545
- const ciphertext = encryptedData.subarray(3)
546
- const iv = Buffer.alloc(16, 0x20)
547
-
548
- const decipher = createDecipheriv('aes-128-cbc', key, iv)
549
- decipher.setAutoPadding(true)
550
-
551
- const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()])
552
- return decrypted.toString('utf8')
553
- } catch {
554
- return null
555
- }
556
- }
557
-
558
- private decryptAESGCM(encryptedData: Buffer, key: Buffer): string | null {
559
- try {
560
- const iv = encryptedData.subarray(3, 15)
561
- const authTag = encryptedData.subarray(-16)
562
- const ciphertext = encryptedData.subarray(15, -16)
563
-
564
- const decipher = createDecipheriv('aes-256-gcm', key, iv)
565
- decipher.setAuthTag(authTag)
566
-
567
- const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()])
568
- return decrypted.toString('utf8')
569
- } catch {
570
- return null
571
- }
572
- }
573
-
574
430
  async isDiscordRunning(variant?: DiscordVariant): Promise<boolean> {
575
431
  const variants = variant ? [variant] : (['stable', 'canary', 'ptb'] as DiscordVariant[])
576
432
 
@@ -31,10 +31,7 @@ export class DiscordBotClient {
31
31
  const credManager = new DiscordBotCredentialManager()
32
32
  const creds = await credManager.getCredentials()
33
33
  if (!creds?.token) {
34
- throw new DiscordBotError(
35
- 'No Discord bot credentials found. Run "auth set <token>" first.',
36
- 'no_credentials',
37
- )
34
+ throw new DiscordBotError('No Discord bot credentials found. Run "auth set <token>" first.', 'no_credentials')
38
35
  }
39
36
  return this.login({ token: creds.token })
40
37
  }
@@ -21,7 +21,9 @@ const mockListGuilds = mock(() =>
21
21
 
22
22
  mock.module('../client', () => ({
23
23
  DiscordBotClient: class MockDiscordBotClient {
24
- async login(_credentials?: any) { return this }
24
+ async login(_credentials?: any) {
25
+ return this
26
+ }
25
27
  testAuth = mockTestAuth
26
28
  listGuilds = mockListGuilds
27
29
  },
@@ -31,7 +31,9 @@ const mockResolveChannel = mock((_guildId: string, channel: string) => {
31
31
 
32
32
  mock.module('../client', () => ({
33
33
  DiscordBotClient: class MockDiscordBotClient {
34
- async login(_credentials?: any) { return this }
34
+ async login(_credentials?: any) {
35
+ return this
36
+ }
35
37
  listChannels = mockListChannels
36
38
  getChannel = mockGetChannel
37
39
  resolveChannel = mockResolveChannel
@@ -68,7 +68,9 @@ const mockResolveChannel = mock((_guildId: string, channel: string) => {
68
68
 
69
69
  mock.module('../client', () => ({
70
70
  DiscordBotClient: class MockDiscordBotClient {
71
- async login(_credentials?: any) { return this }
71
+ async login(_credentials?: any) {
72
+ return this
73
+ }
72
74
  sendMessage = mockSendMessage
73
75
  getMessages = mockGetMessages
74
76
  getMessage = mockGetMessage
@@ -22,7 +22,9 @@ const mockGetGuild = mock((guildId: string) =>
22
22
 
23
23
  mock.module('../client', () => ({
24
24
  DiscordBotClient: class MockDiscordBotClient {
25
- async login(_credentials?: any) { return this }
25
+ async login(_credentials?: any) {
26
+ return this
27
+ }
26
28
  listGuilds = mockListGuilds
27
29
  getGuild = mockGetGuild
28
30
  },
@@ -41,7 +41,9 @@ const mockListUsers = mock((_guildId: string) =>
41
41
 
42
42
  mock.module('../client', () => ({
43
43
  DiscordBotClient: class MockDiscordBotClient {
44
- async login(_credentials?: any) { return this }
44
+ async login(_credentials?: any) {
45
+ return this
46
+ }
45
47
  listChannels = mockListChannels
46
48
  getMessages = mockGetMessages
47
49
  listUsers = mockListUsers
@@ -29,7 +29,9 @@ const mockResolveChannel = mock((_guildId: string, channel: string) => {
29
29
 
30
30
  mock.module('../client', () => ({
31
31
  DiscordBotClient: class MockDiscordBotClient {
32
- async login(_credentials?: any) { return this }
32
+ async login(_credentials?: any) {
33
+ return this
34
+ }
33
35
  createThread = mockCreateThread
34
36
  archiveThread = mockArchiveThread
35
37
  resolveChannel = mockResolveChannel
@@ -28,7 +28,9 @@ const mockGetUser = mock((userId: string) => {
28
28
 
29
29
  mock.module('../client', () => ({
30
30
  DiscordBotClient: class MockDiscordBotClient {
31
- async login(_credentials?: any) { return this }
31
+ async login(_credentials?: any) {
32
+ return this
33
+ }
32
34
  listUsers = mockListUsers
33
35
  getUser = mockGetUser
34
36
  },
@@ -18,10 +18,7 @@ function isAuthCommand(command: CommandType): boolean {
18
18
 
19
19
  const program = new Command()
20
20
 
21
- program
22
- .name('agent-instagram')
23
- .description('CLI tool for Instagram DMs via private mobile API')
24
- .version(pkg.version)
21
+ program.name('agent-instagram').description('CLI tool for Instagram DMs via private mobile API').version(pkg.version)
25
22
 
26
23
  program.hook('preAction', async (_thisCommand, actionCommand) => {
27
24
  if (isAuthCommand(actionCommand)) return
@@ -104,8 +104,7 @@ describe('InstagramClient', () => {
104
104
  const mockManager = {
105
105
  getAccount: () =>
106
106
  Promise.resolve({ account_id: 'testuser', username: 'testuser', created_at: '', updated_at: '' }),
107
- ensureAccountPaths: () =>
108
- Promise.resolve({ account_dir: testDir, session_path: sessionPath }),
107
+ ensureAccountPaths: () => Promise.resolve({ account_dir: testDir, session_path: sessionPath }),
109
108
  } as any
110
109
 
111
110
  const client = new InstagramClient(mockManager)
@@ -124,9 +123,7 @@ describe('InstagramClient', () => {
124
123
  headers: {},
125
124
  }),
126
125
  )
127
- fetchResponses.push(
128
- jsonResponse({ status: 'ok', logged_in_user: { pk: '99' } }),
129
- )
126
+ fetchResponses.push(jsonResponse({ status: 'ok', logged_in_user: { pk: '99' } }))
130
127
 
131
128
  const client = new InstagramClient()
132
129
  const before = Math.floor(Date.now() / 1000)
@@ -155,9 +152,7 @@ describe('InstagramClient', () => {
155
152
  }),
156
153
  }),
157
154
  )
158
- fetchResponses.push(
159
- jsonResponse({ status: 'ok', logged_in_user: { pk: '99' } }),
160
- )
155
+ fetchResponses.push(jsonResponse({ status: 'ok', logged_in_user: { pk: '99' } }))
161
156
 
162
157
  const client = new InstagramClient()
163
158
  const before = Math.floor(Date.now() / 1000)
@@ -1,6 +1,7 @@
1
1
  import { constants, createCipheriv, publicEncrypt, randomBytes, randomUUID } from 'node:crypto'
2
2
  import { existsSync } from 'node:fs'
3
3
  import { mkdir, readFile, writeFile } from 'node:fs/promises'
4
+
4
5
  import { InstagramCredentialManager } from './credential-manager'
5
6
  import {
6
7
  InstagramError,
@@ -164,11 +165,7 @@ export class InstagramClient {
164
165
  return { userId: this.userId ?? '' }
165
166
  }
166
167
 
167
- async twoFactorLogin(
168
- username: string,
169
- code: string,
170
- twoFactorIdentifier: string,
171
- ): Promise<{ userId: string }> {
168
+ async twoFactorLogin(username: string, code: string, twoFactorIdentifier: string): Promise<{ userId: string }> {
172
169
  const { status, data } = await this.request('POST', '/accounts/two_factor_login/', {
173
170
  username,
174
171
  verification_code: code,
@@ -193,7 +190,10 @@ export class InstagramClient {
193
190
  ): Promise<{ contactPoint: string; stepName: string }> {
194
191
  this.ensureSession()
195
192
 
196
- const { data: getData } = await this.request('GET', `${apiPath}?guid=${this.session!.device.uuid}&device_id=${this.session!.device.android_device_id}`)
193
+ const { data: getData } = await this.request(
194
+ 'GET',
195
+ `${apiPath}?guid=${this.session!.device.uuid}&device_id=${this.session!.device.android_device_id}`,
196
+ )
197
197
  const stepName = (getData['step_name'] as string) ?? ''
198
198
 
199
199
  const choice = method === 'sms' ? '0' : '1'
@@ -210,10 +210,7 @@ export class InstagramClient {
210
210
  return { contactPoint, stepName: resultStep }
211
211
  }
212
212
 
213
- async challengeSubmitCode(
214
- apiPath: string,
215
- code: string,
216
- ): Promise<{ userId: string }> {
213
+ async challengeSubmitCode(apiPath: string, code: string): Promise<{ userId: string }> {
217
214
  this.ensureSession()
218
215
 
219
216
  const { status, data } = await this.request('POST', apiPath, {
@@ -304,9 +301,7 @@ export class InstagramClient {
304
301
  async searchChats(query: string, limit = 20): Promise<InstagramChatSummary[]> {
305
302
  const allChats = await this.listChats(Math.max(limit, 50))
306
303
  const lower = query.toLowerCase()
307
- return allChats
308
- .filter((c) => c.name.toLowerCase().includes(lower) || c.id.includes(query))
309
- .slice(0, limit)
304
+ return allChats.filter((c) => c.name.toLowerCase().includes(lower) || c.id.includes(query)).slice(0, limit)
310
305
  }
311
306
 
312
307
  async searchMessages(
@@ -410,7 +405,12 @@ export class InstagramClient {
410
405
  return this.userId
411
406
  }
412
407
 
413
- async getProfile(): Promise<{ user_id: string; username: string; full_name: string | null; profile_pic_url: string | null }> {
408
+ async getProfile(): Promise<{
409
+ user_id: string
410
+ username: string
411
+ full_name: string | null
412
+ profile_pic_url: string | null
413
+ }> {
414
414
  if (!this.userId) {
415
415
  throw new InstagramError('Not authenticated. Call login() first.', 'not_authenticated')
416
416
  }
@@ -441,17 +441,16 @@ export class InstagramClient {
441
441
  const keyIdHeader = response.headers.get('ig-set-password-encryption-key-id')
442
442
 
443
443
  if (pubKeyHeader && keyIdHeader) {
444
- this.debugLog?.(`encryption key_id=${keyIdHeader} pub_key_length=${pubKeyHeader.length} pub_key_prefix=${pubKeyHeader.substring(0, 40)}...`)
444
+ this.debugLog?.(
445
+ `encryption key_id=${keyIdHeader} pub_key_length=${pubKeyHeader.length} pub_key_prefix=${pubKeyHeader.substring(0, 40)}...`,
446
+ )
445
447
  return { keyId: keyIdHeader, publicKey: pubKeyHeader }
446
448
  }
447
449
 
448
450
  return null
449
451
  }
450
452
 
451
- private encryptPassword(
452
- password: string,
453
- key: { keyId: string; publicKey: string },
454
- ): string {
453
+ private encryptPassword(password: string, key: { keyId: string; publicKey: string }): string {
455
454
  const timestamp = Math.floor(Date.now() / 1000).toString()
456
455
  const passwordBytes = Buffer.from(password, 'utf-8')
457
456
 
@@ -463,21 +462,24 @@ export class InstagramClient {
463
462
  const tag = cipher.getAuthTag()
464
463
 
465
464
  const pubKeyPem = Buffer.from(key.publicKey, 'base64').toString('utf-8')
466
- const rsaEncrypted = publicEncrypt(
467
- { key: pubKeyPem, padding: constants.RSA_PKCS1_PADDING },
468
- aesKey,
469
- )
465
+ const rsaEncrypted = publicEncrypt({ key: pubKeyPem, padding: constants.RSA_PKCS1_PADDING }, aesKey)
470
466
 
471
467
  // Wire format: version(1) | keyId(1) | iv(12) | rsaLen(2 LE) | rsaEncrypted | tag(16) | aesEncrypted
472
468
  const keyIdNum = Number.parseInt(key.keyId, 10)
473
469
  const buf = Buffer.alloc(1 + 1 + 12 + 2 + rsaEncrypted.length + 16 + encrypted.length)
474
470
  let offset = 0
475
- buf.writeUInt8(1, offset); offset += 1
476
- buf.writeUInt8(keyIdNum, offset); offset += 1
477
- iv.copy(buf, offset); offset += 12
478
- buf.writeUInt16LE(rsaEncrypted.length, offset); offset += 2
479
- rsaEncrypted.copy(buf, offset); offset += rsaEncrypted.length
480
- tag.copy(buf, offset); offset += 16
471
+ buf.writeUInt8(1, offset)
472
+ offset += 1
473
+ buf.writeUInt8(keyIdNum, offset)
474
+ offset += 1
475
+ iv.copy(buf, offset)
476
+ offset += 12
477
+ buf.writeUInt16LE(rsaEncrypted.length, offset)
478
+ offset += 2
479
+ rsaEncrypted.copy(buf, offset)
480
+ offset += rsaEncrypted.length
481
+ tag.copy(buf, offset)
482
+ offset += 16
481
483
  encrypted.copy(buf, offset)
482
484
 
483
485
  return `#PWD_INSTAGRAM:4:${timestamp}:${buf.toString('base64')}`
@@ -532,7 +534,7 @@ export class InstagramClient {
532
534
  'X-IG-Connection-Type': 'WIFI',
533
535
  'X-IG-Timezone-Offset': String(new Date().getTimezoneOffset() * -60),
534
536
  'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
535
- 'Accept': '*/*',
537
+ Accept: '*/*',
536
538
  'Accept-Language': 'en-US,en;q=0.9',
537
539
  }
538
540
 
@@ -606,7 +608,6 @@ export class InstagramClient {
606
608
  if (this.session) {
607
609
  this.session.user_id = this.userId ?? undefined
608
610
  this.session.cookies = this.serializeCookies()
609
-
610
611
  }
611
612
 
612
613
  await this.saveSession()
@@ -634,9 +635,13 @@ export class InstagramClient {
634
635
  const items = (thread['items'] ?? []) as Array<Record<string, unknown>>
635
636
  const lastItem = items[0]
636
637
 
637
- const name = threadTitle
638
- || users.map((u) => (u['full_name'] as string) || (u['username'] as string) || '').filter(Boolean).join(', ')
639
- || threadId
638
+ const name =
639
+ threadTitle ||
640
+ users
641
+ .map((u) => (u['full_name'] as string) || (u['username'] as string) || '')
642
+ .filter(Boolean)
643
+ .join(', ') ||
644
+ threadId
640
645
 
641
646
  return {
642
647
  id: threadId,