Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add documentation for error cases #471

Closed

Conversation

cosmicexplorer
Copy link
Contributor

Broken out of #287.

While we have a terse description of each case of libsignal_protocol::Error to implement displaydoc::Display, we may also wish to have more in-depth explanation for the purposes of generated documentation. The #[ignore_extra_doc_attributes] flag enables us to provide this additional documentation while retaining the first line for the displaydoc::Display impl.

@cosmicexplorer cosmicexplorer marked this pull request as draft June 30, 2022 02:29
@cosmicexplorer cosmicexplorer marked this pull request as ready for review July 18, 2022 22:36
cosmicexplorer added a commit to cosmicexplorer/libsignal that referenced this pull request Jul 19, 2022
cosmicexplorer added a commit to cosmicexplorer/libsignal that referenced this pull request Jul 19, 2022
cosmicexplorer added a commit to cosmicexplorer/libsignal that referenced this pull request Jul 19, 2022
@jrose-signal
Copy link
Contributor

(still on my todo list, but prose is harder to review than code!)

cosmicexplorer added a commit to cosmicexplorer/libsignal that referenced this pull request Sep 9, 2022
Copy link
Contributor

@jrose-signal jrose-signal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, reviewing this is reminding me how much I disagree with my past self and collaborator about the design of our errors, heh. (We were both much newer to Rust then.) Several of these error cases don't need to be distinguished because clients won't treat them differently (as you yourself point out in some of these). Some should probably be panics per Rust conventions. Some don't have enough information (which key was the bad key??).

But redoing libsignal's API to be ever-more-perfect is not the best use of my time as a Signal employee, and therefore it'd be better to have documentation than not. I know I've delayed on reviewing this for quite a while, and that'll continue a little longer, but I'll pick it up again when I return from vacation.

@@ -11,82 +15,208 @@ use uuid::Uuid;

use std::panic::UnwindSafe;

#[cfg(doc)]
pub use crate::{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: does it have to be pub for rustdoc to pick it up?

Comment on lines +34 to 37
/// Error states recognized by the Signal Protocol.
#[derive(Debug, Display, Error)]
#[ignore_extra_doc_attributes]
pub enum SignalProtocolError {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh, this sounds better designed than what's actually going on: the "SignalProtocol" here is really just about the name of the crate, libsignal-protocol. Arguably it could just be Error or something like that; I'd probably document it as "Possible errors produced by the operations in this crate" to match what you did for the Result alias.

Comment on lines +42 to +43
/// Prefer to use lifetimes, static-sized slices, and dedicated wrapper structs in API
/// signatures to minimize the need to raise this error to FFI boundaries.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation should be client-facing, so comments about API design don't really fit.

@jrose-signal jrose-signal self-assigned this Nov 23, 2022
Copy link
Contributor

@jrose-signal jrose-signal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading this is painful, it reminds me that the error design really isn't that great. As I already remarked above. 😅 But I've owed you this review for a long time, even if I scanned through them pretty quickly.

Comment on lines 38 to 44
/// invalid argument: {0}
///
/// Raised if an invalid argument is provided to any Signal API methods.
///
/// Prefer to use lifetimes, static-sized slices, and dedicated wrapper structs in API
/// signatures to minimize the need to raise this error to FFI boundaries.
InvalidArgument(String),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Probably every single one of these can be an assertion, since they should all indicate programmer error… Something to maybe clean up later.)

Comment on lines 45 to 52
/// invalid state for call to {0} to succeed: {1}
///
/// Raised if some optional value was missing before performing some operation which needed it.
///
/// Prefer to avoid returning [std::result::Result] and [Option] from struct methods in cases
/// where they're not necessary for trait polymorphism, as well as using dedicated wrapper
/// structs in API signatures, to minimize the need to raise this error.
InvalidState(&'static str, String),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"optional" sounds like it's about Option, but this is really "you were supposed to set up certain state before calling this function, and you didn't". For instance, you can't send a message if you haven't started a session with someone.

(These, likewise, should be audited; many of them could be assertions, but some of them might be expensive to check up front, and should become more specific, more actionable errors.)

Comment on lines 54 to 59
/// protobuf encoding was invalid
///
/// Raised if a field in a protobuf is invalid in some way.
///
/// Prefer to raise [Self::InvalidState] except in methods which directly decode protobufs.
InvalidProtobufEncoding,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be renamed InvalidEncoding, since the protobuf is an implementation detail. Raising InvalidState would be incorrect since InvalidState is about things the local client can control, and the contents of an incoming message isn't one of those.

Comment on lines 61 to 67
/// ciphertext serialized bytes were too short <{0}>
///
/// Raised if some ciphertext was deserialized from a too-small slice.
///
/// Prefer to make API method signatures and wrapper structs consume and produce static-sized
/// byte slices to minimize the need to raise this error.
CiphertextMessageTooShort(usize),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be unified with InvalidEncoding above; there's nothing a caller would do differently based on which failure happened. If we think the different kinds of failure are important for debugging, we could add a message to InvalidEncoding. Failing that, there shouldn't be any mention of "slice"; this just indicates a parameter was too small.

Comment on lines +69 to 73
///
/// Raised if the ciphertext version decoded from a protobuf is older than this client.
///
/// The current client's ciphertext version is at [CIPHERTEXT_MESSAGE_CURRENT_VERSION].
LegacyCiphertextVersion(u8),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't mention "protobuf", and the particular current version depends on which protocol is raising this error. Signal, SenderKey, and SealedSender messages all have different versions.

Comment on lines 194 to 197
/// error while invoking an ffi callback: {0}
///
/// Raised to propagate an error from an FFI callback.
FfiBindingError(String),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not about propagating errors; it's when the callback itself can't be invoked. Think JNI-level errors. (It does not actually come up for pure Rust users and maybe doesn't belong here.)

Comment on lines 198 to 204
/// error in method call '{0}': {1}
///
/// Raised to propagate an error through to an FFI exception along with a boxed handle.
ApplicationCallbackError(
&'static str,
#[source] Box<dyn std::error::Error + Send + Sync + UnwindSafe + 'static>,
),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the one where there was an error from a callback and we're just propagating it out, whether through FFI or from a Rust client that returns Err.

Comment on lines 206 to 212
/// invalid sealed sender message: {0}
///
/// Raised if an [crate::sealed_sender::UnidentifiedSenderMessage] could not be
/// deserialized successfully.
///
/// *TODO: this sounds a lot like [Self::InvalidProtobufEncoding] or [Self::UntrustedIdentity]?*
InvalidSealedSenderMessage(String),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, InvalidEncoding with a message again. :-(

Comment on lines 213 to 217
/// unknown sealed sender message version {0}
///
/// Raised if an version decoded from a [crate::sealed_sender::UnidentifiedSenderMessage]
/// was unrecognized.
UnknownSealedSenderVersion(u8),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't be decoded from UnidentifiedSenderMessage; it's in the outermost envelope.

Comment on lines 218 to 221
/// self send of a sealed sender message
///
/// Raised if [sealed_sender_decrypt] finds that the message came from this exact client.
SealedSenderSelfSend,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants