agent-messenger 2.6.3 → 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 (515) 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 +19 -15
  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.d.ts +3 -0
  192. package/dist/src/platforms/webex/markdown-to-html.d.ts.map +1 -0
  193. package/dist/src/platforms/webex/markdown-to-html.js +161 -0
  194. package/dist/src/platforms/webex/markdown-to-html.js.map +1 -0
  195. package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -1
  196. package/dist/src/platforms/webex/token-extractor.js +5 -14
  197. package/dist/src/platforms/webex/token-extractor.js.map +1 -1
  198. package/dist/src/platforms/wechatbot/client.d.ts.map +1 -1
  199. package/dist/src/platforms/wechatbot/client.js.map +1 -1
  200. package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -1
  201. package/dist/src/platforms/wechatbot/commands/message.js.map +1 -1
  202. package/dist/src/platforms/whatsapp/cli.d.ts.map +1 -1
  203. package/dist/src/platforms/whatsapp/cli.js +1 -4
  204. package/dist/src/platforms/whatsapp/cli.js.map +1 -1
  205. package/dist/src/platforms/whatsapp/commands/chat.d.ts.map +1 -1
  206. package/dist/src/platforms/whatsapp/commands/chat.js.map +1 -1
  207. package/dist/src/platforms/whatsapp/commands/message.d.ts.map +1 -1
  208. package/dist/src/platforms/whatsapp/commands/message.js.map +1 -1
  209. package/dist/src/platforms/whatsapp/commands/shared.d.ts.map +1 -1
  210. package/dist/src/platforms/whatsapp/commands/shared.js.map +1 -1
  211. package/dist/src/platforms/whatsapp/credential-manager.d.ts.map +1 -1
  212. package/dist/src/platforms/whatsapp/credential-manager.js +1 -1
  213. package/dist/src/platforms/whatsapp/credential-manager.js.map +1 -1
  214. package/dist/src/platforms/whatsapp/ensure-auth.d.ts.map +1 -1
  215. package/dist/src/platforms/whatsapp/ensure-auth.js.map +1 -1
  216. package/dist/src/platforms/whatsappbot/client.d.ts.map +1 -1
  217. package/dist/src/platforms/whatsappbot/client.js +2 -2
  218. package/dist/src/platforms/whatsappbot/client.js.map +1 -1
  219. package/dist/src/platforms/whatsappbot/commands/auth.d.ts.map +1 -1
  220. package/dist/src/platforms/whatsappbot/commands/auth.js +4 -1
  221. package/dist/src/platforms/whatsappbot/commands/auth.js.map +1 -1
  222. package/dist/src/platforms/whatsappbot/commands/message.d.ts.map +1 -1
  223. package/dist/src/platforms/whatsappbot/commands/message.js.map +1 -1
  224. package/dist/src/platforms/whatsappbot/commands/shared.d.ts.map +1 -1
  225. package/dist/src/platforms/whatsappbot/commands/shared.js.map +1 -1
  226. package/dist/src/shared/chromium/browsers.d.ts +7 -0
  227. package/dist/src/shared/chromium/browsers.d.ts.map +1 -0
  228. package/dist/src/shared/chromium/browsers.js +89 -0
  229. package/dist/src/shared/chromium/browsers.js.map +1 -0
  230. package/dist/src/shared/chromium/cookie-reader.d.ts +20 -0
  231. package/dist/src/shared/chromium/cookie-reader.d.ts.map +1 -0
  232. package/dist/src/shared/chromium/cookie-reader.js +99 -0
  233. package/dist/src/shared/chromium/cookie-reader.js.map +1 -0
  234. package/dist/src/shared/chromium/decryptor.d.ts +42 -0
  235. package/dist/src/shared/chromium/decryptor.d.ts.map +1 -0
  236. package/dist/src/shared/chromium/decryptor.js +205 -0
  237. package/dist/src/shared/chromium/decryptor.js.map +1 -0
  238. package/dist/src/shared/chromium/index.d.ts +6 -0
  239. package/dist/src/shared/chromium/index.d.ts.map +1 -0
  240. package/dist/src/shared/chromium/index.js +4 -0
  241. package/dist/src/shared/chromium/index.js.map +1 -0
  242. package/dist/src/shared/chromium/types.d.ts +11 -0
  243. package/dist/src/shared/chromium/types.d.ts.map +1 -0
  244. package/dist/src/shared/chromium/types.js +2 -0
  245. package/dist/src/shared/chromium/types.js.map +1 -0
  246. package/dist/src/shared/utils/derived-key-cache.d.ts +1 -1
  247. package/dist/src/shared/utils/derived-key-cache.d.ts.map +1 -1
  248. package/dist/src/shared/utils/linux-keyring.js +4 -1
  249. package/dist/src/shared/utils/linux-keyring.js.map +1 -1
  250. package/dist/src/tui/adapters/kakaotalk-adapter.d.ts.map +1 -1
  251. package/dist/src/tui/adapters/kakaotalk-adapter.js +6 -1
  252. package/dist/src/tui/adapters/kakaotalk-adapter.js.map +1 -1
  253. package/dist/src/tui/adapters/telegram-adapter.js +1 -1
  254. package/dist/src/tui/adapters/telegram-adapter.js.map +1 -1
  255. package/dist/src/tui/adapters/webex-adapter.js +1 -1
  256. package/dist/src/tui/adapters/webex-adapter.js.map +1 -1
  257. package/dist/src/tui/app.d.ts.map +1 -1
  258. package/dist/src/tui/app.js +112 -23
  259. package/dist/src/tui/app.js.map +1 -1
  260. package/dist/src/tui/utils.d.ts.map +1 -1
  261. package/dist/src/tui/utils.js +11 -13
  262. package/dist/src/tui/utils.js.map +1 -1
  263. package/dist/src/tui/views/channel-picker.d.ts.map +1 -1
  264. package/dist/src/tui/views/channel-picker.js.map +1 -1
  265. package/dist/src/tui/views/workspace-picker.d.ts.map +1 -1
  266. package/dist/src/tui/views/workspace-picker.js.map +1 -1
  267. package/docs/content/docs/cli/channeltalk.mdx +24 -22
  268. package/docs/content/docs/cli/channeltalkbot.mdx +7 -7
  269. package/docs/content/docs/cli/instagram.mdx +4 -4
  270. package/docs/content/docs/cli/kakaotalk.mdx +9 -8
  271. package/docs/content/docs/cli/line.mdx +14 -14
  272. package/docs/content/docs/cli/webex.mdx +19 -19
  273. package/docs/content/docs/cli/wechatbot.mdx +12 -11
  274. package/docs/content/docs/cli/whatsapp.mdx +5 -4
  275. package/docs/content/docs/cli/whatsappbot.mdx +11 -11
  276. package/docs/content/docs/index.mdx +7 -7
  277. package/docs/content/docs/meta.json +1 -9
  278. package/docs/content/docs/sdk/channeltalk.mdx +5 -6
  279. package/docs/content/docs/sdk/channeltalkbot.mdx +6 -12
  280. package/docs/content/docs/sdk/discord.mdx +36 -43
  281. package/docs/content/docs/sdk/instagram.mdx +18 -18
  282. package/docs/content/docs/sdk/kakaotalk.mdx +27 -18
  283. package/docs/content/docs/sdk/line.mdx +8 -13
  284. package/docs/content/docs/sdk/meta.json +14 -1
  285. package/docs/content/docs/sdk/slack.mdx +36 -42
  286. package/docs/content/docs/sdk/teams.mdx +2 -8
  287. package/docs/content/docs/sdk/webex.mdx +2 -12
  288. package/docs/content/docs/sdk/wechatbot.mdx +1 -5
  289. package/docs/content/docs/sdk/whatsapp.mdx +10 -19
  290. package/docs/content/docs/sdk/whatsappbot.mdx +2 -10
  291. package/docs/content/docs/tui.mdx +23 -23
  292. package/docs/src/app/page.tsx +353 -108
  293. package/e2e/channeltalkbot.e2e.test.ts +1 -5
  294. package/e2e/config.ts +6 -2
  295. package/package.json +59 -58
  296. package/scripts/prepublish.ts +1 -3
  297. package/skills/agent-channeltalk/SKILL.md +1 -1
  298. package/skills/agent-channeltalkbot/SKILL.md +1 -1
  299. package/skills/agent-discord/SKILL.md +1 -1
  300. package/skills/agent-discordbot/SKILL.md +1 -1
  301. package/skills/agent-instagram/SKILL.md +1 -1
  302. package/skills/agent-kakaotalk/SKILL.md +1 -1
  303. package/skills/agent-line/SKILL.md +1 -1
  304. package/skills/agent-slack/SKILL.md +1 -1
  305. package/skills/agent-slackbot/SKILL.md +1 -1
  306. package/skills/agent-teams/SKILL.md +1 -1
  307. package/skills/agent-telegram/SKILL.md +1 -1
  308. package/skills/agent-webex/SKILL.md +1 -1
  309. package/skills/agent-wechatbot/SKILL.md +1 -1
  310. package/skills/agent-whatsapp/SKILL.md +1 -1
  311. package/skills/agent-whatsappbot/SKILL.md +1 -1
  312. package/src/platforms/channeltalk/client.test.ts +116 -29
  313. package/src/platforms/channeltalk/client.ts +26 -6
  314. package/src/platforms/channeltalk/commands/auth.test.ts +5 -5
  315. package/src/platforms/channeltalk/commands/auth.ts +19 -5
  316. package/src/platforms/channeltalk/commands/message.test.ts +2 -6
  317. package/src/platforms/channeltalk/commands/message.ts +5 -1
  318. package/src/platforms/channeltalk/commands/snapshot.test.ts +19 -4
  319. package/src/platforms/channeltalk/commands/snapshot.ts +5 -1
  320. package/src/platforms/channeltalk/ensure-auth.test.ts +20 -17
  321. package/src/platforms/channeltalk/ensure-auth.ts +6 -7
  322. package/src/platforms/channeltalk/index.ts +0 -1
  323. package/src/platforms/channeltalk/token-extractor.test.ts +33 -25
  324. package/src/platforms/channeltalk/token-extractor.ts +120 -372
  325. package/src/platforms/channeltalkbot/client.test.ts +1 -3
  326. package/src/platforms/channeltalkbot/client.ts +39 -13
  327. package/src/platforms/channeltalkbot/commands/auth.test.ts +3 -1
  328. package/src/platforms/channeltalkbot/commands/auth.ts +4 -1
  329. package/src/platforms/channeltalkbot/commands/bot.test.ts +13 -5
  330. package/src/platforms/channeltalkbot/commands/message.test.ts +12 -6
  331. package/src/platforms/channeltalkbot/commands/shared.ts +6 -2
  332. package/src/platforms/channeltalkbot/commands/snapshot.test.ts +17 -5
  333. package/src/platforms/channeltalkbot/credential-manager.test.ts +1 -1
  334. package/src/platforms/channeltalkbot/index.test.ts +0 -2
  335. package/src/platforms/channeltalkbot/index.ts +0 -1
  336. package/src/platforms/discord/commands/auth.test.ts +6 -4
  337. package/src/platforms/discord/commands/auth.ts +14 -14
  338. package/src/platforms/discord/commands/whoami.test.ts +2 -4
  339. package/src/platforms/discord/commands/whoami.ts +2 -0
  340. package/src/platforms/discord/ensure-auth.test.ts +5 -3
  341. package/src/platforms/discord/index.ts +0 -1
  342. package/src/platforms/discord/listener.test.ts +7 -1
  343. package/src/platforms/discord/token-extractor.test.ts +18 -12
  344. package/src/platforms/discord/token-extractor.ts +46 -190
  345. package/src/platforms/discordbot/client.ts +1 -4
  346. package/src/platforms/discordbot/commands/auth.test.ts +3 -1
  347. package/src/platforms/discordbot/commands/channel.test.ts +3 -1
  348. package/src/platforms/discordbot/commands/message.test.ts +3 -1
  349. package/src/platforms/discordbot/commands/server.test.ts +3 -1
  350. package/src/platforms/discordbot/commands/snapshot.test.ts +3 -1
  351. package/src/platforms/discordbot/commands/thread.test.ts +3 -1
  352. package/src/platforms/discordbot/commands/user.test.ts +3 -1
  353. package/src/platforms/instagram/cli.ts +1 -4
  354. package/src/platforms/instagram/client.test.ts +3 -8
  355. package/src/platforms/instagram/client.ts +39 -34
  356. package/src/platforms/instagram/commands/auth.test.ts +13 -12
  357. package/src/platforms/instagram/commands/auth.ts +136 -71
  358. package/src/platforms/instagram/commands/chat.test.ts +21 -24
  359. package/src/platforms/instagram/commands/chat.ts +2 -0
  360. package/src/platforms/instagram/commands/message.test.ts +29 -24
  361. package/src/platforms/instagram/commands/message.ts +3 -4
  362. package/src/platforms/instagram/commands/shared.ts +2 -5
  363. package/src/platforms/instagram/commands/whoami.test.ts +4 -6
  364. package/src/platforms/instagram/credential-manager.ts +2 -6
  365. package/src/platforms/instagram/ensure-auth.test.ts +1 -4
  366. package/src/platforms/instagram/ensure-auth.ts +6 -3
  367. package/src/platforms/instagram/listener.test.ts +7 -3
  368. package/src/platforms/instagram/token-extractor.test.ts +4 -16
  369. package/src/platforms/instagram/token-extractor.ts +55 -309
  370. package/src/platforms/instagram/types.test.ts +2 -6
  371. package/src/platforms/instagram/types.ts +4 -2
  372. package/src/platforms/kakaotalk/auth/kakao-login.ts +30 -8
  373. package/src/platforms/kakaotalk/client.test.ts +37 -25
  374. package/src/platforms/kakaotalk/client.ts +23 -12
  375. package/src/platforms/kakaotalk/commands/auth.test.ts +6 -18
  376. package/src/platforms/kakaotalk/commands/auth.ts +101 -47
  377. package/src/platforms/kakaotalk/commands/chat.test.ts +8 -11
  378. package/src/platforms/kakaotalk/commands/message.test.ts +15 -24
  379. package/src/platforms/kakaotalk/commands/shared.ts +1 -0
  380. package/src/platforms/kakaotalk/commands/whoami.test.ts +6 -10
  381. package/src/platforms/kakaotalk/credential-manager.test.ts +1 -4
  382. package/src/platforms/kakaotalk/index.test.ts +1 -0
  383. package/src/platforms/kakaotalk/index.ts +0 -2
  384. package/src/platforms/kakaotalk/listener.test.ts +7 -1
  385. package/src/platforms/kakaotalk/protocol/connection.ts +4 -1
  386. package/src/platforms/kakaotalk/protocol/crypto.ts +1 -1
  387. package/src/platforms/kakaotalk/protocol/session.ts +12 -6
  388. package/src/platforms/kakaotalk/token-extractor.ts +5 -5
  389. package/src/platforms/kakaotalk/types.ts +8 -7
  390. package/src/platforms/line/cli.ts +1 -4
  391. package/src/platforms/line/client.ts +12 -20
  392. package/src/platforms/line/commands/auth.test.ts +2 -1
  393. package/src/platforms/line/commands/chat.test.ts +2 -1
  394. package/src/platforms/line/commands/chat.ts +1 -4
  395. package/src/platforms/line/commands/friend.test.ts +2 -1
  396. package/src/platforms/line/commands/message.test.ts +2 -1
  397. package/src/platforms/line/commands/message.ts +2 -9
  398. package/src/platforms/line/commands/whoami.test.ts +2 -1
  399. package/src/platforms/line/credential-manager.test.ts +1 -2
  400. package/src/platforms/line/index.test.ts +1 -0
  401. package/src/platforms/line/listener.ts +1 -1
  402. package/src/platforms/line/types.test.ts +1 -0
  403. package/src/platforms/slack/cli.ts +3 -1
  404. package/src/platforms/slack/client-mappers.ts +297 -0
  405. package/src/platforms/slack/client.test.ts +532 -17
  406. package/src/platforms/slack/client.ts +69 -458
  407. package/src/platforms/slack/commands/channel.ts +1 -4
  408. package/src/platforms/slack/commands/emoji.test.ts +6 -4
  409. package/src/platforms/slack/commands/emoji.ts +20 -22
  410. package/src/platforms/slack/commands/message.ts +6 -1
  411. package/src/platforms/slack/commands/pin.test.ts +14 -12
  412. package/src/platforms/slack/commands/reminder.ts +7 -6
  413. package/src/platforms/slack/commands/user.ts +6 -1
  414. package/src/platforms/slack/commands/usergroup.test.ts +3 -3
  415. package/src/platforms/slack/commands/usergroup.ts +10 -7
  416. package/src/platforms/slack/commands/whoami.test.ts +1 -1
  417. package/src/platforms/slack/commands/whoami.ts +2 -0
  418. package/src/platforms/slack/index.ts +0 -2
  419. package/src/platforms/slack/listener.test.ts +1 -0
  420. package/src/platforms/slack/token-extractor.test.ts +7 -12
  421. package/src/platforms/slack/token-extractor.ts +47 -255
  422. package/src/platforms/slackbot/cli.ts +8 -1
  423. package/src/platforms/slackbot/commands/auth.test.ts +3 -1
  424. package/src/platforms/teams/client.ts +1 -1
  425. package/src/platforms/teams/commands/auth.test.ts +1 -1
  426. package/src/platforms/teams/commands/auth.ts +4 -1
  427. package/src/platforms/teams/commands/whoami.test.ts +2 -4
  428. package/src/platforms/teams/commands/whoami.ts +2 -0
  429. package/src/platforms/teams/index.ts +0 -1
  430. package/src/platforms/teams/token-extractor.ts +82 -350
  431. package/src/platforms/telegram/app-config.test.ts +1 -0
  432. package/src/platforms/telegram/chat-utils.test.ts +5 -1
  433. package/src/platforms/telegram/cli.ts +2 -4
  434. package/src/platforms/telegram/client.test.ts +16 -3
  435. package/src/platforms/telegram/client.ts +14 -4
  436. package/src/platforms/telegram/commands/auth.test.ts +1 -0
  437. package/src/platforms/telegram/commands/auth.ts +3 -4
  438. package/src/platforms/telegram/commands/chat.test.ts +2 -5
  439. package/src/platforms/telegram/commands/chat.ts +1 -0
  440. package/src/platforms/telegram/commands/message.test.ts +2 -5
  441. package/src/platforms/telegram/commands/message.ts +1 -0
  442. package/src/platforms/telegram/commands/shared.test.ts +1 -0
  443. package/src/platforms/telegram/commands/whoami.test.ts +5 -7
  444. package/src/platforms/telegram/commands/whoami.ts +1 -1
  445. package/src/platforms/telegram/credential-manager.test.ts +1 -0
  446. package/src/platforms/telegram/credential-manager.ts +11 -2
  447. package/src/platforms/telegram/my-telegram-org.ts +6 -2
  448. package/src/platforms/telegram/types.test.ts +1 -0
  449. package/src/platforms/webex/app-config.test.ts +1 -0
  450. package/src/platforms/webex/cli.ts +1 -4
  451. package/src/platforms/webex/client.test.ts +39 -12
  452. package/src/platforms/webex/client.ts +30 -61
  453. package/src/platforms/webex/commands/auth.test.ts +7 -1
  454. package/src/platforms/webex/commands/auth.ts +12 -15
  455. package/src/platforms/webex/commands/member.test.ts +1 -3
  456. package/src/platforms/webex/commands/member.ts +14 -19
  457. package/src/platforms/webex/commands/message.ts +4 -15
  458. package/src/platforms/webex/commands/snapshot.test.ts +28 -3
  459. package/src/platforms/webex/commands/snapshot.ts +3 -3
  460. package/src/platforms/webex/commands/space.test.ts +3 -3
  461. package/src/platforms/webex/commands/space.ts +2 -9
  462. package/src/platforms/webex/commands/whoami.test.ts +12 -5
  463. package/src/platforms/webex/commands/whoami.ts +2 -0
  464. package/src/platforms/webex/credential-manager.ts +11 -2
  465. package/src/platforms/webex/ensure-auth.ts +1 -3
  466. package/src/platforms/webex/index.ts +1 -7
  467. package/src/platforms/webex/markdown-to-html.test.ts +141 -0
  468. package/src/platforms/webex/markdown-to-html.ts +194 -0
  469. package/src/platforms/webex/token-extractor.ts +6 -29
  470. package/src/platforms/wechatbot/cli.ts +0 -0
  471. package/src/platforms/wechatbot/client.test.ts +6 -2
  472. package/src/platforms/wechatbot/client.ts +6 -1
  473. package/src/platforms/wechatbot/commands/auth.test.ts +3 -7
  474. package/src/platforms/wechatbot/commands/message.test.ts +1 -4
  475. package/src/platforms/wechatbot/commands/message.ts +5 -1
  476. package/src/platforms/wechatbot/commands/template.test.ts +1 -4
  477. package/src/platforms/wechatbot/commands/user.test.ts +2 -7
  478. package/src/platforms/whatsapp/cli.ts +1 -4
  479. package/src/platforms/whatsapp/commands/auth.test.ts +19 -22
  480. package/src/platforms/whatsapp/commands/chat.test.ts +21 -24
  481. package/src/platforms/whatsapp/commands/chat.ts +2 -0
  482. package/src/platforms/whatsapp/commands/message.test.ts +22 -24
  483. package/src/platforms/whatsapp/commands/message.ts +3 -5
  484. package/src/platforms/whatsapp/commands/shared.ts +2 -5
  485. package/src/platforms/whatsapp/commands/whoami.test.ts +2 -2
  486. package/src/platforms/whatsapp/credential-manager.ts +2 -6
  487. package/src/platforms/whatsapp/ensure-auth.test.ts +1 -4
  488. package/src/platforms/whatsapp/ensure-auth.ts +14 -6
  489. package/src/platforms/whatsapp/index.ts +0 -2
  490. package/src/platforms/whatsappbot/client.test.ts +13 -7
  491. package/src/platforms/whatsappbot/client.ts +18 -4
  492. package/src/platforms/whatsappbot/commands/auth.ts +4 -1
  493. package/src/platforms/whatsappbot/commands/message.test.ts +12 -2
  494. package/src/platforms/whatsappbot/commands/message.ts +16 -3
  495. package/src/platforms/whatsappbot/commands/shared.ts +3 -1
  496. package/src/platforms/whatsappbot/commands/whoami.test.ts +1 -3
  497. package/src/platforms/whatsappbot/index.ts +0 -2
  498. package/src/shared/chromium/browsers.test.ts +274 -0
  499. package/src/shared/chromium/browsers.ts +86 -0
  500. package/src/shared/chromium/cookie-reader.test.ts +274 -0
  501. package/src/shared/chromium/cookie-reader.ts +111 -0
  502. package/src/shared/chromium/decryptor.test.ts +449 -0
  503. package/src/shared/chromium/decryptor.ts +227 -0
  504. package/src/shared/chromium/index.ts +11 -0
  505. package/src/shared/chromium/types.ts +11 -0
  506. package/src/shared/utils/derived-key-cache.ts +1 -1
  507. package/src/shared/utils/linux-keyring.ts +4 -4
  508. package/src/tui/adapters/kakaotalk-adapter.ts +6 -1
  509. package/src/tui/adapters/telegram-adapter.ts +1 -1
  510. package/src/tui/adapters/webex-adapter.ts +1 -1
  511. package/src/tui/app.ts +149 -59
  512. package/src/tui/utils.test.ts +144 -145
  513. package/src/tui/utils.ts +27 -29
  514. package/src/tui/views/channel-picker.ts +1 -1
  515. 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
+ })