Centre de confidentialité
Extension payante. Conservation, recherche, export, effacement et journal inaltérable, pour les données que vos formulaires détiennent.
Ce document décrit ce que le module garantit et ce qu’il refuse. Le guide utilisateur en donne la version courte, dans la section « Répondre à une demande de confidentialité ».
Ce qu’il ne prétend pas
Il ne rend pas votre site conforme, et il le dit sur son propre écran.
Il ne sait rien de vos autres extensions, ne donne aucun conseil juridique, et ne supprime pas de compte WordPress. Le dire est utile : un « centre de confidentialité » qui laisserait croire qu’il couvre tout ferait manquer ce qu’on croit fait.
L’adresse est comparée exactement
Un LIKE %camille@example.test% paraît plus serviable et fait deux dégâts
opposés. Il attrape camille@example.test.attaquant.example, dont le titulaire
n’a rien demandé — on exporterait ses données à quelqu’un d’autre. Et il attrape
pas-camille@example.test, qui est une autre personne.
Sur un export, se tromper de personne est une divulgation. Sur un effacement, c’est une perte. Les deux sont irréversibles, et aucune ne se voit au moment où elle se produit.
La casse est normalisée : personne ne considère que Camille@Example.test est
quelqu’un d’autre, et exiger la casse exacte ferait échouer des demandes
légitimes.
Un terme qui n’est pas une adresse ne cherche rien. Sans ce refus, « camille » — ou pire, un espace — balaierait toutes les valeurs du site.
La portée est dans la requête, pas dans l’affichage
Un opérateur qui ne gère que ses formulaires ne doit pas pouvoir apprendre, par un décompte ou un identifiant, qu’une personne a répondu ailleurs. La portée est calculée une fois, à l’entrée, et passée partout ; aucun appel ne la recalcule et aucun ne l’élargit.
Une portée vide ne rend rien. Elle ne rend surtout pas tout — c’est l’erreur
classique du IN () construit à la main, et elle ouvrirait le site entier à qui
n’a aucun formulaire.
Chaque module déclare ce qu’il détient
Le centre ne balaie pas les tables. Il le pourrait — elles sont toutes préfixées
slf_ — mais il faudrait qu’il connaisse la colonne portant l’adresse dans
chacune : vingt fois le même savoir au mauvais endroit. Un module ajouté demain
serait oublié, et l’oubli ne se verrait pas. Un export incomplet a l’air
complet.
Chaque module se déclare donc, par solis_forms_pro_personal_data_providers.
Celui qui ne le fait pas n’apparaît ni à l’export ni à l’effacement — et c’est
constatable, puisque le registre est listé à l’écran.
L’effacement par soumission existait déjà : delete() purge les pièces
jointes et diffuse solis_forms_entry_deleting, auquel tous les modules sont
abonnés. Le centre s’y branche plutôt que de le refaire. Ce qu’il ajoute est
l’effacement par personne — ce qu’un module détient sans soumission
attachée : une opposition SMS, un contact de CRM, une ligne de portail.
« Effacé » et « anonymisé » ne disent pas la même chose
Les confondre coûterait cher le jour où quelqu’un demande la preuve de ce qui a été fait. Une écriture comptable anonymisée reste dans les livres ; une soumission effacée n’y est plus.
Un module qui doit garder une trace rend ce qu’il a anonymisé, et dit ce qu’il conserve et pourquoi. Le centre ne tranche pas à sa place : il rapporte.
Un échec partiel ne défait pas le reste
On pourrait vouloir tout annuler pour garder un état cohérent. Ce serait une erreur ici. Une personne a demandé l’effacement de ses données ; qu’un service distant soit injoignable n’est pas une raison de garder les dix autres copies.
Chaque module est appelé, son résultat consigné, et la demande reste rejouable pour ce qui a échoué. Un module qui lève — une extension tierce, un bogue — est consigné comme un échec et n’emporte pas la demande.
Rejouer est sans danger
Les modules rendent « rien à faire » sur ce qu’ils ont déjà traité. Une seconde exécution reprend ce qui avait échoué sans défaire ce qui avait réussi, et le journal garde les deux passages — c’est précisément ce qu’on veut pouvoir montrer.
La confirmation est un geste à part
Ouvrir une demande et l’exécuter sont deux gestes, deux nonces, deux lignes de journal. On pourrait les réunir derrière une confirmation JavaScript ; cela mettrait un effacement irréversible à un clic de distance, sur un écran qu’on parcourt.
Et confirmer retient qui a confirmé, ce qu’une boîte de dialogue ne sait pas faire.
À l’exécution, l’adresse est redemandée. Elle n’est pas conservée, et son empreinte ne se renverse pas. C’est une contrainte volontaire : la table ne porte pas ce qu’on s’apprête à effacer.
La table des demandes ne porte aucune adresse
Seulement une empreinte, sous le sel du site.
Une table de demandes de suppression qui porterait les adresses de ceux qui ont demandé la suppression serait exactement le fichier qu’ils voulaient voir disparaître — et il survivrait à l’effacement de leurs soumissions. Le libellé affiché se reconstruit depuis les soumissions tant qu’elles existent. Après exécution, il n’y a plus rien à afficher, et c’est le but.
Le journal ne se reprend pas
Append-only, comme le plan l’exige. Pas de state, pas d’updated_at, et aucune
méthode pour reprendre ou supprimer une ligne — la contrainte vit dans la classe
plutôt que dans une permission de base de données, qu’un hébergement mutualisé
n’accorde pas.
Un journal qu’on peut corriger ne prouve rien. C’est sa seule raison d’être : le jour où quelqu’un demande ce qui a été fait de ses données, c’est la seule réponse qui vaille, et elle doit être antérieure à la question.
Effacer une demande ne touche pas son journal. Les deux tables ne sont liées par aucune contrainte : supprimer une demande emporterait la preuve qu’on a fait ce qu’on devait.
L’export n’atterrit jamais dans vos téléversements
C’eût été le plus simple : écrire le ZIP dans uploads/ et en donner l’adresse.
Ce serait un fichier contenant tout d’une personne, sur une adresse devinable,
servie par le serveur web, et que personne ne penserait à effacer. Les demandes
de confidentialité produiraient ainsi exactement la fuite qu’elles servent à
réparer.
L’archive est composée dans le répertoire temporaire du système, servie en flux derrière une capacité, et effacée immédiatement.
Sans ZipArchive — qui n’est pas garanti chez tous les hébergeurs — tout est
servi en un seul CSV, avec une colonne de plus nommant le module. Refuser
l’export pour cette raison priverait d’une obligation à laquelle il faut
répondre.
La conservation est par formulaire, et éteinte par défaut
Une purge active par défaut effacerait, au premier passage nocturne, des réponses que personne n’a décidé de perdre — et sur un site installé depuis deux ans, toutes d’un coup.
En deçà de sept jours, rien n’est appliqué. Le plancher laisse le temps de s’apercevoir qu’on a tapé 1 au lieu de 100, et cette semaine ne coûte rien à qui voulait vraiment purger. Un délai sous le plancher vaut rien, jamais « tout de suite » : lire une saisie fautive comme un ordre d’effacement immédiat serait la pire des deux lectures.
Anonymiser garde les agrégats
C’est la moitié qu’on oublie. Vider la soumission entière serait plus simple et détruirait ce qui n’identifie personne : la date, le formulaire, le montant payé, la réponse à « quel service vous intéresse ». Une boutique qui anonymise ses clients ne doit pas perdre son chiffre d’affaires, et une enquête ne doit pas perdre ses réponses — c’est ce qu’une enquête anonymisée est censée devenir.
Le remplacement se fait par type de champ, pas par libellé. Un champ « Votre
nom » peut s’appeler nom, name, client, qui ; deviner d’après le libellé
marcherait neuf fois sur dix, et la dixième laisserait une identité en place sans
que personne ne s’en aperçoive.
| Traitement | Types |
|---|---|
| Remplacés par un jeton | email, name, phone, address, url, hidden, signature, file |
| Conservés tels quels | select, radio, checkbox, number, date, time, country, payment, calculated |
| Vidés | tout le reste, texte libre compris |
Le texte libre est vidé plutôt que remplacé par un jeton : aucune règle ne peut en extraire l’identité, et un commentaire porte souvent un nom — parfois celui de quelqu’un d’autre. Le garder reviendrait à ne rien anonymiser.
Un type non classé est vidé. L’oubli va vers l’effacement, qui se voit à la relecture, plutôt que vers la conservation, qui ne se voit jamais.
Le jeton est stable et propre au site : deux réponses de la même personne restent rapprochables sans qu’on sache de qui, et le jeton ne vaut rien sur une autre installation.
Le terme est contrôlé deux fois
Le filtre de date du dépôt écarte silencieusement une valeur qu’il ne sait pas lire : une faute de format n’y produit pas d’erreur, elle produit « aucun filtre ». Sur une purge, cela voudrait dire effacer toutes les soumissions du formulaire, sans qu’aucune exception ne le signale.
L’exécuteur revérifie donc chaque date lui-même, avec une comparaison qui ne dépend d’aucun format — deux chaînes que nous avons composées toutes les deux. La correction du format seule aurait suffi aujourd’hui ; ce contrôle tient le jour où quelqu’un change ce que la requête accepte.
Le passage est borné
Un site installé depuis deux ans qui active une conservation de trente jours a, le lendemain, des dizaines de milliers de soumissions arrivées à terme. Les traiter d’un coup dépasse le temps d’exécution, meurt au milieu, et recommence le lendemain au même endroit — indéfiniment.
Ce qui reste attend le lendemain, et le retard se résorbe en quelques jours. Un effacement en retard est sans conséquence ; un effacement qui ne s’achève jamais en a.
Ce que la V1 ne fait pas
Pas de gestion universelle de toutes les extensions WordPress, pas de conseil juridique, pas de suppression d’un compte WordPress sans module dédié. Le flux s’arrête aux données que vos formulaires détiennent.
