Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 28 additions & 26 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
@@ -1,47 +1,49 @@
name: E2E tests
name: E2E Tests

on:
pull_request:
push:
branches:
- main

jobs:
test:
timeout-minutes: 10
e2e:
runs-on: ubuntu-latest
strategy:
matrix:
shard: [1/3, 2/3, 3/3]

steps:
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
- uses: actions/checkout@v4

- run: corepack enable
- name: Enable corepack
run: corepack enable

- uses: actions/setup-node@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 20
cache: 'pnpm'

- name: Get Playwright version
id: playwright-version
run: echo "PLAYWRIGHT_VERSION=$(jq -r .dependencies.playwright package.json)" >> "$GITHUB_OUTPUT"
cache: pnpm

- name: Install dependencies
run: pnpm install

- name: Build app
- name: Install system dependencies for Playwright
run: |
sudo apt-get update
sudo apt-get install -y \
libasound2t64 \
libffi8 \
libx264-164 \
libnss3 \
libatk-bridge2.0-0 \
libxkbcommon0 \
libgbm1 \
libgtk-3-0 \
libdbus-glib-1-2 || true

- name: Build app for E2E
run: pnpm build

- name: Restore Playwright browsers from cache
uses: actions/cache@v3
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.PLAYWRIGHT_VERSION }}-${{ hashFiles('**/playwright.config.ts') }}
restore-keys: |
${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.PLAYWRIGHT_VERSION }}-
${{ runner.os }}-playwright-

- name: Install Playwright Browsers
run: pnpm exec playwright install --with-deps
run: pnpm exec playwright install

- name: Run Playwright tests
run: pnpm run test:e2e --shard=${{ matrix.shard }}
run: pnpm exec playwright test
1 change: 1 addition & 0 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ declare module '@vue/runtime-core' {
Ipv4RangeExpander: typeof import('./src/tools/ipv4-range-expander/ipv4-range-expander.vue')['default']
Ipv4SubnetCalculator: typeof import('./src/tools/ipv4-subnet-calculator/ipv4-subnet-calculator.vue')['default']
Ipv6UlaGenerator: typeof import('./src/tools/ipv6-ula-generator/ipv6-ula-generator.vue')['default']
JavascriptObfuscator: typeof import('./src/tools/javascript-obfuscator/javascript-obfuscator.vue')['default']
JsonDiff: typeof import('./src/tools/json-diff/json-diff.vue')['default']
JsonMinify: typeof import('./src/tools/json-minify/json-minify.vue')['default']
JsonToCsv: typeof import('./src/tools/json-to-csv/json-to-csv.vue')['default']
Expand Down
46 changes: 18 additions & 28 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,19 @@ const useWebServer = process.env.NO_WEB_SERVER !== 'true';
export default defineConfig({
testDir: './src',
testMatch: /\.e2e\.(spec\.)?ts$/,
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: isCI,
/* Retry on CI only */
retries: isCI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: isCI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: baseUrl,

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',

testIdAttribute: 'data-test-id',
locale: 'en-GB',
timezoneId: 'Europe/Paris',
},

/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
Expand All @@ -42,24 +31,25 @@ export default defineConfig({

{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},

{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
use: {
...devices['Desktop Firefox'],
launchOptions: {
firefoxUserPrefs: {
'gfx.webrender.force-disabled': true,
'gfx.x11-egl.force-disabled': true,
'media.hardware-video-decoding.enabled': false,
'layers.acceleration.disabled': true,
},
},
},
},
],

/* Run your local dev server before starting the tests */

...(useWebServer
&& {
webServer: {
command: 'npm run preview',
url: 'http://localhost:5050',
reuseExistingServer: !isCI,
},
}
),
...(useWebServer && {
webServer: {
command: 'npm run preview',
url: 'http://localhost:5050',
reuseExistingServer: !isCI,
},
}),
});
2 changes: 2 additions & 0 deletions src/tools/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { tool as base64FileConverter } from './base64-file-converter';
import { tool as base64StringConverter } from './base64-string-converter';
import { tool as basicAuthGenerator } from './basic-auth-generator';
import { tool as javascriptObfuscator } from './javascript-obfuscator';
import { tool as emailNormalizer } from './email-normalizer';

import { tool as asciiTextDrawer } from './ascii-text-drawer';
Expand Down Expand Up @@ -160,6 +161,7 @@ export const toolsByCategory: ToolCategory[] = [
emailNormalizer,
regexTester,
regexMemo,
javascriptObfuscator,
],
},
{
Expand Down
12 changes: 12 additions & 0 deletions src/tools/javascript-obfuscator/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Lock } from '@vicons/tabler';
import { defineTool } from '../tool';

export const tool = defineTool({
name: 'JavaScript Obfuscator',
path: '/javascript-obfuscator',
description: 'Javascript code obfuscator using base64 or rot13 encoding by Forza for IT Tools',
keywords: ['javascript', 'obfuscator'],
component: () => import('./javascript-obfuscator.vue'),
icon: Lock,
createdAt: new Date('2025-12-31'),
});
11 changes: 11 additions & 0 deletions src/tools/javascript-obfuscator/javascript-obfuscator.e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { expect, test } from '@playwright/test';

test.describe('Tool - JavaScript Obfuscator', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/javascript-obfuscator');
});

test('Has correct title', async ({ page }) => {
await expect(page).toHaveTitle('JavaScript Obfuscator - IT Tools');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Buffer } from 'node:buffer';
import { describe, expect, it } from 'vitest';
import { obfuscateJavascript } from './javascript-obfuscator.service';

describe('JavascriptObfuscator', () => {
it('base64 encodes and wraps with atob', () => {
const src = 'console.log(\'x\');';
const out = obfuscateJavascript(src, 'base64');

expect(out).toContain('atob(\'');
const m = out.match(/atob\('(.+)'\)/);
expect(m).toBeTruthy();
if (m) {
const b64 = m[1];
const decoded = decodeURIComponent(escape(Buffer.from(b64, 'base64').toString('binary')));
expect(decoded).toBe(src);
}
});

it('rot13 encodes and includes runtime decoder', () => {
const src = 'console.log(\'a\');';
const out = obfuscateJavascript(src, 'rot13');

expect(out).toContain('eval(r(s))');
const r = src.replace(/[A-Za-z]/g, c => String.fromCharCode((c <= 'Z' ? 65 : 97) + ((c.charCodeAt(0) - (c <= 'Z' ? 65 : 97) + 13) % 26)));
expect(out).toContain(r);
});
});
31 changes: 31 additions & 0 deletions src/tools/javascript-obfuscator/javascript-obfuscator.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { get } from '@vueuse/core';
import { type MaybeRef, computed } from 'vue';

export { obfuscateJavascript, useObfuscateJavascript };

function base64Encode(str: string) {
// encode UTF-8 to base64
return btoa(unescape(encodeURIComponent(str)));
}

function rot13Encode(str: string) {
return str.replace(/[A-Za-z]/g, c => String.fromCharCode((c <= 'Z' ? 65 : 97) + ((c.charCodeAt(0) - (c <= 'Z' ? 65 : 97) + 13) % 26)));
}

function obfuscateJavascript(code: string, method: 'base64' | 'rot13' = 'base64'): string {
if (!code) {
return '';
}

if (method === 'base64') {
const b = base64Encode(code);
return `(function(){eval(atob('${b}'));})();`;
}

const r = rot13Encode(code);
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}');`;
}

function useObfuscateJavascript(code: MaybeRef<string>, method?: MaybeRef<'base64' | 'rot13'>) {
return computed(() => obfuscateJavascript(get(code), get(method) || 'base64'));
}
Loading
Loading