forked from tangled.org/core
this repo has no description

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>

authored by anirudh.fi and committed by oppi.li 9b23cf54 3d9fc547

Changed files
+160
appview
+160
appview/ingester.go
··· 64 64 err = i.ingestSpindleMember(e) 65 65 case tangled.SpindleNSID: 66 66 err = i.ingestSpindle(e) 67 + case tangled.KnotMemberNSID: 68 + err = i.ingestKnotMember(e) 69 + case tangled.KnotNSID: 70 + err = i.ingestKnot(e) 67 71 case tangled.StringNSID: 68 72 err = i.ingestString(e) 69 73 } ··· 609 613 610 614 return nil 611 615 } 616 + 617 + func (i *Ingester) ingestKnotMember(e *models.Event) error { 618 + did := e.Did 619 + var err error 620 + 621 + l := i.Logger.With("handler", "ingestKnotMember") 622 + l = l.With("nsid", e.Commit.Collection) 623 + 624 + switch e.Commit.Operation { 625 + case models.CommitOperationCreate: 626 + raw := json.RawMessage(e.Commit.Record) 627 + record := tangled.KnotMember{} 628 + err = json.Unmarshal(raw, &record) 629 + if err != nil { 630 + l.Error("invalid record", "err", err) 631 + return err 632 + } 633 + 634 + // only knot owner can invite to knots 635 + ok, err := i.Enforcer.IsKnotInviteAllowed(did, record.Domain) 636 + if err != nil || !ok { 637 + return fmt.Errorf("failed to enforce permissions: %w", err) 638 + } 639 + 640 + memberId, err := i.IdResolver.ResolveIdent(context.Background(), record.Subject) 641 + if err != nil { 642 + return err 643 + } 644 + 645 + if memberId.Handle.IsInvalidHandle() { 646 + return err 647 + } 648 + 649 + err = i.Enforcer.AddKnotMember(record.Domain, memberId.DID.String()) 650 + if err != nil { 651 + return fmt.Errorf("failed to update ACLs: %w", err) 652 + } 653 + 654 + l.Info("added knot member") 655 + case models.CommitOperationDelete: 656 + // we don't store knot members in a table (like we do for spindle) 657 + // and we can't remove this just yet. possibly fixed if we switch 658 + // to either: 659 + // 1. a knot_members table like with spindle and store the rkey 660 + // 2. use the knot host as the rkey 661 + // 662 + // TODO: implement member deletion 663 + l.Info("skipping knot member delete", "did", did, "rkey", e.Commit.RKey) 664 + } 665 + 666 + return nil 667 + } 668 + 669 + func (i *Ingester) ingestKnot(e *models.Event) error { 670 + did := e.Did 671 + var err error 672 + 673 + l := i.Logger.With("handler", "ingestKnot") 674 + l = l.With("nsid", e.Commit.Collection) 675 + 676 + switch e.Commit.Operation { 677 + case models.CommitOperationCreate: 678 + raw := json.RawMessage(e.Commit.Record) 679 + record := tangled.Knot{} 680 + err = json.Unmarshal(raw, &record) 681 + if err != nil { 682 + l.Error("invalid record", "err", err) 683 + return err 684 + } 685 + 686 + domain := e.Commit.RKey 687 + 688 + ddb, ok := i.Db.Execer.(*db.DB) 689 + if !ok { 690 + return fmt.Errorf("failed to index profile record, invalid db cast") 691 + } 692 + 693 + err := db.AddKnot(ddb, domain, did) 694 + if err != nil { 695 + l.Error("failed to add knot to db", "err", err, "domain", domain) 696 + return err 697 + } 698 + 699 + err = serververify.RunVerification(context.Background(), domain, did, i.Config.Core.Dev) 700 + if err != nil { 701 + l.Error("failed to verify knot", "err", err, "domain", domain) 702 + return err 703 + } 704 + 705 + err = serververify.MarkKnotVerified(ddb, i.Enforcer, domain, did) 706 + if err != nil { 707 + return fmt.Errorf("failed to mark verified: %w", err) 708 + } 709 + 710 + return nil 711 + 712 + case models.CommitOperationDelete: 713 + domain := e.Commit.RKey 714 + 715 + ddb, ok := i.Db.Execer.(*db.DB) 716 + if !ok { 717 + return fmt.Errorf("failed to index knot record, invalid db cast") 718 + } 719 + 720 + // get record from db first 721 + registrations, err := db.GetRegistrations( 722 + ddb, 723 + db.FilterEq("domain", domain), 724 + db.FilterEq("did", did), 725 + ) 726 + if err != nil { 727 + return fmt.Errorf("failed to get registration: %w", err) 728 + } 729 + if len(registrations) != 1 { 730 + return fmt.Errorf("got incorret number of registrations: %d, expected 1", len(registrations)) 731 + } 732 + registration := registrations[0] 733 + 734 + tx, err := ddb.Begin() 735 + if err != nil { 736 + return err 737 + } 738 + defer func() { 739 + tx.Rollback() 740 + i.Enforcer.E.LoadPolicy() 741 + }() 742 + 743 + err = db.DeleteKnot( 744 + tx, 745 + db.FilterEq("did", did), 746 + db.FilterEq("domain", domain), 747 + ) 748 + if err != nil { 749 + return err 750 + } 751 + 752 + if registration.Registered != nil { 753 + err = i.Enforcer.RemoveKnot(domain) 754 + if err != nil { 755 + return err 756 + } 757 + } 758 + 759 + err = tx.Commit() 760 + if err != nil { 761 + return err 762 + } 763 + 764 + err = i.Enforcer.E.SavePolicy() 765 + if err != nil { 766 + return err 767 + } 768 + } 769 + 770 + return nil 771 + }