this repo has no description
1use crate::state::AppState;
2use axum::{
3 Json,
4 extract::State,
5 http::StatusCode,
6 response::{IntoResponse, Response},
7};
8use chrono::{Duration, Utc};
9use k256::ecdsa::SigningKey;
10use serde::{Deserialize, Serialize};
11use serde_json::json;
12use tracing::{error, info};
13
14const SECP256K1_MULTICODEC_PREFIX: [u8; 2] = [0xe7, 0x01];
15
16fn public_key_to_did_key(signing_key: &SigningKey) -> String {
17 let verifying_key = signing_key.verifying_key();
18 let compressed_pubkey = verifying_key.to_sec1_bytes();
19 let mut multicodec_key = Vec::with_capacity(2 + compressed_pubkey.len());
20 multicodec_key.extend_from_slice(&SECP256K1_MULTICODEC_PREFIX);
21 multicodec_key.extend_from_slice(&compressed_pubkey);
22 let encoded = multibase::encode(multibase::Base::Base58Btc, &multicodec_key);
23 format!("did:key:{}", encoded)
24}
25
26#[derive(Deserialize)]
27pub struct ReserveSigningKeyInput {
28 pub did: Option<String>,
29}
30
31#[derive(Serialize)]
32#[serde(rename_all = "camelCase")]
33pub struct ReserveSigningKeyOutput {
34 pub signing_key: String,
35}
36
37pub async fn reserve_signing_key(
38 State(state): State<AppState>,
39 Json(input): Json<ReserveSigningKeyInput>,
40) -> Response {
41 let signing_key = SigningKey::random(&mut rand::thread_rng());
42 let private_key_bytes = signing_key.to_bytes();
43 let public_key_did_key = public_key_to_did_key(&signing_key);
44 let expires_at = Utc::now() + Duration::hours(24);
45 let private_bytes: &[u8] = &private_key_bytes;
46 let result = sqlx::query!(
47 r#"
48 INSERT INTO reserved_signing_keys (did, public_key_did_key, private_key_bytes, expires_at)
49 VALUES ($1, $2, $3, $4)
50 RETURNING id
51 "#,
52 input.did,
53 public_key_did_key,
54 private_bytes,
55 expires_at
56 )
57 .fetch_one(&state.db)
58 .await;
59 match result {
60 Ok(row) => {
61 info!("Reserved signing key {} for did {:?}", row.id, input.did);
62 (
63 StatusCode::OK,
64 Json(ReserveSigningKeyOutput {
65 signing_key: public_key_did_key,
66 }),
67 )
68 .into_response()
69 }
70 Err(e) => {
71 error!("DB error in reserve_signing_key: {:?}", e);
72 (
73 StatusCode::INTERNAL_SERVER_ERROR,
74 Json(json!({"error": "InternalError"})),
75 )
76 .into_response()
77 }
78 }
79}