Fix AMO submission requirements: data collection permissions, innerHTML lint, source README
- Declare data_collection_permissions in browser_specific_settings.gecko (Firefox 140+/AMO validation requirement) to reflect wallet address, auth signature, and trading-identity data sent to the backend. - Replace innerHTML assignments in blur-disable.ts and toast.ts with DOM construction (createElementNS/createElement) to clear the AMO linter's unsafe-innerHTML warning on content.js. - Add build instructions to README.md for AMO's source code submission requirement, triggered by WXT/Vite's bundling and minification. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01HoMzqFw3d93hG6c9xB4thU
This commit is contained in:
@@ -1,2 +1,42 @@
|
|||||||
# copilot
|
# Osias — copilot
|
||||||
Your blockchain powered Agent to help with your trading emotions
|
|
||||||
|
Your blockchain-powered trading companion. This is the open-source browser extension
|
||||||
|
frontend (Apache License 2.0). See [`CLAUDE.md`](CLAUDE.md) for full architecture and
|
||||||
|
protocol documentation.
|
||||||
|
|
||||||
|
## Build instructions
|
||||||
|
|
||||||
|
Built with [WXT](https://wxt.dev) (Vite-based). To reproduce the exact `.output/firefox-mv3`
|
||||||
|
bundle submitted to addons.mozilla.org from source:
|
||||||
|
|
||||||
|
**Environment**
|
||||||
|
- Node.js 22.x (built and tested on 22.11.0)
|
||||||
|
- npm 11.x (built and tested on 11.14.1)
|
||||||
|
|
||||||
|
**Steps**
|
||||||
|
```sh
|
||||||
|
npm install # also runs `wxt prepare` via postinstall
|
||||||
|
npm run build:firefox
|
||||||
|
```
|
||||||
|
|
||||||
|
Output is written to `.output/firefox-mv3/`. To produce the uploaded `.zip` directly:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run zip:firefox
|
||||||
|
```
|
||||||
|
|
||||||
|
Output zip is written to `.output/`.
|
||||||
|
|
||||||
|
No build secrets, environment variables, or private dependencies are required — everything
|
||||||
|
needed to build is in this repository and on the public npm registry, pinned via
|
||||||
|
`package-lock.json`.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
- `npm run dev:firefox` — dev build + watch targeting Firefox/Zen, auto-opens a temporary
|
||||||
|
profile with the extension loaded.
|
||||||
|
- `npm run compile` — `tsc --noEmit` type-check only.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Apache License 2.0 — see [`LICENSE`](LICENSE).
|
||||||
|
|||||||
@@ -17,8 +17,33 @@ const locked = new WeakMap<HTMLElement, LockedRecord>();
|
|||||||
// reason toast is surfaced on `click` once the gesture completes.
|
// reason toast is surfaced on `click` once the gesture completes.
|
||||||
const INTERCEPTED_EVENT_TYPES = ['pointerdown', 'mousedown', 'mouseup', 'click'] as const;
|
const INTERCEPTED_EVENT_TYPES = ['pointerdown', 'mousedown', 'mouseup', 'click'] as const;
|
||||||
|
|
||||||
const LOCK_ICON_SVG =
|
const SVG_NS = 'http://www.w3.org/2000/svg';
|
||||||
'<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="10" width="16" height="10" rx="2"></rect><path d="M8 10V7a4 4 0 0 1 8 0v3"></path></svg>';
|
|
||||||
|
function createLockIcon(): SVGSVGElement {
|
||||||
|
const svg = document.createElementNS(SVG_NS, 'svg');
|
||||||
|
svg.setAttribute('viewBox', '0 0 24 24');
|
||||||
|
svg.setAttribute('width', '16');
|
||||||
|
svg.setAttribute('height', '16');
|
||||||
|
svg.setAttribute('fill', 'none');
|
||||||
|
svg.setAttribute('stroke', 'currentColor');
|
||||||
|
svg.setAttribute('stroke-width', '2');
|
||||||
|
svg.setAttribute('stroke-linecap', 'round');
|
||||||
|
svg.setAttribute('stroke-linejoin', 'round');
|
||||||
|
|
||||||
|
const rect = document.createElementNS(SVG_NS, 'rect');
|
||||||
|
rect.setAttribute('x', '4');
|
||||||
|
rect.setAttribute('y', '10');
|
||||||
|
rect.setAttribute('width', '16');
|
||||||
|
rect.setAttribute('height', '10');
|
||||||
|
rect.setAttribute('rx', '2');
|
||||||
|
svg.appendChild(rect);
|
||||||
|
|
||||||
|
const path = document.createElementNS(SVG_NS, 'path');
|
||||||
|
path.setAttribute('d', 'M8 10V7a4 4 0 0 1 8 0v3');
|
||||||
|
svg.appendChild(path);
|
||||||
|
|
||||||
|
return svg;
|
||||||
|
}
|
||||||
|
|
||||||
// `backdrop-filter` (not `filter`) is deliberate: `filter` on the container
|
// `backdrop-filter` (not `filter`) is deliberate: `filter` on the container
|
||||||
// would recomposite the container's entire subtree — including the lock
|
// would recomposite the container's entire subtree — including the lock
|
||||||
@@ -80,7 +105,7 @@ export const blurDisable: Intervention = {
|
|||||||
const overlay = document.createElement('div');
|
const overlay = document.createElement('div');
|
||||||
overlay.dataset.osiasOverlay = 'true';
|
overlay.dataset.osiasOverlay = 'true';
|
||||||
overlay.style.cssText = OVERLAY_STYLE;
|
overlay.style.cssText = OVERLAY_STYLE;
|
||||||
overlay.innerHTML = LOCK_ICON_SVG;
|
overlay.appendChild(createLockIcon());
|
||||||
|
|
||||||
const onOverlayEvent = (event: Event) => {
|
const onOverlayEvent = (event: Event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|||||||
@@ -54,22 +54,35 @@ function ensureToast(): HTMLElement {
|
|||||||
|
|
||||||
el = document.createElement('div');
|
el = document.createElement('div');
|
||||||
el.id = TOAST_ID;
|
el.id = TOAST_ID;
|
||||||
el.innerHTML = `
|
|
||||||
<div class="osias-toast-icon">🔒</div>
|
const icon = document.createElement('div');
|
||||||
<div class="osias-toast-body">
|
icon.className = 'osias-toast-icon';
|
||||||
<div class="osias-toast-title">Osias: buying locked</div>
|
icon.textContent = '🔒';
|
||||||
<div class="osias-toast-reason"></div>
|
|
||||||
<div class="osias-toast-action">View details</div>
|
const body = document.createElement('div');
|
||||||
</div>
|
body.className = 'osias-toast-body';
|
||||||
`;
|
|
||||||
|
const title = document.createElement('div');
|
||||||
|
title.className = 'osias-toast-title';
|
||||||
|
title.textContent = 'Osias: buying locked';
|
||||||
|
|
||||||
|
const reasonEl = document.createElement('div');
|
||||||
|
reasonEl.className = 'osias-toast-reason';
|
||||||
|
|
||||||
|
const action = document.createElement('div');
|
||||||
|
action.className = 'osias-toast-action';
|
||||||
|
action.textContent = 'View details';
|
||||||
// No manual close button — the toast only goes away on its own (auto-hide
|
// No manual close button — the toast only goes away on its own (auto-hide
|
||||||
// timer below) or when the lock state actually changes; clicking it never
|
// timer below) or when the lock state actually changes; clicking it never
|
||||||
// unlocks anything.
|
// unlocks anything.
|
||||||
el.querySelector('.osias-toast-action')?.addEventListener('click', () => {
|
action.addEventListener('click', () => {
|
||||||
const message: OsiasMessage = { type: 'osias:open-popup' };
|
const message: OsiasMessage = { type: 'osias:open-popup' };
|
||||||
browser.runtime.sendMessage(message).catch(() => undefined);
|
browser.runtime.sendMessage(message).catch(() => undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
body.append(title, reasonEl, action);
|
||||||
|
el.append(icon, body);
|
||||||
|
|
||||||
document.body.appendChild(el);
|
document.body.appendChild(el);
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,17 @@ export default defineConfig({
|
|||||||
gecko: {
|
gecko: {
|
||||||
// Placeholder id for local/dev builds; replace before publishing to AMO.
|
// Placeholder id for local/dev builds; replace before publishing to AMO.
|
||||||
id: '[email protected]',
|
id: '[email protected]',
|
||||||
|
// Firefox-required data collection disclosure (Firefox 140+ / AMO
|
||||||
|
// validation). Reflects what the extension actually transmits to the
|
||||||
|
// backend: wallet address + signature during Phantom sign-in
|
||||||
|
// (authenticationInfo, personallyIdentifyingInfo), and the wallet
|
||||||
|
// identity that ties the account to on-chain trading activity
|
||||||
|
// (financialAndPaymentInfo). See copilot/CLAUDE.md's "Backend
|
||||||
|
// connection" and "Wallet auth" sections.
|
||||||
|
data_collection_permissions: {
|
||||||
|
required: ['authenticationInfo', 'personallyIdentifyingInfo', 'financialAndPaymentInfo'],
|
||||||
|
optional: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user