console: improve web3ext loader

The old one worked, but evaluating JS code created from server-provided
input is weird and can lead to RCE in case the console is used with a
malicious server.
This commit is contained in:
Felix Lange 2020-01-22 16:04:50 +01:00
parent 3ee39f28d1
commit 832d1100b9

View file

@ -116,30 +116,8 @@ func (c *Console) init(preload []string) error {
if err := c.initWeb3(bridge); err != nil { if err := c.initWeb3(bridge); err != nil {
return err return err
} }
if err := c.initExtensions(); err != nil {
// Load the supported APIs. return err
apis, err := c.client.SupportedModules()
if err != nil {
return fmt.Errorf("api modules: %v", err)
}
flatten := "var eth = web3.eth; var personal = web3.personal; "
for api := range apis {
if api == "web3" {
continue // manually mapped or ignore
}
if file, ok := web3ext.Modules[api]; ok {
// Load our extension for the module.
if err = c.jsre.Compile(fmt.Sprintf("%s.js", api), file); err != nil {
return fmt.Errorf("%s.js: %v", api, err)
}
flatten += fmt.Sprintf("var %s = web3.%s; ", api, api)
} else if _, err := c.jsre.Run("web3." + api); err == nil {
// Enable web3.js built-in extension if available.
flatten += fmt.Sprintf("var %s = web3.%s; ", api, api)
}
}
if _, err = c.jsre.Run(flatten); err != nil {
return fmt.Errorf("namespace flattening: %v", err)
} }
// Add bridge overrides for web3.js functionality. // Add bridge overrides for web3.js functionality.
@ -204,6 +182,38 @@ func (c *Console) initWeb3(bridge *bridge) error {
return err return err
} }
// initExtensions loads and registers web3.js extensions.
func (c *Console) initExtensions() error {
// Compute aliases from server-provided modules.
apis, err := c.client.SupportedModules()
if err != nil {
return fmt.Errorf("api modules: %v", err)
}
aliases := map[string]struct{}{"eth": {}, "personal": {}}
for api := range apis {
if api == "web3" {
continue
}
aliases[api] = struct{}{}
if file, ok := web3ext.Modules[api]; ok {
if err = c.jsre.Compile(api+".js", file); err != nil {
return fmt.Errorf("%s.js: %v", api, err)
}
}
}
// Apply aliases.
c.jsre.Do(func(vm *goja.Runtime) {
web3 := getObject(vm, "web3")
for name, _ := range aliases {
if v := web3.Get(name); v != nil {
vm.Set(name, v)
}
}
})
return nil
}
// initAdmin creates additional admin APIs implemented by the bridge. // initAdmin creates additional admin APIs implemented by the bridge.
func (c *Console) initAdmin(vm *goja.Runtime, bridge *bridge) { func (c *Console) initAdmin(vm *goja.Runtime, bridge *bridge) {
if admin := getObject(vm, "admin"); admin != nil { if admin := getObject(vm, "admin"); admin != nil {