2022-07-20 17:51:16 +00:00
|
|
|
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
|
exports.tester = exports.loadTester = exports.login = exports.generateSeedPhrase = exports.TEST_KERNEL_SKLINK = exports.KERNEL_HELPER_MODULE = exports.KERNEL_TEST_SUITE = void 0;
|
|
|
|
const libskynet_1 = require("libskynet");
|
|
|
|
const seed_1 = require("libskynet/dist/seed");
|
|
|
|
const dictionary_1 = require("libskynet/dist/dictionary");
|
|
|
|
const path = require("path");
|
|
|
|
const libskynetnode_1 = require("libskynetnode");
|
|
|
|
const kernel = require("libkernel");
|
|
|
|
const crypto_1 = require("crypto");
|
|
|
|
// @ts-ignore
|
|
|
|
const StaticServer = require("static-server");
|
|
|
|
exports.KERNEL_TEST_SUITE = "AQCPJ9WRzMpKQHIsPo8no3XJpUydcDCjw7VJy8lG1MCZ3g";
|
|
|
|
exports.KERNEL_HELPER_MODULE = "AQCoaLP6JexdZshDDZRQaIwN3B7DqFjlY7byMikR7u1IEA";
|
|
|
|
exports.TEST_KERNEL_SKLINK = "AQDJDoXMJiiEMBxXodQvUV89qtQHsnXWyV1ViQ9M1pMjUg";
|
2022-06-30 20:13:15 +00:00
|
|
|
const SEED_ENTROPY_WORDS = 13;
|
2022-07-20 17:51:16 +00:00
|
|
|
const crypto = crypto_1.webcrypto;
|
|
|
|
function generateSeedPhrase() {
|
|
|
|
// Get the random numbers for the seed phrase. Typically, you need to
|
|
|
|
// have code that avoids bias by checking the random results and
|
|
|
|
// re-rolling the random numbers if the result is outside of the range
|
|
|
|
// of numbers that would produce no bias. Because the search space
|
|
|
|
// (1024) evenly divides the random number space (2^16), we can skip
|
|
|
|
// this step and just use a modulus instead. The result will have no
|
|
|
|
// bias, but only because the search space is a power of 2.
|
|
|
|
let randNums = new Uint16Array(SEED_ENTROPY_WORDS);
|
|
|
|
crypto.getRandomValues(randNums);
|
2022-06-30 20:13:15 +00:00
|
|
|
// Generate the seed phrase from the randNums.
|
|
|
|
let seedWords = [];
|
|
|
|
for (let i = 0; i < SEED_ENTROPY_WORDS; i++) {
|
2022-07-20 17:51:16 +00:00
|
|
|
let wordIndex = randNums[i] % libskynet_1.dictionary.length;
|
|
|
|
seedWords.push(libskynet_1.dictionary[wordIndex]);
|
2022-06-30 20:13:15 +00:00
|
|
|
}
|
|
|
|
// Convert the seedWords to a seed.
|
2022-07-20 17:51:16 +00:00
|
|
|
let [seed] = seedWordsToSeed(seedWords);
|
2022-06-30 20:13:15 +00:00
|
|
|
// Compute the checksum.
|
2022-07-20 17:51:16 +00:00
|
|
|
let [checksumOne, checksumTwo, err2] = (0, seed_1.seedToChecksumWords)(seed);
|
2022-06-30 20:13:15 +00:00
|
|
|
// Assemble the final seed phrase and set the text field.
|
2022-07-20 17:51:16 +00:00
|
|
|
return [...seedWords, checksumOne, checksumTwo].join(" ");
|
2022-06-30 20:13:15 +00:00
|
|
|
}
|
2022-07-20 17:51:16 +00:00
|
|
|
exports.generateSeedPhrase = generateSeedPhrase;
|
2022-06-30 20:13:15 +00:00
|
|
|
function seedWordsToSeed(seedWords) {
|
|
|
|
// Input checking.
|
|
|
|
if (seedWords.length !== SEED_ENTROPY_WORDS) {
|
2022-07-20 17:51:16 +00:00
|
|
|
return [
|
|
|
|
new Uint8Array(0),
|
|
|
|
`Seed words should have length ${SEED_ENTROPY_WORDS} but has length ${seedWords.length}`,
|
|
|
|
];
|
2022-06-30 20:13:15 +00:00
|
|
|
}
|
|
|
|
// We are getting 16 bytes of entropy.
|
2022-07-20 17:51:16 +00:00
|
|
|
let bytes = new Uint8Array(seed_1.SEED_BYTES);
|
2022-06-30 20:13:15 +00:00
|
|
|
let curByte = 0;
|
|
|
|
let curBit = 0;
|
|
|
|
for (let i = 0; i < SEED_ENTROPY_WORDS; i++) {
|
|
|
|
// Determine which number corresponds to the next word.
|
|
|
|
let word = -1;
|
2022-07-20 17:51:16 +00:00
|
|
|
for (let j = 0; j < libskynet_1.dictionary.length; j++) {
|
|
|
|
if (seedWords[i].slice(0, dictionary_1.DICTIONARY_UNIQUE_PREFIX) ===
|
|
|
|
libskynet_1.dictionary[j].slice(0, dictionary_1.DICTIONARY_UNIQUE_PREFIX)) {
|
2022-06-30 20:13:15 +00:00
|
|
|
word = j;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (word === -1) {
|
2022-07-20 17:51:16 +00:00
|
|
|
return [
|
|
|
|
new Uint8Array(0),
|
|
|
|
`word '${seedWords[i]}' at index ${i} not found in dictionary`,
|
|
|
|
];
|
2022-06-30 20:13:15 +00:00
|
|
|
}
|
|
|
|
let wordBits = 10;
|
|
|
|
if (i === SEED_ENTROPY_WORDS - 1) {
|
|
|
|
wordBits = 8;
|
|
|
|
}
|
|
|
|
// Iterate over the bits of the 10- or 8-bit word.
|
|
|
|
for (let j = 0; j < wordBits; j++) {
|
|
|
|
let bitSet = (word & (1 << (wordBits - j - 1))) > 0;
|
|
|
|
if (bitSet) {
|
|
|
|
bytes[curByte] |= 1 << (8 - curBit - 1);
|
|
|
|
}
|
|
|
|
curBit += 1;
|
|
|
|
if (curBit >= 8) {
|
|
|
|
// Current byte has 8 bits, go to the next byte.
|
|
|
|
curByte += 1;
|
|
|
|
curBit = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return [bytes, null];
|
|
|
|
}
|
2022-07-20 17:51:16 +00:00
|
|
|
async function login(page, seed = generateSeedPhrase()) {
|
|
|
|
await page.goto("http://skt.us");
|
|
|
|
let userSeed;
|
|
|
|
[userSeed] = (0, libskynet_1.seedPhraseToSeed)(seed);
|
|
|
|
let seedHex = (0, libskynet_1.bufToHex)(userSeed);
|
|
|
|
await page.evaluate((seed) => {
|
|
|
|
window.localStorage.setItem("v1-seed", seed);
|
|
|
|
}, seedHex);
|
|
|
|
let kernelEntrySeed = (0, libskynet_1.deriveChildSeed)(userSeed, "userPreferredKernel2");
|
|
|
|
// Get the registry keys.
|
|
|
|
let [keypair, dataKey] = (0, libskynet_1.taggedRegistryEntryKeys)(kernelEntrySeed, "user kernel");
|
|
|
|
await (0, libskynetnode_1.overwriteRegistryEntry)(keypair, dataKey, (0, libskynet_1.b64ToBuf)(exports.TEST_KERNEL_SKLINK)[0]);
|
|
|
|
}
|
|
|
|
exports.login = login;
|
|
|
|
async function loadTester(page, port = 8080) {
|
|
|
|
const server = new StaticServer({
|
|
|
|
rootPath: path.resolve(__dirname, "..", "public"),
|
|
|
|
port,
|
|
|
|
host: "localhost",
|
|
|
|
});
|
|
|
|
await new Promise((resolve) => {
|
|
|
|
server.start(resolve);
|
|
|
|
});
|
|
|
|
const stop = () => server.stop();
|
|
|
|
process.on("SIGTERM", stop);
|
|
|
|
page.browser().on("disconnected", stop);
|
|
|
|
await page.goto(`http://localhost:${port}/`);
|
|
|
|
await page.evaluate(() => {
|
|
|
|
return kernel.init();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
exports.loadTester = loadTester;
|
|
|
|
class Tester {
|
|
|
|
page;
|
|
|
|
constructor(page) {
|
|
|
|
this.page = page;
|
|
|
|
}
|
|
|
|
async callModule(id, method, data = {}) {
|
|
|
|
return this.page.evaluate(async (id, method, data) => {
|
|
|
|
return kernel.callModule(id, method, data);
|
|
|
|
}, id, method, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const tester = (page) => new Tester(page);
|
|
|
|
exports.tester = tester;
|