mas_jose/jwt/
raw.rs

1// Copyright 2024 New Vector Ltd.
2// Copyright 2022-2024 The Matrix.org Foundation C.I.C.
3//
4// SPDX-License-Identifier: AGPL-3.0-only
5// Please see LICENSE in the repository root for full details.
6
7use 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}