Page web de partage d'une clé PGP publique.
Find a file
Manu b4fde7529a
All checks were successful
Tests automatisés / Validation et Tests (push) Successful in 6s
Tests automatisés / Build de production (push) Successful in 8s
fix: retrait de la branche develop du on push
2025-11-08 15:06:59 -05:00
.forgejo/workflows fix: retrait de la branche develop du on push 2025-11-08 15:06:59 -05:00
css modif: légère retouche des couleurs 2025-11-06 15:52:40 -05:00
js Correction de l'utilisation de innerHTML 2025-11-06 16:16:45 -05:00
public/keys chore: initialisation complète du projet 2025-10-26 01:58:44 -04:00
test fix: sha1 2025-11-06 22:29:58 -05:00
.gitignore fix: doublon .DS_Store 2025-11-06 14:30:52 -05:00
apple-touch-icon.png ajout: favicon 2025-10-27 22:23:18 -04:00
BUILD.md mise à jour 2025-11-08 00:35:24 -05:00
build.sh fix: Commit source dans le footer (bis) 2025-11-08 01:27:17 -05:00
favicon-96x96.png ajout: favicon 2025-10-27 22:23:18 -04:00
favicon.ico ajout: favicon 2025-10-27 22:23:18 -04:00
favicon.svg ajout: favicon 2025-10-27 22:23:18 -04:00
index.html fix: Commit source dans le footer (bis) 2025-11-08 01:27:17 -05:00
LICENSE ajout de la license 2025-10-26 16:15:24 -04:00
package.json màj: workflow plus solide et rapide 2025-11-06 16:35:15 -05:00
README.md mise à jour de la section Architecture 2025-11-08 02:20:44 -05:00
robots.txt ajout: robots.txt 2025-11-02 16:25:58 -05:00
site.webmanifest complété avec les informations manquantes 2025-11-06 16:12:31 -05:00
web-app-manifest-192x192.png ajout: favicon 2025-10-27 22:23:18 -04:00
web-app-manifest-512x512.png ajout: favicon 2025-10-27 22:23:18 -04:00
WORKFLOW.md mise à jour 2025-11-08 00:35:24 -05:00

Visionneuse de clé PGP publique

Tests automatisés

Une application web moderne, sécurisée et accessible pour afficher et partager votre clé PGP publique.

Demo : https://pgp.manu.quebec

Fonctionnalités

  • 📋 Affichage élégant de la clé PGP au format ASCII
  • 📊 Extraction automatique des métadonnées (ID, empreinte, algorithme, dates, UIDs)
  • 📋 Copie rapide vers le presse-papiers (un clic)
  • 💾 Téléchargement de la clé en fichier .asc
  • 📱 Design responsive optimisé mobile/tablette/desktop
  • 🌓 Mode sombre automatique selon les préférences système
  • Accessible (WCAG 2.1 niveau AA) - lecteurs d'écran, navigation clavier
  • 🔒 Sécurisé - CSP strict, protection XSS, validation des entrées
  • Performant - Zéro dépendance, JavaScript vanilla, fichiers minifiés
  • Tests automatisés - CI/CD avec un job de validation complet
  • 🚀 Déploiement continu - Mise à jour automatique via webhook

📁 Structure du projet

pgp-key-viewer/
├── index.html              # Page principale avec ARIA
├── README.md               # Documentation
├── LICENSE                 # MIT License
├── .gitignore
├── robots.txt              # SEO
│
├── .forgejo/
│   └── workflows/
│       └── tests.yml       # CI/CD (tests + build)
│
├── css/
│   └── styles.css          # Design moderne responsive
│
├── js/
│   ├── main.js             # Orchestration et gestion d'état
│   ├── pgp-parser.js       # Parser OpenPGP (SHA-1, packets)
│   └── utils.js            # Utilitaires (copie, notifications, etc.)
│
└── public/
    └── keys/
        └── public.asc      # Votre clé PGP publique

Branches:
├── main                    # Code source (développement)
└── dist                    # Build de production (minifié)

🚀 Installation rapide

1. Cloner le dépôt

git clone https://code.manu.quebec/manu/pgp-key-viewer.git
cd pgp-key-viewer

2. Ajouter votre clé PGP

# Exporter votre clé (remplacer YOUR_KEY_ID)
gpg --export --armor YOUR_KEY_ID > public/keys/public.asc

# Vérifier le format
head -1 public/keys/public.asc
# Doit afficher: -----BEGIN PGP PUBLIC KEY BLOCK-----

3. Tester localement

# Option 1: Python 3
python3 -m http.server 8000

# Option 2: Node.js (si installé)
npx http-server -p 8000

# Puis ouvrir http://localhost:8000

📦 Déploiement en production

Option 1 : Déploiement automatique (recommandé)

Cette méthode utilise la branche dist (qui contient les fichiers de production) et un webhook pour le déploiement continu.

  1. Clonage initial sur votre serveur :

    # Cloner uniquement la branche 'dist' dans le répertoire de votre site
    git clone -b dist https://code.manu.quebec/manu/pgp-key-viewer.git /srv/pgp-key-viewer
    
  2. Mise à jour automatique :

    Après la configuration d'un webhook (voir ci-dessous), chaque mise à jour de la branche dist sur Forgejo déclenchera automatiquement un git pull sur votre serveur, assurant un déploiement instantané.

Option 2 : Build local

Si vous ne souhaitez pas utiliser le build automatique, vous pouvez construire les fichiers de production localement.

# Installer les outils de minification globalement (une seule fois)
npm install -g html-minifier-terser terser clean-css-cli

# Lancer le build
chmod +x build.sh
./build.sh

# Les fichiers optimisés sont dans le dossier dist/
# Vous pouvez ensuite les téléverser sur votre serveur.
cd dist && python3 -m http.server 8000

Configuration Caddy (Exemple)

Voici un exemple de configuration pour Caddy qui inclut les en-têtes de sécurité, le cache, et la gestion du webhook.

pgp.manu.quebec {
    # Chemin vers les fichiers du site
    root * /srv/pgp-key-viewer
    
    # Gérer le webhook de déploiement
    handle /hooks/* {
        reverse_proxy webhook:9000
    }
    
    # Servir les fichiers statiques
    file_server
    
    # Gérer les erreurs 404
    handle_errors {
        @404 expression {http.error.status_code} == 404
        redir @404 / permanent
    }
    
    # Activer la compression
    encode gzip

    # En-têtes de sécurité
    header {
        Content-Security-Policy "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; base-uri 'self'; form-action 'none'; frame-ancestors 'none'; upgrade-insecure-requests;"
        X-Content-Type-Options "nosniff"
        X-XSS-Protection "1; mode=block"
        X-Frame-Options "DENY"
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        Referrer-Policy "strict-origin-when-cross-origin"
        Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=()"
    }
    
    # Cache pour les ressources statiques (1 an)
    header /css/* /js/* /favicon* /apple-touch-icon* /site.webmanifest Cache-Control "public, max-age=31536000, immutable"
    
    # Pas de cache pour les fichiers dynamiques ou susceptibles de changer
    @nocache {
        path /*.html /public/keys/*
    }
    header @nocache Cache-Control "no-cache, no-store, must-revalidate"
}

🔧 Configuration

Changer le chemin de la clé

Dans js/main.js :

const CONFIG = {
    KEY_PATH: './public/keys/public.asc',  // Modifier ici
    FILENAME: 'public.asc',
    MAX_RETRIES: 3,
    RETRY_DELAY: 1000
};

Personnaliser les couleurs

Dans css/styles.css :

:root {
    --color-primary: #4a6fa5;       /* Couleur principale */
    --color-success: #10b981;       /* Vert succès */
    --color-error: #ef4444;         /* Rouge erreur */
    --color-background: #ffffff;    /* Fond clair */
    /* ... */
}

/* Mode sombre */
@media (prefers-color-scheme: dark) {
    :root {
        --color-background: #0d1117;
        --color-text: #e6edf3;
        /* ... */
    }
}

🧪 Tests automatisés

Le workflow CI/CD s'exécute automatiquement à chaque push sur main.

Jobs du workflow

  1. Validation et Tests (all-tests) : Ce job exécute une série de vérifications en une seule étape :

    • Structure du projet et contenu des fichiers.
    • Syntaxe JavaScript (node -c).
    • Format de la clé PGP et de la documentation.
    • Présence de fonctions de sécurité et de balises d'accessibilité.
    • Tests d'intégration avec npm test.
  2. Build de production (build-production) : S'exécute uniquement si le job all-tests réussit. Il minifie les fichiers HTML, CSS, JS et publie le résultat sur la branche dist. Le commit de build contient le hash du commit source de la branche main.

Voir les résultats : Actions sur Forgejo

Tests locaux

# Syntaxe JavaScript
node -c js/main.js
node -c js/utils.js
node -c js/pgp-parser.js

# Lancer les tests d'intégration
npm test

# Lancer un build de production local
./build.sh

🔒 Sécurité

Protections implémentées

  • Content Security Policy (CSP) strict - Aucun script/style inline
  • Protection XSS - escapeHtml(), textContent uniquement
  • Validation des entrées - Taille de fichiers (1MB max), format hexadécimal
  • Protection contre les boucles infinies - Limite de 1000 paquets OpenPGP
  • Timeout sur requêtes réseau - 10 secondes max avec retry automatique
  • Pas de innerHTML - Utilisation de createElement() et textContent
  • Headers de sécurité - HSTS, X-Frame-Options, X-Content-Type-Options
  • Validation des UIDs - Filtrage des caractères de contrôle, limite de 50 UIDs
  • Pas de localStorage - Aucune donnée persistante

Audit de sécurité

Scores attendus :

  • Mozilla Observatory : A+
  • SecurityHeaders.com : A+
  • OWASP ZAP : Aucune vulnérabilité

Accessibilité

Conformité WCAG 2.1 niveau AA

  • Structure sémantique - HTML5, <main>, <aside>, <time>
  • ARIA - role, aria-label, aria-live, aria-hidden
  • Navigation clavier - Focus visible, ordre logique, pas de piège
  • Lecteurs d'écran - Empreinte lue correctement, notifications annoncées
  • Contraste - Ratio 4.5:1 minimum (mode clair et sombre)
  • Responsive - Zoom 200%, touch targets 48x48px
  • Animations - Respect de prefers-reduced-motion

Tests recommandés

  • NVDA (Windows), VoiceOver (macOS/iOS), JAWS
  • Navigation clavier uniquement
  • Zoom 200%
  • axe DevTools, WAVE

📊 Performance

Optimisations

  • Minification - HTML, CSS, JS réduits de ~40-50%
  • Pas de dépendances - Aucune bibliothèque externe
  • Cache agressif - 1 an pour CSS/JS/assets
  • Compression serveur - gzip/zstd via Caddy
  • Lazy loading - Chargement à la demande

Métriques attendues

  • Lighthouse : 95-100/100 (Performance, Accessibility, Best Practices, SEO)
  • First Contentful Paint : < 1s
  • Time to Interactive : < 2s
  • Taille totale : ~50-80 KB (minifié + gzipped)

🛠️ API JavaScript

Fonctions exposées dans la console :

// Configuration
console.log(pgpViewer.config);

// Récupérer la clé en cache
const key = pgpViewer.getCachedKey();

// Recharger la clé
await pgpViewer.reloadKey();

// Parser manuellement
const metadata = parseKeyMetadata(keyContent);

// Utilitaires
showNotification('Message', 'success', 2000);
await copyToClipboard('texte');
downloadFile('contenu', 'fichier.txt');
escapeHtml('<script>alert("xss")</script>');
formatFingerprint('0123456789ABCDEF...');

🐛 Dépannage

Erreur : Clé non trouvée (404)

# Vérifier le fichier existe
ls -la public/keys/public.asc

# Vérifier les permissions
chmod 644 public/keys/public.asc

# Vérifier le chemin dans le code
grep "KEY_PATH" js/main.js

Erreur : Format de clé invalide

# Vérifier le format
head -1 public/keys/public.asc
tail -1 public/keys/public.asc

# Réexporter proprement
gpg --export --armor YOUR_KEY_ID > public/keys/public.asc

Bouton copier ne fonctionne pas

  • Cause : API Clipboard nécessite HTTPS en production
  • Solution : Utiliser HTTPS (Let's Encrypt avec Caddy)
  • Vérifier la console (F12) pour erreurs

Erreur CSP : Style/Script bloqué

  • Cause : Styles ou scripts inline dans le HTML
  • Solution : Tous les styles doivent être dans styles.css, pas dans style="..."
  • Vérifier qu'aucun innerHTML n'injecte du HTML non échappé

Build échoue : dossier dist/ dans la branche dist

  • Cause : Problème de copie dans le workflow
  • Solution : Déjà corrigé dans le workflow actuel
  • Le dossier dist/ est automatiquement supprimé s'il apparaît

📚 Documentation technique

Architecture

  • Pattern : MVC simplifié (Modèle-Vue-Contrôleur)
    • Contrôleur (main.js) : Orchestre l'application. Il initialise le chargement de la clé, gère les événements utilisateur (clics sur les boutons) et met à jour la vue avec les données du modèle.
    • Modèle (pgp-parser.js) : Responsable de la logique métier. Il contient la logique complexe pour parser le bloc de clé PGP, extraire les métadonnées (ID, empreinte, etc.) et les valider.
    • Vue (index.html + css/styles.css) : La structure sémantique (HTML) et la présentation visuelle (CSS) de l'application. Elle est mise à jour par le contrôleur.
    • Utilitaires (utils.js) : Une bibliothèque de fonctions de support découplées de la logique principale. Elle gère des tâches transversales comme l'affichage des notifications, la copie vers le presse-papiers, le téléchargement de fichiers, et l'échappement de caractères HTML pour la sécurité (XSS).

Format OpenPGP

Le parser implémente :

  • Décodage base64 ASCII armored
  • Parsing des paquets OpenPGP (RFC 4880)
  • Extraction des métadonnées (fingerprint SHA-1, UIDs, dates)
  • Validation du format hexadécimal

Workflow Git

graph TD
    subgraph "CI/CD sur Forgejo"
        A[Push sur main] -- Déclenche --> B{Workflow};
        B -- Job: all-tests --> C{Tests & Validations};
        C -- ✅ Succès --> D[Job: build-production];
        C -- ❌ Échec --> E[Notification d'erreur];
        D -- Push force --> F[Branche 'dist' mise à jour];
    end
    subgraph "Serveur de Production"
        F -- Déclenche --> G{Webhook};
        G -- git pull --> H[Site web mis à jour];
    end

🤝 Contribution

  1. Fork le projet sur Forgejo
  2. Créer une branche : git checkout -b feature/amelioration
  3. Commit : git commit -am 'Ajouter amélioration'
  4. Push : git push origin feature/amelioration
  5. Ouvrir une Pull Request

Guidelines

  • Respecter la structure existante
  • Ajouter des tests pour les nouvelles fonctionnalités
  • Vérifier que tous les tests passent localement
  • Pas de dépendances externes
  • Maintenir la compatibilité accessibilité

📄 License

MIT License - Libre d'utilisation commerciale et personnelle.

Voir le fichier LICENSE pour plus de détails.

🔗 Ressources

📈 Statistiques

  • Lignes de code : ~1500 (HTML + CSS + JS)
  • Taille source : ~100 KB
  • Taille minifiée : ~60 KB
  • Taille gzippée : ~20 KB
  • Compatibilité : Chrome 90+, Firefox 88+, Safari 14+

Statut : Production-ready, sécurisé, accessible