From f300d31945a3c93170a67d6037307cee480853ca Mon Sep 17 00:00:00 2001 From: Oleg Bespalov Date: Fri, 24 Jan 2025 11:55:09 +0100 Subject: [PATCH] webcrypto: make WebCrypto globally available --- internal/js/bundle.go | 15 ++++++++++- internal/js/jsmodules.go | 27 +++++++++---------- internal/js/modules/k6/webcrypto/module.go | 13 ++++++++- .../k6/webcrypto/tests/test_setup_test.go | 10 ++----- js/modulestest/runtime.go | 3 +++ 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/internal/js/bundle.go b/internal/js/bundle.go index 13b80ca6fed..adfaf68a7ea 100644 --- a/internal/js/bundle.go +++ b/internal/js/bundle.go @@ -20,6 +20,7 @@ import ( "go.k6.io/k6/internal/event" "go.k6.io/k6/internal/js/compiler" "go.k6.io/k6/internal/js/eventloop" + "go.k6.io/k6/internal/js/modules/k6/webcrypto" "go.k6.io/k6/internal/js/tc55/timers" "go.k6.io/k6/internal/loader" "go.k6.io/k6/js/common" @@ -314,10 +315,11 @@ func (b *Bundle) instantiate(vuImpl *moduleVUImpl, vuID uint64) (*BundleInstance modSys := modules.NewModuleSystem(b.ModuleResolver, vuImpl) b.setInitGlobals(rt, vuImpl, modSys) - err = timers.SetupGlobally(vuImpl) + err = registerGlobals(vuImpl) if err != nil { return nil, err } + vuImpl.initEnv = initenv defer func() { vuImpl.initEnv = nil @@ -383,6 +385,17 @@ func (b *Bundle) instantiate(vuImpl *moduleVUImpl, vuID uint64) (*BundleInstance return bi, nil } +// registerGlobals registers the globals for the runtime. +// e.g. timers and webcrypto. +func registerGlobals(vuImpl *moduleVUImpl) error { + err := timers.SetupGlobally(vuImpl) + if err != nil { + return err + } + + return webcrypto.SetupGlobally(vuImpl) +} + func (b *Bundle) setupJSRuntime(rt *sobek.Runtime, vuID uint64, logger logrus.FieldLogger) error { rt.SetFieldNameMapper(common.FieldNameMapper{}) rt.SetRandSource(common.NewRandSource()) diff --git a/internal/js/jsmodules.go b/internal/js/jsmodules.go index ad48ce4cacc..61cf1aaeb80 100644 --- a/internal/js/jsmodules.go +++ b/internal/js/jsmodules.go @@ -31,17 +31,19 @@ import ( func getInternalJSModules() map[string]interface{} { return map[string]interface{}{ - "k6": k6.New(), - "k6/crypto": crypto.New(), - "k6/crypto/x509": x509.New(), - "k6/data": data.New(), - "k6/encoding": encoding.New(), - "k6/timers": timers.New(), - "k6/execution": execution.New(), - "k6/experimental/csv": csv.New(), - "k6/experimental/redis": redis.New(), - "k6/experimental/streams": streams.New(), - "k6/experimental/webcrypto": webcrypto.New(), + "k6": k6.New(), + "k6/crypto": crypto.New(), + "k6/crypto/x509": x509.New(), + "k6/data": data.New(), + "k6/encoding": encoding.New(), + "k6/timers": timers.New(), + "k6/execution": execution.New(), + "k6/experimental/csv": csv.New(), + "k6/experimental/redis": redis.New(), + "k6/experimental/streams": streams.New(), + "k6/experimental/webcrypto": newWarnExperimentalModule(webcrypto.New(), + "k6/experimental/webcrypto is now part of the k6 core, and globally available. You could just remove import."+ + " The k6/experimental/webcrypto will be removed in k6 v1.1.0"), "k6/experimental/websockets": expws.New(), "k6/experimental/timers": newRemovedModule( "k6/experimental/timers has been graduated, please use k6/timers instead."), @@ -80,14 +82,12 @@ func getJSModules() map[string]interface{} { return result } -//nolint:unused // this is likely going to be used again even if isn't currently used type warnExperimentalModule struct { once *sync.Once msg string base modules.Module } -//nolint:unused // this is likely going to be used again even if isn't currently used func newWarnExperimentalModule(base modules.Module, msg string) modules.Module { return &warnExperimentalModule{ msg: msg, @@ -96,7 +96,6 @@ func newWarnExperimentalModule(base modules.Module, msg string) modules.Module { } } -//nolint:unused // this is likely going to be used again even if isn't currently used func (w *warnExperimentalModule) NewModuleInstance(vu modules.VU) modules.Instance { w.once.Do(func() { vu.InitEnv().Logger.Warn(w.msg) }) return w.base.NewModuleInstance(vu) diff --git a/internal/js/modules/k6/webcrypto/module.go b/internal/js/modules/k6/webcrypto/module.go index c8f298d6fff..76725f48e11 100644 --- a/internal/js/modules/k6/webcrypto/module.go +++ b/internal/js/modules/k6/webcrypto/module.go @@ -9,6 +9,8 @@ import ( "go.k6.io/k6/js/modules" ) +const cryptoGlobalIdentifier = "crypto" + type ( // RootModule is the global module instance that will create Client // instances for each VU. @@ -43,10 +45,19 @@ func (*RootModule) NewModuleInstance(vu modules.VU) modules.Instance { // the exports of the JS module. func (mi *ModuleInstance) Exports() modules.Exports { return modules.Exports{Named: map[string]interface{}{ - "crypto": newCryptoObject(mi.vu), + "crypto": mi.vu.Runtime().GlobalObject().Get(cryptoGlobalIdentifier), }} } +// SetupGlobally sets the crypto object globally. +func SetupGlobally(vu modules.VU) error { + if err := vu.Runtime().Set(cryptoGlobalIdentifier, newCryptoObject(vu)); err != nil { + return fmt.Errorf("unable to set crypto object globally; reason: %w", err) + } + + return nil +} + func newCryptoObject(vu modules.VU) *sobek.Object { rt := vu.Runtime() diff --git a/internal/js/modules/k6/webcrypto/tests/test_setup_test.go b/internal/js/modules/k6/webcrypto/tests/test_setup_test.go index 2abab430dec..d56f4fd8dce 100644 --- a/internal/js/modules/k6/webcrypto/tests/test_setup_test.go +++ b/internal/js/modules/k6/webcrypto/tests/test_setup_test.go @@ -5,7 +5,6 @@ package tests import ( "testing" - "go.k6.io/k6/internal/js/compiler" k6encoding "go.k6.io/k6/internal/js/modules/k6/encoding" "go.k6.io/k6/internal/js/modules/k6/webcrypto" "go.k6.io/k6/js/modulestest" @@ -14,7 +13,7 @@ import ( ) const initGlobals = ` - globalThis.CryptoKey = require("k6/x/webcrypto").CryptoKey; + globalThis.CryptoKey = crypto.CryptoKey; ` // newConfiguredRuntime initializes a new test setup. @@ -29,12 +28,7 @@ func newConfiguredRuntime(t testing.TB) *modulestest.Runtime { _, err = rt.VU.Runtime().RunString("var self = this;") require.NoError(t, err) - err = rt.SetupModuleSystem( - map[string]interface{}{"k6/x/webcrypto": webcrypto.New()}, - nil, - compiler.New(rt.VU.InitEnv().Logger), - ) - require.NoError(t, err) + require.NoError(t, webcrypto.SetupGlobally(rt.VU)) // We compile the Web Platform testharness script into a sobek.Program compileAndRun(t, rt, "./wpt/resources", "testharness.js") diff --git a/js/modulestest/runtime.go b/js/modulestest/runtime.go index c973eba398a..c133b9b6409 100644 --- a/js/modulestest/runtime.go +++ b/js/modulestest/runtime.go @@ -11,6 +11,8 @@ import ( "go.k6.io/k6/internal/js/compiler" "go.k6.io/k6/internal/js/eventloop" "go.k6.io/k6/internal/js/tc55/timers" + + "go.k6.io/k6/internal/js/modules/k6/webcrypto" "go.k6.io/k6/internal/lib/testutils" "go.k6.io/k6/internal/usage" "go.k6.io/k6/js/common" @@ -56,6 +58,7 @@ func NewRuntime(t testing.TB) *Runtime { BuiltinMetrics: metrics.RegisterBuiltinMetrics(vu.InitEnvField.Registry), } require.NoError(t, timers.SetupGlobally(vu)) + require.NoError(t, webcrypto.SetupGlobally(vu)) // let's cancel again in case it has changed t.Cleanup(func() { result.CancelContext() }) return result