209 lines
6.7 KiB
JavaScript
209 lines
6.7 KiB
JavaScript
"use strict";
|
|
/**
|
|
* Avoid modifying this file. It's part of
|
|
* https://github.com/supabase-community/base64url-js. Submit all fixes on
|
|
* that repo!
|
|
*/
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.stringToBase64URL = stringToBase64URL;
|
|
exports.stringFromBase64URL = stringFromBase64URL;
|
|
exports.codepointToUTF8 = codepointToUTF8;
|
|
exports.stringToUTF8 = stringToUTF8;
|
|
exports.stringFromUTF8 = stringFromUTF8;
|
|
/**
|
|
* An array of characters that encode 6 bits into a Base64-URL alphabet
|
|
* character.
|
|
*/
|
|
const TO_BASE64URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".split("");
|
|
/**
|
|
* An array of characters that can appear in a Base64-URL encoded string but
|
|
* should be ignored.
|
|
*/
|
|
const IGNORE_BASE64URL = " \t\n\r=".split("");
|
|
/**
|
|
* An array of 128 numbers that map a Base64-URL character to 6 bits, or if -2
|
|
* used to skip the character, or if -1 used to error out.
|
|
*/
|
|
const FROM_BASE64URL = (() => {
|
|
const charMap = new Array(128);
|
|
for (let i = 0; i < charMap.length; i += 1) {
|
|
charMap[i] = -1;
|
|
}
|
|
for (let i = 0; i < IGNORE_BASE64URL.length; i += 1) {
|
|
charMap[IGNORE_BASE64URL[i].charCodeAt(0)] = -2;
|
|
}
|
|
for (let i = 0; i < TO_BASE64URL.length; i += 1) {
|
|
charMap[TO_BASE64URL[i].charCodeAt(0)] = i;
|
|
}
|
|
return charMap;
|
|
})();
|
|
/**
|
|
* Converts a JavaScript string (which may include any valid character) into a
|
|
* Base64-URL encoded string. The string is first encoded in UTF-8 which is
|
|
* then encoded as Base64-URL.
|
|
*
|
|
* @param str The string to convert.
|
|
*/
|
|
function stringToBase64URL(str) {
|
|
const base64 = [];
|
|
let queue = 0;
|
|
let queuedBits = 0;
|
|
const emitter = (byte) => {
|
|
queue = (queue << 8) | byte;
|
|
queuedBits += 8;
|
|
while (queuedBits >= 6) {
|
|
const pos = (queue >> (queuedBits - 6)) & 63;
|
|
base64.push(TO_BASE64URL[pos]);
|
|
queuedBits -= 6;
|
|
}
|
|
};
|
|
stringToUTF8(str, emitter);
|
|
if (queuedBits > 0) {
|
|
queue = queue << (6 - queuedBits);
|
|
queuedBits = 6;
|
|
while (queuedBits >= 6) {
|
|
const pos = (queue >> (queuedBits - 6)) & 63;
|
|
base64.push(TO_BASE64URL[pos]);
|
|
queuedBits -= 6;
|
|
}
|
|
}
|
|
return base64.join("");
|
|
}
|
|
/**
|
|
* Converts a Base64-URL encoded string into a JavaScript string. It is assumed
|
|
* that the underlying string has been encoded as UTF-8.
|
|
*
|
|
* @param str The Base64-URL encoded string.
|
|
*/
|
|
function stringFromBase64URL(str) {
|
|
const conv = [];
|
|
const emit = (codepoint) => {
|
|
conv.push(String.fromCodePoint(codepoint));
|
|
};
|
|
const state = {
|
|
utf8seq: 0,
|
|
codepoint: 0,
|
|
};
|
|
let queue = 0;
|
|
let queuedBits = 0;
|
|
for (let i = 0; i < str.length; i += 1) {
|
|
const codepoint = str.charCodeAt(i);
|
|
const bits = FROM_BASE64URL[codepoint];
|
|
if (bits > -1) {
|
|
// valid Base64-URL character
|
|
queue = (queue << 6) | bits;
|
|
queuedBits += 6;
|
|
while (queuedBits >= 8) {
|
|
stringFromUTF8((queue >> (queuedBits - 8)) & 0xff, state, emit);
|
|
queuedBits -= 8;
|
|
}
|
|
}
|
|
else if (bits === -2) {
|
|
// ignore spaces, tabs, newlines, =
|
|
continue;
|
|
}
|
|
else {
|
|
throw new Error(`Invalid Base64-URL character "${str.at(i)}" at position ${i}`);
|
|
}
|
|
}
|
|
return conv.join("");
|
|
}
|
|
/**
|
|
* Converts a Unicode codepoint to a multi-byte UTF-8 sequence.
|
|
*
|
|
* @param codepoint The Unicode codepoint.
|
|
* @param emit Function which will be called for each UTF-8 byte that represents the codepoint.
|
|
*/
|
|
function codepointToUTF8(codepoint, emit) {
|
|
if (codepoint <= 0x7f) {
|
|
emit(codepoint);
|
|
return;
|
|
}
|
|
else if (codepoint <= 0x7ff) {
|
|
emit(0xc0 | (codepoint >> 6));
|
|
emit(0x80 | (codepoint & 0x3f));
|
|
return;
|
|
}
|
|
else if (codepoint <= 0xffff) {
|
|
emit(0xe0 | (codepoint >> 12));
|
|
emit(0x80 | ((codepoint >> 6) & 0x3f));
|
|
emit(0x80 | (codepoint & 0x3f));
|
|
return;
|
|
}
|
|
else if (codepoint <= 0x10ffff) {
|
|
emit(0xf0 | (codepoint >> 18));
|
|
emit(0x80 | ((codepoint >> 12) & 0x3f));
|
|
emit(0x80 | ((codepoint >> 6) & 0x3f));
|
|
emit(0x80 | (codepoint & 0x3f));
|
|
return;
|
|
}
|
|
throw new Error(`Unrecognized Unicode codepoint: ${codepoint.toString(16)}`);
|
|
}
|
|
/**
|
|
* Converts a JavaScript string to a sequence of UTF-8 bytes.
|
|
*
|
|
* @param str The string to convert to UTF-8.
|
|
* @param emit Function which will be called for each UTF-8 byte of the string.
|
|
*/
|
|
function stringToUTF8(str, emit) {
|
|
for (let i = 0; i < str.length; i += 1) {
|
|
let codepoint = str.charCodeAt(i);
|
|
if (codepoint > 0xd7ff && codepoint <= 0xdbff) {
|
|
// most UTF-16 codepoints are Unicode codepoints, except values in this
|
|
// range where the next UTF-16 codepoint needs to be combined with the
|
|
// current one to get the Unicode codepoint
|
|
const highSurrogate = ((codepoint - 0xd800) * 0x400) & 0xffff;
|
|
const lowSurrogate = (str.charCodeAt(i + 1) - 0xdc00) & 0xffff;
|
|
codepoint = (lowSurrogate | highSurrogate) + 0x10000;
|
|
i += 1;
|
|
}
|
|
codepointToUTF8(codepoint, emit);
|
|
}
|
|
}
|
|
/**
|
|
* Converts a UTF-8 byte to a Unicode codepoint.
|
|
*
|
|
* @param byte The UTF-8 byte next in the sequence.
|
|
* @param state The shared state between consecutive UTF-8 bytes in the
|
|
* sequence, an object with the shape `{ utf8seq: 0, codepoint: 0 }`.
|
|
* @param emit Function which will be called for each codepoint.
|
|
*/
|
|
function stringFromUTF8(byte, state, emit) {
|
|
if (state.utf8seq === 0) {
|
|
if (byte <= 0x7f) {
|
|
emit(byte);
|
|
return;
|
|
}
|
|
// count the number of 1 leading bits until you reach 0
|
|
for (let leadingBit = 1; leadingBit < 6; leadingBit += 1) {
|
|
if (((byte >> (7 - leadingBit)) & 1) === 0) {
|
|
state.utf8seq = leadingBit;
|
|
break;
|
|
}
|
|
}
|
|
if (state.utf8seq === 2) {
|
|
state.codepoint = byte & 31;
|
|
}
|
|
else if (state.utf8seq === 3) {
|
|
state.codepoint = byte & 15;
|
|
}
|
|
else if (state.utf8seq === 4) {
|
|
state.codepoint = byte & 7;
|
|
}
|
|
else {
|
|
throw new Error("Invalid UTF-8 sequence");
|
|
}
|
|
state.utf8seq -= 1;
|
|
}
|
|
else if (state.utf8seq > 0) {
|
|
if (byte <= 0x7f) {
|
|
throw new Error("Invalid UTF-8 sequence");
|
|
}
|
|
state.codepoint = (state.codepoint << 6) | (byte & 63);
|
|
state.utf8seq -= 1;
|
|
if (state.utf8seq === 0) {
|
|
emit(state.codepoint);
|
|
}
|
|
}
|
|
}
|
|
//# sourceMappingURL=base64url.js.map
|