mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-12 19:32:48 -06:00
builtins: Add StringOperandByteSlice helper
Many built-in functions immediatley convert an `ast.String` into `[]byte` which comes with some cost. This change introduces a `StringOperandByteSlice` function, which IMHO better helps communicate purpose, as well as it makes these operations a little cheaper. Nothing major here, but a small improvement. Also: - Cleaner `sync.Pool` helper module - Add benchmarks for YAML marshalling/unmarshalling Signed-off-by: Anders Eknert <anders@eknert.com>
This commit is contained in:
committed by
Stephan Renatus
parent
066ca43b74
commit
fd75706d7c
+49
-60
@@ -1,32 +1,63 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type termPtrPool struct {
|
||||
pool sync.Pool
|
||||
var (
|
||||
TermPtrPool = NewSyncPool[Term]()
|
||||
BytesReaderPool = NewSyncPool[bytes.Reader]()
|
||||
IndexResultPool = NewSyncPool[IndexResult]()
|
||||
// Needs custom pool because of custom Put logic.
|
||||
sbPool = &stringBuilderPool{
|
||||
pool: sync.Pool{
|
||||
New: func() any {
|
||||
return &strings.Builder{}
|
||||
},
|
||||
},
|
||||
}
|
||||
// Needs custom pool because of custom Put logic.
|
||||
varVisitorPool = &vvPool{
|
||||
pool: sync.Pool{
|
||||
New: func() any {
|
||||
return NewVarVisitor()
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
type (
|
||||
syncPool[T any] struct {
|
||||
pool sync.Pool
|
||||
}
|
||||
stringBuilderPool struct {
|
||||
pool sync.Pool
|
||||
}
|
||||
vvPool struct {
|
||||
pool sync.Pool
|
||||
}
|
||||
)
|
||||
|
||||
func NewSyncPool[T any]() *syncPool[T] {
|
||||
return &syncPool[T]{
|
||||
pool: sync.Pool{
|
||||
New: func() any {
|
||||
return new(T)
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type stringBuilderPool struct {
|
||||
pool sync.Pool
|
||||
func (p *syncPool[T]) Get() *T {
|
||||
return p.pool.Get().(*T)
|
||||
}
|
||||
|
||||
type indexResultPool struct {
|
||||
pool sync.Pool
|
||||
}
|
||||
|
||||
type vvPool struct {
|
||||
pool sync.Pool
|
||||
}
|
||||
|
||||
func (p *termPtrPool) Get() *Term {
|
||||
return p.pool.Get().(*Term)
|
||||
}
|
||||
|
||||
func (p *termPtrPool) Put(t *Term) {
|
||||
p.pool.Put(t)
|
||||
func (p *syncPool[T]) Put(x *T) {
|
||||
if x != nil {
|
||||
p.pool.Put(x)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *stringBuilderPool) Get() *strings.Builder {
|
||||
@@ -38,16 +69,6 @@ func (p *stringBuilderPool) Put(sb *strings.Builder) {
|
||||
p.pool.Put(sb)
|
||||
}
|
||||
|
||||
func (p *indexResultPool) Get() *IndexResult {
|
||||
return p.pool.Get().(*IndexResult)
|
||||
}
|
||||
|
||||
func (p *indexResultPool) Put(x *IndexResult) {
|
||||
if x != nil {
|
||||
p.pool.Put(x)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *vvPool) Get() *VarVisitor {
|
||||
return p.pool.Get().(*VarVisitor)
|
||||
}
|
||||
@@ -58,35 +79,3 @@ func (p *vvPool) Put(vv *VarVisitor) {
|
||||
p.pool.Put(vv)
|
||||
}
|
||||
}
|
||||
|
||||
var TermPtrPool = &termPtrPool{
|
||||
pool: sync.Pool{
|
||||
New: func() any {
|
||||
return &Term{}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var sbPool = &stringBuilderPool{
|
||||
pool: sync.Pool{
|
||||
New: func() any {
|
||||
return &strings.Builder{}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var varVisitorPool = &vvPool{
|
||||
pool: sync.Pool{
|
||||
New: func() any {
|
||||
return NewVarVisitor()
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var IndexResultPool = &indexResultPool{
|
||||
pool: sync.Pool{
|
||||
New: func() any {
|
||||
return &IndexResult{}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -209,8 +209,7 @@ func SetOperand(x ast.Value, pos int) (ast.Set, error) {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// StringOperand converts x to a string. If the cast fails, a descriptive error is
|
||||
// returned.
|
||||
// StringOperand returns x as [ast.String], or a descriptive error if the conversion fails.
|
||||
func StringOperand(x ast.Value, pos int) (ast.String, error) {
|
||||
s, ok := x.(ast.String)
|
||||
if !ok {
|
||||
@@ -219,6 +218,17 @@ func StringOperand(x ast.Value, pos int) (ast.String, error) {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// StringOperandByteSlice returns x a []byte, assuming x is [ast.String], or a descriptive error
|
||||
// if that is not the case. The returned byte slice points directly at the underlying array backing
|
||||
// the string, and should not be modified.
|
||||
func StringOperandByteSlice(x ast.Value, pos int) ([]byte, error) {
|
||||
s, err := StringOperand(x, pos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return util.StringToByteSlice(string(s)), nil
|
||||
}
|
||||
|
||||
// ObjectOperand converts x to an object. If the cast fails, a descriptive
|
||||
// error is returned.
|
||||
func ObjectOperand(x ast.Value, pos int) (ast.Object, error) {
|
||||
|
||||
+20
-48
@@ -255,17 +255,17 @@ func extractVerifyOpts(options ast.Object) (verifyOpt x509.VerifyOptions, err er
|
||||
}
|
||||
|
||||
func builtinCryptoX509ParseKeyPair(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
certificate, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
certificate, err := builtins.StringOperandByteSlice(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
key, err := builtins.StringOperand(operands[1].Value, 1)
|
||||
key, err := builtins.StringOperandByteSlice(operands[1].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certs, err := getTLSx509KeyPairFromString([]byte(certificate), []byte(key))
|
||||
certs, err := getTLSx509KeyPairFromString(certificate, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -326,10 +326,7 @@ func builtinCryptoX509ParseCertificateRequest(_ BuiltinContext, operands []*ast.
|
||||
}
|
||||
|
||||
func builtinCryptoJWKFromPrivateKey(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
var x any
|
||||
|
||||
a := operands[0].Value
|
||||
input, err := builtins.StringOperand(a, 1)
|
||||
input, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -371,6 +368,7 @@ func builtinCryptoJWKFromPrivateKey(_ BuiltinContext, operands []*ast.Term, iter
|
||||
return err
|
||||
}
|
||||
|
||||
var x any
|
||||
if err := util.UnmarshalJSON(jsonKey, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -430,53 +428,51 @@ func toHexEncodedString(src []byte) string {
|
||||
}
|
||||
|
||||
func builtinCryptoMd5(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
s, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
bs, err := builtins.StringOperandByteSlice(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
md5sum := md5.Sum([]byte(s))
|
||||
md5sum := md5.Sum(bs)
|
||||
|
||||
return iter(ast.StringTerm(toHexEncodedString(md5sum[:])))
|
||||
}
|
||||
|
||||
func builtinCryptoSha1(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
s, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
bs, err := builtins.StringOperandByteSlice(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sha1sum := sha1.Sum([]byte(s))
|
||||
sha1sum := sha1.Sum(bs)
|
||||
|
||||
return iter(ast.StringTerm(toHexEncodedString(sha1sum[:])))
|
||||
}
|
||||
|
||||
func builtinCryptoSha256(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
s, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
bs, err := builtins.StringOperandByteSlice(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sha256sum := sha256.Sum256([]byte(s))
|
||||
sha256sum := sha256.Sum256(bs)
|
||||
|
||||
return iter(ast.StringTerm(toHexEncodedString(sha256sum[:])))
|
||||
}
|
||||
|
||||
func hmacHelper(operands []*ast.Term, iter func(*ast.Term) error, h func() hash.Hash) error {
|
||||
a1 := operands[0].Value
|
||||
message, err := builtins.StringOperand(a1, 1)
|
||||
message, err := builtins.StringOperandByteSlice(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a2 := operands[1].Value
|
||||
key, err := builtins.StringOperand(a2, 2)
|
||||
key, err := builtins.StringOperandByteSlice(operands[1].Value, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mac := hmac.New(h, []byte(key))
|
||||
mac.Write([]byte(message))
|
||||
mac := hmac.New(h, key)
|
||||
mac.Write(message)
|
||||
messageDigest := mac.Sum(nil)
|
||||
|
||||
return iter(ast.StringTerm(hex.EncodeToString(messageDigest)))
|
||||
@@ -499,21 +495,17 @@ func builtinCryptoHmacSha512(_ BuiltinContext, operands []*ast.Term, iter func(*
|
||||
}
|
||||
|
||||
func builtinCryptoHmacEqual(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
a1 := operands[0].Value
|
||||
mac1, err := builtins.StringOperand(a1, 1)
|
||||
mac1, err := builtins.StringOperandByteSlice(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a2 := operands[1].Value
|
||||
mac2, err := builtins.StringOperand(a2, 2)
|
||||
mac2, err := builtins.StringOperandByteSlice(operands[1].Value, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res := hmac.Equal([]byte(mac1), []byte(mac2))
|
||||
|
||||
return iter(ast.InternedTerm(res))
|
||||
return iter(ast.InternedTerm(hmac.Equal(mac1, mac2)))
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -668,7 +660,7 @@ func addCACertsFromFile(pool *x509.CertPool, filePath string) (*x509.CertPool, e
|
||||
pool = x509.NewCertPool()
|
||||
}
|
||||
|
||||
caCert, err := readCertFromFile(filePath)
|
||||
caCert, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -703,17 +695,7 @@ func addCACertsFromEnv(pool *x509.CertPool, envName string) (*x509.CertPool, err
|
||||
return nil, fmt.Errorf("could not add CA certificates from envvar %q: %w", envName, err)
|
||||
}
|
||||
|
||||
return pool, err
|
||||
}
|
||||
|
||||
// ReadCertFromFile reads a cert from file
|
||||
func readCertFromFile(localCertFile string) ([]byte, error) {
|
||||
// Read in the cert file
|
||||
certPEM, err := os.ReadFile(localCertFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return certPEM, nil
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
var beginPrefix = []byte("-----BEGIN ")
|
||||
@@ -771,13 +753,3 @@ func getTLSx509KeyPairFromString(certPemBlock []byte, keyPemBlock []byte) (*tls.
|
||||
|
||||
return &cert, nil
|
||||
}
|
||||
|
||||
// ReadKeyFromFile reads a key from file
|
||||
func readKeyFromFile(localKeyFile string) ([]byte, error) {
|
||||
// Read in the cert file
|
||||
key, err := os.ReadFile(localKeyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
+29
-41
@@ -5,7 +5,6 @@
|
||||
package topdown
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
@@ -21,7 +20,6 @@ import (
|
||||
)
|
||||
|
||||
func builtinJSONMarshal(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
|
||||
asJSON, err := ast.JSON(operands[0].Value)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -32,11 +30,10 @@ func builtinJSONMarshal(_ BuiltinContext, operands []*ast.Term, iter func(*ast.T
|
||||
return err
|
||||
}
|
||||
|
||||
return iter(ast.StringTerm(string(bs)))
|
||||
return iter(ast.StringTerm(util.ByteSliceToString(bs)))
|
||||
}
|
||||
|
||||
func builtinJSONMarshalWithOpts(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
|
||||
asJSON, err := ast.JSON(operands[0].Value)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -101,36 +98,34 @@ func builtinJSONMarshalWithOpts(_ BuiltinContext, operands []*ast.Term, iter fun
|
||||
}
|
||||
|
||||
var bs []byte
|
||||
|
||||
if shouldPrettyPrint {
|
||||
bs, err = json.MarshalIndent(asJSON, prefixWith, indentWith)
|
||||
} else {
|
||||
bs, err = json.Marshal(asJSON)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s := util.ByteSliceToString(bs)
|
||||
|
||||
if shouldPrettyPrint {
|
||||
// json.MarshalIndent() function will not prefix the first line of emitted JSON
|
||||
return iter(ast.StringTerm(prefixWith + string(bs)))
|
||||
return iter(ast.StringTerm(prefixWith + s))
|
||||
}
|
||||
|
||||
return iter(ast.StringTerm(string(bs)))
|
||||
return iter(ast.StringTerm(s))
|
||||
|
||||
}
|
||||
|
||||
func builtinJSONUnmarshal(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
|
||||
str, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
bs, err := builtins.StringOperandByteSlice(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var x any
|
||||
|
||||
if err := util.UnmarshalJSON([]byte(str), &x); err != nil {
|
||||
if err := util.UnmarshalJSON(bs, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
v, err := ast.InterfaceToValue(x)
|
||||
@@ -141,22 +136,21 @@ func builtinJSONUnmarshal(_ BuiltinContext, operands []*ast.Term, iter func(*ast
|
||||
}
|
||||
|
||||
func builtinJSONIsValid(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
|
||||
str, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
bs, err := builtins.StringOperandByteSlice(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return iter(ast.InternedTerm(false))
|
||||
}
|
||||
|
||||
return iter(ast.InternedTerm(json.Valid([]byte(str))))
|
||||
return iter(ast.InternedTerm(json.Valid(bs)))
|
||||
}
|
||||
|
||||
func builtinBase64Encode(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
str, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
bs, err := builtins.StringOperandByteSlice(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return iter(ast.StringTerm(base64.StdEncoding.EncodeToString([]byte(str))))
|
||||
return iter(ast.StringTerm(base64.StdEncoding.EncodeToString(bs)))
|
||||
}
|
||||
|
||||
func builtinBase64Decode(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
@@ -183,20 +177,20 @@ func builtinBase64IsValid(_ BuiltinContext, operands []*ast.Term, iter func(*ast
|
||||
}
|
||||
|
||||
func builtinBase64UrlEncode(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
str, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
bs, err := builtins.StringOperandByteSlice(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return iter(ast.StringTerm(base64.URLEncoding.EncodeToString([]byte(str))))
|
||||
return iter(ast.StringTerm(base64.URLEncoding.EncodeToString(bs)))
|
||||
}
|
||||
|
||||
func builtinBase64UrlEncodeNoPad(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
str, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
bs, err := builtins.StringOperandByteSlice(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return iter(ast.StringTerm(base64.RawURLEncoding.EncodeToString([]byte(str))))
|
||||
return iter(ast.StringTerm(base64.RawURLEncoding.EncodeToString(bs)))
|
||||
}
|
||||
|
||||
func builtinBase64UrlDecode(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
@@ -306,45 +300,39 @@ func builtinURLQueryDecodeObject(_ BuiltinContext, operands []*ast.Term, iter fu
|
||||
}
|
||||
|
||||
func builtinYAMLMarshal(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
|
||||
asJSON, err := ast.JSON(operands[0].Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
encoder := json.NewEncoder(&buf)
|
||||
if err := encoder.Encode(asJSON); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bs, err := yaml.JSONToYAML(buf.Bytes())
|
||||
bs, err := yaml.Marshal(asJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return iter(ast.StringTerm(string(bs)))
|
||||
return iter(ast.StringTerm(util.ByteSliceToString(bs)))
|
||||
}
|
||||
|
||||
func builtinYAMLUnmarshal(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
|
||||
str, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
bs, err := builtins.StringOperandByteSlice(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bs, err := yaml.YAMLToJSON([]byte(str))
|
||||
js, err := yaml.YAMLToJSON(bs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(bs)
|
||||
decoder := util.NewJSONDecoder(buf)
|
||||
reader := ast.BytesReaderPool.Get()
|
||||
defer ast.BytesReaderPool.Put(reader)
|
||||
reader.Reset(js)
|
||||
|
||||
var val any
|
||||
err = decoder.Decode(&val)
|
||||
if err != nil {
|
||||
if err = util.NewJSONDecoder(reader).Decode(&val); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v, err := ast.InterfaceToValue(val)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -353,22 +341,22 @@ func builtinYAMLUnmarshal(_ BuiltinContext, operands []*ast.Term, iter func(*ast
|
||||
}
|
||||
|
||||
func builtinYAMLIsValid(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
str, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
bs, err := builtins.StringOperandByteSlice(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return iter(ast.InternedTerm(false))
|
||||
}
|
||||
|
||||
var x any
|
||||
err = yaml.Unmarshal([]byte(str), &x)
|
||||
err = yaml.Unmarshal(bs, &x)
|
||||
return iter(ast.InternedTerm(err == nil))
|
||||
}
|
||||
|
||||
func builtinHexEncode(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
str, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
bs, err := builtins.StringOperandByteSlice(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return iter(ast.StringTerm(hex.EncodeToString([]byte(str))))
|
||||
return iter(ast.StringTerm(hex.EncodeToString(bs)))
|
||||
}
|
||||
|
||||
func builtinHexDecode(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package topdown
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
var (
|
||||
unmarshalled = ast.ObjectTerm(
|
||||
ast.Item(ast.InternedTerm("foo"), ast.ObjectTerm(
|
||||
ast.Item(ast.InternedTerm("bar"), ast.ArrayTerm(ast.InternedTerm("baz"), ast.InternedTerm("qux"))),
|
||||
ast.Item(ast.InternedTerm("num"), ast.InternedTerm(42)),
|
||||
)),
|
||||
)
|
||||
marshalled = `foo:
|
||||
bar:
|
||||
- baz
|
||||
- qux
|
||||
num: 42
|
||||
`
|
||||
)
|
||||
|
||||
// 7447 ns/op 22984 B/op 142 allocs/op
|
||||
// 7343 ns/op 22872 B/op 140 allocs/op
|
||||
func BenchmarkYAMLMarshal(b *testing.B) {
|
||||
expect := ast.InternedTerm(marshalled)
|
||||
operands := []*ast.Term{unmarshalled}
|
||||
iter := eqIter(expect)
|
||||
|
||||
for b.Loop() {
|
||||
if err := builtinYAMLMarshal(BuiltinContext{}, operands, iter); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5393 ns/op 11066 B/op 146 allocs/op
|
||||
// 5210 ns/op 10980 B/op 144 allocs/op
|
||||
func BenchmarkYAMLUnmarshal(b *testing.B) {
|
||||
operands := []*ast.Term{ast.InternedTerm(marshalled)}
|
||||
iter := eqIter(unmarshalled)
|
||||
|
||||
for b.Loop() {
|
||||
if err := builtinYAMLUnmarshal(BuiltinContext{}, operands, iter); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2440,13 +2440,13 @@ func TestHTTPSClient(t *testing.T) {
|
||||
}
|
||||
|
||||
// Set up Environment
|
||||
clientCert, err := readCertFromFile(localClientCertFile)
|
||||
clientCert, err := os.ReadFile(localClientCertFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv("CLIENT_CERT_ENV", string(clientCert))
|
||||
|
||||
clientKey, err := readKeyFromFile(localClientKeyFile)
|
||||
clientKey, err := os.ReadFile(localClientKeyFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
+6
-10
@@ -7,6 +7,7 @@ package topdown
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"regexp/syntax"
|
||||
"sync"
|
||||
|
||||
gintersect "github.com/yashtewari/glob-intersection"
|
||||
@@ -22,18 +23,13 @@ var regexpCacheLock = sync.Mutex{}
|
||||
var regexpCache map[string]*regexp.Regexp
|
||||
|
||||
func builtinRegexIsValid(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
|
||||
s, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return iter(ast.InternedTerm(false))
|
||||
if s, err := builtins.StringOperand(operands[0].Value, 1); err == nil {
|
||||
if _, err = syntax.Parse(string(s), syntax.Perl); err == nil {
|
||||
return iter(ast.InternedTerm(true))
|
||||
}
|
||||
}
|
||||
|
||||
_, err = regexp.Compile(string(s))
|
||||
if err != nil {
|
||||
return iter(ast.InternedTerm(false))
|
||||
}
|
||||
|
||||
return iter(ast.InternedTerm(true))
|
||||
return iter(ast.InternedTerm(false))
|
||||
}
|
||||
|
||||
func builtinRegexMatch(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
|
||||
+14
-14
@@ -428,7 +428,7 @@ func builtinJWTVerify(bctx BuiltinContext, jwt ast.Value, keyStr ast.Value, hash
|
||||
// If a match is found, verify using only that key. Only applicable when a JWKS was provided.
|
||||
if header.kid != "" {
|
||||
if key := getKeyByKid(header.kid, keys); key != nil {
|
||||
err = verify(key.key, getInputSHA([]byte(token.header+"."+token.payload), hasher), []byte(signature))
|
||||
err = verify(key.key, getInputSHA([]byte(token.header+"."+token.payload), hasher), signature)
|
||||
|
||||
return done(err == nil)
|
||||
}
|
||||
@@ -440,7 +440,7 @@ func builtinJWTVerify(bctx BuiltinContext, jwt ast.Value, keyStr ast.Value, hash
|
||||
if key.alg == "" {
|
||||
// No algorithm provided for the key - this is likely a certificate and not a JWKS, so
|
||||
// we'll need to verify to find out
|
||||
err = verify(key.key, getInputSHA([]byte(token.header+"."+token.payload), hasher), []byte(signature))
|
||||
err = verify(key.key, getInputSHA([]byte(token.header+"."+token.payload), hasher), signature)
|
||||
if err == nil {
|
||||
return done(true)
|
||||
}
|
||||
@@ -448,7 +448,7 @@ func builtinJWTVerify(bctx BuiltinContext, jwt ast.Value, keyStr ast.Value, hash
|
||||
if header.alg != key.alg {
|
||||
continue
|
||||
}
|
||||
err = verify(key.key, getInputSHA([]byte(token.header+"."+token.payload), hasher), []byte(signature))
|
||||
err = verify(key.key, getInputSHA([]byte(token.header+"."+token.payload), hasher), signature)
|
||||
if err == nil {
|
||||
return done(true)
|
||||
}
|
||||
@@ -509,7 +509,7 @@ func builtinJWTVerifyHS(bctx BuiltinContext, operands []*ast.Term, hashF func()
|
||||
return err
|
||||
}
|
||||
|
||||
valid := hmac.Equal([]byte(signature), mac.Sum(nil))
|
||||
valid := hmac.Equal(signature, mac.Sum(nil))
|
||||
|
||||
putTokenInCache(bctx, jwt, astSecret, nil, nil, valid)
|
||||
|
||||
@@ -662,7 +662,7 @@ func (constraints *tokenConstraints) validate() error {
|
||||
}
|
||||
|
||||
// verify verifies a JWT using the constraints and the algorithm from the header
|
||||
func (constraints *tokenConstraints) verify(kid, alg, header, payload, signature string) error {
|
||||
func (constraints *tokenConstraints) verify(kid, alg, header, payload string, signature []byte) error {
|
||||
// Construct the payload
|
||||
plaintext := append(append([]byte(header), '.'), []byte(payload)...)
|
||||
|
||||
@@ -670,7 +670,7 @@ func (constraints *tokenConstraints) verify(kid, alg, header, payload, signature
|
||||
if constraints.keys != nil {
|
||||
if kid != "" {
|
||||
if key := getKeyByKid(kid, constraints.keys); key != nil {
|
||||
err := jwsbb.Verify(key.key, alg, plaintext, []byte(signature))
|
||||
err := jwsbb.Verify(key.key, alg, plaintext, signature)
|
||||
if err != nil {
|
||||
return errSignatureNotVerified
|
||||
}
|
||||
@@ -681,7 +681,7 @@ func (constraints *tokenConstraints) verify(kid, alg, header, payload, signature
|
||||
verified := false
|
||||
for _, key := range constraints.keys {
|
||||
if key.alg == "" {
|
||||
err := jwsbb.Verify(key.key, alg, plaintext, []byte(signature))
|
||||
err := jwsbb.Verify(key.key, alg, plaintext, signature)
|
||||
if err == nil {
|
||||
verified = true
|
||||
break
|
||||
@@ -690,7 +690,7 @@ func (constraints *tokenConstraints) verify(kid, alg, header, payload, signature
|
||||
if alg != key.alg {
|
||||
continue
|
||||
}
|
||||
err := jwsbb.Verify(key.key, alg, plaintext, []byte(signature))
|
||||
err := jwsbb.Verify(key.key, alg, plaintext, signature)
|
||||
if err == nil {
|
||||
verified = true
|
||||
break
|
||||
@@ -704,7 +704,7 @@ func (constraints *tokenConstraints) verify(kid, alg, header, payload, signature
|
||||
return nil
|
||||
}
|
||||
if constraints.secret != "" {
|
||||
err := jwsbb.Verify([]byte(constraints.secret), alg, plaintext, []byte(signature))
|
||||
err := jwsbb.Verify([]byte(constraints.secret), alg, plaintext, signature)
|
||||
if err != nil {
|
||||
return errSignatureNotVerified
|
||||
}
|
||||
@@ -1170,17 +1170,17 @@ func decodeJWT(a ast.Value) (*JSONWebToken, error) {
|
||||
return &JSONWebToken{header: parts[0], payload: parts[1], signature: parts[2]}, nil
|
||||
}
|
||||
|
||||
func (token *JSONWebToken) decodeSignature() (string, error) {
|
||||
func (token *JSONWebToken) decodeSignature() ([]byte, error) {
|
||||
decodedSignature, err := getResult(builtinBase64UrlDecode, ast.StringTerm(token.signature))
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
signatureAst, err := builtins.StringOperand(decodedSignature.Value, 1)
|
||||
signatureBs, err := builtins.StringOperandByteSlice(decodedSignature.Value, 1)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
return string(signatureAst), err
|
||||
return signatureBs, nil
|
||||
}
|
||||
|
||||
// Extract, validate and return the JWT header as an ast.Object.
|
||||
|
||||
Reference in New Issue
Block a user