Skip to content

Commit

Permalink
feat: Added library versions of Base64Gunzip, CidrContains, and URLDe…
Browse files Browse the repository at this point in the history
…code. (#381)
  • Loading branch information
skyzyx authored Nov 10, 2024
1 parent 1985a17 commit 3a05e6b
Show file tree
Hide file tree
Showing 5 changed files with 261 additions and 19 deletions.
80 changes: 80 additions & 0 deletions corefunc/base64gunzip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2023-2024, Northwood Labs
// Copyright 2023-2024, Ryan Parman <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package corefunc

import (
"bytes"
"compress/gzip"
"encoding/base64"
"fmt"
"io"
"strings"
)

/*
Base64Gunzip is a function that decodes a Base64-encoded string, then
decompresses the result with gzip. Supports both padded and non-padded Base64
strings.
This functionality is built into OpenTofu 1.8, but is missing in Terraform 1.9.
This also provides a 1:1 implementation that can be used with Terratest or other
Go code.
----
- input (string): A string of gzipped then Base64-encoded data.
*/
func Base64Gunzip(input string) (string, error) {
const maxDecodedLen = 10485760 // 10 MiB

encoder := base64.StdEncoding.WithPadding(base64.NoPadding)

if strings.HasSuffix(input, "=") {
encoder = base64.StdEncoding
}

decodedLen := encoder.DecodedLen(len(input))
decodedBytes := make([]byte, decodedLen)

n, err := encoder.Decode(decodedBytes, []byte(input))
if err != nil {
return "", fmt.Errorf("failed to Base64-decode the data: %w", err)
}

decodedBytes = decodedBytes[:n]
decodedBytesBuf := bytes.NewReader(decodedBytes)

unzippedReader, err := gzip.NewReader(decodedBytesBuf)
if err != nil {
return "", fmt.Errorf("failed to decompress the gzipped data: %w", err)
}

var unzippedBytes bytes.Buffer

limitedReader := io.LimitReader(unzippedReader, maxDecodedLen)

_, err = io.Copy(&unzippedBytes, limitedReader)
if err != nil {
return "", fmt.Errorf("failed to read the decompressed gzipped data: %w", err)
}

err = unzippedReader.Close()
if err != nil {
return "", fmt.Errorf("failed to close the decompressed gzipped data: %w", err)
}

return unzippedBytes.String(), nil
}
101 changes: 101 additions & 0 deletions corefunc/base64gunzip_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2023-2024, Northwood Labs
// Copyright 2023-2024, Ryan Parman <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package corefunc

import (
"fmt"
"testing"

"github.com/northwood-labs/terraform-provider-corefunc/testfixtures"
)

func ExampleBase64Gunzip() {
output, err := Base64Gunzip(
"H4sIAAAAAAAA/wrJSFXIL0jNUyjOLy1KTlXIzEsrSiwuKSpNLiktSlVILFZIzk9JVSjJz8/RAwQAAP//HPstqCwAAAA",
)
if err != nil {
panic(err)
}

fmt.Println(output)

// Output:
// The open source infrastructure as code tool.
}

func TestBase64Gunzip(t *testing.T) {
for name, tc := range testfixtures.Base64GunzipTestTable {
t.Run(name, func(t *testing.T) {
got, err := Base64Gunzip(tc.Input)
if err != nil && tc.ExpectError != nil {
if !tc.ExpectError.MatchString(err.Error()) {
t.Errorf("Base64Gunzip() error = %v, want match %v", err, tc.ExpectError)
}

return
} else if err != nil {
t.Errorf("Base64Gunzip() error = %v", err)

return
}

if got != tc.Expected {
t.Errorf("Base64Gunzip() = %v, want %v", got, tc.Expected)
}
})
}
}

func BenchmarkBase64Gunzip(b *testing.B) {
b.ReportAllocs()

for name, tc := range testfixtures.Base64GunzipTestTable {
b.Run(name, func(b *testing.B) {
b.ResetTimer()

for i := 0; i < b.N; i++ {
_, _ = Base64Gunzip(tc.Input) // lint:allow_unhandled
}
})
}
}

func BenchmarkBase64GunzipParallel(b *testing.B) {
b.ReportAllocs()

for name, tc := range testfixtures.Base64GunzipTestTable {
b.Run(name, func(b *testing.B) {
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, _ = Base64Gunzip(tc.Input) // lint:allow_unhandled
}
})
})
}
}

func FuzzBase64Gunzip(f *testing.F) {
for _, tc := range testfixtures.Base64GunzipTestTable {
f.Add(tc.Input)
}

f.Fuzz(
func(t *testing.T, input string) {
_, _ = Base64Gunzip(input) // lint:allow_unhandled
},
)
}
48 changes: 48 additions & 0 deletions testfixtures/base64gunzip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2023-2024, Northwood Labs
// Copyright 2023-2024, Ryan Parman <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package testfixtures // lint:no_dupe

import "regexp"

// Base64GunzipTestTable is used by both the standard Go tests and also the
// Terraform acceptance tests.
// <https://github.com/golang/go/wiki/TableDrivenTests>
var Base64GunzipTestTable = map[string]struct {
ExpectError *regexp.Regexp
Input string
Expected string
}{
"test": {
Input: "H4sIAAAAAAAA/ypJLS4BAAAA//8BAAD//wx+f9gEAAAA",
Expected: "test",
},
"hey hey, we're the monkees": {
Input: "H4sIAAAAAAAA/8pIrVTISK3UUShPVS9KVSjJSFXIzc/LTk0tBgQAAP//qz+dmhoAAAA=",
Expected: "hey hey, we're the monkees",
},
"hey hey, we're the monkees (no padding)": {
Input: "H4sIAAAAAAAA/8pIrVTISK3UUShPVS9KVSjJSFXIzc/LTk0tBgQAAP//qz+dmhoAAAA",
Expected: "hey hey, we're the monkees",
},
"The open source infrastructure as code tool.": {
Input: "H4sIAAAAAAAA/wrJSFXIL0jNUyjOLy1KTlXIzEsrSiwuKSpNLiktSlVILFZIzk9JVSjJz8/RAwQAAP//HPstqCwAAAA=",
Expected: "The open source infrastructure as code tool.",
},
"The open source infrastructure as code tool. (no padding)": {
Input: "H4sIAAAAAAAA/wrJSFXIL0jNUyjOLy1KTlXIzEsrSiwuKSpNLiktSlVILFZIzk9JVSjJz8/RAwQAAP//HPstqCwAAAA",
Expected: "The open source infrastructure as code tool.",
},
}
Binary file modified unit-coverage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
51 changes: 32 additions & 19 deletions unit-coverage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 3a05e6b

Please sign in to comment.