Files
ucan/toolkit/server/extargs/jsonrpc_test.go

189 lines
4.9 KiB
Go

package extargs
import (
"testing"
"github.com/INFURA/go-ethlibs/jsonrpc"
"github.com/multiformats/go-multihash"
"github.com/stretchr/testify/require"
"github.com/ucan-wg/go-ucan/did/didtest"
"github.com/ucan-wg/go-ucan/pkg/args"
"github.com/ucan-wg/go-ucan/pkg/command"
"github.com/ucan-wg/go-ucan/pkg/policy"
"github.com/ucan-wg/go-ucan/pkg/policy/literal"
"github.com/ucan-wg/go-ucan/token/invocation"
)
func TestJsonRpc(t *testing.T) {
tests := []struct {
name string
req *jsonrpc.Request
pol policy.Policy
expected bool
}{
{
name: "or on method, not matching",
req: jsonrpc.MustRequest(1839673506133526, "eth_getBlockByNumber",
"0x599784", true,
),
pol: policy.MustConstruct(
policy.Or(
policy.Equal(".jsonrpc.method", literal.String("eth_getCode")),
policy.Equal(".jsonrpc.method", literal.String("eth_getBalance")),
policy.Equal(".jsonrpc.method", literal.String("eth_call")),
policy.Equal(".jsonrpc.method", literal.String("eth_blockNumber")),
),
),
expected: false,
},
{
name: "or on method, matching",
req: jsonrpc.MustRequest(1839673506133526, "eth_call",
map[string]string{"to": "0xBADBADBADBADBADBADBADBADBADBADBADBADBAD1"},
),
pol: policy.MustConstruct(
policy.Or(
policy.Equal(".jsonrpc.method", literal.String("eth_getCode")),
policy.Equal(".jsonrpc.method", literal.String("eth_getBalance")),
policy.Equal(".jsonrpc.method", literal.String("eth_call")),
policy.Equal(".jsonrpc.method", literal.String("eth_blockNumber")),
),
),
expected: true,
},
{
name: "complex, optional parameter, matching",
req: jsonrpc.MustRequest(1839673506133526, "debug_traceCall",
true, false, 1234, "callTracer",
),
pol: policy.MustConstruct(
policy.Equal(".jsonrpc.method", literal.String("debug_traceCall")),
policy.Or(
policy.Equal(".jsonrpc.params[3]?", literal.String("callTracer")),
policy.Equal(".jsonrpc.params[3]?", literal.String("prestateTracer")),
),
),
expected: true,
},
{
name: "complex, optional parameter, missing parameter",
req: jsonrpc.MustRequest(1839673506133526, "debug_traceCall",
true, false, 1234,
),
pol: policy.MustConstruct(
policy.Equal(".jsonrpc.method", literal.String("debug_traceCall")),
policy.Or(
policy.Equal(".jsonrpc.params[3]?", literal.String("callTracer")),
policy.Equal(".jsonrpc.params[3]?", literal.String("prestateTracer")),
),
),
expected: true,
},
{
name: "complex, parameter not matching",
req: jsonrpc.MustRequest(1839673506133526, "debug_traceCall",
true, false, 1234, "ho_no",
),
pol: policy.MustConstruct(
policy.Equal(".jsonrpc.method", literal.String("debug_traceCall")),
policy.Or(
policy.Equal(".jsonrpc.params[3]?", literal.String("callTracer")),
policy.Equal(".jsonrpc.params[3]?", literal.String("prestateTracer")),
),
),
expected: false,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
// we don't test the args hash here
emptyArgs := args.New().ReadOnly()
ctx := NewJsonRpcExtArgs(tc.pol, emptyArgs, tc.req)
_, err := ctx.Args()
require.NoError(t, err)
if tc.expected {
require.NoError(t, ctx.Verify())
} else {
require.Error(t, ctx.Verify())
}
})
}
}
func TestJsonRpcHash(t *testing.T) {
servicePersona := didtest.PersonaAlice
clientPersona := didtest.PersonaBob
req := jsonrpc.MustRequest(1839673506133526, "debug_traceCall",
true, false, 1234, "ho_no",
)
pol := policy.MustConstruct(
policy.Equal(".jsonrpc.method", literal.String("debug_traceCall")),
)
makeArg := func(data []byte, code uint64) invocation.Option {
mh, err := multihash.Sum(data, code, -1)
require.NoError(t, err)
return invocation.WithArgument(JsonRpcArgsKey, []byte(mh))
}
tests := []struct {
name string
argOptions []invocation.Option
expected bool
}{
{
name: "correct hash",
argOptions: []invocation.Option{must(MakeJsonRpcHash(req))},
expected: true,
},
{
name: "non-matching hash",
argOptions: []invocation.Option{makeArg([]byte{1, 2, 3, 4}, multihash.SHA2_256)},
expected: false,
},
{
name: "wrong type of hash",
argOptions: []invocation.Option{makeArg([]byte{1, 2, 3, 4}, multihash.BLAKE3)},
expected: false,
},
{
name: "no hash",
argOptions: nil,
expected: true, // having a hash is not enforced
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
inv, err := invocation.New(
clientPersona.DID(),
command.MustParse("/foo"),
servicePersona.DID(),
nil,
tc.argOptions..., // inject hash argument, if any
)
require.NoError(t, err)
ctx := NewJsonRpcExtArgs(pol, inv.Arguments(), req)
if tc.expected {
require.NoError(t, ctx.Verify())
} else {
require.Error(t, ctx.Verify())
}
})
}
}
func must[T any](t T, err error) T {
if err != nil {
panic(err)
}
return t
}