browser-extension-manager 1.6.1 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,72 @@
1
+ # Translations
2
+
3
+ `npm run build` automatically translates `src/_locales/en/messages.json` to 16 languages via the Claude CLI. Only missing translations are generated — existing translations are preserved.
4
+
5
+ ## Languages produced
6
+
7
+ `zh`, `es`, `hi`, `ar`, `pt`, `ru`, `ja`, `de`, `fr`, `ko`, `ur`, `id`, `bn`, `tl`, `vi`, `it`
8
+
9
+ (Output written to `src/_locales/<lang>/messages.json`, then copied to `dist/_locales/` and `packaged/<browser>/raw/_locales/`.)
10
+
11
+ ## How it works
12
+
13
+ [src/gulp/tasks/translate.js](../src/gulp/tasks/translate.js):
14
+
15
+ 1. Reads `src/_locales/en/messages.json` (source of truth — author all your strings here).
16
+ 2. For each target language, reads existing `src/_locales/<lang>/messages.json` if present.
17
+ 3. Computes the set of keys present in `en` but missing (or empty) in the target language.
18
+ 4. Sends the missing keys to Claude CLI (`@anthropic-ai/claude-agent-sdk`) for translation.
19
+ 5. Merges results back into the target locale file.
20
+
21
+ Existing translations are NEVER overwritten — once a key is translated, it stays. Edit the target language file directly if you want to change a translation.
22
+
23
+ ## What gets translated
24
+
25
+ Keys with a `message` field:
26
+
27
+ ```jsonc
28
+ {
29
+ appName: {
30
+ message: 'Tabblar — Workspace & Tab Manager',
31
+ description: 'The name of the extension.'
32
+ },
33
+ appDescription: {
34
+ message: 'Powerful tab and workspace manager...',
35
+ description: 'The description of the extension.'
36
+ }
37
+ }
38
+ ```
39
+
40
+ The `description` field provides context to the translator (helps Claude pick the right translation when a word is ambiguous).
41
+
42
+ ## Manifest `__MSG_*__` placeholders
43
+
44
+ `src/manifest.json` references locale keys via `__MSG_<key>__`:
45
+
46
+ ```jsonc
47
+ {
48
+ name: '__MSG_appName__',
49
+ description: '__MSG_appDescription__',
50
+ }
51
+ ```
52
+
53
+ Chrome resolves these at install time using the user's browser locale, falling back to `default_locale` (set in the manifest).
54
+
55
+ The [test-framework.md](test-framework.md) ships a `locales.test.js` pattern that verifies every `__MSG_*__` placeholder in your manifest has a definition in `messages.json` — catches drift between manifest and i18n catalog before users see broken store listings.
56
+
57
+ ## Disabling translations
58
+
59
+ Don't want auto-translate? Either:
60
+
61
+ - Don't have `_locales/en/messages.json` (then there's nothing to translate from), or
62
+ - Set the `description` of every key to literal "no-translate" (or comparable convention — adjust `translate.js` to match), or
63
+ - Remove the `translate` task from your gulp pipeline (`gulp/main.js` invocation).
64
+
65
+ ## Cost / API key
66
+
67
+ Translations use Claude via `@anthropic-ai/claude-agent-sdk`. You'll need your Claude CLI authenticated (`claude auth`) or the SDK will fail. For most extensions, the cost is one-time per language per key change — typically pennies.
68
+
69
+ ## See also
70
+
71
+ - [build-system.md](build-system.md) — gulp pipeline including translate task
72
+ - [publishing.md](publishing.md) — auto-publishing to Chrome / Firefox / Edge stores
@@ -0,0 +1,95 @@
1
+ # XSS Prevention (ZERO TRUST — MANDATORY)
2
+
3
+ Zero tolerance for unescaped attacker-controllable strings in HTML. Extensions are especially exposed — content scripts read from arbitrary pages, popups render tab titles / URLs / favicon URLs, and all of those are attacker-controllable. Any string from outside the codebase (tab data, page DOM content, Firestore, API responses, URL params, user input) MUST be escaped before being inserted via `innerHTML`, `insertAdjacentHTML`, `outerHTML`, or attribute interpolation.
4
+
5
+ ## The Rule
6
+
7
+ **Canonical form (same as UJM/EM):** `webManager.utilities().escapeHTML(value)` inline at every usage site.
8
+
9
+ ```javascript
10
+ // ✅ CORRECT — canonical inline form
11
+ import webManager from 'web-manager';
12
+
13
+ $el.innerHTML = `<div>${webManager.utilities().escapeHTML(tab.title)}</div>`;
14
+ $el.innerHTML = `<img src="${webManager.utilities().escapeHTML(tab.favIconUrl)}" alt="">`;
15
+
16
+ // ❌ DANGEROUS — attacker-controlled favicon URL can break out of src=""
17
+ $el.innerHTML = `<img src="${tab.favIconUrl}">`;
18
+ // Malicious site serves: favIconUrl = 'x" onerror="alert(1)'
19
+ // Resulting HTML: <img src="x" onerror="alert(1)"> → executes in extension page context
20
+
21
+ // ❌ DANGEROUS — tab title can contain HTML
22
+ $el.innerHTML = `<h1>${tab.title}</h1>`;
23
+ ```
24
+
25
+ **Common extension XSS vectors:**
26
+
27
+ - `tab.title`, `tab.url`, `tab.favIconUrl` from `chrome.tabs.query/get` — any visited page can set these.
28
+ - DOM content read by content scripts and sent back to privileged pages (popup/options/sidepanel).
29
+ - Bookmark titles, history entries, recently-closed tabs — all originate from arbitrary pages.
30
+ - Stored user data (snippets, saved workspaces) if a malicious page can influence what gets stored.
31
+
32
+ ## NEVER Write Your Own Escape Function
33
+
34
+ Do NOT:
35
+
36
+ - Alias: `const escape = webManager.utilities().escapeHTML;`
37
+ - Wrap: `const escape = (s) => webManager.utilities().escapeHTML(s);`
38
+ - Destructure: `const { escapeHTML } = webManager.utilities();`
39
+ - `.bind()` it
40
+ - Define a local `escapeHtml`/`escapeHTML` helper in a `utils.js` and import it across files — this is the most common violation in BXM extensions. Delete the helper, add `import webManager from 'web-manager'`, inline the canonical form at every call site.
41
+
42
+ ## URLs Must Also Be Sanitized
43
+
44
+ `escapeHTML` alone lets `javascript:alert(1)` through — dynamic URLs in executable sinks MUST also be wrapped in `webManager.utilities().sanitizeURL(url)`, which returns `''` for any non-`http:`/`https:` protocol (blocks `javascript:`, `data:`, `vbscript:`). Extensions often build UI from `tab.url` — a malicious page can set a `javascript:` URL that executes when clicked in the popup.
45
+
46
+ **Must sanitize (can execute JS):**
47
+
48
+ - `<a href>`, `<area href>`, `<base href>`
49
+ - `<iframe src>`
50
+ - `<form action>`, `formaction`
51
+ - `<object data>`
52
+ - `<script src>` (don't do dynamically)
53
+ - SVG `href` / `xlink:href`
54
+ - Property assignments: `.href =`, `.src =` (on above elements), `window.location =`, `location.href =`, `location.replace()`, `location.assign()`, `window.open()`, `extension.tabs.create({ url })` if `url` is dynamic
55
+
56
+ **Do NOT need to sanitize:**
57
+
58
+ - `<img src>`, `<video src>`, `<audio src>`, media `src`/`poster` — browsers ignore `javascript:` in media
59
+ - `<link href>` stylesheets
60
+ - Hardcoded paths
61
+
62
+ **Nesting:** sanitize first, then escape for HTML attributes. No escape needed for direct property assignment.
63
+
64
+ ```javascript
65
+ // ✅ CORRECT — href in innerHTML (dynamic URL)
66
+ $el.innerHTML = `<a href="${webManager.utilities().escapeHTML(webManager.utilities().sanitizeURL(tab.url))}">${webManager.utilities().escapeHTML(tab.title)}</a>`;
67
+
68
+ // ✅ CORRECT — property assignment
69
+ $link.href = webManager.utilities().sanitizeURL(tab.url);
70
+ extension.tabs.create({ url: webManager.utilities().sanitizeURL(tab.url) });
71
+
72
+ // ❌ WRONG — escape alone lets `javascript:alert(1)` through
73
+ `<a href="${webManager.utilities().escapeHTML(tab.url)}">...</a>`
74
+ ```
75
+
76
+ ## Do NOT Escape Values Passed to textContent-Based APIs
77
+
78
+ `escapeHTML()` passes non-strings through unchanged — numbers, booleans, `null`, `undefined` come out exactly as they went in. Wrapping these is pure ceremony; it doesn't improve safety and adds reading cost. Don't escape:
79
+
80
+ - **Numbers, booleans, `null`, `undefined`** — `tabs.length`, `Date.now()`, flags.
81
+ - **`String(number)` coercion before escaping** — `escapeHTML(String(n))` is doubly redundant. Just interpolate: `${n}`.
82
+ - **Values from hardcoded maps/enums** — `STATUS_LABELS[key]`, icon-name literals, static SVG data URLs.
83
+ - **Framework-formatted strings** — `date.toLocaleDateString()`, `num.toFixed(2)`.
84
+
85
+ Safe by context (regardless of value):
86
+
87
+ - `textContent`, `.value`, `.placeholder` property assignments
88
+ - `setAttribute()` calls
89
+ - `webManager.utilities().showNotification(...)` — uses textContent internally; pre-escaping causes `'` → `&#039;` double-encoding visible to users.
90
+
91
+ ## See also
92
+
93
+ - [components.md](components.md) — component architecture (where these strings get rendered)
94
+ - [common-mistakes.md](common-mistakes.md) — the local-helper violation is mistake #1
95
+ - `web-manager/src/modules/utilities.js` — the `escapeHTML` / `sanitizeURL` implementations
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browser-extension-manager",
3
- "version": "1.6.1",
3
+ "version": "1.7.0",
4
4
  "description": "Browser Extension Manager dependency manager",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
@@ -34,7 +34,10 @@
34
34
  "mgr": "bin/browser-extension-manager"
35
35
  },
36
36
  "files": [
37
- "dist"
37
+ "dist/",
38
+ "bin/",
39
+ "docs/",
40
+ "CLAUDE.md"
38
41
  ],
39
42
  "preparePackage": {
40
43
  "input": "./src",