Basic gql functionality, need to work on resolving nodeIDs by sending/waiting for read signals

gql_cataclysm
noah metz 2024-03-08 17:43:30 -07:00
parent 7e143c9d93
commit eef8451566
7 changed files with 218 additions and 276 deletions

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"runtime" "runtime"
"slices"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
@ -31,7 +32,8 @@ type DeserializeFn func(ctx *Context, data []byte) (reflect.Value, []byte, error
type FieldInfo struct { type FieldInfo struct {
Index []int Index []int
Tag FieldTag Tag string
NodeTag string
Type reflect.Type Type reflect.Type
} }
@ -49,22 +51,20 @@ type TypeInfo struct {
type ExtensionInfo struct { type ExtensionInfo struct {
ExtType ExtType
Interface *graphql.Interface Fields map[string]FieldInfo
Fields map[string][]int
Data interface{} Data interface{}
} }
type FieldIndex struct { type FieldIndex struct {
FieldTag FieldTag FieldTag
Extension ExtType Extension ExtType
Field string
} }
type NodeInfo struct { type NodeInfo struct {
NodeType NodeType
Type *graphql.Object Type *graphql.Object
Interface *graphql.Interface
Extensions []ExtType Extensions []ExtType
Fields map[string]FieldIndex
} }
// A Context stores all the data to run a graphvent process // A Context stores all the data to run a graphvent process
@ -92,52 +92,65 @@ type Context struct {
nodeMap map[NodeID]*Node nodeMap map[NodeID]*Node
} }
func (ctx *Context) GQLType(t reflect.Type) (graphql.Type, error) { func (ctx *Context) GQLType(t reflect.Type, node_type string) (graphql.Type, error) {
info, mapped := ctx.TypeTypes[t] if t == reflect.TypeFor[NodeID]() {
if mapped { node_info, mapped := ctx.NodeTypes[node_type]
return info.Type, nil if mapped == false {
return nil, fmt.Errorf("Cannot get GQL type for unregistered Node Type \"%s\"", node_type)
} else {
return node_info.Interface, nil
}
} else { } else {
switch t.Kind() { info, mapped := ctx.TypeTypes[t]
case reflect.Array: if mapped {
info, mapped := ctx.TypeTypes[t.Elem()] return info.Type, nil
if mapped { } else {
return graphql.NewList(info.Type), nil switch t.Kind() {
} case reflect.Array:
case reflect.Slice: info, mapped := ctx.TypeTypes[t.Elem()]
info, mapped := ctx.TypeTypes[t.Elem()] if mapped {
if mapped { return graphql.NewList(info.Type), nil
return graphql.NewList(info.Type), nil
}
case reflect.Map:
info, exists := ctx.TypeTypes[t]
if exists {
return info.Type, nil
} else {
err := RegisterMap(ctx, t)
if err != nil {
return nil, err
} }
map_type := ctx.TypeTypes[t].Type case reflect.Slice:
ctx.Log.Logf("gql", "Getting type for %s: %s", t, map_type) info, mapped := ctx.TypeTypes[t.Elem()]
return map_type, nil if mapped {
} return graphql.NewList(info.Type), nil
case reflect.Pointer: }
info, mapped := ctx.TypeTypes[t.Elem()] case reflect.Map:
if mapped { info, exists := ctx.TypeTypes[t]
return info.Type, nil if exists {
return info.Type, nil
} else {
err := RegisterMap(ctx, t, node_type)
if err != nil {
return nil, err
}
map_type := ctx.TypeTypes[t].Type
ctx.Log.Logf("gql", "Getting type for %s: %s", t, map_type)
return map_type, nil
}
case reflect.Pointer:
return ctx.GQLType(t.Elem(), node_type)
} }
return nil, fmt.Errorf("Can't convert %s to GQL type", t)
} }
return nil, fmt.Errorf("Can't convert %s to GQL type", t)
} }
} }
func RegisterMap(ctx *Context, reflect_type reflect.Type) error { func RegisterMap(ctx *Context, reflect_type reflect.Type, node_type string) error {
key_type, err := ctx.GQLType(reflect_type.Key()) ctx.Log.Logf("gql", "Registering map %s with node_type %s", reflect_type, node_type)
node_types := strings.Split(node_type, ":")
if len(node_types) != 2 {
return fmt.Errorf("Invalid node tag for map type %s: \"%s\"", reflect_type, node_type)
}
key_type, err := ctx.GQLType(reflect_type.Key(), node_types[0])
if err != nil { if err != nil {
return err return err
} }
val_type, err := ctx.GQLType(reflect_type.Elem()) val_type, err := ctx.GQLType(reflect_type.Elem(), node_types[1])
if err != nil { if err != nil {
return err return err
} }
@ -181,17 +194,18 @@ func RegisterMap(ctx *Context, reflect_type reflect.Type) error {
func BuildSchema(ctx *Context, query, mutation *graphql.Object) (graphql.Schema, error) { func BuildSchema(ctx *Context, query, mutation *graphql.Object) (graphql.Schema, error) {
types := []graphql.Type{} types := []graphql.Type{}
ctx.Log.Logf("gql", "Building Schema")
for _, info := range(ctx.TypeMap) { for _, info := range(ctx.TypeMap) {
ctx.Log.Logf("gql", "Adding type %+v", info.Type)
types = append(types, info.Type) types = append(types, info.Type)
} }
for _, info := range(ctx.Extensions) {
types = append(types, info.Interface)
}
for _, info := range(ctx.Nodes) { for _, info := range(ctx.Nodes) {
ctx.Log.Logf("gql", "Adding node type object %+v", info.Type)
types = append(types, info.Type) types = append(types, info.Type)
ctx.Log.Logf("gql", "Adding node type interface %+v", info.Interface)
types = append(types, info.Interface)
} }
subscription := graphql.NewObject(graphql.ObjectConfig{ subscription := graphql.NewObject(graphql.ObjectConfig{
@ -214,19 +228,6 @@ func BuildSchema(ctx *Context, query, mutation *graphql.Object) (graphql.Schema,
}) })
} }
func RegisterSignal[S Signal](ctx *Context) error {
reflect_type := reflect.TypeFor[S]()
signal_type := SignalTypeFor[S]()
err := RegisterObject[S](ctx)
if err != nil {
return err
}
ctx.Log.Logf("serialize_types", "Registered SignalType: %+v - %+v", reflect_type, signal_type)
return nil
}
func RegisterExtension[E any, T interface { *E; Extension}](ctx *Context, data interface{}) error { func RegisterExtension[E any, T interface { *E; Extension}](ctx *Context, data interface{}) error {
reflect_type := reflect.TypeFor[E]() reflect_type := reflect.TypeFor[E]()
ext_type := ExtType(SerializedTypeFor[E]()) ext_type := ExtType(SerializedTypeFor[E]())
@ -235,62 +236,24 @@ func RegisterExtension[E any, T interface { *E; Extension}](ctx *Context, data i
return fmt.Errorf("Cannot register extension %+v of type %+v, type already exists in context", reflect_type, ext_type) return fmt.Errorf("Cannot register extension %+v of type %+v, type already exists in context", reflect_type, ext_type)
} }
gql_name := "interface_" + strings.ReplaceAll(reflect_type.String(), ".", "_") fields := map[string]FieldInfo{}
ctx.Log.Logf("gql", "Registering %s with gql name %s", reflect_type, gql_name)
gql_interface := graphql.NewInterface(graphql.InterfaceConfig{
Name: gql_name,
ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object {
ctx, ok := p.Context.Value("resolve").(*ResolveContext)
if ok == false {
return nil
}
node, ok := p.Value.(NodeResult)
if ok == false {
return nil
}
type_info, type_exists := ctx.Context.Nodes[node.NodeType] for _, field := range(reflect.VisibleFields(reflect_type)) {
if type_exists == false {
return ctx.Context.NodeTypes["Base"].Type
}
return type_info.Type
},
Fields: graphql.Fields{
"ID": &graphql.Field{
Type: graphql.String,
},
},
})
fields := map[string][]int{}
for _, field := range reflect.VisibleFields(reflect.TypeFor[E]()) {
gv_tag, tagged_gv := field.Tag.Lookup("gv") gv_tag, tagged_gv := field.Tag.Lookup("gv")
if tagged_gv { if tagged_gv {
fields[gv_tag] = field.Index fields[gv_tag] = FieldInfo{
Index: field.Index,
gql_type, err := ctx.GQLType(field.Type) Tag: gv_tag,
if err != nil { NodeTag: field.Tag.Get("node"),
return err Type: field.Type,
} }
gql_interface.AddFieldConfig(gv_tag, &graphql.Field{
Type: gql_type,
})
} }
} }
err := RegisterObject[E](ctx)
if err != nil {
return err
}
ctx.Log.Logf("serialize_types", "Registered ExtType: %+v - %+v", reflect_type, ext_type) ctx.Log.Logf("serialize_types", "Registered ExtType: %+v - %+v", reflect_type, ext_type)
ctx.Extensions[ext_type] = &ExtensionInfo{ ctx.Extensions[ext_type] = &ExtensionInfo{
ExtType: ext_type, ExtType: ext_type,
Interface: gql_interface,
Data: data, Data: data,
Fields: fields, Fields: fields,
} }
@ -299,8 +262,9 @@ func RegisterExtension[E any, T interface { *E; Extension}](ctx *Context, data i
return nil return nil
} }
func RegisterNodeType(ctx *Context, name string, extensions []ExtType, mappings map[string]FieldIndex) error { func RegisterNodeType(ctx *Context, name string, extensions []ExtType) error {
node_type := NodeTypeFor(name, extensions, mappings) ctx.Log.Logf("gql", "Registering NodeType %s with extensions %+v", name, extensions)
node_type := NodeTypeFor(extensions)
_, exists := ctx.Nodes[node_type] _, exists := ctx.Nodes[node_type]
if exists == true { if exists == true {
return fmt.Errorf("Cannot register node type %+v, type already exists in context", node_type) return fmt.Errorf("Cannot register node type %+v, type already exists in context", node_type)
@ -310,7 +274,7 @@ func RegisterNodeType(ctx *Context, name string, extensions []ExtType, mappings
for _, extension := range(extensions) { for _, extension := range(extensions) {
_, in_ctx := ctx.Extensions[extension] _, in_ctx := ctx.Extensions[extension]
if in_ctx == false { if in_ctx == false {
return fmt.Errorf("Cannot register node type %+v, required extension %+v not in context", node_type, extension) return fmt.Errorf("Cannot register node type %+v, required extension %+v not in context", name, extension)
} }
_, duplicate := ext_found[extension] _, duplicate := ext_found[extension]
@ -321,30 +285,112 @@ func RegisterNodeType(ctx *Context, name string, extensions []ExtType, mappings
ext_found[extension] = true ext_found[extension] = true
} }
gql := graphql.NewObject(graphql.ObjectConfig{ gql_interface := graphql.NewInterface(graphql.InterfaceConfig{
Name: name, Name: name,
Interfaces: []*graphql.Interface{},
Fields: graphql.Fields{ Fields: graphql.Fields{
"ID": &graphql.Field{ "ID": &graphql.Field{
Type: graphql.String, Type: ctx.TypeTypes[reflect.TypeFor[NodeID]()].Type,
}, },
"Type": &graphql.Field{ "Type": &graphql.Field{
Type: graphql.String, Type: ctx.TypeTypes[reflect.TypeFor[NodeType]()].Type,
},
},
ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object {
ctx_val := p.Context.Value("resolve")
ctx, ok := ctx_val.(*ResolveContext)
if ok == false {
return nil
}
val, ok := p.Value.(NodeResult)
if ok == false {
return nil
}
node_info, exists := ctx.Context.Nodes[val.NodeType]
if exists == false {
return nil
}
for _, ext_type := range(extensions) {
if slices.Contains(node_info.Extensions, ext_type) == false {
// node_info does not contain required extension, so this cannot be a type of this interface
return nil
}
}
return node_info.Type
},
})
gql := graphql.NewObject(graphql.ObjectConfig{
Name: name + "Node",
Fields: graphql.Fields{
"ID": &graphql.Field{
Type: ctx.TypeTypes[reflect.TypeFor[NodeID]()].Type,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
source, ok := p.Source.(NodeResult)
if ok == false {
return nil, fmt.Errorf("GQL Node value is not NodeResult")
}
return source.NodeID, nil
},
},
"Type": &graphql.Field{
Type: ctx.TypeTypes[reflect.TypeFor[NodeType]()].Type,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
source, ok := p.Source.(NodeResult)
if ok == false {
return nil, fmt.Errorf("GQL Node value is not NodeResult")
}
return source.NodeType, nil
},
}, },
}, },
IsTypeOf: func(p graphql.IsTypeOfParams) bool { IsTypeOf: func(p graphql.IsTypeOfParams) bool {
source, ok := p.Value.(NodeResult)
if ok == false {
return false return false
}
return source.NodeType == node_type
}, },
}) })
ctx.Nodes[node_type] = &NodeInfo{ ctx.Nodes[node_type] = &NodeInfo{
NodeType: node_type, NodeType: node_type,
Interface: gql_interface,
Type: gql, Type: gql,
Extensions: extensions, Extensions: extensions,
Fields: mappings,
} }
ctx.NodeTypes[name] = ctx.Nodes[node_type] ctx.NodeTypes[name] = ctx.Nodes[node_type]
for _, ext_type := range(extensions) {
ext_info, ext_found := ctx.Extensions[ext_type]
if ext_found == false {
return fmt.Errorf("Extension %s not found", ext_type)
}
for field_name, field_info := range(ext_info.Fields) {
gql_type, err := ctx.GQLType(field_info.Type, field_info.NodeTag)
if err != nil {
return err
}
ctx.Log.Logf("gql", "Adding field %s[%+v] to %s with gql type %+v", field_name, field_info, name, gql_type)
gql_interface.AddFieldConfig(field_name, &graphql.Field{
Type: gql_type,
})
gql.AddFieldConfig(field_name, &graphql.Field{
Type: gql_type,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return nil, fmt.Errorf("NOT_IMPLEMENTED: TODO")
},
})
}
}
return nil return nil
} }
@ -378,16 +424,19 @@ func RegisterObject[T any](ctx *Context) error {
for _, field := range(reflect.VisibleFields(reflect_type)) { for _, field := range(reflect.VisibleFields(reflect_type)) {
gv_tag, tagged_gv := field.Tag.Lookup("gv") gv_tag, tagged_gv := field.Tag.Lookup("gv")
if tagged_gv { if tagged_gv {
node_tag := field.Tag.Get("node")
field_infos[GetFieldTag(gv_tag)] = FieldInfo{ field_infos[GetFieldTag(gv_tag)] = FieldInfo{
Type: field.Type, Type: field.Type,
Tag: GetFieldTag(gv_tag),
Index: field.Index, Index: field.Index,
NodeTag: node_tag,
Tag: gv_tag,
} }
gql_type, err := ctx.GQLType(field.Type) gql_type, err := ctx.GQLType(field.Type, node_tag)
if err != nil { if err != nil {
return err return err
} }
gql.AddFieldConfig(gv_tag, &graphql.Field{ gql.AddFieldConfig(gv_tag, &graphql.Field{
Type: gql_type, Type: gql_type,
Resolve: func(p graphql.ResolveParams) (interface{}, error) { Resolve: func(p graphql.ResolveParams) (interface{}, error) {
@ -563,7 +612,6 @@ func RegisterScalar[S any](ctx *Context, to_json func(interface{})interface{}, f
return nil return nil
} }
func (ctx *Context) AddNode(id NodeID, node *Node) { func (ctx *Context) AddNode(id NodeID, node *Node) {
ctx.nodeMapLock.Lock() ctx.nodeMapLock.Lock()
ctx.nodeMap[id] = node ctx.nodeMap[id] = node
@ -670,6 +718,21 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) {
var err error var err error
err = RegisterScalar[NodeID](ctx, stringify, unstringify[NodeID], unstringifyAST[NodeID])
if err != nil {
return nil, err
}
err = RegisterScalar[NodeType](ctx, identity, coerce[NodeType], astInt[NodeType])
if err != nil {
return nil, err
}
err = RegisterNodeType(ctx, "Base", []ExtType{})
if err != nil {
return nil, err
}
err = RegisterScalar[bool](ctx, identity, coerce[bool], astBool[bool]) err = RegisterScalar[bool](ctx, identity, coerce[bool], astBool[bool])
if err != nil { if err != nil {
return nil, err return nil, err
@ -715,63 +778,77 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) {
return nil, err return nil, err
} }
err = RegisterScalar[NodeID](ctx, stringify, unstringify[NodeID], unstringifyAST[NodeID]) err = RegisterScalar[WaitReason](ctx, identity, coerce[WaitReason], astString[WaitReason])
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = RegisterScalar[WaitReason](ctx, identity, coerce[WaitReason], astString[WaitReason]) err = RegisterObject[Node](ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = RegisterScalar[NodeType](ctx, identity, coerce[NodeType], astInt[NodeType]) err = RegisterObject[WaitInfo](ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = RegisterObject[Node](ctx) err = RegisterExtension[LockableExt](ctx, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = RegisterObject[WaitInfo](ctx) err = RegisterExtension[EventExt](ctx, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = RegisterExtension[LockableExt](ctx, nil) err = RegisterExtension[ListenerExt](ctx, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = RegisterExtension[EventExt](ctx, nil) err = RegisterExtension[GQLExt](ctx, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = RegisterExtension[ListenerExt](ctx, nil) err = RegisterNodeType(ctx, "Lockable", []ExtType{ExtTypeFor[LockableExt]()})
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = RegisterExtension[GQLExt](ctx, nil) err = RegisterObject[LockableExt](ctx)
if err != nil {
return nil, err
}
err = RegisterObject[EventExt](ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = RegisterNodeType(ctx, "Base", []ExtType{}, map[string]FieldIndex{}) err = RegisterObject[ListenerExt](ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = RegisterObject[GQLExt](ctx)
if err != nil {
return nil, err
}
schema, err := BuildSchema(ctx, graphql.NewObject(graphql.ObjectConfig{ schema, err := BuildSchema(ctx, graphql.NewObject(graphql.ObjectConfig{
Name: "Query", Name: "Query",
Fields: graphql.Fields{ Fields: graphql.Fields{
"Test": &graphql.Field{ "Self": &graphql.Field{
Type: graphql.String, Type: ctx.NodeTypes["Base"].Type,
Resolve: func(p graphql.ResolveParams) (interface{}, error) { Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return "TEST", nil // TODO: Send read request and get response instead of hard-coding
return NodeResult{
NodeID: RandID(),
NodeType: NodeTypeFor([]ExtType{}),
}, nil
}, },
}, },
}, },

@ -12,7 +12,7 @@ type EventExt struct {
Name string `gv:"name"` Name string `gv:"name"`
State EventState `gv:"state"` State EventState `gv:"state"`
StateStart time.Time `gv:"state_start"` StateStart time.Time `gv:"state_start"`
Parent NodeID `gv:"parent"` Parent NodeID `gv:"parent" node:"Base"`
} }
func (ext *EventExt) Load(ctx *Context, node *Node) error { func (ext *EventExt) Load(ctx *Context, node *Node) error {

122
gql.go

@ -1,18 +1,12 @@
package graphvent package graphvent
import ( import (
"bytes"
"context" "context"
"crypto"
"crypto/aes"
"crypto/cipher"
"crypto/ecdh" "crypto/ecdh"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic" "crypto/elliptic"
"crypto/rand" "crypto/rand"
"crypto/x509" "crypto/x509"
"encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
@ -20,12 +14,9 @@ import (
"net" "net"
"net/http" "net/http"
"reflect" "reflect"
"strings"
"sync" "sync"
"time" "time"
"filippo.io/edwards25519"
"crypto/sha512"
"github.com/gobwas/ws" "github.com/gobwas/ws"
"github.com/gobwas/ws/wsutil" "github.com/gobwas/ws/wsutil"
"github.com/graphql-go/graphql" "github.com/graphql-go/graphql"
@ -40,39 +31,6 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
) )
func NodeInterfaceDefaultIsType(required_extensions []ExtType) func(graphql.IsTypeOfParams) bool {
return func(p graphql.IsTypeOfParams) bool {
ctx, ok := p.Context.Value("resolve").(*ResolveContext)
if ok == false {
return false
}
node, ok := p.Value.(NodeResult)
if ok == false {
return false
}
node_type_def, exists := ctx.Context.Nodes[node.NodeType]
if exists == false {
return false
} else {
for _, ext := range(required_extensions) {
found := false
for _, e := range(node_type_def.Extensions) {
if e == ext {
found = true
break
}
}
if found == false {
return false
}
}
}
return true
}
}
func PrepResolve(p graphql.ResolveParams) (*ResolveContext, error) { func PrepResolve(p graphql.ResolveParams) (*ResolveContext, error) {
resolve_context, ok := p.Context.Value("resolve").(*ResolveContext) resolve_context, ok := p.Context.Value("resolve").(*ResolveContext)
if ok == false { if ok == false {
@ -82,7 +40,7 @@ func PrepResolve(p graphql.ResolveParams) (*ResolveContext, error) {
return resolve_context, nil return resolve_context, nil
} }
// TODO: Make composabe by checkinf if K is a slice, then recursing in the same way that ExtractList does // TODO: Make composabe by checking if K is a slice, then recursing in the same way that ExtractList does
func ExtractParam[K interface{}](p graphql.ResolveParams, name string) (K, error) { func ExtractParam[K interface{}](p graphql.ResolveParams, name string) (K, error) {
var zero K var zero K
arg_if, ok := p.Args[name] arg_if, ok := p.Args[name]
@ -286,84 +244,6 @@ type ResolveContext struct {
NodeCache map[NodeID]NodeResult NodeCache map[NodeID]NodeResult
} }
func AuthB64(client_key ed25519.PrivateKey, server_pubkey ed25519.PublicKey) (string, error) {
token_start := time.Now()
token_start_bytes, err := token_start.MarshalBinary()
if err != nil {
return "", err
}
session_key_public, session_key_private, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return "", err
}
session_h := sha512.Sum512(session_key_private.Seed())
ecdh_client, err := ECDH.NewPrivateKey(session_h[:32])
if err != nil {
return "", err
}
server_point, err := (&edwards25519.Point{}).SetBytes(server_pubkey)
if err != nil {
return "", err
}
ecdh_server, err := ECDH.NewPublicKey(server_point.BytesMontgomery())
if err != nil {
return "", err
}
secret, err := ecdh_client.ECDH(ecdh_server)
if err != nil {
return "", err
}
if len(secret) != 32 {
return "", fmt.Errorf("ECDH secret not 32 bytes(for AES-256): %d bytes long", len(secret))
}
block, err := aes.NewCipher(secret)
if err != nil {
return "", err
}
iv := make([]byte, block.BlockSize())
iv_len, err := rand.Reader.Read(iv)
if err != nil {
return "", err
} else if iv_len != block.BlockSize() {
return "", fmt.Errorf("Not enough iv bytes read: %d", iv_len)
}
var key_encrypted bytes.Buffer
stream := cipher.NewOFB(block, iv)
writer := &cipher.StreamWriter{S: stream, W: &key_encrypted}
bytes_written, err := writer.Write(session_key_private.Seed())
if err != nil {
return "", err
} else if bytes_written != len(ecdh_client.Bytes()) {
return "", fmt.Errorf("wrong number of bytes encrypted %d/%d", bytes_written, len(ecdh_client.Bytes()))
}
digest := append(session_key_public, token_start_bytes...)
signature, err := client_key.Sign(rand.Reader, digest, crypto.Hash(0))
if err != nil {
return "", err
}
start_b64 := base64.StdEncoding.EncodeToString(token_start_bytes)
iv_b64 := base64.StdEncoding.EncodeToString(iv)
encrypted_b64 := base64.StdEncoding.EncodeToString(key_encrypted.Bytes())
key_b64 := base64.StdEncoding.EncodeToString(session_key_public)
sig_b64 := base64.StdEncoding.EncodeToString(signature)
id_b64 := base64.StdEncoding.EncodeToString(client_key.Public().(ed25519.PublicKey))
return base64.StdEncoding.EncodeToString([]byte(strings.Join([]string{id_b64, iv_b64, key_b64, encrypted_b64, start_b64, sig_b64}, ":"))), nil
}
func NewResolveContext(ctx *Context, server *Node, gql_ext *GQLExt) (*ResolveContext, error) { func NewResolveContext(ctx *Context, server *Node, gql_ext *GQLExt) (*ResolveContext, error) {
return &ResolveContext{ return &ResolveContext{
ID: uuid.New(), ID: uuid.New(),

@ -25,11 +25,11 @@ var ReqStateStrings = map[ReqState]string {
type LockableExt struct{ type LockableExt struct{
State ReqState `gv:"state"` State ReqState `gv:"state"`
ReqID *uuid.UUID `gv:"req_id"` ReqID *uuid.UUID `gv:"req_id"`
Owner *NodeID `gv:"owner"` Owner *NodeID `gv:"owner" node:"Base"`
PendingOwner *NodeID `gv:"pending_owner"` PendingOwner *NodeID `gv:"pending_owner" node:"Base"`
PendingID uuid.UUID `gv:"pending_id"` PendingID uuid.UUID `gv:"pending_id"`
Requirements map[NodeID]ReqState `gv:"requirements"` Requirements map[NodeID]ReqState `gv:"requirements" node:"Lockable:"`
WaitInfos WaitMap `gv:"wait_infos"` WaitInfos WaitMap `gv:"wait_infos" node:":Base"`
} }
func NewLockableExt(requirements []NodeID) *LockableExt { func NewLockableExt(requirements []NodeID) *LockableExt {

@ -104,7 +104,7 @@ func (node *Node) PostDeserialize(ctx *Context) error {
type WaitReason string type WaitReason string
type WaitInfo struct { type WaitInfo struct {
Destination NodeID `gv:"destination"` Destination NodeID `gv:"destination" node:"Base"`
Timeout uuid.UUID `gv:"timeout"` Timeout uuid.UUID `gv:"timeout"`
Reason WaitReason `gv:"reason"` Reason WaitReason `gv:"reason"`
} }
@ -226,7 +226,7 @@ func (node *Node) ReadFields(ctx *Context, reqs map[ExtType][]string)map[ExtType
if exists == false { if exists == false {
fields[req] = fmt.Errorf("%+v does not have %+v extension", node.ID, ext_type) fields[req] = fmt.Errorf("%+v does not have %+v extension", node.ID, ext_type)
} else { } else {
fields[req] = reflect.ValueOf(ext).Elem().FieldByIndex(ext_info.Fields[req]).Interface() fields[req] = reflect.ValueOf(ext).Elem().FieldByIndex(ext_info.Fields[req].Index).Interface()
} }
} }
exts[ext_type] = fields exts[ext_type] = fields

@ -39,28 +39,13 @@ func (t FieldTag) String() string {
return fmt.Sprintf("0x%x", uint64(t)) return fmt.Sprintf("0x%x", uint64(t))
} }
func NodeTypeFor(name string, extensions []ExtType, mappings map[string]FieldIndex) NodeType { func NodeTypeFor(extensions []ExtType) NodeType {
digest := []byte("GRAPHVENT_NODE[" + name + "] - ") digest := []byte("GRAPHVENT_NODE - ")
for _, ext := range(extensions) {
digest = binary.BigEndian.AppendUint64(digest, uint64(ext))
}
digest = binary.BigEndian.AppendUint64(digest, 0) slices.Sort(extensions)
sorted_keys := make([]string, len(mappings))
i := 0
for key := range(mappings) {
sorted_keys[i] = key
i += 1
}
slices.Sort(sorted_keys)
for _, ext := range(extensions) {
digest = binary.BigEndian.AppendUint64(digest, uint64(ext))
for _, key := range(sorted_keys) {
digest = append(digest, []byte(key + ":")...)
digest = binary.BigEndian.AppendUint64(digest, uint64(mappings[key].Extension))
digest = append(digest, []byte(mappings[key].Field + "|")...)
} }
hash := sha512.Sum512(digest) hash := sha512.Sum512(digest)

@ -242,7 +242,7 @@ type ReadResultSignal struct {
} }
func (signal ReadResultSignal) String() string { func (signal ReadResultSignal) String() string {
return fmt.Sprintf("ReadResultSignal(%s, %s, %+v, %+v)", signal.ResponseHeader, signal.NodeID, signal.NodeType, signal.Extensions) return fmt.Sprintf("ReadResultSignal(%s, %s, %+v)", signal.ResponseHeader, signal.NodeID, signal.Extensions)
} }
func NewReadResultSignal(req_id uuid.UUID, node_id NodeID, node_type NodeType, exts map[ExtType]map[string]any) *ReadResultSignal { func NewReadResultSignal(req_id uuid.UUID, node_id NodeID, node_type NodeType, exts map[ExtType]map[string]any) *ReadResultSignal {