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
//! Canonical ID types for domain identifiers.
//!
//! `TenantId` is re-exported from `security_core`. The types `UserId`, `OrderId`, and
//! `OpaquePublicId` are defined here as distinct newtypes over [`uuid::Uuid`].
use serde::{Deserialize, Serialize};
use std::fmt;
use std::str::FromStr;
use uuid::Uuid;
pub use security_core::types::TenantId;
macro_rules! boundary_id {
($(#[$meta:meta])* $name:ident) => {
$(#[$meta])*
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct $name(Uuid);
impl $name {
/// Generates a new random ID.
#[must_use]
pub fn generate() -> Self {
Self(Uuid::new_v4())
}
/// Returns a reference to the inner [`Uuid`].
#[must_use]
pub fn as_inner(&self) -> &Uuid {
&self.0
}
/// Consumes the wrapper and returns the inner [`Uuid`].
#[must_use]
pub fn into_inner(self) -> Uuid {
self.0
}
}
impl From<Uuid> for $name {
fn from(u: Uuid) -> Self {
Self(u)
}
}
impl FromStr for $name {
type Err = uuid::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Uuid::parse_str(s).map(Self)
}
}
impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Debug for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}({})", stringify!($name), self.0)
}
}
};
}
boundary_id!(
/// A unique identifier for a user at the boundary layer.
///
/// # Examples
///
/// ```
/// use secure_boundary::id::UserId;
///
/// let id = UserId::generate();
/// let s = id.to_string();
/// let parsed: UserId = s.parse().unwrap();
/// assert_eq!(id, parsed);
/// ```
UserId
);
boundary_id!(
/// A unique identifier for an order.
///
/// # Examples
///
/// ```
/// use secure_boundary::id::OrderId;
///
/// let id = OrderId::generate();
/// assert!(!id.to_string().is_empty());
/// ```
OrderId
);
boundary_id!(
/// An opaque public identifier safe for exposure in URLs and API responses.
///
/// # Examples
///
/// ```
/// use secure_boundary::id::OpaquePublicId;
///
/// let id = OpaquePublicId::generate();
/// let inner = id.as_inner();
/// assert_eq!(inner.get_version_num(), 4);
/// ```
OpaquePublicId
);