1use std::{borrow::Cow, ops::Deref};
8
9use thiserror::Error;
10
11#[derive(Clone, PartialEq, Eq)]
12pub struct RawJwt<'a> {
13 inner: Cow<'a, str>,
14 first_dot: usize,
15 second_dot: usize,
16}
17
18impl RawJwt<'static> {
19 pub(super) fn new(inner: String, first_dot: usize, second_dot: usize) -> Self {
20 Self {
21 inner: inner.into(),
22 first_dot,
23 second_dot,
24 }
25 }
26}
27
28impl std::fmt::Display for RawJwt<'_> {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 write!(f, "{}", self.inner)
31 }
32}
33
34impl<'a> RawJwt<'a> {
35 pub fn header(&'a self) -> &'a str {
36 &self.inner[..self.first_dot]
37 }
38
39 pub fn payload(&'a self) -> &'a str {
40 &self.inner[self.first_dot + 1..self.second_dot]
41 }
42
43 pub fn signature(&'a self) -> &'a str {
44 &self.inner[self.second_dot + 1..]
45 }
46
47 pub fn signed_part(&'a self) -> &'a str {
48 &self.inner[..self.second_dot]
49 }
50
51 pub fn into_owned(self) -> RawJwt<'static> {
52 RawJwt {
53 inner: self.inner.into_owned().into(),
54 first_dot: self.first_dot,
55 second_dot: self.second_dot,
56 }
57 }
58}
59
60impl Deref for RawJwt<'_> {
61 type Target = str;
62
63 fn deref(&self) -> &Self::Target {
64 &self.inner
65 }
66}
67
68#[derive(Debug, Error)]
69pub enum DecodeError {
70 #[error("no dots found in JWT")]
71 NoDots,
72
73 #[error("only one dot found in JWT")]
74 OnlyOneDot,
75
76 #[error("too many dots in JWT")]
77 TooManyDots,
78}
79
80impl<'a> From<RawJwt<'a>> for String {
81 fn from(val: RawJwt<'a>) -> Self {
82 val.inner.into()
83 }
84}
85
86impl<'a> TryFrom<&'a str> for RawJwt<'a> {
87 type Error = DecodeError;
88 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
89 let mut indices = value
90 .char_indices()
91 .filter_map(|(idx, c)| (c == '.').then_some(idx));
92
93 let first_dot = indices.next().ok_or(DecodeError::NoDots)?;
94 let second_dot = indices.next().ok_or(DecodeError::OnlyOneDot)?;
95
96 if indices.next().is_some() {
97 return Err(DecodeError::TooManyDots);
98 }
99
100 Ok(Self {
101 inner: value.into(),
102 first_dot,
103 second_dot,
104 })
105 }
106}
107
108impl TryFrom<String> for RawJwt<'static> {
109 type Error = DecodeError;
110 fn try_from(value: String) -> Result<Self, Self::Error> {
111 let mut indices = value
112 .char_indices()
113 .filter_map(|(idx, c)| (c == '.').then_some(idx));
114
115 let first_dot = indices.next().ok_or(DecodeError::NoDots)?;
116 let second_dot = indices.next().ok_or(DecodeError::OnlyOneDot)?;
117
118 if indices.next().is_some() {
119 return Err(DecodeError::TooManyDots);
120 }
121
122 Ok(Self {
123 inner: value.into(),
124 first_dot,
125 second_dot,
126 })
127 }
128}