mirror of https://github.com/waku-org/js-waku.git
Replace Base 64 buggy conversion functions with `uint8arrays`
This commit is contained in:
parent
a67df28ae8
commit
d0dea3884b
|
@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
- Examples: Add Relay JavaScript example.
|
- Examples: Add Relay JavaScript example.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Replace Base 64 buggy conversion functions with `uint8arrays`.
|
||||||
|
|
||||||
## [0.19.2] - 2022-03-21
|
## [0.19.2] - 2022-03-21
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -2,10 +2,11 @@ import assert from "assert";
|
||||||
|
|
||||||
import * as base32 from "hi-base32";
|
import * as base32 from "hi-base32";
|
||||||
import { ecdsaVerify } from "secp256k1";
|
import { ecdsaVerify } from "secp256k1";
|
||||||
|
import { fromString } from "uint8arrays/from-string";
|
||||||
|
|
||||||
import { ENR } from "../enr";
|
import { ENR } from "../enr";
|
||||||
import { utf8ToBytes } from "../utf8";
|
import { utf8ToBytes } from "../utf8";
|
||||||
import { base64ToBytes, keccak256Buf } from "../utils";
|
import { keccak256Buf } from "../utils";
|
||||||
|
|
||||||
export type ENRRootValues = {
|
export type ENRRootValues = {
|
||||||
eRoot: string;
|
eRoot: string;
|
||||||
|
@ -43,7 +44,10 @@ export class ENRTree {
|
||||||
// (Trailing recovery bit must be trimmed to pass `ecdsaVerify` method)
|
// (Trailing recovery bit must be trimmed to pass `ecdsaVerify` method)
|
||||||
const signedComponent = root.split(" sig")[0];
|
const signedComponent = root.split(" sig")[0];
|
||||||
const signedComponentBuffer = utf8ToBytes(signedComponent);
|
const signedComponentBuffer = utf8ToBytes(signedComponent);
|
||||||
const signatureBuffer = base64ToBytes(rootValues.signature).slice(0, 64);
|
const signatureBuffer = fromString(rootValues.signature, "base64url").slice(
|
||||||
|
0,
|
||||||
|
64
|
||||||
|
);
|
||||||
|
|
||||||
const isVerified = ecdsaVerify(
|
const isVerified = ecdsaVerify(
|
||||||
signatureBuffer,
|
signatureBuffer,
|
||||||
|
|
|
@ -29,7 +29,7 @@ describe("ENR", function () {
|
||||||
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234/wss"
|
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234/wss"
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
const txt = await enr.encodeTxt(keypair.privateKey);
|
const txt = enr.encodeTxt(keypair.privateKey);
|
||||||
|
|
||||||
const enr2 = ENR.decodeTxt(txt);
|
const enr2 = ENR.decodeTxt(txt);
|
||||||
if (!enr.signature) throw "enr.signature is undefined";
|
if (!enr.signature) throw "enr.signature is undefined";
|
||||||
|
@ -102,7 +102,7 @@ describe("ENR", function () {
|
||||||
enr.setLocationMultiaddr(new Multiaddr("/ip4/18.223.219.100/udp/9000"));
|
enr.setLocationMultiaddr(new Multiaddr("/ip4/18.223.219.100/udp/9000"));
|
||||||
|
|
||||||
enr.set("id", new Uint8Array([0]));
|
enr.set("id", new Uint8Array([0]));
|
||||||
const txt = await enr.encodeTxt(keypair.privateKey);
|
const txt = enr.encodeTxt(keypair.privateKey);
|
||||||
|
|
||||||
ENR.decodeTxt(txt);
|
ENR.decodeTxt(txt);
|
||||||
assert.fail("Expect error here");
|
assert.fail("Expect error here");
|
||||||
|
@ -203,7 +203,7 @@ describe("ENR", function () {
|
||||||
expect(decoded).to.deep.equal(record);
|
expect(decoded).to.deep.equal(record);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should encode/decode to text encoding", async () => {
|
it("should encode/decode to text encoding", () => {
|
||||||
// spec enr https://eips.ethereum.org/EIPS/eip-778
|
// spec enr https://eips.ethereum.org/EIPS/eip-778
|
||||||
const testTxt =
|
const testTxt =
|
||||||
"enr:-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04jRzjzCBOonrkTfj499SZuOh8R33Ls8RRcy5wBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0xOIN1ZHCCdl8";
|
"enr:-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04jRzjzCBOonrkTfj499SZuOh8R33Ls8RRcy5wBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0xOIN1ZHCCdl8";
|
||||||
|
@ -211,7 +211,7 @@ describe("ENR", function () {
|
||||||
expect(decoded.udp).to.be.equal(30303);
|
expect(decoded.udp).to.be.equal(30303);
|
||||||
expect(decoded.ip).to.be.equal("127.0.0.1");
|
expect(decoded.ip).to.be.equal("127.0.0.1");
|
||||||
expect(decoded).to.deep.equal(record);
|
expect(decoded).to.deep.equal(record);
|
||||||
const recordTxt = await record.encodeTxt(privateKey);
|
const recordTxt = record.encodeTxt(privateKey);
|
||||||
expect(recordTxt).to.equal(testTxt);
|
expect(recordTxt).to.equal(testTxt);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,10 +5,12 @@ import { Multiaddr, protocols } from "multiaddr";
|
||||||
// @ts-ignore: No types available
|
// @ts-ignore: No types available
|
||||||
import muConvert from "multiaddr/src/convert";
|
import muConvert from "multiaddr/src/convert";
|
||||||
import PeerId from "peer-id";
|
import PeerId from "peer-id";
|
||||||
|
import { fromString } from "uint8arrays/from-string";
|
||||||
|
import { toString } from "uint8arrays/to-string";
|
||||||
import { encode as varintEncode } from "varint";
|
import { encode as varintEncode } from "varint";
|
||||||
|
|
||||||
import { bytesToUtf8, utf8ToBytes } from "../utf8";
|
import { bytesToUtf8, utf8ToBytes } from "../utf8";
|
||||||
import { base64ToBytes, bytesToBase64, bytesToHex, hexToBytes } from "../utils";
|
import { bytesToHex, hexToBytes } from "../utils";
|
||||||
|
|
||||||
import { ERR_INVALID_ID, ERR_NO_SIGNATURE, MAX_RECORD_SIZE } from "./constants";
|
import { ERR_INVALID_ID, ERR_NO_SIGNATURE, MAX_RECORD_SIZE } from "./constants";
|
||||||
import {
|
import {
|
||||||
|
@ -107,7 +109,7 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||||
`"string encoded ENR must start with '${this.RECORD_PREFIX}'`
|
`"string encoded ENR must start with '${this.RECORD_PREFIX}'`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return ENR.decode(base64ToBytes(encoded.slice(4)));
|
return ENR.decode(fromString(encoded.slice(4), "base64url"));
|
||||||
}
|
}
|
||||||
|
|
||||||
set(k: ENRKey, v: ENRValue): this {
|
set(k: ENRKey, v: ENRValue): this {
|
||||||
|
@ -465,7 +467,7 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||||
return encoded;
|
return encoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
async encodeTxt(privateKey?: Uint8Array): Promise<string> {
|
encodeTxt(privateKey?: Uint8Array): string {
|
||||||
return ENR.RECORD_PREFIX + (await bytesToBase64(this.encode(privateKey)));
|
return ENR.RECORD_PREFIX + toString(this.encode(privateKey), "base64url");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,49 +81,3 @@ export function equalByteArrays(
|
||||||
export function keccak256Buf(message: Message): Uint8Array {
|
export function keccak256Buf(message: Message): Uint8Array {
|
||||||
return new Uint8Array(keccak256.arrayBuffer(message));
|
return new Uint8Array(keccak256.arrayBuffer(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert base64 string to byte array.
|
|
||||||
*/
|
|
||||||
export function base64ToBytes(base64: string): Uint8Array {
|
|
||||||
const e = new Map<string, number>();
|
|
||||||
|
|
||||||
const len = base64.length;
|
|
||||||
const res = [];
|
|
||||||
const A = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
||||||
for (let i = 0; i < 64; i++) {
|
|
||||||
e.set(A.charAt(i), i);
|
|
||||||
}
|
|
||||||
e.set("+", 62);
|
|
||||||
e.set("/", 63);
|
|
||||||
|
|
||||||
let b = 0,
|
|
||||||
l = 0,
|
|
||||||
a;
|
|
||||||
for (let i = 0; i < len; i++) {
|
|
||||||
const c = e.get(base64.charAt(i));
|
|
||||||
if (c === undefined)
|
|
||||||
throw new Error(`Invalid base64 character ${base64.charAt(i)}`);
|
|
||||||
b = (b << 6) + c;
|
|
||||||
l += 6;
|
|
||||||
while (l >= 8) {
|
|
||||||
((a = (b >>> (l -= 8)) & 0xff) || i < len - 2) && res.push(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new Uint8Array(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert byte array to base64 string.
|
|
||||||
*/
|
|
||||||
export async function bytesToBase64(bytes: Uint8Array): Promise<string> {
|
|
||||||
const base64url: string = await new Promise((r) => {
|
|
||||||
const reader = new window.FileReader();
|
|
||||||
reader.onload = (): void => r(reader.result as string);
|
|
||||||
reader.readAsDataURL(new Blob([bytes]));
|
|
||||||
});
|
|
||||||
const base64 = base64url.split(",", 2)[1];
|
|
||||||
// We want URL and Filename Safe base64: https://datatracker.ietf.org/doc/html/rfc4648#section-5
|
|
||||||
// Without trailing padding
|
|
||||||
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue