UNPKG

@bitblit/ratchet-common

Version:

Common tools for general use

209 lines 7.16 kB
import { Logger } from '../logger/logger.js'; import { StringRatchet } from './string-ratchet.js'; import { ErrorRatchet } from './error-ratchet.js'; export class Base64Ratchet { static safeObjectToBase64JSON(input) { return input ? Base64Ratchet.generateBase64VersionOfString(JSON.stringify(input)) : null; } static safeBase64JSONParse(input) { let rval = {}; try { if (input) { rval = JSON.parse(Base64Ratchet.base64StringToString(input, 'utf-8')); } } catch (err) { Logger.warn('Error parsing b64/json : %s as json, got %s', input, err, err); rval = {}; } return rval; } static generateBase64VersionOfBlob(blob) { return new Promise(function (resolve, reject) { if (!blob || blob.size == 0) { reject('Wont convert null or non-blob or empty blob'); } else { const reader = new FileReader(); reader.onloadend = function () { resolve(reader.result.toString()); }; reader.readAsDataURL(blob); } }); } static generateBase64VersionOfString(input) { return Base64Ratchet.generateBase64VersionOfUint8Array(StringRatchet.stringToUint8Array(input)); } static generateBase64VersionOfUint8Array(input) { return Base64Ratchet.uint8ArrayToBase64String(input); } static base64StringToUint8Array(b64encoded) { try { const uint8 = Base64Ratchet.base64StringToBytes(b64encoded); return uint8; } catch (err) { Logger.error('Failed to decode base64: %s', b64encoded); throw err; } } static base64StringToString(input, encoding = 'utf8') { return new TextDecoder(encoding).decode(Base64Ratchet.base64StringToUint8Array(input)); } static BASE64_ABC = [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', ]; static BASE64_CODES = [ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0, 255, 255, 255, 0, 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, 255, 255, 255, 255, 255, 255, 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, ]; static getBase64Code(charCode) { if (charCode >= Base64Ratchet.BASE64_CODES.length) { throw new Error('Unable to parse base64 string.'); } const code = Base64Ratchet.BASE64_CODES[charCode]; if (code === 255) { throw new Error('Unable to parse base64 string.'); } return code; } static uint8ArrayToBase64UrlString(bytes) { let tmp = Base64Ratchet.uint8ArrayToBase64String(bytes); tmp = tmp.split('+').join('-').split('/').join('_').split('=').join(''); return tmp; } static uint8ArrayToBase64String(bytes) { let result = ''; let i; const l = bytes.length; for (i = 2; i < l; i += 3) { result += Base64Ratchet.BASE64_ABC[bytes[i - 2] >> 2]; result += Base64Ratchet.BASE64_ABC[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)]; result += Base64Ratchet.BASE64_ABC[((bytes[i - 1] & 0x0f) << 2) | (bytes[i] >> 6)]; result += Base64Ratchet.BASE64_ABC[bytes[i] & 0x3f]; } if (i === l + 1) { result += Base64Ratchet.BASE64_ABC[bytes[i - 2] >> 2]; result += Base64Ratchet.BASE64_ABC[(bytes[i - 2] & 0x03) << 4]; result += '=='; } if (i === l) { result += Base64Ratchet.BASE64_ABC[bytes[i - 2] >> 2]; result += Base64Ratchet.BASE64_ABC[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)]; result += Base64Ratchet.BASE64_ABC[(bytes[i - 1] & 0x0f) << 2]; result += '='; } return result; } static base64StringToBytes(str) { if (str.length % 4 !== 0) { throw ErrorRatchet.fErr('Unable to parse base64 string, length: %s', str.length); } const index = str.indexOf('='); if (index !== -1 && index < str.length - 2) { throw ErrorRatchet.fErr('Unable to parse base64 string, index %s', index); } const missingOctets = str.endsWith('==') ? 2 : str.endsWith('=') ? 1 : 0; const n = str.length; const result = new Uint8Array(new ArrayBuffer(3 * (n / 4))); let buffer; for (let i = 0, j = 0; i < n; i += 4, j += 3) { buffer = (Base64Ratchet.getBase64Code(str.charCodeAt(i)) << 18) | (Base64Ratchet.getBase64Code(str.charCodeAt(i + 1)) << 12) | (Base64Ratchet.getBase64Code(str.charCodeAt(i + 2)) << 6) | Base64Ratchet.getBase64Code(str.charCodeAt(i + 3)); result[j] = buffer >> 16; result[j + 1] = (buffer >> 8) & 0xff; result[j + 2] = buffer & 0xff; } return result.subarray(0, result.length - missingOctets); } static base64UrlStringToBytes(str) { let dec = str.split('-').join('+').split('_').join('/'); while (dec.length % 4 !== 0) { dec += '='; } Logger.info('pre: %s post %s', str, dec); return Base64Ratchet.base64StringToBytes(dec); } static encodeStringToBase64String(str, encoder = new TextEncoder()) { return Base64Ratchet.uint8ArrayToBase64String(encoder.encode(str)); } static encodeStringToBase64UrlString(str, encoder = new TextEncoder()) { return Base64Ratchet.uint8ArrayToBase64UrlString(encoder.encode(str)); } static decodeBase64StringToString(str, decoder = new TextDecoder()) { return decoder.decode(Base64Ratchet.base64StringToBytes(str)); } static decodeBase64UrlStringToString(str, decoder = new TextDecoder()) { return decoder.decode(Base64Ratchet.base64UrlStringToBytes(str)); } } //# sourceMappingURL=base64-ratchet.js.map