ncantu 497bcf0819 Add real service contract for website-skeleton and improve iframe styling
**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)
2026-01-28 17:28:50 +01:00

183 lines
8.3 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Qui êtes-vous ? 4NK un nouveau web</title>
<style>
* { box-sizing: border-box; }
body {
font-family: system-ui, -apple-system, sans-serif;
max-width: 900px;
margin: 0 auto;
padding: 1rem;
line-height: 1.6;
color: #333;
}
h1 { font-size: 1.5rem; margin-bottom: 1rem; color: #222; }
h2 { font-size: 1.2rem; margin-top: 1.5rem; margin-bottom: 0.5rem; color: #333; }
p { margin: 0.75rem 0; }
ul { margin: 0.5rem 0; padding-left: 1.5rem; }
li { margin: 0.4rem 0; }
a { color: #007bff; }
a:hover { text-decoration: underline; }
.highlight { background: #e8f4fd; padding: 1rem; border-radius: 8px; border-left: 4px solid #007bff; margin: 1rem 0; }
.warning { background: #fff3cd; padding: 1rem; border-radius: 8px; border-left: 4px solid #ffc107; margin: 1rem 0; }
details { margin: 1rem 0; }
summary { cursor: pointer; font-weight: 600; color: #555; }
.meta { font-family: ui-monospace, monospace; font-size: 0.85rem; color: #666; background: #f5f5f5; padding: 0.2em 0.4em; border-radius: 4px; word-break: break-all; }
details h3 { font-size: 0.95rem; margin-top: 1rem; margin-bottom: 0.5rem; font-weight: 600; color: #555; }
#user-pairs-info ul { list-style: none; padding-left: 0; }
#user-pairs-info li { background: #f9f9f9; padding: 0.75rem; border-radius: 6px; margin: 0.5rem 0; border: 1px solid #e0e0e0; }
@media (max-width: 768px) {
body { padding: 0.75rem; }
h1 { font-size: 1.25rem; }
}
</style>
</head>
<body>
<h1>Qui êtes-vous ?</h1>
<p><a href="index.html">← Retour à l'accueil</a> · <a href="contrat.html">Voir le contrat</a></p>
<div class="highlight">
<strong>En résumé :</strong> Vous êtes un <strong>membre</strong> qui peut avoir plusieurs appareils (Pairs).
Chaque appareil possède ses propres clés et peut signer selon <strong>vos règles</strong>.
Vos données sont stockées selon les membres du contrat — vous gardez le contrôle total.
</div>
<h2>Vous êtes le « membre connecté »</h2>
<p>
Quand vous vous connectez à ce service, vous devenez un <strong>membre</strong>.
Contrairement aux sites classiques où vos identifiants sont stockés sur un serveur distant,
ici votre identité reste <strong>chez vous</strong>.
</p>
<h2>Un membre = plusieurs appareils</h2>
<p>
Un membre n'est pas limité à un seul appareil. Vous pouvez avoir <strong>plusieurs appareils</strong>
(ordinateur, téléphone, tablette) qui forment ensemble votre identité :
</p>
<ul>
<li>Chaque appareil s'appelle un « <strong>Pair</strong> » (device).</li>
<li>Chaque Pair possède <strong>sa propre paire de clés</strong> cryptographiques.</li>
<li>Tous vos Pairs peuvent signer en votre nom, selon les règles que <strong>vous</strong> définissez.</li>
</ul>
<p>
<em>Exemple :</em> Vous pouvez configurer votre ordinateur principal et votre téléphone comme deux Pairs.
Si l'un est perdu, vous gardez l'accès via l'autre.
</p>
<h2>Vous définissez les règles</h2>
<p>
Chaque membre a un <strong>contrat</strong> qui définit les règles de signature et de validation.
C'est <strong>vous</strong> qui contrôlez ces règles :
</p>
<ul>
<li><strong>Quels Pairs peuvent signer</strong> — vous décidez quels appareils sont autorisés.</li>
<li><strong>Combien de signatures sont requises</strong> — une seule, ou plusieurs pour plus de sécurité.</li>
<li><strong>Pour quelles actions</strong> — certaines actions peuvent nécessiter plus de validations.</li>
</ul>
<div class="highlight">
<strong>Exemple :</strong> Vous pouvez exiger qu'une action sensible (comme un paiement) soit signée
par <strong>2 de vos 3 appareils</strong> — c'est le principe du « multi-signature ».
</div>
<h2>Où sont stockées vos données ?</h2>
<p>
Les données du service sont stockées selon les <strong>membres définis dans le contrat</strong>.
Chaque membre a ses propres données, séparées des autres :
</p>
<ul>
<li><strong>Vos clés privées</strong> — sur vos appareils (Pairs), jamais sur le serveur.</li>
<li><strong>Vos données utilisateur</strong> — associées à votre identité de membre.</li>
<li><strong>Les preuves de signature</strong> — vérifiables publiquement, liées à vos Pairs.</li>
</ul>
<h2>Votre appareil = votre coffre-fort</h2>
<p>
Chaque appareil (Pair) joue le rôle de <strong>coffre-fort numérique</strong> :
</p>
<ul>
<li><strong>Vos clés de sécurité</strong> sont créées directement dans votre navigateur (dans la fenêtre de connexion).</li>
<li><strong>Elles ne quittent jamais votre appareil</strong> — elles sont stockées localement (IndexedDB).</li>
<li><strong>Personne d'autre n'y a accès</strong>, pas même le service.</li>
</ul>
<h2>Comment ça fonctionne ?</h2>
<ol>
<li>Vous cliquez sur « Se connecter ».</li>
<li>Une fenêtre s'ouvre (UserWallet) où vous déverrouillez votre identité.</li>
<li>Votre appareil <strong>signe</strong> une preuve que c'est bien vous (comme une signature manuscrite, mais numérique).</li>
<li>Le service vérifie cette preuve et vous donne accès.</li>
</ol>
<p>
À aucun moment vos clés secrètes ne sont transmises — seule la <strong>preuve</strong> de votre identité l'est.
</p>
<div class="warning">
<strong>Important :</strong> Si vous perdez l'accès à votre appareil (panne, vol, perte),
vous perdez vos clés. Pensez à configurer un second appareil ou une sauvegarde.
</div>
<h2>Quelle différence avec un mot de passe classique ?</h2>
<ul>
<li><strong>Mot de passe classique</strong> : stocké sur le serveur du site → risque de fuite en cas de piratage.</li>
<li><strong>Ici</strong> : vos clés restent sur votre appareil → même si le service est piraté, vos clés sont en sécurité.</li>
</ul>
<details>
<summary>Détails techniques (pour les curieux)</summary>
<ul>
<li>Vos clés utilisent la cryptographie <strong>secp256k1</strong> (la même que Bitcoin).</li>
<li>Elles sont stockées dans <strong>IndexedDB</strong> de votre navigateur.</li>
<li>La connexion utilise l'authentification multi-facteur (<strong>MFA</strong>).</li>
<li>Le service possède son propre portefeuille (wallet) séparé du vôtre, jamais exposé.</li>
</ul>
<h3>Vos Pairs et clés publiques</h3>
<div id="user-pairs-info">
<p><em>Non connecté — connectez-vous pour voir vos Pairs.</em></p>
</div>
</details>
<script>
(function() {
const SESSION_STORAGE_KEY = 'website-skeleton-session';
const container = document.getElementById('user-pairs-info');
if (!container) return;
const stored = sessionStorage.getItem(SESSION_STORAGE_KEY);
if (!stored) return;
try {
const session = JSON.parse(stored);
if (!session || !session.proof || !session.proof.signatures) return;
const signatures = session.proof.signatures;
if (signatures.length === 0) {
container.innerHTML = '<p><em>Aucun Pair enregistré.</em></p>';
return;
}
let html = '<ul>';
signatures.forEach(function(sig, index) {
const pairUuid = sig.pair_uuid || 'Non spécifié';
const pubKey = sig.cle_publique || 'Non disponible';
html += '<li>';
html += '<strong>Pair ' + (index + 1) + '</strong><br>';
html += 'UUID : <span class="meta">' + pairUuid + '</span><br>';
html += 'Clé publique : <span class="meta">' + pubKey + '</span>';
html += '</li>';
});
html += '</ul>';
container.innerHTML = html;
} catch (e) {
// Session parsing error - keep default message
}
})();
</script>
<p><a href="index.html">← Retour à l'accueil</a> · <a href="contrat.html">Voir le contrat</a></p>
</body>
</html>