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
|
||||
Your blockchain powered Agent to help with your trading emotions
|
||||
# Osias — copilot
|
||||
|
||||
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.
|
||||
const INTERCEPTED_EVENT_TYPES = ['pointerdown', 'mousedown', 'mouseup', 'click'] as const;
|
||||
|
||||
const LOCK_ICON_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>';
|
||||
const SVG_NS = 'http://www.w3.org/2000/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
|
||||
// would recomposite the container's entire subtree — including the lock
|
||||
@@ -80,7 +105,7 @@ export const blurDisable: Intervention = {
|
||||
const overlay = document.createElement('div');
|
||||
overlay.dataset.osiasOverlay = 'true';
|
||||
overlay.style.cssText = OVERLAY_STYLE;
|
||||
overlay.innerHTML = LOCK_ICON_SVG;
|
||||
overlay.appendChild(createLockIcon());
|
||||
|
||||
const onOverlayEvent = (event: Event) => {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -54,22 +54,35 @@ function ensureToast(): HTMLElement {
|
||||
|
||||
el = document.createElement('div');
|
||||
el.id = TOAST_ID;
|
||||
el.innerHTML = `
|
||||
<div class="osias-toast-icon">🔒</div>
|
||||
<div class="osias-toast-body">
|
||||
<div class="osias-toast-title">Osias: buying locked</div>
|
||||
<div class="osias-toast-reason"></div>
|
||||
<div class="osias-toast-action">View details</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const icon = document.createElement('div');
|
||||
icon.className = 'osias-toast-icon';
|
||||
icon.textContent = '🔒';
|
||||
|
||||
const body = document.createElement('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
|
||||
// timer below) or when the lock state actually changes; clicking it never
|
||||
// unlocks anything.
|
||||
el.querySelector('.osias-toast-action')?.addEventListener('click', () => {
|
||||
action.addEventListener('click', () => {
|
||||
const message: OsiasMessage = { type: 'osias:open-popup' };
|
||||
browser.runtime.sendMessage(message).catch(() => undefined);
|
||||
});
|
||||
|
||||
body.append(title, reasonEl, action);
|
||||
el.append(icon, body);
|
||||
|
||||
document.body.appendChild(el);
|
||||
return el;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,17 @@ export default defineConfig({
|
||||
gecko: {
|
||||
// Placeholder id for local/dev builds; replace before publishing to AMO.
|
||||
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