package service import ( "context" "github.com/keys-pub/keys" "github.com/keys-pub/keys/tsutil" "github.com/pkg/errors" ) // Sigchain (RPC) ... func (s *service) Sigchain(ctx context.Context, req *SigchainRequest) (*SigchainResponse, error) { kid, err := s.parseKID(req.KID) if err != nil { return nil, err } key, err := s.key(ctx, kid) if err != nil { return nil, err } sc, err := s.scs.Sigchain(kid) if err != nil { return nil, err } stsOut := statementsToRPC(sc.Statements()) return &SigchainResponse{ Key: key, Statements: stsOut, }, nil } func statementFromRPC(st *Statement) (*keys.Statement, error) { ts := tsutil.ParseMillis(st.Timestamp) kid, err := keys.ParseID(st.KID) if err != nil { return nil, err } return &keys.Statement{ Sig: st.Sig, Data: st.Data, KID: kid, Seq: int(st.Seq), Prev: st.Prev, Revoke: int(st.Revoke), Type: st.Type, Timestamp: ts, }, nil } // statementsFromRPC converts Statement's to keys.Statement's. func statementsFromRPC(sts []*Statement) ([]*keys.Statement, error) { stsOut := make([]*keys.Statement, 0, len(sts)) for _, st := range sts { stOut, err := statementFromRPC(st) if err != nil { return nil, err } stsOut = append(stsOut, stOut) } return stsOut, nil } func statementToRPC(st *keys.Statement) *Statement { return &Statement{ Sig: st.Sig, Data: st.Data, KID: st.KID.String(), Seq: int32(st.Seq), Prev: st.Prev, Revoke: int32(st.Revoke), Timestamp: tsutil.Millis(st.Timestamp), Type: st.Type, } } func statementsToRPC(sts []*keys.Statement) []*Statement { stsOut := make([]*Statement, 0, len(sts)) for _, st := range sts { stsOut = append(stsOut, statementToRPC(st)) } return stsOut } func sigchainFromRPC(kid keys.ID, ssts []*Statement) (*keys.Sigchain, error) { logger.Infof("Resolving sigchain from statements") sc := keys.NewSigchain(kid) sts, err := statementsFromRPC(ssts) if err != nil { return nil, err } if err := sc.AddAll(sts); err != nil { return nil, errors.Wrapf(err, "failed to resolve sigchain from statements") } return sc, nil } // Sigchain (RPC) ... func (s *service) Statement(ctx context.Context, req *StatementRequest) (*StatementResponse, error) { kid, err := s.parseKID(req.KID) if err != nil { return nil, err } sc, err := s.scs.Sigchain(kid) if err != nil { return nil, err } if sc == nil { return nil, keys.NewErrNotFound(kid.String()) } stsOut := statementsToRPC(sc.Statements()) if req.Seq < 0 { return nil, errors.Errorf("invalid seq") } if req.Seq == 0 { return nil, errors.Errorf("no seq specified") } if int(req.Seq-1) >= len(stsOut) { return nil, errors.Errorf("seq too large") } return &StatementResponse{ Statement: stsOut[req.Seq-1], }, nil } // StatementCreate (RPC) ... func (s *service) StatementCreate(ctx context.Context, req *StatementCreateRequest) (*StatementCreateResponse, error) { if req.KID == "" { return nil, errors.Errorf("no kid specified") } kid, err := keys.ParseID(req.KID) if err != nil { return nil, err } key, err := s.edx25519Key(kid) if err != nil { return nil, err } if key == nil { return nil, keys.NewErrNotFound(req.KID) } sc, err := s.scs.Sigchain(key.ID()) if err != nil { return nil, err } st, err := keys.NewSigchainStatement(sc, req.Data, key, "", s.clock.Now()) if err != nil { return nil, err } if err := sc.Add(st); err != nil { return nil, err } if !req.Local { if err := s.client.SigchainSave(ctx, st); err != nil { return nil, err } } if err := s.scs.Save(sc); err != nil { return nil, err } stOut := statementToRPC(st) return &StatementCreateResponse{ Statement: stOut, }, nil } // StatementRevoke (RPC) ... func (s *service) StatementRevoke(ctx context.Context, req *StatementRevokeRequest) (*StatementRevokeResponse, error) { kid, err := keys.ParseID(req.KID) if err != nil { return nil, err } key, err := s.edx25519Key(kid) if err != nil { return nil, err } sc, err := s.scs.Sigchain(key.ID()) if err != nil { return nil, err } st, err := sc.Revoke(int(req.Seq), key) if err != nil { return nil, err } if !req.Local { if err := s.client.SigchainSave(ctx, st); err != nil { return nil, err } } if err := s.scs.Save(sc); err != nil { return nil, err } if _, err = s.users.Update(ctx, key.ID()); err != nil { return nil, err } stOut := statementToRPC(st) return &StatementRevokeResponse{ Statement: stOut, }, nil }