Gestion des Données et APIs Avancées : Utiliser le Stockage Local et les Permissions
Introduction à la Persistance des Données dans les Extensions de Navigateur
Bienvenue dans cette leçon dédiée à un aspect fondamental du développement d'extensions de navigateur : la gestion des données et l'utilisation des permissions. Au-delà de l'interface utilisateur et de la logique de base, une extension performante et utile nécessite souvent de stocker des informations, qu'il s'agisse des préférences de l'utilisateur, de données mises en cache, ou d'états d'application.
Imaginez une extension qui gère des tâches : si elle perd toutes les tâches ajoutées par l'utilisateur à chaque fermeture du navigateur, elle devient inutile. C'est là qu'intervient le stockage local. De plus, pour accéder à ces données ou interagir avec des fonctionnalités spécifiques du navigateur (comme modifier des onglets ou accéder à des API système), votre extension aura besoin de permissions explicites, qui sont la clé de voûte de la sécurité et du contrôle dans l'écosystème des extensions.
Dans cette leçon, nous allons explorer les différentes options de stockage offertes aux extensions, comprendre comment les permissions fonctionnent et comment les déclarer correctement, et enfin, voir comment les utiliser de manière efficace et sécurisée.
Pourquoi Gérer les Données dans une Extension ?
La persistance des données est cruciale pour plusieurs raisons :
- Personnalisation : Stocker les préférences de l'utilisateur (thème sombre, langue, réglages spécifiques) pour une expérience cohérente.
- Performance : Mettre en cache des données coûteuses à récupérer (API externes, résultats de calculs complexes) pour réduire la latence et la consommation de ressources.
- État de l'application : Sauvegarder l'état actuel de l'extension (éléments ouverts, progression, données en cours de saisie) pour le restaurer à la prochaine utilisation.
- Fonctionnalités avancées : Enregistrer des historiques, des signets spécifiques à l'extension, ou d'autres informations propres à la logique métier.
Options de Stockage Local pour les Extensions
Les extensions de navigateur disposent de plusieurs mécanismes pour stocker des données localement. Le choix de l'API dépendra de la nature des données, de leur volume, de la nécessité de synchronisation et des performances attendues.
L'API chrome.storage (ou browser.storage)
C'est l'API recommandée pour le stockage de données persistantes dans les extensions. Elle offre une solution asynchrone, optimisée pour les extensions, et est plus sécurisée que d'autres méthodes. Elle est disponible pour tous les contextes de votre extension (scripts d'arrière-plan, pop-up, pages d'options, scripts de contenu via un message).
L'API storage se décline en plusieurs zones :
-
chrome.storage.local:- Description : Stocke les données localement sur la machine de l'utilisateur. Ces données ne sont pas synchronisées entre différents navigateurs ou profils.
- Capacité : Généralement, jusqu'à 5 MB, mais peut être étendue avec la permission
unlimitedStorage. - Cas d'usage : Préférences non critiques, données mises en cache spécifiques à la machine, états d'application volumineux.
- Avantages : Asynchrone, plus fiable et sécurisé que
localStorage, accessible depuis tous les contextes de l'extension. - Inconvénients : Non synchronisé.
-
chrome.storage.sync:- Description : Stocke les données localement et les synchronise automatiquement via le compte utilisateur du navigateur (par exemple, un compte Google pour Chrome).
- Capacité : Plus limitée, généralement autour de 100 KB par élément, avec une limite totale de 8 MB. Il y a aussi des limites de débit d'écriture.
- Cas d'usage : Préférences utilisateur importantes qui doivent persister à travers différentes machines, petits réglages globaux.
- Avantages : Synchronisation transparente entre les appareils, résilience aux pertes de données locales.
- Inconvénients : Capacités et débits limités, coût en bande passante.
-
chrome.storage.managed(moins courant pour les développeurs d'extensions classiques) :- Description : Permet aux administrateurs de domaine de définir des stratégies pour l'extension, fournissant des données en lecture seule.
Permissions Requises pour chrome.storage
Pour utiliser chrome.storage, vous devez déclarer la permission storage dans votre fichier manifest.json. Si vous avez besoin de plus de 5 MB de stockage local, vous devrez également ajouter la permission unlimitedStorage.
{
"name": "Mon Extension",
"version": "1.0",
"manifest_version": 3,
"permissions": [
"storage",
"unlimitedStorage"
],
"background": {
"service_worker": "background.js"
}
}
Utilisation de chrome.storage.local
Voici un exemple simple pour sauvegarder et récupérer des données :
// background.js ou popup.js
// Fonction pour sauvegarder des données
async function saveSettings(settings) {
try {
await chrome.storage.local.set({ userSettings: settings });
console.log('Paramètres sauvegardés avec succès !');
} catch (error) {
console.error('Erreur lors de la sauvegarde des paramètres :', error);
}
}
// Fonction pour récupérer des données
async function loadSettings() {
try {
const data = await chrome.storage.local.get('userSettings');
if (data.userSettings) {
console.log('Paramètres récupérés :', data.userSettings);
return data.userSettings;
} else {
console.log('Aucun paramètre trouvé.');
return null;
}
} catch (error) {
console.error('Erreur lors de la récupération des paramètres :', error);
return null;
}
}
// Exemple d'utilisation
const myNewSettings = {
theme: 'dark',
notificationsEnabled: true,
lastVisited: new Date().toISOString()
};
saveSettings(myNewSettings);
// Après un certain temps ou événement
loadSettings().then(settings => {
if (settings) {
console.log("Thème actuel :", settings.theme);
}
});
// Écouter les changements de stockage
chrome.storage.onChanged.addListener((changes, namespace) => {
if (namespace === 'local' && changes.userSettings) {
console.log('Les paramètres locaux ont changé :', changes.userSettings.newValue);
}
});
// Supprimer un élément
async function removeSetting(key) {
try {
await chrome.storage.local.remove(key);
console.log(`Clé "${key}" supprimée.`);
} catch (error) {
console.error(`Erreur lors de la suppression de la clé "${key}" :`, error);
}
}
// removeSetting('userSettings'); // Désactivez pour tester la suppression
// Vider tout le stockage local de l'extension
async function clearAllLocalData() {
try {
await chrome.storage.local.clear();
console.log('Tout le stockage local de l\'extension a été vidé.');
} catch (error) {
console.error('Erreur lors du vidage du stockage local :', error);
}
}
// clearAllLocalData(); // Désactivez pour tester le vidage complet
Explication du code :
Ce bloc de code JavaScript montre comment interagir avec chrome.storage.local.
saveSettingsutilisechrome.storage.local.set()pour stocker un objet sous la cléuserSettings.loadSettingsutilisechrome.storage.local.get()pour récupérer l'objet associé àuserSettings.chrome.storage.onChanged.addListenerest un écouteur d'événements qui se déclenche chaque fois qu'une donnée dans le stockage de l'extension est modifiée. C'est très utile pour mettre à jour l'UI ou la logique de l'extension en temps réel.removeSettingmontre comment supprimer une entrée spécifique avecchrome.storage.local.remove().clearAllLocalDataillustre le vidage complet du stockage local de votre extension avecchrome.storage.local.clear(). Nous utilisonsasync/awaitpour gérer les opérations asynchrones de manière plus lisible.
L'API localStorage (Web Storage API)
L'API localStorage est une fonctionnalité du navigateur standard, non spécifique aux extensions. Elle permet de stocker des paires clé-valeur sous forme de chaînes de caractères.
- Description : Stocke des données de manière persistante pour une origine donnée (domaine, protocole, port).
- Capacité : Environ 5-10 MB par origine.
- Cas d'usage : Peu recommandé pour les scripts d'arrière-plan des extensions. Principalement utile si votre extension a une page popup ou une page d'options HTML/JavaScript et que vous voulez stocker des données spécifiques à cette page dans le contexte de cette page, ou si un script de contenu a besoin de stocker des données pour l'origine du site web qu'il manipule.
- Avantages : API simple, synchrone.
- Inconvénients : Déconseillé pour les scripts d'arrière-plan ou pour les données globales de l'extension car il est synchrone (peut bloquer le thread principal) et lié à l'origine, ce qui peut rendre l'accès et la gestion plus complexes dans le contexte d'une extension. Non accessible directement depuis le
service_workerou les scripts d'arrière-plan des extensions V3. - Permissions : Aucune permission spécifique n'est requise.
L'API sessionStorage (Web Storage API)
Similaire à localStorage, mais les données sont éphémères.
- Description : Stocke des données pour la durée de la session de la page ou de l'onglet. Les données sont effacées lorsque l'onglet est fermé.
- Cas d'usage : Stockage temporaire d'informations qui n'ont pas besoin de persister au-delà de la session d'une page spécifique de l'extension (ex: un formulaire incomplet).
- Inconvénients : Mêmes limitations que
localStorageconcernant l'accessibilité dans les contextes d'extension (non accessible directement depuis leservice_worker).
Comparaison Rapide
| Caractéristique | chrome.storage.local | chrome.storage.sync | localStorage | sessionStorage |
| :-------------------- | :--------------------------------- | :----------------------------- | :--------------------------- | :--------------------------- |
| Persistance | Oui (localement) | Oui (synchronisé) | Oui (par origine) | Non (par session/onglet) |
| Synchronisation | Non | Oui (via compte utilisateur) | Non | Non |
| Asynchrone ? | Oui | Oui | Non | Non |
| Accès Contextes | Tous (background, popup, content*) | Tous (background, popup, content*) | Selon l'origine (popup, content) | Selon l'origine (popup, content) |
| Capacité | ~5MB (extensible avec unlimitedStorage) | ~8MB total, ~100KB par item | ~5-10MB par origine | ~5-10MB par origine |
| Permissions | storage | storage | Aucune | Aucune |
| Recommandé pour Ext. | Oui (par défaut) | Oui (pour prefs synchronisées) | Non (sauf cas très spécifiques) | Non (sauf cas très spécifiques) |
| Notes | Stocke des objets JS, pas seulement chaînes | API limitée en taille et débit | Stocke chaînes de caractères | Stocke chaînes de caractères |
* Note : Pour accéder à chrome.storage depuis un script de contenu, le script de contenu doit envoyer un message au script d'arrière-plan, qui effectue l'opération de stockage et renvoie la réponse.
Les Permissions : La Clé de Voûte de la Sécurité et de la Fonctionnalité
Les permissions sont des déclarations faites dans le fichier manifest.json de votre extension qui informent le navigateur (et l'utilisateur) des capacités et des accès que votre extension requiert. Elles sont essentielles car elles :
- Protègent l'utilisateur : Empêchent les extensions malveillantes d'accéder à des données sensibles ou d'effectuer des actions non autorisées.
- Définissent les capacités de l'extension : Permettent à votre extension d'utiliser des APIs spécifiques du navigateur (comme
tabs,alarms,notifications,storage) ou d'interagir avec certaines parties du web. - Gèrent le consentement : Lors de l'installation, le navigateur affiche à l'utilisateur la liste des permissions demandées. L'utilisateur doit les accepter pour installer l'extension.
Déclarer les Permissions dans manifest.json
Les permissions sont déclarées dans la section permissions de votre manifest.json. Elles sont généralement des chaînes de caractères représentant le nom d'une API (ex: "storage") ou des URL pour les permissions d'hôte.
{
"name": "Mon Extension Avancée",
"version": "1.0",
"manifest_version": 3,
"permissions": [
"storage",
"activeTab",
"scripting",
"tabs",
"alarms",
"notifications"
],
"host_permissions": [
"https://api.example.com/*",
"*://*.google.com/"
],
"background": {
"service_worker": "background.js"
}
}
Explication du manifest.json :
permissions: Liste les accès aux APIs du navigateur (commestoragepour le stockage,activeTabpour accéder à l'onglet actif temporairement,scriptingpour injecter du code,tabspour manipuler les onglets,alarmspour planifier des tâches,notificationspour afficher des messages).host_permissions: Spécifie les domaines avec lesquels l'extension est autorisée à interagir. Cela inclut la capacité d'injecter des scripts de contenu ou de faire des requêtesfetch/XMLHttpRequestvers ces domaines."https://api.example.com/*"permet à l'extension d'accéder à n'importe quel chemin surapi.example.comvia HTTPS."*://*.google.com/"permet d'accéder à n'importe quel sous-domaine degoogle.com(ex:www.google.com,mail.google.com) via HTTP ou HTTPS.
Types de Permissions Courantes Liées aux Données et APIs Avancées
storage: Indispensable pour utiliser l'APIchrome.storage.unlimitedStorage: Pour dépasser la limite de 5MB dechrome.storage.local.tabs: Permet d'accéder aux propriétés des onglets (URL, titre), de créer, modifier ou fermer des onglets. Utile si votre extension doit manipuler l'historique ou l'état de navigation.activeTab: Une permission temporaire qui est accordée uniquement lorsque l'utilisateur invoque l'extension (clique sur l'icône, utilise un raccourci clavier, ou sélectionne un élément dans le menu contextuel). Elle permet d'accéder à l'onglet actif sans demander un accès persistant à tous les onglets. C'est une excellente alternative àtabspour des actions contextuelles.scripting(Manifest V3) : RemplaceexecuteScriptde Manifest V2. Permet d'injecter du code JavaScript ou CSS dans les pages web. Nécessite deshost_permissionscorrespondantes.alarms: Permet de planifier des tâches répétitives ou uniques dans le futur, même si l'extension est inactive.notifications: Permet d'afficher des notifications système à l'utilisateur.declarativeNetRequest: API puissante pour bloquer ou modifier des requêtes réseau sans intercepter le trafic. Très performant et sécurisé.host_permissions: Permettent à votre extension d'interagir avec des ressources hébergées sur des domaines spécifiques. Cela inclut :- Effectuer des requêtes HTTP/HTTPS (via
fetchouXMLHttpRequest). - Injecter des scripts de contenu.
- Lire des cookies pour ces domaines.
- Effectuer des requêtes HTTP/HTTPS (via
Permissions "Optionnelles" ou "Runtime"
Pour minimiser le nombre de permissions demandées à l'installation, vous pouvez déclarer certaines permissions comme optionnelles. L'utilisateur peut alors choisir de les accorder ou non après l'installation, via l'interface de gestion de l'extension ou par une interaction déclenchée par votre extension.
{
"name": "Mon Extension avec Permissions Optionnelles",
"version": "1.0",
"manifest_version": 3,
"permissions": [
"storage"
],
"optional_permissions": [
"tabs",
"https://api.external.com/*"
],
"background": {
"service_worker": "background.js"
}
}
Pour demander une permission optionnelle au runtime :
// Dans un script de l'extension (ex: popup.js)
document.getElementById('requestTabsPermission').addEventListener('click', async () => {
try {
const granted = await chrome.permissions.request({
permissions: ['tabs'],
origins: ['https://api.external.com/*']
});
if (granted) {
console.log('Permissions "tabs" et "https://api.external.com/*" accordées.');
// Maintenant, vous pouvez utiliser les APIs correspondantes
} else {
console.log('Permissions refusées.');
}
} catch (error) {
console.error('Erreur lors de la demande de permissions :', error);
}
});
// Pour vérifier si une permission est déjà accordée
async function checkPermissions() {
const hasTabs = await chrome.permissions.contains({ permissions: ['tabs'] });
console.log('Possède la permission "tabs" :', hasTabs);
}
checkPermissions();
Explication du code : Ce code JavaScript montre comment demander dynamiquement des permissions optionnelles à l'utilisateur.
- Un événement de clic sur un bouton déclenche
chrome.permissions.request(), qui ouvre une boîte de dialogue au navigateur demandant à l'utilisateur d'accorder les permissions spécifiées (ici,tabset unhost_permission). - Le
awaitpermet de savoir si l'utilisateur a accordé ou refusé les permissions. chrome.permissions.contains()permet de vérifier à tout moment si une permission donnée est déjà accordée à l'extension.
Bonnes Pratiques et Considérations
- Principe du moindre privilège : Demandez uniquement les permissions absolument nécessaires au fonctionnement de votre extension. Moins de permissions = plus de confiance de l'utilisateur.
- Utilisez
activeTabquand c'est possible : Pour des actions sur l'onglet courant,activeTabest préférable àtabscar il ne donne un accès qu'au moment de l'invocation de l'extension. - Choisissez le bon stockage :
chrome.storage.syncpour les préférences utilisateur synchronisées et petites.chrome.storage.localpour les grandes quantités de données spécifiques à la machine.- Évitez
localStorageetsessionStoragepour la logique centrale de l'extension.
- Gérez les erreurs : Les opérations de stockage et de permission peuvent échouer. Utilisez des blocs
try...catchou des.catch()pour gérer ces scénarios. - Performance : Les opérations
chrome.storagesont asynchrones. Ne bloquez pas le thread principal. Pour des volumes de données très importants ou des requêtes complexes, envisagez des solutions comme IndexedDB (bien que plus complexe à implémenter). - Sécurité des données : Ne stockez jamais d'informations sensibles (mots de passe, données personnelles non cryptées) sans précautions.
chrome.storagen'est pas un mécanisme de stockage crypté. - Informez l'utilisateur : Si votre extension demande beaucoup de permissions ou des permissions spécifiques, expliquez clairement pourquoi elles sont nécessaires dans votre description sur le store ou dans votre page d'options.
Conclusion
La gestion des données persistantes et l'utilisation judicieuse des permissions sont des piliers fondamentaux pour créer des extensions de navigateur robustes, fiables et appréciées des utilisateurs.
- L'API
chrome.storageest votre allié principal pour stocker des données, offrantlocalpour les grandes quantités etsyncpour la synchronisation multi-appareils. - Les permissions, déclarées dans
manifest.json, définissent le champ d'action de votre extension. Elles sont cruciales pour la sécurité et le consentement de l'utilisateur. - Le principe du moindre privilège est votre guide : ne demandez que ce qui est strictement nécessaire, et utilisez les permissions optionnelles pour donner plus de contrôle à l'utilisateur.
En maîtrisant ces concepts, vous serez en mesure de concevoir des extensions qui non seulement répondent aux besoins fonctionnels, mais respectent également la vie privée et la sécurité de vos utilisateurs, créant ainsi une expérience positive et digne de confiance.