New:Socket for Asana Is Now Available.Learn more
Get Started

ZeroX

Package Overview
Versions
2
Alerts
File Explorer
Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

zerox@joelindra.id - firefox Package Compare versions

Comparing version
2.0.0
to
2.0.1
+2
-2
manifest.json
{
"description": "ZeroX",
"description": "ZeroX - Security Toolkit & Burp Suite Proxy Suite",
"manifest_version": 2,
"name": "ZeroX",
"version": "2.0.0",
"version": "2.0.1",
"icons": {

@@ -7,0 +7,0 @@ "48": "icons/icon-48.png",

{
"name": "zerox-firefox-extension",
"version": "2.0.0",
"version": "2.0.1",
"description": "ZeroX Firefox Extension - Security Toolkit",
"scripts": {
"dev": "web-ext run --reload",
"prebuild": "rm -rf web-ext-artifacts/",
"prebuild": "node -e \"try{require('fs').rmSync('web-ext-artifacts',{recursive:true,force:true})}catch(e){}\"",
"build": "web-ext build --overwrite-dest",

@@ -9,0 +9,0 @@ "lint": "web-ext lint",

@@ -0,6 +1,9 @@

/**
* ZeroX Configuration & Fast In-Memory Storage Cache
*/
const defaultConfig = {
enabled: false,
useBurpProxy: false,
useBurpProxyAll: false,
useBurpProxyContainer: false,
addContainerHeader: true,

@@ -24,25 +27,66 @@ logPostMessage: true,

return data
return data;
`}
};
// In-memory cache for ultra-fast zero-latency reads on high-frequency network events
const _configCache = { ...defaultConfig };
if (typeof browser !== "undefined" && browser.storage && browser.storage.local) {
browser.storage.local.get(null).then(stored => {
if (stored) {
Object.assign(_configCache, stored);
}
}).catch(() => {});
browser.storage.onChanged.addListener((changes, areaName) => {
if (areaName !== "local") return;
for (const [key, { newValue }] of Object.entries(changes)) {
_configCache[key] = newValue;
}
});
}
const config = {
getCached(key) {
return _configCache[key] ?? defaultConfig[key];
},
async get(key) {
const r = await browser.storage.local.get(key)
return r[key] ?? defaultConfig[key]
try {
const r = await browser.storage.local.get(key);
const val = r[key] ?? defaultConfig[key];
_configCache[key] = val;
return val;
} catch (e) {
return defaultConfig[key];
}
},
async getAll() {
try {
const r = await browser.storage.local.get(null);
const combined = { ...defaultConfig, ...r };
Object.assign(_configCache, combined);
return combined;
} catch (e) {
return { ...defaultConfig };
}
},
async set(key, value) {
return await browser.storage.local.set({ [key]: value })
_configCache[key] = value;
return await browser.storage.local.set({ [key]: value });
},
async setMultiple(obj) {
Object.assign(_configCache, obj);
return await browser.storage.local.set(obj);
},
onChange(key, handler) {
return browser.storage.onChanged.addListener((changes, areaName) => {
if (areaName != "local") return
if (areaName !== "local") return;
for (const [name, { newValue }] of Object.entries(changes)) {
if (name != key) continue
handler(newValue)
if (name !== key) continue;
handler(newValue);
}
})
});
}
}
};
:root {
--background-color: #232327;
--text-color: #C6C6CA;
--bg-base: #090b12;
--bg-surface: #121626;
--bg-toolbar: #181d30;
--border-color: rgba(255, 255, 255, 0.08);
--border-hover: rgba(168, 85, 247, 0.4);
--text-main: #f1f5f9;
--text-dim: #94a3b8;
--accent: #a855f7;
}

@@ -10,3 +16,6 @@

margin: 0;
color: var(--text-color);
color: var(--text-main);
background-color: var(--bg-base);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Inter", monospace;
font-size: 12px;
}

@@ -18,12 +27,9 @@

main {
background-color: #0C0C0D;
font-family: monospace;
background-color: var(--bg-base);
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto 1fr;
grid-template-areas: "toolbar""list";
grid-template-areas: "toolbar" "list";
align-items: start;
border-bottom: 2px solid black;
height: 100vh;

@@ -33,4 +39,4 @@ }

main.dual {
grid-template-columns: auto 500px;
grid-template-areas: "toolbar filter""list filter";
grid-template-columns: auto 450px;
grid-template-areas: "toolbar filter" "list filter";
}

@@ -41,30 +47,43 @@

display: flex;
column-gap: 5px;
background: #2a2a2e;
padding: 5px;
align-items: center;
column-gap: 8px;
background: var(--bg-toolbar);
border-bottom: 1px solid var(--border-color);
padding: 8px 12px;
width: 100%;
}
#message-toolbar svg {
padding: 4px;
}
#message-toolbar button,
#message-toolbar svg {
border: none;
border-radius: 2px;
#message-toolbar button {
border: 1px solid var(--border-color);
border-radius: 6px;
white-space: nowrap;
user-select: none;
background-color: rgba(249, 249, 250, 0.2);
color: rgb(215, 215, 219);
text-align: center;
background: rgba(255, 255, 255, 0.06);
color: var(--text-main);
padding: 4px 10px;
font-size: 11px;
font-weight: 600;
cursor: pointer;
transition: all 0.15s ease;
}
#message-toolbar button:hover,
#message-toolbar svg:hover {
background-color: rgba(249, 249, 250, 0.3);
#message-toolbar button:hover {
background: rgba(168, 85, 247, 0.2);
border-color: var(--border-hover);
color: #ffffff;
}
#toggleDual {
padding: 4px;
border-radius: 6px;
cursor: pointer;
color: var(--text-dim);
transition: all 0.15s ease;
}
#toggleDual:hover {
color: var(--accent);
background: rgba(255, 255, 255, 0.06);
}
#message-list {

@@ -74,3 +93,2 @@ display: contents;

#message-table {

@@ -80,7 +98,5 @@ grid-area: list;

overflow-x: hidden;
scrollbar-width: thin;
height: 100%;
display: flex;
flex-direction: column;
vertical-align: middle;
justify-content: start;

@@ -90,7 +106,13 @@ counter-reset: message-id;

#message-table>.row {
#message-table > .row {
top: 0;
position: sticky;
z-index: 10;
background: #2a2a2e;
background: var(--bg-surface);
border-bottom: 1px solid var(--border-color);
font-weight: 700;
color: var(--text-dim);
text-transform: uppercase;
font-size: 10.5px;
letter-spacing: 0.5px;
}

@@ -104,23 +126,21 @@

display: grid;
grid-template-columns: 40px 1fr 1fr 4fr 75px;
line-height: 14px;
font-size: 11px;
border-bottom: 1px solid #4E4E51;
background: var(--background-color);
background: #2a2a2e;
grid-template-columns: 45px 1.2fr 1.2fr 4fr 85px;
line-height: 20px;
font-size: 11.5px;
font-family: ui-monospace, SFMono-Regular, monospace;
border-bottom: 1px solid var(--border-color);
background: var(--bg-base);
transition: background 0.1s ease;
}
.row:hover {
background: #3a3a3e
background: rgba(255, 255, 255, 0.04);
}
.row span::after {
display: block;
content: "";
top: -1px;
bottom: -1px;
right: 0px;
left: -1px;
position: absolute;
border-right: 1px solid #4E4E51;
.row span {
position: relative;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: 4px 8px;
}

@@ -130,26 +150,10 @@

counter-increment: message-id;
content: counter(message-id, decimal-leading-zero)
content: counter(message-id, decimal-leading-zero);
color: var(--text-dim);
}
#message-list .row:hover {
border-bottom: 1px solid #4E4E51;
}
#message-table>.row {
border-top: 1px solid #4E4E51;
font-weight: bold;
}
.row span {
position: relative;
white-space: nowrap;
overflow-x: hidden;
text-overflow: ellipsis;
padding: 2px 4px;
}
#message-filter {
display: none;
border-left: 1px solid var(--border-color);
background: var(--bg-surface);
}

@@ -160,3 +164,3 @@

display: grid;
grid-template-rows: 30px auto;
grid-template-rows: 36px auto;
height: 100%;

@@ -168,24 +172,43 @@ }

margin: 0;
line-height: 30px;
font-weight: lighter;
line-height: 36px;
font-size: 12px;
font-weight: 700;
color: var(--text-dim);
border-bottom: 1px solid var(--border-color);
}
textarea {
padding: 5px;
padding: 10px;
height: 100%;
display: block;
resize: none;
background: var(--bg-base);
color: #e2e8f0;
border: none;
outline: none;
font-family: ui-monospace, SFMono-Regular, monospace;
font-size: 12px;
}
.message-details-content {
padding: 10px;
padding: 12px 16px;
display: grid;
grid-template-columns: 90px 1fr;
row-gap: 10px;
column-gap: 10px;
background: #0c0c0d;
grid-template-columns: 100px 1fr;
row-gap: 8px;
column-gap: 12px;
background: #06070c;
border-bottom: 1px solid var(--border-color);
font-family: ui-monospace, SFMono-Regular, monospace;
font-size: 11.5px;
}
.message-details-content span:nth-child(odd) {
color: var(--accent);
font-weight: 600;
}
.message-details-content span:nth-child(even) {
white-space: pre;
white-space: pre-wrap;
word-break: break-all;
color: #cbd5e1;
}

@@ -196,6 +219,2 @@

outline: 0;
}
.message-details-content span:nth-child(odd) {
border-right: 1px solid #b1b1b3;
}

@@ -32,8 +32,8 @@ class Feature {

function proxify(config) {
return async function (e) {
const enabled = await config.get("enabled");
return function (e) {
const enabled = config.getCached("enabled");
if (!enabled) return { type: "direct" };
const useAll = await config.get("useBurpProxyAll");
const useContainers = await config.get("useBurpProxyContainer");
const useAll = config.getCached("useBurpProxyAll");
const useContainers = config.getCached("useBurpProxyContainer");

@@ -44,8 +44,8 @@ // If neither is checked, go direct

// If 'Containers Only' is checked, and we are in default container, go direct
if (useContainers && !useAll && e.cookieStoreId == 'firefox-default')
if (useContainers && !useAll && e.cookieStoreId === 'firefox-default')
return { type: "direct" };
const host = await config.get("burpProxyHost")
const portStr = await config.get("burpProxyPort")
const port = parseInt(portStr, 10) || 8080
const host = config.getCached("burpProxyHost") || "127.0.0.1";
const portStr = config.getCached("burpProxyPort") || "8080";
const port = parseInt(portStr, 10) || 8080;

@@ -52,0 +52,0 @@ return {

@@ -0,20 +1,36 @@

/* ==========================================================================
ZeroX Security Toolkit - Obsidian Cyber Luxury Theme (Refined & Minimalist)
========================================================================== */
:root {
--bg-dark: #1e1b29;
--bg-card: rgba(255, 255, 255, 0.05);
--bg-header: linear-gradient(180deg, rgba(147, 51, 234, 0.15) 0%, rgba(30, 27, 41, 0) 100%);
--bg-base: #090b14;
--bg-surface: rgba(17, 22, 38, 0.75);
--bg-surface-hover: rgba(26, 33, 56, 0.88);
--bg-card: rgba(22, 28, 48, 0.65);
--bg-input: rgba(10, 13, 24, 0.85);
--text-main: #ffffff;
--text-dim: rgba(255, 255, 255, 0.5);
--text-inactive: #f87171;
--text-active: #10b981;
--border-subtle: rgba(255, 255, 255, 0.07);
--border-card: rgba(255, 255, 255, 0.09);
--border-focus: rgba(168, 85, 247, 0.6);
--text-primary: #f8fafc;
--text-secondary: #94a3b8;
--text-muted: #64748b;
--accent-purple: #a855f7;
--accent-purple-dark: #7c3aed;
--accent-purple-glow: rgba(168, 85, 247, 0.4);
--border-dim: rgba(255, 255, 255, 0.1);
--border-active: rgba(168, 85, 247, 0.5);
--accent-cyan: #06b6d4;
--accent-emerald: #10b981;
--accent-rose: #f43f5e;
--font-inter: 'Inter', sans-serif;
--font-stack: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Inter", "Helvetica Neue", Arial, sans-serif;
--transition-fast: 0.15s cubic-bezier(0.4, 0, 0.2, 1);
--transition-smooth: 0.25s cubic-bezier(0.16, 1, 0.3, 1);
--transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
--radius-sm: 8px;
--radius-md: 12px;
--radius-lg: 16px;
--radius-full: 9999px;
}

@@ -26,44 +42,44 @@

box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
width: 360px;
background-color: var(--bg-dark);
color: var(--text-main);
font-family: var(--font-inter);
html, body {
width: 380px;
background-color: var(--bg-base);
background-image:
radial-gradient(circle at 15% 0%, rgba(168, 85, 247, 0.15) 0%, transparent 45%),
radial-gradient(circle at 85% 100%, rgba(59, 130, 246, 0.1) 0%, transparent 45%),
radial-gradient(circle at 50% 50%, rgba(15, 23, 42, 0.3) 0%, transparent 100%);
color: var(--text-primary);
font-family: var(--font-stack);
font-size: 13px;
line-height: 1.4;
overflow-x: hidden;
overflow-y: auto;
scrollbar-width: none;
user-select: none;
}
/* Custom Scrollbar */
::-webkit-scrollbar {
width: 6px;
display: none;
width: 0;
height: 0;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.2);
}
.app-container {
padding: 20px;
padding-bottom: 30px;
background: var(--bg-header);
min-height: 100vh;
padding: 16px 16px 14px 16px;
display: flex;
flex-direction: column;
gap: 12px;
min-height: 100%;
}
/* Header Styles */
header {
margin-bottom: 24px;
/* ==========================================================================
Clean & Simple Header
========================================================================== */
.app-header {
display: flex;
flex-direction: column;
gap: 10px;
}

@@ -75,68 +91,101 @@

justify-content: space-between;
margin-bottom: 20px;
}
.logo-area {
.brand {
display: flex;
align-items: center;
gap: 14px;
gap: 10px;
}
.logo-box {
width: 48px;
height: 48px;
background: linear-gradient(135deg, #a855f7 0%, #7c3aed 100%);
border-radius: 14px;
width: 32px;
height: 32px;
border-radius: 9px;
background: linear-gradient(135deg, rgba(168, 85, 247, 0.22) 0%, rgba(59, 130, 246, 0.15) 100%);
border: 1px solid rgba(168, 85, 247, 0.35);
display: flex;
align-items: center;
justify-content: center;
color: white;
box-shadow: 0 4px 12px var(--accent-purple-glow);
color: #c084fc;
box-shadow: 0 0 12px rgba(168, 85, 247, 0.2);
flex-shrink: 0;
transition: transform var(--transition-smooth);
}
.brand-info h1 {
font-size: 20px;
font-weight: 700;
letter-spacing: -0.5px;
margin-bottom: 2px;
.logo-box:hover {
transform: scale(1.06);
}
.status-badge {
.brand-info {
display: flex;
align-items: center;
gap: 6px;
font-size: 10px;
gap: 8px;
}
.brand-name {
font-size: 17px;
font-weight: 700;
letter-spacing: 0.5px;
letter-spacing: -0.3px;
color: #ffffff;
}
.status-badge {
display: inline-flex;
align-items: center;
gap: 5px;
background: rgba(244, 63, 94, 0.1);
border: 1px solid rgba(244, 63, 94, 0.25);
padding: 2px 7px;
border-radius: 6px;
transition: var(--transition-smooth);
}
.status-dot {
width: 6px;
height: 6px;
width: 5px;
height: 5px;
border-radius: 50%;
background-color: var(--text-inactive);
background-color: var(--accent-rose);
box-shadow: 0 0 6px rgba(244, 63, 94, 0.6);
transition: var(--transition-smooth);
}
.status-text {
color: var(--text-dim);
font-size: 10.5px;
font-weight: 600;
letter-spacing: 0.2px;
color: #fda4af;
transition: var(--transition-smooth);
}
/* Master Active State */
.status-badge.active {
background: rgba(16, 185, 129, 0.12);
border-color: rgba(16, 185, 129, 0.35);
}
.status-badge.active .status-dot {
background-color: var(--text-active);
box-shadow: 0 0 8px var(--text-active);
background-color: var(--accent-emerald);
box-shadow: 0 0 6px rgba(16, 185, 129, 0.8);
animation: pulse-dot 2s infinite ease-in-out;
}
.status-badge.active .status-text {
color: var(--text-active);
color: #6ee7b7;
}
/* Toggle Switch */
.toggle-switch {
width: 44px;
@keyframes pulse-dot {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.25); opacity: 0.8; }
}
/* Master Toggle Switch */
.switch-master {
position: relative;
display: inline-block;
width: 46px;
height: 24px;
position: relative;
cursor: pointer;
}
.toggle-switch input {
.switch-master input {
opacity: 0;

@@ -147,17 +196,14 @@ width: 0;

.slider {
.switch-slider {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.1);
border-radius: 24px;
transition: var(--transition);
border: 1px solid var(--border-dim);
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(255, 255, 255, 0.08);
border: 1px solid var(--border-card);
border-radius: var(--radius-full);
transition: var(--transition-smooth);
}
.slider:before {
.switch-slider:before {
position: absolute;
content: "";
position: absolute;
height: 18px;

@@ -167,185 +213,327 @@ width: 18px;

bottom: 2px;
background: #94a3b8;
background: #64748b;
border-radius: 50%;
transition: var(--transition);
transition: var(--transition-smooth);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.35);
}
input:checked + .slider {
background: var(--accent-purple);
border-color: var(--accent-purple);
.switch-master input:checked + .switch-slider {
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
border-color: rgba(16, 185, 129, 0.5);
box-shadow: 0 0 14px rgba(16, 185, 129, 0.45);
}
input:checked + .slider:before {
transform: translateX(20px);
background: white;
.switch-master input:checked + .switch-slider:before {
transform: translateX(22px);
background: #ffffff;
}
/* Burp Status Bar */
.burp-status {
background: rgba(255, 255, 255, 0.03);
border: 1px solid var(--border-dim);
border-radius: 12px;
padding: 10px 14px;
/* ==========================================================================
Burp Suite Target Card
========================================================================== */
.target-card {
background: var(--bg-surface);
border: 1px solid var(--border-card);
border-radius: var(--radius-md);
padding: 9px 12px;
display: flex;
flex-direction: column;
gap: 7px;
backdrop-filter: blur(14px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
transition: var(--transition-smooth);
}
.target-card:hover {
border-color: rgba(168, 85, 247, 0.3);
}
.target-card-header {
display: flex;
align-items: center;
justify-content: space-between;
backdrop-filter: blur(10px);
cursor: pointer;
transition: var(--transition);
}
.burp-status:hover {
background: rgba(255, 255, 255, 0.08);
border-color: var(--border-active);
.target-title-area {
display: flex;
align-items: center;
gap: 6px;
font-size: 10.5px;
font-weight: 700;
color: var(--text-secondary);
letter-spacing: 0.6px;
text-transform: uppercase;
}
.address-display {
.icon-burp {
color: var(--accent-purple);
}
.preset-chips {
display: flex;
align-items: center;
gap: 4px;
}
.inline-edit-input {
background: rgba(168, 85, 247, 0.1);
border: 1px solid var(--accent-purple);
border-radius: 8px;
color: #fff;
font-size: 11px;
font-family: 'JetBrains Mono', 'Fira Code', monospace;
padding: 4px 8px;
width: 150px;
outline: none;
backdrop-filter: blur(5px);
box-shadow: 0 0 15px rgba(168, 85, 247, 0.2);
transition: var(--transition);
text-align: right;
.port-preset {
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--border-subtle);
border-radius: 6px;
color: var(--text-secondary);
font-family: ui-monospace, SFMono-Regular, monospace;
font-size: 10.5px;
font-weight: 600;
padding: 2px 6px;
cursor: pointer;
transition: var(--transition-fast);
}
.inline-edit-input:focus {
.port-preset:hover {
background: rgba(168, 85, 247, 0.2);
box-shadow: 0 0 20px rgba(168, 85, 247, 0.4), inset 0 0 5px rgba(255, 255, 255, 0.1);
border-color: #c084fc;
border-color: rgba(168, 85, 247, 0.4);
color: #ffffff;
transform: translateY(-1px);
}
.status-info {
.port-preset.active {
background: rgba(168, 85, 247, 0.35);
border-color: var(--accent-purple);
color: #ffffff;
}
.icon-btn {
background: transparent;
border: none;
color: var(--text-secondary);
padding: 3px;
border-radius: 6px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: var(--transition-fast);
}
.icon-btn:hover {
color: #ffffff;
background: rgba(255, 255, 255, 0.08);
}
/* Address Chip */
.address-chip {
display: flex;
align-items: center;
justify-content: space-between;
background: var(--bg-input);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-sm);
padding: 6px 10px;
cursor: pointer;
transition: var(--transition-fast);
}
.address-chip:hover {
border-color: var(--border-focus);
background: rgba(15, 19, 34, 0.95);
}
.address-chip-left {
display: flex;
align-items: center;
gap: 8px;
color: var(--text-dim);
flex: 1;
}
.pulse-indicator {
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--accent-cyan);
box-shadow: 0 0 6px var(--accent-cyan);
flex-shrink: 0;
}
.address-val {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 12px;
font-weight: 500;
font-weight: 600;
color: #e2e8f0;
letter-spacing: 0.3px;
}
.briefcase-icon {
opacity: 0.5;
.edit-icon {
color: var(--text-muted);
opacity: 0.6;
transition: var(--transition-fast);
}
.address {
font-size: 11px;
color: rgba(255, 255, 255, 0.3);
font-family: monospace;
.address-chip:hover .edit-icon {
color: var(--accent-purple);
opacity: 1;
}
/* Main Sections */
main {
.address-input {
flex: 1;
background: transparent;
border: none;
outline: none;
color: #ffffff;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 12px;
font-weight: 600;
width: 100%;
}
.section-divider {
/* ==========================================================================
Section Headers
========================================================================= */
.section-header {
display: flex;
align-items: center;
gap: 12px;
margin: 24px 0 16px;
justify-content: space-between;
margin-top: 2px;
margin-bottom: 1px;
}
.divider-label {
font-size: 11px;
.section-title {
font-size: 10px;
font-weight: 700;
color: var(--text-dim);
letter-spacing: 1px;
white-space: nowrap;
letter-spacing: 0.8px;
color: var(--text-muted);
}
.divider-line {
flex: 1;
height: 1px;
background: var(--border-dim);
}
.divider-count {
font-size: 11px;
.section-badge {
font-size: 9px;
font-weight: 700;
color: var(--text-dim);
opacity: 0.5;
letter-spacing: 0.5px;
color: var(--text-secondary);
background: rgba(255, 255, 255, 0.06);
padding: 1px 5px;
border-radius: 4px;
}
/* Options List */
.options-list {
/* ==========================================================================
Feature Cards & Toggles
========================================================================== */
.feature-cards {
display: flex;
flex-direction: column;
gap: 12px;
gap: 7px;
}
.option-item {
.feature-card {
background: var(--bg-card);
border: 1px solid var(--border-dim);
border-radius: 14px;
padding: 14px 16px;
border: 1px solid var(--border-card);
border-radius: var(--radius-md);
padding: 9px 12px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 11px;
cursor: pointer;
transition: var(--transition);
transition: var(--transition-smooth);
position: relative;
overflow: hidden;
}
.option-item:hover {
background: rgba(255, 255, 255, 0.08);
border-color: var(--border-active);
.feature-card:hover {
background: var(--bg-surface-hover);
border-color: rgba(168, 85, 247, 0.35);
transform: translateY(-1px);
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.28);
}
.option-content {
.feature-icon {
width: 30px;
height: 30px;
border-radius: 9px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: transform var(--transition-fast);
}
.feature-card:hover .feature-icon {
transform: scale(1.06);
}
.bg-purple {
background: rgba(168, 85, 247, 0.15);
color: #c084fc;
border: 1px solid rgba(168, 85, 247, 0.3);
}
.bg-blue {
background: rgba(59, 130, 246, 0.15);
color: #60a5fa;
border: 1px solid rgba(59, 130, 246, 0.3);
}
.bg-emerald {
background: rgba(16, 185, 129, 0.15);
color: #34d399;
border: 1px solid rgba(16, 185, 129, 0.3);
}
.bg-rose {
background: rgba(244, 63, 94, 0.15);
color: #fb7185;
border: 1px solid rgba(244, 63, 94, 0.3);
}
.feature-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 2px;
gap: 1px;
}
.option-label {
font-size: 14px;
.feature-name {
font-size: 12px;
font-weight: 600;
color: #e2e8f0;
color: #ffffff;
letter-spacing: -0.2px;
}
.option-desc {
font-size: 11px;
color: var(--text-dim);
.feature-desc {
font-size: 10px;
color: var(--text-secondary);
}
/* Custom Checkbox */
.checkbox-wrapper {
/* Feature Toggle Control */
.toggle-control {
position: relative;
width: 24px;
height: 24px;
width: 36px;
height: 20px;
flex-shrink: 0;
}
.custom-checkbox {
position: absolute;
.toggle-input {
opacity: 0;
cursor: pointer;
width: 0;
height: 0;
width: 0;
}
.checkbox-mark {
.toggle-slider {
position: absolute;
top: 0;
left: 0;
height: 24px;
width: 24px;
background: rgba(255, 255, 255, 0.05);
border: 2px solid var(--border-dim);
border-radius: 7px;
transition: var(--transition);
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(255, 255, 255, 0.1);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-full);
transition: var(--transition-fast);
}
.custom-checkbox:checked ~ .checkbox-mark {
.toggle-slider:before {
position: absolute;
content: "";
height: 14px;
width: 14px;
left: 2px;
bottom: 2px;
background: #94a3b8;
border-radius: 50%;
transition: var(--transition-fast);
}
.toggle-input:checked + .toggle-slider {
background: var(--accent-purple);

@@ -356,119 +544,179 @@ border-color: var(--accent-purple);

.checkbox-mark:after {
content: "";
position: absolute;
display: none;
left: 7px;
top: 3px;
width: 5px;
height: 10px;
border: solid white;
border-width: 0 2px 2px 0;
transform: rotate(45deg);
.toggle-input:checked + .toggle-slider:before {
transform: translateX(16px);
background: #ffffff;
}
.custom-checkbox:checked ~ .checkbox-mark:after {
display: block;
}
/* Containers Grid */
/* ==========================================================================
Container Launcher Grid
========================================================================== */
.containers-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
margin-bottom: 20px;
gap: 7px;
margin-top: 3px;
}
.identity {
aspect-ratio: 1;
.container-btn {
background: var(--bg-card);
border: 1px solid var(--border-dim);
border-radius: 14px;
border: 1px solid var(--border-card);
border-radius: var(--radius-md);
padding: 7px 4px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 4px;
cursor: pointer;
transition: var(--transition);
transition: var(--transition-fast);
position: relative;
overflow: hidden;
}
.identity:hover {
background: rgba(255, 255, 255, 0.1);
transform: scale(1.05);
z-index: 1;
.container-btn:hover {
background: var(--bg-surface-hover);
transform: translateY(-2px);
box-shadow: 0 5px 14px rgba(0, 0, 0, 0.35);
}
.identity.active {
border-color: var(--accent-purple);
box-shadow: 0 0 15px var(--accent-purple-glow);
.container-btn:active {
transform: scale(0.95);
}
.identity-glyph {
.container-swatch {
width: 20px;
height: 20px;
border-radius: 6px;
transition: var(--transition);
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
transition: transform var(--transition-fast);
}
/* Individual Colors for Containers */
.identity.red .identity-glyph { background: #f87171; box-shadow: 0 0 10px rgba(248, 113, 113, 0.3); }
.identity.orange .identity-glyph { background: #fb923c; box-shadow: 0 0 10px rgba(251, 146, 60, 0.3); }
.identity.yellow .identity-glyph { background: #fbbf24; box-shadow: 0 0 10px rgba(251, 191, 36, 0.3); }
.identity.green .identity-glyph { background: #4ade80; box-shadow: 0 0 10px rgba(74, 222, 128, 0.3); }
.identity.cyan .identity-glyph { background: #22d3ee; box-shadow: 0 0 10px rgba(34, 211, 238, 0.3); }
.identity.blue .identity-glyph { background: #60a5fa; box-shadow: 0 0 10px rgba(96, 165, 250, 0.3); }
.identity.purple .identity-glyph { background: #a78bfa; box-shadow: 0 0 10px rgba(167, 139, 250, 0.3); }
.identity.pink .identity-glyph { background: #f472b6; box-shadow: 0 0 10px rgba(244, 114, 182, 0.3); }
.container-btn:hover .container-swatch {
transform: scale(1.12);
}
/* Selected Indicator */
.identity.selected::after {
content: "";
position: absolute;
top: 6px;
right: 6px;
width: 6px;
height: 6px;
background: #10b981;
border-radius: 50%;
box-shadow: 0 0 5px #10b981;
.container-label {
font-size: 9.5px;
font-weight: 600;
color: var(--text-secondary);
text-transform: capitalize;
letter-spacing: 0.2px;
}
/* Footer */
footer {
padding-top: 10px;
.container-btn:hover .container-label {
color: #ffffff;
}
/* Chromatic Variants */
.container-btn[data-color="red"] .container-swatch {
background: linear-gradient(135deg, #f87171, #ef4444);
box-shadow: 0 0 10px rgba(239, 68, 68, 0.45);
}
.container-btn[data-color="orange"] .container-swatch {
background: linear-gradient(135deg, #fb923c, #f97316);
box-shadow: 0 0 10px rgba(249, 115, 22, 0.45);
}
.container-btn[data-color="yellow"] .container-swatch {
background: linear-gradient(135deg, #fde047, #eab308);
box-shadow: 0 0 10px rgba(234, 179, 8, 0.45);
}
.container-btn[data-color="green"] .container-swatch {
background: linear-gradient(135deg, #4ade80, #22c55e);
box-shadow: 0 0 10px rgba(34, 197, 94, 0.45);
}
.container-btn[data-color="cyan"] .container-swatch {
background: linear-gradient(135deg, #22d3ee, #06b6d4);
box-shadow: 0 0 10px rgba(6, 182, 212, 0.45);
}
.container-btn[data-color="blue"] .container-swatch {
background: linear-gradient(135deg, #60a5fa, #3b82f6);
box-shadow: 0 0 10px rgba(59, 130, 246, 0.45);
}
.container-btn[data-color="purple"] .container-swatch {
background: linear-gradient(135deg, #c084fc, #a855f7);
box-shadow: 0 0 10px rgba(168, 85, 247, 0.45);
}
.container-btn[data-color="pink"] .container-swatch {
background: linear-gradient(135deg, #f472b6, #ec4899);
box-shadow: 0 0 10px rgba(236, 72, 153, 0.45);
}
/* ==========================================================================
Footer
========================================================================== */
.app-footer {
display: flex;
align-items: center;
justify-content: space-between;
border-top: 1px solid var(--border-dim);
margin-top: 10px;
padding-top: 8px;
border-top: 1px solid var(--border-subtle);
margin-top: 2px;
}
.version {
font-size: 11px;
color: rgba(255, 255, 255, 0.2);
font-weight: 500;
.version-tag {
font-size: 10px;
font-weight: 600;
color: var(--text-muted);
letter-spacing: 0.2px;
}
.footer-links {
.footer-link-btn {
background: transparent;
border: none;
color: var(--text-secondary);
font-size: 11px;
font-weight: 600;
display: flex;
gap: 16px;
align-items: center;
gap: 4px;
cursor: pointer;
padding: 3px 6px;
border-radius: var(--radius-sm);
transition: var(--transition-fast);
}
.footer-links a {
font-size: 11px;
color: var(--text-dim);
text-decoration: none;
font-weight: 600;
transition: var(--transition);
.footer-link-btn:hover {
color: #ffffff;
background: rgba(255, 255, 255, 0.08);
}
.footer-links a:hover {
color: white;
/* ==========================================================================
Disabled State (When Master Switch is OFF)
========================================================================== */
.app-main.disabled {
opacity: 0.45;
filter: grayscale(0.4);
pointer-events: none;
transition: opacity var(--transition-smooth), filter var(--transition-smooth);
}
/* Main Disabled State */
#main-content.disabled {
opacity: 0.4;
filter: grayscale(0.5);
/* ==========================================================================
Toast Notification
========================================================================== */
.toast {
position: fixed;
bottom: 12px;
left: 50%;
transform: translateX(-50%) translateY(40px);
background: rgba(15, 23, 42, 0.95);
border: 1px solid rgba(168, 85, 247, 0.5);
color: #ffffff;
font-size: 11px;
font-weight: 600;
padding: 6px 12px;
border-radius: var(--radius-full);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5), 0 0 12px rgba(168, 85, 247, 0.3);
pointer-events: none;
opacity: 0;
transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.25s ease;
z-index: 100;
white-space: nowrap;
}
.toast.show {
transform: translateX(-50%) translateY(0);
opacity: 1;
}

@@ -6,116 +6,186 @@ <!DOCTYPE html>

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ZeroX Security Toolkit</title>
<link rel="stylesheet" href="popup.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
</head>
<body>
<div class="app-container">
<header>
<!-- Sleek Minimalist Header -->
<header class="app-header">
<div class="header-main">
<div class="logo-area">
<div class="logo-box">
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor">
<path d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm0 18c-4.411 0-8-3.589-8-8s3.589-8 8-8 8 3.589 8 8-3.589 8-8 8z"/>
<path d="M13 7h-2v6h6v-2h-4z"/>
<div class="brand">
<div class="logo-box" id="brand-logo" title="ZeroX Security Toolkit">
<svg class="logo-icon" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
<path d="M9.5 9.5l5 5m0-5l-5 5"/>
</svg>
</div>
<div class="brand-info">
<h1>ZeroX</h1>
<div class="status-badge" id="status-badge">
<span class="brand-name">ZeroX</span>
<div class="status-badge" id="status-pill">
<span class="status-dot"></span>
<span class="status-text" id="status-text">INACTIVE</span>
<span class="status-text" id="status-text">Standby</span>
</div>
</div>
</div>
<label class="toggle-switch">
<input id="option-enabled" type="checkbox">
<span class="slider"></span>
</label>
<!-- Master Toggle Switch -->
<div class="master-toggle-wrapper">
<label class="switch-master" title="Toggle ZeroX Interception">
<input id="option-enabled" type="checkbox">
<span class="switch-slider"></span>
</label>
</div>
</div>
<div class="burp-status" id="burp-status-bar" title="Click to edit proxy address">
<div class="status-info">
<svg class="briefcase-icon" viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
<path d="M20 7h-4V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2H4a2 2 0 0 0-2 2v11a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2zM10 5h4v2h-4V5zM4 9h16v3h-16V9zm0 11v-6h16v6H4z"/>
<!-- Burp Suite Target Card -->
<div class="target-card" id="burp-target-card">
<div class="target-card-header">
<div class="target-title-area">
<svg class="icon-burp" viewBox="0 0 24 24" width="13" height="13" fill="currentColor">
<path d="M20 7h-4V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2H4a2 2 0 0 0-2 2v11a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2zM10 5h4v2h-4V5zM4 9h16v3h-16V9zm0 11v-6h16v6H4z"/>
</svg>
<span>Burp Proxy</span>
</div>
<div class="preset-chips">
<button type="button" class="port-preset" data-port="8080" title="Set Port 8080">8080</button>
<button type="button" class="port-preset" data-port="8081" title="Set Port 8081">8081</button>
<button type="button" class="port-preset" data-port="8888" title="Set Port 8888">8888</button>
<button type="button" class="icon-btn" id="btn-copy-address" title="Copy Address">
<svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
</svg>
</button>
</div>
</div>
<div class="address-chip" id="address-chip" title="Click to edit IP:Port">
<div class="address-chip-left">
<span class="pulse-indicator"></span>
<span class="address-val" id="address-text">127.0.0.1:8080</span>
<input type="text" id="address-input" class="address-input" placeholder="127.0.0.1:8080" spellcheck="false" style="display: none;">
</div>
<svg class="edit-icon" viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 20h9"></path>
<path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"></path>
</svg>
<span>Burp Suite</span>
</div>
<div class="address-display">
<span class="address" id="address-text">127.0.0.1:8080</span>
<input type="text" id="address-input" class="inline-edit-input" style="display: none;">
</div>
</div>
</header>
<main id="main-content">
<div class="section-divider">
<span class="divider-label">PROXY SETTINGS</span>
<div class="divider-line"></div>
<!-- Main Content -->
<main class="app-main" id="main-content">
<!-- Interception Rules Section -->
<div class="section-header">
<span class="section-title">ROUTING & INTERCEPTION</span>
</div>
<div class="options-list">
<label class="option-item">
<div class="option-content">
<span class="option-label">All Tabs</span>
<span class="option-desc">Route all traffic through Burp</span>
<div class="feature-cards">
<!-- Option 1: All Tabs -->
<label class="feature-card">
<div class="feature-icon bg-purple">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"></circle>
<line x1="2" y1="12" x2="22" y2="12"></line>
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path>
</svg>
</div>
<div class="checkbox-wrapper">
<input id="option-useBurpProxyAll" type="checkbox" class="custom-checkbox">
<span class="checkbox-mark"></span>
<div class="feature-info">
<div class="feature-name">All Tabs Proxy</div>
<div class="feature-desc">Route all browser traffic via Burp</div>
</div>
<div class="toggle-control">
<input id="option-useBurpProxyAll" type="checkbox" class="toggle-input">
<span class="toggle-slider"></span>
</div>
</label>
<label class="option-item">
<div class="option-content">
<span class="option-label">Containers Only</span>
<span class="option-desc">Proxy container tabs only</span>
<!-- Option 2: Containers Only -->
<label class="feature-card">
<div class="feature-icon bg-blue">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2">
<polygon points="12 2 2 7 12 12 22 7 12 2"></polygon>
<polyline points="2 17 12 22 22 17"></polyline>
<polyline points="2 12 12 17 22 12"></polyline>
</svg>
</div>
<div class="checkbox-wrapper">
<input id="option-useBurpProxyContainer" type="checkbox" class="custom-checkbox">
<span class="checkbox-mark"></span>
<div class="feature-info">
<div class="feature-name">Containers Only</div>
<div class="feature-desc">Route only ZeroX container tabs</div>
</div>
<div class="toggle-control">
<input id="option-useBurpProxyContainer" type="checkbox" class="toggle-input">
<span class="toggle-slider"></span>
</div>
</label>
<label class="option-item">
<div class="option-content">
<span class="option-label">Color Header</span>
<span class="option-desc">Add color identifier to requests</span>
<!-- Option 3: Color Header -->
<label class="feature-card">
<div class="feature-icon bg-emerald">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2">
<path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"></path>
<line x1="7" y1="7" x2="7.01" y2="7"></line>
</svg>
</div>
<div class="checkbox-wrapper">
<input id="option-addContainerHeader" type="checkbox" class="custom-checkbox">
<span class="checkbox-mark"></span>
<div class="feature-info">
<div class="feature-name">Inject Color Header</div>
<div class="feature-desc">Adds X-ZeroX-Color header tag</div>
</div>
<div class="toggle-control">
<input id="option-addContainerHeader" type="checkbox" class="toggle-input">
<span class="toggle-slider"></span>
</div>
</label>
<label class="option-item">
<div class="option-content">
<span class="option-label">Remove Headers</span>
<span class="option-desc">Strip security headers from responses</span>
<!-- Option 4: Remove Security Headers -->
<label class="feature-card">
<div class="feature-icon bg-rose">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
<line x1="9" y1="9" x2="15" y2="15"></line>
<line x1="15" y1="9" x2="9" y2="15"></line>
</svg>
</div>
<div class="checkbox-wrapper">
<input id="option-removeSecurityHeaders" type="checkbox" class="custom-checkbox">
<span class="checkbox-mark"></span>
<div class="feature-info">
<div class="feature-name">Strip Security Headers</div>
<div class="feature-desc">Removes CSP, X-Frame-Options, XSS</div>
</div>
<div class="toggle-control">
<input id="option-removeSecurityHeaders" type="checkbox" class="toggle-input">
<span class="toggle-slider"></span>
</div>
</label>
</div>
<div class="section-divider">
<span class="divider-label">CONTAINERS</span>
<div class="divider-line"></div>
<span class="divider-count">8</span>
<!-- Container Tabs Launcher Section -->
<div class="section-header">
<span class="section-title">LAUNCH CONTAINER TAB</span>
<span class="section-badge">8 PROFILES</span>
</div>
<div id="identities" class="containers-grid">
<!-- Container buttons will be inserted here -->
<!-- Container buttons dynamically generated -->
</div>
</main>
<footer>
<span class="version">v2.0.0</span>
<div class="footer-links">
<a id="settings" href="#">Settings</a>
<!-- Footer -->
<footer class="app-footer">
<div class="footer-left">
<span class="version-tag">ZeroX Security • v2.0.1</span>
</div>
<div class="footer-right">
<button type="button" id="btn-settings" class="footer-link-btn" title="Open Settings">
<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="3"></circle>
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
</svg>
<span>Settings</span>
</button>
</div>
</footer>
<!-- Toast Feedback -->
<div id="toast" class="toast">Address copied!</div>
</div>
<script src="/src/icon.js"></script>
<script src="/src/config.js"></script>

@@ -122,0 +192,0 @@ <script src="/src/popup/popup.js"></script>

@@ -0,162 +1,250 @@

/**
* ZeroX Firefox Extension - Fast, High-Performance Popup Controller
*/
/* Container Identities Definition */
const CONTAINER_COLORS = [
{ name: "red", firefox: "red", symbol: "●" },
{ name: "orange", firefox: "orange", symbol: "●" },
{ name: "yellow", firefox: "yellow", symbol: "●" },
{ name: "green", firefox: "green", symbol: "●" },
{ name: "cyan", firefox: "turquoise", symbol: "●" },
{ name: "blue", firefox: "blue", symbol: "●" },
{ name: "purple", firefox: "purple", symbol: "★" },
{ name: "pink", firefox: "pink", symbol: "♥" }
];
/* Containers Identity */
let toastTimer = null;
function showToast(message) {
const toast = document.getElementById("toast");
if (!toast) return;
toast.textContent = message;
toast.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(() => {
toast.classList.remove("show");
}, 2000);
}
/* Contextual Identities Helper */
async function getOrCreateIdentity(color) {
const name = `ZeroX-${color}`
const icon = "fingerprint"
const [identity] = await browser.contextualIdentities.query({ name })
const name = `ZeroX-${color}`;
const icon = "fingerprint";
const [identity] = await browser.contextualIdentities.query({ name });
if (identity !== undefined) {
return identity
return identity;
}
return await browser.contextualIdentities.create({ name, color, icon })
return await browser.contextualIdentities.create({ name, color, icon });
}
async function createContainerTab(color) {
const identity = await getOrCreateIdentity(color)
const { cookieStoreId } = identity
return browser.tabs.create({ cookieStoreId })
async function createContainerTab(color, colorName) {
try {
const identity = await getOrCreateIdentity(color);
const { cookieStoreId } = identity;
await browser.tabs.create({ cookieStoreId });
showToast(`Opened ${colorName} container`);
} catch (err) {
console.error("Failed to create container tab:", err);
}
}
async function bindCheckboxToConfig(selector, config, configName) {
const checkbox = document.querySelector(selector)
checkbox.checked = await config.get(configName)
checkbox.addEventListener("change", () => config.set(configName, checkbox.checked))
}
/* Render Container Launcher Grid */
function renderContainerGrid() {
const container = document.getElementById("identities");
if (!container) return;
container.innerHTML = "";
CONTAINER_COLORS.forEach(({ name, firefox, symbol }) => {
const btn = document.createElement("div");
btn.className = "container-btn";
btn.dataset.color = name;
btn.title = `Launch isolated ${name} container tab`;
const swatch = document.createElement("div");
swatch.className = "container-swatch";
function createContainerTabButtons() {
const colorMap = [
{ name: "red", firefox: "red", label: "" },
{ name: "orange", firefox: "orange", label: "" },
{ name: "yellow", firefox: "yellow", label: "" },
{ name: "green", firefox: "green", label: "" },
{ name: "cyan", firefox: "turquoise", label: "" },
{ name: "blue", firefox: "blue", label: "" },
{ name: "purple", firefox: "purple", label: "★" },
{ name: "pink", firefox: "pink", label: "♥" }
]
const container = document.querySelector("#identities")
colorMap.forEach(({ name, firefox, label }) => {
const div = document.createElement("div")
div.classList.add("identity", name)
div.title = `Create ${name} container`
const glyph = document.createElement("div")
glyph.classList.add("identity-glyph")
if (label) {
glyph.textContent = label
glyph.style.display = "flex"
glyph.style.alignItems = "center"
glyph.style.justifyContent = "center"
glyph.style.fontSize = "10px"
glyph.style.color = "rgba(0,0,0,0.3)"
}
div.appendChild(glyph)
div.addEventListener("click", ev => {
createContainerTab(firefox)
})
container.appendChild(div)
})
const label = document.createElement("span");
label.className = "container-label";
label.textContent = name;
btn.appendChild(swatch);
btn.appendChild(label);
btn.addEventListener("click", () => {
createContainerTab(firefox, name);
});
container.appendChild(btn);
});
}
async function toggleZeroX(enabled) {
const color = enabled ? "#10b981" : "#ef4444"
const [canvas] = await createIcon(color)
const logoBox = document.querySelector(".logo-box")
if (logoBox) {
const existingCanvas = logoBox.querySelector('canvas')
const existingSvg = logoBox.querySelector('svg')
if (existingCanvas) {
logoBox.replaceChild(canvas, existingCanvas)
} else if (existingSvg) {
logoBox.replaceChild(canvas, existingSvg)
} else {
logoBox.appendChild(canvas)
}
/* Update Master Status UI */
function updateMasterStatus(enabled) {
const statusPill = document.getElementById("status-pill");
const statusText = document.getElementById("status-text");
const mainContent = document.getElementById("main-content");
const masterCheckbox = document.getElementById("option-enabled");
if (masterCheckbox && masterCheckbox.checked !== enabled) {
masterCheckbox.checked = enabled;
}
const main = document.getElementById("main-content")
const statusBadge = document.getElementById("status-badge")
const statusText = document.getElementById("status-text")
if (!enabled) {
main.classList.add('disabled')
statusText.textContent = "INACTIVE"
statusBadge.classList.remove('active')
if (enabled) {
if (statusPill) statusPill.classList.add("active");
if (statusText) statusText.textContent = "Active";
if (mainContent) mainContent.classList.remove("disabled");
} else {
main.classList.remove('disabled')
statusText.textContent = "ACTIVE"
statusBadge.classList.add('active')
if (statusPill) statusPill.classList.remove("active");
if (statusText) statusText.textContent = "Standby";
if (mainContent) mainContent.classList.add("disabled");
}
}
async function setupInlineAddressEdit() {
const statusBar = document.getElementById("burp-status-bar")
const addressText = document.getElementById("address-text")
const addressInput = document.getElementById("address-input")
/* Address & Port Controls */
async function setupAddressControls(currentHost, currentPort) {
const addressChip = document.getElementById("address-chip");
const addressText = document.getElementById("address-text");
const addressInput = document.getElementById("address-input");
const copyBtn = document.getElementById("btn-copy-address");
const presetButtons = document.querySelectorAll(".port-preset");
const updateDisplay = async () => {
const host = await config.get("burpProxyHost")
const port = await config.get("burpProxyPort")
addressText.textContent = `${host}:${port}`
}
const refreshAddressDisplay = (host, port) => {
const fullAddr = `${host}:${port}`;
if (addressText) addressText.textContent = fullAddr;
if (addressInput) addressInput.value = fullAddr;
await updateDisplay()
// Highlight matching preset
presetButtons.forEach(btn => {
if (btn.dataset.port === String(port)) {
btn.classList.add("active");
} else {
btn.classList.remove("active");
}
});
};
statusBar.addEventListener("click", () => {
addressText.style.display = "none"
addressInput.style.display = "block"
addressInput.value = addressText.textContent
addressInput.focus()
})
refreshAddressDisplay(currentHost, currentPort);
const saveAddress = async () => {
const value = addressInput.value.trim()
if (value.includes(":")) {
const [host, port] = value.split(":")
await config.set("burpProxyHost", host)
await config.set("burpProxyPort", port)
}
addressInput.style.display = "none"
addressText.style.display = "block"
await updateDisplay()
}
// Click to inline edit
if (addressChip && addressInput && addressText) {
addressChip.addEventListener("click", (e) => {
if (e.target === addressInput) return;
addressText.style.display = "none";
addressInput.style.display = "block";
addressInput.focus();
addressInput.select();
});
addressInput.addEventListener("blur", saveAddress)
addressInput.addEventListener("keydown", (e) => {
if (e.key === "Enter") saveAddress()
if (e.key === "Escape") {
addressInput.style.display = "none"
addressText.style.display = "block"
}
})
}
const saveAddressInput = async () => {
const raw = addressInput.value.trim();
if (raw.includes(":")) {
const parts = raw.split(":");
const host = parts[0].trim() || "127.0.0.1";
const port = parts[1].trim() || "8080";
await config.setMultiple({ burpProxyHost: host, burpProxyPort: port });
refreshAddressDisplay(host, port);
showToast(`Target set to ${host}:${port}`);
}
addressInput.style.display = "none";
addressText.style.display = "block";
};
async function main() {
createContainerTabButtons()
setupInlineAddressEdit()
addressInput.addEventListener("blur", saveAddressInput);
addressInput.addEventListener("keydown", (e) => {
if (e.key === "Enter") {
saveAddressInput();
} else if (e.key === "Escape") {
addressInput.style.display = "none";
addressText.style.display = "block";
}
});
}
bindCheckboxToConfig("#option-enabled", config, "enabled")
bindCheckboxToConfig("#option-useBurpProxyAll", config, "useBurpProxyAll")
bindCheckboxToConfig("#option-useBurpProxyContainer", config, "useBurpProxyContainer")
bindCheckboxToConfig("#option-addContainerHeader", config, "addContainerHeader")
bindCheckboxToConfig("#option-removeSecurityHeaders", config, "removeSecurityHeaders")
// Quick Port Presets
presetButtons.forEach(btn => {
btn.addEventListener("click", async () => {
const port = btn.dataset.port;
const host = (await config.get("burpProxyHost")) || "127.0.0.1";
await config.set("burpProxyPort", port);
refreshAddressDisplay(host, port);
showToast(`Port switched to ${port}`);
});
});
/* Hook settings link */
document.querySelector("#settings").addEventListener("click", ev => {
browser.runtime.openOptionsPage()
})
config.onChange('enabled', toggleZeroX, true)
toggleZeroX(await config.get("enabled"))
// Copy Address Button
if (copyBtn) {
copyBtn.addEventListener("click", async () => {
const host = (await config.get("burpProxyHost")) || "127.0.0.1";
const port = (await config.get("burpProxyPort")) || "8080";
const fullAddr = `${host}:${port}`;
try {
await navigator.clipboard.writeText(fullAddr);
showToast(`Copied ${fullAddr}`);
} catch (err) {
showToast(`Proxy: ${fullAddr}`);
}
});
}
}
window.addEventListener("load", main)
/* Bind Checkbox with Instant Sync */
function bindCheckbox(elementId, configKey, initialValue) {
const el = document.getElementById(elementId);
if (!el) return;
el.checked = Boolean(initialValue);
el.addEventListener("change", () => {
config.set(configKey, el.checked);
});
}
/* Fast Bootstrap */
async function initPopup() {
renderContainerGrid();
// Batch load all configurations simultaneously
const currentConfig = await config.getAll();
// Master Toggle
const masterCheckbox = document.getElementById("option-enabled");
if (masterCheckbox) {
masterCheckbox.checked = Boolean(currentConfig.enabled);
masterCheckbox.addEventListener("change", () => {
config.set("enabled", masterCheckbox.checked);
updateMasterStatus(masterCheckbox.checked);
});
}
updateMasterStatus(Boolean(currentConfig.enabled));
// Address & Ports
setupAddressControls(
currentConfig.burpProxyHost || "127.0.0.1",
currentConfig.burpProxyPort || "8080"
);
// Feature Toggles
bindCheckbox("option-useBurpProxyAll", "useBurpProxyAll", currentConfig.useBurpProxyAll);
bindCheckbox("option-useBurpProxyContainer", "useBurpProxyContainer", currentConfig.useBurpProxyContainer);
bindCheckbox("option-addContainerHeader", "addContainerHeader", currentConfig.addContainerHeader);
bindCheckbox("option-removeSecurityHeaders", "removeSecurityHeaders", currentConfig.removeSecurityHeaders);
// Settings Link
const settingsBtn = document.getElementById("btn-settings");
if (settingsBtn) {
settingsBtn.addEventListener("click", () => {
browser.runtime.openOptionsPage();
});
}
// Listen for storage changes from background/options page
config.onChange("enabled", (newVal) => {
updateMasterStatus(Boolean(newVal));
});
}
// Start as soon as DOM is ready without waiting for remote assets
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initPopup);
} else {
initPopup();
}

@@ -6,35 +6,62 @@ <!DOCTYPE html>

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ZeroX Settings - Security & Proxy Suite</title>
<link rel="stylesheet" href="settings.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
</head>
<body>
<div class="settings-container">
<header>
<!-- Header -->
<header class="settings-header">
<div class="logo-box">
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor">
<path d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm0 18c-4.411 0-8-3.589-8-8s3.589-8 8-8 8 3.589 8 8-3.589 8-8 8z"/>
<path d="M13 7h-2v6h6v-2h-4z"/>
<svg viewBox="0 0 32 32" width="32" height="32" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="settings-grad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#a855f7"/>
<stop offset="50%" stop-color="#7c3aed"/>
<stop offset="100%" stop-color="#3b82f6"/>
</linearGradient>
</defs>
<path d="M16 3L4 8V15C4 22.38 9.12 29.24 16 31C22.88 29.24 28 22.38 28 15V8L16 3Z" fill="url(#settings-grad)"/>
<path d="M16 6.5L7 10.3V15.5C7 21.2 10.8 26.6 16 28C21.2 26.6 25 21.2 25 15.5V10.3L16 6.5Z" fill="#0c0e17" fill-opacity="0.8"/>
<path d="M12 11L20 21M20 11L12 21" stroke="#ffffff" stroke-width="2.5" stroke-linecap="round"/>
</svg>
</div>
<div class="header-text">
<h1>ZeroX Settings</h1>
<p>Configure your security proxy and tools</p>
<div class="header-badge">ZEROX SECURITY TOOLKIT</div>
<h1>Settings & Configuration</h1>
<p>Manage Burp Suite proxy endpoints and security interception parameters</p>
</div>
</header>
<!-- Main Form -->
<main>
<form>
<form id="settings-form">
<!-- Burp Proxy Settings Card -->
<section class="settings-card">
<div class="card-header">
<svg class="card-icon" viewBox="0 0 24 24" width="18" height="18" fill="currentColor">
<path d="M20 7h-4V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2H4a2 2 0 0 0-2 2v11a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2zM10 5h4v2h-4V5zM4 9h16v3h-16V9zm0 11v-6h16v6H4z"/>
</svg>
<h2>Burp Suite Proxy</h2>
<div class="card-header-icon">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2">
<rect x="2" y="2" width="20" height="8" rx="2" ry="2"></rect>
<rect x="2" y="14" width="20" height="8" rx="2" ry="2"></rect>
<line x1="6" y1="6" x2="6.01" y2="6"></line>
<line x1="6" y1="18" x2="6.01" y2="18"></line>
</svg>
</div>
<div class="card-header-title">
<h2>Burp Suite Proxy Target</h2>
<p>Default target address used for intercepting web traffic</p>
</div>
</div>
<div class="input-group">
<div class="input-grid">
<div class="input-field">
<label for="burphost">Proxy Host</label>
<input type="text" id="burphost" placeholder="127.0.0.1">
<span class="input-hint">The IP address of your Burp instance</span>
<label for="burphost">Proxy Host / IP</label>
<div class="input-wrapper">
<svg class="input-icon" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"></circle>
<line x1="2" y1="12" x2="22" y2="12"></line>
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path>
</svg>
<input type="text" id="burphost" placeholder="127.0.0.1" spellcheck="false" required>
</div>
<span class="input-hint">The hostname or IP address of your Burp Suite instance (usually <code>127.0.0.1</code>)</span>
</div>

@@ -44,4 +71,15 @@

<label for="burpport">Proxy Port</label>
<input type="text" id="burpport" placeholder="8080">
<span class="input-hint">Default is 8080</span>
<div class="input-wrapper">
<svg class="input-icon" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline>
</svg>
<input type="number" id="burpport" placeholder="8080" min="1" max="65535" spellcheck="false" required>
</div>
<div class="quick-port-chips">
<span class="chips-label">Presets:</span>
<button type="button" class="chip-btn" data-port="8080">8080 (Default)</button>
<button type="button" class="chip-btn" data-port="8081">8081</button>
<button type="button" class="chip-btn" data-port="8888">8888</button>
<button type="button" class="chip-btn" data-port="1080">1080 (SOCKS)</button>
</div>
</div>

@@ -51,5 +89,28 @@ </div>

<!-- Information Card -->
<section class="settings-card info-card">
<div class="info-row">
<div class="info-icon">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="16" x2="12" y2="12"></line>
<line x1="12" y1="8" x2="12.01" y2="8"></line>
</svg>
</div>
<div class="info-content">
<h3>Extension Features & Status</h3>
<p>ZeroX isolates tabs into Firefox Container tabs and dynamically adds <code>X-ZeroX-Color</code> headers, enabling pinpoint tracking inside Burp Suite Logger & Repeater.</p>
</div>
</div>
</section>
<div class="form-actions">
<div id="save-status" class="save-status"></div>
<button type="submit" id="save" class="btn-primary">
<span>Save Configuration</span>
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2">
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path>
<polyline points="17 21 17 13 7 13 7 21"></polyline>
<polyline points="7 3 7 8 15 8"></polyline>
</svg>
<span id="btn-text">Save Configuration</span>
</button>

@@ -60,5 +121,5 @@ </div>

<footer>
<p>Created with ♥ by TUΛNHΛDΞS</p>
<p class="version">ZeroX v2.0.0</p>
<footer class="settings-footer">
<p>ZeroX Security Suite • Firefox Add-on</p>
<p class="version">v2.0.1</p>
</footer>

@@ -65,0 +126,0 @@ </div>

@@ -0,16 +1,29 @@

/* ZeroX Settings - Obsidian Cyber Theme */
:root {
--bg-dark: #0f111a;
--bg-surface: #1a1d2b;
--bg-header: linear-gradient(135deg, #a855f7 0%, #7c3aed 100%);
--bg-base: #090b12;
--bg-surface: rgba(18, 22, 38, 0.7);
--bg-surface-elevated: rgba(25, 30, 52, 0.8);
--bg-input: rgba(11, 14, 24, 0.85);
--text-main: #f1f5f9;
--text-dim: #94a3b8;
--border-subtle: rgba(255, 255, 255, 0.08);
--border-card: rgba(255, 255, 255, 0.12);
--border-focus: rgba(168, 85, 247, 0.6);
--accent: #a855f7;
--accent-glow: rgba(168, 85, 247, 0.3);
--text-primary: #f8fafc;
--text-secondary: #94a3b8;
--text-muted: #64748b;
--border: rgba(255, 255, 255, 0.08);
--border-focus: rgba(168, 85, 247, 0.5);
--accent-purple: #a855f7;
--accent-purple-dark: #7c3aed;
--accent-purple-glow: rgba(168, 85, 247, 0.35);
--accent-emerald: #10b981;
--accent-cyan: #06b6d4;
--transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
--font-stack: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Inter", "Helvetica Neue", Arial, sans-serif;
--transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
--radius-sm: 8px;
--radius-md: 14px;
--radius-lg: 20px;
--radius-full: 9999px;
}

@@ -22,13 +35,17 @@

box-sizing: border-box;
-webkit-font-smoothing: antialiased;
}
body {
background-color: var(--bg-dark);
color: var(--text-main);
font-family: 'Inter', -apple-system, sans-serif;
line-height: 1.5;
background-color: var(--bg-base);
background-image:
radial-gradient(circle at 20% 0%, rgba(168, 85, 247, 0.15) 0%, transparent 50%),
radial-gradient(circle at 80% 100%, rgba(59, 130, 246, 0.1) 0%, transparent 50%);
color: var(--text-primary);
font-family: var(--font-stack);
line-height: 1.6;
min-height: 100vh;
display: flex;
justify-content: center;
padding: 40px 20px;
padding: 48px 24px;
}

@@ -38,3 +55,3 @@

width: 100%;
max-width: 600px;
max-width: 640px;
display: flex;

@@ -45,4 +62,6 @@ flex-direction: column;

/* Header */
header {
/* ==========================================================================
Header
========================================================================== */
.settings-header {
display: flex;

@@ -54,36 +73,53 @@ align-items: center;

.logo-box {
width: 60px;
height: 60px;
background: var(--bg-header);
border-radius: 16px;
width: 58px;
height: 58px;
background: linear-gradient(135deg, #181c30 0%, #101322 100%);
border: 1px solid var(--border-card);
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
color: white;
box-shadow: 0 8px 24px var(--accent-glow);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4), 0 0 16px var(--accent-purple-glow);
flex-shrink: 0;
}
.header-text {
display: flex;
flex-direction: column;
gap: 3px;
}
.header-badge {
font-size: 10px;
font-weight: 800;
letter-spacing: 1px;
color: #c084fc;
text-transform: uppercase;
}
.header-text h1 {
font-size: 28px;
font-size: 24px;
font-weight: 800;
letter-spacing: -0.5px;
margin-bottom: 4px;
background: linear-gradient(to right, #fff, #94a3b8);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
color: #ffffff;
}
.header-text p {
color: var(--text-dim);
font-size: 14px;
color: var(--text-secondary);
font-size: 13px;
}
/* Cards */
/* ==========================================================================
Cards & Layout
========================================================================== */
.settings-card {
background: var(--bg-surface);
border: 1px solid var(--border);
border-radius: 24px;
padding: 32px;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(10px);
border: 1px solid var(--border-card);
border-radius: var(--radius-lg);
padding: 28px;
backdrop-filter: blur(16px);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
display: flex;
flex-direction: column;
gap: 24px;
}

@@ -93,24 +129,37 @@

display: flex;
align-items: center;
gap: 12px;
margin-bottom: 28px;
padding-bottom: 16px;
border-bottom: 1px solid var(--border);
align-items: flex-start;
gap: 14px;
padding-bottom: 18px;
border-bottom: 1px solid var(--border-subtle);
}
.card-icon {
color: var(--accent);
.card-header-icon {
width: 36px;
height: 36px;
border-radius: 10px;
background: rgba(168, 85, 247, 0.15);
border: 1px solid rgba(168, 85, 247, 0.3);
color: #c084fc;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.card-header h2 {
font-size: 18px;
.card-header-title h2 {
font-size: 17px;
font-weight: 700;
color: var(--text-main);
color: #ffffff;
}
/* Inputs */
.input-group {
.card-header-title p {
font-size: 12.5px;
color: var(--text-secondary);
}
/* Input Fields */
.input-grid {
display: flex;
flex-direction: column;
gap: 24px;
gap: 20px;
}

@@ -127,48 +176,174 @@

font-weight: 600;
color: var(--text-main);
letter-spacing: 0.3px;
color: #e2e8f0;
letter-spacing: 0.2px;
}
.input-field input {
background: rgba(255, 255, 255, 0.03);
border: 1px solid var(--border);
border-radius: 12px;
padding: 12px 16px;
color: white;
font-family: inherit;
font-size: 14px;
.input-wrapper {
position: relative;
display: flex;
align-items: center;
}
.input-icon {
position: absolute;
left: 14px;
color: var(--text-muted);
pointer-events: none;
transition: var(--transition);
}
.input-field input:focus {
.input-wrapper input {
width: 100%;
background: var(--bg-input);
border: 1px solid var(--border-card);
border-radius: var(--radius-md);
padding: 12px 16px 12px 42px;
color: #ffffff;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 13.5px;
font-weight: 500;
transition: var(--transition);
}
.input-wrapper input:focus {
outline: none;
background: rgba(255, 255, 255, 0.05);
border-color: var(--border-focus);
box-shadow: 0 0 0 4px var(--accent-glow);
border-color: var(--accent-purple);
background: rgba(15, 20, 36, 0.95);
box-shadow: 0 0 0 3px var(--accent-purple-glow);
}
.input-wrapper input:focus + .input-icon,
.input-wrapper:focus-within .input-icon {
color: var(--accent-purple);
}
.input-hint {
font-size: 11.5px;
color: var(--text-muted);
}
.input-hint code {
background: rgba(255, 255, 255, 0.08);
padding: 2px 5px;
border-radius: 4px;
font-family: monospace;
color: #cbd5e1;
}
/* Quick Port Chips */
.quick-port-chips {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
margin-top: 4px;
}
.chips-label {
font-size: 11.5px;
color: var(--text-muted);
font-weight: 600;
}
.chip-btn {
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-sm);
color: var(--text-secondary);
font-family: ui-monospace, SFMono-Regular, monospace;
font-size: 11px;
color: var(--text-dim);
opacity: 0.8;
font-weight: 600;
padding: 4px 10px;
cursor: pointer;
transition: var(--transition);
}
/* Actions */
.chip-btn:hover {
background: rgba(168, 85, 247, 0.2);
border-color: rgba(168, 85, 247, 0.4);
color: #ffffff;
transform: translateY(-1px);
}
.chip-btn.active {
background: rgba(168, 85, 247, 0.35);
border-color: var(--accent-purple);
color: #ffffff;
}
/* Info Card */
.info-card {
padding: 18px 24px;
background: rgba(15, 23, 42, 0.4);
border-color: rgba(59, 130, 246, 0.2);
}
.info-row {
display: flex;
align-items: flex-start;
gap: 14px;
}
.info-icon {
color: #60a5fa;
margin-top: 2px;
}
.info-content h3 {
font-size: 13.5px;
font-weight: 700;
color: #e2e8f0;
margin-bottom: 2px;
}
.info-content p {
font-size: 12px;
color: var(--text-secondary);
line-height: 1.5;
}
.info-content code {
background: rgba(59, 130, 246, 0.15);
color: #93c5fd;
padding: 2px 6px;
border-radius: 4px;
font-family: monospace;
font-size: 11px;
}
/* Form Actions */
.form-actions {
margin-top: 8px;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 16px;
margin-top: 12px;
}
.save-status {
font-size: 12.5px;
font-weight: 600;
color: var(--accent-emerald);
opacity: 0;
transition: opacity 0.2s ease;
}
.save-status.show {
opacity: 1;
}
.btn-primary {
background: var(--bg-header);
color: white;
background: linear-gradient(135deg, #a855f7 0%, #7c3aed 100%);
color: #ffffff;
border: none;
border-radius: 12px;
padding: 14px 28px;
font-size: 14px;
border-radius: var(--radius-md);
padding: 12px 24px;
font-size: 13.5px;
font-weight: 700;
cursor: pointer;
display: flex;
align-items: center;
gap: 8px;
transition: var(--transition);
box-shadow: 0 4px 12px var(--accent-glow);
box-shadow: 0 4px 16px var(--accent-purple-glow);
}

@@ -178,3 +353,3 @@

transform: translateY(-2px);
box-shadow: 0 6px 20px var(--accent-glow);
box-shadow: 0 6px 22px rgba(168, 85, 247, 0.5);
filter: brightness(1.1);

@@ -187,25 +362,20 @@ }

.btn-primary.success {
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
box-shadow: 0 4px 16px rgba(16, 185, 129, 0.4);
}
/* Footer */
footer {
.settings-footer {
display: flex;
align-items: center;
justify-content: space-between;
align-items: center;
padding-top: 20px;
border-top: 1px solid var(--border);
margin-top: 20px;
}
footer p {
border-top: 1px solid var(--border-subtle);
color: var(--text-muted);
font-size: 12px;
color: var(--text-dim);
}
.version {
font-weight: 600;
opacity: 0.5;
}
/* Success State (optional animation) */
.btn-primary.saved {
background: #10b981;
font-weight: 700;
}

@@ -0,36 +1,82 @@

/**
* ZeroX Settings Page Controller
*/
async function main() {
const $ = i => document.getElementById(i)
const hostInput = document.getElementById("burphost");
const portInput = document.getElementById("burpport");
const form = document.getElementById("settings-form");
const saveBtn = document.getElementById("save");
const btnText = document.getElementById("btn-text");
const saveStatus = document.getElementById("save-status");
const presetChips = document.querySelectorAll(".chip-btn");
const configEl = [
[$("burphost"), "burpProxyHost"],
[$("burpport"), "burpProxyPort"],
]
// Load initial values
const currentConfig = await config.getAll();
if (hostInput) hostInput.value = currentConfig.burpProxyHost || "127.0.0.1";
if (portInput) portInput.value = currentConfig.burpProxyPort || "8080";
const updatePresetHighlight = (port) => {
presetChips.forEach(chip => {
if (chip.dataset.port === String(port)) {
chip.classList.add("active");
} else {
chip.classList.remove("active");
}
});
};
/* Config to form */
configEl.forEach(([el, configName]) => {
config.get(configName).then(v => el.value = v)
})
updatePresetHighlight(currentConfig.burpProxyPort || "8080");
/* Form to config */
document.querySelector("form").addEventListener("submit", ev => {
ev.preventDefault();
configEl.forEach(([el, configName]) => {
config.set(configName, el.value)
})
const saveBtn = $("save")
const btnSpan = saveBtn.querySelector("span")
const originalText = btnSpan.textContent
btnSpan.textContent = "Saved Successfully!"
saveBtn.style.background = "#10b981"
setTimeout(() => {
btnSpan.textContent = originalText
saveBtn.style.background = ""
}, 2000)
// Preset Chip click listener
presetChips.forEach(chip => {
chip.addEventListener("click", () => {
if (portInput) {
portInput.value = chip.dataset.port;
updatePresetHighlight(chip.dataset.port);
portInput.focus();
}
});
});
if (portInput) {
portInput.addEventListener("input", () => {
updatePresetHighlight(portInput.value.trim());
});
}
// Save configuration
if (form) {
form.addEventListener("submit", async (e) => {
e.preventDefault();
const host = hostInput.value.trim() || "127.0.0.1";
const port = portInput.value.trim() || "8080";
await config.setMultiple({
burpProxyHost: host,
burpProxyPort: port
});
// UI Success State
if (saveBtn) saveBtn.classList.add("success");
if (btnText) btnText.textContent = "Saved Successfully!";
if (saveStatus) {
saveStatus.textContent = `Active target: ${host}:${port}`;
saveStatus.classList.add("show");
}
setTimeout(() => {
if (saveBtn) saveBtn.classList.remove("success");
if (btnText) btnText.textContent = "Save Configuration";
if (saveStatus) saveStatus.classList.remove("show");
}, 2500);
});
}
}
document.addEventListener("DOMContentLoaded", main)
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", main);
} else {
main();
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display