mirror of
https://tangled.org/tranquil.farm/tranquil-pds
synced 2026-09-26 12:14:15 +00:00
Fix genesis commit stuff, update deps
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
use super::did::verify_did_web;
|
||||
use crate::api::repo::record::utils::create_signed_commit;
|
||||
use crate::auth::{ServiceTokenVerifier, extract_bearer_token_from_header, is_service_token};
|
||||
use crate::plc::{PlcClient, create_genesis_operation, signing_key_to_did_key};
|
||||
use crate::state::{AppState, RateLimitKind};
|
||||
@@ -10,8 +11,8 @@ use axum::{
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use bcrypt::{DEFAULT_COST, hash};
|
||||
use jacquard::types::{did::Did, integer::LimitedU32, string::Tid};
|
||||
use jacquard_repo::{commit::Commit, mst::Mst, storage::BlockStore};
|
||||
use jacquard::types::{integer::LimitedU32, string::Tid};
|
||||
use jacquard_repo::{mst::Mst, storage::BlockStore};
|
||||
use k256::{SecretKey, ecdsa::SigningKey};
|
||||
use rand::rngs::OsRng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -864,33 +865,11 @@ pub async fn create_account(
|
||||
.into_response();
|
||||
}
|
||||
};
|
||||
let did_obj = match Did::new(&did) {
|
||||
Ok(d) => d,
|
||||
Err(_) => {
|
||||
return (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!({"error": "InternalError", "message": "Invalid DID"})),
|
||||
)
|
||||
.into_response();
|
||||
}
|
||||
};
|
||||
let rev = Tid::now(LimitedU32::MIN);
|
||||
let unsigned_commit = Commit::new_unsigned(did_obj, mst_root, rev, None);
|
||||
let signed_commit = match unsigned_commit.sign(&signing_key) {
|
||||
Ok(c) => c,
|
||||
let (commit_bytes, _sig) = match create_signed_commit(&did, mst_root, &rev.to_string(), None, &signing_key) {
|
||||
Ok(result) => result,
|
||||
Err(e) => {
|
||||
error!("Error signing genesis commit: {:?}", e);
|
||||
return (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!({"error": "InternalError"})),
|
||||
)
|
||||
.into_response();
|
||||
}
|
||||
};
|
||||
let commit_bytes = match signed_commit.to_cbor() {
|
||||
Ok(b) => b,
|
||||
Err(e) => {
|
||||
error!("Error serializing genesis commit: {:?}", e);
|
||||
error!("Error creating genesis commit: {:?}", e);
|
||||
return (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!({"error": "InternalError"})),
|
||||
|
||||
@@ -3,23 +3,23 @@ use bytes::Bytes;
|
||||
use cid::Cid;
|
||||
use jacquard::types::{integer::LimitedU32, string::Tid};
|
||||
use jacquard_repo::storage::BlockStore;
|
||||
use k256::ecdsa::{Signature, SigningKey, signature::Signer};
|
||||
use k256::ecdsa::{signature::Signer, Signature, SigningKey};
|
||||
use serde::Serialize;
|
||||
use serde_json::json;
|
||||
use uuid::Uuid;
|
||||
|
||||
/*
|
||||
* Why am I making custom commit objects instead of jacquard's Commit::sign(), you ask?
|
||||
* Why custom commit signing instead of jacquard's Commit::sign()?
|
||||
*
|
||||
* At time of writing, jacquard has a bug in how it creates unsigned bytes for signing.
|
||||
* Jacquard sets sig to empty bytes and serializes (6-field CBOR map)
|
||||
* Indigo/ATProto creates a struct *without* the sig field (5-field CBOR map)
|
||||
* Jacquard previously had a bug in how it created unsigned bytes for signing:
|
||||
* it set sig to empty bytes and serialized (6-field CBOR map), while the
|
||||
* ATProto spec creates a struct *without* the sig field (5-field CBOR map).
|
||||
* These produce different CBOR bytes, so signatures didn't verify with relays.
|
||||
*
|
||||
* These produce different CBOR bytes, so signatures created with jacquard
|
||||
* don't verify with the relay's algorithm. The relay silently rejects commits
|
||||
* with invalid signatures.
|
||||
*
|
||||
* If you have it downloaded, see: reference-relay-indigo/atproto/repo/commit.go UnsignedBytes()
|
||||
* The bug has been fixed in jacquard, but the fix is untested here.
|
||||
* TODO: Switch back to jacquard's Commit::sign() and verify it works.
|
||||
*/
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct UnsignedCommit<'a> {
|
||||
data: Cid,
|
||||
@@ -29,7 +29,7 @@ struct UnsignedCommit<'a> {
|
||||
version: i64,
|
||||
}
|
||||
|
||||
fn create_signed_commit(
|
||||
pub fn create_signed_commit(
|
||||
did: &str,
|
||||
data: Cid,
|
||||
rev: &str,
|
||||
|
||||
@@ -6,8 +6,8 @@ use axum::{
|
||||
};
|
||||
use bcrypt::{DEFAULT_COST, hash};
|
||||
use chrono::{Duration, Utc};
|
||||
use jacquard::types::{did::Did, integer::LimitedU32, string::Tid};
|
||||
use jacquard_repo::{commit::Commit, mst::Mst, storage::BlockStore};
|
||||
use jacquard::types::{integer::LimitedU32, string::Tid};
|
||||
use jacquard_repo::{mst::Mst, storage::BlockStore};
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
@@ -15,6 +15,7 @@ use std::sync::Arc;
|
||||
use tracing::{error, info, warn};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::api::repo::record::utils::create_signed_commit;
|
||||
use crate::state::{AppState, RateLimitKind};
|
||||
use crate::validation::validate_password;
|
||||
|
||||
@@ -391,13 +392,20 @@ pub async fn create_passkey_account(
|
||||
}
|
||||
};
|
||||
|
||||
let is_first_user = sqlx::query_scalar!("SELECT COUNT(*) as count FROM users")
|
||||
.fetch_one(&mut *tx)
|
||||
.await
|
||||
.map(|c| c.unwrap_or(0) == 0)
|
||||
.unwrap_or(false);
|
||||
|
||||
let user_insert: Result<(Uuid,), _> = sqlx::query_as(
|
||||
r#"INSERT INTO users (
|
||||
handle, email, did, password_hash, password_required,
|
||||
preferred_comms_channel,
|
||||
discord_id, telegram_username, signal_number,
|
||||
recovery_token, recovery_token_expires_at
|
||||
) VALUES ($1, $2, $3, NULL, FALSE, $4::comms_channel, $5, $6, $7, $8, $9) RETURNING id"#,
|
||||
recovery_token, recovery_token_expires_at,
|
||||
is_admin
|
||||
) VALUES ($1, $2, $3, NULL, FALSE, $4::comms_channel, $5, $6, $7, $8, $9, $10) RETURNING id"#,
|
||||
)
|
||||
.bind(&handle)
|
||||
.bind(&email)
|
||||
@@ -426,6 +434,7 @@ pub async fn create_passkey_account(
|
||||
)
|
||||
.bind(&setup_token_hash)
|
||||
.bind(setup_expires_at)
|
||||
.bind(is_first_user)
|
||||
.fetch_one(&mut *tx)
|
||||
.await;
|
||||
|
||||
@@ -518,33 +527,11 @@ pub async fn create_passkey_account(
|
||||
.into_response();
|
||||
}
|
||||
};
|
||||
let did_obj = match Did::new(&did) {
|
||||
Ok(d) => d,
|
||||
Err(_) => {
|
||||
return (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!({"error": "InternalError", "message": "Invalid DID"})),
|
||||
)
|
||||
.into_response();
|
||||
}
|
||||
};
|
||||
let rev = Tid::now(LimitedU32::MIN);
|
||||
let unsigned_commit = Commit::new_unsigned(did_obj, mst_root, rev, None);
|
||||
let signed_commit = match unsigned_commit.sign(&secret_key) {
|
||||
Ok(c) => c,
|
||||
let (commit_bytes, _sig) = match create_signed_commit(&did, mst_root, &rev.to_string(), None, &secret_key) {
|
||||
Ok(result) => result,
|
||||
Err(e) => {
|
||||
error!("Error signing genesis commit: {:?}", e);
|
||||
return (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!({"error": "InternalError"})),
|
||||
)
|
||||
.into_response();
|
||||
}
|
||||
};
|
||||
let commit_bytes = match signed_commit.to_cbor() {
|
||||
Ok(b) => b,
|
||||
Err(e) => {
|
||||
error!("Error serializing genesis commit: {:?}", e);
|
||||
error!("Error creating genesis commit: {:?}", e);
|
||||
return (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!({"error": "InternalError"})),
|
||||
@@ -630,6 +617,26 @@ pub async fn create_passkey_account(
|
||||
{
|
||||
warn!("Failed to sequence identity event for {}: {}", did, e);
|
||||
}
|
||||
if let Err(e) =
|
||||
crate::api::repo::record::sequence_account_event(&state, &did, true, None).await
|
||||
{
|
||||
warn!("Failed to sequence account event for {}: {}", did, e);
|
||||
}
|
||||
let profile_record = serde_json::json!({
|
||||
"$type": "app.bsky.actor.profile",
|
||||
"displayName": handle
|
||||
});
|
||||
if let Err(e) = crate::api::repo::record::create_record_internal(
|
||||
&state,
|
||||
&did,
|
||||
"app.bsky.actor.profile",
|
||||
"self",
|
||||
&profile_record,
|
||||
)
|
||||
.await
|
||||
{
|
||||
warn!("Failed to create default profile for {}: {}", did, e);
|
||||
}
|
||||
|
||||
if let Err(e) = crate::comms::enqueue_signup_verification(
|
||||
&state.db,
|
||||
|
||||
@@ -90,6 +90,7 @@ impl ClientMetadataCache {
|
||||
if let Ok(url) = reqwest::Url::parse(client_id) {
|
||||
url.scheme() == "http"
|
||||
&& matches!(url.host_str(), Some("localhost") | Some("127.0.0.1"))
|
||||
&& url.query().is_some()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user