github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/chat/errors.go (about) 1 package chat 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "time" 8 9 "github.com/keybase/client/go/chat/types" 10 "github.com/keybase/client/go/ephemeral" 11 "github.com/keybase/client/go/libkb" 12 "github.com/keybase/client/go/protocol/chat1" 13 "github.com/keybase/client/go/protocol/gregor1" 14 "github.com/keybase/client/go/protocol/keybase1" 15 "github.com/keybase/client/go/teams" 16 "github.com/keybase/go-framed-msgpack-rpc/rpc" 17 "golang.org/x/net/context" 18 ) 19 20 var ErrChatServerTimeout = errors.New("timeout calling chat server") 21 var ErrDuplicateConnection = errors.New("error calling chat server") 22 var ErrKeyServerTimeout = errors.New("timeout calling into key server") 23 24 func NewPermanentUnboxingError(inner error) types.UnboxingError { 25 return PermanentUnboxingError{inner} 26 } 27 28 type PermanentUnboxingError struct{ inner error } 29 30 func (e PermanentUnboxingError) Error() string { 31 switch err := e.inner.(type) { 32 case EphemeralUnboxingError, NotAuthenticatedForThisDeviceError: 33 return err.Error() 34 default: 35 return fmt.Sprintf("Unable to decrypt chat message: %s", err.Error()) 36 } 37 } 38 39 func (e PermanentUnboxingError) IsPermanent() bool { return true } 40 41 func (e PermanentUnboxingError) Inner() error { return e.inner } 42 43 func (e PermanentUnboxingError) ExportType() chat1.MessageUnboxedErrorType { 44 switch err := e.inner.(type) { 45 case VersionError: 46 return err.ExportType() 47 case EphemeralUnboxingError: 48 return chat1.MessageUnboxedErrorType_EPHEMERAL 49 case NotAuthenticatedForThisDeviceError, InvalidMACError: 50 return chat1.MessageUnboxedErrorType_PAIRWISE_MISSING 51 default: 52 return chat1.MessageUnboxedErrorType_MISC 53 } 54 } 55 56 func (e PermanentUnboxingError) VersionKind() chat1.VersionKind { 57 switch err := e.inner.(type) { 58 case VersionError: 59 return err.VersionKind() 60 default: 61 return "" 62 } 63 } 64 65 func (e PermanentUnboxingError) VersionNumber() int { 66 switch err := e.inner.(type) { 67 case VersionError: 68 return err.VersionNumber() 69 default: 70 return 0 71 } 72 } 73 74 func (e PermanentUnboxingError) IsCritical() bool { 75 switch err := e.inner.(type) { 76 case VersionError: 77 return err.IsCritical() 78 default: 79 return false 80 } 81 } 82 83 func (e PermanentUnboxingError) InternalError() string { 84 switch err := e.Inner().(type) { 85 case types.InternalError: 86 return err.InternalError() 87 default: 88 return err.Error() 89 } 90 } 91 92 func (e PermanentUnboxingError) ToStatus() (status keybase1.Status) { 93 if ee, ok := e.inner.(libkb.ExportableError); ok { 94 status = ee.ToStatus() 95 status.Desc = e.Error() 96 } else { 97 status = keybase1.Status{ 98 Name: "GENERIC", 99 Code: libkb.SCGeneric, 100 Desc: e.Error(), 101 } 102 } 103 return status 104 } 105 106 // ============================================================================= 107 108 func NewTransientUnboxingError(inner error) types.UnboxingError { 109 return TransientUnboxingError{inner} 110 } 111 112 type TransientUnboxingError struct{ inner error } 113 114 func (e TransientUnboxingError) Error() string { 115 return fmt.Sprintf("Unable to decrypt chat message (transient): %s", e.inner.Error()) 116 } 117 118 func (e TransientUnboxingError) IsPermanent() bool { return false } 119 120 func (e TransientUnboxingError) Inner() error { return e.inner } 121 122 func (e TransientUnboxingError) ExportType() chat1.MessageUnboxedErrorType { 123 return chat1.MessageUnboxedErrorType_MISC 124 } 125 126 func (e TransientUnboxingError) VersionKind() chat1.VersionKind { 127 return "" 128 } 129 130 func (e TransientUnboxingError) VersionNumber() int { 131 return 0 132 } 133 134 func (e TransientUnboxingError) IsCritical() bool { 135 return false 136 } 137 138 func (e TransientUnboxingError) InternalError() string { 139 switch err := e.Inner().(type) { 140 case types.InternalError: 141 return err.InternalError() 142 default: 143 return err.Error() 144 } 145 } 146 147 func (e TransientUnboxingError) ToStatus() (status keybase1.Status) { 148 if ee, ok := e.inner.(libkb.ExportableError); ok { 149 status = ee.ToStatus() 150 status.Desc = e.Error() 151 } else { 152 status = keybase1.Status{ 153 Name: "GENERIC", 154 Code: libkb.SCGeneric, 155 Desc: e.Error(), 156 } 157 } 158 return status 159 } 160 161 // ============================================================================= 162 163 type EphemeralAlreadyExpiredError struct{} 164 165 func NewEphemeralAlreadyExpiredError() EphemeralAlreadyExpiredError { 166 return EphemeralAlreadyExpiredError{} 167 } 168 169 func (e EphemeralAlreadyExpiredError) Error() string { 170 return "Exploding message is expired" 171 } 172 173 func (e EphemeralAlreadyExpiredError) InternalError() string { 174 return e.Error() 175 } 176 177 // ============================================================================= 178 179 type EphemeralUnboxingError struct { 180 inner ephemeral.EphemeralKeyError 181 } 182 183 func NewEphemeralUnboxingError(inner ephemeral.EphemeralKeyError) EphemeralUnboxingError { 184 return EphemeralUnboxingError{inner} 185 } 186 187 func (e EphemeralUnboxingError) Error() string { 188 return e.inner.HumanError() 189 } 190 191 func (e EphemeralUnboxingError) InternalError() string { 192 return e.inner.Error() 193 } 194 195 // ============================================================================= 196 197 type PublicTeamEphemeralKeyError struct{} 198 199 func NewPublicTeamEphemeralKeyError() PublicTeamEphemeralKeyError { 200 return PublicTeamEphemeralKeyError{} 201 } 202 203 func (e PublicTeamEphemeralKeyError) Error() string { 204 return "Cannot use exploding messages for a public team." 205 } 206 207 // ============================================================================= 208 209 type NotAuthenticatedForThisDeviceError struct{ inner ephemeral.EphemeralKeyError } 210 211 func NewNotAuthenticatedForThisDeviceError(mctx libkb.MetaContext, memberCtime *keybase1.Time, 212 contentCtime gregor1.Time) NotAuthenticatedForThisDeviceError { 213 inner := ephemeral.NewNotAuthenticatedForThisDeviceError(mctx, memberCtime, contentCtime) 214 return NotAuthenticatedForThisDeviceError{inner: inner} 215 } 216 217 func (e NotAuthenticatedForThisDeviceError) Error() string { 218 return e.inner.HumanError() 219 } 220 221 func (e NotAuthenticatedForThisDeviceError) InternalError() string { 222 return e.inner.Error() 223 } 224 225 // ============================================================================= 226 227 type InvalidMACError struct{} 228 229 func NewInvalidMACError() InvalidMACError { 230 return InvalidMACError{} 231 } 232 233 func (e InvalidMACError) Error() string { 234 return "invalid MAC" 235 } 236 237 // ============================================================================= 238 239 type ConsistencyErrorCode int 240 241 const ( 242 DuplicateID ConsistencyErrorCode = iota 243 OutOfOrderID 244 InconsistentHash 245 IncorrectHash 246 ) 247 248 type ChatThreadConsistencyError interface { 249 error 250 Code() ConsistencyErrorCode 251 } 252 253 type chatThreadConsistencyErrorImpl struct { 254 msg string 255 code ConsistencyErrorCode 256 } 257 258 func (e chatThreadConsistencyErrorImpl) Error() string { 259 return e.msg 260 } 261 262 func (e chatThreadConsistencyErrorImpl) Code() ConsistencyErrorCode { 263 return e.code 264 } 265 266 func NewChatThreadConsistencyError(code ConsistencyErrorCode, msg string, formatArgs ...interface{}) ChatThreadConsistencyError { 267 return &chatThreadConsistencyErrorImpl{ 268 code: code, 269 msg: fmt.Sprintf(msg, formatArgs...), 270 } 271 } 272 273 // ============================================================================= 274 275 type BoxingError struct { 276 Msg string 277 Perm bool 278 } 279 280 func NewBoxingError(msg string, perm bool) BoxingError { 281 return BoxingError{ 282 Msg: msg, 283 Perm: perm, 284 } 285 } 286 287 func (e BoxingError) Error() string { 288 return fmt.Sprintf("encryption error: %s perm: %v", e.Msg, e.Perm) 289 } 290 291 func (e BoxingError) IsImmediateFail() (chat1.OutboxErrorType, bool) { 292 if e.Perm { 293 return chat1.OutboxErrorType_MISC, true 294 } 295 return 0, false 296 } 297 298 // ============================================================================= 299 300 type RestrictedBotChannelError struct{} 301 302 func NewRestrictedBotChannelError() RestrictedBotChannelError { 303 return RestrictedBotChannelError{} 304 } 305 306 func (e RestrictedBotChannelError) Error() string { 307 return "bot restricted from sending to this channel" 308 } 309 310 func (e RestrictedBotChannelError) IsImmediateFail() (chat1.OutboxErrorType, bool) { 311 return chat1.OutboxErrorType_RESTRICTEDBOT, true 312 } 313 314 // ============================================================================= 315 316 type BoxingCryptKeysError struct { 317 Err error 318 } 319 320 // Cause implements the pkg/errors Cause() method, also cloned in libkb via HumanError, 321 // so that we know which error to show to the human being using keybase (rather than 322 // for our own internal uses). 323 func (e BoxingCryptKeysError) Cause() error { 324 return e.Err 325 } 326 327 func NewBoxingCryptKeysError(err error) BoxingCryptKeysError { 328 return BoxingCryptKeysError{ 329 Err: err, 330 } 331 } 332 333 func (e BoxingCryptKeysError) Error() string { 334 return fmt.Sprintf("boxing error: unable to get crypt keys: %s", e.Err.Error()) 335 } 336 337 func (e BoxingCryptKeysError) Inner() error { 338 return e.Err 339 } 340 341 func (e BoxingCryptKeysError) IsImmediateFail() (chat1.OutboxErrorType, bool) { 342 if _, ok := e.Err.(libkb.IdentifySummaryError); ok { 343 return chat1.OutboxErrorType_IDENTIFY, true 344 } 345 return 0, false 346 } 347 348 // ============================================================================= 349 350 type BodyHashInvalid struct{} 351 352 func (e BodyHashInvalid) Error() string { 353 return "chat body hash invalid" 354 } 355 356 type VersionError struct { 357 Kind string 358 Version int 359 Critical bool 360 } 361 362 func (e VersionError) Error() string { 363 return fmt.Sprintf("Unable to decrypt because current client is out of date. Please update your version of Keybase! Chat version error: [ unhandled: %s version: %d critical: %v ]", e.Kind, e.Version, e.Critical) 364 } 365 366 func (e VersionError) ExportType() chat1.MessageUnboxedErrorType { 367 if e.Critical { 368 return chat1.MessageUnboxedErrorType_BADVERSION_CRITICAL 369 } 370 return chat1.MessageUnboxedErrorType_BADVERSION 371 } 372 373 func (e VersionError) VersionKind() chat1.VersionKind { 374 return chat1.VersionKind(e.Kind) 375 } 376 377 func (e VersionError) VersionNumber() int { 378 return e.Version 379 } 380 381 func (e VersionError) IsCritical() bool { 382 return e.Critical 383 } 384 385 func NewMessageBoxedVersionError(version chat1.MessageBoxedVersion) VersionError { 386 return VersionError{ 387 Kind: string(chat1.VersionErrorMessageBoxed), 388 Version: int(version), 389 Critical: true, 390 } 391 } 392 393 func NewHeaderVersionError(version chat1.HeaderPlaintextVersion, 394 defaultHeader chat1.HeaderPlaintextUnsupported) VersionError { 395 return VersionError{ 396 Kind: string(chat1.VersionErrorHeader), 397 Version: int(version), 398 Critical: defaultHeader.Mi.Crit, 399 } 400 } 401 402 func NewBodyVersionError(version chat1.BodyPlaintextVersion, defaultBody chat1.BodyPlaintextUnsupported) VersionError { 403 return VersionError{ 404 Kind: string(chat1.VersionErrorBody), 405 Version: int(version), 406 Critical: defaultBody.Mi.Crit, 407 } 408 } 409 410 // ============================================================================= 411 412 type HeaderMismatchError struct { 413 Field string 414 } 415 416 var _ error = (*HeaderMismatchError)(nil) 417 418 func (e HeaderMismatchError) Error() string { 419 return fmt.Sprintf("chat header mismatch on %q", e.Field) 420 } 421 422 func NewHeaderMismatchError(field string) HeaderMismatchError { 423 return HeaderMismatchError{Field: field} 424 } 425 426 // ============================================================================= 427 428 type OfflineError struct { 429 } 430 431 func (e OfflineError) Error() string { 432 return "operation failed: no connection to chat server" 433 } 434 435 type OfflineClient struct { 436 } 437 438 func (e OfflineClient) Call(ctx context.Context, method string, arg interface{}, 439 res interface{}, timeout time.Duration) error { 440 return OfflineError{} 441 } 442 443 func (e OfflineClient) CallCompressed(ctx context.Context, method string, arg interface{}, 444 res interface{}, ctype rpc.CompressionType, timeout time.Duration) error { 445 return OfflineError{} 446 } 447 448 func (e OfflineClient) Notify(ctx context.Context, method string, arg interface{}, timeout time.Duration) error { 449 return OfflineError{} 450 } 451 452 // ============================================================================= 453 454 type DuplicateTopicNameError struct { 455 Conv chat1.ConversationLocal 456 } 457 458 func (e DuplicateTopicNameError) Error() string { 459 return fmt.Sprintf("channel name %s is already in use in %v", 460 e.Conv.GetTopicName(), e.Conv.Info.TlfName) 461 } 462 463 // ============================================================================= 464 465 type ImpteamBadteamError struct { 466 Msg string 467 } 468 469 func (e ImpteamBadteamError) Error() string { 470 return fmt.Sprintf("bad iteam found in conv: %s", e.Msg) 471 } 472 473 // ============================================================================= 474 475 type UnknownTLFNameError struct { 476 tlfName string 477 } 478 479 func NewUnknownTLFNameError(name string) UnknownTLFNameError { 480 return UnknownTLFNameError{ 481 tlfName: name, 482 } 483 } 484 485 func (e UnknownTLFNameError) Error() string { 486 return fmt.Sprintf("unknown conversation name: %s", e.tlfName) 487 } 488 489 // ============================================================================= 490 491 type AttachmentUploadError struct { 492 Msg string 493 Perm bool 494 } 495 496 func NewAttachmentUploadError(msg string, perm bool) AttachmentUploadError { 497 return AttachmentUploadError{ 498 Msg: msg, 499 Perm: perm, 500 } 501 } 502 503 func (e AttachmentUploadError) Error() string { 504 return fmt.Sprintf("attachment failed to upload; %s", e.Msg) 505 } 506 507 func (e AttachmentUploadError) IsImmediateFail() (chat1.OutboxErrorType, bool) { 508 return chat1.OutboxErrorType_MISC, e.Perm 509 } 510 511 // ============================================================================= 512 513 type SenderTestImmediateFailError struct { 514 } 515 516 func (e SenderTestImmediateFailError) Error() string { 517 return "sender test immediate fail error" 518 } 519 520 func (e SenderTestImmediateFailError) IsImmediateFail() (chat1.OutboxErrorType, bool) { 521 return chat1.OutboxErrorType_MISC, true 522 } 523 524 // ============================================================================= 525 526 type DecryptionKeyNotFoundError struct { 527 generation int 528 kbfsEncrypted, public bool 529 } 530 531 func NewDecryptionKeyNotFoundError(generation int, public, kbfsEncrypted bool) DecryptionKeyNotFoundError { 532 return DecryptionKeyNotFoundError{ 533 generation: generation, 534 kbfsEncrypted: kbfsEncrypted, 535 public: public, 536 } 537 } 538 539 func (e DecryptionKeyNotFoundError) Error() string { 540 return fmt.Sprintf("decryption key not found for generation: %v kbfsEncrypted: %v public: %v", 541 e.generation, e.kbfsEncrypted, e.public) 542 } 543 544 // ============================================================================= 545 546 type OfflineErrorKind int 547 548 const ( 549 OfflineErrorKindOnline OfflineErrorKind = iota 550 OfflineErrorKindOfflineBasic 551 OfflineErrorKindOfflineReconnect 552 ) 553 554 func IsOfflineError(err error) OfflineErrorKind { 555 // Check type 556 switch terr := err.(type) { 557 case net.Error: 558 return OfflineErrorKindOfflineReconnect 559 case libkb.APINetError: 560 return OfflineErrorKindOfflineBasic 561 case OfflineError: 562 return OfflineErrorKindOfflineBasic 563 case TransientUnboxingError: 564 return IsOfflineError(terr.Inner()) 565 } 566 // Check error itself 567 switch err { 568 case context.DeadlineExceeded: 569 fallthrough 570 case ErrChatServerTimeout: 571 return OfflineErrorKindOfflineReconnect 572 case ErrDuplicateConnection: 573 return OfflineErrorKindOfflineBasic 574 } 575 576 // Unfortunately, Go throws these without a type and they can occasionally 577 // propagate up. The strings were copied from 578 // https://golang.org/src/crypto/tls/conn.go 579 switch err.Error() { 580 case "tls: use of closed connection", 581 "tls: protocol is shutdown": 582 return OfflineErrorKindOfflineReconnect 583 } 584 return OfflineErrorKindOnline 585 } 586 587 func IsRekeyError(err error) (typ chat1.ConversationErrorType, ok bool) { 588 switch err := err.(type) { 589 case types.UnboxingError: 590 return IsRekeyError(err.Inner()) 591 case libkb.NeedSelfRekeyError: 592 return chat1.ConversationErrorType_SELFREKEYNEEDED, true 593 case libkb.NeedOtherRekeyError: 594 return chat1.ConversationErrorType_OTHERREKEYNEEDED, true 595 default: 596 if teams.IsTeamReadError(err) { 597 return chat1.ConversationErrorType_OTHERREKEYNEEDED, true 598 } 599 } 600 return chat1.ConversationErrorType_NONE, false 601 } 602 603 // ============================================================================= 604 605 type FTLError struct { 606 msg string 607 } 608 609 func NewFTLError(s string) error { 610 return &FTLError{msg: s} 611 } 612 613 func (f FTLError) Error() string { 614 return fmt.Sprintf("FTL Error: %s", f.msg) 615 } 616 617 // ============================================================================= 618 619 type DevStoragePermissionDeniedError struct { 620 role keybase1.TeamRole 621 } 622 623 func NewDevStoragePermissionDeniedError(role keybase1.TeamRole) error { 624 return &DevStoragePermissionDeniedError{role: role} 625 } 626 627 func (e *DevStoragePermissionDeniedError) Error() string { 628 return fmt.Sprintf("role %q is not high enough", e.role) 629 } 630 631 // ============================================================================= 632 633 type DevStorageAdminOnlyError struct { 634 msg string 635 } 636 637 func NewDevStorageAdminOnlyError(msg string) error { 638 return &DevStorageAdminOnlyError{msg: msg} 639 } 640 641 func (e *DevStorageAdminOnlyError) Error() string { 642 return fmt.Sprintf("found a conversation and a message, but role checking failed: %s", e.msg) 643 }