Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: CI

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

jobs:
test:
name: Lint & Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- run: npm ci

- name: Lint
run: npm run lint

- name: Test
run: npm test

# Bonus: validate manifest.json is parseable and the extension can
# be packaged (catches mistakes that would only show up at install time).
- name: Validate manifest
run: node -e "JSON.parse(require('fs').readFileSync('manifest.json', 'utf8')); console.log('manifest.json OK')"
66 changes: 66 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Release

on:
push:
tags:
- 'v*.*.*'

permissions:
contents: write

jobs:
package:
name: Package extension and draft release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- run: npm ci

- name: Lint & test before packaging
run: npm run ci

- name: Verify tag matches manifest version
run: |
TAG="${GITHUB_REF#refs/tags/v}"
MANIFEST_VERSION=$(node -e "console.log(require('./manifest.json').version)")
if [ "$TAG" != "$MANIFEST_VERSION" ]; then
echo "::error::Tag v$TAG does not match manifest version $MANIFEST_VERSION"
exit 1
fi
echo "Tag and manifest version match: $TAG"

- name: Build extension zip
run: |
ZIP_NAME="DIMA_Plugin_Chrome-${GITHUB_REF#refs/tags/v}.zip"
echo "ZIP_NAME=$ZIP_NAME" >> "$GITHUB_ENV"
# We only ship the runtime files — no node_modules, no tests, no CI.
zip -r "$ZIP_NAME" \
manifest.json \
content.js \
modules/ \
data/ \
documentation/ \
README.md \
LICENSE \
M82-logo-16.png M82-logo-48.png M82-logo-128.png \
-x "*.DS_Store"

- name: Upload zip as workflow artifact
uses: actions/upload-artifact@v4
with:
name: ${{ env.ZIP_NAME }}
path: ${{ env.ZIP_NAME }}

- name: Create draft GitHub release
uses: softprops/action-gh-release@v2
with:
draft: true
generate_release_notes: true
files: ${{ env.ZIP_NAME }}
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules/
coverage/
dist/
*.log
.DS_Store
.vscode/
.idea/
78 changes: 78 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import globals from 'globals';

export default [
{
ignores: ['node_modules/**', 'coverage/**', 'dist/**'],
},
// Source: content scripts run in the browser, share globals via window.X = X.
// Most cross-file references go through `window.X`, but a few files use the
// bare global name (e.g. `if (typeof copycopDomains !== 'undefined')`), so
// we treat the data exports as readable globals at the project scope.
// We do NOT list the same names in `globals` AND let the source files
// redeclare them with `const` — that would trip no-redeclare; instead we
// rely on each declaration being the canonical one and disable no-redeclare.
{
files: ['content.js', 'modules/**/*.js', 'data/**/*.js'],
languageOptions: {
ecmaVersion: 2022,
sourceType: 'script',
globals: {
...globals.browser,
chrome: 'readonly',
browser: 'readonly',
module: 'readonly',
},
},
rules: {
'no-unused-vars': [
'warn',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrors: 'none',
},
],
// `const fooDomains = [...]` at top-level is read across files via the
// shared global object — we can't predeclare them without redeclare.
// Detection of typos relies on the test suite rather than this rule.
'no-undef': 'off',
'no-redeclare': 'off',
'no-console': 'off',
'no-empty': ['warn', { allowEmptyCatch: true }],
eqeqeq: ['warn', 'smart'],
'no-implicit-globals': 'off',
},
},
// Tests + tooling: Node + Vitest globals.
{
files: ['tests/**/*.js', 'vitest.config.js', 'eslint.config.js'],
languageOptions: {
ecmaVersion: 2022,
sourceType: 'module',
globals: {
...globals.node,
...globals.browser,
// Vitest globals (test, expect, describe, beforeAll, beforeEach, etc.).
describe: 'readonly',
it: 'readonly',
test: 'readonly',
expect: 'readonly',
beforeAll: 'readonly',
afterAll: 'readonly',
beforeEach: 'readonly',
afterEach: 'readonly',
vi: 'readonly',
},
},
rules: {
'no-unused-vars': [
'warn',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrors: 'none',
},
],
},
},
];
17 changes: 13 additions & 4 deletions modules/Suspicioussitesmanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,11 @@ class SuspiciousSitesManager {
this.log(` ✓ Source laundromat chargée: ${laundromatDomains.length} domaines`);
}

// Avertissement si aucune source n'est chargée
if (this.sources.size === 0) {
// Avertissement si aucune source n'est chargée. Gardé derrière le flag
// debug : c'est une condition "configuration" (l'ordre de chargement
// dans manifest.json est incorrect) et non un signal qui doit polluer
// chaque console de page hôte.
if (this.sources.size === 0 && this.debug) {
console.warn('⚠️ DIMA: Aucune base de données de sites suspects n\'a été chargée');
console.warn(' Vérifiez que les fichiers de bases de données sont correctement chargés avant ce gestionnaire');
}
Expand All @@ -198,8 +201,8 @@ class SuspiciousSitesManager {
*/
aggregateAllSites() {
this.allSites = [];
for (const [sourceName, sourceData] of this.sources) {

for (const [, sourceData] of this.sources) {
this.allSites.push(...sourceData.domains);
}
}
Expand Down Expand Up @@ -577,6 +580,12 @@ class SuspiciousSitesManager {
// pendant laquelle `window.checkSuspiciousSite` n'existait pas, forçant
// content.js à boucler sur ses retries pendant >=100ms à chaque page.
if (typeof window !== 'undefined') {
// Expose la classe (utile pour les tests et pour le rechargement à chaud)
window.SuspiciousSitesManager = SuspiciousSitesManager;

// Init synchrone: en MV3 avec `run_at: document_end` et l'ordre déclaré
// dans manifest.json, toutes les bases (copycopDomains, ...) sont déjà
// chargées à ce point. Pas besoin de différer.
const suspiciousSitesManager = new SuspiciousSitesManager();

// Rendre disponible globalement
Expand Down
Loading
Loading