package service import ( "context" "github.com/keys-pub/keys" "github.com/keys-pub/keys/api" "github.com/keys-pub/keys/tsutil" "github.com/pkg/errors" ) // Key (RPC) ... func (s *service) Key(ctx context.Context, req *KeyRequest) (*KeyResponse, error) { kid, err := s.lookup(ctx, req.Key, &lookupOpts{SearchRemote: req.Search}) if err != nil { return nil, err } if req.Update { if _, err := s.updateUser(ctx, kid, false); err != nil { return nil, err } } else { if err := s.checkForExpiredKey(ctx, kid); err != nil { return nil, err } } key, err := s.key(ctx, kid) if err != nil { return nil, err } return &KeyResponse{ Key: key, }, nil } func (s *service) verifyKey(ctx context.Context, kid keys.ID) (*Key, error) { if err := s.ensureUserVerified(ctx, kid); err != nil { return nil, err } return s.key(ctx, kid) } func (s *service) keyToRPC(ctx context.Context, key *api.Key, saved bool) (*Key, error) { if key == nil { return nil, nil } out := &Key{ ID: key.ID.String(), Type: key.Type, Saved: saved, IsPrivate: len(key.Private) > 0, } if err := s.fillKey(ctx, key.ID, out); err != nil { return nil, err } return out, nil } func (s *service) key(ctx context.Context, kid keys.ID) (*Key, error) { key, err := s.vault.Key(kid) if err != nil { return nil, err } if key != nil { return s.keyToRPC(ctx, key, true) } return s.keyToRPC(ctx, api.NewKey(kid), false) } func (s *service) fillKey(ctx context.Context, kid keys.ID, key *Key) error { res, err := s.users.Get(ctx, kid) if err != nil { return err } key.User = userResultToRPC(res) // Sigchain info sc, err := s.scs.Sigchain(kid) if err != nil { return err } if sc != nil { key.SigchainLength = int32(sc.Length()) last := sc.Last() if last != nil { key.SigchainUpdatedAt = tsutil.Millis(last.Timestamp) } } return nil } // KeyRemove (RPC) removes a key. func (s *service) KeyRemove(ctx context.Context, req *KeyRemoveRequest) (*KeyRemoveResponse, error) { if req.KID == "" { return nil, errors.Errorf("kid not specified") } kid, err := keys.ParseID(req.KID) if err != nil { return nil, err } ok, err := s.vault.Delete(kid.String()) if err != nil { return nil, err } if !ok { return nil, keys.NewErrNotFound(kid.String()) } if kid.IsEdX25519() { _, err = s.scs.Delete(kid) if err != nil { return nil, err } if _, err := s.users.Update(ctx, kid); err != nil { return nil, err } } return &KeyRemoveResponse{}, nil } // KeyGenerate (RPC) creates a key. func (s *service) KeyGenerate(ctx context.Context, req *KeyGenerateRequest) (*KeyGenerateResponse, error) { if req.Type == "" { return nil, errors.Errorf("no key type specified") } var key keys.Key switch req.Type { case string(keys.EdX25519): key = keys.GenerateEdX25519Key() case string(keys.X25519): key = keys.GenerateX25519Key() default: return nil, errors.Errorf("unknown key type %s", req.Type) } vk := api.NewKey(key) now := s.clock.NowMillis() vk.CreatedAt = now vk.UpdatedAt = now if err := s.vault.SaveKey(vk); err != nil { return nil, err } if err := s.scs.Index(vk.ID); err != nil { return nil, err } return &KeyGenerateResponse{ KID: vk.ID.String(), }, nil } func (s *service) parseKID(kid string) (keys.ID, error) { if kid == "" { return "", errors.Errorf("no kid specified") } id, err := keys.ParseID(kid) if err != nil { return "", err } return id, nil } // convertIfX25519ID checks if the ID is a X25519 public key, finds the EdX25519 public key // equivalent if found, otherwise returns itself. func (s *service) convertIfX25519ID(kid keys.ID) (keys.ID, error) { if kid == "" { return "", nil } if kid.IsX25519() { logger.Debugf("Convert sender %s", kid) spk, err := s.vault.FindEdX25519PublicKey(kid) if err != nil { return "", err } if spk == nil { logger.Debugf("No edx25519 key found for %s", kid) // Not found, return original id. return kid, nil } logger.Debugf("Found edx25519 key %s (for %s)", spk, kid) return spk.ID(), nil } return kid, nil } func (s *service) vaultKey(kid keys.ID) (*api.Key, error) { if kid == "" { return nil, nil } key, err := s.vault.Key(kid) if err != nil { return nil, err } if key == nil { return nil, keys.NewErrNotFound(kid.String()) } return key, nil } func (s *service) edx25519Key(kid keys.ID) (*keys.EdX25519Key, error) { if kid == "" { return nil, nil } key, err := s.vault.Key(kid) if err != nil { return nil, err } if key == nil { return nil, keys.NewErrNotFound(kid.String()) } sk := key.AsEdX25519() if sk == nil { return nil, keys.NewErrNotFound(kid.String()) } return sk, nil } func (s *service) x25519Key(kid keys.ID) (*keys.X25519Key, error) { if kid == "" { return nil, nil } key, err := s.vault.Key(kid) if err != nil { return nil, err } if key == nil { return nil, keys.NewErrNotFound(kid.String()) } bk := key.AsX25519() if bk == nil { return nil, keys.NewErrNotFound(kid.String()) } return bk, nil } func (k *Key) userName() string { if k.User != nil && k.User.ID != "" { return k.User.ID } return k.ID } // func keyUserNames(ks []*Key) []string { // out := []string{} // for _, k := range ks { // out = append(out, k.userName()) // } // return out // }