Files
AutistMask/src/content/inpage.js
user 27f16191b4
Some checks failed
check / check (push) Failing after 13s
fix(L4): use location.origin for postMessage, one-shot UUID listener
- Content script sends UUID via location.origin instead of "*"
- Inpage UUID listener removes itself after first message to prevent
  malicious pages from overriding the persisted UUID
2026-02-27 11:58:57 -08:00

193 lines
6.0 KiB
JavaScript

// AutistMask inpage script — injected into the page's JS context.
// Creates window.ethereum (EIP-1193 provider) and announces via EIP-6963.
(function () {
const CHAIN_ID = "0x1"; // Ethereum mainnet
const listeners = {};
let nextId = 1;
const pending = {};
// Listen for responses from the content script
window.addEventListener("message", function onUuid(event) {
if (event.source !== window) return;
if (event.data?.type !== "AUTISTMASK_RESPONSE") return;
const { id, result, error } = event.data;
const p = pending[id];
if (!p) return;
delete pending[id];
if (error) {
p.reject(new Error(error.message || "Request failed"));
} else {
p.resolve(result);
}
});
// Listen for events pushed from the extension
window.addEventListener("message", function onUuid(event) {
if (event.source !== window) return;
if (event.data?.type !== "AUTISTMASK_EVENT") return;
const { eventName, data } = event.data;
emit(eventName, data);
});
function emit(eventName, data) {
const cbs = listeners[eventName];
if (!cbs) return;
for (const cb of cbs) {
try {
cb(data);
} catch (e) {
// ignore listener errors
}
}
}
function sendRequest(args) {
return new Promise((resolve, reject) => {
const id = nextId++;
pending[id] = { resolve, reject };
window.postMessage(
{ type: "AUTISTMASK_REQUEST", id, ...args },
"*",
);
});
}
const provider = {
isAutistMask: true,
isMetaMask: true, // compatibility — many dApps check this
chainId: CHAIN_ID,
networkVersion: "1",
selectedAddress: null,
async request(args) {
const result = await sendRequest({
method: args.method,
params: args.params || [],
});
if (
args.method === "eth_requestAccounts" ||
args.method === "eth_accounts"
) {
provider.selectedAddress =
Array.isArray(result) && result.length > 0
? result[0]
: null;
}
return result;
},
// Legacy methods (still used by some dApps)
enable() {
return this.request({ method: "eth_requestAccounts" });
},
send(methodOrPayload, paramsOrCallback) {
// Handle both send(method, params) and send({method, params})
if (typeof methodOrPayload === "string") {
return this.request({
method: methodOrPayload,
params: paramsOrCallback || [],
});
}
return this.request({
method: methodOrPayload.method,
params: methodOrPayload.params || [],
});
},
sendAsync(payload, callback) {
this.request({
method: payload.method,
params: payload.params || [],
})
.then((result) =>
callback(null, { id: payload.id, jsonrpc: "2.0", result }),
)
.catch((err) => callback(err));
},
on(event, cb) {
if (!listeners[event]) listeners[event] = [];
listeners[event].push(cb);
return this;
},
removeListener(event, cb) {
if (!listeners[event]) return this;
listeners[event] = listeners[event].filter((c) => c !== cb);
return this;
},
removeAllListeners(event) {
if (event) {
delete listeners[event];
} else {
for (const key of Object.keys(listeners)) {
delete listeners[key];
}
}
return this;
},
// Some dApps (wagmi) check this to confirm MetaMask-like behavior
_metamask: {
isUnlocked() {
return Promise.resolve(provider.selectedAddress !== null);
},
},
};
// Set window.ethereum if no other wallet has claimed it
if (typeof window.ethereum === "undefined") {
window.ethereum = provider;
}
window.dispatchEvent(new Event("ethereum#initialized"));
// EIP-6963: Multi Injected Provider Discovery
const ICON_SVG =
"data:image/svg+xml," +
encodeURIComponent(
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">' +
'<rect width="32" height="32" rx="6" fill="#000"/>' +
'<text x="16" y="23" text-anchor="middle" font-family="monospace" font-size="20" font-weight="bold" fill="#fff">A</text>' +
"</svg>",
);
let providerUuid = crypto.randomUUID(); // fallback until real UUID arrives
function buildProviderInfo() {
return {
uuid: providerUuid,
name: "AutistMask",
icon: ICON_SVG,
rdns: "berlin.sneak.autistmask",
};
}
function announceProvider() {
window.dispatchEvent(
new CustomEvent("eip6963:announceProvider", {
detail: Object.freeze({
info: buildProviderInfo(),
provider,
}),
}),
);
}
// Listen for the persisted UUID from the content script
function onProviderUuid(event) {
if (event.source !== window) return;
if (event.data?.type !== "AUTISTMASK_PROVIDER_UUID") return;
window.removeEventListener("message", onProviderUuid);
providerUuid = event.data.uuid;
announceProvider();
}
window.addEventListener("message", onProviderUuid);
window.addEventListener("eip6963:requestProvider", announceProvider);
announceProvider();
})();