Skip to content

Commit 2714fa4

Browse files
authored
Merge pull request #472 from streamich/base64url
Add Base64url encoder and decoder
2 parents fa08c52 + 0746394 commit 2714fa4

File tree

6 files changed

+62
-6
lines changed

6 files changed

+62
-6
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import {toBase64} from '../toBase64';
2+
import {fromBase64Url} from '../fromBase64Url';
3+
4+
const generateBlob = (): Uint8Array => {
5+
const length = Math.floor(Math.random() * 100);
6+
const uint8 = new Uint8Array(length);
7+
for (let i = 0; i < length; i++) {
8+
uint8[i] = Math.floor(Math.random() * 256);
9+
}
10+
return uint8;
11+
};
12+
13+
test('works', () => {
14+
for (let i = 0; i < 100; i++) {
15+
const blob = generateBlob();
16+
const encoded = toBase64(blob).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
17+
const decoded2 = fromBase64Url(encoded);
18+
expect(decoded2).toEqual(blob);
19+
}
20+
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import {toBase64Url} from '../toBase64Url';
2+
3+
const generateBlob = (): Uint8Array => {
4+
const length = Math.floor(Math.random() * 100) + 1;
5+
const uint8 = new Uint8Array(length);
6+
for (let i = 0; i < length; i++) {
7+
uint8[i] = Math.floor(Math.random() * 256);
8+
}
9+
return uint8;
10+
};
11+
12+
test('works', () => {
13+
for (let i = 0; i < 100; i++) {
14+
const blob = generateBlob();
15+
const expected = Buffer.from(blob).toString('base64');
16+
const base64url = toBase64Url(blob, blob.length);
17+
let encoded = base64url.replace(/-/g, '+').replace(/_/g, '/');
18+
const mod = encoded.length % 4;
19+
if (mod === 2) encoded += '==';
20+
else if (mod === 3) encoded += '=';
21+
expect(encoded).toEqual(expected);
22+
}
23+
});

src/util/base64/createFromBase64.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {alphabet} from './constants';
22

33
const E = '=';
44

5-
export const createFromBase64 = (chars: string = alphabet) => {
5+
export const createFromBase64 = (chars: string = alphabet, noPadding: boolean = false) => {
66
if (chars.length !== 64) throw new Error('chars must be 64 characters long');
77
let max = 0;
88
for (let i = 0; i < chars.length; i++) max = Math.max(max, chars.charCodeAt(i));
@@ -12,7 +12,17 @@ export const createFromBase64 = (chars: string = alphabet) => {
1212

1313
return (encoded: string): Uint8Array => {
1414
if (!encoded) return new Uint8Array(0);
15-
const length = encoded.length;
15+
let length = encoded.length;
16+
if (noPadding) {
17+
const mod = length % 4;
18+
if (mod === 2) {
19+
encoded += '==';
20+
length += 2;
21+
} else if (mod === 3) {
22+
encoded += '=';
23+
length += 1;
24+
}
25+
}
1626
if (length % 4 !== 0) throw new Error('Base64 string length must be a multiple of 4');
1727
const mainLength = encoded[length - 1] !== E ? length : length - 4;
1828
let bufferLength = (length >> 2) * 3;

src/util/base64/createToBase64.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import {alphabet} from './constants';
22

3-
const E = '=';
4-
const EE = '==';
5-
6-
export const createToBase64 = (chars: string = alphabet) => {
3+
export const createToBase64 = (chars: string = alphabet, E: string = '=', EE: string = '==') => {
74
if (chars.length !== 64) throw new Error('chars must be 64 characters long');
85

96
const table = chars.split('');

src/util/base64/fromBase64Url.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import {createFromBase64} from './createFromBase64';
2+
3+
export const fromBase64Url = createFromBase64('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', true);

src/util/base64/toBase64Url.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import {createToBase64} from './createToBase64';
2+
3+
export const toBase64Url = createToBase64('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', '', '');

0 commit comments

Comments
 (0)