Security checks
PWA de fidélité pour commerces, 100% offline, sans backend, sans compte. Deux modes : Commerçant (gestion des cartes et scan client) et Client (QR code personnel).
npx -y skills add chawkitariq/fidely --skill security-checksAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Checklist sécurité et RGPD avant tout commit ou ajout de feature dans Fidely. Déclencher quand : commit, ajout formulaire, manipulation IndexedDB/localStorage, scan QR, ajout dépendance, accès caméra, affichage HTML dynamique. Mots-clés : secret, API key, UUID, RGPD, données personnelles, localStorage, IndexedDB, v-html, html5-qrcode, validation input, .env, gitignore, pnpm audit.
SKILL.md
6.2 KB, as published. Nobody here has run it
Skill : Vérifications sécurité
Avant tout commit ou ajout de fonctionnalité, passer en revue ces points.
Ressources disponibles
reference/storage-map.md— carte complète du stockage Fidely (IndexedDB + localStorage)
Checklist rapide
[ ] Aucune clé API, token ou secret dans le code
[ ] Aucune donnée personnelle collectée (UUID anonymes uniquement)
[ ] localStorage/IndexedDB : utilisés correctement (client-only)
[ ] Inputs utilisateur : validés avant traitement
[ ] Dépendances tierces : versions non deprecated/vulnérables
[ ] Fichiers sensibles exclus du commit (.env, clés, etc.)
1. Données sensibles dans le code
Interdit dans tout fichier commité :
❌ const API_KEY = 'sk-abc123...'
❌ const WEBHOOK_SECRET = 'whsec_...'
❌ password: 'monmotdepasse'
❌ Authorization: 'Bearer hardcoded-token'
Ce projet n'a pas de backend actuellement — aucune clé API n'est nécessaire pour le MVP.
Si une API externe est ajoutée, les variables d'env doivent passer par nuxt.config.ts :
runtimeConfig: {
// Côté serveur uniquement (jamais exposé au client)
apiSecret: process.env.API_SECRET,
public: {
// Côté client (visible dans le bundle !)
apiBase: process.env.NUXT_PUBLIC_API_BASE
}
}
Et utilisées via :
const config = useRuntimeConfig()
// Serveur : config.apiSecret
// Client : config.public.apiBase
2. Données personnelles (RGPD)
Ce projet est conçu RGPD by design :
- Les clients sont identifiés par des UUID anonymes générés localement
- Aucun email, nom, téléphone n'est collecté ou stocké
- Toutes les données restent dans le navigateur de l'utilisateur
Ne pas introduire de champs de formulaire demandant des données personnelles sans discussion.
Si une fonctionnalité de compte utilisateur est ajoutée, prévoir une politique de confidentialité.
3. Sécurité du stockage local
localStorage — uniquement fidely_mode (préférence UI) :
- Donnée non sensible — préférence d'affichage uniquement
- Ne jamais y stocker de tokens, secrets, ou données métier
- ⚠️ Ne pas y stocker
client_id— c'est dans IndexedDB
IndexedDB (fidely DB, version 2) :
| Object store | Contenu | Clé |
|---|---|---|
cards | Cartes de fidélité (title, reward_points, reward) | id (UUID v7) |
clients | Points par client ({ cards: Record<string, number> }) | UUID client |
config | Paramètres app dont client_id | string key |
client_idest dans IndexedDBconfigstore — stable et immuable- Ne jamais y stocker de données de paiement, mots de passe, ni PII
4. Validation des inputs utilisateur
Dans merchant.vue, les inputs du formulaire de carte sont validés côté client :
function validate(s: typeof state) {
const errors = []
if (!s.title.trim()) errors.push({ name: 'title', message: 'Champ requis' })
if (!s.reward_points || s.reward_points < 1) errors.push({ name: 'reward_points', message: 'Minimum 1' })
if (!s.reward.trim()) errors.push({ name: 'reward', message: 'Champ requis' })
return errors
}
Règles à toujours respecter pour les nouveaux inputs :
.trim()sur tous les champs texte avant de les stocker- Valider les bornes numériques (min/max)
- Sanitiser avant d'afficher dans le DOM (Vue le fait automatiquement via
{{ }}) - Ne jamais utiliser
v-htmlavec du contenu utilisateur
Validation du QR code scanné :
// Valider le format UUID avant de naviguer
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(text)) {
navigateTo(`/client/${text}`)
}
5. Dépendances tierces
Vérifier avant d'ajouter une dépendance :
pnpm audit # Vulnérabilités connues
pnpm outdated # Versions obsolètes
Dépendances à surveiller (accès caméra / DOM bas niveau) :
html5-qrcode2.3.8 — accès caméra, maintenir à jourqrcode1.5.4 — génération côté client, faible risque
6. Sécurité spécifique au scan QR
Le scanner html5-qrcode lit tout QR code — un QR code malveillant pourrait contenir :
- Une URL (ne pas ouvrir automatiquement)
- Du texte arbitraire (ne pas l'afficher dans
v-html) - Une fausse UUID (valider le format avant navigateTo)
Protection en place dans scan.vue :
// Seul un UUID valide déclenche la navigation
if (/^[0-9a-f]{8}-...-[0-9a-f]{12}$/i.test(trimmed)) {
scanned.value = true // empêche le double-scan
await navigateTo(`/client/${trimmed}`)
}
7. Fichiers à ne jamais commiter
# Déjà exclus dans .gitignore
.env
.env.*
!.env.example
.nuxt/
node_modules/
dist/
Vérifier avant git add :
git status # Aucun .env dans les fichiers modifiés
git diff --cached # Revue du diff avant commit
8. Si des API routes SSR sont ajoutées (futur)
Si le projet évolue vers un backend Nuxt (server/api/), ajouter systématiquement :
// server/api/endpoint.post.ts
export default defineEventHandler(async (event) => {
// 1. Lire et valider le body
const body = await readBody(event)
// 2. Valider avec zod ou manuellement
if (!body.clientId || typeof body.clientId !== 'string') {
throw createError({ statusCode: 400, message: 'clientId requis' })
}
// 3. Ne jamais retourner d'erreurs système raw
try {
// logique
}
catch {
throw createError({ statusCode: 500, message: 'Erreur interne' })
}
})
Confirmation en fin de vérification
✅ security-checks passé
- Secrets : [aucun secret en dur]
- RGPD : [aucune PII collectée / stockée]
- Stockage : [client_id dans IndexedDB, mode dans localStorage uniquement]
- Inputs : [validation Zod + trim en place]
- QR scan : [UUID validé par regex avant navigateTo]
- Dépendances : [pnpm audit → 0 vulnérabilité critique]