Skip to content

Commit

Permalink
refactor: Digest to make it event loop safe
Browse files Browse the repository at this point in the history
  • Loading branch information
olegbespalov committed Apr 17, 2024
1 parent 929a883 commit d3fa3aa
Showing 1 changed file with 44 additions and 29 deletions.
73 changes: 44 additions & 29 deletions webcrypto/subtle_crypto.go
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"errors"
"fmt"
"hash"

"github.com/dop251/goja"
"go.k6.io/k6/js/modules"
Expand Down Expand Up @@ -414,49 +415,63 @@ 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 := promises.New(sc.vu)
rt := sc.vu.Runtime()

// Validate that the value we received is either an ArrayBuffer, TypedArray, or DataView
// This uses the technique described in https://github.com/dop251/goja/issues/379#issuecomment-1164441879
if !IsInstanceOf(sc.vu.Runtime(), data, ArrayBufferConstructor, DataViewConstructor) &&
!IsTypedArray(sc.vu.Runtime(), data) {
reject(errors.New("data must be an ArrayBuffer, TypedArray, or DataView"))
return promise
}
var (
hashFn func() hash.Hash
bytes []byte
)

// 2.
bytes, err := exportArrayBuffer(rt, data)
if err != nil {
reject(err)
return promise
}
err := func() error {
var err error

// 3.
normalized, err := normalizeAlgorithm(rt, algorithm, OperationIdentifierDigest)
// Validate that the value we received is either an ArrayBuffer, TypedArray, or DataView
// This uses the technique described in https://github.com/dop251/goja/issues/379#issuecomment-1164441879
if !IsInstanceOf(sc.vu.Runtime(), data, ArrayBufferConstructor, DataViewConstructor) &&
!IsTypedArray(sc.vu.Runtime(), data) {
return errors.New("data must be an ArrayBuffer, TypedArray, or DataView")
}

bytes, err = exportArrayBuffer(rt, data)
if err != nil {
return err
}

normalized, err := normalizeAlgorithm(rt, algorithm, OperationIdentifierDigest)
if err != nil {
return err
}

var ok bool
hashFn, ok = getHashFn(normalized.Name)
if !ok {
return NewError(NotSupportedError, "unsupported algorithm: "+normalized.Name)
}

return nil
}()

promise, resolve, reject := rt.NewPromise()
if err != nil {
// "if an error occurred, return a Promise rejected with NormalizedAlgorithm"
reject(err)
return promise
}

// 6.
callback := sc.vu.RegisterCallback()
go func() {
// 6.
hashFn, ok := getHashFn(normalized.Name)
if !ok {
// 7.
reject(NewError(NotSupportedError, "unsupported algorithm: "+normalized.Name))
return
}

// 8.
hash := hashFn()
hash.Write(bytes)
digest := hash.Sum(nil)

// 9.
resolve(rt.NewArrayBuffer(digest))
callback(func() error {
if err != nil {
reject(err)
return nil //nolint:nilerr // we return nil to indicate that the error was handled
}

resolve(rt.NewArrayBuffer(digest))
return nil
})
}()

return promise
Expand Down

0 comments on commit d3fa3aa

Please sign in to comment.