Compare commits
1 commit
master
...
feature/v3
Author | SHA1 | Date | |
---|---|---|---|
ab53a6ac24 |
3 changed files with 34 additions and 0 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1172,6 +1172,7 @@ dependencies = [
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"prometheus",
|
"prometheus",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
"ring",
|
||||||
"rustls",
|
"rustls",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
|
@ -32,6 +32,7 @@ lru = "0.6"
|
||||||
parking_lot = "0.11"
|
parking_lot = "0.11"
|
||||||
prometheus = { version = "0.12", features = [ "process" ] }
|
prometheus = { version = "0.12", features = [ "process" ] }
|
||||||
reqwest = { version = "0.11", default_features = false, features = [ "json", "stream", "rustls-tls" ] }
|
reqwest = { version = "0.11", default_features = false, features = [ "json", "stream", "rustls-tls" ] }
|
||||||
|
ring = "*"
|
||||||
rustls = "0.19"
|
rustls = "0.19"
|
||||||
serde = "1"
|
serde = "1"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
|
|
@ -17,6 +17,7 @@ use log::{debug, error, info, trace, warn};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use prometheus::{Encoder, TextEncoder};
|
use prometheus::{Encoder, TextEncoder};
|
||||||
use reqwest::{Client, StatusCode};
|
use reqwest::{Client, StatusCode};
|
||||||
|
use ring::signature::ECDSA_P256_SHA256_ASN1;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sodiumoxide::crypto::box_::{open_precomputed, Nonce, PrecomputedKey, NONCEBYTES};
|
use sodiumoxide::crypto::box_::{open_precomputed, Nonce, PrecomputedKey, NONCEBYTES};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
@ -170,6 +171,8 @@ enum TokenValidationError {
|
||||||
TokenExpired,
|
TokenExpired,
|
||||||
#[error("Invalid chapter hash.")]
|
#[error("Invalid chapter hash.")]
|
||||||
InvalidChapterHash,
|
InvalidChapterHash,
|
||||||
|
#[error("Invalid v32 format")]
|
||||||
|
InvalidV32Format,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Responder for TokenValidationError {
|
impl Responder for TokenValidationError {
|
||||||
|
@ -217,6 +220,35 @@ fn validate_token(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validate_token_v32(pub_key: &[u8], token: String) -> Result<(), TokenValidationError> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Token<'a> {
|
||||||
|
expires: DateTime<Utc>,
|
||||||
|
client_id: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
let (token_base64, sig_base64) = token
|
||||||
|
.split_once('~')
|
||||||
|
.ok_or_else(|| TokenValidationError::InvalidV32Format)?;
|
||||||
|
let token = base64::decode_config(token_base64, BASE64_CONFIG)?;
|
||||||
|
let sig = base64::decode_config(sig_base64, BASE64_CONFIG)?;
|
||||||
|
|
||||||
|
ring::signature::UnparsedPublicKey::new(&ECDSA_P256_SHA256_ASN1, pub_key)
|
||||||
|
.verify(&token, &sig)
|
||||||
|
.map_err(|_| TokenValidationError::DecryptionFailure)?;
|
||||||
|
|
||||||
|
// At this point, token has a valid signature, now to check token fields
|
||||||
|
|
||||||
|
let token: Token =
|
||||||
|
serde_json::from_slice(&token).map_err(|_| TokenValidationError::InvalidToken)?;
|
||||||
|
|
||||||
|
if token.expires < Utc::now() {
|
||||||
|
return Err(TokenValidationError::TokenExpired);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn push_headers(builder: &mut HttpResponseBuilder) -> &mut HttpResponseBuilder {
|
fn push_headers(builder: &mut HttpResponseBuilder) -> &mut HttpResponseBuilder {
|
||||||
builder
|
builder
|
||||||
|
|
Loading…
Reference in a new issue