Migrate to encodify

This commit is contained in:
Maurus Decimus
2026-09-28 10:45:15 +02:00
parent 42f7c87911
commit 5dc92c7329
29 changed files with 418 additions and 540 deletions
+18 -8
View File
@@ -7,8 +7,7 @@
use std::io::{self, Write};
use std::time::Duration;
use base64::Engine;
use base64::engine::general_purpose::URL_SAFE_NO_PAD;
use encodify::base64::{Base64, Padding, URL_SAFE};
use serde_json::Value;
use ureq::config::Config;
use ureq::tls::{RootCerts, TlsConfig};
@@ -19,6 +18,8 @@ pub const SCOPE_APP_ONLY: &str = "https://outlook.office365.com/.default";
pub const SCOPE_DELEGATED: &str =
"https://outlook.office365.com/EWS.AccessAsUser.All offline_access";
const JWT_SEGMENT: Base64 = URL_SAFE.with_padding(Padding::Optional).any_alphabet();
#[derive(Debug, Clone)]
pub struct AcquiredToken {
pub access_token: String,
@@ -81,11 +82,7 @@ pub fn decode_jwt_claims(token: &str) -> Option<JwtClaims> {
let mut parts = token.split('.');
let _header = parts.next()?;
let payload = parts.next()?;
let bytes = URL_SAFE_NO_PAD
.decode(payload)
.or_else(|_| base64::engine::general_purpose::STANDARD_NO_PAD.decode(payload))
.or_else(|_| base64::engine::general_purpose::STANDARD.decode(payload))
.ok()?;
let bytes = JWT_SEGMENT.decode(payload).ok()?;
let value: Value = serde_json::from_slice(&bytes).ok()?;
Some(JwtClaims {
tenant_id: value.get("tid").and_then(Value::as_str).map(str::to_owned),
@@ -329,7 +326,7 @@ fn urlencode(s: &str) -> String {
#[cfg(test)]
mod tests {
use super::*;
use base64::engine::general_purpose::URL_SAFE_NO_PAD;
use encodify::base64::{STANDARD, STANDARD_NO_PAD, URL_SAFE_NO_PAD};
fn make_jwt(tid: &str, upn: &str, exp: u64) -> String {
let header = URL_SAFE_NO_PAD.encode(b"{\"alg\":\"none\"}");
@@ -347,6 +344,19 @@ mod tests {
assert_eq!(claims.exp, Some(9999999999));
}
#[test]
fn jwt_payload_decodes_in_either_alphabet_with_or_without_padding() {
let claims = r#"{"tid":"t-3","upn":"??>>@xy","exp":1}"#;
for engine in [URL_SAFE_NO_PAD, URL_SAFE, STANDARD_NO_PAD, STANDARD] {
let token = format!("h.{}.s", engine.encode(claims));
let decoded = decode_jwt_claims(&token).unwrap();
assert_eq!(decoded.upn.as_deref(), Some("??>>@xy"), "{token}");
}
assert!(decode_jwt_claims("h.eyJ0aWQiOiJ0LTMifQ.s").is_some());
assert!(decode_jwt_claims("h.eyJ0aWQiOiJ0LTMifQ=.s").is_none());
assert!(decode_jwt_claims("h.eyJ0 aWQiOiJ0LTMifQ.s").is_none());
}
#[test]
fn malformed_token_returns_none() {
assert!(decode_jwt_claims("garbage").is_none());