summaryrefslogtreecommitdiffstats
path: root/openpgp/src/message/mod.rs
diff options
context:
space:
mode:
authorWiktor Kwapisiewicz <wiktor@metacode.biz>2020-04-08 15:26:37 +0200
committerWiktor Kwapisiewicz <wiktor@metacode.biz>2020-04-23 12:26:16 +0200
commit71bdf66e45e16d193eb93411c0450f28a3874f24 (patch)
tree61315321656580cdf2790ccacae39122492017eb /openpgp/src/message/mod.rs
parentf1ae1baa4d1b2a52f490b4faaabea7bdf1029568 (diff)
openpgp: Add doctests and fixes for docs to Message struct.
- Add Examples to all public functions. - Add example armored message to the header. - Fix wording. - Fixes #468.
Diffstat (limited to 'openpgp/src/message/mod.rs')
-rw-r--r--openpgp/src/message/mod.rs222
1 files changed, 220 insertions, 2 deletions
diff --git a/openpgp/src/message/mod.rs b/openpgp/src/message/mod.rs
index 8ab63553..747d2b89 100644
--- a/openpgp/src/message/mod.rs
+++ b/openpgp/src/message/mod.rs
@@ -8,6 +8,17 @@
//! This module provides support for validating and working with
//! OpenPGP messages.
//!
+//! Example of ASCII-armored OpenPGP message:
+//!
+//! ```txt
+//! -----BEGIN PGP MESSAGE-----
+//!
+//! yDgBO22WxBHv7O8X7O/jygAEzol56iUKiXmV+XmpCtmpqQUKiQrFqclFqUDBovzS
+//! vBSFjNSiVHsuAA==
+//! =njUN
+//! -----END PGP MESSAGE-----
+//! ```
+//!
//! [Section 11.3 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-11.3
use std::convert::TryFrom;
@@ -60,7 +71,7 @@ impl From<MessageParserError> for anyhow::Error {
}
-/// Whether a packet sequence is a valid OpenPGP Message.
+/// Represents the status of a parsed message.
#[derive(Debug)]
pub enum MessageValidity {
/// The packet sequence is a valid OpenPGP message.
@@ -111,6 +122,17 @@ impl MessageValidity {
}
/// Used to help validate a packet sequence is a valid OpenPGP message.
+///
+/// ```rust
+/// # extern crate sequoia_openpgp as openpgp;
+/// use openpgp::message::{MessageValidator, MessageValidity, Token};
+///
+/// let mut l = MessageValidator::new();
+/// l.push_token(Token::Literal, &[0]);
+/// l.finish();
+///
+/// assert!(if let MessageValidity::Message = l.check() { true } else { false });
+/// ```
#[derive(Debug)]
pub struct MessageValidator {
tokens: Vec<Token>,
@@ -144,6 +166,26 @@ impl MessageValidator {
///
/// Note: a `MessageValidator` will only return this after
/// `MessageValidator::finish` has been called.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # extern crate sequoia_openpgp as openpgp;
+ /// use openpgp::message::MessageValidator;
+ /// use openpgp::packet::Tag;
+ ///
+ /// let mut l = MessageValidator::new();
+ /// l.push(Tag::Literal, &[0]);
+ ///
+ /// // Note: Even though we've read the whole message, because `finish` hasn't been called,
+ /// // `l.is_message()` still returns false.
+ /// assert!(!l.is_message());
+ ///
+ /// l.finish();
+ ///
+ /// // After `l.finish()` has been called the packet sequence is considered to ba a valid message.
+ /// assert!(l.is_message());
+ /// ```
pub fn is_message(&self) -> bool {
self.check().is_message()
}
@@ -153,12 +195,65 @@ impl MessageValidator {
///
/// Note: a `MessageValidator` will only return this before
/// `MessageValidator::finish` has been called.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # extern crate sequoia_openpgp as openpgp;
+ /// use openpgp::message::MessageValidator;
+ /// use openpgp::packet::Tag;
+ ///
+ /// let mut l = MessageValidator::new();
+ /// l.push(Tag::Literal, &[0]);
+ ///
+ /// // Note: Even though we've read the whole message, because `finish` hasn't been called,
+ /// // `l.is_message()` still returns false.
+ /// assert!(!l.is_message());
+ ///
+ /// // `l.is_message_prefix()` returns true because this is a valid message prefix.
+ /// assert!(l.is_message_prefix());
+ /// ```
pub fn is_message_prefix(&self) -> bool {
self.check().is_message_prefix()
}
/// Returns whether the packet sequence is definitely not a valid
/// OpenPGP Message.
+ ///
+ /// # Examples
+ ///
+ /// When the packet sequence is too short the validator will report an error.
+ ///
+ /// ```rust
+ /// # extern crate sequoia_openpgp as openpgp;
+ /// use openpgp::message::MessageValidator;
+ ///
+ /// let mut l = MessageValidator::new();
+ ///
+ /// // Note: `l.is_err()` will not return true if this still can be a valid message prefix.
+ /// assert!(!l.is_err());
+ ///
+ /// l.finish();
+ ///
+ /// // Now that the packet sequence has been marked as finished `l.is_err()` will return true.
+ /// assert!(l.is_err());
+ /// ```
+ ///
+ /// When an unexpected packet is encountered the validator will report an error
+ /// early.
+ ///
+ /// ```rust
+ /// # extern crate sequoia_openpgp as openpgp;
+ /// use openpgp::message::MessageValidator;
+ /// use openpgp::packet::Tag;
+ ///
+ /// let mut l = MessageValidator::new();
+ /// l.push(Tag::UserID, &[0]);
+ ///
+ /// // `l.is_err()` will return true even though `l.finish()` has not been called as this
+ /// // is definitely not a valid message prefix.
+ /// assert!(l.is_err());
+ /// ```
pub fn is_err(&self) -> bool {
self.check().is_err()
}
@@ -186,6 +281,19 @@ impl MessageValidator {
///
/// Note: the token *must* correspond to a packet; this function
/// will panic if `token` is `Token::Pop`.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # extern crate sequoia_openpgp as openpgp;
+ /// use openpgp::message::{MessageValidator, MessageValidity, Token};
+ ///
+ /// let mut l = MessageValidator::new();
+ /// l.push_token(Token::Literal, &[0]);
+ /// l.finish();
+ ///
+ /// assert!(if let MessageValidity::Message = l.check() { true } else { false });
+ /// ```
pub fn push_token(&mut self, token: Token, path: &[usize]) {
assert!(!self.finished);
assert!(self.depth.is_some());
@@ -217,6 +325,20 @@ impl MessageValidator {
/// Unlike `push_token`, this function does not automatically
/// account for changes in the depth. If you use this function
/// directly, you must push any required `Token::Pop` tokens.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # extern crate sequoia_openpgp as openpgp;
+ /// use openpgp::message::{MessageValidator, MessageValidity};
+ /// use openpgp::packet::Tag;
+ ///
+ /// let mut l = MessageValidator::new();
+ /// l.push(Tag::Literal, &[0]);
+ /// l.finish();
+ ///
+ /// assert!(if let MessageValidity::Message = l.check() { true } else { false });
+ /// ```
pub fn push(&mut self, tag: Tag, path: &[usize]) {
if self.error.is_some() {
return;
@@ -253,6 +375,18 @@ impl MessageValidator {
}
/// Note that the entire message has been seen.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # extern crate sequoia_openpgp as openpgp;
+ /// use openpgp::message::{MessageValidator, MessageValidity};
+ ///
+ /// let mut l = MessageValidator::new();
+ /// l.finish();
+ ///
+ /// assert!(if let MessageValidity::Error(_) = l.check() { true } else { false });
+ /// ```
pub fn finish(&mut self) {
assert!(!self.finished);
@@ -278,7 +412,30 @@ impl MessageValidator {
/// this function will only ever return either
/// MessageValidity::MessagePrefix or MessageValidity::Error. Once
/// MessageValidity::finish() has been called, then only
- /// MessageValidity::Message or MessageValidity::Bad will be called.
+ /// MessageValidity::Message or MessageValidity::Error will be returned.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # extern crate sequoia_openpgp as openpgp;
+ /// use openpgp::message::{MessageValidator, MessageValidity};
+ /// use openpgp::packet::Tag;
+ ///
+ /// // No packets will return an error.
+ /// let mut l = MessageValidator::new();
+ /// assert!(if let MessageValidity::MessagePrefix = l.check() { true } else { false });
+ /// l.finish();
+ ///
+ /// assert!(if let MessageValidity::Error(_) = l.check() { true } else { false });
+ ///
+ /// // Simple one-literal message.
+ /// let mut l = MessageValidator::new();
+ /// l.push(Tag::Literal, &[0]);
+ /// assert!(if let MessageValidity::MessagePrefix = l.check() { true } else { false });
+ /// l.finish();
+ ///
+ /// assert!(if let MessageValidity::Message = l.check() { true } else { false });
+ /// ```
pub fn check(&self) -> MessageValidity {
if let Some(ref err) = self.error {
return MessageValidity::Error((*err).clone().into());
@@ -320,6 +477,41 @@ use super::*;
/// 4880].
///
/// [Section 11.3 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-11.3
+///
+/// [ASCII Armored Messages] are wrapped in `-----BEGIN PGP MESSAGE-----` header
+/// and `-----END PGP MESSAGE-----` tail lines:
+///
+/// ```txt
+/// -----BEGIN PGP MESSAGE-----
+///
+/// xA0DAAoW5saJekzviSQByxBiAAAAAADYtdiv2KfZgtipwnUEABYKACcFglwJHYoW
+/// IQRnpIdTo4Cms7fffcXmxol6TO+JJAkQ5saJekzviSQAAIJ6APwK6FxtHXn8txDl
+/// tBFsIXlOSLOs4BvArlZzZSMomIyFLAEAwCLJUChMICDxWXRlHxORqU5x6hlO3DdW
+/// sl/1DAbnRgI=
+/// =AqoO
+/// -----END PGP MESSAGE-----
+/// ```
+///
+/// [ASCII Armored Messages]: https://tools.ietf.org/html/rfc4880#section-6.6
+///
+/// # Examples
+///
+/// Creating a Messaage encrypted with a password.
+///
+/// ```
+/// # use sequoia_openpgp as openpgp;
+/// # f().unwrap(); fn f() -> sequoia_openpgp::Result<()> {
+/// use std::io::Write;
+/// use openpgp::serialize::stream::{Message, Encryptor, LiteralWriter};
+///
+/// let mut sink = vec![];
+/// let message = Encryptor::with_passwords(
+/// Message::new(&mut sink), vec!["ściśle tajne".into()]).build()?;
+/// let mut w = LiteralWriter::new(message).build()?;
+/// w.write_all(b"Hello world.")?;
+/// w.finalize()?;
+/// # Ok(()) }
+/// ```
#[derive(PartialEq)]
pub struct Message {
/// A message is just a validated packet pile.
@@ -377,6 +569,32 @@ impl Message {
///
/// Returns `None` if no literal data packet is found. This
/// happens if a SEIP container has not been decrypted.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # extern crate sequoia_openpgp as openpgp;
+ /// # fn main() { f().unwrap(); }
+ /// # fn f() -> openpgp::Result<()> {
+ /// use std::io;
+ /// use std::io::Read;
+ /// use openpgp::Message;
+ /// use openpgp::armor::{Reader, ReaderMode};
+ /// use openpgp::parse::Parse;
+ ///
+ /// let data = "yxJiAAAAAABIZWxsbyB3b3JsZCE="; // base64 over literal data packet
+ ///
+ /// let mut cursor = io::Cursor::new(&data);
+ /// let mut reader = Reader::new(&mut cursor, ReaderMode::VeryTolerant);
+ ///
+ /// let mut buf = Vec::new();
+ /// reader.read_to_end(&mut buf)?;
+ ///
+ /// let message = Message::from_bytes(&buf)?;
+ /// assert_eq!(message.body().unwrap().body(), b"Hello world!");
+ /// # Ok(())
+ /// # }
+ /// ```
pub fn body(&self) -> Option<&Literal> {
for packet in self.pile.descendants() {
if let &Packet::Literal(ref l) = packet {