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
20 let mut multicodec_key = Vec::with_capacity(2 + compressed_pubkey.len());
21 multicodec_key.extend_from_slice(&SECP256K1_MULTICODEC_PREFIX);
22 multicodec_key.extend_from_slice(&compressed_pubkey);
23
24 let encoded = multibase::encode(multibase::Base::Base58Btc, &multicodec_key);
25
26 format!("did:key:{}", encoded)
27}
28
29#[derive(Deserialize)]
30pub struct ReserveSigningKeyInput {
31 pub did: Option<String>,
32}
33
34#[derive(Serialize)]
35#[serde(rename_all = "camelCase")]
36pub struct ReserveSigningKeyOutput {
37 pub signing_key: String,
38}
39
40pub async fn reserve_signing_key(
41 State(state): State<AppState>,
42 Json(input): Json<ReserveSigningKeyInput>,
43) -> Response {
44 let signing_key = SigningKey::random(&mut rand::thread_rng());
45 let private_key_bytes = signing_key.to_bytes();
46 let public_key_did_key = public_key_to_did_key(&signing_key);
47
48 let expires_at = Utc::now() + Duration::hours(24);
49
50 let private_bytes: &[u8] = &private_key_bytes;
51
52 let result = sqlx::query!(
53 r#"
54 INSERT INTO reserved_signing_keys (did, public_key_did_key, private_key_bytes, expires_at)
55 VALUES ($1, $2, $3, $4)
56 RETURNING id
57 "#,
58 input.did,
59 public_key_did_key,
60 private_bytes,
61 expires_at
62 )
63 .fetch_one(&state.db)
64 .await;
65
66 match result {
67 Ok(row) => {
68 info!(
69 "Reserved signing key {} for did {:?}",
70 row.id,
71 input.did
72 );
73 (
74 StatusCode::OK,
75 Json(ReserveSigningKeyOutput {
76 signing_key: public_key_did_key,
77 }),
78 )
79 .into_response()
80 }
81 Err(e) => {
82 error!("DB error in reserve_signing_key: {:?}", e);
83 (
84 StatusCode::INTERNAL_SERVER_ERROR,
85 Json(json!({"error": "InternalError"})),
86 )
87 .into_response()
88 }
89 }
90}