Skip to content

Commit

Permalink
refactor: ExportKey to make it event loop safe
Browse files Browse the repository at this point in the history
  • Loading branch information
olegbespalov committed Apr 18, 2024
1 parent 58424ca commit b241d21
Showing 1 changed file with 61 additions and 56 deletions.
117 changes: 61 additions & 56 deletions webcrypto/subtle_crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/dop251/goja"
"go.k6.io/k6/js/common"
"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 @@ -826,83 +825,89 @@ func (sc *SubtleCrypto) ImportKey( //nolint:funlen // we have a lot of error han
//
// The `format` parameter identifies the format of the key data.
// The `key` parameter is the key to export, as a CryptoKey object.
func (sc *SubtleCrypto) ExportKey(format KeyFormat, key goja.Value) *goja.Promise {
func (sc *SubtleCrypto) ExportKey( //nolint:funlen // we have a lot of error handling
format KeyFormat,
key goja.Value,
) *goja.Promise {
rt := sc.vu.Runtime()
promise, resolve, reject := promises.New(sc.vu)

var algorithm Algorithm
algValue := key.ToObject(rt).Get("algorithm")
if err := rt.ExportTo(algValue, &algorithm); err != nil {
reject(NewError(SyntaxError, "key is not a valid CryptoKey"))
return promise
}
var (
ck *CryptoKey
keyExporter func(*CryptoKey, KeyFormat) (interface{}, error)
)

ck, ok := key.Export().(*CryptoKey)
if !ok {
reject(NewError(ImplementationError, "unable to extract CryptoKey"))
return promise
}
err := func() error {
var algorithm Algorithm
algValue := key.ToObject(rt).Get("algorithm")
if err := rt.ExportTo(algValue, &algorithm); err != nil {
return NewError(SyntaxError, "key is not a valid CryptoKey")
}

var ok bool
ck, ok = key.Export().(*CryptoKey)
if !ok {
return NewError(ImplementationError, "unable to extract CryptoKey")
}

inputAlgorithm := key.ToObject(rt).Get("algorithm").ToObject(rt)
inputAlgorithm := key.ToObject(rt).Get("algorithm").ToObject(rt)

keyAlgorithmName := inputAlgorithm.Get("name").String()
if algorithm.Name != keyAlgorithmName {
reject(NewError(InvalidAccessError, "algorithm name does not match key algorithm name"))
return promise
}
keyAlgorithmName := inputAlgorithm.Get("name").String()
if algorithm.Name != keyAlgorithmName {
return NewError(InvalidAccessError, "algorithm name does not match key algorithm name")
}

go func() {
// 5.
if !isRegisteredAlgorithm(algorithm.Name, OperationIdentifierExportKey) {
reject(NewError(NotSupportedError, "unsupported algorithm "+algorithm.Name))
return
return NewError(NotSupportedError, "unsupported algorithm "+algorithm.Name)
}

// 6.
if !ck.Extractable {
reject(NewError(InvalidAccessError, "the key is not extractable"))
return
return NewError(InvalidAccessError, "the key is not extractable")
}

var result interface{}
var err error

switch keyAlgorithmName {
case AESCbc, AESCtr, AESGcm:
result, err = exportAESKey(ck, format)
if err != nil {
reject(err)
return
}
keyExporter = exportAESKey
case HMAC:
result, err = exportHMACKey(ck, format)
if err != nil {
reject(err)
return
}
keyExporter = exportHMACKey
case ECDH, ECDSA:
result, err = exportECKey(ck, format)
keyExporter = exportECKey
default:
return NewError(NotSupportedError, "unsupported algorithm "+keyAlgorithmName)
}

return nil
}()

promise, resolve, reject := rt.NewPromise()
if err != nil {
reject(err)
return promise
}

callback := sc.vu.RegisterCallback()
go func() {
result, err := keyExporter(ck, format)

callback(func() error {
if err != nil {
reject(err)
return
return nil //nolint:nilerr // we return nil to indicate that the error was handled
}
default:
reject(NewError(NotSupportedError, "unsupported algorithm "+keyAlgorithmName))
return
}

if !isBinaryExportedFormat(format) {
resolve(result)
return
}
if !isBinaryExportedFormat(format) {
resolve(result)
return nil
}

b, ok := result.([]byte)
if !ok {
reject(NewError(ImplementationError, "for "+format+" []byte expected as result"))
return
}
b, ok := result.([]byte)
if !ok {
reject(NewError(ImplementationError, "for "+format+" []byte expected as result"))
return nil
}

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

return promise
Expand Down

0 comments on commit b241d21

Please sign in to comment.