Skip to content

Commit

Permalink
Merge pull request #13 from SyntaxNode/alignment-fix
Browse files Browse the repository at this point in the history
Handle GPP Base64 Quantum Quirks
  • Loading branch information
SyntaxNode authored Jan 22, 2024
2 parents 8cca024 + 8bebee2 commit 2cc0862
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 12 deletions.
30 changes: 20 additions & 10 deletions parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,17 @@ type gppTestData struct {

func TestParse(t *testing.T) {
testData := map[string]gppTestData{
"GPP-tcf": {
"gpp-tcf": {
description: "GPP string with EU TCF V2",
gppString: "DBABM~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA",
expected: GppContainer{
Version: 1,
SectionTypes: []constants.SectionID{2},
Sections: []Section{GenericSection{sectionID: 2,
value: "CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA"}},
},
},
"gpp-tcf-valid-quantum": { // header is valid base64 quantum, should gracefully decode correctly
description: "GPP string with EU TCF V2",
gppString: "DBABMA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA",
expected: GppContainer{
Expand All @@ -30,9 +40,9 @@ func TestParse(t *testing.T) {
value: "CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA"}},
},
},
"GPP-tcv-usp": {
"gpp-tcf-usp": {
description: "GPP string with EU TCF v2 and US Privacy",
gppString: "DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN",
gppString: "DBACNY~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN",
expected: GppContainer{
Version: 1,
SectionTypes: []constants.SectionID{2, 6},
Expand All @@ -42,7 +52,7 @@ func TestParse(t *testing.T) {
value: "1YNN"}},
},
},
"GPP-tcfca-usp": {
"gpp-tcfca-usp": {
description: "GPP string with Canadian TCF and US Privacy",
gppString: "DBABjw~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN",
expected: GppContainer{
Expand All @@ -54,7 +64,7 @@ func TestParse(t *testing.T) {
value: "1YNN"}},
},
},
"GPP-uspca": {
"gpp-uspca": {
description: "GPP string with USPCA",
gppString: "DBABBgA~xlgWEYCZAA",
expected: GppContainer{
Expand Down Expand Up @@ -88,7 +98,7 @@ func TestParse(t *testing.T) {
},
},
},
"GPP-uspva": {
"gpp-uspva": {
description: "GPP string with USPVA",
gppString: "DBABRgA~bSFgmiU",
expected: GppContainer{
Expand All @@ -115,9 +125,9 @@ func TestParse(t *testing.T) {
},
},
},
"GPP-tcf-error": {
"gpp-tcf-error": {
description: "GPP string with EU TCF V2",
gppString: "DBGBMA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA",
gppString: "DBGBM~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA",
expected: GppContainer{
Version: 1,
SectionTypes: []constants.SectionID{2},
Expand All @@ -126,10 +136,10 @@ func TestParse(t *testing.T) {
},
expectedError: []error{fmt.Errorf("error parsing GPP header, section identifiers: error reading an int offset value in a Range(Fibonacci) entry(1): error reading bit 4 of Integer(Fibonacci): expected 1 bit at bit 32, but the byte array was only 4 bytes long")},
},
"GPP-uspca-error": {
"gpp-uspca-error": {
description: "GPP string with USPCA",
gppString: "DBABBgA~xlgWE",
expectedError: []error{fmt.Errorf("error parsing uspca consent string: illegal base64 data at input byte 4")},
expectedError: []error{fmt.Errorf("error parsing uspca consent string: unable to set field CoreSegment.SensitiveDataProcessing due to parse error: expected 2 bits to start at bit 32, but the byte array was only 4 bytes long")},
},
}

Expand Down
16 changes: 14 additions & 2 deletions util/bitstream.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,30 @@ func NewBitStream(b []byte) *BitStream {
return &BitStream{p: 0, b: b}
}

// NewBitStreamFromBase64 creates a new bit stream object from a base64 encoded string
// NewBitStreamFromBase64 creates a new bit stream object from a base64-url encoded string
func NewBitStreamFromBase64(encoded string) (*BitStream, error) {
buff := []byte(encoded)
buff := []byte(padLastQuantum(encoded))
decoded := make([]byte, base64.RawURLEncoding.DecodedLen(len(buff)))
n, err := base64.RawURLEncoding.Decode(decoded, buff)
if err != nil {
return nil, err
}
decoded = decoded[:n:n]

return NewBitStream(decoded), nil
}

// padLastQuantum pads the last quantum with zeros if it's incomplete to
// ensure all bits are decoded using the standard base64 algorithm. The last
// bits would otherwise be truncated down to the closest byte.
func padLastQuantum(encoded string) string {
if (len(encoded) % 4) > 0 {
return encoded + "A" // pad with zeros
}

return encoded
}

// GetPosition reads out the position of the bit pointer in the bit stream
func (bs *BitStream) GetPosition() uint16 {
return bs.p
Expand Down

0 comments on commit 2cc0862

Please sign in to comment.