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.
- package/.claude-plugin/plugin.json +1 -1
- package/dist/package.json +1 -1
- package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/teams/token-extractor.js +9 -2
- package/dist/src/platforms/teams/token-extractor.js.map +1 -1
- package/dist/src/shared/chromium/decryptor.d.ts +6 -0
- package/dist/src/shared/chromium/decryptor.d.ts.map +1 -1
- package/dist/src/shared/chromium/decryptor.js +26 -6
- package/dist/src/shared/chromium/decryptor.js.map +1 -1
- package/e2e/channeltalk.e2e.test.ts +13 -13
- package/e2e/channeltalkbot.e2e.test.ts +13 -13
- package/e2e/discord.e2e.test.ts +24 -24
- package/e2e/discordbot.e2e.test.ts +16 -16
- package/e2e/instagram.e2e.test.ts +10 -10
- package/e2e/kakaotalk.e2e.test.ts +7 -7
- package/e2e/line.e2e.test.ts +8 -8
- package/e2e/slack.e2e.test.ts +34 -34
- package/e2e/slackbot.e2e.test.ts +14 -14
- package/e2e/teams.e2e.test.ts +23 -23
- package/e2e/telegram.e2e.test.ts +8 -8
- package/e2e/webex.e2e.test.ts +14 -14
- package/e2e/whatsapp.e2e.test.ts +8 -8
- package/e2e/whatsappbot.e2e.test.ts +6 -6
- package/package.json +1 -1
- package/skills/agent-channeltalk/SKILL.md +1 -1
- package/skills/agent-channeltalkbot/SKILL.md +1 -1
- package/skills/agent-discord/SKILL.md +1 -1
- package/skills/agent-discordbot/SKILL.md +1 -1
- package/skills/agent-instagram/SKILL.md +1 -1
- package/skills/agent-kakaotalk/SKILL.md +1 -1
- package/skills/agent-line/SKILL.md +1 -1
- package/skills/agent-slack/SKILL.md +1 -1
- package/skills/agent-slackbot/SKILL.md +1 -1
- package/skills/agent-teams/SKILL.md +1 -1
- package/skills/agent-telegram/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +1 -1
- package/skills/agent-wechatbot/SKILL.md +1 -1
- package/skills/agent-whatsapp/SKILL.md +1 -1
- package/skills/agent-whatsappbot/SKILL.md +1 -1
- package/src/platforms/channeltalk/client.test.ts +26 -26
- package/src/platforms/channeltalk/commands/auth.test.ts +16 -16
- package/src/platforms/channeltalk/commands/bot.test.ts +2 -2
- package/src/platforms/channeltalk/commands/chat.test.ts +3 -3
- package/src/platforms/channeltalk/commands/group.test.ts +4 -4
- package/src/platforms/channeltalk/commands/manager.test.ts +2 -2
- package/src/platforms/channeltalk/commands/message.test.ts +17 -17
- package/src/platforms/channeltalk/commands/snapshot.test.ts +7 -7
- package/src/platforms/channeltalk/commands/whoami.test.ts +3 -3
- package/src/platforms/channeltalk/credential-manager.test.ts +18 -18
- package/src/platforms/channeltalk/ensure-auth.test.ts +5 -5
- package/src/platforms/channeltalk/index.test.ts +23 -23
- package/src/platforms/channeltalk/token-extractor.test.ts +21 -21
- package/src/platforms/channeltalk/types.test.ts +12 -12
- package/src/platforms/channeltalkbot/client.test.ts +14 -14
- package/src/platforms/channeltalkbot/commands/auth.test.ts +16 -16
- package/src/platforms/channeltalkbot/commands/bot.test.ts +6 -6
- package/src/platforms/channeltalkbot/commands/chat.test.ts +9 -9
- package/src/platforms/channeltalkbot/commands/group.test.ts +6 -6
- package/src/platforms/channeltalkbot/commands/manager.test.ts +3 -3
- package/src/platforms/channeltalkbot/commands/message.test.ts +10 -10
- package/src/platforms/channeltalkbot/commands/snapshot.test.ts +7 -7
- package/src/platforms/channeltalkbot/commands/whoami.test.ts +4 -4
- package/src/platforms/channeltalkbot/credential-manager.test.ts +27 -27
- package/src/platforms/channeltalkbot/index.test.ts +15 -15
- package/src/platforms/discord/client.test.ts +28 -28
- package/src/platforms/discord/commands/auth.test.ts +7 -7
- package/src/platforms/discord/commands/channel.test.ts +7 -7
- package/src/platforms/discord/commands/dm.test.ts +4 -4
- package/src/platforms/discord/commands/file.test.ts +4 -4
- package/src/platforms/discord/commands/friend.test.ts +6 -6
- package/src/platforms/discord/commands/member.test.ts +5 -5
- package/src/platforms/discord/commands/mention.test.ts +5 -5
- package/src/platforms/discord/commands/message.test.ts +9 -9
- package/src/platforms/discord/commands/note.test.ts +6 -6
- package/src/platforms/discord/commands/profile.test.ts +4 -4
- package/src/platforms/discord/commands/reaction.test.ts +5 -5
- package/src/platforms/discord/commands/server.test.ts +7 -7
- package/src/platforms/discord/commands/snapshot.test.ts +6 -6
- package/src/platforms/discord/commands/thread.test.ts +6 -6
- package/src/platforms/discord/commands/user.test.ts +5 -5
- package/src/platforms/discord/commands/whoami.test.ts +6 -6
- package/src/platforms/discord/credential-manager.test.ts +16 -16
- package/src/platforms/discord/ensure-auth.test.ts +8 -8
- package/src/platforms/discord/index.test.ts +17 -17
- package/src/platforms/discord/listener.test.ts +33 -33
- package/src/platforms/discord/token-extractor.test.ts +53 -53
- package/src/platforms/discord/types.test.ts +26 -26
- package/src/platforms/discordbot/client.test.ts +31 -31
- package/src/platforms/discordbot/commands/auth.test.ts +18 -18
- package/src/platforms/discordbot/commands/channel.test.ts +11 -11
- package/src/platforms/discordbot/commands/file.test.ts +7 -7
- package/src/platforms/discordbot/commands/message.test.ts +25 -25
- package/src/platforms/discordbot/commands/reaction.test.ts +6 -6
- package/src/platforms/discordbot/commands/server.test.ts +12 -12
- package/src/platforms/discordbot/commands/snapshot.test.ts +13 -13
- package/src/platforms/discordbot/commands/thread.test.ts +10 -10
- package/src/platforms/discordbot/commands/user.test.ts +9 -9
- package/src/platforms/discordbot/commands/whoami.test.ts +4 -4
- package/src/platforms/discordbot/credential-manager.test.ts +28 -28
- package/src/platforms/instagram/client.test.ts +18 -18
- package/src/platforms/instagram/commands/auth.test.ts +11 -11
- package/src/platforms/instagram/commands/chat.test.ts +6 -6
- package/src/platforms/instagram/commands/message.test.ts +11 -11
- package/src/platforms/instagram/commands/shared.test.ts +12 -12
- package/src/platforms/instagram/commands/whoami.test.ts +3 -3
- package/src/platforms/instagram/credential-manager.test.ts +21 -21
- package/src/platforms/instagram/ensure-auth.test.ts +4 -4
- package/src/platforms/instagram/index.test.ts +9 -9
- package/src/platforms/instagram/listener.test.ts +8 -8
- package/src/platforms/instagram/token-extractor.test.ts +35 -35
- package/src/platforms/kakaotalk/client.test.ts +33 -33
- package/src/platforms/kakaotalk/commands/auth.test.ts +11 -11
- package/src/platforms/kakaotalk/commands/chat.test.ts +6 -6
- package/src/platforms/kakaotalk/commands/message.test.ts +7 -7
- package/src/platforms/kakaotalk/commands/whoami.test.ts +5 -5
- package/src/platforms/kakaotalk/credential-manager.test.ts +15 -15
- package/src/platforms/kakaotalk/index.test.ts +15 -15
- package/src/platforms/kakaotalk/listener.test.ts +17 -17
- package/src/platforms/line/client.test.ts +17 -17
- package/src/platforms/line/commands/auth.test.ts +8 -8
- package/src/platforms/line/commands/chat.test.ts +7 -7
- package/src/platforms/line/commands/friend.test.ts +6 -6
- package/src/platforms/line/commands/message.test.ts +7 -7
- package/src/platforms/line/commands/whoami.test.ts +6 -6
- package/src/platforms/line/credential-manager.test.ts +17 -17
- package/src/platforms/line/index.test.ts +10 -10
- package/src/platforms/line/listener.test.ts +15 -15
- package/src/platforms/line/types.test.ts +14 -14
- package/src/platforms/slack/cli.test.ts +8 -8
- package/src/platforms/slack/client.test.ts +151 -151
- package/src/platforms/slack/commands/activity.test.ts +13 -13
- package/src/platforms/slack/commands/auth.test.ts +34 -34
- package/src/platforms/slack/commands/bookmark.test.ts +9 -9
- package/src/platforms/slack/commands/channel.test.ts +17 -17
- package/src/platforms/slack/commands/drafts.test.ts +7 -7
- package/src/platforms/slack/commands/emoji.test.ts +3 -3
- package/src/platforms/slack/commands/file.test.ts +12 -12
- package/src/platforms/slack/commands/message.test.ts +19 -19
- package/src/platforms/slack/commands/pin.test.ts +7 -7
- package/src/platforms/slack/commands/reaction.test.ts +10 -10
- package/src/platforms/slack/commands/reminder.test.ts +9 -9
- package/src/platforms/slack/commands/saved.test.ts +7 -7
- package/src/platforms/slack/commands/sections.test.ts +5 -5
- package/src/platforms/slack/commands/snapshot.test.ts +13 -13
- package/src/platforms/slack/commands/unread.test.ts +6 -6
- package/src/platforms/slack/commands/user.test.ts +10 -10
- package/src/platforms/slack/commands/usergroup.test.ts +15 -15
- package/src/platforms/slack/commands/whoami.test.ts +6 -6
- package/src/platforms/slack/commands/workspace.test.ts +26 -26
- package/src/platforms/slack/credential-manager.test.ts +14 -14
- package/src/platforms/slack/ensure-auth.test.ts +21 -21
- package/src/platforms/slack/index.test.ts +12 -12
- package/src/platforms/slack/listener.test.ts +17 -17
- package/src/platforms/slack/token-extractor-node.test.ts +2 -2
- package/src/platforms/slack/token-extractor.test.ts +37 -37
- package/src/platforms/slack/types.test.ts +21 -21
- package/src/platforms/slackbot/client.test.ts +22 -22
- package/src/platforms/slackbot/commands/auth.test.ts +14 -14
- package/src/platforms/slackbot/commands/channel.test.ts +7 -7
- package/src/platforms/slackbot/commands/message.test.ts +13 -13
- package/src/platforms/slackbot/commands/reaction.test.ts +6 -6
- package/src/platforms/slackbot/commands/user.test.ts +7 -7
- package/src/platforms/slackbot/commands/whoami.test.ts +4 -4
- package/src/platforms/slackbot/credential-manager.test.ts +22 -22
- package/src/platforms/slackbot/types.test.ts +7 -7
- package/src/platforms/teams/client.test.ts +30 -30
- package/src/platforms/teams/commands/auth.test.ts +8 -8
- package/src/platforms/teams/commands/channel.test.ts +7 -7
- package/src/platforms/teams/commands/file.test.ts +4 -4
- package/src/platforms/teams/commands/message.test.ts +5 -5
- package/src/platforms/teams/commands/reaction.test.ts +4 -4
- package/src/platforms/teams/commands/snapshot.test.ts +7 -7
- package/src/platforms/teams/commands/team.test.ts +8 -8
- package/src/platforms/teams/commands/user.test.ts +4 -4
- package/src/platforms/teams/commands/whoami.test.ts +6 -6
- package/src/platforms/teams/credential-manager.test.ts +17 -17
- package/src/platforms/teams/ensure-auth.test.ts +13 -13
- package/src/platforms/teams/index.test.ts +15 -15
- package/src/platforms/teams/token-extractor.test.ts +109 -49
- package/src/platforms/teams/token-extractor.ts +7 -2
- package/src/platforms/teams/types.test.ts +26 -26
- package/src/platforms/telegram/app-config.test.ts +4 -4
- package/src/platforms/telegram/chat-utils.test.ts +12 -12
- package/src/platforms/telegram/client.test.ts +4 -4
- package/src/platforms/telegram/commands/auth.test.ts +16 -16
- package/src/platforms/telegram/commands/chat.test.ts +9 -9
- package/src/platforms/telegram/commands/message.test.ts +6 -6
- package/src/platforms/telegram/commands/shared.test.ts +3 -3
- package/src/platforms/telegram/commands/whoami.test.ts +3 -3
- package/src/platforms/telegram/credential-manager.test.ts +10 -10
- package/src/platforms/telegram/types.test.ts +6 -6
- package/src/platforms/webex/app-config.test.ts +8 -8
- package/src/platforms/webex/cli.test.ts +5 -5
- package/src/platforms/webex/client.test.ts +65 -65
- package/src/platforms/webex/commands/auth.test.ts +18 -18
- package/src/platforms/webex/commands/member.test.ts +5 -5
- package/src/platforms/webex/commands/message.test.ts +12 -12
- package/src/platforms/webex/commands/snapshot.test.ts +5 -5
- package/src/platforms/webex/commands/space.test.ts +10 -10
- package/src/platforms/webex/commands/whoami.test.ts +6 -6
- package/src/platforms/webex/credential-manager.test.ts +22 -22
- package/src/platforms/webex/encryption.test.ts +4 -4
- package/src/platforms/webex/ensure-auth.test.ts +5 -5
- package/src/platforms/webex/index.test.ts +5 -5
- package/src/platforms/webex/markdown-to-html.test.ts +33 -33
- package/src/platforms/webex/token-extractor.test.ts +23 -23
- package/src/platforms/webex/types.test.ts +27 -27
- package/src/platforms/wechatbot/client.test.ts +27 -27
- package/src/platforms/wechatbot/commands/auth.test.ts +15 -15
- package/src/platforms/wechatbot/commands/message.test.ts +8 -8
- package/src/platforms/wechatbot/commands/template.test.ts +9 -9
- package/src/platforms/wechatbot/commands/user.test.ts +7 -7
- package/src/platforms/wechatbot/commands/whoami.test.ts +5 -5
- package/src/platforms/wechatbot/credential-manager.test.ts +18 -18
- package/src/platforms/wechatbot/index.test.ts +10 -10
- package/src/platforms/wechatbot/types.test.ts +25 -25
- package/src/platforms/whatsapp/commands/auth.test.ts +13 -13
- package/src/platforms/whatsapp/commands/chat.test.ts +8 -8
- package/src/platforms/whatsapp/commands/message.test.ts +10 -10
- package/src/platforms/whatsapp/commands/whoami.test.ts +3 -3
- package/src/platforms/whatsapp/credential-manager.test.ts +23 -23
- package/src/platforms/whatsapp/ensure-auth.test.ts +4 -4
- package/src/platforms/whatsapp/index.test.ts +8 -8
- package/src/platforms/whatsapp/types.test.ts +42 -42
- package/src/platforms/whatsappbot/client.test.ts +27 -27
- package/src/platforms/whatsappbot/commands/auth.test.ts +14 -14
- package/src/platforms/whatsappbot/commands/message.test.ts +16 -16
- package/src/platforms/whatsappbot/commands/template.test.ts +9 -9
- package/src/platforms/whatsappbot/commands/whoami.test.ts +5 -5
- package/src/platforms/whatsappbot/credential-manager.test.ts +18 -18
- package/src/platforms/whatsappbot/index.test.ts +7 -7
- package/src/platforms/whatsappbot/types.test.ts +18 -18
- package/src/shared/chromium/browsers.test.ts +22 -22
- package/src/shared/chromium/cookie-reader.test.ts +13 -13
- package/src/shared/chromium/decryptor.test.ts +97 -32
- package/src/shared/chromium/decryptor.ts +27 -6
- package/src/shared/utils/concurrency.test.ts +6 -6
- package/src/shared/utils/derived-key-cache.test.ts +11 -11
- package/src/tui/utils.test.ts +31 -31
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, spyOn,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
262
|
+
it('rejects empty tokens', () => {
|
|
263
263
|
expect(extractor.isValidSkypeToken('')).toBe(false)
|
|
264
264
|
})
|
|
265
265
|
|
|
266
|
-
|
|
266
|
+
it('rejects short tokens', () => {
|
|
267
267
|
expect(extractor.isValidSkypeToken('short')).toBe(false)
|
|
268
268
|
})
|
|
269
269
|
|
|
270
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
193
|
-
|
|
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 {
|