identity_jose/jws/
charset.rs

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
// Copyright 2020-2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use core::str::from_utf8;

use crate::error::Error;
use crate::error::Result;

/// The requirements towards the character set when encoding a JWS.
///
/// See the individual variants for more details.
#[derive(Clone, Copy, Debug)]
pub enum CharSet {
  /// The ASCII space character and all printable ASCII characters other
  /// than period ('.') (those characters in the ranges %x20-2D and %x2F-7E)
  /// MAY be included in a non-detached payload using the JWS Compact
  /// Serialization, provided that the application can transmit the
  /// resulting JWS without modification.
  Default,
  /// If a JWS using the JWS Compact Serialization and a non-detached
  /// payload is to be transmitted in a context that requires URL-safe
  /// characters, then the application MUST ensure that the payload
  /// contains only the URL-safe characters 'a'-'z', 'A'-'Z', '0'-'9',
  /// dash ('-'), underscore ('_'), and tilde ('~').
  UrlSafe,
}

impl CharSet {
  /// Validate unencoded content for used with the compact serialization
  /// format. The payload MUST NOT contain a period (`.`) and MAY be
  /// required to only contain URL-safe characters.
  ///
  /// [More Info](https://tools.ietf.org/html/rfc7797#section-5.2)
  pub fn validate<'data>(&self, data: &'data [u8]) -> Result<&'data str> {
    let payload: &'data str = from_utf8(data).map_err(|_| Error::InvalidContent("invalid UTF-8"))?;

    if payload.contains('.') {
      return Err(Error::InvalidContent("invalid character `.`"));
    }

    if !self.__validate(payload) {
      return Err(Error::InvalidContent("invalid character(s)"));
    }

    Ok(payload)
  }

  fn __validate(&self, data: &str) -> bool {
    match self {
      Self::Default => data.chars().all(|ch| matches!(ch, '\x20'..='\x2D' | '\x2F'..='\x7E')),
      Self::UrlSafe => data
        .chars()
        .all(|ch| matches!(ch, 'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' | '~')),
    }
  }
}