1package teams
2
3import (
4	"fmt"
5
6	"golang.org/x/net/context"
7
8	"github.com/keybase/client/go/libkb"
9	"github.com/keybase/client/go/protocol/keybase1"
10)
11
12func NewStubbedError(l *ChainLinkUnpacked) StubbedError {
13	return StubbedError{l: l, note: nil}
14}
15
16func NewStubbedErrorWithNote(l *ChainLinkUnpacked, note string) StubbedError {
17	return StubbedError{l: l, note: &note}
18}
19
20type StubbedError struct {
21	l    *ChainLinkUnpacked
22	note *string
23}
24
25func (e StubbedError) Error() string {
26	if e.note == nil {
27		return fmt.Sprintf("stubbed link when not expected (seqno %d)", int(e.l.outerLink.Seqno))
28	}
29	return fmt.Sprintf("%s (stubbed link when not expected; at seqno %d)",
30		*e.note, int(e.l.outerLink.Seqno))
31}
32
33type InvalidLink struct {
34	l    *ChainLinkUnpacked
35	note string
36}
37
38func (e InvalidLink) Error() string {
39	return fmt.Sprintf("invalid link (seqno %d): %s", e.l.Seqno(), e.note)
40}
41
42func NewInvalidLink(l *ChainLinkUnpacked, format string, args ...interface{}) InvalidLink {
43	return InvalidLink{l, fmt.Sprintf(format, args...)}
44}
45
46type AppendLinkError struct {
47	prevSeqno keybase1.Seqno
48	l         *ChainLinkUnpacked
49	inner     error
50}
51
52func (e AppendLinkError) Error() string {
53	return fmt.Sprintf("appending %v->%v: %v", e.prevSeqno, e.l.Seqno(), e.inner)
54}
55
56func (e AppendLinkError) Unwrap() error {
57	return e.inner
58}
59
60func NewAppendLinkError(l *ChainLinkUnpacked, prevSeqno keybase1.Seqno, inner error) AppendLinkError {
61	return AppendLinkError{prevSeqno, l, inner}
62}
63
64type InflateError struct {
65	l    *ChainLinkUnpacked
66	note *string
67}
68
69func (e InflateError) Error() string {
70	if e.note == nil {
71		return fmt.Sprintf("error inflating previously-stubbed link (seqno %d)", int(e.l.outerLink.Seqno))
72	}
73	return fmt.Sprintf("error inflating previously-stubbed link (seqno %d) (%s)",
74		int(e.l.outerLink.Seqno), *e.note)
75}
76
77func NewInflateError(l *ChainLinkUnpacked) InflateError {
78	return InflateError{l: l, note: nil}
79}
80
81func NewInflateErrorWithNote(l *ChainLinkUnpacked, note string) InflateError {
82	return InflateError{l: l, note: &note}
83}
84
85type UnexpectedSeqnoError struct {
86	expected keybase1.Seqno
87	actual   keybase1.Seqno
88}
89
90func (e UnexpectedSeqnoError) Error() string {
91	return fmt.Sprintf("expected seqno:%v but got %v", e.expected, e.actual)
92}
93
94func NewUnexpectedSeqnoError(expected, actual keybase1.Seqno) UnexpectedSeqnoError {
95	return UnexpectedSeqnoError{expected, actual}
96}
97
98type AdminPermissionError struct {
99	TeamID      keybase1.TeamID
100	UserVersion keybase1.UserVersion
101	Desc        string
102}
103
104func (e AdminPermissionError) Error() string {
105	return fmt.Sprintf("For team %s, user %s: %s", e.TeamID, e.UserVersion.PercentForm(), e.Desc)
106}
107
108func NewAdminPermissionError(t keybase1.TeamID, uv keybase1.UserVersion, d string) AdminPermissionError {
109	return AdminPermissionError{t, uv, d}
110}
111
112type AdminNotFoundError struct {
113	Admin SCTeamAdmin
114}
115
116func (e AdminNotFoundError) Error() string {
117	return fmt.Sprintf("Admin permission specified in %+v wasn't found", e.Admin)
118}
119
120func NewAdminNotFoundError(a SCTeamAdmin) AdminNotFoundError {
121	return AdminNotFoundError{a}
122}
123
124type ProofError struct {
125	p   proof
126	msg string
127}
128
129func NewProofError(p proof, s string) ProofError {
130	return ProofError{p, s}
131}
132
133func (p ProofError) Error() string {
134	return fmt.Sprintf("proof error for proof '%s': %s", p.p.reason, p.msg)
135}
136
137type PermissionError struct {
138	TeamID      keybase1.TeamID
139	UserVersion keybase1.UserVersion
140	Desc        string
141}
142
143func NewPermissionError(t keybase1.TeamID, uv keybase1.UserVersion, d string) PermissionError {
144	return PermissionError{t, uv, d}
145}
146
147func (e PermissionError) Error() string {
148	return fmt.Sprintf("For team %s, user %s: %s", e.TeamID, e.UserVersion.PercentForm(), e.Desc)
149}
150
151type PrevError struct {
152	Msg string
153}
154
155func NewPrevError(format string, args ...interface{}) error {
156	return PrevError{fmt.Sprintf(format, args...)}
157}
158
159func (e PrevError) Error() string {
160	return e.Msg
161}
162
163type InviteError struct {
164	id  keybase1.TeamInviteID
165	err error
166}
167
168func NewInviteError(id keybase1.TeamInviteID, err error) InviteError {
169	return InviteError{id: id, err: err}
170}
171
172func (i InviteError) Error() string {
173	return fmt.Sprintf("Invite error: Invite ID %s: %s", i.id, i.err)
174}
175
176func (i InviteError) Unwrap() error {
177	return i.err
178}
179
180type InvitelinkBadRoleError struct {
181	role keybase1.TeamRole
182}
183
184func NewInvitelinkBadRoleError(role keybase1.TeamRole) InvitelinkBadRoleError {
185	return InvitelinkBadRoleError{role: role}
186}
187
188func (i InvitelinkBadRoleError) Error() string {
189	return fmt.Sprintf("Cannot create invitelink to add invitees as %s", i.role)
190}
191
192type ResolveError struct {
193	name keybase1.TeamName
194	id   keybase1.TeamID
195}
196
197func (e ResolveError) Error() string {
198	return fmt.Sprintf("mismatched team name and id: %v <-/-> %v", e.name.String(), e.id.String())
199}
200
201func NewResolveError(name keybase1.TeamName, id keybase1.TeamID) ResolveError {
202	return ResolveError{name, id}
203}
204
205type TeamDoesNotExistError struct {
206	descriptor string
207	public     bool // Whether this is about the public version of the team
208}
209
210func (e TeamDoesNotExistError) Error() string {
211	if e.public {
212		return fmt.Sprintf("Team %q (public) does not exist", e.descriptor)
213	}
214	return fmt.Sprintf("Team %q does not exist", e.descriptor)
215}
216
217func NewTeamDoesNotExistError(public bool, format string, args ...interface{}) error {
218	return TeamDoesNotExistError{
219		descriptor: fmt.Sprintf(format, args...),
220		public:     public,
221	}
222}
223
224type ImplicitTeamOperationError struct {
225	msg string
226}
227
228func (e ImplicitTeamOperationError) Error() string {
229	return fmt.Sprintf("Implicit team operation not allowed: %v", e.msg)
230}
231
232type ExplicitTeamOperationError struct {
233	msg string
234}
235
236func (e ExplicitTeamOperationError) Error() string {
237	return fmt.Sprintf("Operation only allowed on implicit teams: %s", e.msg)
238}
239
240func NewImplicitTeamOperationError(format string, args ...interface{}) error {
241	return &ImplicitTeamOperationError{msg: fmt.Sprintf(format, args...)}
242}
243
244func NewExplicitTeamOperationError(m string) error {
245	return &ExplicitTeamOperationError{msg: m}
246}
247
248func IsTeamReadError(err error) bool {
249	aerr, ok := err.(libkb.AppStatusError)
250	return ok && keybase1.StatusCode(aerr.Code) == keybase1.StatusCode_SCTeamReadError
251}
252
253func FixupTeamGetError(ctx context.Context, g *libkb.GlobalContext, e error, teamDescriptor string, publicTeam bool) error {
254	return fixupTeamGetError(ctx, g, e, teamDescriptor, publicTeam)
255}
256
257func fixupTeamGetError(ctx context.Context, g *libkb.GlobalContext, e error, teamDescriptor string, publicTeam bool) error {
258	if e == nil {
259		return nil
260	}
261	switch e := e.(type) {
262	case libkb.AppStatusError:
263		switch keybase1.StatusCode(e.Code) {
264		case keybase1.StatusCode_SCTeamReadError:
265			g.Log.CDebugf(ctx, "replacing error: %v", e)
266			e.Desc = fmt.Sprintf("You are not a member of team %q; try `keybase team request-access %s` for access", teamDescriptor, teamDescriptor)
267			return e
268		case keybase1.StatusCode_SCTeamNotFound:
269			g.Log.CDebugf(ctx, "replacing error: %v", e)
270			return NewTeamDoesNotExistError(publicTeam, teamDescriptor)
271		}
272	case TeamDoesNotExistError:
273		// Replace the not found error so that it has a name instead of team ID.
274		// If subteams are involved the name might not correspond to the ID
275		// but it's better to have this understandable error message that's accurate
276		// most of the time than one with an ID that's always accurate.
277		g.Log.CDebugf(ctx, "replacing error: %v", e)
278		return NewTeamDoesNotExistError(publicTeam, teamDescriptor)
279	}
280	return e
281}
282
283func NewKeyMaskNotFoundErrorForApplication(a keybase1.TeamApplication) libkb.KeyMaskNotFoundError {
284	return libkb.KeyMaskNotFoundError{App: a}
285}
286
287func NewKeyMaskNotFoundErrorForApplicationAndGeneration(a keybase1.TeamApplication, g keybase1.PerTeamKeyGeneration) libkb.KeyMaskNotFoundError {
288	return libkb.KeyMaskNotFoundError{App: a, Gen: g}
289}
290
291type AdminPermissionRequiredError struct{}
292
293func NewAdminPermissionRequiredError() error { return &AdminPermissionRequiredError{} }
294
295func (e *AdminPermissionRequiredError) Error() string {
296	return "Only admins can perform this operation."
297}
298
299type ImplicitAdminCannotLeaveError struct{}
300
301func NewImplicitAdminCannotLeaveError() error { return &ImplicitAdminCannotLeaveError{} }
302
303func (e ImplicitAdminCannotLeaveError) Error() string {
304	return "You cannot leave this team. You are an implicit admin (admin of a parent team) but not an explicit member."
305}
306
307type NotExplicitMemberOfSubteamError struct{}
308
309func NewNotExplicitMemberOfSubteamError() error { return NotExplicitMemberOfSubteamError{} }
310
311func (e NotExplicitMemberOfSubteamError) Error() string {
312	return "You are not an explicit member of this subteam, so you can't access chats or files; try adding yourself (if you're an admin of the parent team)"
313}
314
315func (e NotExplicitMemberOfSubteamError) HumanError() error {
316	return e
317}
318
319type TeamTombstonedError struct{}
320
321func NewTeamTombstonedError() error { return &TeamTombstonedError{} }
322
323func (e TeamTombstonedError) Error() string {
324	return "team has been tombstoned"
325}
326
327type TeamDeletedError struct{}
328
329func NewTeamDeletedError() error { return &TeamDeletedError{} }
330
331func (e TeamDeletedError) Error() string {
332	return "team has been deleted"
333}
334
335type SubteamOwnersError struct{}
336
337func NewSubteamOwnersError() error { return &SubteamOwnersError{} }
338
339func (e SubteamOwnersError) Error() string {
340	return "Subteams cannot have owners. Try admin instead."
341}
342
343// The sigchain link is problematically new.
344type GreenLinkError struct{ seqno keybase1.Seqno }
345
346func NewGreenLinkError(seqno keybase1.Seqno) error {
347	return GreenLinkError{seqno: seqno}
348}
349
350func (e GreenLinkError) Error() string {
351	// Report the probable cause for this error.
352	return fmt.Sprintf("team sigchain is being rapidly updated (seqno: %v)", e.seqno)
353}
354
355type UnsupportedLinkTypeError struct {
356	outerType libkb.SigchainV2Type
357	innerType string
358}
359
360func NewUnsupportedLinkTypeError(outerType libkb.SigchainV2Type, innerType string) error {
361	return UnsupportedLinkTypeError{
362		outerType: outerType,
363		innerType: innerType,
364	}
365}
366
367func (e UnsupportedLinkTypeError) Error() string {
368	return fmt.Sprintf("unsupported team link type: %v (%v)", e.outerType, e.innerType)
369}
370
371type PrecheckAppendError struct {
372	Inner error
373}
374
375func NewPrecheckAppendError(inner error) error { return PrecheckAppendError{Inner: inner} }
376
377func (e PrecheckAppendError) Error() string {
378	return fmt.Sprintf("Precheck append error: %v", e.Inner)
379}
380
381func (e PrecheckAppendError) Unwrap() error {
382	return e.Inner
383}
384
385type PrecheckStructuralError struct {
386	Inner error
387	Msg   string
388}
389
390func NewPrecheckStructuralError(message string, inner error) error {
391	return PrecheckStructuralError{Inner: inner, Msg: message}
392}
393
394func (e PrecheckStructuralError) Error() string {
395	if e.Inner != nil {
396		return fmt.Sprintf("Precheck structural error: %s: %v", e.Msg, e.Inner)
397	}
398	return e.Msg
399}
400
401type AttemptedInviteSocialOwnerError struct{ Msg string }
402
403func NewAttemptedInviteSocialOwnerError(assertion string) error {
404	them := assertion
405	if assertion == "" {
406		them = "That user"
407	}
408	return AttemptedInviteSocialOwnerError{Msg: fmt.Sprintf("%v doesn't have a Keybase account yet, so you can't add them"+
409		" as an owner; you can add them as reader or writer.", them)}
410}
411
412func (e AttemptedInviteSocialOwnerError) Error() string { return e.Msg }
413
414type UserHasNotResetError struct{ Msg string }
415
416func NewUserHasNotResetError(format string, args ...interface{}) error {
417	return UserHasNotResetError{Msg: fmt.Sprintf(format, args...)}
418}
419
420func (e UserHasNotResetError) Error() string { return e.Msg }
421
422type AddMembersError struct {
423	Assertion libkb.AssertionExpression
424	Err       error
425}
426
427func NewAddMembersError(a libkb.AssertionExpression, e error) AddMembersError {
428	return AddMembersError{a, e}
429}
430
431func (a AddMembersError) Error() string {
432	if a.Assertion == nil {
433		return fmt.Sprintf("Error adding members: %v", a.Err)
434	}
435	urls := a.Assertion.CollectUrls(nil)
436	if len(urls) == 1 && urls[0].IsEmail() {
437		return fmt.Sprintf("Error adding email %q: %v", urls[0].GetValue(), a.Err)
438	}
439	return fmt.Sprintf("Error adding %q: %v", a.Assertion.String(), a.Err)
440}
441
442type BadNameError struct {
443	Msg string
444}
445
446func (b BadNameError) Error() string {
447	return fmt.Sprintf("bad name error: %s", b.Msg)
448}
449
450func NewBadNameError(s string) BadNameError {
451	return BadNameError{Msg: s}
452}
453
454type FastLoadError struct {
455	Msg string
456}
457
458func (f FastLoadError) Error() string {
459	return fmt.Sprintf("fast load error: %s", f.Msg)
460}
461
462func NewFastLoadError(format string, args ...interface{}) error {
463	return FastLoadError{Msg: fmt.Sprintf(format, args...)}
464}
465
466type BadPublicError struct {
467	id       keybase1.TeamID
468	isPublic bool
469}
470
471func NewBadPublicError(id keybase1.TeamID, isPublic bool) error {
472	return BadPublicError{id, isPublic}
473}
474
475func (e BadPublicError) Error() string {
476	return fmt.Sprintf("Public bit for team %s is wrong (%v)", e.id, e.isPublic)
477}
478
479type AuditError struct {
480	Msg string
481}
482
483func NewAuditError(format string, args ...interface{}) error {
484	return AuditError{Msg: fmt.Sprintf(format, args...)}
485}
486
487func (e AuditError) Error() string {
488	return fmt.Sprintf("Audit error: %s", e.Msg)
489}
490
491type KBFSKeyGenerationError struct {
492	Required, Exists int
493}
494
495func NewKBFSKeyGenerationError(required, exists int) KBFSKeyGenerationError {
496	return KBFSKeyGenerationError{
497		Required: required,
498		Exists:   exists,
499	}
500}
501
502func (e KBFSKeyGenerationError) Error() string {
503	return fmt.Sprintf("KBFS key generation too low: %v < %v", e.Exists, e.Required)
504}
505
506type FTLMissingSeedError struct {
507	gen keybase1.PerTeamKeyGeneration
508}
509
510func NewFTLMissingSeedError(g keybase1.PerTeamKeyGeneration) error {
511	return FTLMissingSeedError{gen: g}
512}
513
514func (e FTLMissingSeedError) Error() string {
515	return fmt.Sprintf("FTL Missing seed at generation: %d", e.gen)
516}
517
518type MixedServerTrustAssertionError struct{}
519
520func NewMixedServerTrustAssertionError() error {
521	return MixedServerTrustAssertionError{}
522}
523
524func (e MixedServerTrustAssertionError) Error() string {
525	return "cannot add team members via server trust (email or SMS) and also with checkable assertions"
526}
527
528type CompoundInviteError struct {
529	Assertion string
530}
531
532func NewCompoundInviteError(s string) error {
533	return CompoundInviteError{s}
534}
535
536func (e CompoundInviteError) Error() string {
537	return fmt.Sprintf("cannot pair an invitation with a compound assertion (%s)", e.Assertion)
538}
539
540type StaleBoxError interface {
541	IsStaleBoxError()
542}
543
544type BoxRaceError struct {
545	inner error
546}
547
548func (e BoxRaceError) Error() string {
549	return e.inner.Error()
550}
551
552func (e BoxRaceError) IsStaleBoxError() {}
553
554func isStaleBoxError(err error) bool {
555	if err == nil {
556		return false
557	}
558	_, ok := err.(StaleBoxError)
559	return ok
560}
561
562type NeedHiddenChainRotationError struct{}
563
564func (e NeedHiddenChainRotationError) Error() string {
565	return "need hidden chain rotation"
566}
567
568type MissingReaderKeyMaskError struct {
569	gen keybase1.PerTeamKeyGeneration
570	app keybase1.TeamApplication
571}
572
573func NewMissingReaderKeyMaskError(gen keybase1.PerTeamKeyGeneration, app keybase1.TeamApplication) error {
574	return MissingReaderKeyMaskError{gen, app}
575}
576
577func (e MissingReaderKeyMaskError) Error() string {
578	return fmt.Sprintf("missing reader key mask for gen:%v app:%v", e.gen, e.app)
579}
580
581type MapAncestorsError struct {
582	err error
583
584	// failedLoadingAtAncestorIdx indicates the team the MapTeamAncestors load failed at.
585	// So if it failed loading the initial team passed in, failedLoadingAtAncestorIdx=0.
586	// Each successive parent team adds one to the index. So if the team tree were
587	// A.B.C.D.E and MapTeamAncestors was called on D, and the function failed at B,
588	// failed=2.
589	failedLoadingAtAncestorIdx int
590}
591
592func NewMapAncestorsError(err error, failedLoadingAtAncestorIdx int) error {
593	return &MapAncestorsError{err, failedLoadingAtAncestorIdx}
594}
595
596func (e *MapAncestorsError) Error() string {
597	return fmt.Sprintf("failed to load ancestor %d during load: %s",
598		e.failedLoadingAtAncestorIdx, e.err)
599}
600
601func (e *MapAncestorsError) Unwrap() error {
602	return e.err
603}
604
605// MemberNotFoundInChainError is an error that is returned when a member is not in a team, and this
606// fact is verified in the sigchain (i.e., not servertrust).
607type MemberNotFoundInChainError struct {
608	err error
609}
610
611func NewMemberNotFoundInChainError(err error) error {
612	return &MemberNotFoundInChainError{err}
613}
614
615func (e *MemberNotFoundInChainError) Error() string {
616	return fmt.Sprintf("could not find team member in team: %s", e.err)
617}
618
619func (e *MemberNotFoundInChainError) Unwrap() error {
620	return e.err
621}
622
623type InviteLinkAcceptanceError struct {
624	Cause error
625}
626
627func (e InviteLinkAcceptanceError) Error() string {
628	return fmt.Sprintf("InviteLinkAcceptanceError: %s", e.Cause)
629}
630
631func NewInviteLinkAcceptanceError(format string, args ...interface{}) InviteLinkAcceptanceError {
632	return InviteLinkAcceptanceError{fmt.Errorf(format, args...)}
633}
634