**Motivations:** - website-skeleton needs a real service contract with valid UUIDs and validators - Service wallet required for production use with configurable public key - Iframe styling needs improvement to remove scrollbars and match UserWallet theme **Root causes:** - DEFAULT_VALIDATEURS used placeholder public key that cannot verify signatures - No service wallet generation script for production deployment - Iframe had fixed height causing scrollbars and visual mismatch with dark theme **Correctifs:** - Created real service contract in src/serviceContract.ts with dedicated UUIDs (skeleton-service-uuid-4nkweb-2026) - Added service wallet generation script (generate-service-wallet.mjs) with .env and .env.private files - Improved iframe container styling: increased height (800px), dark background (#1a1a1a), better shadows, hidden scrollbars - Added .env.private to .gitignore for security **Evolutions:** - Service contract automatically loaded on startup and sent to UserWallet iframe - Public key configurable via VITE_SKELETON_SERVICE_PUBLIC_KEY environment variable - Added npm script 'generate-wallet' for easy wallet generation - Enhanced iframe visual integration with UserWallet dark theme **Pages affectées:** - website-skeleton/src/serviceContract.ts (new) - website-skeleton/src/config.ts - website-skeleton/src/main.ts - website-skeleton/generate-service-wallet.mjs (new) - website-skeleton/index.html - website-skeleton/package.json - website-skeleton/.gitignore - website-skeleton/.env (new) - website-skeleton/.env.private (new)
8.1 KiB
website-skeleton
Squelette d'un site qui intègre UserWallet en iframe : écoute des messages postMessage (login-proof, error, contract), vérification des preuves de login via service-login-verify, et affichage du statut (accepté / refusé). Connexion via un seul parcours : « Se connecter » puis authentification MFA dans l'iframe.
Prérequis
- service-login-verify :
npm run builddans../service-login-verifyavant d'installer ou builder le skeleton. - UserWallet : à servir sur l'URL configurée (voir ci‑dessous) pour que l'iframe fonctionne.
Installation
cd website-skeleton
npm install
npm run build
Développement
npm run dev
Ouvre par défaut sur http://localhost:3024. L'iframe pointe vers UserWallet (USERWALLET_ORIGIN).
Configuration
- Origine UserWallet :
src/config.tsdéfinitUSERWALLET_ORIGIN. En dev, défauthttp://localhost:3018(si UserWallet tourne en dev sur ce port). En prod, défauthttps://userwallet.certificator.4nkweb.com. Pour override : variable d'environnementVITE_USERWALLET_ORIGIN(ex.VITE_USERWALLET_ORIGIN=http://localhost:3018 npm run dev). - Contrat de service : Le skeleton a un contrat de service réel défini dans
src/serviceContract.tsavec UUID32b9095a-562d-4239-ae45-2d7ffb1a40de. Le contrat est chargé automatiquement au démarrage et envoyé à l'iframe UserWallet. - Clé publique du service : Configurez
VITE_SKELETON_SERVICE_PUBLIC_KEYavec une clé publique secp256k1 compressée valide (66 hex chars, commençant par 02 ou 03). Exemple :VITE_SKELETON_SERVICE_PUBLIC_KEY=02abc123... npm run dev. Si non configurée, un placeholder est utilisé mais les signatures ne pourront pas être vérifiées. - Validateurs : Les validateurs sont extraits automatiquement du contrat de service skeleton. Le skeleton peut aussi recevoir un contrat personnalisé via
postMessage(typecontract) qui remplacera le contrat par défaut.
Chargement dynamique des contrats
Le skeleton écoute les messages postMessage de type contract pour recevoir le contrat et mettre à jour les validateurs dynamiquement :
// Exemple d'envoi de contrat depuis le parent
window.postMessage({
type: 'contract',
payload: {
contrat: {
uuid: '...',
validateurs: { membres_du_role: [...] },
datajson: { types_names_chiffres: 'contrat' }
},
contrats_fils: [...], // Optionnel
actions: [...] // Optionnel, pour extraire l'action login
}
}, '*');
Le skeleton :
- Reçoit le message
contract - Extrait les validateurs de l'action login (recherche dans
actionspour un type contenant "login") - Met à jour les
allowedPubkeysutilisés pour la vérification - Affiche un statut de confirmation
Le skeleton utilise automatiquement le contrat de service skeleton au démarrage. Si un contrat personnalisé est reçu via postMessage, il remplace le contrat par défaut.
Utilisation
- Lancer UserWallet (dev ou déployé) sur l'URL configurée.
- Lancer le skeleton (
npm run devou servirdist/). - Ouvrir la page du skeleton : l'iframe affiche UserWallet.
- Envoyer contrat (optionnel) : envoyer un message
contractavec le contrat et ses actions pour mettre à jour les validateurs. - Se connecter : cliquer « Se connecter » → envoi du contrat à l'iframe, affichage de l'iframe.
- Login MFA : depuis l'iframe, effectuer le flux de login (MFA) ; à la fin, UserWallet envoie
login-proofau parent. Le skeleton vérifie la preuve (verifyLoginProof) et affiche « Login accepté » ou « Login refusé : … ». - Description du contrat : page
contrat.html(lien depuis l'accueil) décrit le contrat de service skeleton. - Description du membre : page
membre.htmldécrit le membre connecté (l'utilisateur), pas le validateur du service. Clés générées dans l'iframe (UserWallet), stockées en IndexedDB. Distinction créateur du service (wallet .env.private, jamais exposé) vs utilisateur (iframe, IndexedDB).
Exemple d'intégration
Envoi de contrat depuis le parent
// Depuis la page parente qui héberge l'iframe
const iframe = document.getElementById('userwallet');
const userwalletOrigin = 'https://userwallet.example.com';
// Envoyer le contrat avec l'action login
iframe.contentWindow.postMessage({
type: 'contract',
payload: {
contrat: {
uuid: 'contrat-uuid-123',
validateurs: {
membres_du_role: [
{
membre_uuid: 'membre-uuid-456',
signatures_obligatoires: [
{
membre_uuid: 'membre-uuid-456',
cle_publique: '02abc123...', // Clé publique secp256k1
cardinalite_minimale: 1
}
]
}
]
},
datajson: {
types_names_chiffres: 'contrat'
}
},
contrats_fils: [], // Optionnel
actions: [
{
uuid: 'action-login-uuid',
types: {
types_names_chiffres: 'action-login',
types_uuid: ['action-uuid']
},
validateurs_action: {
membres_du_role: [
{
membre_uuid: 'membre-uuid-456',
signatures_obligatoires: [
{
membre_uuid: 'membre-uuid-456',
cle_publique: '02abc123...',
cardinalite_minimale: 1
}
]
}
]
}
}
]
}
}, userwalletOrigin);
Réception et vérification de login-proof
Le skeleton écoute automatiquement les messages login-proof et vérifie la preuve :
// Le skeleton fait automatiquement :
window.addEventListener('message', (event) => {
if (event.data?.type === 'login-proof') {
const result = verifyLoginProof(event.data.payload, {
allowedPubkeys, // Construit depuis les validateurs
nonceCache, // Cache anti-rejeu
timestampWindowMs: 300000 // 5 minutes
});
if (result.accept) {
// Ouvrir la session utilisateur
console.log('Login accepté');
} else {
// Refuser le login
console.error('Login refusé:', result.reason);
}
}
});
Gestion des erreurs
Les raisons de refus possibles :
invalid_proof_structure: Structure de la preuve invalidetimestamp_out_of_window: Timestamp hors fenêtre (défaut ±5 min)nonce_reused: Nonce déjà utilisé (anti-rejeu)validators_not_verifiable: Aucune clé publique dans les validateursno_validator_signature: Aucune signature valide de validateurssignature_cle_publique_not_authorized: Signature avec clé non autorisée
Structure
index.html: page avec iframe, liens « Description du contrat » / « Description du membre », bouton « Se connecter ».src/main.ts: chargement de l'iframe, écoutemessage, envoi du contrat au clic « Se connecter », appel àverifyLoginProof, gestion des messagescontract.contrat.html: page de description du contrat de service skeleton (labels, UUIDs, usage).membre.html: page de description du membre connecté (utilisateur) et de son device (Pair) ; clés iframe / IndexedDB. Distinction service (.env.private) vs utilisateur.src/config.ts:USERWALLET_ORIGIN,DEFAULT_VALIDATEURS(extraits du contrat skeleton), typesContratetAction.src/serviceContract.ts: contrat de service skeleton avec UUID dédié, action login, et configuration de la clé publique viaVITE_SKELETON_SERVICE_PUBLIC_KEY.src/contract.ts: extraction des validateurs depuis les contrats (extractLoginValidators), validation de structure (isValidContract,isValidAction).
Déploiement
- Production :
https://skeleton.certificator.4nkweb.com(proxy → 192.168.1.105:3024). - Installation :
./install-website-skeleton.shsur le backend, puis./update-proxy-nginx.shpour proxy + certificat. Voirdocs/WEBSITE_SKELETON.md.
Références
docs/WEBSITE_SKELETON.md(documentation détaillée)features/service-login-verify.mdfeatures/userwallet-contrat-login-reste-a-faire.md(§ 3.7)userwallet/(iframe)service-login-verify/(vérification)