forked from tangled.org/core
Monorepo for Tangled — https://tangled.org

appview,rbac: ingest sh.tangled.knot{,member} records

The knot.member is only ingested for create/update ops but we can't
delete it yet. See comment.

Signed-off-by: Anirudh Oppiliappan <anirudh@tangled.sh>

Changed files
+160
appview
+160
appview/ingester.go
···
err = i.ingestSpindleMember(e)
case tangled.SpindleNSID:
err = i.ingestSpindle(e)
+
case tangled.KnotMemberNSID:
+
err = i.ingestKnotMember(e)
+
case tangled.KnotNSID:
+
err = i.ingestKnot(e)
case tangled.StringNSID:
err = i.ingestString(e)
}
···
return nil
}
+
+
func (i *Ingester) ingestKnotMember(e *models.Event) error {
+
did := e.Did
+
var err error
+
+
l := i.Logger.With("handler", "ingestKnotMember")
+
l = l.With("nsid", e.Commit.Collection)
+
+
switch e.Commit.Operation {
+
case models.CommitOperationCreate:
+
raw := json.RawMessage(e.Commit.Record)
+
record := tangled.KnotMember{}
+
err = json.Unmarshal(raw, &record)
+
if err != nil {
+
l.Error("invalid record", "err", err)
+
return err
+
}
+
+
// only knot owner can invite to knots
+
ok, err := i.Enforcer.IsKnotInviteAllowed(did, record.Domain)
+
if err != nil || !ok {
+
return fmt.Errorf("failed to enforce permissions: %w", err)
+
}
+
+
memberId, err := i.IdResolver.ResolveIdent(context.Background(), record.Subject)
+
if err != nil {
+
return err
+
}
+
+
if memberId.Handle.IsInvalidHandle() {
+
return err
+
}
+
+
err = i.Enforcer.AddKnotMember(record.Domain, memberId.DID.String())
+
if err != nil {
+
return fmt.Errorf("failed to update ACLs: %w", err)
+
}
+
+
l.Info("added knot member")
+
case models.CommitOperationDelete:
+
// we don't store knot members in a table (like we do for spindle)
+
// and we can't remove this just yet. possibly fixed if we switch
+
// to either:
+
// 1. a knot_members table like with spindle and store the rkey
+
// 2. use the knot host as the rkey
+
//
+
// TODO: implement member deletion
+
l.Info("skipping knot member delete", "did", did, "rkey", e.Commit.RKey)
+
}
+
+
return nil
+
}
+
+
func (i *Ingester) ingestKnot(e *models.Event) error {
+
did := e.Did
+
var err error
+
+
l := i.Logger.With("handler", "ingestKnot")
+
l = l.With("nsid", e.Commit.Collection)
+
+
switch e.Commit.Operation {
+
case models.CommitOperationCreate:
+
raw := json.RawMessage(e.Commit.Record)
+
record := tangled.Knot{}
+
err = json.Unmarshal(raw, &record)
+
if err != nil {
+
l.Error("invalid record", "err", err)
+
return err
+
}
+
+
domain := e.Commit.RKey
+
+
ddb, ok := i.Db.Execer.(*db.DB)
+
if !ok {
+
return fmt.Errorf("failed to index profile record, invalid db cast")
+
}
+
+
err := db.AddKnot(ddb, domain, did)
+
if err != nil {
+
l.Error("failed to add knot to db", "err", err, "domain", domain)
+
return err
+
}
+
+
err = serververify.RunVerification(context.Background(), domain, did, i.Config.Core.Dev)
+
if err != nil {
+
l.Error("failed to verify knot", "err", err, "domain", domain)
+
return err
+
}
+
+
err = serververify.MarkKnotVerified(ddb, i.Enforcer, domain, did)
+
if err != nil {
+
return fmt.Errorf("failed to mark verified: %w", err)
+
}
+
+
return nil
+
+
case models.CommitOperationDelete:
+
domain := e.Commit.RKey
+
+
ddb, ok := i.Db.Execer.(*db.DB)
+
if !ok {
+
return fmt.Errorf("failed to index knot record, invalid db cast")
+
}
+
+
// get record from db first
+
registrations, err := db.GetRegistrations(
+
ddb,
+
db.FilterEq("domain", domain),
+
db.FilterEq("did", did),
+
)
+
if err != nil {
+
return fmt.Errorf("failed to get registration: %w", err)
+
}
+
if len(registrations) != 1 {
+
return fmt.Errorf("got incorret number of registrations: %d, expected 1", len(registrations))
+
}
+
registration := registrations[0]
+
+
tx, err := ddb.Begin()
+
if err != nil {
+
return err
+
}
+
defer func() {
+
tx.Rollback()
+
i.Enforcer.E.LoadPolicy()
+
}()
+
+
err = db.DeleteKnot(
+
tx,
+
db.FilterEq("did", did),
+
db.FilterEq("domain", domain),
+
)
+
if err != nil {
+
return err
+
}
+
+
if registration.Registered != nil {
+
err = i.Enforcer.RemoveKnot(domain)
+
if err != nil {
+
return err
+
}
+
}
+
+
err = tx.Commit()
+
if err != nil {
+
return err
+
}
+
+
err = i.Enforcer.E.SavePolicy()
+
if err != nil {
+
return err
+
}
+
}
+
+
return nil
+
}