use base64::Engine;
use chrono::{DateTime, TimeZone, Utc};
use serde_json::{Value, json};
use dpp_crypto::keystore::KeyStore;
use dpp_domain::ProductGroup;
use dpp_domain::access::ProductGroupAccessPolicy;
use super::{SdJwtVcError, issue, vct_for, verify};
pub(super) const KEY_ID: &str = "sd-jwt-issuer";
pub(super) const ISSUER: &str = "https://passports.operator.example";
pub(super) const SCHEMA_VERSION: &str = "2.6.0";
pub(super) const ISSUED_AT: i64 = 1_789_000_000;
pub(super) fn now() -> DateTime<Utc> {
Utc.timestamp_opt(ISSUED_AT + 60, 0).unwrap()
}
pub(super) fn policy() -> ProductGroupAccessPolicy {
ProductGroupAccessPolicy::for_passport("battery", SCHEMA_VERSION)
.expect("battery 2.6.0 schema is embedded")
}
pub(super) fn payload() -> Value {
json!({
"id": "018f3a4c-0000-7000-8000-000000000001",
"productGroup": "battery",
"schemaVersion": SCHEMA_VERSION,
"batchId": "BATCH-7781",
"productGroupData": {
"batteryChemistry": "LFP",
"cathodeMaterial": ["LiFePO4"],
"stateOfHealthPct": 87.5,
"testReportResults": "report-4471",
"safetyMeasures": ["Do not puncture"],
}
})
}
pub(super) fn public_key_b64(store: &KeyStore) -> String {
let info = store.public_key(KEY_ID).expect("key present");
base64::engine::general_purpose::URL_SAFE_NO_PAD
.encode(hex::decode(&info.verifying_key_hex).unwrap())
}
pub(super) fn digests(credential: &dpp_crypto::sd_jwt::SdJwt, names: &[&str]) -> Vec<String> {
names
.iter()
.flat_map(|n| credential.digests_for_claim(n))
.collect()
}
pub(super) fn issued(store: &KeyStore) -> dpp_crypto::sd_jwt::SdJwt {
issue(
store,
KEY_ID,
&payload(),
&policy(),
ISSUER,
&vct_for(ProductGroup::Battery, SCHEMA_VERSION),
ISSUED_AT,
)
.expect("issue")
}
pub(super) fn issued_with(store: &KeyStore, extra: &[(&str, Value)]) -> String {
let mut payload = payload();
let object = payload.as_object_mut().unwrap();
for (k, v) in extra {
object.insert((*k).to_owned(), v.clone());
}
issue(
store,
KEY_ID,
&payload,
&policy(),
ISSUER,
&vct_for(ProductGroup::Battery, SCHEMA_VERSION),
ISSUED_AT,
)
.expect("issue")
.serialise()
}
pub(super) fn check(
store: &KeyStore,
credential: &str,
at: DateTime<Utc>,
) -> Result<(), SdJwtVcError> {
verify(
credential,
&public_key_b64(store),
&vct_for(ProductGroup::Battery, SCHEMA_VERSION),
at,
)
.map(|_| ())
}