1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4// Export-Import for RPC stubs
5
6package libkb
7
8import (
9	"encoding/hex"
10	"encoding/json"
11	"errors"
12	"fmt"
13	"io"
14	"sort"
15	"strconv"
16	"strings"
17	"time"
18
19	"github.com/keybase/client/go/protocol/chat1"
20	"github.com/keybase/client/go/protocol/gregor1"
21	keybase1 "github.com/keybase/client/go/protocol/keybase1"
22	"github.com/keybase/go-crypto/openpgp"
23	pgpErrors "github.com/keybase/go-crypto/openpgp/errors"
24	"github.com/keybase/go-framed-msgpack-rpc/rpc"
25	"golang.org/x/net/context"
26)
27
28func (sh SigHint) Export() *keybase1.SigHint {
29	return &keybase1.SigHint{
30		RemoteId:  sh.remoteID,
31		ApiUrl:    sh.apiURL,
32		HumanUrl:  sh.humanURL,
33		CheckText: sh.checkText,
34	}
35}
36
37func (l LinkCheckResult) ExportToIdentifyRow(i int) keybase1.IdentifyRow {
38	return keybase1.IdentifyRow{
39		RowId:     i,
40		Proof:     ExportRemoteProof(l.link),
41		TrackDiff: ExportTrackDiff(l.diff),
42	}
43}
44
45func (l LinkCheckResult) Export() keybase1.LinkCheckResult {
46	ret := keybase1.LinkCheckResult{
47		ProofId:       l.position,
48		ProofResult:   ExportProofError(l.err),
49		SnoozedResult: ExportProofError(l.snoozedErr),
50		TorWarning:    l.torWarning,
51	}
52	if l.cached != nil {
53		ret.Cached = l.cached.Export()
54	}
55	bt := false
56	if l.diff != nil {
57		ret.Diff = ExportTrackDiff(l.diff)
58		if l.diff.BreaksTracking() {
59			bt = true
60		}
61	}
62	if l.remoteDiff != nil {
63		ret.RemoteDiff = ExportTrackDiff(l.remoteDiff)
64		if l.remoteDiff.BreaksTracking() {
65			bt = true
66		}
67	}
68	if l.hint != nil {
69		ret.Hint = l.GetHint().Export()
70	}
71	ret.TmpTrackExpireTime = keybase1.ToTime(l.tmpTrackExpireTime)
72	ret.BreaksTracking = bt
73	return ret
74}
75
76func (cr CheckResult) Export() *keybase1.CheckResult {
77	return &keybase1.CheckResult{
78		ProofResult: ExportProofError(cr.Status),
79		Time:        keybase1.ToTime(cr.Time),
80		Freshness:   cr.Freshness(),
81	}
82}
83
84func ExportRemoteProof(p RemoteProofChainLink) keybase1.RemoteProof {
85	k, v := p.ToKeyValuePair()
86	return keybase1.RemoteProof{
87		ProofType:     p.GetProofType(),
88		Key:           k,
89		Value:         strings.ToLower(v),
90		DisplayMarkup: v,
91		SigID:         p.GetSigID(),
92		MTime:         keybase1.ToTime(p.GetCTime()),
93	}
94}
95
96func (is IdentifyState) ExportToUncheckedIdentity(mctx MetaContext) *keybase1.Identity {
97	return is.res.ExportToUncheckedIdentity(mctx)
98}
99
100func (ir IdentifyOutcome) ExportToUncheckedIdentity(mctx MetaContext) *keybase1.Identity {
101	tmp := keybase1.Identity{
102		Status: ExportErrorAsStatus(mctx.G(), ir.Error),
103	}
104	if ir.TrackUsed != nil {
105		tmp.WhenLastTracked = keybase1.ToTime(ir.TrackUsed.GetCTime())
106	}
107
108	pc := ir.ProofChecksSorted(mctx)
109	tmp.Proofs = make([]keybase1.IdentifyRow, len(pc))
110	for j, p := range pc {
111		tmp.Proofs[j] = p.ExportToIdentifyRow(j)
112	}
113
114	tmp.Revoked = make([]keybase1.TrackDiff, len(ir.Revoked))
115	for j, d := range ir.Revoked {
116		// Should have all non-nil elements...
117		tmp.Revoked[j] = *ExportTrackDiff(d)
118		if d.BreaksTracking() {
119			tmp.BreaksTracking = true
120		}
121	}
122	tmp.RevokedDetails = ir.RevokedDetails
123	return &tmp
124}
125
126type ExportableError interface {
127	error
128	ToStatus() keybase1.Status
129}
130
131func ExportProofError(pe ProofError) (ret keybase1.ProofResult) {
132	if pe == nil {
133		ret.State = keybase1.ProofState_OK
134		ret.Status = keybase1.ProofStatus_OK
135	} else {
136		ret.Status = pe.GetProofStatus()
137		ret.State = ProofErrorToState(pe)
138		ret.Desc = pe.GetDesc()
139	}
140	return
141}
142
143func ImportProofError(e keybase1.ProofResult) ProofError {
144	ps := e.Status
145	if ps == keybase1.ProofStatus_OK {
146		return nil
147	}
148	return NewProofError(ps, e.Desc)
149}
150
151func ExportErrorAsStatus(g *GlobalContext, e error) (ret *keybase1.Status) {
152	switch e {
153	case nil:
154		return nil
155	case io.EOF:
156		return &keybase1.Status{
157			Code: SCStreamEOF,
158			Name: "STREAM_EOF",
159		}
160	case pgpErrors.ErrKeyIncorrect:
161		return &keybase1.Status{
162			Code: SCKeyNoActive,
163			Name: "SC_KEY_NO_ACTIVE",
164			Desc: "No PGP key found",
165		}
166	case context.Canceled:
167		return &keybase1.Status{
168			Code: SCCanceled,
169			Name: "SC_CANCELED",
170			Desc: "Canceled",
171		}
172	}
173
174	// Before checking to see if an error implements ExportableError, peel off
175	// any wrappers from the `errors` package (KBFS uses these). This is a
176	// no-op for other types.
177	e = HumanError(e)
178	if ee, ok := e.(ExportableError); ok {
179		tmp := ee.ToStatus()
180		return &tmp
181	}
182
183	if g != nil && g.Env.GetRunMode() != ProductionRunMode {
184		g.Log.Warning("not exportable error: %v (%T)", e, e)
185	}
186
187	return &keybase1.Status{
188		Name: "GENERIC",
189		Code: SCGeneric,
190		Desc: e.Error(),
191	}
192}
193
194//=============================================================================
195
196func MakeWrapError(g *GlobalContext) func(e error) interface{} {
197	return func(e error) interface{} {
198		return ExportErrorAsStatus(g, e)
199	}
200}
201
202func WrapError(e error) interface{} {
203	return ExportErrorAsStatus(nil, e)
204}
205
206var _ rpc.WrapErrorFunc = MakeWrapError(nil)
207
208type ErrorUnwrapper struct {
209	Contextified
210}
211
212func NewContextifiedErrorUnwrapper(g *GlobalContext) ErrorUnwrapper {
213	return ErrorUnwrapper{NewContextified(g)}
214
215}
216
217func (c ErrorUnwrapper) MakeArg() interface{} {
218	return &keybase1.Status{}
219}
220
221func (c ErrorUnwrapper) UnwrapError(arg interface{}) (appError error, dispatchError error) {
222	targ, ok := arg.(*keybase1.Status)
223	if !ok {
224		dispatchError = errors.New("Error converting status to keybase1.Status object")
225		return
226	}
227	appError = ImportStatusAsError(c.G(), targ)
228	return
229}
230
231var _ rpc.ErrorUnwrapper = NewContextifiedErrorUnwrapper(nil)
232var _ rpc.ErrorUnwrapper = ErrorUnwrapper{}
233
234//=============================================================================
235
236func ImportStatusAsError(g *GlobalContext, s *keybase1.Status) error {
237	if s == nil {
238		return nil
239	}
240	switch s.Code {
241	case SCOk:
242		return nil
243	case SCGeneric:
244		return errors.New(s.Desc)
245	case SCBadSession:
246		return BadSessionError{s.Desc}
247	case SCBadLoginPassword:
248		return PassphraseError{s.Desc}
249	case SCKeyBadGen:
250		return KeyGenError{s.Desc}
251	case SCAlreadyLoggedIn:
252		return LoggedInError{}
253	case SCCanceled:
254		return CanceledError{s.Desc}
255	case SCInputCanceled:
256		return InputCanceledError{}
257	case SCKeyNoSecret:
258		return NoSecretKeyError{}
259	case SCLoginRequired:
260		return LoginRequiredError{s.Desc}
261	case SCNoSession:
262		return NoSessionError{}
263	case SCKeyCorrupted:
264		return KeyCorruptedError{s.Desc}
265	case SCOffline:
266		return OfflineError{}
267	case SCKeyInUse:
268		var fp *PGPFingerprint
269		if len(s.Desc) > 0 {
270			fp, _ = PGPFingerprintFromHex(s.Desc)
271		}
272		return KeyExistsError{fp}
273	case SCKeyNotFound:
274		return NoKeyError{s.Desc}
275	case SCKeyNoEldest:
276		return NoSigChainError{}
277	case SCStreamExists:
278		return StreamExistsError{}
279	case SCBadInvitationCode:
280		return BadInvitationCodeError{}
281	case SCStreamNotFound:
282		return StreamNotFoundError{}
283	case SCStreamWrongKind:
284		return StreamWrongKindError{}
285	case SCStreamEOF:
286		return io.EOF
287	case SCSelfNotFound:
288		return SelfNotFoundError{msg: s.Desc}
289	case SCDeviceNotFound:
290		return NoDeviceError{Reason: s.Desc}
291	case SCDecryptionKeyNotFound:
292		return NoDecryptionKeyError{Msg: s.Desc}
293	case SCTimeout:
294		return TimeoutError{}
295	case SCDeviceMismatch:
296		return ReceiverDeviceError{Msg: s.Desc}
297	case SCBadKexPhrase:
298		return InvalidKexPhraseError{}
299	case SCReloginRequired:
300		return ReloginRequiredError{}
301	case SCDeviceRequired:
302		return DeviceRequiredError{}
303	case SCMissingResult:
304		return IdentifyDidNotCompleteError{}
305	case SCSibkeyAlreadyExists:
306		return SibkeyAlreadyExistsError{}
307	case SCSigCreationDisallowed:
308		service := ""
309		if len(s.Fields) > 0 && s.Fields[0].Key == "remote_service" {
310			service = s.Fields[0].Value
311		}
312		return ServiceDoesNotSupportNewProofsError{Service: service}
313	case SCNoUI:
314		return NoUIError{Which: s.Desc}
315	case SCNoUIDelegation:
316		return UIDelegationUnavailableError{}
317	case SCProfileNotPublic:
318		return ProfileNotPublicError{msg: s.Desc}
319	case SCIdentifyFailed:
320		var assertion string
321		if len(s.Fields) > 0 && s.Fields[0].Key == "assertion" {
322			assertion = s.Fields[0].Value
323		}
324		return IdentifyFailedError{Assertion: assertion, Reason: s.Desc}
325	case SCIdentifiesFailed:
326		return IdentifiesFailedError{}
327	case SCIdentifySummaryError:
328		ret := IdentifySummaryError{}
329		for _, pair := range s.Fields {
330			if pair.Key == "username" {
331				ret.username = NewNormalizedUsername(pair.Value)
332			} else {
333				// The other keys are expected to be "problem_%d".
334				ret.problems = append(ret.problems, pair.Value)
335			}
336		}
337		return ret
338	case SCTrackingBroke:
339		return TrackingBrokeError{}
340	case SCResolutionFailed:
341		var input string
342		if len(s.Fields) > 0 && s.Fields[0].Key == "input" {
343			input = s.Fields[0].Value
344		}
345		return ResolutionError{Msg: s.Desc, Input: input}
346	case SCAccountReset:
347		var e keybase1.UserVersion
348		var r keybase1.Seqno
349		seqnoFromString := func(s string) keybase1.Seqno {
350			i, _ := strconv.Atoi(s)
351			return keybase1.Seqno(i)
352		}
353		for _, field := range s.Fields {
354			switch field.Key {
355			case "e_uid":
356				e.Uid, _ = keybase1.UIDFromString(field.Value)
357			case "e_version":
358				e.EldestSeqno = seqnoFromString(field.Value)
359			case "r_version":
360				r = seqnoFromString(field.Value)
361			}
362		}
363		return NewAccountResetError(e, r)
364	case SCKeyNoPGPEncryption:
365		ret := NoPGPEncryptionKeyError{User: s.Desc}
366		for _, field := range s.Fields {
367			if field.Key == "HasKeybaseEncryptionKey" {
368				ret.HasKeybaseEncryptionKey = true
369			}
370		}
371		return ret
372	case SCKeyNoNaClEncryption:
373		ret := NoNaClEncryptionKeyError{}
374		for _, field := range s.Fields {
375			switch field.Key {
376			case "Username":
377				ret.Username = field.Value
378			case "HasPGPKey":
379				ret.HasPGPKey = true
380			case "HasPUK":
381				ret.HasPUK = true
382			case "HasPaperKey":
383				ret.HasPaperKey = true
384			case "HasDeviceKey":
385				ret.HasDeviceKey = true
386			}
387		}
388		return ret
389	case SCWrongCryptoFormat:
390		ret := WrongCryptoFormatError{Operation: s.Desc}
391		for _, field := range s.Fields {
392			switch field.Key {
393			case "wanted":
394				ret.Wanted = CryptoMessageFormat(field.Value)
395			case "received":
396				ret.Received = CryptoMessageFormat(field.Value)
397			}
398		}
399		return ret
400	case SCKeySyncedPGPNotFound:
401		return NoSyncedPGPKeyError{}
402	case SCKeyNoMatchingGPG:
403		ret := NoMatchingGPGKeysError{}
404		for _, field := range s.Fields {
405			switch field.Key {
406			case "fingerprints":
407				ret.Fingerprints = strings.Split(field.Value, ",")
408			case "has_active_device":
409				ret.HasActiveDevice = true
410			}
411		}
412		return ret
413	case SCDevicePrevProvisioned:
414		return DeviceAlreadyProvisionedError{}
415	case SCDeviceProvisionViaDevice:
416		return ProvisionViaDeviceRequiredError{}
417	case SCDeviceNoProvision:
418		return ProvisionUnavailableError{}
419	case SCGPGUnavailable:
420		return GPGUnavailableError{}
421	case SCNotFound:
422		return NotFoundError{Msg: s.Desc}
423	case SCDeleted:
424		return UserDeletedError{Msg: s.Desc}
425	case SCDecryptionError:
426		ret := DecryptionError{}
427		for _, field := range s.Fields {
428			switch field.Key {
429			case "Cause":
430				ret.Cause.Err = fmt.Errorf(field.Value)
431			case "Code":
432				if code, err := strconv.Atoi(field.Value); err == nil {
433					ret.Cause.StatusCode = code
434				}
435			}
436		}
437		return ret
438	case SCSigCannotVerify:
439		ret := VerificationError{}
440		for _, field := range s.Fields {
441			switch field.Key {
442			case "Cause":
443				ret.Cause.Err = fmt.Errorf(field.Value)
444			case "Code":
445				if code, err := strconv.Atoi(field.Value); err == nil {
446					ret.Cause.StatusCode = code
447				}
448			}
449		}
450		return ret
451	case SCKeyRevoked:
452		return KeyRevokedError{msg: s.Desc}
453	case SCDeviceNameInUse:
454		return DeviceNameInUseError{}
455	case SCDeviceBadName:
456		return DeviceBadNameError{}
457	case SCGenericAPIError:
458		var code int
459		for _, field := range s.Fields {
460			if field.Key == "code" {
461				var err error
462				code, err = strconv.Atoi(field.Value)
463				if err != nil && g != nil {
464					g.Log.Warning("error parsing generic API error code: %s", err)
465				}
466			}
467		}
468		return &APIError{
469			Msg:  s.Desc,
470			Code: code,
471		}
472	case SCChatInternal:
473		return ChatInternalError{}
474	case SCChatStalePreviousState:
475		return ChatStalePreviousStateError{}
476	case SCChatEphemeralRetentionPolicyViolatedError:
477		var maxAge gregor1.DurationSec
478		for _, field := range s.Fields {
479			if field.Key == "MaxAge" {
480				dur, err := time.ParseDuration(field.Value)
481				if err == nil {
482					maxAge = gregor1.ToDurationSec(dur)
483				}
484			}
485		}
486		return ChatEphemeralRetentionPolicyViolatedError{maxAge}
487	case SCChatConvExists:
488		var convID chat1.ConversationID
489		for _, field := range s.Fields {
490			if field.Key == "ConvID" {
491				bs, err := chat1.MakeConvID(field.Value)
492				if err != nil && g != nil {
493					g.Log.Warning("error parsing ChatConvExistsError")
494				}
495				convID = bs
496			}
497		}
498		return ChatConvExistsError{
499			ConvID: convID,
500		}
501	case SCChatUnknownTLFID:
502		var tlfID chat1.TLFID
503		for _, field := range s.Fields {
504			if field.Key == "TlfID" {
505				var err error
506				tlfID, err = chat1.MakeTLFID(field.Value)
507				if err != nil && g != nil {
508					g.Log.Warning("error parsing chat unknown TLF ID error")
509				}
510			}
511		}
512		return ChatUnknownTLFIDError{
513			TlfID: tlfID,
514		}
515	case SCChatNotInConv:
516		var uid gregor1.UID
517		for _, field := range s.Fields {
518			if field.Key == "UID" {
519				val, err := hex.DecodeString(field.Value)
520				if err != nil && g != nil {
521					g.Log.Warning("error parsing chat not in conv UID")
522				}
523				uid = gregor1.UID(val)
524			}
525		}
526		return ChatNotInConvError{
527			UID: uid,
528		}
529	case SCChatNotInTeam:
530		var uid gregor1.UID
531		for _, field := range s.Fields {
532			if field.Key == "UID" {
533				val, err := hex.DecodeString(field.Value)
534				if err != nil && g != nil {
535					g.Log.Warning("error parsing chat not in conv UID")
536				}
537				uid = gregor1.UID(val)
538			}
539		}
540		return ChatNotInTeamError{
541			UID: uid,
542		}
543	case SCChatTLFFinalized:
544		var tlfID chat1.TLFID
545		for _, field := range s.Fields {
546			if field.Key == "TlfID" {
547				var err error
548				tlfID, err = chat1.MakeTLFID(field.Value)
549				if err != nil && g != nil {
550					g.Log.Warning("error parsing chat tlf finalized TLFID: %s", err.Error())
551				}
552			}
553		}
554		return ChatTLFFinalizedError{
555			TlfID: tlfID,
556		}
557	case SCChatBadMsg:
558		return ChatBadMsgError{Msg: s.Desc}
559	case SCChatBroadcast:
560		return ChatBroadcastError{Msg: s.Desc}
561	case SCChatRateLimit:
562		var rlimit chat1.RateLimit
563		for _, field := range s.Fields {
564			if field.Key == "RateLimit" {
565				err := json.Unmarshal([]byte(field.Value), &rlimit)
566				if err != nil && g != nil {
567					g.Log.Warning("error parsing chat rate limit: %s", err.Error())
568				}
569			}
570		}
571		if rlimit.Name == "" && g != nil {
572			g.Log.Warning("error rate limit information not found")
573		}
574		return ChatRateLimitError{
575			RateLimit: rlimit,
576			Msg:       s.Desc,
577		}
578	case SCChatAlreadySuperseded:
579		return ChatAlreadySupersededError{Msg: s.Desc}
580	case SCChatAlreadyDeleted:
581		return ChatAlreadyDeletedError{Msg: s.Desc}
582	case SCBadEmail:
583		return BadEmailError{Msg: s.Desc}
584	case SCExists:
585		return ExistsError{Msg: s.Desc}
586	case SCInvalidAddress:
587		return InvalidAddressError{Msg: s.Desc}
588	case SCChatCollision:
589		return ChatCollisionError{}
590	case SCChatMessageCollision:
591		var headerHash string
592		for _, field := range s.Fields {
593			if field.Key == "HeaderHash" {
594				headerHash = field.Value
595			}
596		}
597		return ChatMessageCollisionError{
598			HeaderHash: headerHash,
599		}
600	case SCChatDuplicateMessage:
601		var soutboxID string
602		for _, field := range s.Fields {
603			if field.Key == "OutboxID" {
604				soutboxID = field.Value
605			}
606		}
607		boutboxID, _ := hex.DecodeString(soutboxID)
608		return ChatDuplicateMessageError{
609			OutboxID: chat1.OutboxID(boutboxID),
610		}
611	case SCChatClientError:
612		return ChatClientError{Msg: s.Desc}
613	case SCChatUsersAlreadyInConversationError:
614		var uids []keybase1.UID
615		for _, field := range s.Fields {
616			if field.Key == "uid" {
617				uids = append(uids, keybase1.UID(field.Value))
618			}
619		}
620		return ChatUsersAlreadyInConversationError{Uids: uids}
621	case SCChatBadConversationError:
622		var msg string
623		for _, field := range s.Fields {
624			if field.Key == "Msg" {
625				msg = field.Value
626			}
627		}
628		return ChatBadConversationError{
629			Msg: msg,
630		}
631	case SCNeedSelfRekey:
632		ret := NeedSelfRekeyError{Msg: s.Desc}
633		for _, field := range s.Fields {
634			if field.Key == "Tlf" {
635				ret.Tlf = field.Value
636			}
637		}
638		return ret
639	case SCNeedOtherRekey:
640		ret := NeedOtherRekeyError{Msg: s.Desc}
641		for _, field := range s.Fields {
642			if field.Key == "Tlf" {
643				ret.Tlf = field.Value
644			}
645		}
646		return ret
647	case SCLoginStateTimeout:
648		var e LoginStateTimeoutError
649		for _, field := range s.Fields {
650			switch field.Key {
651			case "ActiveRequest":
652				e.ActiveRequest = field.Value
653			case "AttemptedRequest":
654				e.AttemptedRequest = field.Value
655			case "Duration":
656				dur, err := time.ParseDuration(field.Value)
657				if err == nil {
658					e.Duration = dur
659				}
660			}
661		}
662		return e
663	case SCRevokeCurrentDevice:
664		return RevokeCurrentDeviceError{}
665	case SCRevokeLastDevice:
666		e := RevokeLastDeviceError{}
667		for _, field := range s.Fields {
668			if field.Key == "NoPassphrase" {
669				e.NoPassphrase = field.BoolValue()
670			}
671		}
672		return e
673	case SCRevokeLastDevicePGP:
674		return RevokeLastDevicePGPError{}
675	case SCTeamKeyMaskNotFound:
676		e := KeyMaskNotFoundError{}
677		for _, field := range s.Fields {
678			switch field.Key {
679			case "App":
680				e.App = keybase1.TeamApplication(field.IntValue())
681			case "Gen":
682				e.Gen = keybase1.PerTeamKeyGeneration(field.IntValue())
683			}
684		}
685		return e
686	case SCDeviceProvisionOffline:
687		return ProvisionFailedOfflineError{}
688	case SCGitInvalidRepoName:
689		e := InvalidRepoNameError{}
690		for _, field := range s.Fields {
691			if field.Key == "Name" {
692				e.Name = field.Value
693			}
694		}
695		return e
696	case SCGitRepoAlreadyExists:
697		e := RepoAlreadyExistsError{}
698		for _, field := range s.Fields {
699			switch field.Key {
700			case "DesiredName":
701				e.DesiredName = field.Value
702			case "ExistingName":
703				e.ExistingName = field.Value
704			case "ExistingID":
705				e.ExistingID = field.Value
706			}
707		}
708		return e
709	case SCGitRepoDoesntExist:
710		e := RepoDoesntExistError{}
711		for _, field := range s.Fields {
712			if field.Key == "Name" {
713				e.Name = field.Value
714			}
715		}
716		return e
717	case SCNoOp:
718		return NoOpError{Desc: s.Desc}
719	case SCNoSpaceOnDevice:
720		return NoSpaceOnDeviceError{Desc: s.Desc}
721	case SCTeamInviteBadToken:
722		return TeamInviteBadTokenError{}
723	case SCTeamInviteTokenReused:
724		return TeamInviteTokenReusedError{}
725	case SCTeamBadMembership:
726		return TeamBadMembershipError{}
727	case SCTeamProvisionalCanKey, SCTeamProvisionalCannotKey:
728		e := TeamProvisionalError{}
729		for _, field := range s.Fields {
730			switch field.Key {
731			case "IsPublic":
732				if field.Value == "1" {
733					e.IsPublic = true
734				}
735			case "PreResolveDisplayName":
736				e.PreResolveDisplayName = field.Value
737			}
738		}
739		if s.Code == SCTeamProvisionalCanKey {
740			e.CanKey = true
741		}
742		return e
743	case SCEphemeralPairwiseMACsMissingUIDs:
744		uids := []keybase1.UID{}
745		for _, field := range s.Fields {
746			uids = append(uids, keybase1.UID(field.Value))
747		}
748		return NewEphemeralPairwiseMACsMissingUIDsError(uids)
749	case SCMerkleClientError:
750		e := MerkleClientError{m: s.Desc}
751		for _, field := range s.Fields {
752			if field.Key == "type" {
753				i, err := strconv.Atoi(field.Value)
754				if err != nil {
755					g.Log.Warning("error parsing merkle error type: %s", err)
756				} else {
757					e.t = merkleClientErrorType(i)
758				}
759			}
760		}
761		return e
762	case SCFeatureFlag:
763		var feature Feature
764		for _, field := range s.Fields {
765			if field.Key == "feature" {
766				feature = Feature(field.Value)
767			}
768		}
769		return NewFeatureFlagError(s.Desc, feature)
770	case SCNoPaperKeys:
771		return NoPaperKeysError{}
772	case SCTeamContactSettingsBlock:
773		e := TeamContactSettingsBlockError{}
774		for _, field := range s.Fields {
775			switch field.Key {
776			case "uids":
777				e.blockedUIDs = parseUIDsFromString(field.Value)
778			case "usernames":
779				e.blockedUsernames = parseUsernamesFromString(field.Value)
780			}
781		}
782		return e
783	case SCAssertionParseError:
784		e := AssertionParseError{}
785		for _, field := range s.Fields {
786			switch field.Key {
787			case "err":
788				e.err = field.Value
789			case "reason":
790				s, err := strconv.Atoi(field.Value)
791				if err == nil {
792					reason := AssertionParseErrorReason(s)
793					e.reason = reason
794				}
795			}
796		}
797		return e
798
799	default:
800		ase := AppStatusError{
801			Code:   s.Code,
802			Name:   s.Name,
803			Desc:   s.Desc,
804			Fields: make(map[string]string),
805		}
806		for _, f := range s.Fields {
807			ase.Fields[f.Key] = f.Value
808		}
809		return ase
810	}
811}
812
813//=============================================================================
814
815func (a AppStatusError) ToStatus() keybase1.Status {
816	var fields []keybase1.StringKVPair
817	for k, v := range a.Fields {
818		fields = append(fields, keybase1.StringKVPair{Key: k, Value: v})
819	}
820
821	return keybase1.Status{
822		Code:   a.Code,
823		Name:   a.Name,
824		Desc:   a.Desc,
825		Fields: fields,
826	}
827}
828
829//=============================================================================
830
831func ExportTrackDiff(d TrackDiff) (res *keybase1.TrackDiff) {
832	if d != nil {
833		res = &keybase1.TrackDiff{
834			Type:          d.GetTrackDiffType(),
835			DisplayMarkup: d.ToDisplayString(),
836		}
837	}
838	return
839}
840
841//=============================================================================
842
843func ImportPGPFingerprintSlice(fp []byte) (ret *PGPFingerprint) {
844	if fp == nil {
845		return nil
846	}
847	if len(fp) != PGPFingerprintLen {
848		return nil
849	}
850
851	var tmp PGPFingerprint
852	copy(tmp[:], fp)
853	return &tmp
854}
855
856//=============================================================================
857
858func (s TrackSummary) Export(username string) (ret keybase1.TrackSummary) {
859	ret.Time = keybase1.ToTime(s.time)
860	ret.IsRemote = s.isRemote
861	ret.Username = username
862	return
863}
864
865func ImportTrackSummary(s *keybase1.TrackSummary) *TrackSummary {
866	if s == nil {
867		return nil
868	}
869
870	ret := &TrackSummary{
871		time:     keybase1.FromTime(s.Time),
872		isRemote: s.IsRemote,
873		username: s.Username,
874	}
875	return ret
876}
877
878func ExportTrackSummary(l *TrackLookup, username string) *keybase1.TrackSummary {
879	if l == nil {
880		return nil
881	}
882
883	tmp := l.ToSummary().Export(username)
884	return &tmp
885}
886
887//=============================================================================
888
889func (ir *IdentifyOutcome) Export(g *GlobalContext) *keybase1.IdentifyOutcome {
890	v := make([]string, len(ir.Warnings))
891	for i, w := range ir.Warnings {
892		v[i] = w.Warning()
893	}
894	del := make([]keybase1.TrackDiff, len(ir.Revoked))
895	for i, d := range ir.Revoked {
896		del[i] = *ExportTrackDiff(d)
897	}
898	ret := &keybase1.IdentifyOutcome{
899		Username:          ir.Username.String(),
900		Status:            ExportErrorAsStatus(g, ir.Error),
901		Warnings:          v,
902		TrackUsed:         ExportTrackSummary(ir.TrackUsed, ir.Username.String()),
903		TrackStatus:       ir.TrackStatus(),
904		NumTrackFailures:  ir.NumTrackFailures(),
905		NumTrackChanges:   ir.NumTrackChanges(),
906		NumProofFailures:  ir.NumProofFailures(),
907		NumRevoked:        ir.NumRevoked(),
908		NumProofSuccesses: ir.NumProofSuccesses(),
909		Revoked:           del,
910		TrackOptions:      ir.TrackOptions,
911		Reason:            ir.Reason,
912	}
913	return ret
914}
915
916//=============================================================================
917
918func DisplayTrackArg(sessionID int, stmt string) *keybase1.DisplayTrackStatementArg {
919	return &keybase1.DisplayTrackStatementArg{
920		SessionID: sessionID,
921		Stmt:      stmt,
922	}
923}
924
925//=============================================================================
926
927func ImportWarnings(v []string) Warnings {
928	w := make([]Warning, len(v))
929	for i, s := range v {
930		w[i] = StringWarning(s)
931	}
932	return Warnings{w: w}
933}
934
935//=============================================================================
936
937func (c CryptocurrencyChainLink) Export() (ret keybase1.Cryptocurrency) {
938	ret.Pkhash = c.pkhash
939	ret.Address = c.address
940	ret.SigID = c.GetSigID()
941	ret.Type = c.typ.String()
942	ret.Family = string(c.typ.ToCryptocurrencyFamily())
943	return ret
944}
945
946//=============================================================================
947
948func (p PassphraseError) ToStatus() (s keybase1.Status) {
949	s.Code = SCBadLoginPassword
950	s.Name = "BAD_LOGIN_PASSWORD"
951	s.Desc = p.Msg
952	return
953}
954
955func (m Markup) Export() (ret keybase1.Text) {
956	ret.Data = m.data
957	ret.Markup = true
958	return
959}
960
961//=============================================================================
962
963func (e LoggedInError) ToStatus() (s keybase1.Status) {
964	s.Code = SCAlreadyLoggedIn
965	s.Name = "ALREADY_LOGGED_IN"
966	s.Desc = "Already logged in as a different user"
967	return
968}
969
970//=============================================================================
971
972func (e LoggedInWrongUserError) ToStatus() (s keybase1.Status) {
973	s.Code = SCAlreadyLoggedIn
974	s.Name = "ALREADY_LOGGED_IN"
975	s.Desc = e.Error()
976	return
977}
978
979//=============================================================================
980
981func (e KeyGenError) ToStatus() (s keybase1.Status) {
982	s.Code = SCKeyBadGen
983	s.Name = "KEY_BAD_GEN"
984	s.Desc = e.Msg
985	return
986}
987
988//=============================================================================
989
990func (c CanceledError) ToStatus() (s keybase1.Status) {
991	s.Code = SCCanceled
992	s.Name = "CANCELED"
993	s.Desc = c.M
994	return
995}
996
997//=============================================================================
998
999func (e BadSessionError) ToStatus() (s keybase1.Status) {
1000	s.Code = SCBadSession
1001	s.Name = "BAD_SESSION"
1002	s.Desc = e.Desc
1003	return s
1004}
1005
1006//=============================================================================
1007
1008func (e InputCanceledError) ToStatus() (s keybase1.Status) {
1009	s.Code = SCInputCanceled
1010	s.Name = "CANCELED"
1011	s.Desc = "Input canceled"
1012	return
1013}
1014
1015//=============================================================================
1016
1017func (e SkipSecretPromptError) ToStatus() (s keybase1.Status) {
1018	s.Code = SCInputCanceled
1019	s.Name = "CANCELED"
1020	s.Desc = "Input canceled due to skip secret prompt"
1021	return
1022}
1023
1024//=============================================================================
1025
1026func (c KeyCorruptedError) ToStatus() (s keybase1.Status) {
1027	s.Code = SCKeyCorrupted
1028	s.Name = "KEY_CORRUPTED"
1029	if c.Msg != "" {
1030		s.Desc = c.Msg
1031	}
1032	return
1033}
1034
1035//=============================================================================
1036
1037func (e OfflineError) ToStatus() (s keybase1.Status) {
1038	s.Code = SCOffline
1039	s.Name = "OFFLINE"
1040	return s
1041}
1042
1043//=============================================================================
1044
1045func (c KeyExistsError) ToStatus() (s keybase1.Status) {
1046	s.Code = SCKeyInUse
1047	s.Name = "KEY_IN_USE"
1048	if c.Key != nil {
1049		s.Desc = c.Key.String()
1050	}
1051	return
1052}
1053
1054//=============================================================================
1055
1056func (ids Identities) Export() (res []keybase1.PGPIdentity) {
1057	var n int
1058	if ids == nil {
1059		n = 0
1060	} else {
1061		n = len(ids)
1062	}
1063	res = make([]keybase1.PGPIdentity, n)
1064	for i, id := range ids {
1065		res[i] = id.Export()
1066	}
1067	return
1068}
1069
1070func ImportPGPIdentities(ids []keybase1.PGPIdentity) (ret Identities) {
1071	ret = Identities(make([]Identity, len(ids)))
1072	for i, id := range ids {
1073		ret[i] = ImportPGPIdentity(id)
1074	}
1075	return
1076}
1077
1078//=============================================================================
1079
1080func (id Identity) Export() (ret keybase1.PGPIdentity) {
1081	ret.Username = id.Username
1082	ret.Email = id.Email
1083	ret.Comment = id.Comment
1084	return
1085}
1086
1087func ImportPGPIdentity(arg keybase1.PGPIdentity) (ret Identity) {
1088	ret.Username = arg.Username
1089	ret.Email = arg.Email
1090	ret.Comment = arg.Comment
1091	return
1092}
1093
1094//=============================================================================
1095
1096// Interface for sorting a list of PublicKeys
1097
1098type PublicKeyList []keybase1.PublicKey
1099
1100func (l PublicKeyList) Len() int { return len(l) }
1101func (l PublicKeyList) Less(i, j int) bool {
1102	// Keys created first come first.
1103	if l[i].CTime != l[j].CTime {
1104		return l[i].CTime < l[j].CTime
1105	}
1106	// For keys created at the same time, if one of them's the eldest key, it comes first.
1107	if l[i].IsEldest != l[j].IsEldest {
1108		return l[i].IsEldest
1109	}
1110	// Otherwise just sort by KID.
1111	return l[i].KID < l[j].KID
1112}
1113func (l PublicKeyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
1114
1115func ExportPGPIdentity(identity *openpgp.Identity) keybase1.PGPIdentity {
1116	if identity == nil || identity.UserId == nil {
1117		return keybase1.PGPIdentity{}
1118	}
1119	return keybase1.PGPIdentity{
1120		Username: identity.UserId.Name,
1121		Email:    identity.UserId.Email,
1122		Comment:  identity.UserId.Comment,
1123	}
1124}
1125
1126func (kf KeyFamily) Export() []keybase1.PublicKey {
1127	var res []keybase1.PublicKey
1128	for kid := range kf.AllKIDs {
1129		if pgpKeySet, isPGP := kf.PGPKeySets[kid]; isPGP {
1130			res = append(res, pgpKeySet.PermissivelyMergedKey.Export())
1131		} else {
1132			res = append(res, keybase1.PublicKey{KID: kid})
1133		}
1134	}
1135	return res
1136}
1137
1138func (bundle *PGPKeyBundle) Export() keybase1.PublicKey {
1139	kid := bundle.GetKID()
1140	fingerprintStr := ""
1141	identities := []keybase1.PGPIdentity{}
1142	fingerprintStr = bundle.GetFingerprint().String()
1143	for _, identity := range bundle.Identities {
1144		identities = append(identities, ExportPGPIdentity(identity))
1145	}
1146	return keybase1.PublicKey{
1147		KID:            kid,
1148		PGPFingerprint: fingerprintStr,
1149		PGPIdentities:  identities,
1150	}
1151}
1152
1153func (ckf ComputedKeyFamily) exportPublicKey(key GenericKey) (pk keybase1.PublicKey) {
1154	pk.KID = key.GetKID()
1155	if pgpBundle, isPGP := key.(*PGPKeyBundle); isPGP {
1156		pk.PGPFingerprint = pgpBundle.GetFingerprint().String()
1157		ids := make([]keybase1.PGPIdentity, len(pgpBundle.Identities))
1158		i := 0
1159		for _, identity := range pgpBundle.Identities {
1160			ids[i] = ExportPGPIdentity(identity)
1161			i++
1162		}
1163		pk.PGPIdentities = ids
1164		pk.IsRevoked = len(pgpBundle.Revocations)+len(pgpBundle.UnverifiedRevocations) > 0
1165	}
1166	pk.DeviceID = ckf.cki.KIDToDeviceID[pk.KID]
1167	device := ckf.cki.Devices[pk.DeviceID]
1168	if device != nil {
1169		if device.Description != nil {
1170			pk.DeviceDescription = *device.Description
1171		}
1172		pk.DeviceType = device.Type
1173	}
1174	cki, ok := ckf.cki.Infos[pk.KID]
1175	if ok && cki != nil {
1176		if cki.Parent.IsValid() {
1177			pk.ParentID = cki.Parent.String()
1178		}
1179		pk.IsSibkey = cki.Sibkey
1180		pk.IsEldest = cki.Eldest
1181		pk.CTime = keybase1.TimeFromSeconds(cki.CTime)
1182		pk.ETime = keybase1.TimeFromSeconds(cki.ETime)
1183	}
1184	return pk
1185}
1186
1187func publicKeyV2BaseFromComputedKeyInfo(kid keybase1.KID, info ComputedKeyInfo) (base keybase1.PublicKeyV2Base) {
1188	base = keybase1.PublicKeyV2Base{
1189		Kid:      kid,
1190		IsSibkey: info.Sibkey,
1191		IsEldest: info.Eldest,
1192		CTime:    keybase1.TimeFromSeconds(info.CTime),
1193		ETime:    keybase1.TimeFromSeconds(info.ETime),
1194	}
1195	if info.DelegatedAt != nil {
1196		base.Provisioning = keybase1.SignatureMetadata{
1197			Time: keybase1.TimeFromSeconds(info.DelegatedAt.Unix),
1198			PrevMerkleRootSigned: keybase1.MerkleRootV2{
1199				HashMeta: info.DelegatedAtHashMeta,
1200				Seqno:    info.DelegatedAt.Chain,
1201			},
1202			FirstAppearedUnverified: info.FirstAppearedUnverified,
1203		}
1204		dLen := len(info.DelegationsList)
1205		if dLen > 0 {
1206			base.Provisioning.SigningKID = info.DelegationsList[dLen-1].KID
1207		}
1208	}
1209	base.Provisioning.SigChainLocation = info.DelegatedAtSigChainLocation
1210	if info.RevokedAt != nil {
1211		base.Revocation = &keybase1.SignatureMetadata{
1212			Time: keybase1.TimeFromSeconds(info.RevokedAt.Unix),
1213			PrevMerkleRootSigned: keybase1.MerkleRootV2{
1214				HashMeta: info.RevokedAtHashMeta,
1215				Seqno:    info.RevokedAt.Chain,
1216			},
1217			FirstAppearedUnverified: info.RevokeFirstAppearedUnverified,
1218			SigningKID:              info.RevokedBy,
1219		}
1220		if info.RevokedAtSigChainLocation != nil {
1221			base.Revocation.SigChainLocation = *info.RevokedAtSigChainLocation
1222		}
1223	}
1224	return
1225}
1226
1227func (cki ComputedKeyInfos) exportDeviceKeyV2(kid keybase1.KID) (key keybase1.PublicKeyV2NaCl) {
1228	info := cki.Infos[kid]
1229	if info == nil {
1230		cki.G().Log.Errorf("Tried to export nonexistent KID: %s", kid.String())
1231		return
1232	}
1233	key = keybase1.PublicKeyV2NaCl{
1234		Base:     publicKeyV2BaseFromComputedKeyInfo(kid, *info),
1235		DeviceID: cki.KIDToDeviceID[kid],
1236	}
1237	if !info.Parent.IsNil() {
1238		key.Parent = &info.Parent
1239	}
1240	if device := cki.Devices[key.DeviceID]; device != nil {
1241		key.DeviceType = device.Type
1242		if device.Description != nil {
1243			key.DeviceDescription = *device.Description
1244		}
1245	}
1246	return
1247}
1248
1249func (cki ComputedKeyInfos) exportPGPKeyV2(kid keybase1.KID, kf *KeyFamily) (key keybase1.PublicKeyV2PGPSummary) {
1250	info := cki.Infos[kid]
1251	if info == nil {
1252		cki.G().Log.Errorf("Tried to export nonexistent KID: %s", kid.String())
1253		return
1254	}
1255	keySet := kf.PGPKeySets[kid]
1256	if keySet == nil {
1257		cki.G().Log.Errorf("Tried to export PGP key with no key set, KID: %s", kid.String())
1258		return
1259	}
1260	var bundle *PGPKeyBundle
1261	if info.ActivePGPHash != "" {
1262		bundle = keySet.KeysByHash[info.ActivePGPHash]
1263	} else {
1264		bundle = keySet.PermissivelyMergedKey
1265	}
1266	if bundle == nil {
1267		cki.G().Log.Errorf("Tried to export PGP key with no bundle, KID: %s", kid.String())
1268		return
1269	}
1270	key = keybase1.PublicKeyV2PGPSummary{
1271		Base:        publicKeyV2BaseFromComputedKeyInfo(kid, *info),
1272		Fingerprint: keybase1.PGPFingerprint(bundle.GetFingerprint()),
1273		Identities:  bundle.Export().PGPIdentities,
1274	}
1275	return
1276}
1277
1278// Export is used by IDRes.  It includes PGP keys.
1279func (ckf ComputedKeyFamily) Export() []keybase1.PublicKey {
1280	var exportedKeys []keybase1.PublicKey
1281	for _, key := range ckf.GetAllActiveSibkeys() {
1282		exportedKeys = append(exportedKeys, ckf.exportPublicKey(key))
1283	}
1284	for _, key := range ckf.GetAllActiveSubkeys() {
1285		exportedKeys = append(exportedKeys, ckf.exportPublicKey(key))
1286	}
1287	sort.Sort(PublicKeyList(exportedKeys))
1288	return exportedKeys
1289}
1290
1291// ExportDeviceKeys is used by ExportToUserPlusKeys.  The key list
1292// only contains device keys.  It also returns the number of PGP
1293// keys in the key family.
1294func (ckf ComputedKeyFamily) ExportDeviceKeys() (exportedKeys []keybase1.PublicKey, pgpKeyCount int) {
1295	for _, key := range ckf.GetAllActiveSibkeys() {
1296		if _, isPGP := key.(*PGPKeyBundle); isPGP {
1297			pgpKeyCount++
1298			continue
1299		}
1300		exportedKeys = append(exportedKeys, ckf.exportPublicKey(key))
1301	}
1302	for _, key := range ckf.GetAllActiveSubkeys() {
1303		if _, isPGP := key.(*PGPKeyBundle); isPGP {
1304			pgpKeyCount++
1305			continue
1306		}
1307		exportedKeys = append(exportedKeys, ckf.exportPublicKey(key))
1308	}
1309	sort.Sort(PublicKeyList(exportedKeys))
1310	return exportedKeys, pgpKeyCount
1311}
1312
1313type perUserKeyList []keybase1.PerUserKey
1314
1315func (l perUserKeyList) Len() int { return len(l) }
1316func (l perUserKeyList) Less(i, j int) bool {
1317	return l[i].Gen < l[j].Gen
1318}
1319func (l perUserKeyList) Swap(i, j int) {
1320	l[i], l[j] = l[j], l[i]
1321}
1322
1323// ExportPerUserKeys exports the per-user public KIDs.
1324func (ckf ComputedKeyFamily) ExportPerUserKeys() (ret []keybase1.PerUserKey) {
1325
1326	for _, k := range ckf.cki.PerUserKeys {
1327		ret = append(ret, k)
1328	}
1329	sort.Sort(perUserKeyList(ret))
1330	return ret
1331}
1332
1333// ExportDeletedDeviceKeys is used by ExportToUserPlusKeys.  The key list
1334// only contains deleted device keys.
1335func (ckf ComputedKeyFamily) ExportDeletedDeviceKeys() []keybase1.PublicKey {
1336	var keys []keybase1.PublicKey
1337	for _, key := range ckf.GetDeletedKeys() {
1338		if _, isPGP := key.(*PGPKeyBundle); isPGP {
1339			continue
1340		}
1341		keys = append(keys, ckf.exportPublicKey(key))
1342	}
1343	sort.Sort(PublicKeyList(keys))
1344	return keys
1345}
1346
1347// ExportAllPGPKeys exports all pgp keys.
1348func (ckf ComputedKeyFamily) ExportAllPGPKeys() (keys []keybase1.PublicKey) {
1349	for _, key := range ckf.GetAllActiveSibkeys() {
1350		if _, isPGP := key.(*PGPKeyBundle); isPGP {
1351			keys = append(keys, ckf.exportPublicKey(key))
1352		}
1353	}
1354	for _, key := range ckf.GetAllActiveSubkeys() {
1355		if _, isPGP := key.(*PGPKeyBundle); isPGP {
1356			keys = append(keys, ckf.exportPublicKey(key))
1357		}
1358	}
1359	sort.Sort(PublicKeyList(keys))
1360	return keys
1361}
1362
1363func (ckf ComputedKeyFamily) ExportRevokedDeviceKeys() []keybase1.RevokedKey {
1364	var ex []keybase1.RevokedKey
1365	for _, key := range ckf.GetRevokedKeys() {
1366		if _, isPGP := key.Key.(*PGPKeyBundle); isPGP {
1367			continue
1368		}
1369		rkey := keybase1.RevokedKey{
1370			Key: ckf.exportPublicKey(key.Key),
1371			Time: keybase1.KeybaseTime{
1372				Unix:  keybase1.TimeFromSeconds(key.RevokedAt.Unix),
1373				Chain: key.RevokedAt.Chain,
1374			},
1375			By: key.RevokedBy,
1376		}
1377		ex = append(ex, rkey)
1378	}
1379
1380	return ex
1381}
1382
1383func (u *User) Export() *keybase1.User {
1384	return &keybase1.User{
1385		Uid:      u.GetUID(),
1386		Username: u.GetName(),
1387	}
1388}
1389
1390func (u *User) ExportToVersionVector() keybase1.UserVersionVector {
1391	idv, _ := u.GetIDVersion()
1392	return keybase1.UserVersionVector{
1393		Id:       idv,
1394		SigHints: u.GetSigHintsVersion(),
1395		SigChain: int64(u.GetSigChainLastKnownSeqno()),
1396		// CachedAt is set by the upak loader right before we write to disk.
1397	}
1398}
1399
1400func (u *User) ExportToUserPlusKeys() keybase1.UserPlusKeys {
1401	ret := keybase1.UserPlusKeys{
1402		Uid:         u.GetUID(),
1403		Username:    u.GetName(),
1404		EldestSeqno: u.GetCurrentEldestSeqno(),
1405	}
1406	ckf := u.GetComputedKeyFamily()
1407	if ckf != nil {
1408		ret.DeviceKeys, ret.PGPKeyCount = ckf.ExportDeviceKeys()
1409		ret.RevokedDeviceKeys = ckf.ExportRevokedDeviceKeys()
1410		ret.DeletedDeviceKeys = ckf.ExportDeletedDeviceKeys()
1411		ret.PerUserKeys = ckf.ExportPerUserKeys()
1412	}
1413
1414	ret.Uvv = u.ExportToVersionVector()
1415	return ret
1416}
1417
1418func (u *User) ExportToUserPlusAllKeys() keybase1.UserPlusAllKeys {
1419	return keybase1.UserPlusAllKeys{
1420		Base:         u.ExportToUserPlusKeys(),
1421		PGPKeys:      u.GetComputedKeyFamily().ExportAllPGPKeys(),
1422		RemoteTracks: u.ExportRemoteTracks(),
1423	}
1424}
1425
1426type PerUserKeysList []keybase1.PerUserKey
1427
1428func (p PerUserKeysList) Len() int           { return len(p) }
1429func (p PerUserKeysList) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
1430func (p PerUserKeysList) Less(i, j int) bool { return p[i].Gen < p[j].Gen }
1431
1432func (cki *ComputedKeyInfos) exportUPKV2Incarnation(uid keybase1.UID, username string, eldestSeqno keybase1.Seqno, kf *KeyFamily, status keybase1.StatusCode, reset *keybase1.ResetSummary) keybase1.UserPlusKeysV2 {
1433
1434	var perUserKeysList PerUserKeysList
1435	if cki != nil {
1436		for _, puk := range cki.PerUserKeys {
1437			perUserKeysList = append(perUserKeysList, puk)
1438		}
1439		sort.Sort(perUserKeysList)
1440	}
1441
1442	deviceKeys := make(map[keybase1.KID]keybase1.PublicKeyV2NaCl)
1443	pgpSummaries := make(map[keybase1.KID]keybase1.PublicKeyV2PGPSummary)
1444	if cki != nil {
1445		for kid := range cki.Infos {
1446			if KIDIsPGP(kid) {
1447				pgpSummaries[kid] = cki.exportPGPKeyV2(kid, kf)
1448			} else {
1449				deviceKeys[kid] = cki.exportDeviceKeyV2(kid)
1450			}
1451		}
1452	}
1453
1454	return keybase1.UserPlusKeysV2{
1455		Uid:         uid,
1456		Username:    username,
1457		EldestSeqno: eldestSeqno,
1458		PerUserKeys: perUserKeysList,
1459		DeviceKeys:  deviceKeys,
1460		PGPKeys:     pgpSummaries,
1461		Status:      status,
1462		Reset:       reset,
1463		// Uvv and RemoteTracks are set later, and only for the current incarnation
1464	}
1465}
1466
1467func (u *User) ExportToUPKV2AllIncarnations() (*keybase1.UserPlusKeysV2AllIncarnations, error) {
1468	// The KeyFamily holds all the PGP key bundles, and it applies to all
1469	// generations of this user.
1470	kf := u.GetKeyFamily()
1471
1472	uid := u.GetUID()
1473	name := u.GetName()
1474	status := u.GetStatus()
1475
1476	// Make a map of EldestKID -> ResetSummary for all resets
1477
1478	resetMap := make(map[keybase1.Seqno](*keybase1.ResetSummary))
1479	if resets := u.leaf.resets; resets != nil {
1480		for _, l := range resets.chain {
1481			tmp := l.Summarize()
1482			resetMap[l.Prev.LastSeqno] = &tmp
1483		}
1484	}
1485
1486	// First assemble all the past versions of this user.
1487	pastIncarnations := []keybase1.UserPlusKeysV2{}
1488	if u.sigChain() != nil {
1489		for _, subchain := range u.sigChain().prevSubchains {
1490			if len(subchain) == 0 {
1491				return nil, fmt.Errorf("Tried to export empty subchain for uid %s username %s", u.GetUID(), u.GetName())
1492			}
1493			lastLink := subchain[len(subchain)-1]
1494			cki := lastLink.cki
1495			eldestSeqno := subchain[0].GetSeqno()
1496			lastSeqno := lastLink.GetSeqno()
1497			reset := resetMap[lastSeqno]
1498			if reset != nil {
1499				reset.EldestSeqno = eldestSeqno
1500			}
1501			pastIncarnations = append(pastIncarnations, cki.exportUPKV2Incarnation(uid, name, eldestSeqno, kf, status, reset))
1502		}
1503	}
1504
1505	// Then assemble the current version. This one gets a couple extra fields, Uvv and RemoteTracks.
1506	current := u.GetComputedKeyInfos().exportUPKV2Incarnation(uid, name, u.GetCurrentEldestSeqno(), kf, status, nil)
1507	current.RemoteTracks = make(map[keybase1.UID]keybase1.RemoteTrack)
1508	if tab := u.IDTable(); tab != nil {
1509		for _, track := range tab.GetTrackList() {
1510			current.RemoteTracks[track.whomUID] = track.Export()
1511		}
1512		current.Unstubbed = !tab.HasStubs()
1513	}
1514	if accountID := u.StellarAccountID(); accountID != nil {
1515		tmp := accountID.String()
1516		current.StellarAccountID = &tmp
1517	}
1518
1519	// Collect the link IDs (that is, the hashes of the signature inputs) from all subchains.
1520	linkIDs := map[keybase1.Seqno]keybase1.LinkID{}
1521	if u.sigChain() != nil {
1522		for _, link := range u.sigChain().chainLinks {
1523			// Assert that all the links are in order as they go in. We should
1524			// never fail this check, but we *really* want to know about it if
1525			// we do.
1526			if int(link.GetSeqno()) != len(linkIDs)+1 {
1527				return nil, fmt.Errorf("Encountered out-of-sequence chain link %d while exporting uid %s username %s", link.GetSeqno(), u.GetUID(), u.GetName())
1528			}
1529			linkIDs[link.GetSeqno()] = link.LinkID().Export()
1530		}
1531	}
1532
1533	return &keybase1.UserPlusKeysV2AllIncarnations{
1534		Current:          current,
1535		PastIncarnations: pastIncarnations,
1536		Uvv:              u.ExportToVersionVector(),
1537		SeqnoLinkIDs:     linkIDs,
1538		MinorVersion:     UPK2MinorVersionCurrent,
1539	}, nil
1540}
1541
1542// NOTE: This list *must* be in sorted order. If we ever write V3, be careful to keep it sorted!
1543func (u *User) ExportRemoteTracks() []keybase1.RemoteTrack {
1544	var ret []keybase1.RemoteTrack
1545	if u.IDTable() == nil {
1546		return ret
1547	}
1548	trackList := u.IDTable().GetTrackList()
1549	for _, track := range trackList {
1550		ret = append(ret, track.Export())
1551	}
1552	sort.Slice(ret, func(i, j int) bool { return ret[i].Username < ret[j].Username })
1553	return ret
1554}
1555
1556func (i LinkID) Export() keybase1.LinkID {
1557	return keybase1.LinkID(i.String())
1558}
1559
1560func (t TrackChainLink) Export() keybase1.RemoteTrack {
1561	return keybase1.RemoteTrack{
1562		Uid:      t.whomUID,
1563		Username: t.whomUsername.String(),
1564		LinkID:   t.id.Export(),
1565	}
1566}
1567
1568//=============================================================================
1569
1570func (a PGPGenArg) ExportTo(ret *keybase1.PGPKeyGenArg) {
1571	ret.PrimaryBits = a.PrimaryBits
1572	ret.SubkeyBits = a.SubkeyBits
1573	ret.CreateUids = keybase1.PGPCreateUids{Ids: a.Ids.Export()}
1574}
1575
1576//=============================================================================
1577
1578func ImportKeyGenArg(a keybase1.PGPKeyGenArg) (ret PGPGenArg) {
1579	ret.PrimaryBits = a.PrimaryBits
1580	ret.SubkeyBits = a.SubkeyBits
1581	ret.Ids = ImportPGPIdentities(a.CreateUids.Ids)
1582	return ret
1583}
1584
1585//=============================================================================
1586
1587func (e BadInvitationCodeError) ToStatus() (s keybase1.Status) {
1588	s.Code = SCBadInvitationCode
1589	s.Name = "BAD_INVITATION_CODE"
1590	return s
1591}
1592
1593//=============================================================================
1594
1595func (e StreamExistsError) ToStatus() (s keybase1.Status) {
1596	s.Code = SCStreamExists
1597	s.Name = "STREAM_EXISTS"
1598	return s
1599}
1600
1601func (e StreamNotFoundError) ToStatus() (s keybase1.Status) {
1602	s.Code = SCStreamNotFound
1603	s.Name = "SC_STREAM_NOT_FOUND"
1604	return s
1605}
1606
1607func (e StreamWrongKindError) ToStatus() (s keybase1.Status) {
1608	s.Code = SCStreamWrongKind
1609	s.Name = "STREAM_WRONG_KIND"
1610	return s
1611}
1612
1613func (e UnknownStreamError) ToStatus() (s keybase1.Status) {
1614	s.Code = SCStreamUnknown
1615	s.Name = "STREAM_UNKNOWN"
1616	return s
1617}
1618
1619//=============================================================================
1620
1621func (u NoSecretKeyError) ToStatus() (s keybase1.Status) {
1622	s.Code = SCKeyNoSecret
1623	s.Name = "KEY_NO_SECRET"
1624	return s
1625}
1626
1627//=============================================================================
1628
1629func (u LoginRequiredError) ToStatus() (s keybase1.Status) {
1630	s.Code = SCLoginRequired
1631	s.Name = "LOGIN_REQUIRED"
1632	s.Desc = u.Context
1633	return s
1634}
1635
1636//=============================================================================
1637
1638func (u NoSessionError) ToStatus() (s keybase1.Status) {
1639	s.Code = SCNoSession
1640	s.Name = "NO_SESSION"
1641	return s
1642}
1643
1644//=============================================================================
1645
1646func (e APINetError) ToStatus() (s keybase1.Status) {
1647	s.Code = SCAPINetworkError
1648	s.Name = "API_NETWORK_ERROR"
1649	s.Desc = e.Error()
1650	return s
1651}
1652
1653func (e ProofNotFoundForServiceError) ToStatus() (s keybase1.Status) {
1654	s.Code = SCProofError
1655	s.Name = "PROOF_ERROR"
1656	s.Desc = e.Error()
1657	return s
1658}
1659
1660func (e ProofNotFoundForUsernameError) ToStatus() (s keybase1.Status) {
1661	s.Code = SCProofError
1662	s.Name = "PROOF_ERROR"
1663	s.Desc = e.Error()
1664	return s
1665}
1666
1667func (e NoDecryptionKeyError) ToStatus() (s keybase1.Status) {
1668	s.Code = SCDecryptionKeyNotFound
1669	s.Name = "KEY_NOT_FOUND_DECRYPTION"
1670	s.Desc = e.Msg
1671	return s
1672}
1673
1674func (e NoKeyError) ToStatus() (s keybase1.Status) {
1675	s.Code = SCKeyNotFound
1676	s.Name = "KEY_NOT_FOUND"
1677	s.Desc = e.Msg
1678	return s
1679}
1680
1681func (e NoSyncedPGPKeyError) ToStatus() keybase1.Status {
1682	return keybase1.Status{
1683		Code: SCKeySyncedPGPNotFound,
1684		Name: "KEY_NOT_FOUND_SYNCED_PGP",
1685		Desc: e.Error(),
1686	}
1687}
1688
1689func (e IdentifyTimeoutError) ToStatus() keybase1.Status {
1690	return keybase1.Status{
1691		Code: SCIdentificationExpired,
1692		Name: "IDENTIFICATION_EXPIRED",
1693		Desc: e.Error(),
1694	}
1695}
1696
1697func (e SelfNotFoundError) ToStatus() keybase1.Status {
1698	return keybase1.Status{
1699		Code: SCSelfNotFound,
1700		Name: "SELF_NOT_FOUND",
1701		Desc: e.Error(),
1702	}
1703}
1704
1705func (e NoDeviceError) ToStatus() keybase1.Status {
1706	return keybase1.Status{
1707		Code: SCDeviceNotFound,
1708		Name: "DEVICE_NOT_FOUND",
1709		Desc: e.Reason,
1710	}
1711}
1712
1713func (e TimeoutError) ToStatus() keybase1.Status {
1714	return keybase1.Status{
1715		Code: SCTimeout,
1716		Name: "SC_TIMEOUT",
1717		Desc: e.Error(),
1718	}
1719}
1720
1721func (e ReceiverDeviceError) ToStatus() keybase1.Status {
1722	return keybase1.Status{
1723		Code: SCDeviceMismatch,
1724		Name: "SC_DEVICE_MISMATCH",
1725		Desc: e.Error(),
1726	}
1727}
1728
1729func (e InvalidKexPhraseError) ToStatus() keybase1.Status {
1730	return keybase1.Status{
1731		Code: SCBadKexPhrase,
1732		Name: "SC_BAD_KEX_PHRASE",
1733		Desc: e.Error(),
1734	}
1735}
1736
1737func (e ReloginRequiredError) ToStatus() keybase1.Status {
1738	return keybase1.Status{
1739		Code: SCReloginRequired,
1740		Name: "SC_RELOGIN_REQUIRED",
1741		Desc: e.Error(),
1742	}
1743}
1744
1745func (e DeviceRequiredError) ToStatus() keybase1.Status {
1746	return keybase1.Status{
1747		Code: SCDeviceRequired,
1748		Name: "SC_DEVICE_REQUIRED",
1749		Desc: e.Error(),
1750	}
1751}
1752
1753func (e IdentifyDidNotCompleteError) ToStatus() keybase1.Status {
1754	return keybase1.Status{
1755		Code: SCMissingResult,
1756		Name: "SC_MISSING_RESULT",
1757		Desc: e.Error(),
1758	}
1759}
1760
1761func (e SibkeyAlreadyExistsError) ToStatus() keybase1.Status {
1762	return keybase1.Status{
1763		Code: SCSibkeyAlreadyExists,
1764		Name: "SC_SIBKEY_ALREADY_EXISTS",
1765		Desc: e.Error(),
1766	}
1767}
1768
1769func (e ServiceDoesNotSupportNewProofsError) ToStatus() keybase1.Status {
1770	return keybase1.Status{
1771		Code: SCSigCreationDisallowed,
1772		Name: "SC_SIG_CREATION_DISALLOWED",
1773		Desc: e.Error(),
1774	}
1775}
1776
1777func (e UIDelegationUnavailableError) ToStatus() keybase1.Status {
1778	return keybase1.Status{
1779		Code: SCNoUIDelegation,
1780		Name: "SC_UI_DELEGATION_UNAVAILABLE",
1781		Desc: e.Error(),
1782	}
1783}
1784
1785func (e NoUIError) ToStatus() keybase1.Status {
1786	return keybase1.Status{
1787		Code: SCNoUI,
1788		Name: "SC_NO_UI",
1789		Desc: e.Which,
1790	}
1791}
1792
1793func (e ResolutionError) ToStatus() keybase1.Status {
1794	return keybase1.Status{
1795		Code: SCResolutionFailed,
1796		Name: "SC_RESOLUTION_FAILED",
1797		Desc: e.Msg,
1798		Fields: []keybase1.StringKVPair{
1799			{Key: "input", Value: e.Input},
1800		},
1801	}
1802}
1803
1804func (e IdentifyFailedError) ToStatus() keybase1.Status {
1805	return keybase1.Status{
1806		Code: SCIdentifyFailed,
1807		Name: "SC_IDENTIFY_FAILED",
1808		Desc: e.Reason,
1809		Fields: []keybase1.StringKVPair{
1810			{Key: "assertion", Value: e.Assertion},
1811		},
1812	}
1813}
1814
1815func (e IdentifiesFailedError) ToStatus() keybase1.Status {
1816	return keybase1.Status{
1817		Code: SCIdentifiesFailed,
1818		Name: "SC_IDENTIFIES_FAILED",
1819		Desc: e.Error(),
1820	}
1821}
1822
1823func (e IdentifySummaryError) ToStatus() keybase1.Status {
1824	kvpairs := []keybase1.StringKVPair{
1825		{Key: "username", Value: e.username.String()},
1826	}
1827	for index, problem := range e.problems {
1828		kvpairs = append(kvpairs, keybase1.StringKVPair{
1829			Key:   fmt.Sprintf("problem_%d", index),
1830			Value: problem,
1831		})
1832	}
1833	return keybase1.Status{
1834		Code:   SCIdentifySummaryError,
1835		Name:   "SC_IDENTIFY_SUMMARY_ERROR",
1836		Desc:   e.Error(),
1837		Fields: kvpairs,
1838	}
1839}
1840
1841func (e ProfileNotPublicError) ToStatus() keybase1.Status {
1842	return keybase1.Status{
1843		Code: SCProfileNotPublic,
1844		Name: "SC_PROFILE_NOT_PUBLIC",
1845		Desc: e.msg,
1846	}
1847}
1848
1849func (e TrackingBrokeError) ToStatus() keybase1.Status {
1850	return keybase1.Status{
1851		Code: SCTrackingBroke,
1852		Name: "SC_TRACKING_BROKE",
1853	}
1854}
1855
1856func (e NoPGPEncryptionKeyError) ToStatus() keybase1.Status {
1857	ret := keybase1.Status{
1858		Code: SCKeyNoPGPEncryption,
1859		Name: "SC_KEY_NO_PGP_ENCRYPTION",
1860		Desc: e.User,
1861	}
1862	if e.HasKeybaseEncryptionKey {
1863		ret.Fields = []keybase1.StringKVPair{
1864			{Key: "HasKeybaseEncryptionKey", Value: "1"},
1865		}
1866	}
1867	return ret
1868}
1869
1870func (e NoNaClEncryptionKeyError) ToStatus() keybase1.Status {
1871	ret := keybase1.Status{
1872		Code: SCKeyNoNaClEncryption,
1873		Name: "SC_KEY_NO_NACL_ENCRYPTION",
1874		Desc: e.Error(),
1875	}
1876
1877	ret.Fields = []keybase1.StringKVPair{{Key: "Username", Value: e.Username}}
1878
1879	if e.HasPGPKey {
1880		ret.Fields = append(ret.Fields, keybase1.StringKVPair{Key: "HasPGPKey", Value: "1"})
1881	}
1882	if e.HasPUK {
1883		ret.Fields = append(ret.Fields, keybase1.StringKVPair{Key: "HasPUK", Value: "1"})
1884	}
1885	if e.HasDeviceKey {
1886		ret.Fields = append(ret.Fields, keybase1.StringKVPair{Key: "HasDeviceKey", Value: "1"})
1887	}
1888	if e.HasPaperKey {
1889		ret.Fields = append(ret.Fields, keybase1.StringKVPair{Key: "HasPaperKey", Value: "1"})
1890	}
1891	return ret
1892}
1893
1894func (e WrongCryptoFormatError) ToStatus() keybase1.Status {
1895	ret := keybase1.Status{
1896		Code: SCWrongCryptoFormat,
1897		Name: "SC_WRONG_CRYPTO_FORMAT",
1898		Desc: e.Operation,
1899		Fields: []keybase1.StringKVPair{
1900			{Key: "wanted", Value: string(e.Wanted)},
1901			{Key: "received", Value: string(e.Received)},
1902		},
1903	}
1904	return ret
1905}
1906
1907func (e NoMatchingGPGKeysError) ToStatus() keybase1.Status {
1908	s := keybase1.Status{
1909		Code: SCKeyNoMatchingGPG,
1910		Name: "SC_KEY_NO_MATCHING_GPG",
1911		Fields: []keybase1.StringKVPair{
1912			{Key: "fingerprints", Value: strings.Join(e.Fingerprints, ",")},
1913		},
1914	}
1915	if e.HasActiveDevice {
1916		s.Fields = append(s.Fields, keybase1.StringKVPair{Key: "has_active_device", Value: "1"})
1917	}
1918	return s
1919}
1920
1921func (e DeviceAlreadyProvisionedError) ToStatus() keybase1.Status {
1922	return keybase1.Status{
1923		Code: SCDevicePrevProvisioned,
1924		Name: "SC_DEVICE_PREV_PROVISIONED",
1925		Desc: e.Error(),
1926	}
1927}
1928
1929func (e ProvisionUnavailableError) ToStatus() keybase1.Status {
1930	return keybase1.Status{
1931		Code: SCDeviceNoProvision,
1932		Name: "SC_DEVICE_NO_PROVISION",
1933		Desc: e.Error(),
1934	}
1935}
1936
1937func (e ProvisionViaDeviceRequiredError) ToStatus() keybase1.Status {
1938	return keybase1.Status{
1939		Code: SCDeviceProvisionViaDevice,
1940		Name: "SC_DEVICE_PROVISION_VIA_DEVICE",
1941		Desc: e.Error(),
1942	}
1943}
1944
1945func ExportTrackIDComponentToRevokedProof(tidc TrackIDComponent) keybase1.RevokedProof {
1946	key, value := tidc.ToKeyValuePair()
1947	ret := keybase1.RevokedProof{
1948		Diff: *ExportTrackDiff(TrackDiffRevoked{tidc}),
1949		Proof: keybase1.RemoteProof{
1950			Key:           key,
1951			Value:         value,
1952			DisplayMarkup: value,
1953			ProofType:     tidc.GetProofType(),
1954		},
1955	}
1956	return ret
1957}
1958
1959func (e GPGUnavailableError) ToStatus() keybase1.Status {
1960	return keybase1.Status{
1961		Code: SCGPGUnavailable,
1962		Name: "SC_GPG_UNAVAILABLE",
1963		Desc: e.Error(),
1964	}
1965}
1966
1967func (e NotFoundError) ToStatus() keybase1.Status {
1968	return keybase1.Status{
1969		Code: SCNotFound,
1970		Name: "SC_NOT_FOUND",
1971		Desc: e.Error(),
1972	}
1973}
1974
1975func (e UserDeletedError) ToStatus() keybase1.Status {
1976	return keybase1.Status{
1977		Code: SCDeleted,
1978		Name: "SC_DELETED",
1979		Desc: e.Error(),
1980	}
1981}
1982
1983func (e DecryptionError) ToStatus() keybase1.Status {
1984	cause := e.Cause.Err.Error()
1985	return keybase1.Status{
1986		Code: SCDecryptionError,
1987		Name: "SC_DECRYPTION_ERROR",
1988		Fields: []keybase1.StringKVPair{
1989			{Key: "Cause", Value: cause}, // raw developer-friendly string
1990			{Key: "Code", Value: strconv.Itoa(e.Cause.StatusCode)},
1991		},
1992	}
1993}
1994
1995func (e VerificationError) ToStatus() keybase1.Status {
1996	cause := e.Cause.Err.Error()
1997	return keybase1.Status{
1998		Code: SCSigCannotVerify,
1999		Name: "SC_SIG_CANNOT_VERIFY",
2000		Fields: []keybase1.StringKVPair{
2001			{Key: "Cause", Value: cause}, // raw developer-friendly string
2002			{Key: "Code", Value: strconv.Itoa(e.Cause.StatusCode)},
2003		},
2004	}
2005}
2006
2007func (e NoSigChainError) ToStatus() keybase1.Status {
2008	return keybase1.Status{
2009		Code: SCKeyNoEldest,
2010		Name: "SC_KEY_NO_ELDEST",
2011		Desc: e.Error(),
2012	}
2013}
2014
2015func (e KeyRevokedError) ToStatus() keybase1.Status {
2016	return keybase1.Status{
2017		Code: SCKeyRevoked,
2018		Name: "SC_KEY_REVOKED_ERROR",
2019		Desc: e.msg,
2020	}
2021}
2022
2023func (a *APIError) ToStatus() (s keybase1.Status) {
2024	s.Code = SCGenericAPIError
2025	s.Name = "GENERIC_API_ERROR"
2026	s.Desc = a.Msg
2027	s.Fields = []keybase1.StringKVPair{
2028		{Key: "code", Value: fmt.Sprintf("%d", a.Code)},
2029	}
2030	return
2031}
2032
2033func (e DeviceNameInUseError) ToStatus() (s keybase1.Status) {
2034	return keybase1.Status{
2035		Code: SCDeviceNameInUse,
2036		Name: "SC_DEVICE_NAME_IN_USE",
2037		Desc: e.Error(),
2038	}
2039}
2040
2041func (e ChatInternalError) ToStatus() keybase1.Status {
2042	return keybase1.Status{
2043		Code: SCChatInternal,
2044		Name: "SC_CHAT_INTERNAL",
2045		Desc: e.Error(),
2046	}
2047}
2048
2049func (e ChatStalePreviousStateError) ToStatus() keybase1.Status {
2050	return keybase1.Status{
2051		Code: SCChatStalePreviousState,
2052		Name: "SC_CHAT_STALE_PREVIOUS_STATE",
2053		Desc: e.Error(),
2054	}
2055}
2056
2057func (e ChatEphemeralRetentionPolicyViolatedError) ToStatus() keybase1.Status {
2058	kv := keybase1.StringKVPair{
2059		Key:   "MaxAge",
2060		Value: e.MaxAge.ToDuration().String(),
2061	}
2062	return keybase1.Status{
2063		Code:   SCChatEphemeralRetentionPolicyViolatedError,
2064		Name:   "SC_CHAT_EPHEMERAL_RETENTION_POLICY_VIOLATED",
2065		Desc:   e.Error(),
2066		Fields: []keybase1.StringKVPair{kv},
2067	}
2068}
2069
2070func (e ChatConvExistsError) ToStatus() keybase1.Status {
2071	kv := keybase1.StringKVPair{
2072		Key:   "ConvID",
2073		Value: e.ConvID.String(),
2074	}
2075	return keybase1.Status{
2076		Code:   SCChatConvExists,
2077		Name:   "SC_CHAT_CONVEXISTS",
2078		Desc:   e.Error(),
2079		Fields: []keybase1.StringKVPair{kv},
2080	}
2081}
2082
2083func (e ChatUnknownTLFIDError) ToStatus() keybase1.Status {
2084	kv := keybase1.StringKVPair{
2085		Key:   "TlfID",
2086		Value: e.TlfID.String(),
2087	}
2088	return keybase1.Status{
2089		Code:   SCChatUnknownTLFID,
2090		Name:   "SC_CHAT_UNKNOWN_TLFID",
2091		Desc:   e.Error(),
2092		Fields: []keybase1.StringKVPair{kv},
2093	}
2094}
2095
2096func (e ChatNotInConvError) ToStatus() keybase1.Status {
2097	kv := keybase1.StringKVPair{
2098		Key:   "UID",
2099		Value: e.UID.String(),
2100	}
2101	return keybase1.Status{
2102		Code:   SCChatNotInConv,
2103		Name:   "SC_CHAT_NOT_IN_CONV",
2104		Desc:   e.Error(),
2105		Fields: []keybase1.StringKVPair{kv},
2106	}
2107}
2108
2109func (e ChatNotInTeamError) ToStatus() keybase1.Status {
2110	kv := keybase1.StringKVPair{
2111		Key:   "UID",
2112		Value: e.UID.String(),
2113	}
2114	return keybase1.Status{
2115		Code:   SCChatNotInTeam,
2116		Name:   "SC_CHAT_NOT_IN_TEAM",
2117		Desc:   e.Error(),
2118		Fields: []keybase1.StringKVPair{kv},
2119	}
2120}
2121
2122func (e ChatBadMsgError) ToStatus() keybase1.Status {
2123	return keybase1.Status{
2124		Code: SCChatBadMsg,
2125		Name: "SC_CHAT_BADMSG",
2126		Desc: e.Error(),
2127	}
2128}
2129
2130func (e ChatBroadcastError) ToStatus() keybase1.Status {
2131	return keybase1.Status{
2132		Code: SCChatBroadcast,
2133		Name: "SC_CHAT_BROADCAST",
2134		Desc: e.Error(),
2135	}
2136}
2137
2138func (e ChatRateLimitError) ToStatus() keybase1.Status {
2139	b, _ := json.Marshal(e.RateLimit)
2140	kv := keybase1.StringKVPair{
2141		Key:   "RateLimit",
2142		Value: string(b),
2143	}
2144	return keybase1.Status{
2145		Code:   SCChatRateLimit,
2146		Name:   "SC_CHAT_RATELIMIT",
2147		Desc:   e.Error(),
2148		Fields: []keybase1.StringKVPair{kv},
2149	}
2150}
2151
2152func (e ChatAlreadySupersededError) ToStatus() keybase1.Status {
2153	return keybase1.Status{
2154		Code: SCChatAlreadySuperseded,
2155		Name: "SC_CHAT_ALREADY_SUPERSEDED",
2156		Desc: e.Error(),
2157	}
2158}
2159
2160func (e ChatAlreadyDeletedError) ToStatus() keybase1.Status {
2161	return keybase1.Status{
2162		Code: SCChatAlreadyDeleted,
2163		Name: "SC_CHAT_ALREADY_DELETED",
2164		Desc: e.Error(),
2165	}
2166}
2167
2168func (e ChatTLFFinalizedError) ToStatus() keybase1.Status {
2169	kv := keybase1.StringKVPair{
2170		Key:   "TlfID",
2171		Value: e.TlfID.String(),
2172	}
2173	return keybase1.Status{
2174		Code:   SCChatTLFFinalized,
2175		Name:   "SC_CHAT_TLF_FINALIZED",
2176		Desc:   e.Error(),
2177		Fields: []keybase1.StringKVPair{kv},
2178	}
2179}
2180
2181func (e ChatCollisionError) ToStatus() keybase1.Status {
2182	return keybase1.Status{
2183		Code: SCChatCollision,
2184		Name: "SC_CHAT_COLLISION",
2185		Desc: e.Error(),
2186	}
2187}
2188
2189func (e ChatMessageCollisionError) ToStatus() keybase1.Status {
2190	kv := keybase1.StringKVPair{
2191		Key:   "HeaderHash",
2192		Value: e.HeaderHash,
2193	}
2194	return keybase1.Status{
2195		Code:   SCChatMessageCollision,
2196		Name:   "SC_CHAT_MESSAGE_COLLISION",
2197		Desc:   e.Error(),
2198		Fields: []keybase1.StringKVPair{kv},
2199	}
2200}
2201
2202func (e ChatDuplicateMessageError) ToStatus() keybase1.Status {
2203	kv := keybase1.StringKVPair{
2204		Key:   "OutboxID",
2205		Value: e.OutboxID.String(),
2206	}
2207	return keybase1.Status{
2208		Code:   SCChatDuplicateMessage,
2209		Name:   "SC_CHAT_DUPLICATE_MESSAGE",
2210		Desc:   e.Error(),
2211		Fields: []keybase1.StringKVPair{kv},
2212	}
2213}
2214
2215func (e ChatClientError) ToStatus() keybase1.Status {
2216	return keybase1.Status{
2217		Code: SCChatClientError,
2218		Name: "SC_CHAT_CLIENT_ERROR",
2219		Desc: e.Msg,
2220	}
2221}
2222
2223func (e ChatUsersAlreadyInConversationError) ToStatus() keybase1.Status {
2224	fields := []keybase1.StringKVPair{}
2225	for _, uid := range e.Uids {
2226		fields = append(fields, keybase1.StringKVPair{Key: "uid", Value: uid.String()})
2227	}
2228	return keybase1.Status{
2229		Code:   SCChatUsersAlreadyInConversationError,
2230		Name:   "SC_CHAT_USERS_ALREADY_IN_CONVERSATION_ERROR",
2231		Fields: fields,
2232	}
2233}
2234
2235func (e ChatBadConversationError) ToStatus() keybase1.Status {
2236	return keybase1.Status{
2237		Code: SCChatBadConversationError,
2238		Name: "SC_CHAT_BAD_CONVERSATION_ERROR",
2239		Fields: []keybase1.StringKVPair{
2240			{
2241				Key:   "Msg",
2242				Value: e.Msg,
2243			},
2244		},
2245	}
2246}
2247
2248func (e BadEmailError) ToStatus() keybase1.Status {
2249	return keybase1.Status{
2250		Code: SCBadEmail,
2251		Name: "SC_BAD_EMAIL",
2252		Desc: e.Error(),
2253	}
2254}
2255
2256func (e ExistsError) ToStatus() keybase1.Status {
2257	return keybase1.Status{
2258		Code: SCExists,
2259		Name: "SC_EXISTS",
2260		Desc: e.Error(),
2261	}
2262}
2263
2264func (e InvalidAddressError) ToStatus() keybase1.Status {
2265	return keybase1.Status{
2266		Code: SCInvalidAddress,
2267		Name: "SC_INVALID_ADDRESS",
2268		Desc: e.Error(),
2269	}
2270}
2271
2272func (e NeedSelfRekeyError) ToStatus() keybase1.Status {
2273	return keybase1.Status{
2274		Code: SCNeedSelfRekey,
2275		Name: "SC_NEED_SELF_REKEY",
2276		Desc: e.Error(),
2277	}
2278}
2279
2280func (e NeedOtherRekeyError) ToStatus() keybase1.Status {
2281	return keybase1.Status{
2282		Code: SCNeedOtherRekey,
2283		Name: "SC_NEED_OTHER_REKEY",
2284		Desc: e.Error(),
2285	}
2286}
2287
2288func ImportDbKey(k keybase1.DbKey) DbKey {
2289	return DbKey{
2290		Typ: ObjType(k.ObjType),
2291		Key: k.Key,
2292	}
2293}
2294
2295func (e AccountResetError) ToStatus() keybase1.Status {
2296	return keybase1.Status{
2297		Code: SCAccountReset,
2298		Name: "ACCOUNT_RESET",
2299		Desc: e.Error(),
2300		Fields: []keybase1.StringKVPair{
2301			{Key: "e_uid", Value: string(e.expected.Uid)},
2302			{Key: "e_version", Value: fmt.Sprintf("%d", e.expected.EldestSeqno)},
2303			{Key: "r_version", Value: fmt.Sprintf("%d", e.received)},
2304		},
2305	}
2306}
2307
2308func (e LoginStateTimeoutError) ToStatus() keybase1.Status {
2309	return keybase1.Status{
2310		Code: SCLoginStateTimeout,
2311		Name: "LOGIN_STATE_TIMEOUT",
2312		Desc: e.Error(),
2313		Fields: []keybase1.StringKVPair{
2314			{Key: "ActiveRequest", Value: e.ActiveRequest},
2315			{Key: "AttemptedRequest", Value: e.AttemptedRequest},
2316			{Key: "Duration", Value: e.Duration.String()},
2317		},
2318	}
2319}
2320
2321func (e RevokeCurrentDeviceError) ToStatus() keybase1.Status {
2322	return keybase1.Status{
2323		Code: SCRevokeCurrentDevice,
2324		Name: "SC_DEVICE_REVOKE_CURRENT",
2325		Desc: e.Error(),
2326	}
2327}
2328
2329func (e RevokeLastDeviceError) ToStatus() keybase1.Status {
2330	x := keybase1.Status{
2331		Code: SCRevokeLastDevice,
2332		Name: "SC_DEVICE_REVOKE_LAST",
2333		Desc: e.Error(),
2334	}
2335
2336	if e.NoPassphrase {
2337		x.Fields = []keybase1.StringKVPair{
2338			{Key: "NoPassphrase", Value: "true"},
2339		}
2340	}
2341
2342	return x
2343}
2344
2345func (e RevokeLastDevicePGPError) ToStatus() keybase1.Status {
2346	return keybase1.Status{
2347		Code: SCRevokeLastDevicePGP,
2348		Name: "SC_DEVICE_REVOKE_LAST_PGP",
2349		Desc: e.Error(),
2350	}
2351}
2352
2353func (e KeyMaskNotFoundError) ToStatus() keybase1.Status {
2354	return keybase1.Status{
2355		Code: SCTeamKeyMaskNotFound,
2356		Name: "TEAM_KEY_MASK_NOT_FOUND",
2357		Desc: e.Error(),
2358		Fields: []keybase1.StringKVPair{
2359			{Key: "App", Value: strconv.Itoa(int(e.App))},
2360			{Key: "Gen", Value: strconv.Itoa(int(e.Gen))},
2361		},
2362	}
2363}
2364
2365func (e ProvisionFailedOfflineError) ToStatus() keybase1.Status {
2366	return keybase1.Status{
2367		Code: SCDeviceProvisionOffline,
2368		Name: "SC_DEVICE_PROVISION_OFFLINE",
2369		Desc: e.Error(),
2370	}
2371}
2372
2373func (e InvalidRepoNameError) ToStatus() (s keybase1.Status) {
2374	s.Code = int(keybase1.StatusCode_SCGitInvalidRepoName)
2375	s.Name = "GIT_INVALID_REPO_NAME"
2376	s.Desc = e.Error()
2377	s.Fields = []keybase1.StringKVPair{
2378		{Key: "Name", Value: e.Name},
2379	}
2380	return
2381}
2382
2383func (e RepoAlreadyExistsError) ToStatus() (s keybase1.Status) {
2384	s.Code = int(keybase1.StatusCode_SCGitRepoAlreadyExists)
2385	s.Name = "GIT_REPO_ALREADY_EXISTS"
2386	s.Desc = e.Error()
2387	s.Fields = []keybase1.StringKVPair{
2388		{Key: "DesiredName", Value: e.DesiredName},
2389		{Key: "ExistingName", Value: e.ExistingName},
2390		{Key: "ExistingID", Value: e.ExistingID},
2391	}
2392	return
2393}
2394
2395func (e RepoDoesntExistError) ToStatus() (s keybase1.Status) {
2396	s.Code = int(keybase1.StatusCode_SCGitRepoDoesntExist)
2397	s.Name = "GIT_REPO_DOESNT_EXIST"
2398	s.Desc = e.Error()
2399	s.Fields = []keybase1.StringKVPair{
2400		{Key: "Name", Value: e.Name},
2401	}
2402	return
2403}
2404
2405func (e NoOpError) ToStatus() (s keybase1.Status) {
2406	s.Code = SCNoOp
2407	s.Name = "SC_NO_OP"
2408	s.Desc = e.Desc
2409	return
2410}
2411
2412func (e NoSpaceOnDeviceError) ToStatus() (s keybase1.Status) {
2413	s.Code = SCNoSpaceOnDevice
2414	s.Name = "NO_SPACE_ON_DEVICE"
2415	s.Desc = e.Desc
2416	return
2417}
2418
2419func (e TeamInviteBadTokenError) ToStatus() (s keybase1.Status) {
2420	s.Code = SCTeamInviteBadToken
2421	s.Name = "TEAM_INVITE_BAD_TOKEN"
2422	return
2423}
2424
2425func (e TeamInviteTokenReusedError) ToStatus() (s keybase1.Status) {
2426	s.Code = SCTeamInviteTokenReused
2427	s.Name = "TEAM_INVITE_TOKEN_REUSED"
2428	return
2429}
2430
2431func (e TeamBadMembershipError) ToStatus() (s keybase1.Status) {
2432	s.Code = SCTeamBadMembership
2433	s.Name = "TEAM_BAD_MEMBERSHIP"
2434	return
2435}
2436
2437func (e TeamProvisionalError) ToStatus() keybase1.Status {
2438	var ret keybase1.Status
2439	if e.CanKey {
2440		ret.Code = SCTeamProvisionalCanKey
2441		ret.Name = "TEAM_PROVISIONAL_CAN_KEY"
2442		ret.Fields = append(ret.Fields, keybase1.StringKVPair{Key: "CanKey", Value: "1"})
2443	} else {
2444		ret.Code = SCTeamProvisionalCannotKey
2445		ret.Name = "TEAM_PROVISIONAL_CANNOT_KEY"
2446	}
2447	ret.Fields = append(ret.Fields, keybase1.StringKVPair{Key: "PreResolveDisplayName", Value: e.PreResolveDisplayName})
2448	if e.IsPublic {
2449		ret.Fields = append(ret.Fields, keybase1.StringKVPair{Key: "IsPublic", Value: "1"})
2450	}
2451	return ret
2452}
2453
2454func (e EphemeralPairwiseMACsMissingUIDsError) ToStatus() (ret keybase1.Status) {
2455	ret.Code = SCEphemeralPairwiseMACsMissingUIDs
2456	ret.Name = "EPHEMERAL_PAIRWISE_MACS_MISSING_UIDS"
2457	for _, uid := range e.UIDs {
2458		ret.Fields = append(ret.Fields, keybase1.StringKVPair{
2459			Key:   "uid",
2460			Value: uid.String(),
2461		})
2462	}
2463	return ret
2464}
2465
2466func (e MerkleClientError) ToStatus() (ret keybase1.Status) {
2467	ret.Code = SCMerkleClientError
2468	ret.Name = "MERKLE_CLIENT_ERROR"
2469	ret.Fields = append(ret.Fields, keybase1.StringKVPair{Key: "type", Value: fmt.Sprintf("%d", int(e.t))})
2470	ret.Desc = e.m
2471	return ret
2472}
2473
2474func (e FeatureFlagError) ToStatus() (ret keybase1.Status) {
2475	ret.Code = SCFeatureFlag
2476	ret.Name = "FEATURE_FLAG"
2477	ret.Desc = e.msg
2478	ret.Fields = []keybase1.StringKVPair{{Key: "feature", Value: string(e.feature)}}
2479	return ret
2480}
2481
2482func (e BadUsernameError) ToStatus() (ret keybase1.Status) {
2483	ret.Code = SCBadUsername
2484	ret.Name = "BAD_USERNAME"
2485	ret.Desc = e.Error()
2486	return ret
2487}
2488
2489func (e NoPaperKeysError) ToStatus() (ret keybase1.Status) {
2490	ret.Code = SCNoPaperKeys
2491	ret.Name = "NO_PAPER_KEYS"
2492	ret.Desc = e.Error()
2493	return
2494}
2495
2496func (e TeamContactSettingsBlockError) ToStatus() (ret keybase1.Status) {
2497	ret.Code = SCTeamContactSettingsBlock
2498	ret.Name = "TEAM_CONTACT_SETTINGS_BLOCK"
2499	ret.Desc = e.Error()
2500	ret.Fields = []keybase1.StringKVPair{
2501		{Key: "uids", Value: parseUIDsToString(e.blockedUIDs)},
2502		{Key: "usernames", Value: parseUsernamesToString(e.blockedUsernames)},
2503	}
2504	return
2505}
2506
2507func parseUIDsToString(input []keybase1.UID) string {
2508	uids := make([]string, len(input))
2509	for i, uid := range input {
2510		uids[i] = uid.String()
2511	}
2512	return strings.Join(uids, ",")
2513}
2514
2515func parseUsernamesToString(input []NormalizedUsername) string {
2516	usernames := make([]string, len(input))
2517	for i, username := range input {
2518		usernames[i] = username.String()
2519	}
2520	return strings.Join(usernames, ",")
2521}
2522
2523func (e AssertionParseError) ToStatus() (ret keybase1.Status) {
2524	ret.Code = SCAssertionParseError
2525	ret.Name = "ASSERTION_PARSE_ERROR"
2526	ret.Desc = e.Error()
2527	ret.Fields = append(ret.Fields, keybase1.StringKVPair{Key: "err", Value: e.err})
2528	ret.Fields = append(ret.Fields, keybase1.StringKVPair{Key: "reason", Value: fmt.Sprintf("%d", e.reason)})
2529	return
2530}
2531