Skip to content

Commit

Permalink
[IndexedDB/KATC] Firefox array deserialization improvements and more …
Browse files Browse the repository at this point in the history
…tests (#1795)
  • Loading branch information
RebeccaMahany authored Jul 25, 2024
1 parent 9add075 commit 55765bc
Show file tree
Hide file tree
Showing 10 changed files with 293 additions and 339 deletions.
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

0 comments on commit 55765bc

Please sign in to comment.