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 { afterEach, describe, expect,
|
|
1
|
+
import { afterEach, describe, expect, it } from 'bun:test'
|
|
2
2
|
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
|
3
3
|
import { tmpdir } from 'node:os'
|
|
4
4
|
import { join } from 'node:path'
|
|
@@ -26,34 +26,34 @@ describe('browsers', () => {
|
|
|
26
26
|
})
|
|
27
27
|
|
|
28
28
|
describe('CHROMIUM_BROWSERS', () => {
|
|
29
|
-
|
|
29
|
+
it('has 7 browsers', () => {
|
|
30
30
|
expect(CHROMIUM_BROWSERS).toHaveLength(7)
|
|
31
31
|
})
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
it('includes major supported browsers', () => {
|
|
34
34
|
const browserNames = CHROMIUM_BROWSERS.map((browser) => browser.name)
|
|
35
35
|
|
|
36
36
|
expect(browserNames).toEqual(expect.arrayContaining(['Chrome', 'Edge', 'Arc', 'Brave', 'Vivaldi', 'Chromium']))
|
|
37
37
|
})
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
it('Arc has empty linux path', () => {
|
|
40
40
|
expect(CHROMIUM_BROWSERS.find((browser) => browser.name === 'Arc')?.linux).toBe('')
|
|
41
41
|
})
|
|
42
42
|
})
|
|
43
43
|
|
|
44
44
|
describe('BROWSER_KEYCHAIN_VARIANTS', () => {
|
|
45
|
-
|
|
45
|
+
it('has 7 keychain variants', () => {
|
|
46
46
|
expect(BROWSER_KEYCHAIN_VARIANTS).toHaveLength(7)
|
|
47
47
|
})
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
it('each variant has service and account properties', () => {
|
|
50
50
|
for (const variant of BROWSER_KEYCHAIN_VARIANTS) {
|
|
51
51
|
expect(variant.service).toBeString()
|
|
52
52
|
expect(variant.account).toBeString()
|
|
53
53
|
}
|
|
54
54
|
})
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
it('includes known safe storage services', () => {
|
|
57
57
|
const services = BROWSER_KEYCHAIN_VARIANTS.map((variant) => variant.service)
|
|
58
58
|
|
|
59
59
|
expect(services).toEqual(expect.arrayContaining(['Chrome Safe Storage', 'Microsoft Edge Safe Storage']))
|
|
@@ -61,7 +61,7 @@ describe('browsers', () => {
|
|
|
61
61
|
})
|
|
62
62
|
|
|
63
63
|
describe('getBrowserBasePath', () => {
|
|
64
|
-
|
|
64
|
+
it('returns darwin path with Library/Application Support prefix', () => {
|
|
65
65
|
// given
|
|
66
66
|
const chrome = CHROMIUM_BROWSERS.find((browser) => browser.name === 'Chrome')!
|
|
67
67
|
|
|
@@ -74,7 +74,7 @@ describe('browsers', () => {
|
|
|
74
74
|
expect(path).toEndWith(join('Google', 'Chrome'))
|
|
75
75
|
})
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
it('returns linux path with .config prefix', () => {
|
|
78
78
|
// given
|
|
79
79
|
const chrome = CHROMIUM_BROWSERS.find((browser) => browser.name === 'Chrome')!
|
|
80
80
|
|
|
@@ -86,7 +86,7 @@ describe('browsers', () => {
|
|
|
86
86
|
expect(path).toContain(join('.config', 'google-chrome'))
|
|
87
87
|
})
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
it('returns win32 path with LOCALAPPDATA prefix', () => {
|
|
90
90
|
// given
|
|
91
91
|
const localAppData = mkdtempSync(join(tmpdir(), 'browser-localappdata-'))
|
|
92
92
|
tempDirs.push(localAppData)
|
|
@@ -100,7 +100,7 @@ describe('browsers', () => {
|
|
|
100
100
|
expect(path).toBe(join(localAppData, 'Google', 'Chrome', 'User Data'))
|
|
101
101
|
})
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
it('returns null for unsupported platform', () => {
|
|
104
104
|
// given
|
|
105
105
|
const chrome = CHROMIUM_BROWSERS.find((browser) => browser.name === 'Chrome')!
|
|
106
106
|
|
|
@@ -111,7 +111,7 @@ describe('browsers', () => {
|
|
|
111
111
|
expect(path).toBeNull()
|
|
112
112
|
})
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
it('returns null when browser has empty path for platform', () => {
|
|
115
115
|
// given
|
|
116
116
|
const arc = CHROMIUM_BROWSERS.find((browser) => browser.name === 'Arc')!
|
|
117
117
|
|
|
@@ -124,7 +124,7 @@ describe('browsers', () => {
|
|
|
124
124
|
})
|
|
125
125
|
|
|
126
126
|
describe('discoverBrowserProfileDirs', () => {
|
|
127
|
-
|
|
127
|
+
it('always includes Default dir even when base does not exist', () => {
|
|
128
128
|
// given
|
|
129
129
|
const browserBase = join(tmpdir(), `missing-browser-base-${Date.now()}-${Math.random().toString(36).slice(2)}`)
|
|
130
130
|
|
|
@@ -135,7 +135,7 @@ describe('browsers', () => {
|
|
|
135
135
|
expect(dirs).toEqual([join(browserBase, 'Default')])
|
|
136
136
|
})
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
it('discovers Profile 1 and Profile 2 dirs when they exist', () => {
|
|
139
139
|
// given
|
|
140
140
|
const browserBase = mkdtempSync(join(tmpdir(), 'browser-profiles-'))
|
|
141
141
|
tempDirs.push(browserBase)
|
|
@@ -153,7 +153,7 @@ describe('browsers', () => {
|
|
|
153
153
|
])
|
|
154
154
|
})
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
it('ignores non-profile directories', () => {
|
|
157
157
|
// given
|
|
158
158
|
const browserBase = mkdtempSync(join(tmpdir(), 'browser-non-profile-'))
|
|
159
159
|
tempDirs.push(browserBase)
|
|
@@ -168,7 +168,7 @@ describe('browsers', () => {
|
|
|
168
168
|
expect(dirs).toEqual([join(browserBase, 'Default'), join(browserBase, 'Profile 1')])
|
|
169
169
|
})
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
it('ignores files that match profile pattern', () => {
|
|
172
172
|
// given
|
|
173
173
|
const browserBase = mkdtempSync(join(tmpdir(), 'browser-profile-files-'))
|
|
174
174
|
tempDirs.push(browserBase)
|
|
@@ -182,7 +182,7 @@ describe('browsers', () => {
|
|
|
182
182
|
expect(dirs).toEqual([join(browserBase, 'Default'), join(browserBase, 'Profile 2')])
|
|
183
183
|
})
|
|
184
184
|
|
|
185
|
-
|
|
185
|
+
it('returns only Default when base directory is empty', () => {
|
|
186
186
|
// given
|
|
187
187
|
const browserBase = mkdtempSync(join(tmpdir(), 'browser-empty-'))
|
|
188
188
|
tempDirs.push(browserBase)
|
|
@@ -196,7 +196,7 @@ describe('browsers', () => {
|
|
|
196
196
|
})
|
|
197
197
|
|
|
198
198
|
describe('findLocalStatePath', () => {
|
|
199
|
-
|
|
199
|
+
it('returns null when no Local State exists at any level', () => {
|
|
200
200
|
// given
|
|
201
201
|
const rootDir = mkdtempSync(join(tmpdir(), 'browser-local-state-missing-'))
|
|
202
202
|
tempDirs.push(rootDir)
|
|
@@ -210,7 +210,7 @@ describe('browsers', () => {
|
|
|
210
210
|
expect(path).toBeNull()
|
|
211
211
|
})
|
|
212
212
|
|
|
213
|
-
|
|
213
|
+
it('finds Local State 2 levels up from cookie path', () => {
|
|
214
214
|
// given
|
|
215
215
|
const rootDir = mkdtempSync(join(tmpdir(), 'browser-local-state-two-'))
|
|
216
216
|
tempDirs.push(rootDir)
|
|
@@ -226,7 +226,7 @@ describe('browsers', () => {
|
|
|
226
226
|
expect(path).toBe(join(profileDir, 'Local State'))
|
|
227
227
|
})
|
|
228
228
|
|
|
229
|
-
|
|
229
|
+
it('finds Local State 3 levels up from cookie path', () => {
|
|
230
230
|
// given
|
|
231
231
|
const rootDir = mkdtempSync(join(tmpdir(), 'browser-local-state-three-'))
|
|
232
232
|
tempDirs.push(rootDir)
|
|
@@ -242,7 +242,7 @@ describe('browsers', () => {
|
|
|
242
242
|
expect(path).toBe(join(browserDir, 'Local State'))
|
|
243
243
|
})
|
|
244
244
|
|
|
245
|
-
|
|
245
|
+
it('returns null for path with too few segments', () => {
|
|
246
246
|
// given
|
|
247
247
|
const cookiePath = 'Cookies'
|
|
248
248
|
|
|
@@ -253,7 +253,7 @@ describe('browsers', () => {
|
|
|
253
253
|
expect(path).toBeNull()
|
|
254
254
|
})
|
|
255
255
|
|
|
256
|
-
|
|
256
|
+
it('finds the first match when multiple levels could match', () => {
|
|
257
257
|
// given
|
|
258
258
|
const rootDir = mkdtempSync(join(tmpdir(), 'browser-local-state-first-'))
|
|
259
259
|
tempDirs.push(rootDir)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Database } from 'bun:sqlite'
|
|
2
|
-
import { afterEach, describe, expect,
|
|
2
|
+
import { afterEach, describe, expect, it } from 'bun:test'
|
|
3
3
|
import { existsSync, mkdtempSync, rmSync } from 'node:fs'
|
|
4
4
|
import { tmpdir } from 'node:os'
|
|
5
5
|
import { join } from 'node:path'
|
|
@@ -31,7 +31,7 @@ describe('ChromiumCookieReader', () => {
|
|
|
31
31
|
})
|
|
32
32
|
|
|
33
33
|
describe('queryAll', () => {
|
|
34
|
-
|
|
34
|
+
it('returns all matching rows from a real SQLite database', async () => {
|
|
35
35
|
// given
|
|
36
36
|
const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
|
|
37
37
|
tempDirs.push(tempDir)
|
|
@@ -55,7 +55,7 @@ describe('ChromiumCookieReader', () => {
|
|
|
55
55
|
])
|
|
56
56
|
})
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
it('returns empty array when database file does not exist', async () => {
|
|
59
59
|
// given
|
|
60
60
|
const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
|
|
61
61
|
tempDirs.push(tempDir)
|
|
@@ -69,7 +69,7 @@ describe('ChromiumCookieReader', () => {
|
|
|
69
69
|
expect(result).toEqual([])
|
|
70
70
|
})
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
it('returns empty array when query matches no rows', async () => {
|
|
73
73
|
// given
|
|
74
74
|
const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
|
|
75
75
|
tempDirs.push(tempDir)
|
|
@@ -86,7 +86,7 @@ describe('ChromiumCookieReader', () => {
|
|
|
86
86
|
expect(result).toEqual([])
|
|
87
87
|
})
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
it('supports parameterized queries with params', async () => {
|
|
90
90
|
// given
|
|
91
91
|
const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
|
|
92
92
|
tempDirs.push(tempDir)
|
|
@@ -108,7 +108,7 @@ describe('ChromiumCookieReader', () => {
|
|
|
108
108
|
expect(result).toEqual([{ name: 'token', value: 'xyz789' }])
|
|
109
109
|
})
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
it('cleans up temp file after query', async () => {
|
|
112
112
|
// given
|
|
113
113
|
const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
|
|
114
114
|
tempDirs.push(tempDir)
|
|
@@ -135,7 +135,7 @@ describe('ChromiumCookieReader', () => {
|
|
|
135
135
|
})
|
|
136
136
|
|
|
137
137
|
describe('queryFirst', () => {
|
|
138
|
-
|
|
138
|
+
it('returns first matching row from a real SQLite database', async () => {
|
|
139
139
|
// given
|
|
140
140
|
const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
|
|
141
141
|
tempDirs.push(tempDir)
|
|
@@ -156,7 +156,7 @@ describe('ChromiumCookieReader', () => {
|
|
|
156
156
|
expect(result).toEqual({ name: 'session', value: 'abc123' })
|
|
157
157
|
})
|
|
158
158
|
|
|
159
|
-
|
|
159
|
+
it('returns null when database file does not exist', async () => {
|
|
160
160
|
// given
|
|
161
161
|
const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
|
|
162
162
|
tempDirs.push(tempDir)
|
|
@@ -170,7 +170,7 @@ describe('ChromiumCookieReader', () => {
|
|
|
170
170
|
expect(result).toBeNull()
|
|
171
171
|
})
|
|
172
172
|
|
|
173
|
-
|
|
173
|
+
it('returns null when query matches no rows', async () => {
|
|
174
174
|
// given
|
|
175
175
|
const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
|
|
176
176
|
tempDirs.push(tempDir)
|
|
@@ -187,7 +187,7 @@ describe('ChromiumCookieReader', () => {
|
|
|
187
187
|
expect(result).toBeNull()
|
|
188
188
|
})
|
|
189
189
|
|
|
190
|
-
|
|
190
|
+
it('supports parameterized queries with params', async () => {
|
|
191
191
|
// given
|
|
192
192
|
const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
|
|
193
193
|
tempDirs.push(tempDir)
|
|
@@ -211,7 +211,7 @@ describe('ChromiumCookieReader', () => {
|
|
|
211
211
|
})
|
|
212
212
|
|
|
213
213
|
describe('edge cases', () => {
|
|
214
|
-
|
|
214
|
+
it('handles multiple calls to same reader instance', async () => {
|
|
215
215
|
// given
|
|
216
216
|
const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
|
|
217
217
|
tempDirs.push(tempDir)
|
|
@@ -241,7 +241,7 @@ describe('ChromiumCookieReader', () => {
|
|
|
241
241
|
expect(firstRow).toEqual({ name: 'token', value: 'xyz789' })
|
|
242
242
|
})
|
|
243
243
|
|
|
244
|
-
|
|
244
|
+
it('returns empty array for malformed SQL without throwing', async () => {
|
|
245
245
|
// given
|
|
246
246
|
const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
|
|
247
247
|
tempDirs.push(tempDir)
|
|
@@ -256,7 +256,7 @@ describe('ChromiumCookieReader', () => {
|
|
|
256
256
|
expect(result).toEqual([])
|
|
257
257
|
})
|
|
258
258
|
|
|
259
|
-
|
|
259
|
+
it('returns null for malformed SQL without throwing', async () => {
|
|
260
260
|
// given
|
|
261
261
|
const tempDir = mkdtempSync(join(tmpdir(), 'chromium-cookie-reader-'))
|
|
262
262
|
tempDirs.push(tempDir)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, spyOn,
|
|
1
|
+
import { beforeEach, describe, expect, spyOn, it } from 'bun:test'
|
|
2
2
|
import { createCipheriv, pbkdf2Sync, randomBytes } from 'node:crypto'
|
|
3
3
|
|
|
4
4
|
import * as linuxKeyring from '@/shared/utils/linux-keyring'
|
|
@@ -29,7 +29,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
29
29
|
})
|
|
30
30
|
|
|
31
31
|
describe('constructor', () => {
|
|
32
|
-
|
|
32
|
+
it('prepends appKeychainVariants before browser variants', () => {
|
|
33
33
|
// given
|
|
34
34
|
const appVariants = [{ service: 'App Safe Storage', account: 'App' }]
|
|
35
35
|
|
|
@@ -40,7 +40,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
40
40
|
expect((decryptor as any).keychainVariants).toEqual([...appVariants, ...BROWSER_KEYCHAIN_VARIANTS])
|
|
41
41
|
})
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
it('uses only browser variants when no appKeychainVariants provided', () => {
|
|
44
44
|
// given
|
|
45
45
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'darwin' })
|
|
46
46
|
|
|
@@ -50,7 +50,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
50
50
|
})
|
|
51
51
|
|
|
52
52
|
describe('isEncryptedValue', () => {
|
|
53
|
-
|
|
53
|
+
it('returns true for v10 prefix with sufficient length', () => {
|
|
54
54
|
// given
|
|
55
55
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
56
56
|
|
|
@@ -61,7 +61,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
61
61
|
expect(result).toBe(true)
|
|
62
62
|
})
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
it('returns true for v11 prefix with sufficient length', () => {
|
|
65
65
|
// given
|
|
66
66
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
67
67
|
|
|
@@ -72,7 +72,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
72
72
|
expect(result).toBe(true)
|
|
73
73
|
})
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
it('returns false for non-v10/v11 prefix', () => {
|
|
76
76
|
// given
|
|
77
77
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
78
78
|
|
|
@@ -83,7 +83,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
83
83
|
expect(result).toBe(false)
|
|
84
84
|
})
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
it('returns false for too-short buffer (< 4 bytes)', () => {
|
|
87
87
|
// given
|
|
88
88
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
89
89
|
|
|
@@ -94,7 +94,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
94
94
|
expect(result).toBe(false)
|
|
95
95
|
})
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
it('returns false for null/empty buffer', () => {
|
|
98
98
|
// given
|
|
99
99
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
100
100
|
|
|
@@ -105,7 +105,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
105
105
|
})
|
|
106
106
|
|
|
107
107
|
describe('decryptAESCBC / decryptAESCBCRaw', () => {
|
|
108
|
-
|
|
108
|
+
it('decrypts v10-prefixed AES-128-CBC data with correct key', () => {
|
|
109
109
|
// given
|
|
110
110
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
111
111
|
const encrypted = encryptAESCBC('test-value', peanutsKey)
|
|
@@ -117,7 +117,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
117
117
|
expect(result).toBe('test-value')
|
|
118
118
|
})
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
it('returns null with wrong key', () => {
|
|
121
121
|
// given
|
|
122
122
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
123
123
|
const encrypted = encryptAESCBC('test-value', peanutsKey)
|
|
@@ -130,7 +130,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
130
130
|
expect(result).toBeNull()
|
|
131
131
|
})
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
it('returns null for corrupted ciphertext', () => {
|
|
134
134
|
// given
|
|
135
135
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
136
136
|
const encrypted = encryptAESCBC('test-value', peanutsKey)
|
|
@@ -144,7 +144,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
144
144
|
expect(result).toBeNull()
|
|
145
145
|
})
|
|
146
146
|
|
|
147
|
-
|
|
147
|
+
it('decryptAESCBC returns string, decryptAESCBCRaw returns Buffer', () => {
|
|
148
148
|
// given
|
|
149
149
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
150
150
|
const encrypted = encryptAESCBC('test-value', peanutsKey)
|
|
@@ -160,7 +160,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
160
160
|
})
|
|
161
161
|
|
|
162
162
|
describe('decryptAESGCM / decryptAESGCMRaw', () => {
|
|
163
|
-
|
|
163
|
+
it('decrypts v10-prefixed AES-256-GCM data with correct key', () => {
|
|
164
164
|
// given
|
|
165
165
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'win32' })
|
|
166
166
|
const masterKey = randomBytes(32)
|
|
@@ -173,7 +173,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
173
173
|
expect(result).toBe('test-value')
|
|
174
174
|
})
|
|
175
175
|
|
|
176
|
-
|
|
176
|
+
it('returns null with wrong key', () => {
|
|
177
177
|
// given
|
|
178
178
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'win32' })
|
|
179
179
|
const masterKey = randomBytes(32)
|
|
@@ -186,7 +186,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
186
186
|
expect(result).toBeNull()
|
|
187
187
|
})
|
|
188
188
|
|
|
189
|
-
|
|
189
|
+
it('returns null for data shorter than minimum length (3+12+16 = 31 bytes)', () => {
|
|
190
190
|
// given
|
|
191
191
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'win32' })
|
|
192
192
|
|
|
@@ -197,7 +197,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
197
197
|
expect(result).toBeNull()
|
|
198
198
|
})
|
|
199
199
|
|
|
200
|
-
|
|
200
|
+
it('decryptAESGCM returns string, decryptAESGCMRaw returns Buffer', () => {
|
|
201
201
|
// given
|
|
202
202
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'win32' })
|
|
203
203
|
const masterKey = randomBytes(32)
|
|
@@ -214,7 +214,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
214
214
|
})
|
|
215
215
|
|
|
216
216
|
describe('decryptCookie / decryptCookieRaw', () => {
|
|
217
|
-
|
|
217
|
+
it('returns plaintext for non-encrypted values (no v10/v11 prefix)', () => {
|
|
218
218
|
// given
|
|
219
219
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
220
220
|
const plaintext = Buffer.from('plain-cookie')
|
|
@@ -228,7 +228,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
228
228
|
expect(rawResult).toEqual(plaintext)
|
|
229
229
|
})
|
|
230
230
|
|
|
231
|
-
|
|
231
|
+
it('dispatches to Linux decryption for linux platform with v10 prefix', () => {
|
|
232
232
|
// given
|
|
233
233
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
234
234
|
const encrypted = Buffer.from('v10cookie')
|
|
@@ -242,7 +242,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
242
242
|
spy.mockRestore()
|
|
243
243
|
})
|
|
244
244
|
|
|
245
|
-
|
|
245
|
+
it('returns null for unsupported platform (e.g. freebsd)', () => {
|
|
246
246
|
// given
|
|
247
247
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'freebsd' as NodeJS.Platform })
|
|
248
248
|
|
|
@@ -253,7 +253,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
253
253
|
expect(result).toBeNull()
|
|
254
254
|
})
|
|
255
255
|
|
|
256
|
-
|
|
256
|
+
it('decryptCookie returns string, decryptCookieRaw returns Buffer', () => {
|
|
257
257
|
// given
|
|
258
258
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
259
259
|
const encrypted = encryptAESCBC('test-value', peanutsKey)
|
|
@@ -269,7 +269,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
269
269
|
})
|
|
270
270
|
|
|
271
271
|
describe('decryptLinuxCookieRaw', () => {
|
|
272
|
-
|
|
272
|
+
it('decrypts v10-prefixed cookie using peanuts key (known key, verifiable)', () => {
|
|
273
273
|
// given
|
|
274
274
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
275
275
|
const encrypted = encryptAESCBC('linux-cookie', peanutsKey)
|
|
@@ -281,7 +281,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
281
281
|
expect(result).toEqual(Buffer.from('linux-cookie'))
|
|
282
282
|
})
|
|
283
283
|
|
|
284
|
-
|
|
284
|
+
it('falls back to peanuts key for v11 when no keyring app names configured', () => {
|
|
285
285
|
// given
|
|
286
286
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
287
287
|
const encrypted = encryptAESCBC('linux-v11-cookie', peanutsKey, 'v11')
|
|
@@ -295,7 +295,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
295
295
|
})
|
|
296
296
|
|
|
297
297
|
describe('decryptDPAPI', () => {
|
|
298
|
-
|
|
298
|
+
it('returns null on non-win32 platforms', () => {
|
|
299
299
|
// given
|
|
300
300
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'linux' })
|
|
301
301
|
|
|
@@ -307,8 +307,73 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
307
307
|
})
|
|
308
308
|
})
|
|
309
309
|
|
|
310
|
+
describe('extractDPAPIPayload', () => {
|
|
311
|
+
it('extracts payload wrapped in markers', () => {
|
|
312
|
+
// given
|
|
313
|
+
const b64 = Buffer.from('hello').toString('base64')
|
|
314
|
+
const stdout = `<<<B64>>>${b64}<<<END>>>\r\n`
|
|
315
|
+
|
|
316
|
+
// when
|
|
317
|
+
const result = ChromiumCookieDecryptor.extractDPAPIPayload(stdout)
|
|
318
|
+
|
|
319
|
+
// then
|
|
320
|
+
expect(result).toBe(b64)
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
it('strips CLIXML progress-stream contamination before the payload', () => {
|
|
324
|
+
// given: PowerShell emits CLIXML on first module auto-load
|
|
325
|
+
const b64 = Buffer.from('secret-token').toString('base64')
|
|
326
|
+
const stdout =
|
|
327
|
+
'#< CLIXML\r\n' +
|
|
328
|
+
'<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">' +
|
|
329
|
+
'<Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T>' +
|
|
330
|
+
'<T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record">' +
|
|
331
|
+
'<AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC>' +
|
|
332
|
+
'<T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>' +
|
|
333
|
+
`<<<B64>>>${b64}<<<END>>>\r\n`
|
|
334
|
+
|
|
335
|
+
// when
|
|
336
|
+
const result = ChromiumCookieDecryptor.extractDPAPIPayload(stdout)
|
|
337
|
+
|
|
338
|
+
// then
|
|
339
|
+
expect(result).toBe(b64)
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
it('tolerates whitespace and line breaks inside the payload', () => {
|
|
343
|
+
// given
|
|
344
|
+
const b64 = Buffer.from('hello').toString('base64')
|
|
345
|
+
const chunked = b64.slice(0, 3) + '\r\n' + b64.slice(3)
|
|
346
|
+
const stdout = `<<<B64>>>${chunked}<<<END>>>`
|
|
347
|
+
|
|
348
|
+
// when
|
|
349
|
+
const result = ChromiumCookieDecryptor.extractDPAPIPayload(stdout)
|
|
350
|
+
|
|
351
|
+
// then
|
|
352
|
+
expect(result).toBe(b64)
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
it('returns null when markers are missing', () => {
|
|
356
|
+
// given: stdout contains only CLIXML noise, no real payload
|
|
357
|
+
const stdout = '#< CLIXML\r\n<Objs></Objs>\r\n'
|
|
358
|
+
|
|
359
|
+
// when
|
|
360
|
+
const result = ChromiumCookieDecryptor.extractDPAPIPayload(stdout)
|
|
361
|
+
|
|
362
|
+
// then
|
|
363
|
+
expect(result).toBeNull()
|
|
364
|
+
})
|
|
365
|
+
|
|
366
|
+
it('returns null when payload between markers is empty', () => {
|
|
367
|
+
// when
|
|
368
|
+
const result = ChromiumCookieDecryptor.extractDPAPIPayload('<<<B64>>><<<END>>>')
|
|
369
|
+
|
|
370
|
+
// then
|
|
371
|
+
expect(result).toBeNull()
|
|
372
|
+
})
|
|
373
|
+
})
|
|
374
|
+
|
|
310
375
|
describe('stripIntegrityHash', () => {
|
|
311
|
-
|
|
376
|
+
it('returns input unchanged when length <= 32', () => {
|
|
312
377
|
// given
|
|
313
378
|
const decrypted = Buffer.alloc(32, 0x41)
|
|
314
379
|
|
|
@@ -319,7 +384,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
319
384
|
expect(result).toEqual(decrypted)
|
|
320
385
|
})
|
|
321
386
|
|
|
322
|
-
|
|
387
|
+
it('strips first 32 bytes when they contain non-printable characters', () => {
|
|
323
388
|
// given
|
|
324
389
|
const hash = Buffer.concat([Buffer.from([0x00, 0x1f, 0xff]), Buffer.alloc(29, 0x01)])
|
|
325
390
|
const value = Buffer.from('cookie-value')
|
|
@@ -331,7 +396,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
331
396
|
expect(result).toEqual(value)
|
|
332
397
|
})
|
|
333
398
|
|
|
334
|
-
|
|
399
|
+
it('returns input unchanged when first 32 bytes are all printable ASCII', () => {
|
|
335
400
|
// given
|
|
336
401
|
const printablePrefix = Buffer.from('12345678901234567890123456789012')
|
|
337
402
|
const decrypted = Buffer.concat([printablePrefix, Buffer.from('cookie-value')])
|
|
@@ -343,7 +408,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
343
408
|
expect(result).toEqual(decrypted)
|
|
344
409
|
})
|
|
345
410
|
|
|
346
|
-
|
|
411
|
+
it('correctly strips binary hash prefix followed by readable cookie value', () => {
|
|
347
412
|
// given
|
|
348
413
|
const hash = randomBytes(32)
|
|
349
414
|
const value = Buffer.from('readable-cookie-value')
|
|
@@ -355,7 +420,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
355
420
|
expect(result).toEqual(value)
|
|
356
421
|
})
|
|
357
422
|
|
|
358
|
-
|
|
423
|
+
it('handles non-printable bytes that would be mangled by UTF-8 conversion (the v130+ fix)', () => {
|
|
359
424
|
// given
|
|
360
425
|
const binaryPrefix = Buffer.from([
|
|
361
426
|
...Array.from({ length: 16 }, (_, i) => i),
|
|
@@ -372,7 +437,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
372
437
|
})
|
|
373
438
|
|
|
374
439
|
describe('loadCachedKey / clearKeyCache', () => {
|
|
375
|
-
|
|
440
|
+
it('loadCachedKey is no-op on non-darwin platform', async () => {
|
|
376
441
|
// given
|
|
377
442
|
const keyCache = {
|
|
378
443
|
get: async () => Buffer.from('should-not-be-used'),
|
|
@@ -392,7 +457,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
392
457
|
expect((decryptor as any).usedCachedKey).toBe(false)
|
|
393
458
|
})
|
|
394
459
|
|
|
395
|
-
|
|
460
|
+
it('loadCachedKey is no-op when no keyCache configured', async () => {
|
|
396
461
|
// given
|
|
397
462
|
const decryptor = new ChromiumCookieDecryptor({ platform: 'darwin', keyCachePlatform: 'slack' })
|
|
398
463
|
|
|
@@ -404,7 +469,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
404
469
|
expect((decryptor as any).usedCachedKey).toBe(false)
|
|
405
470
|
})
|
|
406
471
|
|
|
407
|
-
|
|
472
|
+
it('clearKeyCache resets cached key state', async () => {
|
|
408
473
|
// given
|
|
409
474
|
const clear = async () => {}
|
|
410
475
|
const keyCache = { get: async () => null, clear }
|
|
@@ -426,7 +491,7 @@ describe('ChromiumCookieDecryptor', () => {
|
|
|
426
491
|
})
|
|
427
492
|
|
|
428
493
|
describe('linux v11 keyring behavior', () => {
|
|
429
|
-
|
|
494
|
+
it('uses configured keyring password before falling back', () => {
|
|
430
495
|
// given
|
|
431
496
|
const password = 'secret-from-keyring'
|
|
432
497
|
const key = pbkdf2Sync(password, 'saltysalt', 1, 16, 'sha1')
|