Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | 6x 2x 2x 6x 17x 6x 6x 6x 6x 4x 4x 4x 12x 8x 4x 4x 6x 29x 2x 27x 27x 6x 18x 3x 15x 15x 2x 2x 2x 15x 8x 8x 3x 5x 5x 7x 6x 6x 4x 4x 4x 4x 4x 4x 2x 6x 6x 1x 5x 20x 5x 1x | // Usage flags
const printHelp = () => {
console.log(`teXt0wnz backend server
Usage: {bun,node} server [port] [options]
Options:
--ssl Enable SSL (requires certificates in ssl-dir)
--ssl-dir <path> SSL certificate directory (default: /etc/ssl/private)
--save-interval <min> Auto-save interval in minutes (default: 30)
--session-name <name> Session file prefix (default: joint)
--debug Enable verbose console messages
--help Show this help message
Examples:
bun server 8080 --ssl --session-name myart --debug
node server --save-interval 60 --session-name collaborative
`);
process.exit(0);
};
const callout = msg => {
console.log(
`╓───── ${sanitize(msg, 100, false)}\n╙───────────────────────────────── ─ ─`,
);
};
const createTimestampedFilename = (sessionName, extension) => {
// Windows safe file names
const timestamp = new Date().toISOString().replace(/[:]/g, '-');
return `${sessionName}-${timestamp}.${extension}`;
};
// Strips possibly sensitive headers
const cleanHeaders = headers => {
const SENSITIVE_HEADERS = [
'authorization',
'cookie',
'set-cookie',
'proxy-authorization',
'x-api-key',
];
const redacted = {};
for (const [key, value] of Object.entries(headers)) {
if (SENSITIVE_HEADERS.includes(key.toLowerCase())) {
redacted[key] = '[REDACTED]';
} else {
redacted[key] = value;
}
}
return redacted;
};
// Strips Unicode control characters and newlines,
// limits length, and optionally adds quotes
const sanitize = (input, limit = 100, quote = true) => {
if (input === null || input === undefined) {
return '';
}
const str = String(input)
.trim()
.replace(/\p{C}/gu, '')
.replace(/[\n\r]/g, '')
.substring(0, limit);
return quote ? `'${str}'` : str;
};
const anonymizeIp = ip => {
if (!ip) {
return 'unknown';
}
let normalizedIp = ip;
if (normalizedIp.includes('::ffff:')) {
const ipv4Mapped = normalizedIp.match(/^::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/);
Eif (ipv4Mapped) {
normalizedIp = ipv4Mapped[1];
}
}
// Mask the final octet for IPv4
if (normalizedIp.includes('.')) {
const parts = normalizedIp.split('.');
if (parts.length !== 4) {
return 'invalid ip';
}
parts[3] = 'X';
return parts.join('.');
}
// Handle IPv6 (including compressed notation)
if (normalizedIp.includes(':')) {
const expandIPv6 = address => {
if (address.includes('::')) {
const [head, tail] = address.split('::', 2);
const headParts = head ? head.split(':') : [];
const tailParts = tail ? tail.split(':') : [];
const missing = 8 - (headParts.length + tailParts.length);
const zeros = Array(missing > 0 ? missing : 0).fill('0');
return [...headParts, ...zeros, ...tailParts];
} else {
return address.split(':');
}
};
const parts = expandIPv6(normalizedIp);
if (parts.length !== 8) {
return 'invalid ip';
}
// Mask the last 4 segments
for (let i = 4; i < 8; i++) {
parts[i] = 'X';
}
return parts.join(':');
}
return 'unknown';
};
export {
printHelp,
callout,
createTimestampedFilename,
cleanHeaders,
sanitize,
anonymizeIp,
};
|