forked from yvv/decision
Auth Duniter v2 : vérification réelle + extension signing + titres outils
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Backend :
- Vérification Sr25519/Ed25519 réelle via substrateinterface (bypass démo)
- Message signé : <Bytes>{challenge}</Bytes> (convention polkadot.js)
- DEV_PROFILES : Charlie → Référent structure, Dave → Auteur (WoT member)
Frontend :
- Signing via extension polkadot.js / Cesium2 (_signWithExtension)
- @polkadot/extension-dapp + @polkadot/util installés
- Vite : global=globalThis + optimizeDeps pour les packages polkadot
- Boîte à outils : titres complets des 4 sections
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -45,15 +45,15 @@ DEV_PROFILES = [
|
||||
},
|
||||
{
|
||||
"address": "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmkP7j4bJa3zN7d8tY",
|
||||
"display_name": "Charlie (Comite Tech)",
|
||||
"display_name": "Charlie (Référent structure)",
|
||||
"wot_status": "member",
|
||||
"is_smith": True,
|
||||
"is_techcomm": True,
|
||||
},
|
||||
{
|
||||
"address": "5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy",
|
||||
"display_name": "Dave (Observateur)",
|
||||
"wot_status": "unknown",
|
||||
"display_name": "Dave (Auteur)",
|
||||
"wot_status": "member",
|
||||
"is_smith": False,
|
||||
"is_techcomm": False,
|
||||
},
|
||||
@@ -132,15 +132,40 @@ async def verify_challenge(
|
||||
detail="Challenge invalide",
|
||||
)
|
||||
|
||||
# 4. Verify Ed25519 signature
|
||||
# TODO: Implement actual Ed25519 verification using substrate-interface
|
||||
# For now we accept any signature to allow development/testing.
|
||||
# In production this MUST verify: verify(address_pubkey, challenge_bytes, signature_bytes)
|
||||
#
|
||||
# from substrateinterface import Keypair
|
||||
# keypair = Keypair(ss58_address=payload.address)
|
||||
# if not keypair.verify(payload.challenge.encode(), bytes.fromhex(payload.signature)):
|
||||
# raise HTTPException(status_code=401, detail="Signature invalide")
|
||||
# 4. Verify signature (bypass for demo profiles in DEMO_MODE)
|
||||
_demo_addresses = {p["address"] for p in DEV_PROFILES}
|
||||
is_demo_bypass = settings.DEMO_MODE and payload.address in _demo_addresses
|
||||
|
||||
if not is_demo_bypass:
|
||||
# polkadot.js / Cesium2 signRaw(type='bytes') wraps: <Bytes>{challenge}</Bytes>
|
||||
message = f"<Bytes>{payload.challenge}</Bytes>".encode("utf-8")
|
||||
sig_hex = payload.signature.removeprefix("0x")
|
||||
try:
|
||||
sig_bytes = bytes.fromhex(sig_hex)
|
||||
except ValueError:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Format de signature invalide (hex attendu)",
|
||||
)
|
||||
|
||||
from substrateinterface import Keypair, KeypairType
|
||||
|
||||
verified = False
|
||||
# Try Sr25519 first (default Substrate/Cesium2), then Ed25519 (Duniter v1 migration)
|
||||
for key_type in [KeypairType.SR25519, KeypairType.ED25519]:
|
||||
try:
|
||||
kp = Keypair(ss58_address=payload.address, crypto_type=key_type)
|
||||
if kp.verify(message, sig_bytes):
|
||||
verified = True
|
||||
break
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if not verified:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Signature invalide",
|
||||
)
|
||||
|
||||
# 5. Consume the challenge
|
||||
del _pending_challenges[payload.address]
|
||||
|
||||
Reference in New Issue
Block a user