From a5032b69f8bc0fdac5c451d3ed73a76ab20c350c Mon Sep 17 00:00:00 2001 From: Oleg Bespalov Date: Wed, 17 Apr 2024 17:05:30 +0200 Subject: [PATCH] refactor: ImportKey to make it event loop safe --- webcrypto/subtle_crypto.go | 104 ++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 48 deletions(-) diff --git a/webcrypto/subtle_crypto.go b/webcrypto/subtle_crypto.go index 31983e0..49e90a4 100644 --- a/webcrypto/subtle_crypto.go +++ b/webcrypto/subtle_crypto.go @@ -725,7 +725,7 @@ func (sc *SubtleCrypto) DeriveBits(algorithm goja.Value, baseKey goja.Value, len // `ALGORITHM` is the name of the algorithm. // - for PBKDF2: pass the string "PBKDF2" // - for HKDF: pass the string "HKDF" -func (sc *SubtleCrypto) ImportKey( +func (sc *SubtleCrypto) ImportKey( //nolint:funlen // we have a lot of error handling format KeyFormat, keyData goja.Value, algorithm goja.Value, @@ -733,72 +733,80 @@ func (sc *SubtleCrypto) ImportKey( keyUsages []CryptoKeyUsage, ) *goja.Promise { rt := sc.vu.Runtime() - promise, resolve, reject := promises.New(sc.vu) - var keyBytes []byte + var ( + keyBytes []byte + ki KeyImporter + ) + + err := func() error { + switch format { + case Pkcs8KeyFormat, RawKeyFormat, SpkiKeyFormat: + ab, err := exportArrayBuffer(rt, keyData) + if err != nil { + return err + } - // 2. - switch format { - case Pkcs8KeyFormat, RawKeyFormat, SpkiKeyFormat: - ab, err := exportArrayBuffer(rt, keyData) + keyBytes = make([]byte, len(ab)) + copy(keyBytes, ab) + case JwkKeyFormat: + var err error + keyBytes, err = json.Marshal(keyData.Export()) + if err != nil { + return NewError(ImplementationError, "invalid keyData format for JWK format: "+err.Error()) + } + default: + return NewError(ImplementationError, "unsupported format "+format) + } + normalized, err := normalizeAlgorithm(rt, algorithm, OperationIdentifierImportKey) if err != nil { - reject(err) - return promise + return err } - keyBytes = make([]byte, len(ab)) - copy(keyBytes, ab) - case JwkKeyFormat: - var err error - keyBytes, err = json.Marshal(keyData.Export()) + ki, err = newKeyImporter(rt, normalized, algorithm) if err != nil { - reject(NewError(ImplementationError, "wrong keyData format for JWK format: "+err.Error())) - return promise + return err } - default: - reject(NewError(ImplementationError, "unsupported format "+format)) - return promise - } - // 3. - normalized, err := normalizeAlgorithm(rt, algorithm, OperationIdentifierImportKey) - if err != nil { - reject(err) - return promise - } + return nil + }() - ki, err := newKeyImporter(rt, normalized, algorithm) + promise, resolve, reject := rt.NewPromise() if err != nil { reject(err) return promise } - // 5. + callback := sc.vu.RegisterCallback() go func() { - // 8. - result, err := ki.ImportKey(format, keyBytes, keyUsages) - if err != nil { - reject(err) - return - } + result, err := func() (*CryptoKey, error) { + result, err := ki.ImportKey(format, keyBytes, keyUsages) + if err != nil { + return nil, err + } - // 9. - isSecretKey := result.Type == SecretCryptoKeyType - isPrivateKey := result.Type == PrivateCryptoKeyType - isUsagesEmpty := len(keyUsages) == 0 - if (isSecretKey || isPrivateKey) && isUsagesEmpty { - reject(NewError(SyntaxError, "usages cannot not be empty for a secret or private CryptoKey")) - return - } + isSecretKey := result.Type == SecretCryptoKeyType + isPrivateKey := result.Type == PrivateCryptoKeyType + isUsagesEmpty := len(keyUsages) == 0 + if (isSecretKey || isPrivateKey) && isUsagesEmpty { + return nil, NewError(SyntaxError, "usages cannot not be empty for a secret or private CryptoKey") + } + + result.Extractable = extractable + result.Usages = keyUsages - // 10. - result.Extractable = extractable + return result, nil + }() - // 11. - result.Usages = keyUsages + callback(func() error { + if err != nil { + reject(err) + return nil //nolint:nilerr // we return nil to indicate that the error was handled + } - // 12. - resolve(result) + resolve(result) + return nil + }) }() return promise