Skip to content

Commit

Permalink
Chromium build (init)
Browse files Browse the repository at this point in the history
  • Loading branch information
yaroslav-ilin committed Jun 15, 2024
1 parent 8abfd4c commit 1b5fb2f
Show file tree
Hide file tree
Showing 11 changed files with 387 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules/
**/*.mmdb
**/*.d.?ts
assets/chromium/
lib/**/index.mjs
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ assets/public/maxmind/GeoLite2-Country.mmdb :
curl -vL "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=${MAXMIND_LICENSE_KEY}&suffix=tar.gz" | tar --strip-components 1 -xzv -C `dirname $@`
ls -lAh `dirname $@`

assets/chromium/manifest.json : package.json
mkdir -p `dirname $@`
bun bin/manifest.ts chromium > $@

assets/chromium/service_worker.js : src/service_worker.ts
mkdir -p `dirname $@`
bun build --entrypoints src/service_worker.ts --outdir assets/chromium

.PHONY : clean
clean :
-rm assets/chromium/{manifest.json,service_worker.js}

.PHONY : distclean
distclean :
-rm assets/public/maxmind/GeoLite2-Country.mmdb
Expand Down
11 changes: 11 additions & 0 deletions assets/_locales/en/messages.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"ext_description": {
"message": "Capture The Flag — browser extension."
},
"ext_name": {
"message": "Capture The Flag"
},
"ext_short_name": {
"message": "CTF"
}
}
1 change: 1 addition & 0 deletions assets/chromium/_locales
1 change: 1 addition & 0 deletions assets/chromium/icons
17 changes: 17 additions & 0 deletions bin/manifest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { argv } from 'node:process';

import _ from 'lodash-es';

import pkg from '../package.json' with { type: 'json' };
import Manifest from '../src/manifest.ts';

if (import.meta.main) {
main();
}

function main(args = argv.slice(2)) {
const manifest = new Manifest(process.env, pkg);
const target = _.first(args) as 'firefox' | 'chromium';

console.log(manifest.render(target));
}
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@
"license": "MPL-2.0",
"type": "module",
"scripts": {
"t": "bun test --watch",
"postinstall": "make lib/maxmind"
},
"dependencies": {
"buffer": "^6.0.3",
"lodash-es": "^4.17.21",
"mmdb-lib": "^2.1.1"
},
"devDependencies": {
"@types/bun": "latest",
"@types/lodash-es": "^4.17.12",
"chrome-types": "latest",
"eslint-config-nilfalse": "github:nilfalse/eslint",
"prettier": "^3.3",
"webpack-cli": "^5.1.4"
Expand Down
167 changes: 167 additions & 0 deletions src/manifest.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import { describe, expect, it } from 'bun:test';

import Manifest from './manifest';

describe('manifest', () => {
describe('Firefox', () => {
it('should create manifest v2', async () => {
const manifest = new Manifest(
{},
{ author: 'nilfalse.com', version: '1.0.0' },
);

expect(manifest.render('firefox').split('\n')).toStrictEqual([
'{',
' "manifest_version": 2,',
' "name": "__MSG_ext_name__",',
' "short_name": "__MSG_ext_short_name__",',
' "version": "1.0.0",',
' "default_locale": "en",',
' "description": "__MSG_ext_description__",',
' "icons": {',
' "32": "icons/icon_32px.png",',
' "48": "icons/icon_48px.png",',
' "128": "icons/icon_128px.png",',
' "256": "icons/icon_256px.png",',
' "512": "icons/icon_512px.png"',
' },',
' "page_action": {',
' "default_icon": {',
' "32": "icons/icon_32px.png",',
' "48": "icons/icon_48px.png",',
' "128": "icons/icon_128px.png",',
' "256": "icons/icon_256px.png",',
' "512": "icons/icon_512px.png"',
' },',
' "default_popup": "popup.html",',
' "show_matches": [',
' "<all_urls>"',
' ]',
' },',
' "background": {},',
' "permissions": [',
' "dns",',
' "webRequest",',
' "storage"',
' ],',
' "host_permissions": [',
' "<all_urls>"',
' ],',
' "author": "nilfalse.com",',
' "browser_specific_settings": {',
' "gecko": {',
' "id": "@ctf"',
' }',
' }',
'}',
]);
});

it('should use commit hash for version when it is available', async () => {
const manifest = new Manifest(
{ GITHUB_SHA: '666e666' },
{ author: 'nilfalse.com', version: '1.0.0' },
);

expect(manifest.render('firefox').split('\n')).toStrictEqual([
'{',
' "manifest_version": 2,',
' "name": "__MSG_ext_name__",',
' "short_name": "__MSG_ext_short_name__",',
' "version": "1.0.0",',
' "version_name": "1.0.0 (666e666)",',
' "default_locale": "en",',
' "description": "__MSG_ext_description__",',
' "icons": {',
' "32": "icons/icon_32px.png",',
' "48": "icons/icon_48px.png",',
' "128": "icons/icon_128px.png",',
' "256": "icons/icon_256px.png",',
' "512": "icons/icon_512px.png"',
' },',
' "page_action": {',
' "default_icon": {',
' "32": "icons/icon_32px.png",',
' "48": "icons/icon_48px.png",',
' "128": "icons/icon_128px.png",',
' "256": "icons/icon_256px.png",',
' "512": "icons/icon_512px.png"',
' },',
' "default_popup": "popup.html",',
' "show_matches": [',
' "<all_urls>"',
' ]',
' },',
' "background": {},',
' "permissions": [',
' "dns",',
' "webRequest",',
' "storage"',
' ],',
' "host_permissions": [',
' "<all_urls>"',
' ],',
' "author": "nilfalse.com",',
' "browser_specific_settings": {',
' "gecko": {',
' "id": "@ctf"',
' }',
' }',
'}',
]);
});
});

describe('Chromium', () => {
it('should create manifest v3', async () => {
const manifest = new Manifest(
{ GITHUB_SHA: '666e666' },
{ author: 'nilfalse.com', version: '1.0.0' },
);

expect(manifest.render('chromium').split('\n')).toStrictEqual([
'{',
' "manifest_version": 3,',
' "name": "__MSG_ext_name__",',
' "short_name": "__MSG_ext_short_name__",',
' "version": "1.0.0",',
' "version_name": "1.0.0 (666e666)",',
' "default_locale": "en",',
' "description": "__MSG_ext_description__",',
' "icons": {',
' "32": "icons/icon_32px.png",',
' "48": "icons/icon_48px.png",',
' "128": "icons/icon_128px.png",',
' "256": "icons/icon_256px.png",',
' "512": "icons/icon_512px.png"',
' },',
' "action": {',
' "default_icon": {',
' "32": "icons/icon_32px.png",',
' "48": "icons/icon_48px.png",',
' "128": "icons/icon_128px.png",',
' "256": "icons/icon_256px.png",',
' "512": "icons/icon_512px.png"',
' },',
' "default_popup": "popup.html",',
' "show_matches": [',
' "<all_urls>"',
' ]',
' },',
' "background": {',
' "service_worker": "service_worker.js"',
' },',
' "permissions": [',
' "webRequest",',
' "storage",',
' "offscreen"',
' ],',
' "host_permissions": [',
' "<all_urls>"',
' ],',
' "author": "nilfalse.com"',
'}',
]);
});
});
});
100 changes: 100 additions & 0 deletions src/manifest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import _ from 'lodash-es';

export default class Manifest {
constructor(
private readonly env: Record<string, string | undefined>,
private readonly pkg: Record<string, unknown>,
) {}

get version() {
const { GITHUB_SHA } = this.env;
const { version } = this.pkg as { version: string };

return GITHUB_SHA && version + ` (${GITHUB_SHA.substring(0, 8)})`;
}

get icons() {
return {
32: 'icons/icon_32px.png',
48: 'icons/icon_48px.png',
128: 'icons/icon_128px.png',
256: 'icons/icon_256px.png',
512: 'icons/icon_512px.png',
};
}

get action() {
return {
default_icon: this.icons,
default_popup: 'popup.html',
show_matches: ['<all_urls>'],
};
}

render(target: 'firefox' | 'chromium') {
const { author, version } = this.pkg;

const manifest = {
manifest_version: undefined,

name: '__MSG_ext_name__',
short_name: '__MSG_ext_short_name__',
version,
version_name: this.version,

default_locale: 'en',
description: '__MSG_ext_description__',

icons: this.icons,

action: undefined,
page_action: undefined,

options_ui: undefined,
// {
// page: 'options.html',
// open_in_tab: false,
// },

background: {
background: undefined,
service_worker: undefined,
},

permissions: ['webRequest', 'storage'],
host_permissions: ['<all_urls>'],
author,

browser_specific_settings: undefined,
};

switch (target) {
case 'firefox':
_.set(manifest, 'manifest_version', 2);
_.set(manifest, 'page_action', this.action);
_.set(manifest, 'browser_specific_settings', {
gecko: {
id: '@ctf',
},
});

manifest.permissions.unshift('dns');

break;
case 'chromium':
_.set(manifest, 'manifest_version', 3);
_.set(manifest, 'background.service_worker', 'service_worker.js');
_.set(manifest, 'action', this.action);

manifest.permissions.push('offscreen');

break;
default:
throw new Error(
`Unknown manifest: ${target}, expected 'firefox' or 'chromium'`,
);
}

return JSON.stringify(manifest, null, 2);
}
}
44 changes: 44 additions & 0 deletions src/service_worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/// <reference lib="WebWorker" />
/// <reference types="chrome-types" />

import * as maxmind from '../lib/maxmind/index.mjs';

chrome.runtime.onInstalled.addListener((details) => {
console.log('Chrome Installing', details.reason);

if (details.reason !== 'install' && details.reason !== 'update') {
return;
}
});

const MAXMIND_URL = 'https://ctf.pages.dev/maxmind/GeoLite2-Country.mmdb';

self.addEventListener('activate', (event) => {
console.log('Activating');

event.waitUntil(
caches
.match(MAXMIND_URL)
.then(
(r) =>
r ||
caches
.open('v1')
.then((cache) => cache.addAll([MAXMIND_URL]))
.then(() => caches.match(MAXMIND_URL)),
)
.then((r) => {
console.log(r);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return r!;
})
.then(maxmind.init)
.then((reader) => {
console.log('Reader', reader);

console.log(reader.get('185.51.76.136'));
}),
);
});

declare const self: ServiceWorkerGlobalScope;
Loading

0 comments on commit 1b5fb2f

Please sign in to comment.