agent-messenger 2.10.0 → 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 +15 -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 +219 -145
  180. package/src/platforms/teams/token-extractor.ts +13 -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,5 +1,6 @@
1
- import { beforeEach, describe, expect, spyOn, test } from 'bun:test'
2
- import { homedir } from 'node:os'
1
+ import { beforeEach, describe, expect, spyOn, it } from 'bun:test'
2
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
3
+ import { homedir, tmpdir } from 'node:os'
3
4
  import { join } from 'node:path'
4
5
 
5
6
  import { TeamsTokenExtractor } from './token-extractor'
@@ -12,62 +13,29 @@ describe('TeamsTokenExtractor', () => {
12
13
  })
13
14
 
14
15
  describe('getDesktopCookiesPaths', () => {
15
- test('returns darwin desktop paths on macOS', () => {
16
+ it('returns darwin desktop paths on macOS', () => {
16
17
  const darwinExtractor = new TeamsTokenExtractor('darwin')
17
18
  const paths = darwinExtractor.getDesktopCookiesPaths()
18
19
 
20
+ const darwinEbWebView = join(
21
+ homedir(),
22
+ 'Library',
23
+ 'Containers',
24
+ 'com.microsoft.teams2',
25
+ 'Data',
26
+ 'Library',
27
+ 'Application Support',
28
+ 'Microsoft',
29
+ 'MSTeams',
30
+ 'EBWebView',
31
+ )
19
32
  expect(paths).toEqual([
20
- {
21
- path: join(
22
- homedir(),
23
- 'Library',
24
- 'Containers',
25
- 'com.microsoft.teams2',
26
- 'Data',
27
- 'Library',
28
- 'Application Support',
29
- 'Microsoft',
30
- 'MSTeams',
31
- 'EBWebView',
32
- 'WV2Profile_tfw',
33
- 'Cookies',
34
- ),
35
- accountType: 'work',
36
- },
37
- {
38
- path: join(
39
- homedir(),
40
- 'Library',
41
- 'Containers',
42
- 'com.microsoft.teams2',
43
- 'Data',
44
- 'Library',
45
- 'Application Support',
46
- 'Microsoft',
47
- 'MSTeams',
48
- 'EBWebView',
49
- 'WV2Profile_tfl',
50
- 'Cookies',
51
- ),
52
- accountType: 'personal',
53
- },
54
- {
55
- path: join(
56
- homedir(),
57
- 'Library',
58
- 'Containers',
59
- 'com.microsoft.teams2',
60
- 'Data',
61
- 'Library',
62
- 'Application Support',
63
- 'Microsoft',
64
- 'MSTeams',
65
- 'EBWebView',
66
- 'Default',
67
- 'Cookies',
68
- ),
69
- accountType: 'work',
70
- },
33
+ { path: join(darwinEbWebView, 'WV2Profile_tfw', 'Cookies'), accountType: 'work' },
34
+ { path: join(darwinEbWebView, 'WV2Profile_tfw', 'Network', 'Cookies'), accountType: 'work' },
35
+ { path: join(darwinEbWebView, 'WV2Profile_tfl', 'Cookies'), accountType: 'personal' },
36
+ { path: join(darwinEbWebView, 'WV2Profile_tfl', 'Network', 'Cookies'), accountType: 'personal' },
37
+ { path: join(darwinEbWebView, 'Default', 'Cookies'), accountType: 'work' },
38
+ { path: join(darwinEbWebView, 'Default', 'Network', 'Cookies'), accountType: 'work' },
71
39
  {
72
40
  path: join(homedir(), 'Library', 'Application Support', 'Microsoft', 'Teams', 'Cookies'),
73
41
  accountType: 'work',
@@ -75,7 +43,7 @@ describe('TeamsTokenExtractor', () => {
75
43
  ])
76
44
  })
77
45
 
78
- test('returns linux desktop path on Linux', () => {
46
+ it('returns linux desktop path on Linux', () => {
79
47
  const linuxExtractor = new TeamsTokenExtractor('linux')
80
48
  const paths = linuxExtractor.getDesktopCookiesPaths()
81
49
 
@@ -87,70 +55,40 @@ describe('TeamsTokenExtractor', () => {
87
55
  ])
88
56
  })
89
57
 
90
- test('returns win32 desktop paths on Windows', () => {
58
+ it('returns win32 desktop paths on Windows', () => {
91
59
  const winExtractor = new TeamsTokenExtractor('win32')
92
60
  const paths = winExtractor.getDesktopCookiesPaths()
93
61
 
94
62
  const localAppData = process.env.LOCALAPPDATA || join(homedir(), 'AppData', 'Local')
95
63
  const appdata = process.env.APPDATA || join(homedir(), 'AppData', 'Roaming')
64
+ const winEbWebView = join(
65
+ localAppData,
66
+ 'Packages',
67
+ 'MSTeams_8wekyb3d8bbwe',
68
+ 'LocalCache',
69
+ 'Microsoft',
70
+ 'MSTeams',
71
+ 'EBWebView',
72
+ )
96
73
  expect(paths).toEqual([
97
- {
98
- path: join(
99
- localAppData,
100
- 'Packages',
101
- 'MSTeams_8wekyb3d8bbwe',
102
- 'LocalCache',
103
- 'Microsoft',
104
- 'MSTeams',
105
- 'EBWebView',
106
- 'WV2Profile_tfw',
107
- 'Cookies',
108
- ),
109
- accountType: 'work',
110
- },
111
- {
112
- path: join(
113
- localAppData,
114
- 'Packages',
115
- 'MSTeams_8wekyb3d8bbwe',
116
- 'LocalCache',
117
- 'Microsoft',
118
- 'MSTeams',
119
- 'EBWebView',
120
- 'WV2Profile_tfl',
121
- 'Cookies',
122
- ),
123
- accountType: 'personal',
124
- },
125
- {
126
- path: join(
127
- localAppData,
128
- 'Packages',
129
- 'MSTeams_8wekyb3d8bbwe',
130
- 'LocalCache',
131
- 'Microsoft',
132
- 'MSTeams',
133
- 'EBWebView',
134
- 'Default',
135
- 'Cookies',
136
- ),
137
- accountType: 'work',
138
- },
139
- {
140
- path: join(appdata, 'Microsoft', 'Teams', 'Cookies'),
141
- accountType: 'work',
142
- },
74
+ { path: join(winEbWebView, 'WV2Profile_tfw', 'Cookies'), accountType: 'work' },
75
+ { path: join(winEbWebView, 'WV2Profile_tfw', 'Network', 'Cookies'), accountType: 'work' },
76
+ { path: join(winEbWebView, 'WV2Profile_tfl', 'Cookies'), accountType: 'personal' },
77
+ { path: join(winEbWebView, 'WV2Profile_tfl', 'Network', 'Cookies'), accountType: 'personal' },
78
+ { path: join(winEbWebView, 'Default', 'Cookies'), accountType: 'work' },
79
+ { path: join(winEbWebView, 'Default', 'Network', 'Cookies'), accountType: 'work' },
80
+ { path: join(appdata, 'Microsoft', 'Teams', 'Cookies'), accountType: 'work' },
143
81
  ])
144
82
  })
145
83
 
146
- test('returns empty array for unsupported platform', () => {
84
+ it('returns empty array for unsupported platform', () => {
147
85
  const unsupportedExtractor = new TeamsTokenExtractor('freebsd' as NodeJS.Platform)
148
86
  expect(unsupportedExtractor.getDesktopCookiesPaths()).toEqual([])
149
87
  })
150
88
  })
151
89
 
152
90
  describe('getBrowserCookiesPaths', () => {
153
- 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)', () => {
154
92
  const darwinExtractor = new TeamsTokenExtractor('darwin')
155
93
  const paths = darwinExtractor.getBrowserCookiesPaths()
156
94
 
@@ -165,7 +103,7 @@ describe('TeamsTokenExtractor', () => {
165
103
  })
166
104
  })
167
105
 
168
- test('returns browser cookie paths on Linux', () => {
106
+ it('returns browser cookie paths on Linux', () => {
169
107
  const linuxExtractor = new TeamsTokenExtractor('linux')
170
108
  const paths = linuxExtractor.getBrowserCookiesPaths()
171
109
 
@@ -176,7 +114,7 @@ describe('TeamsTokenExtractor', () => {
176
114
  })
177
115
  })
178
116
 
179
- test('returns browser cookie paths on Windows', () => {
117
+ it('returns browser cookie paths on Windows', () => {
180
118
  const winExtractor = new TeamsTokenExtractor('win32')
181
119
  const paths = winExtractor.getBrowserCookiesPaths()
182
120
 
@@ -188,12 +126,12 @@ describe('TeamsTokenExtractor', () => {
188
126
  })
189
127
  })
190
128
 
191
- test('returns empty array for unsupported platform', () => {
129
+ it('returns empty array for unsupported platform', () => {
192
130
  const unsupportedExtractor = new TeamsTokenExtractor('freebsd' as NodeJS.Platform)
193
131
  expect(unsupportedExtractor.getBrowserCookiesPaths()).toEqual([])
194
132
  })
195
133
 
196
- test('all browser paths have accountType work', () => {
134
+ it('all browser paths have accountType work', () => {
197
135
  const darwinExtractor = new TeamsTokenExtractor('darwin')
198
136
  const paths = darwinExtractor.getBrowserCookiesPaths()
199
137
  expect(paths.every((p) => p.accountType === 'work')).toBe(true)
@@ -201,7 +139,7 @@ describe('TeamsTokenExtractor', () => {
201
139
  })
202
140
 
203
141
  describe('getTeamsCookiesPaths', () => {
204
- test('returns darwin paths on macOS with desktop paths first', () => {
142
+ it('returns darwin paths on macOS with desktop paths first', () => {
205
143
  const darwinExtractor = new TeamsTokenExtractor('darwin')
206
144
  const paths = darwinExtractor.getTeamsCookiesPaths()
207
145
  const desktopPaths = darwinExtractor.getDesktopCookiesPaths()
@@ -209,7 +147,7 @@ describe('TeamsTokenExtractor', () => {
209
147
  expect(paths.slice(0, desktopPaths.length)).toEqual(desktopPaths)
210
148
  })
211
149
 
212
- test('browser paths come after desktop paths on macOS', () => {
150
+ it('browser paths come after desktop paths on macOS', () => {
213
151
  const darwinExtractor = new TeamsTokenExtractor('darwin')
214
152
  const paths = darwinExtractor.getTeamsCookiesPaths()
215
153
  const desktopPaths = darwinExtractor.getDesktopCookiesPaths()
@@ -219,7 +157,7 @@ describe('TeamsTokenExtractor', () => {
219
157
  expect(paths.slice(desktopPaths.length)).toEqual(browserPaths)
220
158
  })
221
159
 
222
- test('returns linux paths with desktop first then browser paths', () => {
160
+ it('returns linux paths with desktop first then browser paths', () => {
223
161
  const linuxExtractor = new TeamsTokenExtractor('linux')
224
162
  const paths = linuxExtractor.getTeamsCookiesPaths()
225
163
  const desktopPaths = linuxExtractor.getDesktopCookiesPaths()
@@ -233,7 +171,7 @@ describe('TeamsTokenExtractor', () => {
233
171
  expect(paths.length).toBeGreaterThan(desktopPaths.length)
234
172
  })
235
173
 
236
- test('returns win32 paths with desktop first then browser paths', () => {
174
+ it('returns win32 paths with desktop first then browser paths', () => {
237
175
  const winExtractor = new TeamsTokenExtractor('win32')
238
176
  const paths = winExtractor.getTeamsCookiesPaths()
239
177
  const desktopPaths = winExtractor.getDesktopCookiesPaths()
@@ -242,7 +180,7 @@ describe('TeamsTokenExtractor', () => {
242
180
  expect(paths.length).toBeGreaterThan(desktopPaths.length)
243
181
  })
244
182
 
245
- test('returns empty array for unsupported platform', () => {
183
+ it('returns empty array for unsupported platform', () => {
246
184
  const unsupportedExtractor = new TeamsTokenExtractor('freebsd' as NodeJS.Platform)
247
185
  const paths = unsupportedExtractor.getTeamsCookiesPaths()
248
186
 
@@ -251,21 +189,21 @@ describe('TeamsTokenExtractor', () => {
251
189
  })
252
190
 
253
191
  describe('getLocalStatePath', () => {
254
- test('returns darwin Local State path on macOS', () => {
192
+ it('returns darwin Local State path on macOS', () => {
255
193
  const darwinExtractor = new TeamsTokenExtractor('darwin')
256
194
  const path = darwinExtractor.getLocalStatePath()
257
195
 
258
196
  expect(path).toBe(join(homedir(), 'Library', 'Application Support', 'Microsoft', 'Teams', 'Local State'))
259
197
  })
260
198
 
261
- test('returns linux Local State path on Linux', () => {
199
+ it('returns linux Local State path on Linux', () => {
262
200
  const linuxExtractor = new TeamsTokenExtractor('linux')
263
201
  const path = linuxExtractor.getLocalStatePath()
264
202
 
265
203
  expect(path).toBe(join(homedir(), '.config', 'Microsoft', 'Microsoft Teams', 'Local State'))
266
204
  })
267
205
 
268
- test('returns win32 Local State path on Windows', () => {
206
+ it('returns win32 Local State path on Windows', () => {
269
207
  const winExtractor = new TeamsTokenExtractor('win32')
270
208
  const path = winExtractor.getLocalStatePath()
271
209
 
@@ -275,7 +213,7 @@ describe('TeamsTokenExtractor', () => {
275
213
  })
276
214
 
277
215
  describe('getKeychainVariants', () => {
278
- test('includes Teams-specific keychain entries', () => {
216
+ it('includes Teams-specific keychain entries', () => {
279
217
  const macExtractor = new TeamsTokenExtractor('darwin')
280
218
  const variants = macExtractor.getKeychainVariants()
281
219
 
@@ -288,7 +226,7 @@ describe('TeamsTokenExtractor', () => {
288
226
  expect(variants).toContainEqual({ service: 'Teams Safe Storage', account: 'Teams' })
289
227
  })
290
228
 
291
- test('includes browser keychain entries appended after Teams entries', () => {
229
+ it('includes browser keychain entries appended after Teams entries', () => {
292
230
  const macExtractor = new TeamsTokenExtractor('darwin')
293
231
  const variants = macExtractor.getKeychainVariants()
294
232
 
@@ -300,7 +238,7 @@ describe('TeamsTokenExtractor', () => {
300
238
  expect(variants).toContainEqual({ service: 'Chromium Safe Storage', account: 'Chromium' })
301
239
  })
302
240
 
303
- test('Teams entries come before browser entries', () => {
241
+ it('Teams entries come before browser entries', () => {
304
242
  const macExtractor = new TeamsTokenExtractor('darwin')
305
243
  const variants = macExtractor.getKeychainVariants()
306
244
 
@@ -311,59 +249,81 @@ describe('TeamsTokenExtractor', () => {
311
249
  })
312
250
 
313
251
  describe('isValidSkypeToken', () => {
314
- test('validates JWT-like skype token format', () => {
252
+ it('validates JWT-like skype token format', () => {
315
253
  const validToken = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature'
316
254
  expect(extractor.isValidSkypeToken(validToken)).toBe(true)
317
255
  })
318
256
 
319
- test('validates long base64 token format', () => {
257
+ it('validates long base64 token format', () => {
320
258
  const validToken = 'a'.repeat(100)
321
259
  expect(extractor.isValidSkypeToken(validToken)).toBe(true)
322
260
  })
323
261
 
324
- test('rejects empty tokens', () => {
262
+ it('rejects empty tokens', () => {
325
263
  expect(extractor.isValidSkypeToken('')).toBe(false)
326
264
  })
327
265
 
328
- test('rejects short tokens', () => {
266
+ it('rejects short tokens', () => {
329
267
  expect(extractor.isValidSkypeToken('short')).toBe(false)
330
268
  })
331
269
 
332
- test('rejects null/undefined', () => {
270
+ it('rejects null/undefined', () => {
333
271
  expect(extractor.isValidSkypeToken(null as unknown as string)).toBe(false)
334
272
  expect(extractor.isValidSkypeToken(undefined as unknown as string)).toBe(false)
335
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
+ })
336
296
  })
337
297
 
338
298
  describe('isEncryptedValue', () => {
339
- test('detects v10 encrypted values', () => {
299
+ it('detects v10 encrypted values', () => {
340
300
  const encrypted = Buffer.from('v10encrypted_data')
341
301
  expect(extractor.isEncryptedValue(encrypted)).toBe(true)
342
302
  })
343
303
 
344
- test('detects v11 encrypted values', () => {
304
+ it('detects v11 encrypted values', () => {
345
305
  const encrypted = Buffer.from('v11encrypted_data')
346
306
  expect(extractor.isEncryptedValue(encrypted)).toBe(true)
347
307
  })
348
308
 
349
- test('rejects non-encrypted values', () => {
309
+ it('rejects non-encrypted values', () => {
350
310
  const plain = Buffer.from('plain_text')
351
311
  expect(extractor.isEncryptedValue(plain)).toBe(false)
352
312
  })
353
313
 
354
- test('rejects empty buffers', () => {
314
+ it('rejects empty buffers', () => {
355
315
  const empty = Buffer.alloc(0)
356
316
  expect(extractor.isEncryptedValue(empty)).toBe(false)
357
317
  })
358
318
 
359
- test('rejects short buffers', () => {
319
+ it('rejects short buffers', () => {
360
320
  const short = Buffer.from('v1')
361
321
  expect(extractor.isEncryptedValue(short)).toBe(false)
362
322
  })
363
323
  })
364
324
 
365
325
  describe('extract', () => {
366
- test('returns null when cookies path does not exist', async () => {
326
+ it('returns null when cookies path does not exist', async () => {
367
327
  const linuxExtractor = new TeamsTokenExtractor('linux')
368
328
  const extractFromCookiesDBSpy = spyOn(linuxExtractor as any, 'extractFromCookiesDB').mockResolvedValue([])
369
329
 
@@ -373,7 +333,7 @@ describe('TeamsTokenExtractor', () => {
373
333
  extractFromCookiesDBSpy.mockRestore()
374
334
  })
375
335
 
376
- test('extracts token from cookies database when available', async () => {
336
+ it('extracts token from cookies database when available', async () => {
377
337
  const mockToken = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature_here'
378
338
 
379
339
  const linuxExtractor = new TeamsTokenExtractor('linux')
@@ -389,7 +349,7 @@ describe('TeamsTokenExtractor', () => {
389
349
  extractFromCookiesDBSpy.mockRestore()
390
350
  })
391
351
 
392
- test('returns null when extraction fails', async () => {
352
+ it('returns null when extraction fails', async () => {
393
353
  const darwinExtractor = new TeamsTokenExtractor('darwin')
394
354
  const extractFromCookiesDBSpy = spyOn(darwinExtractor as any, 'extractFromCookiesDB').mockResolvedValue([])
395
355
 
@@ -400,8 +360,122 @@ describe('TeamsTokenExtractor', () => {
400
360
  })
401
361
  })
402
362
 
363
+ describe('extractFromCookiesDB (Network/Cookies fallback)', () => {
364
+ const mockToken = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature_here'
365
+ let workDir: string
366
+
367
+ beforeEach(() => {
368
+ workDir = mkdtempSync(join(tmpdir(), 'teams-extractor-test-'))
369
+ })
370
+
371
+ const cleanup = () => rmSync(workDir, { recursive: true, force: true })
372
+
373
+ // Regression for #156: if only Network/Cookies exists, missing sibling must not poison accountType.
374
+ it('falls through to Network/Cookies when Cookies is missing', async () => {
375
+ // given: only Network/Cookies exists on disk for WV2Profile_tfl
376
+ const profileDir = join(workDir, 'WV2Profile_tfl')
377
+ const networkDir = join(profileDir, 'Network')
378
+ mkdirSync(networkDir, { recursive: true })
379
+ const cookiesPath = join(profileDir, 'Cookies')
380
+ const networkCookiesPath = join(networkDir, 'Cookies')
381
+ writeFileSync(networkCookiesPath, '')
382
+
383
+ const winExtractor = new TeamsTokenExtractor('win32')
384
+ const getPathsSpy = spyOn(winExtractor, 'getTeamsCookiesPaths').mockReturnValue([
385
+ { path: cookiesPath, accountType: 'personal' },
386
+ { path: networkCookiesPath, accountType: 'personal' },
387
+ ])
388
+ const tried: string[] = []
389
+ const copyAndExtractSpy = spyOn(winExtractor as any, 'copyAndExtract').mockImplementation(async (...args) => {
390
+ const path = args[0] as string
391
+ tried.push(path)
392
+ return mockToken
393
+ })
394
+
395
+ // when
396
+ const results = await (winExtractor as any).extractFromCookiesDB()
397
+
398
+ // then: the Cookies path was skipped (never passed to copyAndExtract),
399
+ // the Network/Cookies sibling was tried, and the token was returned.
400
+ expect(tried).toEqual([networkCookiesPath])
401
+ expect(results).toEqual([{ token: mockToken, accountType: 'personal' }])
402
+
403
+ getPathsSpy.mockRestore()
404
+ copyAndExtractSpy.mockRestore()
405
+ cleanup()
406
+ })
407
+
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 () => {
447
+ // given: work account has Cookies missing but Network/Cookies present
448
+ const workProfile = join(workDir, 'WV2Profile_tfw')
449
+ const workNetworkDir = join(workProfile, 'Network')
450
+ mkdirSync(workNetworkDir, { recursive: true })
451
+ const workCookies = join(workProfile, 'Cookies')
452
+ const workNetworkCookies = join(workNetworkDir, 'Cookies')
453
+ writeFileSync(workNetworkCookies, '')
454
+
455
+ const winExtractor = new TeamsTokenExtractor('win32')
456
+ const getPathsSpy = spyOn(winExtractor, 'getTeamsCookiesPaths').mockReturnValue([
457
+ { path: workCookies, accountType: 'work' },
458
+ { path: workNetworkCookies, accountType: 'work' },
459
+ ])
460
+ const copyAndExtractSpy = spyOn(winExtractor as any, 'copyAndExtract').mockResolvedValue(mockToken)
461
+
462
+ // when
463
+ const results = await (winExtractor as any).extractFromCookiesDB()
464
+
465
+ // then: missing first path did not block the sibling; work token extracted
466
+ expect(results).toHaveLength(1)
467
+ expect(results[0].accountType).toBe('work')
468
+ expect(copyAndExtractSpy).toHaveBeenCalledTimes(1)
469
+ expect(copyAndExtractSpy).toHaveBeenCalledWith(workNetworkCookies)
470
+
471
+ getPathsSpy.mockRestore()
472
+ copyAndExtractSpy.mockRestore()
473
+ cleanup()
474
+ })
475
+ })
476
+
403
477
  describe('copyAndExtract', () => {
404
- test('attempts to copy database to temp location', async () => {
478
+ it('attempts to copy database to temp location', async () => {
405
479
  const darwinExtractor = new TeamsTokenExtractor('darwin')
406
480
 
407
481
  const copyFileSpy = spyOn(darwinExtractor as any, 'copyDatabaseToTemp').mockReturnValue('/tmp/test-cookies')
@@ -420,7 +494,7 @@ describe('TeamsTokenExtractor', () => {
420
494
  cleanupSpy.mockRestore()
421
495
  })
422
496
 
423
- test('returns null when copy fails (file locked)', async () => {
497
+ it('returns null when copy fails (file locked)', async () => {
424
498
  const darwinExtractor = new TeamsTokenExtractor('darwin')
425
499
 
426
500
  const copyFileSpy = spyOn(darwinExtractor as any, 'copyDatabaseToTemp').mockImplementation(() => {
@@ -437,7 +511,7 @@ describe('TeamsTokenExtractor', () => {
437
511
 
438
512
  describe('decryption', () => {
439
513
  describe('decryptAESGCM', () => {
440
- test('returns null for invalid encrypted data', () => {
514
+ it('returns null for invalid encrypted data', () => {
441
515
  const darwinExtractor = new TeamsTokenExtractor('darwin')
442
516
  const invalidData = Buffer.from('too_short')
443
517
  const key = Buffer.alloc(32, 0)
@@ -446,7 +520,7 @@ describe('TeamsTokenExtractor', () => {
446
520
  expect(result).toBeNull()
447
521
  })
448
522
 
449
- test('returns null when decryption fails', () => {
523
+ it('returns null when decryption fails', () => {
450
524
  const darwinExtractor = new TeamsTokenExtractor('darwin')
451
525
  const fakeEncrypted = Buffer.concat([
452
526
  Buffer.from('v10'),
@@ -462,7 +536,7 @@ describe('TeamsTokenExtractor', () => {
462
536
  })
463
537
 
464
538
  describe('getKeychainPassword (macOS)', () => {
465
- test('tries multiple keychain variants', async () => {
539
+ it('tries multiple keychain variants', async () => {
466
540
  const darwinExtractor = new TeamsTokenExtractor('darwin')
467
541
  const execSyncSpy = spyOn(darwinExtractor as any, 'execSecurityCommand')
468
542
  .mockReturnValueOnce(null)
@@ -476,7 +550,7 @@ describe('TeamsTokenExtractor', () => {
476
550
  execSyncSpy.mockRestore()
477
551
  })
478
552
 
479
- test('returns null when all keychain variants fail', async () => {
553
+ it('returns null when all keychain variants fail', async () => {
480
554
  const darwinExtractor = new TeamsTokenExtractor('darwin')
481
555
  const execSyncSpy = spyOn(darwinExtractor as any, 'execSecurityCommand').mockReturnValue(null)
482
556
 
@@ -491,7 +565,7 @@ describe('TeamsTokenExtractor', () => {
491
565
 
492
566
  describe('process management', () => {
493
567
  describe('isTeamsRunning', () => {
494
- test('returns true when Teams process is found', async () => {
568
+ it('returns true when Teams process is found', async () => {
495
569
  const darwinExtractor = new TeamsTokenExtractor('darwin')
496
570
  const checkProcessRunningSpy = spyOn(darwinExtractor as any, 'checkProcessRunning').mockReturnValue(true)
497
571
 
@@ -501,7 +575,7 @@ describe('TeamsTokenExtractor', () => {
501
575
  checkProcessRunningSpy.mockRestore()
502
576
  })
503
577
 
504
- test('returns false when no Teams process is found', async () => {
578
+ it('returns false when no Teams process is found', async () => {
505
579
  const darwinExtractor = new TeamsTokenExtractor('darwin')
506
580
  const checkProcessRunningSpy = spyOn(darwinExtractor as any, 'checkProcessRunning').mockReturnValue(false)
507
581
 
@@ -513,17 +587,17 @@ describe('TeamsTokenExtractor', () => {
513
587
  })
514
588
 
515
589
  describe('getProcessName', () => {
516
- test('returns correct process name for macOS', () => {
590
+ it('returns correct process name for macOS', () => {
517
591
  const darwinExtractor = new TeamsTokenExtractor('darwin')
518
592
  expect((darwinExtractor as any).getProcessName()).toBe('Microsoft Teams')
519
593
  })
520
594
 
521
- test('returns correct process name for Windows', () => {
595
+ it('returns correct process name for Windows', () => {
522
596
  const winExtractor = new TeamsTokenExtractor('win32')
523
597
  expect((winExtractor as any).getProcessName()).toBe('Teams.exe')
524
598
  })
525
599
 
526
- test('returns correct process name for Linux', () => {
600
+ it('returns correct process name for Linux', () => {
527
601
  const linuxExtractor = new TeamsTokenExtractor('linux')
528
602
  expect((linuxExtractor as any).getProcessName()).toBe('teams')
529
603
  })
@@ -531,7 +605,7 @@ describe('TeamsTokenExtractor', () => {
531
605
  })
532
606
 
533
607
  describe('SQLite extraction', () => {
534
- test('returns null when database path does not exist', async () => {
608
+ it('returns null when database path does not exist', async () => {
535
609
  const darwinExtractor = new TeamsTokenExtractor('darwin')
536
610
 
537
611
  const result = await (darwinExtractor as any).extractFromSQLite('/nonexistent/path')
@@ -539,7 +613,7 @@ describe('TeamsTokenExtractor', () => {
539
613
  expect(result).toBeNull()
540
614
  })
541
615
 
542
- test('returns null when extraction throws', async () => {
616
+ it('returns null when extraction throws', async () => {
543
617
  const darwinExtractor = new TeamsTokenExtractor('darwin')
544
618
 
545
619
  const result = await (darwinExtractor as any).extractFromSQLite('/dev/null')