mirror of
https://tangled.org/tranquil.farm/tranquil-pds
synced 2026-09-04 09:16:54 +00:00
Fix genesis commit stuff, update deps
This commit is contained in:
Generated
+265
-425
File diff suppressed because it is too large
Load Diff
+14
-14
@@ -5,9 +5,9 @@ edition = "2024"
|
||||
[dependencies]
|
||||
anyhow = "1.0.100"
|
||||
async-trait = "0.1.89"
|
||||
aws-config = "1.8.11"
|
||||
aws-sdk-s3 = "1.116.0"
|
||||
axum = { version = "0.8.7", features = ["ws", "macros"] }
|
||||
aws-config = "1.8.12"
|
||||
aws-sdk-s3 = "1.118.0"
|
||||
axum = { version = "0.8.8", features = ["ws", "macros"] }
|
||||
base32 = "0.5"
|
||||
base64 = "0.22.1"
|
||||
bcrypt = "0.17.1"
|
||||
@@ -20,20 +20,20 @@ governor = "0.10"
|
||||
hkdf = "0.12"
|
||||
hmac = "0.12"
|
||||
aes-gcm = "0.10"
|
||||
jacquard = { version = "0.9.3", default-features = false, features = ["api", "api_bluesky", "api_full", "derive", "dns"] }
|
||||
jacquard-axum = "0.9.2"
|
||||
jacquard-repo = "0.9.2"
|
||||
jacquard = { version = "0.9.5", default-features = false, features = ["api", "api_bluesky", "api_full", "derive", "dns"] }
|
||||
jacquard-axum = "0.9.6"
|
||||
jacquard-repo = "0.9.6"
|
||||
jsonwebtoken = { version = "10.2.0", features = ["rust_crypto"] }
|
||||
k256 = { version = "0.13.3", features = ["ecdsa", "pem", "pkcs8"] }
|
||||
multibase = "0.9.1"
|
||||
multihash = "0.19.3"
|
||||
rand = "0.8.5"
|
||||
reqwest = { version = "0.12.24", features = ["json"] }
|
||||
reqwest = { version = "0.12.28", features = ["json"] }
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_bytes = "0.11.14"
|
||||
serde_ipld_dagcbor = "0.6.4"
|
||||
ipld-core = "0.4.2"
|
||||
serde_json = "1.0.145"
|
||||
serde_json = "1.0.146"
|
||||
serde_urlencoded = "0.7"
|
||||
sha2 = "0.10.9"
|
||||
subtle = "2.5"
|
||||
@@ -49,21 +49,21 @@ tokio-tungstenite = { version = "0.28.0", features = ["native-tls"] }
|
||||
urlencoding = "2.1"
|
||||
uuid = { version = "1.19.0", features = ["v4", "v5", "fast-rng"] }
|
||||
iroh-car = "0.5.1"
|
||||
image = { version = "0.25", default-features = false, features = ["jpeg", "png", "gif", "webp"] }
|
||||
redis = { version = "0.27", features = ["tokio-comp", "connection-manager"] }
|
||||
tower-http = { version = "0.6", features = ["fs", "cors"] }
|
||||
image = { version = "0.25.9", default-features = false, features = ["jpeg", "png", "gif", "webp"] }
|
||||
redis = { version = "1.0.1", features = ["tokio-comp", "connection-manager"] }
|
||||
tower-http = { version = "0.6.8", features = ["fs", "cors"] }
|
||||
hickory-resolver = { version = "0.24", features = ["tokio-runtime"] }
|
||||
metrics = "0.24"
|
||||
metrics = "0.24.3"
|
||||
metrics-exporter-prometheus = { version = "0.16", default-features = false, features = ["http-listener"] }
|
||||
bs58 = "0.5.1"
|
||||
totp-rs = { version = "5", features = ["qr"] }
|
||||
webauthn-rs = { version = "0.5", features = ["danger-allow-state-serialisation", "danger-user-presence-only-security-keys"] }
|
||||
webauthn-rs = { version = "0.5.4", features = ["danger-allow-state-serialisation", "danger-user-presence-only-security-keys"] }
|
||||
webauthn-rs-proto = "0.5.4"
|
||||
[features]
|
||||
external-infra = []
|
||||
[dev-dependencies]
|
||||
ctor = "0.6.3"
|
||||
testcontainers = "0.26.0"
|
||||
testcontainers = "0.26.2"
|
||||
testcontainers-modules = { version = "0.14.0", features = ["postgres"] }
|
||||
wiremock = "0.6.5"
|
||||
# urlencoding is also in dependencies, but tests use it directly
|
||||
|
||||
@@ -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