package libsignal import "fmt" // Error codes as defined in signal_protocol.h. Duplicated here as plain Go // constants (rather than referenced via cgo) so this file has no cgo // dependency and callers outside this package can compare against them. const ( ErrNoMemory = -12 ErrInvalidArgument = -22 ErrUnknown = -1000 ErrDuplicateMessage = -1001 ErrInvalidKey = -1002 ErrInvalidKeyID = -1003 ErrInvalidMAC = -1004 ErrInvalidMessage = -1005 ErrInvalidVersion = -1006 ErrLegacyMessage = -1007 ErrNoSession = -1008 ErrStaleKeyExchange = -1009 ErrUntrustedIdentity = -1010 ErrVRFSigVerifyFailed = -1011 ErrInvalidProtobuf = -1100 ErrFPVersionMismatch = -1200 ErrFPIdentMismatch = -1201 ) // Error wraps a libsignal-c return code. type Error struct { Code int Op string } func (e *Error) Error() string { return fmt.Sprintf("libsignal: %s: %s (%d)", e.Op, errName(e.Code), e.Code) } func errName(code int) string { switch code { case ErrNoMemory: return "out of memory" case ErrInvalidArgument: return "invalid argument" case ErrUnknown: return "unknown error" case ErrDuplicateMessage: return "duplicate message" case ErrInvalidKey: return "invalid key" case ErrInvalidKeyID: return "invalid key id" case ErrInvalidMAC: return "invalid MAC" case ErrInvalidMessage: return "invalid message" case ErrInvalidVersion: return "invalid version" case ErrLegacyMessage: return "message uses a protocol version no longer supported" case ErrNoSession: return "no session" case ErrStaleKeyExchange: return "stale key exchange" case ErrUntrustedIdentity: return "untrusted identity" case ErrVRFSigVerifyFailed: return "VRF signature verification failed" case ErrInvalidProtobuf: return "invalid protobuf" case ErrFPVersionMismatch: return "fingerprint version mismatch" case ErrFPIdentMismatch: return "fingerprint identity mismatch" default: return "library error" } } // newError returns nil for a non-negative (success) return code, or an // *Error wrapping it otherwise. op names the operation that produced code, // for diagnostics. func newError(op string, code int) error { if code >= 0 { return nil } return &Error{Code: code, Op: op} } // IsUntrustedIdentity reports whether err is (or wraps) SG_ERR_UNTRUSTED_IDENTITY - // the signal that a remote device's identity key changed since it was last // trusted (the case a TOFU trust policy must not silently paper over). func IsUntrustedIdentity(err error) bool { e, ok := err.(*Error) return ok && e.Code == ErrUntrustedIdentity } // IsNoSession reports whether err is (or wraps) SG_ERR_NO_SESSION. func IsNoSession(err error) bool { e, ok := err.(*Error) return ok && e.Code == ErrNoSession } // IsDuplicateMessage reports whether err is (or wraps) SG_ERR_DUPLICATE_MESSAGE. func IsDuplicateMessage(err error) bool { e, ok := err.(*Error) return ok && e.Code == ErrDuplicateMessage } // IsLegacyMessage reports whether err is (or wraps) SG_ERR_LEGACY_MESSAGE. func IsLegacyMessage(err error) bool { e, ok := err.(*Error) return ok && e.Code == ErrLegacyMessage }