From 76512afd4e91662af2c2e112dfc8db970d3fcee9 Mon Sep 17 00:00:00 2001 From: Noah Metz Date: Fri, 21 Jul 2023 19:16:30 -0600 Subject: [PATCH] First pass of gql read permission --- gql_mutation.go | 4 +- gql_query.go | 4 +- gql_resolvers.go | 140 ++++++++++++++++++++++++++--------------------- gql_subscribe.go | 20 +++---- node.go | 22 ++++---- 5 files changed, 98 insertions(+), 92 deletions(-) diff --git a/gql_mutation.go b/gql_mutation.go index 907d339..24f0974 100644 --- a/gql_mutation.go +++ b/gql_mutation.go @@ -16,7 +16,7 @@ var GQLMutationSendUpdate = NewField(func()*graphql.Field { }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { - ctx, err := GetResolveContext(p) + ctx, err := PrepResolve(p) if err != nil { return nil, err } @@ -83,7 +83,7 @@ var GQLMutationStartChild = NewField(func()*graphql.Field{ }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { - ctx, err := GetResolveContext(p) + ctx, err := PrepResolve(p) if err != nil { return nil, err } diff --git a/gql_query.go b/gql_query.go index 8406efb..ca8ea27 100644 --- a/gql_query.go +++ b/gql_query.go @@ -6,7 +6,7 @@ import ( var GQLQuerySelf = &graphql.Field{ Type: GQLTypeGQLThread.Type, Resolve: func(p graphql.ResolveParams) (interface{}, error) { - ctx, err := GetResolveContext(p) + ctx, err := PrepResolve(p) if err != nil { return nil, err } @@ -23,7 +23,7 @@ var GQLQuerySelf = &graphql.Field{ var GQLQueryUser = &graphql.Field{ Type: GQLTypeUser.Type, Resolve: func(p graphql.ResolveParams) (interface{}, error) { - ctx, err := GetResolveContext(p) + ctx, err := PrepResolve(p) if err != nil { return nil, err } diff --git a/gql_resolvers.go b/gql_resolvers.go index c6ce781..4c57376 100644 --- a/gql_resolvers.go +++ b/gql_resolvers.go @@ -5,7 +5,7 @@ import ( "github.com/graphql-go/graphql" ) -func GetResolveContext(p graphql.ResolveParams) (*ResolveContext, error) { +func PrepResolve(p graphql.ResolveParams) (*ResolveContext, error) { resolve_context, ok := p.Context.Value("resolve").(*ResolveContext) if ok == false { return nil, fmt.Errorf("Bad resolve in params context") @@ -43,28 +43,42 @@ func ExtractID(p graphql.ResolveParams, name string) (NodeID, error) { } func GQLNodeID(p graphql.ResolveParams) (interface{}, error) { + ctx, err := PrepResolve(p) + if err != nil { + return nil, err + } + node, ok := p.Source.(Node) if ok == false || node == nil { return nil, fmt.Errorf("Failed to cast source to Node") } + + err = UseStates(ctx.Context, []Node{node, ctx.User}, func(nodes NodeMap) error { + return node.Allowed("read", "id", ctx.User) + }) + if err != nil { + return nil, err + } + return node.ID(), nil } func GQLThreadListen(p graphql.ResolveParams) (interface{}, error) { + ctx, err := PrepResolve(p) + if err != nil { + return nil, err + } + node, ok := p.Source.(*GQLThread) if ok == false || node == nil { return nil, fmt.Errorf("Failed to cast source to GQLThread") } - ctx, ok := p.Context.Value("graph_context").(*Context) - if ok == false { - return nil, fmt.Errorf("Failed to cast context graph_context to Context") - } listen := "" - err := UseStates(ctx, []Node{node}, func(nodes NodeMap) (error) { + err = UseStates(ctx.Context, []Node{node, ctx.User}, func(nodes NodeMap) error { listen = node.Listen - return nil + return node.Allowed("read", "listen", ctx.User) }) if err != nil { @@ -75,20 +89,20 @@ func GQLThreadListen(p graphql.ResolveParams) (interface{}, error) { } func GQLThreadParent(p graphql.ResolveParams) (interface{}, error) { + ctx, err := PrepResolve(p) + if err != nil { + return nil, err + } + node, ok := p.Source.(Thread) if ok == false || node == nil { return nil, fmt.Errorf("Failed to cast source to Thread") } - ctx, ok := p.Context.Value("graph_context").(*Context) - if ok == false { - return nil, fmt.Errorf("Failed to cast context graph_context to Context") - } - var parent Thread = nil - err := UseStates(ctx, []Node{node}, func(nodes NodeMap) (error) { + err = UseStates(ctx.Context, []Node{node, ctx.User}, func(nodes NodeMap) (error) { parent = node.Parent() - return nil + return node.Allowed("read", "parent", ctx.User) }) if err != nil { @@ -99,20 +113,20 @@ func GQLThreadParent(p graphql.ResolveParams) (interface{}, error) { } func GQLThreadState(p graphql.ResolveParams) (interface{}, error) { + ctx, err := PrepResolve(p) + if err != nil { + return nil, err + } + node, ok := p.Source.(Thread) if ok == false || node == nil { return nil, fmt.Errorf("Failed to cast source to Thread") } - ctx, ok := p.Context.Value("graph_context").(*Context) - if ok == false { - return nil, fmt.Errorf("Failed to cast context graph_context to Context") - } - var state string - err := UseStates(ctx, []Node{node}, func(nodes NodeMap) (error) { + err = UseStates(ctx.Context, []Node{node, ctx.User}, func(nodes NodeMap) (error) { state = node.State() - return nil + return node.Allowed("read", "state", ctx.User) }) if err != nil { @@ -123,20 +137,20 @@ func GQLThreadState(p graphql.ResolveParams) (interface{}, error) { } func GQLThreadChildren(p graphql.ResolveParams) (interface{}, error) { + ctx, err := PrepResolve(p) + if err != nil { + return nil, err + } + node, ok := p.Source.(Thread) if ok == false || node == nil { return nil, fmt.Errorf("Failed to cast source to Thread") } - ctx, ok := p.Context.Value("graph_context").(*Context) - if ok == false { - return nil, fmt.Errorf("Failed to cast context graph_context to Context") - } - var children []Thread = nil - err := UseStates(ctx, []Node{node}, func(nodes NodeMap) (error) { + err = UseStates(ctx.Context, []Node{node, ctx.User}, func(nodes NodeMap) (error) { children = node.Children() - return nil + return node.Allowed("read", "children", ctx.User) }) if err != nil { @@ -147,20 +161,20 @@ func GQLThreadChildren(p graphql.ResolveParams) (interface{}, error) { } func GQLLockableName(p graphql.ResolveParams) (interface{}, error) { - node, ok := p.Source.(Lockable) - if ok == false || node == nil { - return nil, fmt.Errorf("Failed to cast source to Lockable") + ctx, err := PrepResolve(p) + if err != nil { + return nil, err } - ctx, ok := p.Context.Value("graph_context").(*Context) + node, ok := p.Source.(Lockable) if ok == false || node == nil { - return nil, fmt.Errorf("Failed to cast context graph_context to Context") + return nil, fmt.Errorf("Failed to cast source to Lockable") } name := "" - err := UseStates(ctx, []Node{node}, func(nodes NodeMap) error { + err = UseStates(ctx.Context, []Node{node, ctx.User}, func(nodes NodeMap) error { name = node.Name() - return nil + return node.Allowed("read", "name", ctx.User) }) if err != nil { @@ -171,20 +185,20 @@ func GQLLockableName(p graphql.ResolveParams) (interface{}, error) { } func GQLLockableRequirements(p graphql.ResolveParams) (interface{}, error) { + ctx, err := PrepResolve(p) + if err != nil { + return nil, err + } + node, ok := p.Source.(Lockable) if ok == false || node == nil { return nil, fmt.Errorf("Failed to cast source to Lockable") } - ctx, ok := p.Context.Value("graph_context").(*Context) - if ok == false { - return nil, fmt.Errorf("Failed to cast context graph_context to Context") - } - var requirements []Lockable = nil - err := UseStates(ctx, []Node{node}, func(nodes NodeMap) (error) { + err = UseStates(ctx.Context, []Node{node, ctx.User}, func(nodes NodeMap) (error) { requirements = node.Requirements() - return nil + return node.Allowed("read", "requirements", ctx.User) }) if err != nil { @@ -195,20 +209,20 @@ func GQLLockableRequirements(p graphql.ResolveParams) (interface{}, error) { } func GQLLockableDependencies(p graphql.ResolveParams) (interface{}, error) { + ctx, err := PrepResolve(p) + if err != nil { + return nil, err + } + node, ok := p.Source.(Lockable) if ok == false || node == nil { return nil, fmt.Errorf("Failed to cast source to Lockable") } - ctx, ok := p.Context.Value("graph_context").(*Context) - if ok == false { - return nil, fmt.Errorf("Failed to cast context graph_context to Context") - } - var dependencies []Lockable = nil - err := UseStates(ctx, []Node{node}, func(nodes NodeMap) (error) { + err = UseStates(ctx.Context, []Node{node, ctx.User}, func(nodes NodeMap) (error) { dependencies = node.Dependencies() - return nil + return node.Allowed("read", "dependencies", ctx.User) }) if err != nil { @@ -219,20 +233,20 @@ func GQLLockableDependencies(p graphql.ResolveParams) (interface{}, error) { } func GQLLockableOwner(p graphql.ResolveParams) (interface{}, error) { + ctx, err := PrepResolve(p) + if err != nil { + return nil, err + } + node, ok := p.Source.(Lockable) if ok == false || node == nil { return nil, fmt.Errorf("Failed to cast source to Lockable") } - ctx, ok := p.Context.Value("graph_context").(*Context) - if ok == false { - return nil, fmt.Errorf("Failed to cast context graph_context to Context") - } - var owner Node = nil - err := UseStates(ctx, []Node{node}, func(nodes NodeMap) (error) { + err = UseStates(ctx.Context, []Node{node, ctx.User}, func(nodes NodeMap) (error) { owner = node.Owner() - return nil + return node.Allowed("read", "owner", ctx.User) }) if err != nil { @@ -243,25 +257,25 @@ func GQLLockableOwner(p graphql.ResolveParams) (interface{}, error) { } func GQLThreadUsers(p graphql.ResolveParams) (interface{}, error) { + ctx, err := PrepResolve(p) + if err != nil { + return nil, err + } + node, ok := p.Source.(*GQLThread) if ok == false || node == nil { return nil, fmt.Errorf("Failed to cast source to GQLThread") } - ctx, ok := p.Context.Value("graph_context").(*Context) - if ok == false { - return nil, fmt.Errorf("Failed to cast context graph_context to Context") - } - var users []*User - err := UseStates(ctx, []Node{node}, func(nodes NodeMap) error { + err = UseStates(ctx.Context, []Node{node, ctx.User}, func(nodes NodeMap) error { users = make([]*User, len(node.Users)) i := 0 for _, user := range(node.Users) { users[i] = user i += 1 } - return nil + return node.Allowed("read", "users", ctx.User) }) if err != nil { diff --git a/gql_subscribe.go b/gql_subscribe.go index 46f99c4..04be99c 100644 --- a/gql_subscribe.go +++ b/gql_subscribe.go @@ -1,6 +1,5 @@ package graphvent import ( - "fmt" "github.com/graphql-go/graphql" ) @@ -17,19 +16,14 @@ func GQLSubscribeSelf(p graphql.ResolveParams) (interface{}, error) { } func GQLSubscribeFn(p graphql.ResolveParams, send_nil bool, fn func(*Context, *GQLThread, GraphSignal, graphql.ResolveParams)(interface{}, error))(interface{}, error) { - server, ok := p.Context.Value("gql_server").(*GQLThread) - if ok == false { - return nil, fmt.Errorf("Failed to get gql_server from context and cast to GQLServer") - } - - ctx, ok := p.Context.Value("graph_context").(*Context) - if ok == false { - return nil, fmt.Errorf("Failed to get graph_context from context and cast to Context") + ctx, err := PrepResolve(p) + if err != nil { + return nil, err } c := make(chan interface{}) go func(c chan interface{}, server *GQLThread) { - ctx.Log.Logf("gqlws", "GQL_SUBSCRIBE_THREAD_START") + ctx.Context.Log.Logf("gqlws", "GQL_SUBSCRIBE_THREAD_START") sig_c := UpdateChannel(server, 1, RandID()) if send_nil == true { sig_c <- nil @@ -39,14 +33,14 @@ func GQLSubscribeFn(p graphql.ResolveParams, send_nil bool, fn func(*Context, *G if ok == false { return } - ret, err := fn(ctx, server, val, p) + ret, err := fn(ctx.Context, server, val, p) if err != nil { - ctx.Log.Logf("gqlws", "type convertor error %s", err) + ctx.Context.Log.Logf("gqlws", "type convertor error %s", err) return } c <- ret } - }(c, server) + }(c, ctx.Server) return c, nil } diff --git a/node.go b/node.go index 4248621..08b7cbd 100644 --- a/node.go +++ b/node.go @@ -406,21 +406,22 @@ func LoadNodeRecurse(ctx * Context, id NodeID, nodes NodeMap) (Node, error) { return node, nil } -// Internal function to check for a duplicate node in a slice by ID -func checkForDuplicate(nodes []Node) error { +// Internal function to filter duplicate nodes from a list +func filterDuplicates(nodes []Node) []Node { + ret := []Node{} found := map[NodeID]bool{} for _, node := range(nodes) { if node == nil { - return fmt.Errorf("Cannot get state of nil node") + return []Node{} } _, exists := found[node.ID()] - if exists == true { - return fmt.Errorf("Attempted to get state of %s twice", node.ID()) + if exists == false { + found[node.ID()] = true + ret = append(ret, node) } - found[node.ID()] = true } - return nil + return ret } // Convert any slice of types that implement Node to a []Node @@ -443,10 +444,7 @@ func UseStates(ctx * Context, init_nodes []Node, nodes_fn NodesFn) error { // Add nodes to an existing read context and call nodes_fn with new_nodes locked for read func UseMoreStates(ctx * Context, new_nodes []Node, nodes NodeMap, nodes_fn NodesFn) error { - err := checkForDuplicate(new_nodes) - if err != nil { - return err - } + new_nodes = filterDuplicates(new_nodes) locked_nodes := []Node{} for _, node := range(new_nodes) { @@ -458,7 +456,7 @@ func UseMoreStates(ctx * Context, new_nodes []Node, nodes NodeMap, nodes_fn Node } } - err = nodes_fn(nodes) + err := nodes_fn(nodes) for _, node := range(locked_nodes) { delete(nodes, node.ID())