···2121 let bday = NaiveDate::parse_from_str(birth_date, "%Y-%m-%d").ok()?;
2222 let today = Utc::now().date_naive();
2323 let mut age = today.year() - bday.year();
2424- let m = today.month() as i32 - bday.month() as i32;
2424+ let m = i32::try_from(today.month()).unwrap_or(0) - i32::try_from(bday.month()).unwrap_or(0);
2525 if m < 0 || (m == 0 && today.day() < bday.day()) {
2626 age -= 1;
2727 }
···8484 .ok()
8585 .flatten()
8686 .ok_or(ApiError::AccountNotFound)?;
8787- let handle_for_check = unsafe { Handle::new_unchecked(&handle) };
8787+ let handle_for_check: Handle = handle.parse().map_err(|_| ApiError::InvalidHandle(None))?;
8888 if let Ok(true) = state
8989 .user_repo
9090 .check_handle_exists(&handle_for_check, user_id)
···100100 Ok(0) => Err(ApiError::AccountNotFound),
101101 Ok(_) => {
102102 if let Some(old) = old_handle {
103103- let _ = state.cache.delete(&format!("handle:{}", old)).await;
103103+ let _ = state
104104+ .cache
105105+ .delete(&crate::cache_keys::handle_key(&old))
106106+ .await;
104107 }
105105- let _ = state.cache.delete(&format!("handle:{}", handle)).await;
108108+ let _ = state
109109+ .cache
110110+ .delete(&crate::cache_keys::handle_key(&handle))
111111+ .await;
106112 if let Err(e) = crate::api::repo::record::sequence_identity_event(
107113 &state,
108114 did,
+18-9
crates/tranquil-pds/src/api/admin/config.rs
···33use crate::state::AppState;
44use axum::{Json, extract::State};
55use serde::{Deserialize, Serialize};
66-use tracing::error;
66+use tracing::{error, warn};
77use tranquil_types::CidLink;
8899#[derive(Serialize)]
···187187 };
188188189189 if let Some(old_cid_str) = should_delete_old {
190190- let old_cid = unsafe { CidLink::new_unchecked(old_cid_str) };
191191- if let Ok(Some(storage_key)) =
192192- state.infra_repo.get_blob_storage_key_by_cid(&old_cid).await
193193- {
194194- if let Err(e) = state.blob_store.delete(&storage_key).await {
195195- error!("Failed to delete old logo blob from storage: {:?}", e);
190190+ match CidLink::new(old_cid_str) {
191191+ Ok(old_cid) => {
192192+ if let Ok(Some(storage_key)) =
193193+ state.infra_repo.get_blob_storage_key_by_cid(&old_cid).await
194194+ {
195195+ if let Err(e) = state.blob_store.delete(&storage_key).await {
196196+ error!("Failed to delete old logo blob from storage: {:?}", e);
197197+ }
198198+ if let Err(e) = state.infra_repo.delete_blob_by_cid(&old_cid).await {
199199+ error!("Failed to delete old logo blob record: {:?}", e);
200200+ }
201201+ }
196202 }
197197- if let Err(e) = state.infra_repo.delete_blob_by_cid(&old_cid).await {
198198- error!("Failed to delete old logo blob record: {:?}", e);
203203+ Err(e) => {
204204+ warn!(
205205+ "Old logo CID in database is invalid, skipping cleanup: {:?}",
206206+ e
207207+ );
199208 }
200209 }
201210 }
+1-1
crates/tranquil-pds/src/api/admin/invite.rs
···144144 })
145145 .collect();
146146147147- let next_cursor = if codes_rows.len() == limit as usize {
147147+ let next_cursor = if codes_rows.len() == usize::try_from(limit).unwrap_or(0) {
148148 codes_rows.last().map(|r| r.code.clone())
149149 } else {
150150 None
+8-2
crates/tranquil-pds/src/api/admin/status.rs
···175175 Some("com.atproto.admin.defs#repoRef") => {
176176 let did_str = input.subject.get("did").and_then(|d| d.as_str());
177177 if let Some(did_str) = did_str {
178178- let did = unsafe { Did::new_unchecked(did_str) };
178178+ let did: Did = match did_str.parse() {
179179+ Ok(d) => d,
180180+ Err(_) => return Err(ApiError::InvalidDid("Invalid DID format".into())),
181181+ };
179182 if let Some(takedown) = &input.takedown {
180183 let takedown_ref = if takedown.applied {
181184 takedown.r#ref.as_deref()
···230233 }
231234 }
232235 if let Ok(Some(handle)) = state.user_repo.get_handle_by_did(&did).await {
233233- let _ = state.cache.delete(&format!("handle:{}", handle)).await;
236236+ let _ = state
237237+ .cache
238238+ .delete(&crate::cache_keys::handle_key(&handle))
239239+ .await;
234240 }
235241 return Ok((
236242 StatusCode::OK,
···57575858 for part in scope_parts {
5959 if let Some(cid_str) = part.strip_prefix("ref:") {
6060- let cache_key = format!("scope_ref:{}", cid_str);
6060+ let cache_key = crate::cache_keys::scope_ref_key(cid_str);
6161 if let Some(cached) = state.cache.get(&cache_key).await {
6262 for s in cached.split_whitespace() {
6363 if !resolved_scopes.contains(&s.to_string()) {
···77 mime_encode_header, sanitize_header_value, validate_locale,
88};
991010-pub use service::{CommsService, channel_display_name, repo as comms_repo};
1010+pub use service::{CommsService, repo as comms_repo};
···225225#[tokio::test]
226226async fn test_unsupported_did_method() {
227227 let verifier = CarVerifier::new();
228228- let result = verifier.resolve_did_document("did:unknown:test").await;
228228+ let did: tranquil_types::Did = "did:unknown:test".parse().expect("valid DID format");
229229+ let result = verifier.resolve_did_document(&did).await;
229230 assert!(result.is_err());
230231 let err = result.unwrap_err();
231232 assert!(matches!(err, VerifyError::DidResolutionFailed(_)));
···9999 use tranquil_pds::api::repo::record::utils::create_signed_commit;
100100101101 let signing_key = SigningKey::random(&mut rand::thread_rng());
102102- let did = unsafe { Did::new_unchecked("did:plc:testuser123456789abcdef") };
102102+ let did: Did = "did:plc:testuser123456789abcdef"
103103+ .parse()
104104+ .expect("valid test DID");
103105 let data_cid =
104106 Cid::from_str("bafyreib2rxk3ryblouj3fxza5jvx6psmwewwessc4m6g6e7pqhhkwqomfi").unwrap();
105107 let rev = Tid::now(LimitedU32::MIN).to_string();