Skip to content

Commit 13a6761

Browse files
committed
Merge PR CorentinTh#1702: Add JavaScript Obfuscator tool
2 parents e17d97d + bc49c85 commit 13a6761

9 files changed

Lines changed: 686 additions & 56 deletions

.github/workflows/e2e-tests.yml

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,49 @@
1-
name: E2E tests
1+
name: E2E Tests
2+
23
on:
34
pull_request:
45
push:
56
branches:
67
- main
8+
79
jobs:
8-
test:
9-
timeout-minutes: 10
10+
e2e:
1011
runs-on: ubuntu-latest
11-
strategy:
12-
matrix:
13-
shard: [1/3, 2/3, 3/3]
12+
1413
steps:
15-
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
14+
- uses: actions/checkout@v4
1615

17-
- run: corepack enable
16+
- name: Enable corepack
17+
run: corepack enable
1818

19-
- uses: actions/setup-node@v3
19+
- name: Setup Node.js
20+
uses: actions/setup-node@v3
2021
with:
2122
node-version: 20
22-
cache: 'pnpm'
23-
24-
- name: Get Playwright version
25-
id: playwright-version
26-
run: echo "PLAYWRIGHT_VERSION=$(jq -r .dependencies.playwright package.json)" >> "$GITHUB_OUTPUT"
23+
cache: pnpm
2724

2825
- name: Install dependencies
2926
run: pnpm install
3027

31-
- name: Build app
28+
- name: Install system dependencies for Playwright
29+
run: |
30+
sudo apt-get update
31+
sudo apt-get install -y \
32+
libasound2t64 \
33+
libffi8 \
34+
libx264-164 \
35+
libnss3 \
36+
libatk-bridge2.0-0 \
37+
libxkbcommon0 \
38+
libgbm1 \
39+
libgtk-3-0 \
40+
libdbus-glib-1-2 || true
41+
42+
- name: Build app for E2E
3243
run: pnpm build
3344

34-
- name: Restore Playwright browsers from cache
35-
uses: actions/cache@v3
36-
with:
37-
path: ~/.cache/ms-playwright
38-
key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.PLAYWRIGHT_VERSION }}-${{ hashFiles('**/playwright.config.ts') }}
39-
restore-keys: |
40-
${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.PLAYWRIGHT_VERSION }}-
41-
${{ runner.os }}-playwright-
42-
4345
- name: Install Playwright Browsers
44-
run: pnpm exec playwright install --with-deps
46+
run: pnpm exec playwright install
4547

4648
- name: Run Playwright tests
47-
run: pnpm run test:e2e --shard=${{ matrix.shard }}
49+
run: pnpm exec playwright test

components.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ declare module '@vue/runtime-core' {
107107
Ipv4RangeExpander: typeof import('./src/tools/ipv4-range-expander/ipv4-range-expander.vue')['default']
108108
Ipv4SubnetCalculator: typeof import('./src/tools/ipv4-subnet-calculator/ipv4-subnet-calculator.vue')['default']
109109
Ipv6UlaGenerator: typeof import('./src/tools/ipv6-ula-generator/ipv6-ula-generator.vue')['default']
110+
JavascriptObfuscator: typeof import('./src/tools/javascript-obfuscator/javascript-obfuscator.vue')['default']
110111
JsonDiff: typeof import('./src/tools/json-diff/json-diff.vue')['default']
111112
JsonMinify: typeof import('./src/tools/json-minify/json-minify.vue')['default']
112113
JsonToCsv: typeof import('./src/tools/json-to-csv/json-to-csv.vue')['default']

playwright.config.ts

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,19 @@ const useWebServer = process.env.NO_WEB_SERVER !== 'true';
1010
export default defineConfig({
1111
testDir: './src',
1212
testMatch: /\.e2e\.(spec\.)?ts$/,
13-
/* Run tests in files in parallel */
1413
fullyParallel: true,
15-
/* Fail the build on CI if you accidentally left test.only in the source code. */
1614
forbidOnly: isCI,
17-
/* Retry on CI only */
1815
retries: isCI ? 2 : 0,
19-
/* Opt out of parallel tests on CI. */
2016
workers: isCI ? 1 : undefined,
21-
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
2217
reporter: 'html',
23-
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
2418
use: {
25-
/* Base URL to use in actions like `await page.goto('/')`. */
2619
baseURL: baseUrl,
27-
28-
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
2920
trace: 'on-first-retry',
30-
3121
testIdAttribute: 'data-test-id',
3222
locale: 'en-GB',
3323
timezoneId: 'Europe/Paris',
3424
},
3525

36-
/* Configure projects for major browsers */
3726
projects: [
3827
{
3928
name: 'chromium',
@@ -42,24 +31,25 @@ export default defineConfig({
4231

4332
{
4433
name: 'firefox',
45-
use: { ...devices['Desktop Firefox'] },
46-
},
47-
48-
{
49-
name: 'webkit',
50-
use: { ...devices['Desktop Safari'] },
34+
use: {
35+
...devices['Desktop Firefox'],
36+
launchOptions: {
37+
firefoxUserPrefs: {
38+
'gfx.webrender.force-disabled': true,
39+
'gfx.x11-egl.force-disabled': true,
40+
'media.hardware-video-decoding.enabled': false,
41+
'layers.acceleration.disabled': true,
42+
},
43+
},
44+
},
5145
},
5246
],
5347

54-
/* Run your local dev server before starting the tests */
55-
56-
...(useWebServer
57-
&& {
58-
webServer: {
59-
command: 'npm run preview',
60-
url: 'http://localhost:5050',
61-
reuseExistingServer: !isCI,
62-
},
63-
}
64-
),
48+
...(useWebServer && {
49+
webServer: {
50+
command: 'npm run preview',
51+
url: 'http://localhost:5050',
52+
reuseExistingServer: !isCI,
53+
},
54+
}),
6555
});

src/tools/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { tool as base64FileConverter } from './base64-file-converter';
22
import { tool as base64StringConverter } from './base64-string-converter';
33
import { tool as basicAuthGenerator } from './basic-auth-generator';
4-
import { tool as markdownPreview } from './markdown-preview';
4+
import { tool as javascriptObfuscator } from './javascript-obfuscator';
55
import { tool as emailNormalizer } from './email-normalizer';
66

77
import { tool as asciiTextDrawer } from './ascii-text-drawer';
@@ -117,7 +117,6 @@ export const toolsByCategory: ToolCategory[] = [
117117
xmlToJson,
118118
jsonToXml,
119119
markdownToHtml,
120-
markdownPreview,
121120
],
122121
},
123122
{
@@ -162,6 +161,7 @@ export const toolsByCategory: ToolCategory[] = [
162161
emailNormalizer,
163162
regexTester,
164163
regexMemo,
164+
javascriptObfuscator,
165165
],
166166
},
167167
{
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Lock } from '@vicons/tabler';
2+
import { defineTool } from '../tool';
3+
4+
export const tool = defineTool({
5+
name: 'JavaScript Obfuscator',
6+
path: '/javascript-obfuscator',
7+
description: 'Javascript code obfuscator using base64 or rot13 encoding by Forza for IT Tools',
8+
keywords: ['javascript', 'obfuscator'],
9+
component: () => import('./javascript-obfuscator.vue'),
10+
icon: Lock,
11+
createdAt: new Date('2025-12-31'),
12+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { expect, test } from '@playwright/test';
2+
3+
test.describe('Tool - JavaScript Obfuscator', () => {
4+
test.beforeEach(async ({ page }) => {
5+
await page.goto('/javascript-obfuscator');
6+
});
7+
8+
test('Has correct title', async ({ page }) => {
9+
await expect(page).toHaveTitle('JavaScript Obfuscator - IT Tools');
10+
});
11+
});
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Buffer } from 'node:buffer';
2+
import { describe, expect, it } from 'vitest';
3+
import { obfuscateJavascript } from './javascript-obfuscator.service';
4+
5+
describe('JavascriptObfuscator', () => {
6+
it('base64 encodes and wraps with atob', () => {
7+
const src = 'console.log(\'x\');';
8+
const out = obfuscateJavascript(src, 'base64');
9+
10+
expect(out).toContain('atob(\'');
11+
const m = out.match(/atob\('(.+)'\)/);
12+
expect(m).toBeTruthy();
13+
if (m) {
14+
const b64 = m[1];
15+
const decoded = decodeURIComponent(escape(Buffer.from(b64, 'base64').toString('binary')));
16+
expect(decoded).toBe(src);
17+
}
18+
});
19+
20+
it('rot13 encodes and includes runtime decoder', () => {
21+
const src = 'console.log(\'a\');';
22+
const out = obfuscateJavascript(src, 'rot13');
23+
24+
expect(out).toContain('eval(r(s))');
25+
const r = src.replace(/[A-Za-z]/g, c => String.fromCharCode((c <= 'Z' ? 65 : 97) + ((c.charCodeAt(0) - (c <= 'Z' ? 65 : 97) + 13) % 26)));
26+
expect(out).toContain(r);
27+
});
28+
});
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { get } from '@vueuse/core';
2+
import { type MaybeRef, computed } from 'vue';
3+
4+
export { obfuscateJavascript, useObfuscateJavascript };
5+
6+
function base64Encode(str: string) {
7+
// encode UTF-8 to base64
8+
return btoa(unescape(encodeURIComponent(str)));
9+
}
10+
11+
function rot13Encode(str: string) {
12+
return str.replace(/[A-Za-z]/g, c => String.fromCharCode((c <= 'Z' ? 65 : 97) + ((c.charCodeAt(0) - (c <= 'Z' ? 65 : 97) + 13) % 26)));
13+
}
14+
15+
function obfuscateJavascript(code: string, method: 'base64' | 'rot13' = 'base64'): string {
16+
if (!code) {
17+
return '';
18+
}
19+
20+
if (method === 'base64') {
21+
const b = base64Encode(code);
22+
return `(function(){eval(atob('${b}'));})();`;
23+
}
24+
25+
const r = rot13Encode(code);
26+
return `(function(s){function r(u){return u.replace(/[A-Za-z]/g,c=>String.fromCharCode((c<='Z'?65:97)+((c.charCodeAt(0)-(c<='Z'?65:97)+13)%26)))};eval(r(s))})('${r}');`;
27+
}
28+
29+
function useObfuscateJavascript(code: MaybeRef<string>, method?: MaybeRef<'base64' | 'rot13'>) {
30+
return computed(() => obfuscateJavascript(get(code), get(method) || 'base64'));
31+
}

0 commit comments

Comments
 (0)