1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use std::time::SystemTime;

use generic_array::ArrayLength;
use typenum::Unsigned;

use crate::algorithm::{Signature, Signer as AlgorithmSigner};
use crate::error::BadSignature;
use crate::{BadTimedSignature, Separator, UnsignedValue};

/// A signer can sign and unsign bytes, validating the signature provided.
///
/// A salt can be used to namespace the hash, so that a signed string is only
/// valid for a given namespace. Leaving this at the default value or re-using a salt value
/// across different parts of your application where the same signed value in one part can
/// mean something different in another part is a security risk.
///
/// # Basic Usage
/// ```rust
/// use itsdangerous::{default_builder, Signer};
///
/// // Create a signer using the default builder, and an arbitrary secret key.
/// let signer = default_builder("secret key").build();
///
/// // Sign an arbitrary string.
/// let signed = signer.sign("hello world!");
///
/// // Unsign the string and validate whether or not its expired.
/// let unsigned = signer.unsign(&signed).expect("Signature was not valid");
/// assert_eq!(unsigned, "hello world!");
/// ```
pub trait Signer {
    /// Signs the given string.
    fn sign<S: AsRef<str>>(&self, value: S) -> String;

    /// Unsigns the given string. The logical inverse of [`sign`].
    ///
    /// # Remarks
    ///
    /// This method performs zero copies or heap allocations and returns a reference to a slice
    /// of the provided `value`, If you need a copy, consider doing `unsign(..).to_owned()`
    /// to convert the [`&str`] to a [`String`].
    ///
    /// [`&str`]: std::str
    /// [`sign`]: Signer::sign
    fn unsign<'a>(&'a self, value: &'a str) -> Result<&'a str, BadSignature<'a>>;

    fn separator(&self) -> Separator;

    /// Given a base-64 encoded signature, attempt to verify whether or not
    /// it is valid for the given `value`.
    fn verify_encoded_signature(&self, value: &[u8], encoded_signature: &[u8]) -> bool;

    /// Gets the output size in bytes of the base-64 encoded signature part that this
    /// signer will emit.
    fn signature_output_size(&self) -> usize;
}

pub trait GetSigner {
    type OutputSize: ArrayLength<u8> + Unsigned;
    type Signer: AlgorithmSigner<OutputSize = Self::OutputSize>;

    /// Returns a signer that can be used to build a signature for a given key + values.
    fn get_signer(&self) -> Self::Signer;

    /// Returns the signature for a given key + value.
    fn get_signature(&self, value: &[u8]) -> Signature<Self::OutputSize> {
        self.get_signer().input_chained(value).sign()
    }
}

/// A TimestampSigner wraps an inner Signer, giving it the ability to dish
/// out signatures with timestamps.
///
/// # Basic Usage
/// ```rust
/// use std::time::Duration;
/// use itsdangerous::{default_builder, Signer, TimestampSigner, IntoTimestampSigner};
///
/// // Create a signer using the default builder, and an arbitrary secret key.
/// let signer = default_builder("secret key").build().into_timestamp_signer();
///
/// // Sign an arbitrary string.
/// let signed = signer.sign("hello world!");
///
/// // Unsign the string and validate whether or not its expired.
/// let unsigned = signer.unsign(&signed).expect("Signature was not valid");
/// let value = unsigned
///     .value_if_not_expired(Duration::from_secs(60))
///     .expect("Signature was expired");
/// assert_eq!(value, "hello world!");
/// ```
pub trait TimestampSigner {
    fn separator(&self) -> Separator;

    /// Signs a value with an arbitrary timestamp.
    fn sign_with_timestamp<S: AsRef<str>>(&self, value: S, timestamp: SystemTime) -> String;

    /// Signs a value using the current system timestamp (as provided by [`SystemTime::now`]).
    fn sign<S: AsRef<str>>(&self, value: S) -> String;

    /// The inverse of [`sign`] / [`sign_with_timestamp`], returning an [`UnsignedValue`], which you
    /// can grab the value, timestamp, and assert the max age of the signed value with.
    ///
    /// # Remarks
    ///
    /// This method performs zero copies or heap allocations and returns a reference to a slice
    /// of the provided `value`, inside of the [`UnsignedValue`] that is returned. If you need a
    /// copy, consider doing `unsigned_value.value().to_owned()` to convert the [`&str`] to a [`String`].
    ///
    /// [`&str`]: std::str
    /// [`sign`]: TimestampSigner::sign
    /// [`sign_with_timestamp`]: TimestampSigner::sign_with_timestamp
    fn unsign<'a>(&'a self, value: &'a str) -> Result<UnsignedValue, BadTimedSignature<'a>>;
}

pub trait IntoTimestampSigner {
    type TimestampSigner: TimestampSigner;

    /// Converts this [`Signer`] into a [`TimestampSigner`], giving it the ability
    /// to do signing with timestamps!
    fn into_timestamp_signer(self) -> Self::TimestampSigner;
}

/// Returns a referenec to the underlying [`Signer`].
pub trait AsSigner {
    type Signer: Signer;

    /// Returns a reference to the underlying [`Signer`] if you wish to use its methods.
    ///
    /// # Example
    /// ```rust
    /// use itsdangerous::{default_builder, TimestampSigner, IntoTimestampSigner, Signer, AsSigner};
    ///
    /// let timestamp_signer = default_builder("hello world").build().into_timestamp_signer();
    /// let signer = timestamp_signer.as_signer();
    /// let signer = signer.sign("hello without a timestamp!");
    /// ```
    fn as_signer(&self) -> &Self::Signer;
}