UNPKG

password-obscura

Version:

A lightweight NPM package to visually obscure passwords or strings using customizable shift-based and symbol-mapping logic. Inspired by Caesar Cipher — reimagined for modern devs.

383 lines (377 loc) 11.9 kB
// src/lib/caesar.ts function caesarCipher(text, shift) { return text.replace(/[a-z]/gi, (char) => { const base = char >= "a" && char <= "z" ? 97 : 65; return String.fromCharCode((char.charCodeAt(0) - base + shift) % 26 + base); }); } function caesarDecipher(text, shift) { return caesarCipher(text, 26 - shift % 26); } // src/lib/rot13.ts function rot13(str) { return str.replace(/[a-z]/gi, (char) => { const base = char <= "Z" ? 65 : 97; return String.fromCharCode((char.charCodeAt(0) - base + 13) % 26 + base); }); } // src/lib/symbolMap.ts var DEFAULT_SYMBOL_MAP = { // Lowercase letters a: "\u{1F525}", b: "\u2B50", c: "\u{1F31F}", d: "\u{1F4AB}", e: "\u2728", f: "\u{1F308}", g: "\u{1F30A}", h: "\u{1F32A}\uFE0F", i: "\u2744\uFE0F", j: "\u{1F319}", k: "\u2600\uFE0F", l: "\u{1F338}", m: "\u{1F33A}", n: "\u{1F33B}", o: "\u{1F337}", p: "\u{1F339}", q: "\u{1F331}", r: "\u{1F340}", s: "\u{1F33F}", t: "\u{1F33E}", u: "\u{1F344}", v: "\u{1F335}", w: "\u{1F334}", x: "\u{1F38B}", y: "\u{1F332}", z: "\u{1F333}", // Uppercase letters A: "\u{1F680}", B: "\u26A1", C: "\u{1F48E}", D: "\u{1F3AF}", E: "\u{1F3AA}", F: "\u{1F3AD}", G: "\u{1F3A8}", H: "\u{1F3B5}", I: "\u{1F3B8}", J: "\u{1F3BA}", K: "\u{1F3BB}", L: "\u{1F941}", M: "\u{1F3A4}", N: "\u{1F3A7}", O: "\u{1F3AE}", P: "\u{1F579}\uFE0F", Q: "\u{1F3B2}", R: "\u{1F0CF}", S: "\u{1F38A}", T: "\u{1F381}", U: "\u{1F388}", V: "\u{1F380}", W: "\u{1F48D}", X: "\u{1F451}", Y: "\u{1F531}", Z: "\u2694\uFE0F", // Numbers "0": "\u{1F534}", "1": "\u{1F7E0}", "2": "\u{1F7E1}", "3": "\u{1F7E2}", "4": "\u{1F535}", "5": "\u{1F7E3}", "6": "\u{1F7E4}", "7": "\u26AB", "8": "\u26AA", "9": "\u{1F536}" }; function symbolMapEncode(text, symbolMap = DEFAULT_SYMBOL_MAP) { return text.split("").map((char) => symbolMap[char] || char).join(""); } function symbolMapDecode(text, symbolMap = DEFAULT_SYMBOL_MAP) { const reverseMap = {}; Object.entries(symbolMap).forEach(([char, symbol]) => { reverseMap[symbol] = char; }); const chars = Array.from(text); return chars.map((char) => reverseMap[char] || char).join(""); } // src/lib/atbash.ts function atbashCipher(text) { return text.replace(/[a-zA-Z]/g, (char) => { if (char >= "a" && char <= "z") { return String.fromCharCode(25 - (char.charCodeAt(0) - 97) + 97); } else { return String.fromCharCode(25 - (char.charCodeAt(0) - 65) + 65); } }); } var atbashDecipher = atbashCipher; // src/lib/dynamicCipher.ts var DEFAULT_TABLES = [ "abcdefghijklmnopqrstuvwxyz", "zyxwvutsrqponmlkjihgfedcba", "aeiouybcdfghjklmnpqrstvwxz", "bcdefghijklmnopqrstuvwxyza" ]; var FIBONACCI_SEQUENCE = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]; var PRIME_NUMBERS = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]; function generateShift(position, pattern, baseShift = 3, customShifts) { let shift; switch (pattern) { case "even-odd": shift = position % 2 === 0 ? baseShift : baseShift + 1; break; case "fibonacci": shift = FIBONACCI_SEQUENCE[position % FIBONACCI_SEQUENCE.length]; break; case "prime": shift = PRIME_NUMBERS[position % PRIME_NUMBERS.length]; break; case "progressive": shift = baseShift + position % 10; break; case "custom": if (!customShifts || customShifts.length === 0) { shift = baseShift; } else { shift = customShifts[position % customShifts.length]; } break; default: shift = baseShift; break; } return shift % 26; } function multiTableCaesar(text, config) { const { tables, shiftPattern, customShifts, baseShift = 3 } = config; const standardAlphabet = "abcdefghijklmnopqrstuvwxyz"; return text.split("").map((char, index) => { if (!/[a-zA-Z]/.test(char)) return char; const tableIndex = index % tables.length; const table = tables[tableIndex]; const shift = generateShift(index, shiftPattern, baseShift, customShifts); const standardIndex = standardAlphabet.indexOf(char.toLowerCase()); if (standardIndex === -1) return char; const shiftedIndex = (standardIndex + shift) % standardAlphabet.length; const newChar = table[shiftedIndex]; if (!newChar) return char; return char === char.toUpperCase() ? newChar.toUpperCase() : newChar; }).join(""); } function multiTableCaesarDecrypt(text, config) { const { tables, shiftPattern, customShifts, baseShift = 3 } = config; const standardAlphabet = "abcdefghijklmnopqrstuvwxyz"; return text.split("").map((char, index) => { if (!/[a-zA-Z]/.test(char)) return char; const tableIndex = index % tables.length; const table = tables[tableIndex]; const shift = generateShift(index, shiftPattern, baseShift, customShifts); const tableIndex_char = table.indexOf(char.toLowerCase()); if (tableIndex_char === -1) return char; const originalIndex = (tableIndex_char - shift + standardAlphabet.length) % standardAlphabet.length; const originalChar = standardAlphabet[originalIndex]; if (!originalChar) return char; return char === char.toUpperCase() ? originalChar.toUpperCase() : originalChar; }).join(""); } function polyalphabeticCipher(text, config) { const { keyword, tables = DEFAULT_TABLES } = config; const keywordRepeated = keyword.repeat( Math.ceil(text.length / keyword.length) ); return text.split("").map((char, index) => { if (!/[a-zA-Z]/.test(char)) return char; const keyChar = keywordRepeated[index]; const keyShift = keyChar.toLowerCase().charCodeAt(0) - 97; const tableIndex = keyShift % tables.length; const table = tables[tableIndex]; const charIndex = table.indexOf(char.toLowerCase()); if (charIndex === -1) return char; const newIndex = (charIndex + keyShift) % table.length; const newChar = table[newIndex]; return char === char.toUpperCase() ? newChar.toUpperCase() : newChar; }).join(""); } function polyalphabeticDecipher(text, config) { const { keyword, tables = DEFAULT_TABLES } = config; const keywordRepeated = keyword.repeat( Math.ceil(text.length / keyword.length) ); return text.split("").map((char, index) => { if (!/[a-zA-Z]/.test(char)) return char; const keyChar = keywordRepeated[index]; const keyShift = keyChar.toLowerCase().charCodeAt(0) - 97; const tableIndex = keyShift % tables.length; const table = tables[tableIndex]; const charIndex = table.indexOf(char.toLowerCase()); if (charIndex === -1) return char; const newIndex = (charIndex - keyShift + table.length) % table.length; const newChar = table[newIndex]; return char === char.toUpperCase() ? newChar.toUpperCase() : newChar; }).join(""); } function advancedSubstitution(text, layers) { let result = text; layers.forEach((layer) => { var _a, _b; switch (layer.type) { case "table": if (layer.config && layer.config.tables) { result = multiTableCaesar(result, layer.config); } break; case "shift": const shift = ((_a = layer.config) == null ? void 0 : _a.shift) || 3; result = result.replace(/[a-zA-Z]/g, (char) => { const base = char >= "a" ? 97 : 65; return String.fromCharCode( (char.charCodeAt(0) - base + shift) % 26 + base ); }); break; case "reverse": result = result.split("").reverse().join(""); break; case "transpose": const blockSize = ((_b = layer.config) == null ? void 0 : _b.blockSize) || 3; const blocks = []; for (let i = 0; i < result.length; i += blockSize) { blocks.push(result.slice(i, i + blockSize)); } result = blocks.map((block) => block.split("").reverse().join("")).join(""); break; } }); return result; } function advancedSubstitutionDecrypt(text, layers) { let result = text; [...layers].reverse().forEach((layer) => { var _a, _b; switch (layer.type) { case "table": if (layer.config && layer.config.tables) { result = multiTableCaesarDecrypt(result, layer.config); } break; case "shift": const shift = ((_a = layer.config) == null ? void 0 : _a.shift) || 3; result = result.replace(/[a-zA-Z]/g, (char) => { const base = char >= "a" ? 97 : 65; return String.fromCharCode( (char.charCodeAt(0) - base - shift + 26) % 26 + base ); }); break; case "reverse": result = result.split("").reverse().join(""); break; case "transpose": const blockSize = ((_b = layer.config) == null ? void 0 : _b.blockSize) || 3; const blocks = []; for (let i = 0; i < result.length; i += blockSize) { blocks.push(result.slice(i, i + blockSize)); } result = blocks.map((block) => block.split("").reverse().join("")).join(""); break; } }); return result; } // src/index.ts function obscure(input, options) { switch (options.method) { case "caesar": return caesarCipher(input, options.shift ?? 3); case "rot13": return rot13(input); case "symbolMap": return symbolMapEncode(input, options.symbolMap ?? DEFAULT_SYMBOL_MAP); case "mirror": return atbashCipher(input); case "multiTable": if (!options.tableConfig) { options.tableConfig = { tables: DEFAULT_TABLES, shiftPattern: "even-odd", baseShift: 3 }; } return multiTableCaesar(input, options.tableConfig); case "polyalphabetic": if (!options.polyConfig) { throw new Error("polyConfig is required for polyalphabetic method"); } return polyalphabeticCipher(input, options.polyConfig); case "advanced": if (!options.layers || options.layers.length === 0) { options.layers = [ { type: "shift", config: { shift: 3 } }, { type: "table", config: { tables: DEFAULT_TABLES, shiftPattern: "fibonacci", baseShift: 2 } }, { type: "reverse" } ]; } return advancedSubstitution(input, options.layers); default: throw new Error(`Unsupported method: ${options.method}`); } } function reveal(input, options) { switch (options.method) { case "caesar": return caesarDecipher(input, options.shift ?? 3); case "rot13": return rot13(input); // rot13 is symmetric case "symbolMap": return symbolMapDecode(input, options.symbolMap ?? DEFAULT_SYMBOL_MAP); case "mirror": return atbashDecipher(input); // atbash is symmetric case "multiTable": if (!options.tableConfig) { options.tableConfig = { tables: DEFAULT_TABLES, shiftPattern: "even-odd", baseShift: 3 }; } return multiTableCaesarDecrypt(input, options.tableConfig); case "polyalphabetic": if (!options.polyConfig) { throw new Error("polyConfig is required for polyalphabetic method"); } return polyalphabeticDecipher(input, options.polyConfig); case "advanced": if (!options.layers || options.layers.length === 0) { options.layers = [ { type: "shift", config: { shift: 3 } }, { type: "table", config: { tables: DEFAULT_TABLES, shiftPattern: "fibonacci", baseShift: 2 } }, { type: "reverse" } ]; } return advancedSubstitutionDecrypt(input, options.layers); default: throw new Error(`Unsupported method: ${options.method}`); } } export { DEFAULT_SYMBOL_MAP, DEFAULT_TABLES, obscure, reveal };