use tracing::info;
use vta_sdk::webvh::WebvhDidRecord;
use vti_common::error::AppError;
use crate::store::{KeyspaceHandle, Store};
use crate::webvh_store;
use crate::tee::did_autogen::DID_LOG_STORE_KEY as TEE_DID_LOG_STORE_KEY;
pub async fn backfill_serverless_webvh_identity(
store: &Store,
storage_encryption_key: Option<[u8; 32]>,
vta_did: &str,
) -> Result<(), AppError> {
if !vta_did.starts_with("did:webvh:") {
return Ok(());
}
let with_enc = |ks: KeyspaceHandle| match storage_encryption_key {
Some(key) => ks.with_encryption(key),
None => ks,
};
let webvh_ks = with_enc(store.keyspace(crate::keyspaces::WEBVH)?);
let mut persisted = false;
if webvh_store::get_did_log(&webvh_ks, vta_did)
.await?
.is_none()
{
let keys_ks = with_enc(store.keyspace(crate::keyspaces::KEYS)?);
if let Some(bytes) = keys_ks.get_raw(TEE_DID_LOG_STORE_KEY).await? {
let log_content = String::from_utf8(bytes).map_err(|e| {
AppError::Internal(format!("corrupt stored VTA did.jsonl log: {e}"))
})?;
webvh_store::store_did_log(&webvh_ks, vta_did, &log_content).await?;
persisted = true;
}
}
if webvh_store::get_did(&webvh_ks, vta_did).await?.is_none() {
let record = build_serverless_webvh_record(vta_did);
webvh_store::store_did(&webvh_ks, &record).await?;
persisted = true;
}
if persisted {
store.persist().await?;
info!(
did = %vta_did,
"backfilled serverless webvh DID record + log into the webvh keyspace"
);
}
Ok(())
}
fn build_serverless_webvh_record(did: &str) -> WebvhDidRecord {
let scid = did.split(':').nth(2).unwrap_or_default().to_string();
let now = chrono::Utc::now();
WebvhDidRecord {
did: did.to_string(),
server_id: "serverless".to_string(),
mnemonic: String::new(),
scid,
context_id: "vta".to_string(),
portable: true,
log_entry_count: 1,
pre_rotation_count: 1,
next_fragment_id: 2,
created_at: now,
updated_at: now,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn record_scid_is_third_colon_segment() {
let record = build_serverless_webvh_record("did:webvh:QmScidValue:example.com:vta");
assert_eq!(record.scid, "QmScidValue");
assert_eq!(record.did, "did:webvh:QmScidValue:example.com:vta");
assert_eq!(record.server_id, "serverless");
assert_eq!(record.next_fragment_id, 2);
assert_eq!(record.pre_rotation_count, 1);
assert_eq!(record.log_entry_count, 1);
assert!(record.portable);
}
}