agent-messenger 2.10.1 → 2.10.2

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 (239) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dist/package.json +1 -1
  3. package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
  4. package/dist/src/platforms/teams/token-extractor.js +9 -2
  5. package/dist/src/platforms/teams/token-extractor.js.map +1 -1
  6. package/dist/src/shared/chromium/decryptor.d.ts +6 -0
  7. package/dist/src/shared/chromium/decryptor.d.ts.map +1 -1
  8. package/dist/src/shared/chromium/decryptor.js +26 -6
  9. package/dist/src/shared/chromium/decryptor.js.map +1 -1
  10. package/e2e/channeltalk.e2e.test.ts +13 -13
  11. package/e2e/channeltalkbot.e2e.test.ts +13 -13
  12. package/e2e/discord.e2e.test.ts +24 -24
  13. package/e2e/discordbot.e2e.test.ts +16 -16
  14. package/e2e/instagram.e2e.test.ts +10 -10
  15. package/e2e/kakaotalk.e2e.test.ts +7 -7
  16. package/e2e/line.e2e.test.ts +8 -8
  17. package/e2e/slack.e2e.test.ts +34 -34
  18. package/e2e/slackbot.e2e.test.ts +14 -14
  19. package/e2e/teams.e2e.test.ts +23 -23
  20. package/e2e/telegram.e2e.test.ts +8 -8
  21. package/e2e/webex.e2e.test.ts +14 -14
  22. package/e2e/whatsapp.e2e.test.ts +8 -8
  23. package/e2e/whatsappbot.e2e.test.ts +6 -6
  24. package/package.json +1 -1
  25. package/skills/agent-channeltalk/SKILL.md +1 -1
  26. package/skills/agent-channeltalkbot/SKILL.md +1 -1
  27. package/skills/agent-discord/SKILL.md +1 -1
  28. package/skills/agent-discordbot/SKILL.md +1 -1
  29. package/skills/agent-instagram/SKILL.md +1 -1
  30. package/skills/agent-kakaotalk/SKILL.md +1 -1
  31. package/skills/agent-line/SKILL.md +1 -1
  32. package/skills/agent-slack/SKILL.md +1 -1
  33. package/skills/agent-slackbot/SKILL.md +1 -1
  34. package/skills/agent-teams/SKILL.md +1 -1
  35. package/skills/agent-telegram/SKILL.md +1 -1
  36. package/skills/agent-webex/SKILL.md +1 -1
  37. package/skills/agent-wechatbot/SKILL.md +1 -1
  38. package/skills/agent-whatsapp/SKILL.md +1 -1
  39. package/skills/agent-whatsappbot/SKILL.md +1 -1
  40. package/src/platforms/channeltalk/client.test.ts +26 -26
  41. package/src/platforms/channeltalk/commands/auth.test.ts +16 -16
  42. package/src/platforms/channeltalk/commands/bot.test.ts +2 -2
  43. package/src/platforms/channeltalk/commands/chat.test.ts +3 -3
  44. package/src/platforms/channeltalk/commands/group.test.ts +4 -4
  45. package/src/platforms/channeltalk/commands/manager.test.ts +2 -2
  46. package/src/platforms/channeltalk/commands/message.test.ts +17 -17
  47. package/src/platforms/channeltalk/commands/snapshot.test.ts +7 -7
  48. package/src/platforms/channeltalk/commands/whoami.test.ts +3 -3
  49. package/src/platforms/channeltalk/credential-manager.test.ts +18 -18
  50. package/src/platforms/channeltalk/ensure-auth.test.ts +5 -5
  51. package/src/platforms/channeltalk/index.test.ts +23 -23
  52. package/src/platforms/channeltalk/token-extractor.test.ts +21 -21
  53. package/src/platforms/channeltalk/types.test.ts +12 -12
  54. package/src/platforms/channeltalkbot/client.test.ts +14 -14
  55. package/src/platforms/channeltalkbot/commands/auth.test.ts +16 -16
  56. package/src/platforms/channeltalkbot/commands/bot.test.ts +6 -6
  57. package/src/platforms/channeltalkbot/commands/chat.test.ts +9 -9
  58. package/src/platforms/channeltalkbot/commands/group.test.ts +6 -6
  59. package/src/platforms/channeltalkbot/commands/manager.test.ts +3 -3
  60. package/src/platforms/channeltalkbot/commands/message.test.ts +10 -10
  61. package/src/platforms/channeltalkbot/commands/snapshot.test.ts +7 -7
  62. package/src/platforms/channeltalkbot/commands/whoami.test.ts +4 -4
  63. package/src/platforms/channeltalkbot/credential-manager.test.ts +27 -27
  64. package/src/platforms/channeltalkbot/index.test.ts +15 -15
  65. package/src/platforms/discord/client.test.ts +28 -28
  66. package/src/platforms/discord/commands/auth.test.ts +7 -7
  67. package/src/platforms/discord/commands/channel.test.ts +7 -7
  68. package/src/platforms/discord/commands/dm.test.ts +4 -4
  69. package/src/platforms/discord/commands/file.test.ts +4 -4
  70. package/src/platforms/discord/commands/friend.test.ts +6 -6
  71. package/src/platforms/discord/commands/member.test.ts +5 -5
  72. package/src/platforms/discord/commands/mention.test.ts +5 -5
  73. package/src/platforms/discord/commands/message.test.ts +9 -9
  74. package/src/platforms/discord/commands/note.test.ts +6 -6
  75. package/src/platforms/discord/commands/profile.test.ts +4 -4
  76. package/src/platforms/discord/commands/reaction.test.ts +5 -5
  77. package/src/platforms/discord/commands/server.test.ts +7 -7
  78. package/src/platforms/discord/commands/snapshot.test.ts +6 -6
  79. package/src/platforms/discord/commands/thread.test.ts +6 -6
  80. package/src/platforms/discord/commands/user.test.ts +5 -5
  81. package/src/platforms/discord/commands/whoami.test.ts +6 -6
  82. package/src/platforms/discord/credential-manager.test.ts +16 -16
  83. package/src/platforms/discord/ensure-auth.test.ts +8 -8
  84. package/src/platforms/discord/index.test.ts +17 -17
  85. package/src/platforms/discord/listener.test.ts +33 -33
  86. package/src/platforms/discord/token-extractor.test.ts +53 -53
  87. package/src/platforms/discord/types.test.ts +26 -26
  88. package/src/platforms/discordbot/client.test.ts +31 -31
  89. package/src/platforms/discordbot/commands/auth.test.ts +18 -18
  90. package/src/platforms/discordbot/commands/channel.test.ts +11 -11
  91. package/src/platforms/discordbot/commands/file.test.ts +7 -7
  92. package/src/platforms/discordbot/commands/message.test.ts +25 -25
  93. package/src/platforms/discordbot/commands/reaction.test.ts +6 -6
  94. package/src/platforms/discordbot/commands/server.test.ts +12 -12
  95. package/src/platforms/discordbot/commands/snapshot.test.ts +13 -13
  96. package/src/platforms/discordbot/commands/thread.test.ts +10 -10
  97. package/src/platforms/discordbot/commands/user.test.ts +9 -9
  98. package/src/platforms/discordbot/commands/whoami.test.ts +4 -4
  99. package/src/platforms/discordbot/credential-manager.test.ts +28 -28
  100. package/src/platforms/instagram/client.test.ts +18 -18
  101. package/src/platforms/instagram/commands/auth.test.ts +11 -11
  102. package/src/platforms/instagram/commands/chat.test.ts +6 -6
  103. package/src/platforms/instagram/commands/message.test.ts +11 -11
  104. package/src/platforms/instagram/commands/shared.test.ts +12 -12
  105. package/src/platforms/instagram/commands/whoami.test.ts +3 -3
  106. package/src/platforms/instagram/credential-manager.test.ts +21 -21
  107. package/src/platforms/instagram/ensure-auth.test.ts +4 -4
  108. package/src/platforms/instagram/index.test.ts +9 -9
  109. package/src/platforms/instagram/listener.test.ts +8 -8
  110. package/src/platforms/instagram/token-extractor.test.ts +35 -35
  111. package/src/platforms/kakaotalk/client.test.ts +33 -33
  112. package/src/platforms/kakaotalk/commands/auth.test.ts +11 -11
  113. package/src/platforms/kakaotalk/commands/chat.test.ts +6 -6
  114. package/src/platforms/kakaotalk/commands/message.test.ts +7 -7
  115. package/src/platforms/kakaotalk/commands/whoami.test.ts +5 -5
  116. package/src/platforms/kakaotalk/credential-manager.test.ts +15 -15
  117. package/src/platforms/kakaotalk/index.test.ts +15 -15
  118. package/src/platforms/kakaotalk/listener.test.ts +17 -17
  119. package/src/platforms/line/client.test.ts +17 -17
  120. package/src/platforms/line/commands/auth.test.ts +8 -8
  121. package/src/platforms/line/commands/chat.test.ts +7 -7
  122. package/src/platforms/line/commands/friend.test.ts +6 -6
  123. package/src/platforms/line/commands/message.test.ts +7 -7
  124. package/src/platforms/line/commands/whoami.test.ts +6 -6
  125. package/src/platforms/line/credential-manager.test.ts +17 -17
  126. package/src/platforms/line/index.test.ts +10 -10
  127. package/src/platforms/line/listener.test.ts +15 -15
  128. package/src/platforms/line/types.test.ts +14 -14
  129. package/src/platforms/slack/cli.test.ts +8 -8
  130. package/src/platforms/slack/client.test.ts +151 -151
  131. package/src/platforms/slack/commands/activity.test.ts +13 -13
  132. package/src/platforms/slack/commands/auth.test.ts +34 -34
  133. package/src/platforms/slack/commands/bookmark.test.ts +9 -9
  134. package/src/platforms/slack/commands/channel.test.ts +17 -17
  135. package/src/platforms/slack/commands/drafts.test.ts +7 -7
  136. package/src/platforms/slack/commands/emoji.test.ts +3 -3
  137. package/src/platforms/slack/commands/file.test.ts +12 -12
  138. package/src/platforms/slack/commands/message.test.ts +19 -19
  139. package/src/platforms/slack/commands/pin.test.ts +7 -7
  140. package/src/platforms/slack/commands/reaction.test.ts +10 -10
  141. package/src/platforms/slack/commands/reminder.test.ts +9 -9
  142. package/src/platforms/slack/commands/saved.test.ts +7 -7
  143. package/src/platforms/slack/commands/sections.test.ts +5 -5
  144. package/src/platforms/slack/commands/snapshot.test.ts +13 -13
  145. package/src/platforms/slack/commands/unread.test.ts +6 -6
  146. package/src/platforms/slack/commands/user.test.ts +10 -10
  147. package/src/platforms/slack/commands/usergroup.test.ts +15 -15
  148. package/src/platforms/slack/commands/whoami.test.ts +6 -6
  149. package/src/platforms/slack/commands/workspace.test.ts +26 -26
  150. package/src/platforms/slack/credential-manager.test.ts +14 -14
  151. package/src/platforms/slack/ensure-auth.test.ts +21 -21
  152. package/src/platforms/slack/index.test.ts +12 -12
  153. package/src/platforms/slack/listener.test.ts +17 -17
  154. package/src/platforms/slack/token-extractor-node.test.ts +2 -2
  155. package/src/platforms/slack/token-extractor.test.ts +37 -37
  156. package/src/platforms/slack/types.test.ts +21 -21
  157. package/src/platforms/slackbot/client.test.ts +22 -22
  158. package/src/platforms/slackbot/commands/auth.test.ts +14 -14
  159. package/src/platforms/slackbot/commands/channel.test.ts +7 -7
  160. package/src/platforms/slackbot/commands/message.test.ts +13 -13
  161. package/src/platforms/slackbot/commands/reaction.test.ts +6 -6
  162. package/src/platforms/slackbot/commands/user.test.ts +7 -7
  163. package/src/platforms/slackbot/commands/whoami.test.ts +4 -4
  164. package/src/platforms/slackbot/credential-manager.test.ts +22 -22
  165. package/src/platforms/slackbot/types.test.ts +7 -7
  166. package/src/platforms/teams/client.test.ts +30 -30
  167. package/src/platforms/teams/commands/auth.test.ts +8 -8
  168. package/src/platforms/teams/commands/channel.test.ts +7 -7
  169. package/src/platforms/teams/commands/file.test.ts +4 -4
  170. package/src/platforms/teams/commands/message.test.ts +5 -5
  171. package/src/platforms/teams/commands/reaction.test.ts +4 -4
  172. package/src/platforms/teams/commands/snapshot.test.ts +7 -7
  173. package/src/platforms/teams/commands/team.test.ts +8 -8
  174. package/src/platforms/teams/commands/user.test.ts +4 -4
  175. package/src/platforms/teams/commands/whoami.test.ts +6 -6
  176. package/src/platforms/teams/credential-manager.test.ts +17 -17
  177. package/src/platforms/teams/ensure-auth.test.ts +13 -13
  178. package/src/platforms/teams/index.test.ts +15 -15
  179. package/src/platforms/teams/token-extractor.test.ts +109 -49
  180. package/src/platforms/teams/token-extractor.ts +7 -2
  181. package/src/platforms/teams/types.test.ts +26 -26
  182. package/src/platforms/telegram/app-config.test.ts +4 -4
  183. package/src/platforms/telegram/chat-utils.test.ts +12 -12
  184. package/src/platforms/telegram/client.test.ts +4 -4
  185. package/src/platforms/telegram/commands/auth.test.ts +16 -16
  186. package/src/platforms/telegram/commands/chat.test.ts +9 -9
  187. package/src/platforms/telegram/commands/message.test.ts +6 -6
  188. package/src/platforms/telegram/commands/shared.test.ts +3 -3
  189. package/src/platforms/telegram/commands/whoami.test.ts +3 -3
  190. package/src/platforms/telegram/credential-manager.test.ts +10 -10
  191. package/src/platforms/telegram/types.test.ts +6 -6
  192. package/src/platforms/webex/app-config.test.ts +8 -8
  193. package/src/platforms/webex/cli.test.ts +5 -5
  194. package/src/platforms/webex/client.test.ts +65 -65
  195. package/src/platforms/webex/commands/auth.test.ts +18 -18
  196. package/src/platforms/webex/commands/member.test.ts +5 -5
  197. package/src/platforms/webex/commands/message.test.ts +12 -12
  198. package/src/platforms/webex/commands/snapshot.test.ts +5 -5
  199. package/src/platforms/webex/commands/space.test.ts +10 -10
  200. package/src/platforms/webex/commands/whoami.test.ts +6 -6
  201. package/src/platforms/webex/credential-manager.test.ts +22 -22
  202. package/src/platforms/webex/encryption.test.ts +4 -4
  203. package/src/platforms/webex/ensure-auth.test.ts +5 -5
  204. package/src/platforms/webex/index.test.ts +5 -5
  205. package/src/platforms/webex/markdown-to-html.test.ts +33 -33
  206. package/src/platforms/webex/token-extractor.test.ts +23 -23
  207. package/src/platforms/webex/types.test.ts +27 -27
  208. package/src/platforms/wechatbot/client.test.ts +27 -27
  209. package/src/platforms/wechatbot/commands/auth.test.ts +15 -15
  210. package/src/platforms/wechatbot/commands/message.test.ts +8 -8
  211. package/src/platforms/wechatbot/commands/template.test.ts +9 -9
  212. package/src/platforms/wechatbot/commands/user.test.ts +7 -7
  213. package/src/platforms/wechatbot/commands/whoami.test.ts +5 -5
  214. package/src/platforms/wechatbot/credential-manager.test.ts +18 -18
  215. package/src/platforms/wechatbot/index.test.ts +10 -10
  216. package/src/platforms/wechatbot/types.test.ts +25 -25
  217. package/src/platforms/whatsapp/commands/auth.test.ts +13 -13
  218. package/src/platforms/whatsapp/commands/chat.test.ts +8 -8
  219. package/src/platforms/whatsapp/commands/message.test.ts +10 -10
  220. package/src/platforms/whatsapp/commands/whoami.test.ts +3 -3
  221. package/src/platforms/whatsapp/credential-manager.test.ts +23 -23
  222. package/src/platforms/whatsapp/ensure-auth.test.ts +4 -4
  223. package/src/platforms/whatsapp/index.test.ts +8 -8
  224. package/src/platforms/whatsapp/types.test.ts +42 -42
  225. package/src/platforms/whatsappbot/client.test.ts +27 -27
  226. package/src/platforms/whatsappbot/commands/auth.test.ts +14 -14
  227. package/src/platforms/whatsappbot/commands/message.test.ts +16 -16
  228. package/src/platforms/whatsappbot/commands/template.test.ts +9 -9
  229. package/src/platforms/whatsappbot/commands/whoami.test.ts +5 -5
  230. package/src/platforms/whatsappbot/credential-manager.test.ts +18 -18
  231. package/src/platforms/whatsappbot/index.test.ts +7 -7
  232. package/src/platforms/whatsappbot/types.test.ts +18 -18
  233. package/src/shared/chromium/browsers.test.ts +22 -22
  234. package/src/shared/chromium/cookie-reader.test.ts +13 -13
  235. package/src/shared/chromium/decryptor.test.ts +97 -32
  236. package/src/shared/chromium/decryptor.ts +27 -6
  237. package/src/shared/utils/concurrency.test.ts +6 -6
  238. package/src/shared/utils/derived-key-cache.test.ts +11 -11
  239. package/src/tui/utils.test.ts +31 -31
@@ -1,4 +1,4 @@
1
- import { beforeEach, describe, expect, spyOn, test } from 'bun:test'
1
+ import { beforeEach, describe, expect, spyOn, it } from 'bun:test'
2
2
  import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
3
3
  import { homedir, tmpdir } from 'node:os'
4
4
  import { join } from 'node:path'
@@ -13,7 +13,7 @@ describe('TeamsTokenExtractor', () => {
13
13
  })
14
14
 
15
15
  describe('getDesktopCookiesPaths', () => {
16
- test('returns darwin desktop paths on macOS', () => {
16
+ it('returns darwin desktop paths on macOS', () => {
17
17
  const darwinExtractor = new TeamsTokenExtractor('darwin')
18
18
  const paths = darwinExtractor.getDesktopCookiesPaths()
19
19
 
@@ -43,7 +43,7 @@ describe('TeamsTokenExtractor', () => {
43
43
  ])
44
44
  })
45
45
 
46
- test('returns linux desktop path on Linux', () => {
46
+ it('returns linux desktop path on Linux', () => {
47
47
  const linuxExtractor = new TeamsTokenExtractor('linux')
48
48
  const paths = linuxExtractor.getDesktopCookiesPaths()
49
49
 
@@ -55,7 +55,7 @@ describe('TeamsTokenExtractor', () => {
55
55
  ])
56
56
  })
57
57
 
58
- test('returns win32 desktop paths on Windows', () => {
58
+ it('returns win32 desktop paths on Windows', () => {
59
59
  const winExtractor = new TeamsTokenExtractor('win32')
60
60
  const paths = winExtractor.getDesktopCookiesPaths()
61
61
 
@@ -81,14 +81,14 @@ describe('TeamsTokenExtractor', () => {
81
81
  ])
82
82
  })
83
83
 
84
- test('returns empty array for unsupported platform', () => {
84
+ it('returns empty array for unsupported platform', () => {
85
85
  const unsupportedExtractor = new TeamsTokenExtractor('freebsd' as NodeJS.Platform)
86
86
  expect(unsupportedExtractor.getDesktopCookiesPaths()).toEqual([])
87
87
  })
88
88
  })
89
89
 
90
90
  describe('getBrowserCookiesPaths', () => {
91
- test('returns browser cookie paths on macOS (at least Default profile per browser)', () => {
91
+ it('returns browser cookie paths on macOS (at least Default profile per browser)', () => {
92
92
  const darwinExtractor = new TeamsTokenExtractor('darwin')
93
93
  const paths = darwinExtractor.getBrowserCookiesPaths()
94
94
 
@@ -103,7 +103,7 @@ describe('TeamsTokenExtractor', () => {
103
103
  })
104
104
  })
105
105
 
106
- test('returns browser cookie paths on Linux', () => {
106
+ it('returns browser cookie paths on Linux', () => {
107
107
  const linuxExtractor = new TeamsTokenExtractor('linux')
108
108
  const paths = linuxExtractor.getBrowserCookiesPaths()
109
109
 
@@ -114,7 +114,7 @@ describe('TeamsTokenExtractor', () => {
114
114
  })
115
115
  })
116
116
 
117
- test('returns browser cookie paths on Windows', () => {
117
+ it('returns browser cookie paths on Windows', () => {
118
118
  const winExtractor = new TeamsTokenExtractor('win32')
119
119
  const paths = winExtractor.getBrowserCookiesPaths()
120
120
 
@@ -126,12 +126,12 @@ describe('TeamsTokenExtractor', () => {
126
126
  })
127
127
  })
128
128
 
129
- test('returns empty array for unsupported platform', () => {
129
+ it('returns empty array for unsupported platform', () => {
130
130
  const unsupportedExtractor = new TeamsTokenExtractor('freebsd' as NodeJS.Platform)
131
131
  expect(unsupportedExtractor.getBrowserCookiesPaths()).toEqual([])
132
132
  })
133
133
 
134
- test('all browser paths have accountType work', () => {
134
+ it('all browser paths have accountType work', () => {
135
135
  const darwinExtractor = new TeamsTokenExtractor('darwin')
136
136
  const paths = darwinExtractor.getBrowserCookiesPaths()
137
137
  expect(paths.every((p) => p.accountType === 'work')).toBe(true)
@@ -139,7 +139,7 @@ describe('TeamsTokenExtractor', () => {
139
139
  })
140
140
 
141
141
  describe('getTeamsCookiesPaths', () => {
142
- test('returns darwin paths on macOS with desktop paths first', () => {
142
+ it('returns darwin paths on macOS with desktop paths first', () => {
143
143
  const darwinExtractor = new TeamsTokenExtractor('darwin')
144
144
  const paths = darwinExtractor.getTeamsCookiesPaths()
145
145
  const desktopPaths = darwinExtractor.getDesktopCookiesPaths()
@@ -147,7 +147,7 @@ describe('TeamsTokenExtractor', () => {
147
147
  expect(paths.slice(0, desktopPaths.length)).toEqual(desktopPaths)
148
148
  })
149
149
 
150
- test('browser paths come after desktop paths on macOS', () => {
150
+ it('browser paths come after desktop paths on macOS', () => {
151
151
  const darwinExtractor = new TeamsTokenExtractor('darwin')
152
152
  const paths = darwinExtractor.getTeamsCookiesPaths()
153
153
  const desktopPaths = darwinExtractor.getDesktopCookiesPaths()
@@ -157,7 +157,7 @@ describe('TeamsTokenExtractor', () => {
157
157
  expect(paths.slice(desktopPaths.length)).toEqual(browserPaths)
158
158
  })
159
159
 
160
- test('returns linux paths with desktop first then browser paths', () => {
160
+ it('returns linux paths with desktop first then browser paths', () => {
161
161
  const linuxExtractor = new TeamsTokenExtractor('linux')
162
162
  const paths = linuxExtractor.getTeamsCookiesPaths()
163
163
  const desktopPaths = linuxExtractor.getDesktopCookiesPaths()
@@ -171,7 +171,7 @@ describe('TeamsTokenExtractor', () => {
171
171
  expect(paths.length).toBeGreaterThan(desktopPaths.length)
172
172
  })
173
173
 
174
- test('returns win32 paths with desktop first then browser paths', () => {
174
+ it('returns win32 paths with desktop first then browser paths', () => {
175
175
  const winExtractor = new TeamsTokenExtractor('win32')
176
176
  const paths = winExtractor.getTeamsCookiesPaths()
177
177
  const desktopPaths = winExtractor.getDesktopCookiesPaths()
@@ -180,7 +180,7 @@ describe('TeamsTokenExtractor', () => {
180
180
  expect(paths.length).toBeGreaterThan(desktopPaths.length)
181
181
  })
182
182
 
183
- test('returns empty array for unsupported platform', () => {
183
+ it('returns empty array for unsupported platform', () => {
184
184
  const unsupportedExtractor = new TeamsTokenExtractor('freebsd' as NodeJS.Platform)
185
185
  const paths = unsupportedExtractor.getTeamsCookiesPaths()
186
186
 
@@ -189,21 +189,21 @@ describe('TeamsTokenExtractor', () => {
189
189
  })
190
190
 
191
191
  describe('getLocalStatePath', () => {
192
- test('returns darwin Local State path on macOS', () => {
192
+ it('returns darwin Local State path on macOS', () => {
193
193
  const darwinExtractor = new TeamsTokenExtractor('darwin')
194
194
  const path = darwinExtractor.getLocalStatePath()
195
195
 
196
196
  expect(path).toBe(join(homedir(), 'Library', 'Application Support', 'Microsoft', 'Teams', 'Local State'))
197
197
  })
198
198
 
199
- test('returns linux Local State path on Linux', () => {
199
+ it('returns linux Local State path on Linux', () => {
200
200
  const linuxExtractor = new TeamsTokenExtractor('linux')
201
201
  const path = linuxExtractor.getLocalStatePath()
202
202
 
203
203
  expect(path).toBe(join(homedir(), '.config', 'Microsoft', 'Microsoft Teams', 'Local State'))
204
204
  })
205
205
 
206
- test('returns win32 Local State path on Windows', () => {
206
+ it('returns win32 Local State path on Windows', () => {
207
207
  const winExtractor = new TeamsTokenExtractor('win32')
208
208
  const path = winExtractor.getLocalStatePath()
209
209
 
@@ -213,7 +213,7 @@ describe('TeamsTokenExtractor', () => {
213
213
  })
214
214
 
215
215
  describe('getKeychainVariants', () => {
216
- test('includes Teams-specific keychain entries', () => {
216
+ it('includes Teams-specific keychain entries', () => {
217
217
  const macExtractor = new TeamsTokenExtractor('darwin')
218
218
  const variants = macExtractor.getKeychainVariants()
219
219
 
@@ -226,7 +226,7 @@ describe('TeamsTokenExtractor', () => {
226
226
  expect(variants).toContainEqual({ service: 'Teams Safe Storage', account: 'Teams' })
227
227
  })
228
228
 
229
- test('includes browser keychain entries appended after Teams entries', () => {
229
+ it('includes browser keychain entries appended after Teams entries', () => {
230
230
  const macExtractor = new TeamsTokenExtractor('darwin')
231
231
  const variants = macExtractor.getKeychainVariants()
232
232
 
@@ -238,7 +238,7 @@ describe('TeamsTokenExtractor', () => {
238
238
  expect(variants).toContainEqual({ service: 'Chromium Safe Storage', account: 'Chromium' })
239
239
  })
240
240
 
241
- test('Teams entries come before browser entries', () => {
241
+ it('Teams entries come before browser entries', () => {
242
242
  const macExtractor = new TeamsTokenExtractor('darwin')
243
243
  const variants = macExtractor.getKeychainVariants()
244
244
 
@@ -249,59 +249,81 @@ describe('TeamsTokenExtractor', () => {
249
249
  })
250
250
 
251
251
  describe('isValidSkypeToken', () => {
252
- test('validates JWT-like skype token format', () => {
252
+ it('validates JWT-like skype token format', () => {
253
253
  const validToken = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature'
254
254
  expect(extractor.isValidSkypeToken(validToken)).toBe(true)
255
255
  })
256
256
 
257
- test('validates long base64 token format', () => {
257
+ it('validates long base64 token format', () => {
258
258
  const validToken = 'a'.repeat(100)
259
259
  expect(extractor.isValidSkypeToken(validToken)).toBe(true)
260
260
  })
261
261
 
262
- test('rejects empty tokens', () => {
262
+ it('rejects empty tokens', () => {
263
263
  expect(extractor.isValidSkypeToken('')).toBe(false)
264
264
  })
265
265
 
266
- test('rejects short tokens', () => {
266
+ it('rejects short tokens', () => {
267
267
  expect(extractor.isValidSkypeToken('short')).toBe(false)
268
268
  })
269
269
 
270
- test('rejects null/undefined', () => {
270
+ it('rejects null/undefined', () => {
271
271
  expect(extractor.isValidSkypeToken(null as unknown as string)).toBe(false)
272
272
  expect(extractor.isValidSkypeToken(undefined as unknown as string)).toBe(false)
273
273
  })
274
+
275
+ // Regression for #156: PowerShell CLIXML leaks into DPAPI output on Windows.
276
+ it('rejects CLIXML progress-stream contamination', () => {
277
+ // given: the exact shape of the leak reported in #156
278
+ const clixml =
279
+ '#< CLIXML\r\n<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">' +
280
+ '<Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T>' +
281
+ '<T>System.Object</T></TN><MS><I64 N="SourceId">1</I64></MS></Obj></Objs>'
282
+
283
+ // then
284
+ expect(extractor.isValidSkypeToken(clixml)).toBe(false)
285
+ })
286
+
287
+ it('rejects anything containing angle brackets or whitespace', () => {
288
+ expect(extractor.isValidSkypeToken('a'.repeat(60) + '<div>')).toBe(false)
289
+ expect(extractor.isValidSkypeToken('a'.repeat(40) + ' ' + 'b'.repeat(40))).toBe(false)
290
+ expect(extractor.isValidSkypeToken('a'.repeat(40) + '\n' + 'b'.repeat(40))).toBe(false)
291
+ })
292
+
293
+ it('rejects a bare 36-char UUID', () => {
294
+ expect(extractor.isValidSkypeToken('12345678-1234-1234-1234-123456789012')).toBe(false)
295
+ })
274
296
  })
275
297
 
276
298
  describe('isEncryptedValue', () => {
277
- test('detects v10 encrypted values', () => {
299
+ it('detects v10 encrypted values', () => {
278
300
  const encrypted = Buffer.from('v10encrypted_data')
279
301
  expect(extractor.isEncryptedValue(encrypted)).toBe(true)
280
302
  })
281
303
 
282
- test('detects v11 encrypted values', () => {
304
+ it('detects v11 encrypted values', () => {
283
305
  const encrypted = Buffer.from('v11encrypted_data')
284
306
  expect(extractor.isEncryptedValue(encrypted)).toBe(true)
285
307
  })
286
308
 
287
- test('rejects non-encrypted values', () => {
309
+ it('rejects non-encrypted values', () => {
288
310
  const plain = Buffer.from('plain_text')
289
311
  expect(extractor.isEncryptedValue(plain)).toBe(false)
290
312
  })
291
313
 
292
- test('rejects empty buffers', () => {
314
+ it('rejects empty buffers', () => {
293
315
  const empty = Buffer.alloc(0)
294
316
  expect(extractor.isEncryptedValue(empty)).toBe(false)
295
317
  })
296
318
 
297
- test('rejects short buffers', () => {
319
+ it('rejects short buffers', () => {
298
320
  const short = Buffer.from('v1')
299
321
  expect(extractor.isEncryptedValue(short)).toBe(false)
300
322
  })
301
323
  })
302
324
 
303
325
  describe('extract', () => {
304
- test('returns null when cookies path does not exist', async () => {
326
+ it('returns null when cookies path does not exist', async () => {
305
327
  const linuxExtractor = new TeamsTokenExtractor('linux')
306
328
  const extractFromCookiesDBSpy = spyOn(linuxExtractor as any, 'extractFromCookiesDB').mockResolvedValue([])
307
329
 
@@ -311,7 +333,7 @@ describe('TeamsTokenExtractor', () => {
311
333
  extractFromCookiesDBSpy.mockRestore()
312
334
  })
313
335
 
314
- test('extracts token from cookies database when available', async () => {
336
+ it('extracts token from cookies database when available', async () => {
315
337
  const mockToken = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature_here'
316
338
 
317
339
  const linuxExtractor = new TeamsTokenExtractor('linux')
@@ -327,7 +349,7 @@ describe('TeamsTokenExtractor', () => {
327
349
  extractFromCookiesDBSpy.mockRestore()
328
350
  })
329
351
 
330
- test('returns null when extraction fails', async () => {
352
+ it('returns null when extraction fails', async () => {
331
353
  const darwinExtractor = new TeamsTokenExtractor('darwin')
332
354
  const extractFromCookiesDBSpy = spyOn(darwinExtractor as any, 'extractFromCookiesDB').mockResolvedValue([])
333
355
 
@@ -349,7 +371,7 @@ describe('TeamsTokenExtractor', () => {
349
371
  const cleanup = () => rmSync(workDir, { recursive: true, force: true })
350
372
 
351
373
  // Regression for #156: if only Network/Cookies exists, missing sibling must not poison accountType.
352
- test('falls through to Network/Cookies when Cookies is missing', async () => {
374
+ it('falls through to Network/Cookies when Cookies is missing', async () => {
353
375
  // given: only Network/Cookies exists on disk for WV2Profile_tfl
354
376
  const profileDir = join(workDir, 'WV2Profile_tfl')
355
377
  const networkDir = join(profileDir, 'Network')
@@ -383,7 +405,45 @@ describe('TeamsTokenExtractor', () => {
383
405
  cleanup()
384
406
  })
385
407
 
386
- test('a missing path does not mark the account type as seen', async () => {
408
+ // Regression for #156: CLIXML-contaminated decrypt output must not short-circuit
409
+ // the work account, leaving other valid paths unvisited.
410
+ it('does not mark accountType seen when the first path yields CLIXML garbage', async () => {
411
+ // given: first work path returns CLIXML garbage, second work path returns a real token
412
+ const clixmlGarbage =
413
+ '#< CLIXML\r\n<Objs xmlns="http://schemas.microsoft.com/powershell/2004/04">' +
414
+ '<Obj S="progress"><TN><T>Progress</T></TN></Obj></Objs>\r\n' +
415
+ 'a'.repeat(80)
416
+ const realToken = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature_here'
417
+
418
+ const winExtractor = new TeamsTokenExtractor('win32')
419
+ const firstPath = join(workDir, 'WV2Profile_tfw', 'Cookies')
420
+ const secondPath = join(workDir, 'Default', 'Network', 'Cookies')
421
+ const getPathsSpy = spyOn(winExtractor, 'getTeamsCookiesPaths').mockReturnValue([
422
+ { path: firstPath, accountType: 'work' },
423
+ { path: secondPath, accountType: 'work' },
424
+ ])
425
+ mkdirSync(join(workDir, 'WV2Profile_tfw'), { recursive: true })
426
+ mkdirSync(join(workDir, 'Default', 'Network'), { recursive: true })
427
+ writeFileSync(firstPath, '')
428
+ writeFileSync(secondPath, '')
429
+
430
+ const copyAndExtractSpy = spyOn(winExtractor as any, 'copyAndExtract')
431
+ .mockResolvedValueOnce(clixmlGarbage)
432
+ .mockResolvedValueOnce(realToken)
433
+
434
+ // when
435
+ const results = await (winExtractor as any).extractFromCookiesDB()
436
+
437
+ // then: garbage was rejected, loop continued to the real token
438
+ expect(copyAndExtractSpy).toHaveBeenCalledTimes(2)
439
+ expect(results).toEqual([{ token: realToken, accountType: 'work' }])
440
+
441
+ getPathsSpy.mockRestore()
442
+ copyAndExtractSpy.mockRestore()
443
+ cleanup()
444
+ })
445
+
446
+ it('a missing path does not mark the account type as seen', async () => {
387
447
  // given: work account has Cookies missing but Network/Cookies present
388
448
  const workProfile = join(workDir, 'WV2Profile_tfw')
389
449
  const workNetworkDir = join(workProfile, 'Network')
@@ -415,7 +475,7 @@ describe('TeamsTokenExtractor', () => {
415
475
  })
416
476
 
417
477
  describe('copyAndExtract', () => {
418
- test('attempts to copy database to temp location', async () => {
478
+ it('attempts to copy database to temp location', async () => {
419
479
  const darwinExtractor = new TeamsTokenExtractor('darwin')
420
480
 
421
481
  const copyFileSpy = spyOn(darwinExtractor as any, 'copyDatabaseToTemp').mockReturnValue('/tmp/test-cookies')
@@ -434,7 +494,7 @@ describe('TeamsTokenExtractor', () => {
434
494
  cleanupSpy.mockRestore()
435
495
  })
436
496
 
437
- test('returns null when copy fails (file locked)', async () => {
497
+ it('returns null when copy fails (file locked)', async () => {
438
498
  const darwinExtractor = new TeamsTokenExtractor('darwin')
439
499
 
440
500
  const copyFileSpy = spyOn(darwinExtractor as any, 'copyDatabaseToTemp').mockImplementation(() => {
@@ -451,7 +511,7 @@ describe('TeamsTokenExtractor', () => {
451
511
 
452
512
  describe('decryption', () => {
453
513
  describe('decryptAESGCM', () => {
454
- test('returns null for invalid encrypted data', () => {
514
+ it('returns null for invalid encrypted data', () => {
455
515
  const darwinExtractor = new TeamsTokenExtractor('darwin')
456
516
  const invalidData = Buffer.from('too_short')
457
517
  const key = Buffer.alloc(32, 0)
@@ -460,7 +520,7 @@ describe('TeamsTokenExtractor', () => {
460
520
  expect(result).toBeNull()
461
521
  })
462
522
 
463
- test('returns null when decryption fails', () => {
523
+ it('returns null when decryption fails', () => {
464
524
  const darwinExtractor = new TeamsTokenExtractor('darwin')
465
525
  const fakeEncrypted = Buffer.concat([
466
526
  Buffer.from('v10'),
@@ -476,7 +536,7 @@ describe('TeamsTokenExtractor', () => {
476
536
  })
477
537
 
478
538
  describe('getKeychainPassword (macOS)', () => {
479
- test('tries multiple keychain variants', async () => {
539
+ it('tries multiple keychain variants', async () => {
480
540
  const darwinExtractor = new TeamsTokenExtractor('darwin')
481
541
  const execSyncSpy = spyOn(darwinExtractor as any, 'execSecurityCommand')
482
542
  .mockReturnValueOnce(null)
@@ -490,7 +550,7 @@ describe('TeamsTokenExtractor', () => {
490
550
  execSyncSpy.mockRestore()
491
551
  })
492
552
 
493
- test('returns null when all keychain variants fail', async () => {
553
+ it('returns null when all keychain variants fail', async () => {
494
554
  const darwinExtractor = new TeamsTokenExtractor('darwin')
495
555
  const execSyncSpy = spyOn(darwinExtractor as any, 'execSecurityCommand').mockReturnValue(null)
496
556
 
@@ -505,7 +565,7 @@ describe('TeamsTokenExtractor', () => {
505
565
 
506
566
  describe('process management', () => {
507
567
  describe('isTeamsRunning', () => {
508
- test('returns true when Teams process is found', async () => {
568
+ it('returns true when Teams process is found', async () => {
509
569
  const darwinExtractor = new TeamsTokenExtractor('darwin')
510
570
  const checkProcessRunningSpy = spyOn(darwinExtractor as any, 'checkProcessRunning').mockReturnValue(true)
511
571
 
@@ -515,7 +575,7 @@ describe('TeamsTokenExtractor', () => {
515
575
  checkProcessRunningSpy.mockRestore()
516
576
  })
517
577
 
518
- test('returns false when no Teams process is found', async () => {
578
+ it('returns false when no Teams process is found', async () => {
519
579
  const darwinExtractor = new TeamsTokenExtractor('darwin')
520
580
  const checkProcessRunningSpy = spyOn(darwinExtractor as any, 'checkProcessRunning').mockReturnValue(false)
521
581
 
@@ -527,17 +587,17 @@ describe('TeamsTokenExtractor', () => {
527
587
  })
528
588
 
529
589
  describe('getProcessName', () => {
530
- test('returns correct process name for macOS', () => {
590
+ it('returns correct process name for macOS', () => {
531
591
  const darwinExtractor = new TeamsTokenExtractor('darwin')
532
592
  expect((darwinExtractor as any).getProcessName()).toBe('Microsoft Teams')
533
593
  })
534
594
 
535
- test('returns correct process name for Windows', () => {
595
+ it('returns correct process name for Windows', () => {
536
596
  const winExtractor = new TeamsTokenExtractor('win32')
537
597
  expect((winExtractor as any).getProcessName()).toBe('Teams.exe')
538
598
  })
539
599
 
540
- test('returns correct process name for Linux', () => {
600
+ it('returns correct process name for Linux', () => {
541
601
  const linuxExtractor = new TeamsTokenExtractor('linux')
542
602
  expect((linuxExtractor as any).getProcessName()).toBe('teams')
543
603
  })
@@ -545,7 +605,7 @@ describe('TeamsTokenExtractor', () => {
545
605
  })
546
606
 
547
607
  describe('SQLite extraction', () => {
548
- test('returns null when database path does not exist', async () => {
608
+ it('returns null when database path does not exist', async () => {
549
609
  const darwinExtractor = new TeamsTokenExtractor('darwin')
550
610
 
551
611
  const result = await (darwinExtractor as any).extractFromSQLite('/nonexistent/path')
@@ -553,7 +613,7 @@ describe('TeamsTokenExtractor', () => {
553
613
  expect(result).toBeNull()
554
614
  })
555
615
 
556
- test('returns null when extraction throws', async () => {
616
+ it('returns null when extraction throws', async () => {
557
617
  const darwinExtractor = new TeamsTokenExtractor('darwin')
558
618
 
559
619
  const result = await (darwinExtractor as any).extractFromSQLite('/dev/null')
@@ -189,8 +189,13 @@ export class TeamsTokenExtractor {
189
189
  }
190
190
 
191
191
  isValidSkypeToken(token: string): boolean {
192
- if (!token || token.length === 0) return false
193
- return token.length >= 50
192
+ if (!token || token.length < 50) return false
193
+ // Real skype tokens are JWT-shaped or long base64url-ish strings. Reject anything
194
+ // containing XML/CLIXML artifacts (e.g. leaked PowerShell progress stream) or
195
+ // other non-token characters up front to stop garbage from being reported as valid.
196
+ if (/[<>{}\s"'`]/.test(token)) return false
197
+ if (token.startsWith('eyJ')) return /^[A-Za-z0-9._-]+$/.test(token)
198
+ return /^[A-Za-z0-9._~+/=-]+$/.test(token)
194
199
  }
195
200
 
196
201
  isEncryptedValue(value: Buffer): boolean {