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.
- 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 +15 -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 +219 -145
- package/src/platforms/teams/token-extractor.ts +13 -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,5 +1,6 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, spyOn,
|
|
2
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
262
|
+
it('rejects empty tokens', () => {
|
|
325
263
|
expect(extractor.isValidSkypeToken('')).toBe(false)
|
|
326
264
|
})
|
|
327
265
|
|
|
328
|
-
|
|
266
|
+
it('rejects short tokens', () => {
|
|
329
267
|
expect(extractor.isValidSkypeToken('short')).toBe(false)
|
|
330
268
|
})
|
|
331
269
|
|
|
332
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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')
|