nehonix-uri-processor
Version:
A powerful URI processor for encoding, decoding, and analyzing URI data securely.
611 lines • 21.3 kB
JavaScript
import punycode from "punycode";
import { NehonixCoreUtils as NCU } from "../utils/NehonixCoreUtils";
import { htmlEntities } from "../utils/html.enties";
import { AppLogger } from "../common/AppLogger";
class NES {
/**
* Encodes a string according to a specific encoding type
* @param input The string to encode
* @param encodingType The encoding type to use
* @returns The encoded string
*/
static encode(input, encodingType) {
try {
switch (encodingType) {
case "percentEncoding":
return NES.encodePercentEncoding(input);
case "doublepercent":
return NES.encodeDoublePercentEncoding(input);
case "base64":
return NES.encodeBase64(input);
case "hex":
return NES.encodeHex(input);
case "unicode":
return NES.encodeUnicode(input);
case "htmlEntity":
return NES.encodeHTMLEntities(input);
case "punycode":
return NES.encodePunycode(input);
case "asciihex":
return NES.encodeASCIIWithHex(input);
case "asciioct":
return NES.encodeASCIIWithOct(input);
case "rot13":
return NES.encodeROT13(input);
case "base32":
return NES.encodeBase32(input);
case "urlSafeBase64":
return NES.encodeURLSafeBase64(input);
case "jsEscape":
return NES.encodeJavaScriptEscape(input);
case "cssEscape":
return NES.encodeCSSEscape(input);
case "utf7":
return NES.encodeUTF7(input);
case "quotedPrintable":
return NES.encodeQuotedPrintable(input);
case "decimalHtmlEntity":
return NES.encodeDecimalHTMLEntities(input);
case "jwt":
return NES.encodeJWT(input);
case "rawHex":
return NES.encodeRawHex(input);
case "url":
return NES.encodeUrl(input);
default:
throw new Error(`Unsupported encoding type: ${encodingType}`);
}
}
catch (e) {
throw e;
}
}
// =============== ENCODING METHODS ===============
/**
* Encodes with percent encoding (URL)
*/
static encodePercentEncoding(input, encodeSpaces = false) {
let encoded = encodeURIComponent(input);
if (encodeSpaces) {
encoded = encoded.replace(/\+/g, "%20");
}
return encoded;
}
/**
* Encodes with double percent encoding
*/
static encodeDoublePercentEncoding(input) {
const firstPass = NES.encodePercentEncoding(input, true);
return firstPass.replace(/%/g, "%25");
}
/**
* Encodes in base64
*/
static encodeBase64(input) {
try {
if (typeof Buffer !== "undefined") {
return Buffer.from(input).toString("base64");
}
else {
return btoa(input);
}
}
catch (e) {
if (e.name === "InvalidCharacterError") {
const bytes = new TextEncoder().encode(input);
let binary = "";
for (let i = 0; i < bytes.length; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
throw new Error(`Base64 encoding failed: ${e.message}`);
}
}
/**
* Encodes in hexadecimal (format \xXX)
*/
static encodeHex(input) {
let result = "";
for (let i = 0; i < input.length; i++) {
const hex = input.charCodeAt(i).toString(16).padStart(2, "0");
result += `\\x${hex}`;
}
return result;
}
/**
* Encodes in Unicode (format \uXXXX)
*/
static encodeUnicode(input) {
let result = "";
for (let i = 0; i < input.length; i++) {
const cp = input.codePointAt(i);
if (cp > 0xffff) {
result += `\\u{${cp.toString(16)}}`;
if (cp > 0xffff)
i++;
}
else {
result += `\\u${cp.toString(16).padStart(4, "0")}`;
}
}
return result;
}
/**
* Encodes HTML entities in a string
*/
static encodeHTMLEntities(input) {
let result = "";
for (let i = 0; i < input.length; i++) {
const char = input[i];
result += htmlEntities[char] || char;
}
return result;
}
/**
* Encodes in punycode
*/
static encodePunycode(input) {
try {
if (typeof require !== "undefined") {
return `xn--${punycode.encode(input)}`;
}
else {
AppLogger.warn("Punycode module not available, punycode encoding not performed");
return input;
}
}
catch (e) {
throw new Error(`Punycode encoding failed: ${e.message}`);
}
}
/**
* Encodes in ASCII with hexadecimal representation
*/
static encodeASCIIWithHex(input) {
let result = "";
for (let i = 0; i < input.length; i++) {
const code = input.charCodeAt(i);
result += `\\x${code.toString(16).padStart(2, "0")}`;
}
return result;
}
/**
* Encodes in ASCII with octal representation
*/
static encodeASCIIWithOct(input) {
let result = "";
for (let i = 0; i < input.length; i++) {
const code = input.charCodeAt(i);
result += `\\${code.toString(8).padStart(3, "0")}`;
}
return result;
}
/**
* Encodes all characters in percent encoding
*/
static encodeAllChars(input) {
let result = "";
for (let i = 0; i < input.length; i++) {
const hex = input.charCodeAt(i).toString(16).padStart(2, "0");
result += `%${hex}`;
}
return result;
}
/**
* Calculates confidence level for base64 encoding
*/
static calculateBase64Confidence(input) {
if (!NCU.hasBase64Pattern(input))
return 0;
let testString = input;
if (input.includes("=")) {
const parts = input.split("=");
testString = parts[parts.length - 1];
}
const base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=_-";
let validCharsCount = 0;
for (let i = 0; i < testString.length; i++) {
if (base64Chars.includes(testString[i])) {
validCharsCount++;
}
}
const ratio = validCharsCount / testString.length;
const lengthMod4 = testString.length % 4;
const lengthFactor = lengthMod4 === 0 ? 0.1 : 0;
try {
let decodableString = testString;
decodableString = decodableString.replace(/-/g, "+").replace(/_/g, "/");
while (decodableString.length % 4 !== 0) {
decodableString += "=";
}
const decoded = NCU.decodeB64(decodableString);
const readableChars = decoded.replace(/[^\x20-\x7E]/g, "").length;
const readableRatio = readableChars / decoded.length;
if (readableRatio > 0.7) {
return Math.min(0.95, ratio + 0.2 + lengthFactor);
}
}
catch (e) {
return Math.max(0.1, ratio - 0.3);
}
return Math.min(0.8, ratio + lengthFactor);
}
/**
* Encodes using ROT13 cipher
*/
static encodeROT13(input) {
return input.replace(/[a-zA-Z]/g, (char) => {
const code = char.charCodeAt(0);
const base = code < 91 ? 65 : 97;
return String.fromCharCode(((code - base + 13) % 26) + base);
});
}
/**
* Encodes in Base32
*/
static encodeBase32(input) {
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
let result = "";
let bits = 0;
let value = 0;
for (let i = 0; i < input.length; i++) {
value = (value << 8) | input.charCodeAt(i);
bits += 8;
while (bits >= 5) {
result += alphabet[(value >> (bits - 5)) & 31];
bits -= 5;
}
}
if (bits > 0) {
result += alphabet[(value << (5 - bits)) & 31];
}
while (result.length % 8 !== 0) {
result += "=";
}
return result;
}
/**
* Encodes in URL-safe Base64
*/
static encodeURLSafeBase64(input) {
const base64 = NES.encodeBase64(input);
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
/**
* Encodes string with JavaScript escape sequences
*/
static encodeJavaScriptEscape(input) {
let result = "";
for (let i = 0; i < input.length; i++) {
const cp = input.codePointAt(i);
if (cp < 128) {
switch (input[i]) {
case "\\":
result += "\\\\";
break;
case '"':
result += '\\"';
break;
case "'":
result += "\\'";
break;
case "\n":
result += "\\n";
break;
case "\r":
result += "\\r";
break;
case "\t":
result += "\\t";
break;
case "\b":
result += "\\b";
break;
case "\f":
result += "\\f";
break;
default:
if (cp < 32 || cp === 127) {
result += `\\x${cp.toString(16).padStart(2, "0")}`;
}
else {
result += input[i];
}
}
}
else if (cp <= 0xffff) {
result += `\\u${cp.toString(16).padStart(4, "0")}`;
}
else {
result += `\\u${input
.charCodeAt(i)
.toString(16)
.padStart(4, "0")}\\u${input
.charCodeAt(i + 1)
.toString(16)
.padStart(4, "0")}`;
i++;
}
}
return result;
}
/**
* Encodes string with CSS escape sequences
*/
static encodeCSSEscape(input) {
let result = "";
for (let i = 0; i < input.length; i++) {
const cp = input.codePointAt(i);
if (cp === 0) {
result += "\\FFFD ";
}
else if (cp < 33 ||
cp === 127 ||
/[\\!"#$%&'()*+,./:;<=>?@[\]^`{|}~]/.test(input[i])) {
result += `\\${cp.toString(16).toUpperCase()} `;
}
else if (cp > 0xffff) {
result += `\\${cp.toString(16).toUpperCase()} `;
if (cp > 0xffff)
i++;
}
else {
result += input[i];
}
}
return result;
}
/**
* Encodes in UTF-7
*/
static encodeUTF7(input) {
let result = "";
let inBase64 = false;
let base64Buffer = "";
for (let i = 0; i < input.length; i++) {
const cp = input.charCodeAt(i);
if (cp >= 33 && cp <= 126 && cp !== 43) {
if (inBase64) {
result += base64Buffer.replace(/=+$/, "") + "-";
base64Buffer = "";
inBase64 = false;
}
result += input[i];
}
else {
if (!inBase64) {
result += "+";
inBase64 = true;
}
let unicodeChar = String.fromCharCode(cp);
base64Buffer += NES.encodeBase64(unicodeChar).replace(/=+$/, "");
}
}
if (inBase64) {
result += base64Buffer + "-";
}
return result;
}
/**
* Encodes in Quoted-Printable
*/
static encodeQuotedPrintable(input) {
let result = "";
const unsafe = /[^\x20-\x7E]|[=]/g;
for (let i = 0; i < input.length; i++) {
const char = input[i];
const code = input.charCodeAt(i);
if (char === "\r" || char === "\n") {
result += char;
}
else if (char === " " || char === "\t") {
if (i === input.length - 1 ||
input[i + 1] === "\r" ||
input[i + 1] === "\n") {
result += `=${code.toString(16).toUpperCase().padStart(2, "0")}`;
}
else {
result += char;
}
}
else if (unsafe.test(char)) {
result += `=${code.toString(16).toUpperCase().padStart(2, "0")}`;
}
else {
result += char;
}
if (result.length >= 75 && i < input.length - 1) {
result += "=\r\n";
}
}
return result;
}
/**
* Encodes in decimal HTML entity format
*/
static encodeDecimalHTMLEntities(input) {
let result = "";
for (let i = 0; i < input.length; i++) {
const cp = input.codePointAt(i);
result += `&#${cp};`;
if (cp > 0xffff)
i++;
}
return result;
}
/**
* Encodes in raw hexadecimal (no prefixes)
*/
static encodeRawHex(input) {
let result = "";
for (let i = 0; i < input.length; i++) {
const hex = input.charCodeAt(i).toString(16).padStart(2, "0");
result += hex;
}
return result;
}
/**
* Encodes as a JWT with the input as the payload
*/
static encodeJWT(input) {
try {
const header = { alg: "none" };
const headerEncoded = NES.encodeURLSafeBase64(JSON.stringify(header));
const payloadEncoded = NES.encodeURLSafeBase64(input);
return `${headerEncoded}.${payloadEncoded}.`;
}
catch (e) {
throw new Error(`JWT encoding failed: ${e.message}`);
}
}
/**
* Encodes as a URL (percent-encoding with spaces as %20)
*/
static encodeUrl(input) {
return NES.encodePercentEncoding(input, true);
}
/**
* Performs multiple encodings on an input string synchronously
* @param input The string to encode
* @param types Array of encoding types to apply
* @param options Configuration options for nested encoding
* @returns Object containing encoding results
*/
static encodeMultiple(input, types, options = {}) {
// Default options
const { sequential = false, includeIntermediate = true } = options;
const results = [];
let currentInput = input;
// Process each encoding type
for (let i = 0; i < types.length; i++) {
const encodingType = types[i];
try {
// Encode the current input using the specified encoding type
const encodedResult = NES.encode(currentInput, encodingType);
// Store the result
results.push({
original: currentInput,
encoded: encodedResult,
type: encodingType,
});
// If sequential, use this result as input for the next encoding
if (sequential && i < types.length - 1) {
currentInput = encodedResult;
}
}
catch (e) {
// Log the error but continue with other encodings
AppLogger.error(`Error encoding with ${encodingType}: ${e.message}`);
results.push({
original: currentInput,
encoded: `ERROR: ${e.message}`,
type: encodingType,
});
}
}
// Prepare response object
const response = {
input: input,
results: includeIntermediate ? results : [],
};
// For sequential encoding, add the final result
if (sequential) {
response.finalResult =
results.length > 0 ? results[results.length - 1].encoded : input;
}
// If not including intermediate results but not sequential,
// we still want to include all direct encoding results
if (!includeIntermediate && !sequential) {
response.results = results;
}
return response;
}
/**
* Performs multiple encodings on an input string asynchronously
* @param input The string to encode
* @param types Array of encoding types to apply
* @param options Configuration options for nested encoding
* @returns Promise resolving to object containing encoding results
*/
static async encodeMultipleAsync(input, types, options = {}) {
// Default options
const { sequential = false, includeIntermediate = true } = options;
const results = [];
let currentInput = input;
if (sequential) {
// For sequential processing, we need to process in order
for (let i = 0; i < types.length; i++) {
const encodingType = types[i];
try {
// Encode the current input using the specified encoding type
// Wrap in Promise.resolve to handle potential async operations
const encodedResult = await Promise.resolve(NES.encode(currentInput, encodingType));
// Store the result
results.push({
original: currentInput,
encoded: encodedResult,
type: encodingType,
});
// Use this result as input for the next encoding
if (i < types.length - 1) {
currentInput = encodedResult;
}
}
catch (e) {
// Log the error but continue with other encodings
AppLogger.error(`Error encoding with ${encodingType}: ${e.message}`);
results.push({
original: currentInput,
encoded: `ERROR: ${e.message}`,
type: encodingType,
});
}
}
}
else {
// For parallel processing, we can process all encodings concurrently
const encodingPromises = types.map(async (encodingType) => {
try {
// Encode the input using the specified encoding type
const encodedResult = await Promise.resolve(NES.encode(input, encodingType));
return {
original: input,
encoded: encodedResult,
type: encodingType,
};
}
catch (e) {
// Log the error but continue with other encodings
AppLogger.error(`Error encoding with ${encodingType}: ${e.message}`);
return {
original: input,
encoded: `ERROR: ${e.message}`,
type: encodingType,
};
}
});
// Wait for all encodings to complete
results.push(...(await Promise.all(encodingPromises)));
}
// Prepare response object
const response = {
input: input,
results: includeIntermediate ? results : [],
};
// For sequential encoding, add the final result
if (sequential) {
response.finalResult =
results.length > 0 ? results[results.length - 1].encoded : input;
}
// If not including intermediate results but not sequential,
// we still want to include all direct encoding results
if (!includeIntermediate && !sequential) {
response.results = results;
}
return response;
}
}
export { NES as NehonixEncService };
export default NES;
//# sourceMappingURL=NehonixEnc.service.js.map