Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IndexedDB/KATC] Firefox array deserialization improvements and more tests #1795

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 0 additions & 88 deletions ee/indexeddb/indexeddb_test.go

This file was deleted.

28 changes: 0 additions & 28 deletions ee/indexeddb/test_data/README.md

This file was deleted.

30 changes: 22 additions & 8 deletions ee/katc/deserialize_firefox.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,24 +227,38 @@ func deserializeUtf16String(strLen uint32, srcReader io.ByteReader) ([]byte, err
func deserializeArray(arrayLength uint32, srcReader io.ByteReader) ([]byte, error) {
resultArr := make([]any, arrayLength)

// We discard the next pair before reading the array.
_, _, _ = nextPair(srcReader)
for {
// The next pair is the index.
idxTag, idx, err := nextPair(srcReader)
if err != nil {
return nil, fmt.Errorf("reading next index in array: %w", err)
}

if idxTag == tagEndOfKeys {
break
}

for i := 0; i < int(arrayLength); i += 1 {
itemTag, _, err := nextPair(srcReader)
// Now, read the data for this index.
itemTag, itemData, err := nextPair(srcReader)
if err != nil {
return nil, fmt.Errorf("reading item at index %d in array: %w", i, err)
return nil, fmt.Errorf("reading item at index %d in array: %w", idx, err)
}

switch itemTag {
case tagObjectObject:
obj, err := deserializeNestedObject(srcReader)
if err != nil {
return nil, fmt.Errorf("reading object at index %d in array: %w", i, err)
return nil, fmt.Errorf("reading object at index %d in array: %w", idx, err)
}
resultArr[idx] = string(obj) // cast to string so it's readable when marshalled again below
case tagString:
str, err := deserializeString(itemData, srcReader)
if err != nil {
return nil, fmt.Errorf("reading string at index %d in array: %w", idx, err)
}
resultArr[i] = string(obj) // cast to string so it's readable when marshalled again below
resultArr[idx] = string(str) // cast to string so it's readable when marshalled again below
default:
return nil, fmt.Errorf("cannot process item at index %d in array: unsupported tag type %x", i, itemTag)
return nil, fmt.Errorf("cannot process item at index %d in array: unsupported tag type %x", idx, itemTag)
}
}

Expand Down
106 changes: 0 additions & 106 deletions ee/katc/deserialize_firefox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,119 +4,13 @@ import (
"bytes"
"context"
"encoding/binary"
"encoding/json"
"io"
"testing"

"github.com/google/uuid"
"github.com/kolide/launcher/pkg/log/multislogger"
"github.com/stretchr/testify/require"
)

func Test_deserializeFirefox(t *testing.T) {
t.Parallel()

// Build expected object
u, err := uuid.NewRandom()
require.NoError(t, err, "generating test UUID")
idValue := u.String()
arrWithNestedObj := []string{"{\"id\":\"3\"}"}
nestedArrBytes, err := json.Marshal(arrWithNestedObj)
require.NoError(t, err)
expectedObj := map[string][]byte{
"id": []byte(idValue), // will exercise deserializeString
"version": []byte("1"), // will exercise int deserialization
"option": nil, // will exercise null/undefined deserialization
"types": nestedArrBytes, // will exercise deserializeArray, deserializeNestedObject
}

// Build a serialized object to deserialize
serializedObj := []byte{
// Header
0x00, 0x00, 0x00, 0x00, // header tag data -- discarded
0x00, 0x00, 0xf1, 0xff, // LE `tagHeader`
// Begin object
0x00, 0x00, 0x00, 0x00, // object tag data -- discarded
0x08, 0x00, 0xff, 0xff, // LE `tagObject`
// Begin `id` key
0x02, 0x00, 0x00, 0x80, // LE data about upcoming string: length 2 (remaining bytes), is ASCII
0x04, 0x00, 0xff, 0xff, // LE `tagString`
0x69, 0x64, // "id"
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding to get to 8-byte word boundary
// End `id` key
// Begin `id` value
0x24, 0x00, 0x00, 0x80, // LE data about upcoming string: length 36 (remaining bytes), is ASCII
0x04, 0x00, 0xff, 0xff, // LE `tagString`
}
// Append `id`
serializedObj = append(serializedObj, []byte(idValue)...)
// Append `id` padding, add `version`
serializedObj = append(serializedObj,
0x00, 0x00, 0x00, 0x00, // padding to get to 8-byte word boundary for `id` string
// End `id` value
// Begin `version` key
0x07, 0x00, 0x00, 0x80, // LE data about upcoming string: length 7 (remaining bytes), is ASCII
0x04, 0x00, 0xff, 0xff, // LE `tagString`
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, // "version"
0x00, // padding to get to 8-byte word boundary
// End `version` key
// Begin `version` value
0x01, 0x00, 0x00, 0x00, // Value `1`
0x03, 0x00, 0xff, 0xff, // LE `tagInt32`
// End `version` value
// Begin `option` key
0x06, 0x00, 0x00, 0x80, // LE data about upcoming string: length 6 (remaining bytes), is ASCII
0x04, 0x00, 0xff, 0xff, // LE `tagString`
0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, // "option"
0x00, 0x00, // padding to get to 8-byte word boundary
// End `option` key
// Begin `option` value
0x00, 0x00, 0x00, 0x00, // Unused data, discarded
0x00, 0x00, 0xff, 0xff, // LE `tagNull`
// End `option` value
// Begin `types` key
0x05, 0x00, 0x00, 0x80, // LE data about upcoming string: length 5 (remaining bytes), is ASCII
0x04, 0x00, 0xff, 0xff, // LE `tagString`
0x74, 0x79, 0x70, 0x65, 0x73, // "types"
0x00, 0x00, 0x00, // padding to get to 8-byte word boundary
// End `types` key
// Begin `types` value
0x01, 0x00, 0x00, 0x00, // Array length (1)
0x07, 0x00, 0xff, 0xff, // LE `tagArrayObject`
// Begin first array item
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // An extra pair that gets discarded, I don't know why
0x00, 0x00, 0x00, 0x00, // Tag data, discarded
0x08, 0x00, 0xff, 0xff, // LE `tagObjectObject`
// Begin nested object
// Begin `id` key
0x02, 0x00, 0x00, 0x80, // LE data about upcoming string: length 2 (remaining bytes), is ASCII
0x04, 0x00, 0xff, 0xff, // LE `tagString`
0x69, 0x64, // "id"
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding to get to 8-byte word boundary
// End `id` key
// Begin `id` value
0x03, 0x00, 0x00, 0x00, // Value `3`
0x03, 0x00, 0xff, 0xff, // LE `tagInt32`
// End `id` value
// Object footer
0x00, 0x00, 0x00, 0x00, // tag data -- discarded
0x13, 0x00, 0xff, 0xff, // LE `tagEndOfKeys` 0xffff0013
// End nested object
// End first array item
// End `types` value
// Object footer
0x00, 0x00, 0x00, 0x00, // tag data -- discarded
0x13, 0x00, 0xff, 0xff, // LE `tagEndOfKeys`
)

results, err := deserializeFirefox(context.TODO(), multislogger.NewNopLogger(), map[string][]byte{
"data": serializedObj,
})
require.NoError(t, err, "expected to be able to deserialize object")

require.Equal(t, expectedObj, results)
}

func Test_deserializeFirefox_missingTopLevelDataKey(t *testing.T) {
t.Parallel()

Expand Down
Loading
Loading