implement gunzipbase64 (#799)

Signed-off-by: Lars With <lars@with.de>
This commit is contained in:
l-with 2023-12-21 17:16:15 +01:00 committed by GitHub
parent b186fd3912
commit ae5ec54458
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 114 additions and 4 deletions

View File

@ -53,6 +53,10 @@ var DescriptionList = map[string]descriptionEntry{
Description: "`base64gzip` compresses a string with gzip and then encodes the result in Base64 encoding.",
ParamDescription: []string{""},
},
"gunzipbase64": {
Description: "`gunzipbase64` decodes a Base64-encoded string and uncompresses the result with gzip.",
ParamDescription: []string{""},
},
"base64sha256": {
Description: "`base64sha256` computes the SHA256 hash of a given string and encodes it with Base64. This is not equivalent to `base64encode(sha256(\"test\"))` since `sha256()` returns hexadecimal representation.",
ParamDescription: []string{""},

View File

@ -8,6 +8,7 @@ import (
"compress/gzip"
"encoding/base64"
"fmt"
"io"
"log"
"net/url"
"unicode/utf8"
@ -178,6 +179,37 @@ var Base64GzipFunc = function.New(&function.Spec{
},
})
// GunzipBase64Func constructs a function that Bae64 decodes a string and decompresses the result with gunzip.
var GunzipBase64Func = function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "str",
Type: cty.String,
},
},
Type: function.StaticReturnType(cty.String),
RefineResult: refineNotNull,
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
str, strMarks := args[0].Unmark()
s := str.AsString()
sDec, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return cty.UnknownVal(cty.String), fmt.Errorf("failed to decode base64 data %s", redactIfSensitive(s, strMarks))
}
sDecBuffer := bytes.NewReader(sDec)
gzipReader, err := gzip.NewReader(sDecBuffer)
if err != nil {
return cty.UnknownVal(cty.String), fmt.Errorf("failed to gunzip bytestream: %w", err)
}
gunzip, err := io.ReadAll(gzipReader)
if err != nil {
return cty.UnknownVal(cty.String), fmt.Errorf("failed to read gunzip raw data: %w", err)
}
return cty.StringVal(string(gunzip)), nil
},
})
// URLEncodeFunc constructs a function that applies URL encoding to a given string.
var URLEncodeFunc = function.New(&function.Spec{
Params: []function.Parameter{
@ -228,6 +260,13 @@ func Base64Gzip(str cty.Value) (cty.Value, error) {
return Base64GzipFunc.Call([]cty.Value{str})
}
// GunzipBase64 decodes a Base64-encoded string and uncompresses the result with gzip.
//
// Opentofu uses the "standard" Base64 alphabet as defined in RFC 4648 section 4.
func GunzipBase64(str cty.Value) (cty.Value, error) {
return GunzipBase64Func.Call([]cty.Value{str})
}
// URLEncode applies URL encoding to a given string.
//
// This function identifies characters in the given string that would have a

View File

@ -159,6 +159,39 @@ func TestBase64Gzip(t *testing.T) {
}
}
func TestGunzipBase64(t *testing.T) {
tests := []struct {
String cty.Value
Want cty.Value
Err bool
}{
{
cty.StringVal("H4sIAAAAAAAA/ypJLS4BAAAA//8BAAD//wx+f9gEAAAA"),
cty.StringVal("test"),
false,
},
}
for _, test := range tests {
t.Run(fmt.Sprintf("gunzipbase64(%#v)", test.String), func(t *testing.T) {
got, err := GunzipBase64(test.String)
if test.Err {
if err == nil {
t.Fatal("succeeded; want error")
}
return
} else if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if !got.RawEquals(test.Want) {
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
}
})
}
}
func TestURLEncode(t *testing.T) {
tests := []struct {
String cty.Value

View File

@ -43,6 +43,7 @@ func (s *Scope) Functions() map[string]function.Function {
"base64decode": funcs.Base64DecodeFunc,
"base64encode": funcs.Base64EncodeFunc,
"base64gzip": funcs.Base64GzipFunc,
"gunzipbase64": funcs.GunzipBase64Func,
"base64sha256": funcs.Base64Sha256Func,
"base64sha512": funcs.Base64Sha512Func,
"bcrypt": funcs.BcryptFunc,

View File

@ -108,6 +108,13 @@ func TestFunctions(t *testing.T) {
},
},
"gunzipbase64": {
{
`gunzipbase64("H4sIAAAAAAAA/ypJLS4BAAAA//8BAAD//wx+f9gEAAAA")`,
cty.StringVal("test"),
},
},
"base64sha256": {
{
`base64sha256("test")`,

View File

@ -517,6 +517,10 @@
"title": "<code>csvdecode</code>",
"path": "language/functions/csvdecode"
},
{
"title": "<code>gunzipbase64</code>",
"path": "language/functions/gunzipbase64"
},
{
"title": "<code>jsondecode</code>",
"path": "language/functions/jsondecode"
@ -758,13 +762,13 @@
"hidden": true
},
{
"title": "base64gzip",
"path": "language/functions/base64gzip",
"title": "base64sha256",
"path": "language/functions/base64sha256",
"hidden": true
},
{
"title": "base64sha256",
"path": "language/functions/base64sha256",
"title": "base64gzip",
"path": "language/functions/base64gzip",
"hidden": true
},
{
@ -927,6 +931,11 @@
"path": "language/functions/formatlist",
"hidden": true
},
{
"title": "gunzipbase64",
"path": "language/functions/gunzipbase64",
"hidden": true
},
{
"title": "indent",
"path": "language/functions/indent",

View File

@ -0,0 +1,17 @@
---
page_title: gunzipbase64 - Functions - Configuration Language
description: |-
The gunzipbase64 funtion decodes a Base64-encoded string and uncompresses the result with gzip.
---
# `gunzipbase64` Function
`gunzipbase64` decodes a Base64-encoded string and uncompresses the result with gzip.
Opentofu uses the "standard" Base64 alphabet as defined in
[RFC 4648 section 4](https://tools.ietf.org/html/rfc4648#section-4).
## Related Functions
* [`base64gzip`](/docs/language/functions/base64gzip) compresses a string with gzip and then encodes the result in
Base64 encoding.