telegabber/e2ee/omemo/libsignal/errors.go
2026-07-28 00:38:46 -04:00

113 lines
3.1 KiB
Go

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
}