ÉDITION AUTOMATIQUE · LECTURE DU CODE
L’architecture en mouvement.
Un suivi sourcé des commits, des dépendances et des mentions de protocoles. Ce rapport décrit le code, pas les déploiements.
Intervalle : 7e129f44 → 8fed8991. Généré le 2026-11-07T12:07:19+00:00.
Mentions dans les lignes ajoutées et dépendances Cargo directes ; aucun test exécuté, aucun état de déploiement déduit. Source locale uniquement.
Journal des changements
- 8fed8991 Tu es l'Architecte Principal et Lead Product Engineer d'ASTROPORT.ONE, un écosystème logiciel souverain, décentralisé et sans tiers de confiance, propulsé par le démon tout-en-un écrit en Rust : `astroportd`.
- aa7cd4d1 0.5.5-beta : robustesse, arrivée du Capitaine, liens d'accueil, station marraine
- 63db1b5d 0.5.4-beta : Personnes et Contacts réunis, visio sans tiers, traductions par écran
Architecture : dépendances directes
Relations extraites des sections [dependencies] des Cargo.toml. Une dépendance de compilation ne prouve pas un flux réseau.
| Module | Fichiers modifiés | Dépend de |
|---|---|---|
| astro-bro | 0 | astro-core, astro-crypto, astro-db, astro-nostr-proto |
| astro-core | 1 | — |
| astro-crypto | 1 | astro-nostr-proto |
| astro-dav | 0 | astro-crypto, astro-db, astro-nostr-proto |
| astro-db | 2 | astro-crypto, astro-nostr-proto |
| astro-duniter | 2 | astro-core, astro-g1-runtime |
| astro-economy | 0 | astro-core, astro-db, astro-nostr-proto |
| astro-facecloud | 5 | astro-crypto, astro-dav, astro-db, astro-nostr-proto |
| astro-g1-runtime | 0 | — |
| astro-lifecycle | 0 | astro-core, astro-crypto, astro-db, astro-nostr-proto |
| astro-nostr-proto | 1 | — |
| astro-p2p | 0 | astro-dav |
| astro-plugins | 0 | — |
| astro-relay | 0 | astro-db, astro-nostr-proto |
| astro-sync | 0 | astro-crypto, astro-dav, astro-db, astro-facecloud, astro-nostr-proto |
| astro-ui | 42 | astro-core, astro-db |
Protocoles : mentions nouvelles ou modifiées
La présence d’un nom dans le diff ne prouve ni conformité ni fonctionnalité livrée. Les citations sont des données du dépôt, pas des instructions.
- Nostr — CLAUDE.md:84
1. **Nostr + IPFS sont les SEULES sources de vérité :**
- IPFS — CLAUDE.md:84
1. **Nostr + IPFS sont les SEULES sources de vérité :**
- Nostr — CLAUDE.md:89
- Racine Capitaine : Clé SSH `~/.ssh/id_ed25519` → SHA-512 → Salt/Pepper → Scrypt → Graine Ed25519 maîtresse (PeerID IPFS 12D3Koo = Ğ1 = Nostr secp256k1 via SHA-256).
- IPFS — CLAUDE.md:89
- Racine Capitaine : Clé SSH `~/.ssh/id_ed25519` → SHA-512 → Salt/Pepper → Scrypt → Graine Ed25519 maîtresse (PeerID IPFS 12D3Koo = Ğ1 = Nostr secp256k1 via SHA-256).
- Nostr — CLAUDE.md:91
- Tolérance aux pannes : Partage de secret de Shamir SSSS 2-sur-3 (Part 1 QR imprimé, Part 2 station locale, Part 3 amis N¹ via NIP-59).
- IPFS — CLAUDE.md:94
- `ẐEN` (Production coopérative privée) : `UPLANETNAME` = SHA-256(swarm.key). 1 Ẑen = 1 €/$/£... Kubo strictement interdit (libp2p PSK isolé).
- UENC — CLAUDE.md:96
5. **Format Chiffré uCloud UENC v2 :**
- Nostr — CLAUDE.md:101
### 2. PROTOCOLE NOSTR & PARE-FEU SOCIAL (TIERED GATED RELAY)
- WebDAV — CLAUDE.md:103
- Le relais interne WebSocket et l'API HTTP/WebDAV/CardDAV/CalDAV partagent le **même port unique** (pas de multi-ports complexes).
- CardDAV — CLAUDE.md:103
- Le relais interne WebSocket et l'API HTTP/WebDAV/CardDAV/CalDAV partagent le **même port unique** (pas de multi-ports complexes).
- CalDAV — CLAUDE.md:103
- Le relais interne WebSocket et l'API HTTP/WebDAV/CardDAV/CalDAV partagent le **même port unique** (pas de multi-ports complexes).
- Nostr — CLAUDE.md:104
- Authentification NIP-42 systématique sur WebSocket et NIP-98 sur les requêtes HTTP d'API.
- Nostr — CLAUDE.md:107
- Cercle N¹ (Amis réciproques dans kind 3) : Kinds 21/22 (Vidéos en copie privée avec tag NIP-70 `["-"]`), réplication automatique FaceCloud, sauvegarde de la Part 3 Shamir.
- Nostr — CLAUDE.md:108
- Écriture réservée aux membres du cercle social ($N^1 \cup N^2$), **sauf** pour le kind 1059 (Gift Wrap NIP-59) ciblant un compte hébergé qui est TOUJOURS admis sans auth préalable (porte d'entrée réseau).
- Nostr — RELEASE_NOTES.md:42
- Signalisation chiffrée comme un message privé (NIP-59, enveloppe qui expire) ; seul un proche fait sonner.
- Nostr — RELEASE_NOTES.md:44
- **Présence** sur option (Mon compte → Visio) : vos amis réciproques voient « en ligne » ou « en appel » ; battements NIP-101 (kind 24315) vers les autres stations ; rien n'est stocké.
- Nostr — RELEASE_NOTES.md:49
- Jargon retiré des écrans des membres (NIP-65, kind 0, NIP-05) ; l'index A–Z du carnet ne masque plus la liste sur téléphone.
- Nostr — crates/astro-crypto/src/nip59.rs:97
/// Comme [`gift_wrap`], mais l'enveloppe porte une expiration (NIP-40) : le relai l'oublie passé `expires_at`. Pour les
- Nostr — crates/astro-crypto/src/nip59.rs:102
pub fn gift_wrap_expiring(sender_secret: &[u8; 32], recipient_hex: &str, rumor: &Rumor, now: u64, expires_at: u64) -> Result<Event, Nip59Error> { - Nostr — crates/astro-crypto/src/nip59.rs:106
fn wrap_with(sender_secret: &[u8; 32], recipient_hex: &str, rumor: &Rumor, now: u64, expires_at: Option<u64>) -> Result<Event, Nip59Error> { - IPFS — crates/astro-crypto/src/nip59.rs:179
for marker in [&b"ipfs"[..], b"bafkrei", b"\"cid\""] { - Nostr — crates/astro-facecloud/src/review.rs:46
/// Range des visages dans une personne : ils prennent `name`, la fiche `contact` (UID vCard) et la clé Nostr de la personne.
- Nostr — crates/astro-nostr-proto/src/lib.rs:54
/// Signal d'appel visio (offre, réponse, raccrochage…) : **rumeur privée** emballée en NIP-59, jamais publiée en clair.
- Nostr — crates/astro-ui/src/api.rs:1395
/// Où ranger des visages : une fiche choisie, ou un nom (et la clé Nostr de la personne, si elle est connue).
- Nostr — crates/astro-ui/src/api.rs:1400
/// Clé Nostr (64 hex, minuscules).
- Nostr — docs/GUIDE.md:488
**Rapprochement photo ↔ fiche ↔ MULTIPASS.** Une fiche relie un visage à un MULTIPASS de deux façons : la fiche porte une clé Nostr (`X-NOSTR-PUBKEY` ou `X-NOSTR-NPUB`, en hexadécimal ou `npub1…`), ou son email est celui
- Nostr — src/address_book.rs:177
/// Lignes de l'index : chemin, champs, me, clé Nostr, lien, avertissement, UID.
- WebRTC — src/chat.rs:11
//! - **Appels visio** : la sonnerie et la poignée de main WebRTC (offre, réponse, raccrochage, refus, occupé) voyagent par le
- Nostr — src/chat.rs:449
let rumor = nip59::Rumor { pubkey: owner.to_owned(), created_at: created, kind: kind::CALL_SIGNAL, tags: vec![vec!["p".into(), peer.clone()]], content: content.to_string() }; - Nostr — src/chat.rs:451
let wrap = nip59::gift_wrap_expiring(&secret, &peer, &rumor, created, created + CALL_TTL).map_err(|e| ChatError::Invalid(e.to_string()))?;
- Nostr — src/chat.rs:466
async fn handle_call(&self, owner: &str, sender: &str, rumor: &nip59::Rumor) -> usize { - Nostr — src/chat.rs:528
/// Nom à montrer pour `peer` : sa fiche de contact, sinon son profil Nostr, sinon le début de sa clé.
- Nostr — src/chat.rs:536
"SELECT COALESCE((SELECT json_extract(f.fields, '$.name') FROM contact_cards f WHERE f.owner_hex = ?1 AND json_extract(f.fields, '$.nostr') = ?2 LIMIT 1), \
- Nostr — src/chat.rs:590
/// Boucle de réception jusqu'à l'arrêt. Une enveloppe NIP-59 acceptée par le relai réveille la lecture **tout de suite** :
- Duniter — src/constellation.rs:41
/// Numéro du bloc ; négatif pour l'historique de la Ğ1 v1 repris à la genèse de Duniter v2s.
- CardDAV — src/identity_links.rs:189
if let Err(e) = ingest::replace(&self.dav, owner, carddav::CONTACTS_DIR, &file, Some("text/vcard"), std::io::Cursor::new(vcard::set_property(text, "UID", Some(&uid), now()).into_bytes())).await { - Nostr — src/identity_links.rs:297
/// Relie les visages à leur fiche par la clé Nostr (une seule fiche pour cette clé ; vos propres visages à « Ma fiche »),
- IPFS — src/init.rs:404
// Un uCloud repris d'Astroport.ONE (import-ucloud) n'a ses blobs que dans IPFS : sans --kubo, il devient illisible.
- Nostr — src/presence.rs:1
//! Présence visio (« en ligne », « en appel ») entre amis mutuels, **sur option** (NIP-101, kind 24315).
- Nostr — src/presence.rs:4
//! choisi d'être joignable (paramètre 31903 `d=visio`, `{"reachable": true}` : une option du membre vit dans Nostr, pas sur - Nostr — src/presence.rs:25
/// Statuts reconnus (NIP-101).
- Nostr — src/register.rs:546
let r = Registrar::new(db.clone(), dir.join("nostr"), "0".repeat(64), Arc::new(|hex| format!("jeton-{}", &hex[..8])), Limits::default()).require_captain(); - Nostr — src/register.rs:550
assert!(!dir.join("nostr").exists(), "rien n'est créé"); - IPFS — src/serve.rs:467
let msg = format!("{n} fichier(s) de l'uCloud repris d'Astroport.ONE ne sont que dans IPFS : sans --kubo (ex. --kubo http://127.0.0.1:5001) ils restent illisibles (fiches, photos, miniatures)"); - Nostr — src/serve.rs:878
println!("chat : conversations privées 1 à 1 (NIP-17), réception dès l'arrivée (contrôle toutes les 3 s) ; présence visio sur option"); - Nostr — src/sponsor.rs:4
//! son relai, et en ẐEN la `swarm.key`. L'offre est chiffrée (NIP-44 v2) avec une clé tirée pour l'occasion, puis
- Nostr — src/sponsor.rs:44
/// Relai Nostr de la marraine (`wss://…`).
- Nostr — src/sponsor.rs:90
let sealed = astro_crypto::nip44::encrypt(&key, &plain).map_err(|e| format!("chiffrement : {e}"))?; - Nostr — src/sponsor.rs:119
let plain = Zeroizing::new(astro_crypto::nip44::decrypt(&token.key, sealed).map_err(|_| "offre indéchiffrable : le jeton ne correspond pas".to_owned())?);
- Nostr — src/ui_backend.rs:962
// La fiche reliée donne aussitôt sa clé Nostr aux visages (et partage leurs photos, amis réciproques).
- Nostr — tests/chat.rs:226
let old = astro_crypto::nip59::Rumor { pubkey: alice.clone(), created_at: 1_700_000_000, kind: astro_nostr_proto::kind::CALL_SIGNAL, tags: vec![vec!["p".into(), bob.clone()]], content: json!({ "type": "offer", "call" - Nostr — tests/chat.rs:227
let wrap = astro_crypto::nip59::gift_wrap(&ALICE, &bob, &old, 1_700_000_000).unwrap();
- Nostr — tests/chat.rs:307
evs.iter().filter_map(|w| astro_crypto::nip59::unwrap(&EVE, w).ok()).map(|o| serde_json::from_str::<serde_json::Value>(&o.rumor.content).unwrap()).find(|v| v["call"] == call).unwrap()
- Nostr — tests/chat.rs:388
// Un autre kind ne réveille pas ; une enveloppe NIP-59, si.
- CardDAV — tests/identity_links.rs:212
let text = String::from_utf8(astro_dav::carddav::read_file(&b.dav, &alice, "/Contacts/marie1.vcf").await.unwrap()).unwrap();
- CardDAV — tests/identity_links.rs:238
let text = String::from_utf8(astro_dav::carddav::read_file(&b.dav, &alice, "/Contacts/marie2.vcf").await.unwrap()).unwrap();
- Nostr — tests/presence.rs:102
async fn a_remote_mutual_friend_receives_a_nip101_heartbeat_and_only_while_reachable() { - Nostr — tests/presence.rs:115
assert_eq!(ev.tags, vec![vec!["p".to_owned(), carol.clone()], vec!["status".to_owned(), "online".to_owned()]], "format NIP-101 : destinataires, puis un statut");
- Nostr — tests/ui_e2e.rs:1372
let registrar = Arc::new(astroportd::register::Registrar::new(db.clone(), dir.join("game/nostr"), "0".repeat(64), Arc::new(|hex| derive_dav_token(SECRET, hex)), astroportd::register::Limits::default()).require_captai - Nostr — tests/ui_e2e.rs:1514
let registrar = Arc::new(astroportd::register::Registrar::new(b.db.clone(), b.dir.join("nostr"), "0".repeat(64), Arc::new(|hex| derive_dav_token(SECRET, hex)), astroportd::register::Limits::default()));
Fichiers de l’intervalle
MCLAUDE.mdMCargo.lockMCargo.tomlMREADME.mdMRELEASE_NOTES.mdMcrates/astro-core/src/activity.rsMcrates/astro-crypto/src/nip59.rsMcrates/astro-db/src/lib.rsMcrates/astro-db/src/schema.sqlMcrates/astro-duniter/src/chain.rsMcrates/astro-duniter/src/pool.rsMcrates/astro-facecloud/src/board.rsMcrates/astro-facecloud/src/pipeline.rsMcrates/astro-facecloud/src/review.rsMcrates/astro-facecloud/tests/board.rsMcrates/astro-facecloud/tests/facecloud.rsMcrates/astro-nostr-proto/src/lib.rsMcrates/astro-ui/Cargo.tomlMcrates/astro-ui/src/api.rsMcrates/astro-ui/src/web.rsMcrates/astro-ui/tests/cockpit_rules.mjsAcrates/astro-ui/tests/lang_parts.mjsMcrates/astro-ui/web/app.jsMcrates/astro-ui/web/index.htmlMcrates/astro-ui/web/m-account.jsMcrates/astro-ui/web/m-book.cssAcrates/astro-ui/web/m-call.cssAcrates/astro-ui/web/m-call.jsMcrates/astro-ui/web/m-card.jsMcrates/astro-ui/web/m-chat.cssMcrates/astro-ui/web/m-chat.jsMcrates/astro-ui/web/m-cockpit.cssMcrates/astro-ui/web/m-cockpit.jsMcrates/astro-ui/web/m-contacts.jsMcrates/astro-ui/web/m-coop.jsAcrates/astro-ui/web/m-framed.cssAcrates/astro-ui/web/m-framed.jsMcrates/astro-ui/web/m-home.jsAcrates/astro-ui/web/m-lang-en-account.jsAcrates/astro-ui/web/m-lang-en-billets.jsAcrates/astro-ui/web/m-lang-en-call.jsAcrates/astro-ui/web/m-lang-en-contacts.jsAcrates/astro-ui/web/m-lang-en-options.jsAcrates/astro-ui/web/m-lang-en-sync.jsMcrates/astro-ui/web/m-lang-en.jsAcrates/astro-ui/web/m-lang-es-account.jsAcrates/astro-ui/web/m-lang-es-billets.jsAcrates/astro-ui/web/m-lang-es-call.jsAcrates/astro-ui/web/m-lang-es-contacts.jsAcrates/astro-ui/web/m-lang-es-options.jsAcrates/astro-ui/web/m-lang-es-sync.jsMcrates/astro-ui/web/m-lang-es.jsMcrates/astro-ui/web/m-library.jsMcrates/astro-ui/web/m-people.cssMcrates/astro-ui/web/m-people.jsAcrates/astro-ui/web/m-review.jsAcrates/astro-ui/web/m-who.jsMcrates/astro-ui/web/register.htmlMcrates/astro-ui/web/register.jsMdocs/GUIDE.mdMdocs/index.htmlAexamples/turn_relay.rsMinstall.shMsrc/address_book.rsMsrc/billet.rsMsrc/chat.rsMsrc/constellation.rsMsrc/coop_config.rsAsrc/first_run.rsMsrc/hosting_fee.rsMsrc/identity_links.rsMsrc/init.rsMsrc/invites.rsMsrc/legacy_ucloud.rsMsrc/lib.rsMsrc/main.rsAsrc/presence.rsMsrc/primal_init.rsMsrc/register.rsMsrc/serve.rsMsrc/settlement.rsAsrc/sponsor.rsMsrc/station.rsAsrc/station_domain.rsAsrc/stun.rsAsrc/turn.rsMsrc/ui_backend.rsAsrc/welcome.rsMsrc/zen_react.rsMtests/address_book.rsMtests/chat.rsMtests/identity_links.rsAtests/presence.rsAtests/stun.rsAtests/turn.rsMtests/ui_e2e.rs