feat(browser-ext): move browser extension to browser-ext/ and update API client to tRPC
- Create browser-ext/ with full extension code (MV3 manifest, background service worker, content script, popup, options page) - Add tRPC API client that communicates with unified monolith endpoints - Implement cache, settings, and phishing detection utilities - Create extension tRPC router in web app (getAuthStatus, linkDevice, reportPhishing) - Configure Vite build with manifest V3 support - Write unit tests for cache, phishing detector, and API client - All 20 tests passing, TypeScript lint clean
This commit is contained in:
80
browser-ext/scripts/generate-icons.mjs
Normal file
80
browser-ext/scripts/generate-icons.mjs
Normal file
@@ -0,0 +1,80 @@
|
||||
import { writeFileSync, mkdirSync } from "fs";
|
||||
import { resolve } from "path";
|
||||
import { deflateSync } from "zlib";
|
||||
|
||||
const __dirname = import.meta.dirname;
|
||||
const iconsDir = resolve(__dirname, "../public/icons");
|
||||
mkdirSync(iconsDir, { recursive: true });
|
||||
|
||||
function crc32(buf) {
|
||||
let crc = 0xffffffff;
|
||||
const table = new Int32Array(256);
|
||||
for (let i = 0; i < 256; i++) {
|
||||
let c = i;
|
||||
for (let j = 0; j < 8; j++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
||||
table[i] = c;
|
||||
}
|
||||
for (let i = 0; i < buf.length; i++) crc = table[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);
|
||||
return (crc ^ 0xffffffff) >>> 0;
|
||||
}
|
||||
|
||||
function chunk(type, data) {
|
||||
const len = Buffer.alloc(4);
|
||||
len.writeUInt32BE(data.length);
|
||||
const typeB = Buffer.from(type, "ascii");
|
||||
const crcData = Buffer.concat([typeB, data]);
|
||||
const crcV = Buffer.alloc(4);
|
||||
crcV.writeUInt32BE(crc32(crcData));
|
||||
return Buffer.concat([len, typeB, data, crcV]);
|
||||
}
|
||||
|
||||
function createPNG(size) {
|
||||
const raw = Buffer.alloc(size * size * 4);
|
||||
const cx = size / 2;
|
||||
const cy = size / 2;
|
||||
const r = size * 0.42;
|
||||
|
||||
for (let y = 0; y < size; y++) {
|
||||
for (let x = 0; x < size; x++) {
|
||||
const dx = x - cx;
|
||||
const dy = y - cy;
|
||||
const dist = Math.sqrt(dx * dx + dy * dy);
|
||||
const i = (y * size + x) * 4;
|
||||
if (dist <= r) {
|
||||
raw[i] = 99;
|
||||
raw[i + 1] = 102;
|
||||
raw[i + 2] = 241;
|
||||
raw[i + 3] = 255;
|
||||
} else {
|
||||
raw[i] = 0;
|
||||
raw[i + 1] = 0;
|
||||
raw[i + 2] = 0;
|
||||
raw[i + 3] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const filter = Buffer.alloc(size * size + size);
|
||||
for (let y = 0; y < size; y++) {
|
||||
filter[y * (size * 4 + 1)] = 0;
|
||||
raw.copy(filter, y * (size * 4 + 1) + 1, y * size * 4, (y + 1) * size * 4);
|
||||
}
|
||||
|
||||
const compressed = deflateSync(filter);
|
||||
const ihdr = Buffer.alloc(13);
|
||||
ihdr.writeUInt32BE(size, 0);
|
||||
ihdr.writeUInt32BE(size, 4);
|
||||
ihdr[8] = 8;
|
||||
ihdr[9] = 6;
|
||||
ihdr[10] = 0;
|
||||
ihdr[11] = 0;
|
||||
ihdr[12] = 0;
|
||||
|
||||
const sig = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
||||
return Buffer.concat([sig, chunk("IHDR", ihdr), chunk("IDAT", compressed), chunk("IEND", Buffer.alloc(0))]);
|
||||
}
|
||||
|
||||
for (const size of [16, 48, 128]) {
|
||||
writeFileSync(resolve(iconsDir, `icon-${size}.png`), createPNG(size));
|
||||
console.log(`Created icon-${size}.png`);
|
||||
}
|
||||
Reference in New Issue
Block a user