
Research
Malicious npm Packages Impersonate Flashbots SDKs, Targeting Ethereum Wallet Credentials
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
melato.org/jsoncall
jsoncall is a Go module that facilitates creating HTTP web services from Go interfaces, using reflection to marshal/unmarshal Go method inputs/outputs to/from a single JSON object.
To create a Go client and a Go server that communicate via a HTTP, the following steps need to be done:
This example uses an interface, and a custom api descriptor.
package example
import (
_ "embed"
"net/http"
"melato.org/jsoncall"
)
type Demo interface {
Repeat(s string, count int) ([]string, error)
}
//go:embed demo.json
var demoNames []byte
func NewDemoCaller() (*jsoncall.Caller, error) {
var api *Demo
return jsoncall.NewCaller(api, demoNames)
}
import (
"example"
)
type DemoImpl struct {}
func (t *DemoImpl) Repeat(s string, count int) ([]string, error) {
if count < 0 {
return nil, fmt.Errorf("negative count: %d", count)
}
list := make([]string, count)
for i := 0; i < count; i++ {
list[i] = s
}
return list, nil
}
type Server struct {}
func (t *Server) DemoReceiver(w http.ResponseWriter, r *http.Request) interface{} {
return &example.DemoImpl{}
}
func (t *Server) Run() error {
demoCaller, err := example.NewDemoCaller()
if err != nil {
return err
}
mux := http.NewServeMux()
mux.Handle("/demo/", demoCaller.NewHttpHandler(t.DemoReceiver)
return http.ListenAndServe(":8080", mux)
}
func NewDemoClient() (example.Demo, error) {
caller, err := example.NewDemoCaller()
if err != nil {
return nil, err
}
c := caller.NewHttpClient("http://localhost:8081/demo/")
return generated.NewDemoClient(c), nil
}
package main
import (
"example"
"melato.org/jsoncall/generate"
)
func GenerateStub() error {
var g generate.Generator
g.Init()
g.Package = "generated"
g.Type = "exampleClient"
g.Func = "NewDemoClient"
g.OutputFile = "../generated/generated_example.go"
g.Package = "generated"
//g.Imports = []string{"example/a", "example/b"}
caller, err := example.NewExampleCaller()
if err != nil {
return err
}
return g.Output(g.GenerateClient(caller))
}
The API descriptor is an optional JSON file. When the API changes, by adding or removing methods, you need to update the API descriptor by hand. To facilitate updating, there is a tool that automatically updates the JSON file. It removes methods that are no longer in the API interface. It adds new methods, using default naming conventions for the method names and their parameters. You can then edit the file by hand to replace the default names with custom names.
package main
import (
"melato.org/jsoncall/generate"
)
func Main() {
var api *example.Example
err := generate.UpdateDescriptor(api, "../api.json")
if err != nil {
fmt.Println(err)
}
}
To create an initial API descriptor, you can create an empty api.json file, and then update it with the code above.
[
{
"method": "Repeat",
"path": "repeat",
"in": [
"s",
"count"
],
"out": [
"result",
"error"
]
}
]
A client can call this server by making an HTTP POST request to http://localhost:8080/demo/repeat with body:
{"s":"a","count":2}
For example, using curl:
curl --data-binary '{"s":"a","count":2}' http://localhost:8080/repeat
It should get a response like this:
{"result":["a","a"]}
The chosen protocol has some similarities with JSON-RPC 2.0, but does not follow it entirely.
The default output keys "result" and "error" follow the JSON-RPC conventions, when there is a single output.
Putting the method name in the url allows us to know how to unmarshal the body of the request into the arguments. If we encoded the method in the JSON request, as per JSON-RPC, we couldn't unmarshal the request with a single pass.
Putting the method parameters in a map allows us to unmarshal them into a struct (generated via reflection) that has a field for each parameter.
We use a map for the parameters, so we can unmarshal them into their different types. If we had put the parameters in an array, we could only unmarshal them into one array type, such as []any.
We could have placed the parameters into a "params" map, as JSON-RPC specifies. Perhaps we'll add an option to do this.
FAQs
Unknown package
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
Security News
Ruby maintainers from Bundler and rbenv teams are building rv to bring Python uv's speed and unified tooling approach to Ruby development.
Security News
Following last week’s supply chain attack, Nx published findings on the GitHub Actions exploit and moved npm publishing to Trusted Publishers.