@fanboynz/network-scanner
Version:
A Puppeteer-based network scanner for analyzing web traffic, generating adblock filter rules, and identifying third-party requests. Features include fingerprint spoofing, Cloudflare bypass, content analysis with curl/grep, and multiple output formats.
794 lines (696 loc) • 32.2 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Regex Tools - Converter & Validator</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1000px;
margin: 0 auto;
background: rgba(255, 255, 255, 0.95);
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 30px;
text-align: center;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
animation: fadeInDown 0.5s ease;
}
.header p {
opacity: 0.9;
font-size: 1.1em;
}
.tabs {
display: flex;
background: #f7f9fc;
border-bottom: 2px solid #e2e8f0;
}
.tab {
flex: 1;
padding: 20px;
text-align: center;
cursor: pointer;
background: transparent;
border: none;
font-size: 1.1em;
font-weight: 600;
color: #64748b;
transition: all 0.3s ease;
position: relative;
}
.tab:hover {
background: rgba(102, 126, 234, 0.1);
}
.tab.active {
color: #667eea;
background: white;
}
.tab.active::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(90deg, #667eea, #764ba2);
animation: slideIn 0.3s ease;
}
.content {
padding: 40px;
min-height: 500px;
}
.tab-content {
display: none;
animation: fadeIn 0.3s ease;
}
.tab-content.active {
display: block;
}
.input-group {
margin-bottom: 30px;
}
.input-group label {
display: block;
margin-bottom: 10px;
font-weight: 600;
color: #334155;
font-size: 1.1em;
}
.input-group input[type="text"],
.input-group textarea {
width: 100%;
padding: 15px;
border: 2px solid #e2e8f0;
border-radius: 10px;
font-size: 1em;
font-family: 'Consolas', 'Monaco', monospace;
transition: all 0.3s ease;
}
.input-group input[type="text"]:focus,
.input-group textarea:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.input-group textarea {
resize: vertical;
min-height: 100px;
}
.checkbox-group {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.checkbox-group input[type="checkbox"] {
width: 20px;
height: 20px;
margin-right: 10px;
cursor: pointer;
}
.checkbox-group label {
cursor: pointer;
font-weight: 500;
color: #475569;
}
.button {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 15px 40px;
border-radius: 10px;
font-size: 1.1em;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
}
.button:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
}
.button:active {
transform: translateY(0);
}
.output-section {
margin-top: 40px;
padding: 25px;
background: #f8fafc;
border-radius: 10px;
border: 2px solid #e2e8f0;
}
.output-section h3 {
margin-bottom: 15px;
color: #334155;
font-size: 1.3em;
}
.output-box {
background: white;
padding: 20px;
border-radius: 8px;
border: 1px solid #e2e8f0;
font-family: 'Consolas', 'Monaco', monospace;
margin-bottom: 20px;
word-break: break-all;
transition: all 0.3s ease;
}
.output-box:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.examples-list {
list-style: none;
padding: 0;
}
.examples-list li {
background: white;
padding: 15px;
margin-bottom: 10px;
border-radius: 8px;
border-left: 4px solid #667eea;
font-family: 'Consolas', 'Monaco', monospace;
transition: all 0.3s ease;
}
.examples-list li:hover {
transform: translateX(5px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.error {
background: #fee;
color: #c00;
padding: 15px;
border-radius: 8px;
border: 1px solid #fcc;
margin-top: 10px;
}
.success {
background: #e6fffa;
color: #047857;
padding: 15px;
border-radius: 8px;
border: 1px solid #6ee7b7;
margin-top: 10px;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInDown {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideIn {
from {
transform: scaleX(0);
}
to {
transform: scaleX(1);
}
}
@media (max-width: 768px) {
.header h1 {
font-size: 1.8em;
}
.content {
padding: 20px;
}
.button {
width: 100%;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>?? Regex Tools</h1>
<p>Convert and Validate Regular Expressions with Ease</p>
</div>
<div class="tabs">
<button class="tab active" data-tab="convert">
?? Convert to JSON
</button>
<button class="tab" data-tab="validate">
? Validate Regex
</button>
</div>
<div class="content">
<!-- Convert Tab -->
<div id="convert" class="tab-content active">
<div class="input-group">
<label for="standardRegex">Enter Standard Regex Pattern:</label>
<input type="text" id="standardRegex" placeholder="e.g., ^https?://.*\.example\.com/.*$">
</div>
<button class="button" id="convertBtn">Convert to JSON</button>
<div id="convertOutput"></div>
</div>
<!-- Validate Tab -->
<div id="validate" class="tab-content">
<div class="checkbox-group" style="background: #f0f9ff; padding: 15px; border-radius: 8px; margin-bottom: 20px; border: 2px solid #0ea5e9;">
<input type="checkbox" id="useStandardRegex">
<label for="useStandardRegex"><strong>?? Check this box to validate Standard Regex</strong> (uncheck for JSON format)</label>
</div>
<div class="input-group">
<label for="regexToValidate">Enter Regex Pattern:</label>
<textarea id="regexToValidate" placeholder='?? IMPORTANT: Check the box above if entering standard regex! For JSON (box unchecked): {"filterRegex": ["^https?:\\\\/\\\\/.*"]} For Standard (box checked): ^https?:\\/\\/.*'></textarea>
</div>
<button class="button" id="validateBtn">Validate Regex</button>
<div id="validateOutput"></div>
</div>
</div>
</div>
<script>
// Use DOMContentLoaded to ensure all elements are loaded
document.addEventListener('DOMContentLoaded', function() {
// Tab switching with event delegation
const tabs = document.querySelectorAll('.tab');
tabs.forEach(tab => {
tab.addEventListener('click', function() {
const tabName = this.getAttribute('data-tab');
switchTab(tabName, this);
});
});
// Button event listeners
document.getElementById('convertBtn').addEventListener('click', convertToJSON);
document.getElementById('validateBtn').addEventListener('click', validateRegex);
document.getElementById('useStandardRegex').addEventListener('change', toggleRegexInput);
// Enter key support
document.getElementById('standardRegex').addEventListener('keypress', function(e) {
if (e.key === 'Enter') convertToJSON();
});
document.getElementById('regexToValidate').addEventListener('keypress', function(e) {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
validateRegex();
}
});
});
function switchTab(tabName, clickedTab) {
// Update tabs
document.querySelectorAll('.tab').forEach(tab => {
tab.classList.remove('active');
});
clickedTab.classList.add('active');
// Update content
document.querySelectorAll('.tab-content').forEach(content => {
content.classList.remove('active');
});
document.getElementById(tabName).classList.add('active');
}
function toggleRegexInput() {
const checkbox = document.getElementById('useStandardRegex');
const textarea = document.getElementById('regexToValidate');
if (checkbox.checked) {
textarea.placeholder = 'Enter standard regex pattern, e.g., ^https?://.*';
} else {
textarea.placeholder = 'Enter JSON regex, e.g., {"pattern": "^https?://.*", "flags": "gi"}';
}
textarea.value = '';
}
function generateExamples(regex) {
const examples = [];
try {
// Get the pattern string
const pattern = regex.source || regex.pattern || regex.toString();
// Helper function to generate random string of specific length
function generateRandomString(minLen, maxLen) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-+=';
const length = maxLen ? Math.floor(Math.random() * (maxLen - minLen + 1)) + minLen : minLen;
let result = '';
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
if (pattern.includes('http')) {
// Check for specific domain requirements
if (pattern.includes('com|org')) {
// Pattern requires .com or .org domains
const protocols = pattern.includes('https?') ? ['https://', 'http://'] : ['https://'];
const domains = ['example', 'test-site', 'web-app', 'api-server', 'my-service'];
const extensions = ['com', 'org'];
for (let i = 0; i < 5; i++) {
const protocol = protocols[i % protocols.length];
const domain = domains[i % domains.length];
const ext = extensions[i % extensions.length];
// Build the path part
let path = '';
// Check for specific length requirements in path
const pathMatch = pattern.match(/\[A-Za-z0-9[^\]]*\]\{(\d+),?(\d*)\}/);
if (pathMatch) {
const minLen = parseInt(pathMatch[1]);
const maxLen = pathMatch[2] ? parseInt(pathMatch[2]) : minLen + 20;
path = generateRandomString(minLen, maxLen);
} else {
path = 'api/v1/users/profile/data';
}
let url = `${protocol}${domain}.${ext}/${path}`;
// Add query params if pattern requires them
if (pattern.includes('\\?')) {
// Check for minimum length requirements in query
const queryMatch = pattern.match(/\\\?\.\{(\d+),?(\d*)\}/);
if (queryMatch) {
const minLen = parseInt(queryMatch[1]);
const maxLen = queryMatch[2] ? parseInt(queryMatch[2]) : minLen + 10;
url += '?' + generateRandomString(minLen, maxLen);
} else if (pattern.match(/\?\.\{(\d+),/)) {
// Handle any {n,} pattern after ?
const match = pattern.match(/\?\.\{(\d+),/);
const minLen = parseInt(match[1]);
url += '?param=' + generateRandomString(Math.max(minLen - 6, 1), minLen + 15);
} else {
url += '?param=value&key=data';
}
} else if (pattern.includes('&.{')) {
// Handle &.{n,} case
const ampMatch = pattern.match(/&\.\{(\d+),/);
if (ampMatch) {
const minLen = parseInt(ampMatch[1]);
url += '&' + generateRandomString(minLen, minLen + 15);
}
}
examples.push(url);
}
} else {
// General URL patterns
const protocols = pattern.includes('https?') ? ['http://', 'https://'] : ['https://'];
const urls = [
'www.example.com/path/to/resource',
'subdomain.test.com/api/endpoint',
'example.org/page/section/item',
'demo.net/products/category',
'sample.io/user/profile/settings'
];
urls.forEach((url, i) => {
if (i < 5) {
let fullUrl = protocols[i % protocols.length] + url;
// Check for length requirements
const lengthMatch = pattern.match(/\{(\d+),?(\d*)\}/);
if (lengthMatch && !pattern.includes('\\?')) {
const minLen = parseInt(lengthMatch[1]);
const maxLen = lengthMatch[2] ? parseInt(lengthMatch[2]) : minLen + 10;
fullUrl += '/' + generateRandomString(minLen, maxLen);
}
examples.push(fullUrl);
}
});
}
// Test all generated examples against the regex
const validExamples = [];
for (const example of examples) {
try {
// Reset regex lastIndex in case of global flag
regex.lastIndex = 0;
if (regex.test(example)) {
validExamples.push(example);
}
} catch (e) {
console.error('Error testing example:', e);
}
}
// If we don't have enough valid examples, try more specific ones with proper lengths
if (validExamples.length < 5) {
const moreSpecific = [];
for (let i = 0; i < 10; i++) {
const protocol = i % 2 === 0 ? 'https://' : 'http://';
const domain = ['test-api', 'web-server', 'my-app', 'demo-site', 'api-gateway'][i % 5];
const ext = i % 2 === 0 ? 'com' : 'org';
// Generate path with proper length if specified
let path = 'Path_';
const pathMatch = pattern.match(/\[A-Za-z0-9[^\]]*\]\{(\d+),?(\d*)\}/);
if (pathMatch) {
const minLen = parseInt(pathMatch[1]);
const maxLen = pathMatch[2] ? parseInt(pathMatch[2]) : minLen + 20;
path = generateRandomString(minLen, maxLen);
} else {
path += generateRandomString(10, 30);
}
let url = `${protocol}${domain}.${ext}/${path}`;
// Add query with proper length if needed
if (pattern.includes('\\?')) {
const queryMatch = pattern.match(/\\\?\.\{(\d+),?(\d*)\}/);
if (queryMatch) {
const minLen = parseInt(queryMatch[1]);
url += '?q=' + generateRandomString(Math.max(minLen - 2, 1), minLen + 10);
} else if (pattern.match(/\?\.\{(\d+),/)) {
const match = pattern.match(/\?\.\{(\d+),/);
const minLen = parseInt(match[1]);
url += '?' + generateRandomString(minLen, minLen + 15);
} else {
url += '?param=' + generateRandomString(10, 20);
}
} else if (pattern.includes('&.{')) {
const ampMatch = pattern.match(/&\.\{(\d+),/);
if (ampMatch) {
const minLen = parseInt(ampMatch[1]);
url += '&' + generateRandomString(minLen, minLen + 15);
}
}
moreSpecific.push(url);
}
for (const url of moreSpecific) {
regex.lastIndex = 0;
if (regex.test(url) && validExamples.length < 5) {
validExamples.push(url);
}
}
}
return validExamples.length > 0 ? validExamples.slice(0, 5) : [
'Pattern is very specific - generating custom examples...',
'Try: https://example.com/Page_Name/path?query=value12345',
'Try: http://test.org/API_endpoint/data?param=longvalue123',
'Manual testing recommended for this pattern',
'Validation successful'
];
} else if (pattern.includes('@')) {
examples.push(
'user@example.com',
'john.doe@company.org',
'admin+tag@subdomain.example.com',
'contact@business.co.uk',
'support123@service.io'
);
} else if (pattern.includes('\\d')) {
// Check for length requirements
const lengthMatch = pattern.match(/\{(\d+),?(\d*)\}/);
if (lengthMatch) {
const minLen = parseInt(lengthMatch[1]);
const maxLen = lengthMatch[2] ? parseInt(lengthMatch[2]) : minLen + 10;
for (let i = 0; i < 5; i++) {
examples.push(generateRandomString(minLen, maxLen));
}
} else {
examples.push(
'12345',
'2024-01-15',
'ID-9876-XY',
'Version 3.14.159',
'Order #00425'
);
}
} else if (pattern.includes('\\w')) {
// Check for length requirements
const lengthMatch = pattern.match(/\{(\d+),?(\d*)\}/);
if (lengthMatch) {
const minLen = parseInt(lengthMatch[1]);
const maxLen = lengthMatch[2] ? parseInt(lengthMatch[2]) : minLen + 10;
for (let i = 0; i < 5; i++) {
examples.push(generateRandomString(minLen, maxLen));
}
} else {
examples.push(
'HelloWorld',
'user_name_123',
'CamelCaseExample',
'snake_case_text',
'MixedContent2024'
);
}
} else {
// Check for any length requirements in the pattern
const lengthMatch = pattern.match(/\{(\d+),?(\d*)\}/);
if (lengthMatch) {
const minLen = parseInt(lengthMatch[1]);
const maxLen = lengthMatch[2] ? parseInt(lengthMatch[2]) : minLen + 15;
for (let i = 0; i < 5; i++) {
examples.push(generateRandomString(minLen, maxLen));
}
} else {
// Generic examples
examples.push(
'example text',
'Sample String 123',
'test-data-here',
'Another_Example',
'final.test.value'
);
}
}
// Filter examples that actually match the regex
const validExamples = examples.filter(ex => {
try {
regex.lastIndex = 0;
return regex.test(ex);
} catch (e) {
return false;
}
});
return validExamples.length > 0 ? validExamples.slice(0, 5) : [
'No automatic examples could be generated.',
'The pattern may be too specific.',
'Try testing with your own strings.',
'Enter test strings manually.',
'Pattern validation successful.'
];
} catch (error) {
console.error('Error in generateExamples:', error);
return ['Error generating examples'];
}
}
function convertToJSON() {
const standardRegex = document.getElementById('standardRegex').value;
const outputDiv = document.getElementById('convertOutput');
if (!standardRegex) {
outputDiv.innerHTML = '<div class="error">Please enter a regex pattern</div>';
return;
}
try {
// Remove surrounding quotes if present
let cleanPattern = standardRegex.trim();
if ((cleanPattern.startsWith('"') && cleanPattern.endsWith('"')) ||
(cleanPattern.startsWith("'") && cleanPattern.endsWith("'"))) {
cleanPattern = cleanPattern.slice(1, -1);
}
// Test if the regex is valid first (using the cleaned pattern)
const testRegex = new RegExp(cleanPattern);
// For JSON string format: the input pattern stays as is
// JSON.stringify will handle the escaping
const jsonOutput = {
filterRegex: [cleanPattern]
};
// Generate examples
const examples = generateExamples(testRegex);
outputDiv.innerHTML = `
<div class="output-section">
<h3>?? JSON Output:</h3>
<div class="output-box">${JSON.stringify(jsonOutput, null, 2)}</div>
<h3>? Example Matches:</h3>
<ul class="examples-list">
${examples.map(ex => `<li>${escapeHtml(ex)}</li>`).join('')}
</ul>
<div class="success">? Regex successfully converted to JSON format!</div>
</div>
`;
} catch (error) {
outputDiv.innerHTML = `<div class="error">? Invalid regex pattern: ${escapeHtml(error.message)}</div>`;
}
}
function validateRegex() {
const useStandard = document.getElementById('useStandardRegex').checked;
const regexInput = document.getElementById('regexToValidate').value.trim();
const outputDiv = document.getElementById('validateOutput');
if (!regexInput) {
outputDiv.innerHTML = '<div class="error">Please enter a regex pattern to validate</div>';
return;
}
try {
let regex;
let pattern;
if (useStandard) {
// Use standard regex directly
pattern = regexInput;
regex = new RegExp(pattern);
} else {
// JSON mode - handle multiple formats
if (regexInput.startsWith('{')) {
// Full JSON format
const jsonRegex = JSON.parse(regexInput);
if (jsonRegex.filterRegex && Array.isArray(jsonRegex.filterRegex)) {
pattern = jsonRegex.filterRegex[0];
} else if (jsonRegex.pattern) {
pattern = jsonRegex.pattern;
} else {
throw new Error('Invalid JSON format. Expected {"filterRegex": ["pattern"]}');
}
} else if (regexInput.startsWith('"') && regexInput.endsWith('"')) {
// Just a quoted string - parse as JSON string
pattern = JSON.parse(regexInput);
} else {
// Raw pattern without quotes or JSON wrapper
outputDiv.innerHTML = `
<div class="error">
? Invalid format for JSON mode.<br><br>
You can use one of these formats:<br>
<div class="output-box" style="margin-top: 10px; background: #fef3c7;">
1. Full JSON: {"filterRegex": ["${escapeHtml(regexInput)}"]}<br><br>
2. Quoted string: "${escapeHtml(regexInput)}"
</div>
<br>
?? <strong>Tip:</strong> Check the "Use Standard Regex" box above to validate regex patterns directly without quotes.
</div>
`;
return;
}
regex = new RegExp(pattern);
}
// Generate examples
const examples = generateExamples(regex);
outputDiv.innerHTML = `
<div class="output-section">
<h3>?? Validation Result:</h3>
<div class="output-box">
Pattern: ${escapeHtml(pattern)}<br>
Type: ${useStandard ? 'Standard Regex' : 'JSON Regex'}
</div>
<h3>? Example Matches:</h3>
<ul class="examples-list">
${examples.map(ex => `<li>${escapeHtml(ex)}</li>`).join('')}
</ul>
<div class="success">? Regex is valid!</div>
</div>
`;
} catch (error) {
if (error instanceof SyntaxError && !useStandard) {
outputDiv.innerHTML = `<div class="error">? Invalid JSON syntax: ${escapeHtml(error.message)}<br><br>Expected format: {"filterRegex": ["your-regex-pattern"]} or "your-regex-pattern"</div>`;
} else {
outputDiv.innerHTML = `<div class="error">? Invalid regex: ${escapeHtml(error.message)}</div>`;
}
}
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
</script>
</body>
</html>