mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-05-19 18:58:03 +02:00
220 lines
5.9 KiB
Go
220 lines
5.9 KiB
Go
package localstorage
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"testing"
|
|
"unicode/utf16"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/syndtr/goleveldb/leveldb"
|
|
)
|
|
|
|
func TestDecodeChromiumString(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
input []byte
|
|
want string
|
|
wantErr string
|
|
}{
|
|
{
|
|
name: "latin1",
|
|
input: encodeChromiumLatin1("abc123"),
|
|
want: "abc123",
|
|
},
|
|
{
|
|
name: "utf16le",
|
|
input: encodeChromiumUTF16("飞连"),
|
|
want: "飞连",
|
|
},
|
|
{
|
|
name: "unknown format",
|
|
input: []byte{2, 'x'},
|
|
wantErr: "unknown chromium string format",
|
|
},
|
|
{
|
|
name: "invalid utf16 byte length",
|
|
input: []byte{chromiumStringUTF16Format, 0x61},
|
|
wantErr: "invalid UTF-16 byte length",
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
got, err := decodeChromiumString(tc.input)
|
|
if tc.wantErr != "" {
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), tc.wantErr)
|
|
return
|
|
}
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, tc.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseChromiumLocalStorageEntry(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
key []byte
|
|
value []byte
|
|
wantParsed bool
|
|
wantMeta bool
|
|
wantURL string
|
|
wantKey string
|
|
wantValue string
|
|
wantContains string
|
|
}{
|
|
{
|
|
name: "skip version key",
|
|
key: []byte(chromiumLocalStorageVersionKey),
|
|
wantParsed: false,
|
|
},
|
|
{
|
|
name: "meta key",
|
|
key: []byte(chromiumLocalStorageMetaPrefix + "https://example.com"),
|
|
value: []byte{0x08, 0x96, 0x01},
|
|
wantParsed: true,
|
|
wantMeta: true,
|
|
wantURL: "https://example.com",
|
|
wantValue: "meta data, value bytes is [8 150 1]",
|
|
},
|
|
{
|
|
name: "meta access key",
|
|
key: []byte(chromiumLocalStorageMetaAccessKey + "https://example.com"),
|
|
value: []byte{0x10, 0x20},
|
|
wantParsed: true,
|
|
wantMeta: true,
|
|
wantURL: "https://example.com",
|
|
wantValue: "meta data, value bytes is [16 32]",
|
|
},
|
|
{
|
|
name: "latin1 business key",
|
|
key: append([]byte("_https://example.com\x00"), encodeChromiumLatin1("token")...),
|
|
value: encodeChromiumLatin1("abc123"),
|
|
wantParsed: true,
|
|
wantURL: "https://example.com",
|
|
wantKey: "token",
|
|
wantValue: "abc123",
|
|
},
|
|
{
|
|
name: "utf16 business key",
|
|
key: append([]byte("_https://example.com\x00"), encodeChromiumUTF16("飞连")...),
|
|
value: encodeChromiumUTF16("终端安全"),
|
|
wantParsed: true,
|
|
wantURL: "https://example.com",
|
|
wantKey: "飞连",
|
|
wantValue: "终端安全",
|
|
},
|
|
{
|
|
name: "unsupported business key format",
|
|
key: append([]byte("_https://example.com\x00"), []byte{2, 'x'}...),
|
|
value: encodeChromiumLatin1("abc123"),
|
|
wantParsed: true,
|
|
wantURL: "https://example.com",
|
|
wantContains: "unsupported chromium localStorage key encoding",
|
|
wantValue: "abc123",
|
|
},
|
|
{
|
|
name: "missing origin separator",
|
|
key: append([]byte("_https://example.com"), encodeChromiumLatin1("token")...),
|
|
value: encodeChromiumLatin1("abc123"),
|
|
wantParsed: true,
|
|
wantContains: "missing origin separator",
|
|
wantValue: "abc123",
|
|
},
|
|
{
|
|
name: "unsupported value format",
|
|
key: append([]byte("_https://example.com\x00"), encodeChromiumLatin1("token")...),
|
|
value: []byte{2, 'x'},
|
|
wantParsed: true,
|
|
wantURL: "https://example.com",
|
|
wantKey: "token",
|
|
wantValue: "unsupported chromium localStorage value encoding: unknown chromium string format 0x02",
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
got, parsed := parseChromiumLocalStorageEntry(tc.key, tc.value)
|
|
|
|
assert.Equal(t, tc.wantParsed, parsed)
|
|
assert.Equal(t, tc.wantMeta, got.IsMeta)
|
|
assert.Equal(t, tc.wantURL, got.URL)
|
|
assert.Equal(t, tc.wantValue, got.Value)
|
|
if tc.wantContains != "" {
|
|
assert.Contains(t, got.Key, tc.wantContains)
|
|
return
|
|
}
|
|
assert.Equal(t, tc.wantKey, got.Key)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExtractChromiumLocalStorage(t *testing.T) {
|
|
dir := t.TempDir()
|
|
db, err := leveldb.OpenFile(dir, nil)
|
|
require.NoError(t, err)
|
|
|
|
testEntries := map[string][]byte{
|
|
chromiumLocalStorageVersionKey: []byte("1"),
|
|
chromiumLocalStorageMetaPrefix + "https://example.com": {0x08, 0x96, 0x01},
|
|
chromiumLocalStorageMetaAccessKey + "https://example.com": {0x10, 0x20},
|
|
string(append([]byte("_https://example.com\x00"), encodeChromiumLatin1("token")...)): encodeChromiumLatin1("abc123"),
|
|
string(append([]byte("_https://example.com\x00"), encodeChromiumUTF16("飞连")...)): encodeChromiumUTF16("终端安全"),
|
|
}
|
|
|
|
for key, value := range testEntries {
|
|
require.NoError(t, db.Put([]byte(key), value, nil))
|
|
}
|
|
require.NoError(t, db.Close())
|
|
|
|
got, err := extractChromiumLocalStorage(dir)
|
|
require.NoError(t, err)
|
|
require.Len(t, got, 4)
|
|
|
|
metaCount := 0
|
|
valuesByKey := make(map[string]string)
|
|
for _, entry := range got {
|
|
if entry.IsMeta {
|
|
metaCount++
|
|
assert.Equal(t, "https://example.com", entry.URL)
|
|
assert.Contains(t, entry.Value, "meta data, value bytes is")
|
|
continue
|
|
}
|
|
valuesByKey[entry.Key] = entry.Value
|
|
assert.Equal(t, "https://example.com", entry.URL)
|
|
}
|
|
|
|
assert.Equal(t, 2, metaCount)
|
|
assert.Equal(t, "abc123", valuesByKey["token"])
|
|
assert.Equal(t, "终端安全", valuesByKey["飞连"])
|
|
}
|
|
|
|
func encodeChromiumLatin1(s string) []byte {
|
|
return append([]byte{chromiumStringLatin1Format}, []byte(s)...)
|
|
}
|
|
|
|
func encodeChromiumUTF16(s string) []byte {
|
|
encoded := utf16.Encode([]rune(s))
|
|
result := make([]byte, 1, 1+len(encoded)*2)
|
|
result[0] = chromiumStringUTF16Format
|
|
for _, r := range encoded {
|
|
var raw [2]byte
|
|
binary.LittleEndian.PutUint16(raw[:], r)
|
|
result = append(result, raw[:]...)
|
|
}
|
|
return result
|
|
}
|