Compatibilité PHP
SPIP 4.1 nécessite PHP 7.4 minimum, et fonctionne jusqu’à PHP 8.1.
Il nécessite les extensions PHP : sodium, Zlib, Zip et Phar.
Rappel : SPIP 4.0 c’est PHP 7.3 à 8.0.
Compatibilité PHP 8.1
Pour la compatibilité PHP 8.1, nous avons du corriger / adapter de nombreuses fonctions.
Cela concerne particulièrement des appels à des fonctions de PHP traitant des chaînes de caractères, si elles reçoivent null
au lieu d’une chaîne, pour éviter des deprecated
: https://php.watch/versions/8.1/internal-func-non-nullable-null-deprecation
Authentification & Chiffrement
Nous reprenons en l’adaptant le travail de g0uz sur le plugin Chiffrer.
- Cela corrige certains rares cas où la librairie Javascript utilisée jusqu’à présent échouait dans l’identification de l’internaute
- Cela renforce la sécurité en évitant certains types d’attaques.
Le formulaire de login
HTTPS est désormais encore plus fortement conseillé
En effet, SPIP ne cherche plus à chiffrer le mot de passe des auteurs en Javascript depuis le formulaire de login, et le mot de passe arrive donc systématiquement « en clair » à SPIP. Il est donc fortement conseillé d’avoir son site en HTTPS, car HTTPS assure alors la sécurité de la transmission.
En conséquence, la constante _AUTORISER_AUTH_FAIBLE
, qui permettait de forcer l’envoi du mot de passe en clair, est supprimée.
Poivre, sel, hash du mot de passe
Le mot de passe d’un auteur est maintenant haché dans SPIP en utilisant un poivre (une clé spécifique pour le site). Par ailleurs, la fonction password_hash
de PHP s’occupe de trouver le meilleur algorithme de hachage et de créer un sel dedans. La fonction password_verify
de PHP est utilisée pour le vérifier.
Les "aléas" rotatifs des auteurs sont toujours créés, mais ne sont plus utilisés pour saler le mot de passe vu que PHP gère cela très bien. Par contre, l’application supplémentaire d’un poivre est une nouveauté.
Comme avant, à chaque authentification réussie d’un auteur, on enregistre un nouveau hash en base, en recréant un hash avec password_hash
: cela applique un nouveau sel dessus donc, et éventuellement PHP en profite pour utiliser un algorithme de hachage plus performant si besoin.
Clés de chiffrement
Pour mener à bien ce poivre, et d’autres actions dans SPIP, des clés de chiffrement sont utilisées et stockées dans config/cles.php
. Il y en a 2 par défaut :
- secret_des_auth : elle sert à poivrer le mot de passe des auteurs. C’est une nouvelle clé donc.
- secret_du_site : elle sert pour moitié à calculer le secret du site. L’autre moitié étant stocké en base dans l’entrée
secret_du_site
de la tablespip_meta
. Ce secret du site (combiné) permet de signer et/ou chiffrer certaines parties de SPIP (contextes ajax, actions d’auteurs).
Lorsqu’un webmestre se connecte, les clés sont sauvegardées dans le nouveau champ backup_cles
de la table spip_auteurs
, en le chiffrant avec le mot de passe en clair de l’auteur.
Ceci permet de restaurer les clés du site si le fichier cles.php
a été effacé, lors de l’authentification d’un webmestre.
La classe \Spip\Chiffrer\SpipCles
permet de manipuler les clés au besoin.
Password
SPIP fournit deux méthodes qui sont utilisées dans ecrire/auth/spip.php
- \Spip\Chiffrer\Password::verifier($clair, $hash, $key = null): bool
- \Spip\Chiffrer\Password::hacher($clair, $key = null): string
La clé par défaut est celle de secret_des_auth
, utilisée pour poivrer.
Chiffrement
Trois méthodes sont aussi fournies pour chiffrer et déchiffrer (chiffrage symétrique) des contenus.
Dedans nous utilisons la librairie Sodium (fournie par défaut dans PHP >= 7.2).
- Chiffrement::chiffrer($message, $key): ?string
- Chiffrement::dechiffrer($encoded, $key): ?string
- Chiffrement::keygen(): string
La méthode keygen
produit simplement une clé de chiffrement à la longueur adaptée.
Les méthodes chiffrer()
et dechiffrer()
seront très lentes si la clé transmise n’a pas la bonne longueur : on considère alors la clé de chiffrement comme étant un mot de passe nécessitant un traitement supplémentaire lourd (avec sodium_crypto_pwhash
).
Signature des actions
Les actions sont authentifiées maintenant en utilisant hash_hmac
et hash_equals
(et les aléas d’auteurs et/ou le secret du site)
Qualité du code
Il y a de quoi progresser sur la qualité du code PHP de SPIP… l’avenir ne peut être que meilleur ;-)
Typage
Ce faisant pour PHP 8.1, nous avons commencé à typer certains arguments et retours de fonctions pour détecter au plus tôt certains appels incorrects.
C’est un changement potentiellement impactant : cela peut créer des erreurs de squelettes là où l’erreur était auparavant plus silencieuse ou tolérée. De même cela pourrait provoquer des erreurs PHP dans des plugins ou des scripts maison sur les appels erronés à ces fonctions.
En assurant la compatibilité avec les nouvelles versions de PHP nous irons forcément vers plus de typage dans le code de SPIP au fur et à mesure des évolutions et factorisations du code source.
La conséquence sera donc que les personnes développant des plugins ou des squelettes devront être plus vigilantes sur les appels effectués d’une part, et d’autre part que nous restreindrons certainement les nouvelles fonctions à des types uniques (éviter les mixed
), de même que certaines fonctions déjà existantes verront probablement certains types d’arguments mixtes réduits (éviter qu’un argument puisse recevoir un peu tout comme int | string | array
par exemple), de même pour les retours de fonctions.
Au vu du code de SPIP historique ce ne sera pas si évident.
Sucre syntaxique
Nous avons passé l’outil Rector sur le code de SPIP 4.1 avec la configuration PHP 7.4. L’outil permet de transformer la syntaxe du code source PHP en modifiant certains éléments qui peuvent être simplifiés grâce à des écritures plus récentes de PHP. Par exemple utiliser les opérateurs ??
ou ??=
lorsque c’est possible (Voir la doc PHP).
C’est toujours ça de pris :-)
Changements d’API sur les URLs et objets
Certaines fonctions d’appels pour calculer ou décoder les URLs sont modifiées.
Les anciennes API sont dépréciées.
Il y a maintenant 2 jeux de fonctions distincts pour générer l’URL d’un objet et pour décoder une URL. Ce nouveau mécanisme permet de définir une fonction pour générer une URL propre pour les #URL_PAGE
.
Les nouvelles fonctions sont typées. Dans les explications suivantes, on ne présente que le début des signatures des différentes fonctions modifiées.
Voir la demande d’ajout correspondante pour le détail complet.
Encodage
generer_objet_url (anciennement generer_url_entite
)
Cette fonction génére une URL, qui peut être soit pour l’espace public (paramètre $public = true
), soit pour l’espace privé ($public = false
), soit par défaut ($public = null
) retourner une URL pour l’espace dans lequel on se trouve actuellement …
La fonction generer_objet_url()
est la fonction de haut niveau, qui va finir par appeler une fonction urls_xxx_generer_url_objet()
_dist selon le module d’URL actif.
Note : Pour cette fonction la signature change légèrement.
Dans generer_url_entite()
maintenant déprécié :
- Le 5e paramètre
$public
pouvait valoirtrue, false, null ou 'string'
. Dans le cas d’une chaine, il correspondait à un paramètre "connect".
Ce sont maintenant 2 paramètres séparés pour generer_objet_url
:
- Le 5e est
?bool $public = null
(donctrue, false ou null)
, - le 6e est
string $connect = ''
.
Dans la majorité des cas, cela n’affectera pas les usages et renommer simplement la fonction devrait être suffisant.
- generer_url_entite($id, $objet, ...)
+ generer_objet_url($id, string $objet, ...)
generer_objet_url_absolue
Generer l’url absolue vers un objet
- generer_url_entite_absolue($id, $entite, ...)
+ generer_objet_url_absolue($id = 0, string $entite = '', ...)
Décodage
La fonction de décodage des URLs s’appelle maintenant urls_xxxx_decoder_url_dist()
ce qui évite toute confusion avec l’ancienne fonction urls_xxxx_dist()
.
De plus, pour un module d’URLs qui voudrait être compatible avec les anciennes versions de SPIP et cette nouvelle convention, il suffit de proposer une fonction urls_xxxx_dist()
non typée qui fait le routage vers les 2 fonctions urls_xxx_generer_url_objet_dist()
et decoder_url()
du module.
Objet
generer_objet_lien
Génère un lien (titre cliquable vers url) vers un objet
- generer_lien_entite($id_objet, $objet, ...)
+ generer_objet_lien(int $id_objet, string $objet, ...)
generer_objet_info
Donner une information sur un objet éditorial. Utilisé entre autres par #INFO_XX
- generer_info_entite($id_objet, $type_objet, $info, ...)
+ generer_objet_info($id_objet, string $type_objet, string $info, ...)
Les fonctions permettant de définir des calculs spécifiques pour l’obtention d’information sont aussi renommées. Pour l’information calculée ’xxx’ : appelé via generer_objet_info(3, 'article', 'xxx')
ou #INFO_XXX{article,3}
.
Si ces fonctions existent, elles sont utilisées par SPIP dans ce cas :
// xxx spécifiquement sur l’objet 'type'
- generer_xxx_{type}($id_objet, $type_objet, ...)
+ generer_{type}_xxx($id_objet, string $type_objet, ...)
// sinon xxx sur un objet quelconque
- generer_xxx_entite($id_objet, $type_objet, $row, ...)
+ generer_objet_xxx($id_objet, string $type_objet, array $row, ...)
L’ancien nommage est déprécié.
Suivant ce principe, la fonction interne à SPIP pour calculer l’introduction a été renommée :
generer_objet_introduction
Génère l’introduction de l’objet (fonction privée à SPIP), utilisé par #INTRODUCTION
et #INFO_INTRODUCTION
)
- generer_introduction_entite($id_objet, $objet, $ligne_sql, ...)
+ generer_objet_introduction(int $id_objet, string $objet, array $ligne_sql, ...)
Réécriture de transmettre
en .api
Pour faciliter et sécuriser partiellement l’envoi de données spécifiques (CSV, JSON) à des auteurs connus de SPIP, l’URL d’api transmettre.api a été mis en place (elle remplace un ancien mécanisme à l’objectif identique qui utilisait un squelette transmettre.html
).
L’URL est générée avec la fonction generer_url_api_low_sec()
(« low sec » signifiant ici « sécurité basse »). Un jeton fixe est créé pour cette action (avec ses paramètres) pour l’auteur désigné et sera acceptée même si l’auteur est déconnecté (ce qui veut dire que quiconque possède l’URL pourra accéder au contenu renvoyé).
Historiquement cela permet de générer des fichiers non publics (RSS des articles proposés à publication, statistiques du site) qui peuvent être exploités par des outils tierces (agrégateur RSS par exemple).
Également :
- la fonction
securiser_acces()
est renommee ensecuriser_acces_low_sec()
et definie dans inc/acces. - On garde un
filtre_securiser_acces_dist()
dans inc/filtres pour la compat des vieux squelettes - la fonction
param_low_sec()
est depreciee
Mises à jour des librairies
Nous avons mis à jour différentes librairies utilisées par SPIP.
Javascript
- spip/spip -> Sortable 1.14.0
- spip/spip -> jquery Form 4.3.0
- spip/spip -> JS Cookie 3.0.1
- spip/statistiques -> d3 7.3.0
- spip/statistiques -> luxon 2.3.0
- spip/plan -> jstree 3.3.12
PHP
- spip/compresseur -> css-tidy 2.0.0
- spip/medias -> getid3 1.9.21
- spip/medias -> svg-sanitizer 0.14.1
Suppression de librairies
Nous avons supprimé jQuery.cookie
qui était déprécié depuis SPIP 3.2 au profit de JS Cookie.
Pour rappel si vous n’aviez pas encore adaptés vos utilisations :
$.cookie(key) devient Cookies.get(key)
$.cookie(key, value) devient Cookies.set(key, value)
$.cookie(key, value, options) devient Cookies.set(key, value, options)
Interface
Les rubriques dans l’espace privé affichent maintenant aussi la liste des articles refusés.
Nettoyages
Nous avons supprimé
#FORMULAIRE_CONFIGURER_METAS
qui était déprécié depuis SPIP 3.0 au profit des formulaires
#FORMULAIRE_CONFIGURER_XX
. Voir la documentation Configurer une fonctionnalité de votre site, ou un plugin à ce sujet.
Quelques adaptations
Dans un squelette, pour avoir la liste des tables des objets éditoriaux, préférer #NULL
(qui retourne null
) plutôt que #REM
(qui retourne une chaîne vide).
- [(#REM|lister_tables_objets_sql)]
+ [(#NULL|lister_tables_objets_sql)]
Plugins
Archiviste
Le plugin "Archiviste" a été mis à jour pour utiliser les extensions PHP Zip, zlib et Phar, qui sont désormais requises. Ceci nous a permis de supprimer les (très) vielles librairies Pcl* que nous traînions depuis quelques années.
À noter aussi que le plugin est accompagné de tests unitaires écrits avec PHPUnit.
Bigup
Le formulaire de configuration de Bigup est affiché sur la page des options avancées, avec une formulation un peu plus parlante pour le titre du formulaire d’explication.
Compresseur
Mise à jour de la librairie CSSTidy en version 2.0 et correction d’un bug dans la compression des fichiers Javascript sur certains environnements.
Forum
- correction d’un bug qui affichait le lien vers la page de contrôle des forums pour les auteurs non autorisés.
- normalisation de l’ajout d’un forum en base afin de bien faire passer les informations par les pipeline pre/post insertion
- correction d’un bug d’affichage d’icône en langue RTL
- correction d’un bug qui permettait d’accéder au forum privé des rédacteurs alors que celui-ci était désactivé dans la configuration
- correction d’un bug dans la recherche de message depuis la page de contrôle des forums
Mediabox
- amélioration de l’affichage des textes longs dans la légende des modales
- utilisation d’un thème sombre par défaut dans l’espace privé
- rétablissement du support des URLs avec fragments à l’aide d’un sélecteur dans l’attribut
data-href-popin
- ajout du support des attributs
data-(max|min)-(width|height)
etdata-(width|height)
sur les liens mediabox et rétablissement de la compatibilité avec les anciennes classes du typeboxInline boxIframe boxWidth-xx boxHeight-xx
- correction d’un bug avec certaines images distantes qui n’étaient pas affichées par la modale (notamment des SVG), car l’image n’a pas de dimension connue
Medias
- permettre de personnaliser le comportement en autolien des images en fonction du media, de l’extension, de la taille ou de l’id_document
- correction d’un bug dans le modèle d’embed des fichiers CSV
- retrait de la librairie obsolète jQuery multifile
- mise à jour des librairies SVG Sanitizer et getid3
- retrait des préfixes navigateurs dans les CSS du plugin
- amélioration UX des boutons dans le bloc des documents d’un objet
- correction d’un bug dans le code généré pour les attributs d’une image avec légende
- amélioration du modèle utilisé pour l’insertion des images SVG dans le texte d’un objet
- correction d’un bug d’affichage de la médiathèque quand un document comporte une très longue URL dans les champs titre ou credit
Plan
Mise à jour de la librairie Jstree en version 3.3.12.
Révisions
Correction d’un bug qui empêchait le fonctionnement du génie d’optimisation des révisions.
Sites
- correction d’un bug qui affichait la date en double dans les listes d’articles syndiqués
- amélioration des formulaires d’édition de site en utilisant un placeholder dans les champs d’URL (au lieu de les pré-remplir avec http://)
- correction d’un bug d’affichage de la liste des sites en colonne latérale de l’espace privé
Statistiques
- mise à jour des librairies D3.js, d3-time-format et Luxon.js
- correction d’un bug d’affichage des noms des mois dans les statistiques en langue arabe
SVP
- correction d’un bug dans le déballage des archives de plugin avec les nouvelles fonctions du plugin Archiviste
- amélioration de présentation des cases à cocher dans la liste des plugins
- correction d’un bug de sélection des plugins quand la personne faisait "tout cocher" puis "cocher les mises à jour"
- correction d’un bug dans l’affichage des messages de retour du formulaire de chargement de plugin
- toujours afficher le lien vers la documentation du plugin qu’il soit actif ou non
- correction d’un bug qui empêchait d’activer un plugin quand les téléchargements sont interdits
TextWheel
- correction d’un bug qui échappait par erreur certains liens automatiques
- correction d’un bug de direction d’affichage des puces quand la page contient des bloc de textes de directions différentes
URLs étendues
Pour faire suite aux changements d’API sur les URLs et objets, les fonctions d’URLs ont été reprises pour une écriture plus claire et mieux typée avec 2 points d’entrée pour la partie décodage/encodage.
Voir la demande d’ajout correspondante pour le détail complet.
Squelettes dist
- correction d’un bug qui provoquait le débordement des paginations sur petit écran
- application du filtre
|header_silencieux
sur les pages publiques afin de respecter la valeur de la globalespip_header_silencieux
- retrait des classes spécifiques à Internet Explorer dans les CSS
- correction d’un bug d’affichage des images et SVG sur petit écran