use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
use crate::schema::WebcIdent;
use uuid::Uuid;
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
pub struct BaseClaims {
#[serde(with = "time::serde::timestamp")]
pub exp: OffsetDateTime,
#[serde(with = "time::serde::timestamp")]
pub iat: OffsetDateTime,
pub sub: String,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug, schemars::JsonSchema)]
pub struct DeployWorkloadTokenV1 {
#[serde(with = "time::serde::timestamp")]
#[schemars(with = "u64")]
pub exp: OffsetDateTime,
#[serde(with = "time::serde::timestamp")]
#[schemars(with = "u64")]
pub iat: OffsetDateTime,
pub sub: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub jti: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none")]
pub webc: Option<WebcIdent>,
#[serde(skip_serializing_if = "Option::is_none")]
pub allowed_packages: Option<Vec<WebcIdent>>,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(untagged)]
pub enum DeployWorkloadTokenData {
V1(DeployWorkloadTokenV1),
}
impl From<DeployWorkloadTokenV1> for DeployWorkloadTokenData {
fn from(value: DeployWorkloadTokenV1) -> Self {
Self::V1(value)
}
}
#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
pub struct DeployWorkloadToken {
pub raw: String,
pub data: DeployWorkloadTokenData,
}
impl DeployWorkloadTokenData {
pub fn expires(&self) -> Option<&OffsetDateTime> {
match self {
DeployWorkloadTokenData::V1(v1) => Some(&v1.exp),
}
}
pub fn issued_at(&self) -> &OffsetDateTime {
match self {
DeployWorkloadTokenData::V1(v1) => &v1.iat,
}
}
pub fn subject(&self) -> &str {
match self {
DeployWorkloadTokenData::V1(v1) => &v1.sub,
}
}
pub fn webc_spec(&self) -> Option<&WebcIdent> {
match self {
Self::V1(v1) => v1.webc.as_ref(),
}
}
pub fn jti(&self) -> Option<&Uuid> {
match self {
Self::V1(v) => v.jti.as_ref(),
}
}
pub fn has_webc_spec(&self) -> bool {
self.webc_spec().is_some()
}
pub fn as_v1(&self) -> &DeployWorkloadTokenV1 {
match &self {
DeployWorkloadTokenData::V1(x) => x,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_deser_tokens() {
#[allow(deprecated)]
let expected = DeployWorkloadTokenData::V1(DeployWorkloadTokenV1 {
exp: OffsetDateTime::from_unix_timestamp(10000).unwrap(),
iat: OffsetDateTime::from_unix_timestamp(20000).unwrap(),
sub: "user-1".to_string(),
jti: None,
webc: Some(WebcIdent {
repository: Some("https://registry.wapm.dev".parse().unwrap()),
namespace: "ns".to_string(),
name: "name".to_string(),
tag: Some("1.2.3".to_string()),
}),
allowed_packages: Some(vec![WebcIdent {
repository: Some("https://registry.wapm.dev".parse().unwrap()),
namespace: "ns".to_string(),
name: "name".to_string(),
tag: Some("1.2.3".to_string()),
}]),
});
let raw = r#"
{
"exp": 10000,
"iat": 20000,
"sub": "user-1",
"webc": {
"repository": "https://registry.wapm.dev/",
"namespace": "ns",
"name": "name",
"tag": "1.2.3",
"hash": null,
"download_url": "https://test.com/lala"
},
"cfg": {
"uid": "123",
"backend_url": "http://test.com"
},
"allowed_packages": [
{
"repository": "https://registry.wapm.dev/",
"namespace": "ns",
"name": "name",
"tag": "1.2.3",
"hash": null,
"download_url": "https://test.com/lala"
}
]
}
"#;
let deser: DeployWorkloadTokenData =
crate::schema::deserialize_json(raw.as_bytes()).unwrap();
assert_eq!(
deser
.webc_spec()
.unwrap()
.build_download_url()
.unwrap()
.to_string(),
"https://registry.wapm.dev/ns/name@1.2.3",
);
pretty_assertions::assert_eq!(deser, expected);
}
}