Page web de partage d'une clé PGP publique.
Find a file
Manu 19ed3f35bc
All checks were successful
tests-automated / Validation et Tests (push) Successful in 18s
tests-automated / Build de production (push) Successful in 16s
docs: mettre à jour l'exemple de config Caddy dans le README
Ajout de 'manifest-src \'self\'' à l'exemple de CSP dans la configuration Caddy.
2026-01-07 00:27:45 -05:00
.forgejo/workflows ci: adaptation du workflow Forgejo pour les nouvelles mesures de sécurité PGP 2026-01-03 17:20:41 -05:00
conductor fix(ci): formatage après archivage de piste 2025-12-24 08:44:28 -05:00
css Style : corriger le formatage pour le workflow (centrage crochet) 2026-01-04 20:18:07 -05:00
js UI : remplacer les notifications de copie par un crochet vert fluo sur le bouton 2026-01-04 19:48:47 -05:00
public mise à jour de robots.txt 2026-01-03 00:24:51 -05:00
test sécurité: renforcement du parseur PGP contre les vulnérabilités de type forgery et injection 2026-01-03 17:18:47 -05:00
.gitignore ajout de .gemini/ 2025-12-26 16:24:19 -05:00
.prettierignore fix(ci): corriger les problèmes de formatage et ignorer le dossier coverage 2025-12-23 17:20:22 -05:00
.prettierrc ci: intégration du linting et formatage automatique 2025-11-20 20:23:48 -05:00
BUILD.md Examen complet du projet : audit de sécurité, mise à jour des dépendances, optimisation du workflow Forgejo et mise à jour de la documentation. 2025-12-18 08:18:48 -05:00
build.sh Build & Doc : renforcer le cache busting et corriger l'exemple Caddy 2026-01-04 20:07:33 -05:00
deploy.sh security: correction des vulnérabilités d'injection dans les scripts de build et de déploiement 2025-12-22 17:04:20 -05:00
eslint.config.js fix(ci): corriger les problèmes de formatage et ignorer le dossier coverage 2025-12-23 17:20:22 -05:00
GEMINI.md docs: mettre à jour le journal de maintenance 2026-01-07 00:27:36 -05:00
index.html fix: corriger le blocage du manifeste par la CSP 2026-01-07 00:27:20 -05:00
LICENSE ajout de la license 2025-10-26 16:15:24 -04:00
package-lock.json maintenance : mise à jour mineure des dépendances de développement 2026-01-03 17:29:33 -05:00
package.json docs: traduction de la description du paquet en français 2026-01-01 17:13:38 -05:00
README.md docs: mettre à jour l'exemple de config Caddy dans le README 2026-01-07 00:27:45 -05:00
vitest.config.js Mise à jour globale : audit de sécurité (0 faille), montée de version Node.js (22 LTS) dans le workflow, mise à jour des dépendances et nettoyage des configurations de test. 2025-12-20 08:42:53 -05:00
WORKFLOW.md Examen complet du projet : audit de sécurité, mise à jour des dépendances, optimisation du workflow Forgejo et mise à jour de la documentation. 2025-12-18 08:18:48 -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 dépendances localement
npm install

# Lancer le build
npm run build

# 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'; manifest-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)
    # Le cache busting (?v=hash) assure le rafraîchissement lors des mises à jour
    header /css/* /js/* /favicon* /apple-touch-icon* /site.webmanifest Cache-Control "public, max-age=31536000, immutable"

    # Pas de cache pour les fichiers d'entrée pour garantir que le navigateur voit les nouveaux liens
    @nocache {
        path / /index.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).
    • Qualité du code (npm run lint et npm run format:check).
    • 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 via le script deploy.sh. 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

# Vérifier la qualité du code (Lint & Format)
npm run lint
npm run format:check

# 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 inline (même pour le thème)
  • 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');

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, Lint & Format};
        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+

Dernière revue complète de sécurité et mise à jour des dépendances : 7 janvier 2026.