Skip to main content

softchat/
error.rs

1use thiserror::Error;
2
3/// Stable, redacted failures exposed by Softchat.
4#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
5#[cfg_attr(feature = "native-bindings", derive(uniffi::Error))]
6pub enum SoftchatError {
7    /// The supplied secret key is not one valid 32-byte secp256k1 scalar.
8    #[error("invalid secret key")]
9    InvalidSecretKey,
10
11    /// The supplied public key is not one valid 32-byte x-only public key.
12    #[error("invalid public key")]
13    InvalidPublicKey,
14
15    /// The supplied event ID is malformed or does not match the event body.
16    #[error("invalid Nostr event ID")]
17    InvalidEventId,
18
19    /// The supplied Schnorr signature is malformed or does not verify.
20    #[error("invalid Nostr event signature")]
21    InvalidEventSignature,
22
23    /// The event kind is outside the NIP-01 16-bit range.
24    #[error("invalid Nostr event kind")]
25    InvalidEventKind,
26
27    /// The event timestamp cannot be represented exactly on every target.
28    #[error("invalid Nostr event timestamp")]
29    InvalidEventTimestamp,
30
31    /// A NIP-01 tag is not an array containing at least one string.
32    #[error("invalid Nostr event tag")]
33    InvalidEventTag,
34
35    /// The event is not valid NIP-01 JSON.
36    #[error("invalid Nostr event JSON")]
37    InvalidEventJson,
38
39    /// The encoded event exceeds the portable Softchat input bound.
40    #[error("Nostr event is too large")]
41    EventTooLarge,
42
43    /// Signing failed after the event draft and identity were validated.
44    #[error("Nostr event signing failed")]
45    EventSigningFailed,
46
47    /// A NIP-59 envelope could not be created from the supplied inputs.
48    #[error("NIP-59 envelope creation failed")]
49    Nip59EnvelopeCreationFailed,
50
51    /// A NIP-59 envelope failed route, structure, or authentication checks.
52    #[error("invalid NIP-59 envelope")]
53    InvalidNip59Envelope,
54
55    /// A one-to-one NIP-17 text rumor could not be created.
56    #[error("NIP-17 text message creation failed")]
57    Nip17MessageCreationFailed,
58
59    /// A rumor is not a valid one-to-one NIP-17 text message.
60    #[error("invalid NIP-17 text message")]
61    InvalidNip17Message,
62
63    /// A NIP-19 display identifier is malformed, unsupported, or oversized.
64    #[error("invalid NIP-19 identifier")]
65    InvalidNip19Identifier,
66
67    /// An external signer does not provide the capability required by a request.
68    #[error("external signer capability is unavailable")]
69    ExternalSignerCapabilityUnavailable,
70
71    /// An external signer operation was cancelled by the user or host.
72    #[error("external signer operation was cancelled")]
73    ExternalSignerCancelled,
74
75    /// An external signer provider rejected an otherwise valid request.
76    #[error("external signer rejected the request")]
77    ExternalSignerRejected,
78
79    /// An external signer returned a signature that did not authenticate.
80    #[error("external signer returned an invalid signature")]
81    InvalidExternalSignature,
82
83    /// A relay frame is malformed, unsupported, oversized, or has invalid arity.
84    #[error("invalid relay frame")]
85    InvalidRelayFrame,
86
87    /// A NIP-01 relay filter is malformed or exceeds the portable bounds.
88    #[error("invalid relay filter")]
89    InvalidRelayFilter,
90
91    /// A NIP-42 authentication request is malformed or does not match its context.
92    #[error("invalid relay authentication")]
93    InvalidRelayAuthentication,
94
95    /// An EVENTS batch or its acknowledgement set violates the Softchat profile.
96    #[error("invalid relay batch")]
97    InvalidRelayBatch,
98
99    /// Inline Softchat attachment metadata is malformed or outside its bounds.
100    #[error("invalid attachment metadata")]
101    InvalidAttachmentMetadata,
102
103    /// Attachment bytes exceed the bounded in-memory compatibility operation.
104    #[error("attachment is too large")]
105    AttachmentTooLarge,
106
107    /// Attachment encryption failed after validation.
108    #[error("attachment encryption failed")]
109    AttachmentEncryptionFailed,
110
111    /// Attachment authentication or decryption failed.
112    #[error("attachment decryption failed")]
113    AttachmentDecryptionFailed,
114
115    /// A NIP-98 request plan has an invalid method, URL, payload, or redirect.
116    #[error("invalid HTTP authorization request")]
117    InvalidHttpAuthorization,
118
119    /// A typed Softchat chat event is malformed or violates its profile.
120    #[error("invalid Softchat event")]
121    InvalidSoftchatEvent,
122
123    /// A canonical Softchat event could not be created from the supplied values.
124    #[error("Softchat event creation failed")]
125    SoftchatEventCreationFailed,
126
127    /// A pure event-history projection contains unauthorized or malformed input.
128    #[error("invalid Softchat event projection")]
129    InvalidSoftchatProjection,
130
131    /// A private metadata rumor or its retained JSON is invalid.
132    #[error("invalid private user metadata")]
133    InvalidUserMetadata,
134
135    /// A private NIP-02 contact backup is malformed or ambiguous.
136    #[error("invalid private contact list")]
137    InvalidContactList,
138
139    /// NIP-78 or Softchat app-data content is malformed or unauthorized.
140    #[error("invalid application data")]
141    InvalidApplicationData,
142
143    /// A relay-session transition is invalid for its current state.
144    #[error("invalid relay session transition")]
145    InvalidRelaySession,
146
147    /// A bounded relay-session queue cannot accept more work.
148    #[error("relay session queue is full")]
149    RelaySessionQueueFull,
150
151    /// A delivery transition or retry result is contradictory.
152    #[error("invalid delivery state")]
153    InvalidDeliveryState,
154
155    /// A platform persistence result does not match its requested transaction.
156    #[error("invalid persistence adapter result")]
157    InvalidPersistenceResult,
158
159    /// A Noise NK handshake key or message is malformed or unauthenticated.
160    #[error("invalid Noise handshake")]
161    InvalidNoiseHandshake,
162
163    /// A single-use Noise handshake capability was already consumed.
164    #[error("Noise handshake is already consumed")]
165    NoiseHandshakeConsumed,
166
167    /// An established Noise session was explicitly closed.
168    #[error("Noise session is closed")]
169    NoiseSessionClosed,
170
171    /// Noise transport rejected a frame without exposing cryptographic detail.
172    #[error("Noise transport operation failed")]
173    NoiseTransportFailed,
174
175    /// A Negentropy set, frame, limit, or state transition is invalid.
176    #[error("invalid Negentropy reconciliation")]
177    InvalidNegentropy,
178
179    /// NIP-44 does not permit an empty plaintext.
180    #[error("plaintext must not be empty")]
181    EmptyPlaintext,
182
183    /// The UTF-8 plaintext exceeds the NIP-44 v2 limit.
184    #[error("plaintext is too large")]
185    PlaintextTooLarge,
186
187    /// The message declares an algorithm this library does not understand.
188    #[error("unsupported encryption algorithm")]
189    UnsupportedAlgorithm,
190
191    /// The encoded ciphertext exceeds Softchat's cheap pre-decode bound.
192    #[error("ciphertext is too large")]
193    CiphertextTooLarge,
194
195    /// Encryption failed after the inputs were validated.
196    #[error("message encryption failed")]
197    EncryptionFailed,
198
199    /// Authentication, decoding, padding, version, or UTF-8 validation failed.
200    #[error("message decryption failed")]
201    DecryptionFailed,
202
203    /// The local identity's secret material was explicitly erased.
204    #[error("identity is erased")]
205    IdentityErased,
206
207    /// An unexpected implementation failure was redacted at the public boundary.
208    #[error("Softchat operation failed")]
209    InternalFailure,
210}
211
212impl SoftchatError {
213    /// Stable machine-readable error code used by authored language facades.
214    #[must_use]
215    pub const fn code(&self) -> &'static str {
216        match self {
217            Self::InvalidSecretKey => "invalid_secret_key",
218            Self::InvalidPublicKey => "invalid_public_key",
219            Self::InvalidEventId => "invalid_event_id",
220            Self::InvalidEventSignature => "invalid_event_signature",
221            Self::InvalidEventKind => "invalid_event_kind",
222            Self::InvalidEventTimestamp => "invalid_event_timestamp",
223            Self::InvalidEventTag => "invalid_event_tag",
224            Self::InvalidEventJson => "invalid_event_json",
225            Self::EventTooLarge => "event_too_large",
226            Self::EventSigningFailed => "event_signing_failed",
227            Self::Nip59EnvelopeCreationFailed => "nip59_envelope_creation_failed",
228            Self::InvalidNip59Envelope => "invalid_nip59_envelope",
229            Self::Nip17MessageCreationFailed => "nip17_message_creation_failed",
230            Self::InvalidNip17Message => "invalid_nip17_message",
231            Self::InvalidNip19Identifier => "invalid_nip19_identifier",
232            Self::ExternalSignerCapabilityUnavailable => "external_signer_capability_unavailable",
233            Self::ExternalSignerCancelled => "external_signer_cancelled",
234            Self::ExternalSignerRejected => "external_signer_rejected",
235            Self::InvalidExternalSignature => "invalid_external_signature",
236            Self::InvalidRelayFrame => "invalid_relay_frame",
237            Self::InvalidRelayFilter => "invalid_relay_filter",
238            Self::InvalidRelayAuthentication => "invalid_relay_authentication",
239            Self::InvalidRelayBatch => "invalid_relay_batch",
240            Self::InvalidAttachmentMetadata => "invalid_attachment_metadata",
241            Self::AttachmentTooLarge => "attachment_too_large",
242            Self::AttachmentEncryptionFailed => "attachment_encryption_failed",
243            Self::AttachmentDecryptionFailed => "attachment_decryption_failed",
244            Self::InvalidHttpAuthorization => "invalid_http_authorization",
245            Self::InvalidSoftchatEvent => "invalid_softchat_event",
246            Self::SoftchatEventCreationFailed => "softchat_event_creation_failed",
247            Self::InvalidSoftchatProjection => "invalid_softchat_projection",
248            Self::InvalidUserMetadata => "invalid_user_metadata",
249            Self::InvalidContactList => "invalid_contact_list",
250            Self::InvalidApplicationData => "invalid_application_data",
251            Self::InvalidRelaySession => "invalid_relay_session",
252            Self::RelaySessionQueueFull => "relay_session_queue_full",
253            Self::InvalidDeliveryState => "invalid_delivery_state",
254            Self::InvalidPersistenceResult => "invalid_persistence_result",
255            Self::InvalidNoiseHandshake => "invalid_noise_handshake",
256            Self::NoiseHandshakeConsumed => "noise_handshake_consumed",
257            Self::NoiseSessionClosed => "noise_session_closed",
258            Self::NoiseTransportFailed => "noise_transport_failed",
259            Self::InvalidNegentropy => "invalid_negentropy",
260            Self::EmptyPlaintext => "empty_plaintext",
261            Self::PlaintextTooLarge => "plaintext_too_large",
262            Self::UnsupportedAlgorithm => "unsupported_algorithm",
263            Self::CiphertextTooLarge => "ciphertext_too_large",
264            Self::EncryptionFailed => "encryption_failed",
265            Self::DecryptionFailed => "decryption_failed",
266            Self::IdentityErased => "identity_erased",
267            Self::InternalFailure => "internal_failure",
268        }
269    }
270}