Skip to content

Commit

Permalink
Move anchor server to pkg/anchor/server.go.
Browse files Browse the repository at this point in the history
  • Loading branch information
lthibault committed Jul 24, 2023
1 parent 80a8d3a commit fda982b
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 95 deletions.
95 changes: 0 additions & 95 deletions pkg/anchor/anchor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package anchor

import (
"context"
"errors"

"capnproto.org/go/capnp/v3"
api "github.com/wetware/ww/api/anchor"
Expand Down Expand Up @@ -103,97 +102,3 @@ func (it *Iterator) Anchor() Anchor {

return Anchor{}
}

/*---------------------------*
| |
| Server Implementation |
| |
*----------------------------*/

type server struct{ *Node }

func (s server) Shutdown() {
s.Release() // nodeHook holds the lock when shutting down.
}

func (s server) Ls(ctx context.Context, call api.Anchor_ls) error {
s.Lock()
defer s.Unlock()

children := s.children

if len(children) == 0 {
return nil
}

res, err := call.AllocResults()
if err != nil {
return err
}

cs, err := res.NewChildren(int32(len(children)))
if err != nil {
return err
}

var index int
for name, child := range children {
if err = cs.At(index).SetName(name); err != nil {
break
}

if err = cs.At(index).SetAnchor(anchor(child)); err != nil {
break
}

index++
}

return err
}

// FIXME: there is currently a vector for resource-exhaustion attacks.
// We don't enforce a maximum depth on anchors, nor do we enforce a max
// number of children per node. An attacker can exploit this by walking
// an arbitrarily long path and/or by creating arbitrarily many anchors,
// ultimately exhausting the attacker's memory.
func (s server) Walk(ctx context.Context, call api.Anchor_walk) error {
path := newPath(call)
if path.Err() != nil {
return path.Err()
}

res, err := call.AllocResults()
if err != nil {
return err
}

// Iteratively "walk" to designated path. It's important to avoid
// recursion, so that RPCs can't blow up the stack.
//
// Each iteration of the loop shadows the n symbol, including its
// embedded node, such that we are holding the final node when we
// exit the loop.
for path, name := path.Next(); name != ""; path, name = path.Next() {
s.Node = s.Child(name) // shallow copy
}

return res.SetAnchor(anchor(s))
}

func (s server) Cell(ctx context.Context, call api.Anchor_cell) error {
return errors.New("NOT IMPLEMENTED") // TODO(soon): implement Anchor.Cell()
}

func anchor(n interface{ Anchor() Anchor }) api.Anchor {
return api.Anchor(n.Anchor())
}

func newPath(call api.Anchor_walk) Path {
path, err := call.Args().Path()
if err != nil {
return failure(err)
}

return NewPath(path)
}
96 changes: 96 additions & 0 deletions pkg/anchor/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package anchor

import (
"context"
"errors"

api "github.com/wetware/ww/api/anchor"
)

type server struct{ *Node }

func (s server) Shutdown() {
s.Release() // nodeHook holds the lock when shutting down.
}

func (s server) Ls(ctx context.Context, call api.Anchor_ls) error {
s.Lock()
defer s.Unlock()

children := s.children

if len(children) == 0 {
return nil
}

res, err := call.AllocResults()
if err != nil {
return err
}

cs, err := res.NewChildren(int32(len(children)))
if err != nil {
return err
}

var index int
for name, child := range children {
if err = cs.At(index).SetName(name); err != nil {
break
}

if err = cs.At(index).SetAnchor(anchor(child)); err != nil {
break
}

index++
}

return err
}

// FIXME: there is currently a vector for resource-exhaustion attacks.
// We don't enforce a maximum depth on anchors, nor do we enforce a max
// number of children per node. An attacker can exploit this by walking
// an arbitrarily long path and/or by creating arbitrarily many anchors,
// ultimately exhausting the attacker's memory.
func (s server) Walk(ctx context.Context, call api.Anchor_walk) error {
path := newPath(call)
if path.Err() != nil {
return path.Err()
}

res, err := call.AllocResults()
if err != nil {
return err
}

// Iteratively "walk" to designated path. It's important to avoid
// recursion, so that RPCs can't blow up the stack.
//
// Each iteration of the loop shadows the n symbol, including its
// embedded node, such that we are holding the final node when we
// exit the loop.
for path, name := path.Next(); name != ""; path, name = path.Next() {
s.Node = s.Child(name) // shallow copy
}

return res.SetAnchor(anchor(s))
}

func (s server) Cell(ctx context.Context, call api.Anchor_cell) error {
return errors.New("NOT IMPLEMENTED") // TODO(soon): implement Anchor.Cell()
}

func anchor(n interface{ Anchor() Anchor }) api.Anchor {
return api.Anchor(n.Anchor())
}

func newPath(call api.Anchor_walk) Path {
path, err := call.Args().Path()
if err != nil {
return failure(err)
}

return NewPath(path)
}

0 comments on commit fda982b

Please sign in to comment.