Skip to content

Commit

Permalink
Merge pull request #60 from grafana/refactor/improve
Browse files Browse the repository at this point in the history
Leverage some of the k6 APIs to handle Javascript operations
  • Loading branch information
oleiade authored Jan 22, 2024
2 parents 82b9c8e + 334e146 commit d9b36bb
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 42 deletions.
40 changes: 6 additions & 34 deletions webcrypto/goja.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import (
"strings"

"github.com/dop251/goja"
"go.k6.io/k6/js/common"
)

// exportArrayBuffer interprets the given value as an ArrayBuffer, TypedArray or DataView
// and returns a copy of the underlying byte slice.
func exportArrayBuffer(rt *goja.Runtime, v goja.Value) ([]byte, error) {
if isNullish(v) {
if common.IsNullish(v) {
return nil, NewError(TypeError, "data is null or undefined")
}

Expand Down Expand Up @@ -45,26 +46,26 @@ func exportArrayBuffer(rt *goja.Runtime, v goja.Value) ([]byte, error) {
// traverseObject traverses the given object using the given fields and returns the value
// at the end of the traversal. It assumes that all the traversed fields are Objects.
func traverseObject(rt *goja.Runtime, src goja.Value, fields ...string) (goja.Value, error) {
if isNullish(src) {
if common.IsNullish(src) {
return nil, NewError(TypeError, "Object is null or undefined")
}

obj := src.ToObject(rt)
if isNullish(obj) {
if common.IsNullish(obj) {
return nil, NewError(TypeError, "Object is null or undefined")
}

for idx, field := range fields {
src = obj.Get(field)
if isNullish(src) {
if common.IsNullish(src) {
return nil, NewError(
TypeError,
fmt.Sprintf("field %s is null or undefined", strings.Join(fields[:idx+1], ".")),
)
}

obj = src.ToObject(rt)
if isNullish(obj) {
if common.IsNullish(obj) {
return nil, NewError(
TypeError,
fmt.Sprintf("field %s is not an Object", strings.Join(fields[:idx+1], ".")),
Expand Down Expand Up @@ -154,32 +155,3 @@ const (
// BigUint64ArrayConstructor is the name of the BigUint64ArrayConstructor constructor
BigUint64ArrayConstructor = "BigUint64Array"
)

// IsNullish checks if the given value is nullish, i.e. nil, undefined or null.
// FIXME @oleiade: this declaration can be removed once the k6 version including it is released
func isNullish(v goja.Value) bool {
return v == nil || goja.IsUndefined(v) || goja.IsNull(v)
}

// makeHandledPromise will create a promise and return its resolve and reject methods,
// wrapped in such a way that it will block the eventloop from exiting before they are
// called even if the promise isn't resolved by the time the current script ends executing.
func (sc *SubtleCrypto) makeHandledPromise() (*goja.Promise, func(interface{}), func(interface{})) {
runtime := sc.vu.Runtime()
callback := sc.vu.RegisterCallback()
p, resolve, reject := runtime.NewPromise()

return p, func(i interface{}) {
// more stuff
callback(func() error {
resolve(i)
return nil
})
}, func(i interface{}) {
// more stuff
callback(func() error {
reject(i)
return nil
})
}
}
17 changes: 9 additions & 8 deletions webcrypto/subtle_crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/dop251/goja"
"go.k6.io/k6/js/modules"
"go.k6.io/k6/js/promises"
)

// FIXME: SubtleCrypto is described as an "interface", should it be a nested module
Expand Down Expand Up @@ -37,7 +38,7 @@ type SubtleCrypto struct {
// The `data` parameter should contain the data to be encryption.
func (sc *SubtleCrypto) Encrypt(algorithm, key, data goja.Value) *goja.Promise {
rt := sc.vu.Runtime()
promise, resolve, reject := sc.makeHandledPromise()
promise, resolve, reject := promises.New(sc.vu)

// 2.
// We obtain a copy of the key data, because we might need to modify it.
Expand Down Expand Up @@ -129,7 +130,7 @@ func (sc *SubtleCrypto) Encrypt(algorithm, key, data goja.Value) *goja.Promise {
// The `data` parameter should contain the data to be decrypted.
func (sc *SubtleCrypto) Decrypt(algorithm, key, data goja.Value) *goja.Promise {
rt := sc.vu.Runtime()
promise, resolve, reject := sc.makeHandledPromise()
promise, resolve, reject := promises.New(sc.vu)

// 2.
// We obtain a copy of the key data, because we might need to modify it.
Expand Down Expand Up @@ -219,7 +220,7 @@ func (sc *SubtleCrypto) Decrypt(algorithm, key, data goja.Value) *goja.Promise {
// The `data` parameter should contain the data to be signed.
func (sc *SubtleCrypto) Sign(algorithm, key, data goja.Value) *goja.Promise {
rt := sc.vu.Runtime()
promise, resolve, reject := sc.makeHandledPromise()
promise, resolve, reject := promises.New(sc.vu)

// 2.
// We obtain a copy of the key data, because we might need to modify it.
Expand Down Expand Up @@ -322,7 +323,7 @@ func (sc *SubtleCrypto) Sign(algorithm, key, data goja.Value) *goja.Promise {
// The `data` parameter should contain the original signed data.
func (sc *SubtleCrypto) Verify(algorithm, key, signature, data goja.Value) *goja.Promise {
rt := sc.vu.Runtime()
promise, resolve, reject := sc.makeHandledPromise()
promise, resolve, reject := promises.New(sc.vu)

// 2.
signatureData, err := exportArrayBuffer(sc.vu.Runtime(), signature)
Expand Down Expand Up @@ -421,7 +422,7 @@ func (sc *SubtleCrypto) Verify(algorithm, key, signature, data goja.Value) *goja
//
// The `data` parameter should contain the data to be digested.
func (sc *SubtleCrypto) Digest(algorithm goja.Value, data goja.Value) *goja.Promise {
promise, resolve, reject := sc.makeHandledPromise()
promise, resolve, reject := promises.New(sc.vu)
rt := sc.vu.Runtime()

// Validate that the value we received is either an ArrayBuffer, TypedArray, or DataView
Expand Down Expand Up @@ -488,7 +489,7 @@ func (sc *SubtleCrypto) Digest(algorithm goja.Value, data goja.Value) *goja.Prom
//
// The `keyUsages` parameter is an array of strings indicating what the key can be used for.
func (sc *SubtleCrypto) GenerateKey(algorithm goja.Value, extractable bool, keyUsages []CryptoKeyUsage) *goja.Promise {
promise, resolve, reject := sc.makeHandledPromise()
promise, resolve, reject := promises.New(sc.vu)

normalized, err := normalizeAlgorithm(sc.vu.Runtime(), algorithm, OperationIdentifierGenerateKey)
if err != nil {
Expand Down Expand Up @@ -630,7 +631,7 @@ func (sc *SubtleCrypto) ImportKey(
keyUsages []CryptoKeyUsage,
) *goja.Promise {
rt := sc.vu.Runtime()
promise, resolve, reject := sc.makeHandledPromise()
promise, resolve, reject := promises.New(sc.vu)

// 2.
ab, err := exportArrayBuffer(rt, keyData)
Expand Down Expand Up @@ -703,7 +704,7 @@ func (sc *SubtleCrypto) ImportKey(
// TODO @oleiade: implement support for JWK format
func (sc *SubtleCrypto) ExportKey(format KeyFormat, key goja.Value) *goja.Promise {
rt := sc.vu.Runtime()
promise, resolve, reject := sc.makeHandledPromise()
promise, resolve, reject := promises.New(sc.vu)

var algorithm Algorithm
algValue := key.ToObject(rt).Get("algorithm")
Expand Down

0 comments on commit d9b36bb

Please sign in to comment.