This commit is contained in:
Derrick Hammer 2023-04-03 13:29:20 -04:00
parent 7efd901b97
commit 2e15a16faa
Signed by: pcfreak30
GPG Key ID: C997C339BE476FF2
15 changed files with 1293 additions and 5219 deletions

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
"description": "Lume Web is your decentralized gateway into the web3 internet, the web owned and controlled by its users", "description": "Lume Web is your decentralized gateway into the web3 internet, the web owned and controlled by its users",
"manifest_version": 2, "manifest_version": 2,
"name": "Lume Web", "name": "Lume Web",
"version": "0.3.0", "version": "0.3.0.3",
"homepage_url": "https://lumeweb.com", "homepage_url": "https://lumeweb.com",
"icons": { "icons": {
"48": "icon.png", "48": "icon.png",
@ -24,7 +24,7 @@
"content_scripts": [ "content_scripts": [
{ {
"matches": [ "matches": [
"http://kernel.skynet/" "http://kernel.lume/"
], ],
"js": [ "js": [
"bootloader.js" "bootloader.js"

View File

@ -16,7 +16,7 @@ esbuild.buildSync({
esbuild.buildSync({ esbuild.buildSync({
entryPoints: ["src/main/bootloader.ts"], entryPoints: ["src/main/bootloader.ts"],
outfile: "dist/bootloader.js", outfile: "dist/bootloader.js",
format: "esm", format: "iife",
bundle: true, bundle: true,
legalComments: "external", legalComments: "external",
// minify: true // minify: true
@ -27,14 +27,14 @@ esbuild.buildSync({
esbuild.buildSync({ esbuild.buildSync({
entryPoints: ["src/main/bridge.ts"], entryPoints: ["src/main/bridge.ts"],
outfile: "dist/bridge.js", outfile: "dist/bridge.js",
format: "esm", format: "iife",
bundle: true, bundle: true,
legalComments: "external", legalComments: "external",
// minify: true // minify: true
define: { define: {
global: "self", global: "self",
}, },
}); }); /*
esbuild.buildSync({ esbuild.buildSync({
entryPoints: ["src/main/crypto.ts"], entryPoints: ["src/main/crypto.ts"],
outfile: "dist/crypto.js", outfile: "dist/crypto.js",
@ -58,3 +58,4 @@ esbuild.buildSync({
global: "window", global: "window",
} }
}); });
*/

View File

@ -15,45 +15,45 @@
"author": "David Vorick", "author": "David Vorick",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@lumeweb/kernel-dns-client": "https://github.com/LumeWeb/kernel-dns-client.git", "@helia/unixfs": "^1.2.1",
"@lumeweb/webextension-polyfill": "https://github.com/LumeWeb/webextension-polyfill.git",
"@rollup/plugin-node-resolve": "^13.3.0", "@rollup/plugin-node-resolve": "^13.3.0",
"@types/ejs": "^3.1.1", "@types/ejs": "^3.1.2",
"@types/read": "^0.0.29", "@types/read": "^0.0.29",
"@types/webextension-polyfill": "^0.9.0", "@types/webextension-polyfill": "^0.9.2",
"@typescript-eslint/eslint-plugin": "^5.18.0", "@typescript-eslint/eslint-plugin": "^5.57.0",
"browserify-fs": "^1.0.0", "browserify-fs": "^1.0.0",
"cpy-cli": "^4.1.0", "cpy-cli": "^4.2.0",
"esbuild": "^0.14.51", "esbuild": "^0.14.54",
"eslint": "^8.13.0", "eslint": "^8.37.0",
"events": "^3.3.0", "events": "^3.3.0",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"prettier": "^2.6.2", "prettier": "^2.8.7",
"process": "^0.11.10", "process": "^0.11.10",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup": "^2.75.6", "rollup": "^2.79.1",
"stream": "^0.0.2", "stream": "^0.0.2",
"typescript": "^4.6.3", "typescript": "^4.9.5",
"util": "^0.12.4", "util": "^0.12.5",
"webextension-polyfill": "^0.9.0" "webextension-polyfill": "^0.9.0"
}, },
"dependencies": { "dependencies": {
"@lumeweb/kernel-dht-client": "https://github.com/LumeWeb/kernel-dht-client.git", "@lumeweb/kernel-dns-client": "git+https://git.lumeweb.com/LumeWeb/kernel-dns-client.git",
"@lumeweb/kernel-ipfs-client": "https://github.com/LumeWeb/kernel-ipfs-client.git", "@lumeweb/kernel-ipfs-client": "git+https://git.lumeweb.com/LumeWeb/kernel-ipfs-client.git",
"@lumeweb/libresolver": "https://github.com/LumeWeb/libresolver.git", "@lumeweb/libresolver": "git+https://git.lumeweb.com/LumeWeb/libresolver.git",
"@lumeweb/tld-enum": "https://github.com/LumeWeb/list-of-top-level-domains.git", "@lumeweb/tld-enum": "git+https://git.lumeweb.com/LumeWeb/list-of-top-level-domains.git",
"@peculiar/webcrypto": "^1.4.0", "@lumeweb/webextension-polyfill": "git+https://git.lumeweb.com/LumeWeb/webextension-polyfill.git",
"dexie": "^3.2.2", "@peculiar/webcrypto": "^1.4.3",
"ejs": "^3.1.8", "@siaweb/libweb": "git+https://git.lumeweb.com/LumeWeb/libsiaweb.git",
"buffer": "^6.0.3",
"is-ipfs": "^6.0.2", "is-ipfs": "^6.0.2",
"libkernel": "https://github.com/LumeWeb/libextension.git", "libkernel": "^0.1.48",
"libskynet": "^0.0.62", "libskynet": "^0.0.62",
"node-cache": "^5.1.2" "node-cache": "^5.1.2"
}, },
"browser": { "browser": {
"libkmodule": false, "crypto": "crypto-browserify",
"path": "path-browserify",
"fs": "browserify-fs", "fs": "browserify-fs",
"crypto": "crypto-browserify" "libkmodule": false,
"path": "path-browserify"
} }
} }

7
src/clients.ts Normal file
View File

@ -0,0 +1,7 @@
import { createClient as createDnsClient } from "@lumeweb/kernel-dns-client";
import { createClient as createIpfsClient } from "@lumeweb/kernel-ipfs-client";
const dnsClient = createDnsClient();
const ipfsClient = createIpfsClient();
export { dnsClient, ipfsClient };

View File

@ -7,86 +7,17 @@ import {
OnRequestDetailsType, OnRequestDetailsType,
StreamFilter, StreamFilter,
} from "../types.js"; } from "../types.js";
import { getRelayProxies, streamToArray } from "../util.js"; import { getRelayProxies } from "../util.js";
import { ipfsPath, ipnsPath, path } from "is-ipfs"; import { ipfsPath, ipnsPath, path as checkPath } from "is-ipfs";
import { import { createClient } from "@lumeweb/kernel-ipfs-client";
fetchIpfs,
fetchIpns,
statIpfs,
statIpns,
} from "@lumeweb/kernel-ipfs-client";
import ejs from "ejs";
import { cacheDb } from "../databases.js";
import { DNS_RECORD_TYPE, DNSResult } from "@lumeweb/libresolver"; import { DNS_RECORD_TYPE, DNSResult } from "@lumeweb/libresolver";
import RequestStream from "../requestStream.js"; import RequestStream from "../requestStream.js";
import ContentFilterRegistry from "../contentFilterRegistry.js"; import ContentFilterRegistry from "../contentFilterRegistry.js";
import { UnixFSStats } from "@helia/unixfs";
const INDEX_HTML_FILES = ["index.html", "index.htm", "index.shtml"]; import * as path from "path";
const DIRECTORY_TEMPLATE = ejs.compile(`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><%= path %></title>
<style></style>
</head>
<body>
<div id="header" class="row">
<div class="col-xs-2">
<div id="logo" class="ipfs-logo"></div>
</div>
</div>
<br>
<div class="col-xs-12">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Index of <%= path %></strong>
</div>
<table class="table table-striped">
<tbody>
<tr>
<td class="narrow">
<div class="ipfs-icon ipfs-_blank">&nbsp;</div>
</td>
<td class="padding">
<a href="<%= parentHref %>">..</a>
</td>
<td></td>
</tr>
<% links.forEach(function (link) { %>
<tr>
<td><div class="ipfs-icon ipfs-_blank">&nbsp;</div></td>
<td><a href="<%= link.link %>"><%= link.name %></a></t>
<td><%= link.size %></td>
</td>
</tr>
<% }) %>
</tbody>
</table>
</div>
</div>
</body>
</html>`);
interface StatFileResponse {
exists: boolean;
contentType: string | null;
error: any;
directory: boolean;
files: StatFileSubfile[];
timeout: boolean;
size: number;
}
interface StatFileSubfile {
name: string;
size: number;
}
const MAX_CACHE_SIZE = 1024 * 1024 * 1024 * 50;
export default class IpfsProvider extends BaseProvider { export default class IpfsProvider extends BaseProvider {
private _client = createClient();
async shouldHandleRequest( async shouldHandleRequest(
details: OnBeforeRequestDetailsType details: OnBeforeRequestDetailsType
): Promise<boolean> { ): Promise<boolean> {
@ -99,15 +30,16 @@ export default class IpfsProvider extends BaseProvider {
} }
let contentRecords = (dnsResult as DNSResult).records.map( let contentRecords = (dnsResult as DNSResult).records.map(
(item) => "/" + item.value.replace("://", "/").replace(/^\+/, "/") (item: { value: string }) =>
"/" + item.value.replace("://", "/").replace(/^\+/, "/")
); );
contentRecords = contentRecords.filter((item) => path(item)); contentRecords = contentRecords.filter((item) => checkPath(item));
if (!contentRecords.length) { if (!contentRecords.length) {
return false; return false;
} }
this.setData(details, "hash", contentRecords.shift()); this.setData(details, "cid", contentRecords.shift());
return true; return true;
} }
@ -131,64 +63,35 @@ export default class IpfsProvider extends BaseProvider {
): Promise<BlockingResponse | boolean> { ): Promise<BlockingResponse | boolean> {
let urlObj = new URL(details.url); let urlObj = new URL(details.url);
let urlPath = urlObj.pathname; let urlPath = urlObj.pathname;
let hash = this.getData(details, "hash"); const cid = this.getData(details, "cid");
let resp: StatFileResponse | null = null;
let fetchMethod: typeof fetchIpfs | typeof fetchIpns;
let err; let err;
let contentType: string; let stat: UnixFSStats | null = null;
let contentSize = 0;
let cachedPage: { contentType: string; data: Blob } | null = null; let parsedPath = path.parse(urlPath);
let contentSize;
try { try {
// @ts-ignore if (ipnsPath(parsedPath.root)) {
cachedPage = await cacheDb.items.where("url").equals(details.url).first(); let ipnsLookup = await this._client.ipns(cid);
} catch {} stat = await this._client.stat(ipnsLookup);
} else if (ipfsPath(parsedPath.root)) {
if (!cachedPage) { stat = await this._client.stat(cid);
try {
if (ipfsPath(hash)) {
hash = hash.replace("/ipfs/", "");
resp = await statIpfs(hash.replace("/ipfs/", ""), urlPath);
fetchMethod = fetchIpfs;
} else if (ipnsPath(hash)) {
hash = hash.replace("/ipns/", "");
resp = await statIpns(hash.replace("/ipns/", ""), urlPath);
fetchMethod = fetchIpns;
} else {
err = "invalid content";
} }
} catch (e: any) { } catch (e) {
err = (e as Error).message; err = (e as Error).message;
} }
contentType = resp?.contentType as string; if (err) {
if (contentType?.includes(";")) {
contentType = contentType?.split(";").shift() as string;
}
contentSize = resp?.size as number;
} else {
contentType = cachedPage.contentType;
contentSize = cachedPage.data.size;
}
if (resp) {
if (!resp.exists) {
err = "404"; err = "404";
} }
if (resp.directory) {
contentType = "text/html";
}
}
this.setData(details, "contentType", contentType); // this.setData(details, "contentType", contentType);
const isSmallFile = contentSize <= MAX_CACHE_SIZE;
const reqStream = new RequestStream( const reqStream = new RequestStream(
details, details
isSmallFile && ContentFilterRegistry.hasFilters(contentType) /* ContentFilterRegistry.hasFilters(contentType)
? ContentFilterRegistry.filter(contentType) ? ContentFilterRegistry.filter(contentType)
: undefined : undefined*/
); );
reqStream.start(); reqStream.start();
@ -196,49 +99,20 @@ export default class IpfsProvider extends BaseProvider {
reqStream.close(); reqStream.close();
return {}; return {};
} }
if (cachedPage) {
(
cachedPage?.data.stream() as unknown as ReadableStream<Uint8Array>
).pipeThrough(reqStream.stream);
return {};
}
if (resp?.directory) {
let indexFiles =
resp?.files.filter((item) => INDEX_HTML_FILES.includes(item.name)) ||
[];
if (indexFiles.length > 0) {
urlPath += `/${indexFiles[0].name}`;
}
}
if (isSmallFile) {
streamToArray(reqStream.readableStream).then((data: Uint8Array) => {
// @ts-ignore
return cacheDb.items.put({
url: details.url,
contentType,
data: new Blob([data.buffer], { type: contentType }),
timestamp: Date.now(),
});
});
}
const streamWriter = reqStream.stream.writable.getWriter(); const streamWriter = reqStream.stream.writable.getWriter();
// @ts-ignore const reader = this._client.cat(parsedPath.root, { path: parsedPath.dir });
fetchMethod?.(hash, urlPath, (data: Buffer) => {
streamWriter.write(data); (async function () {
}) try {
.then(() => { for await (const chunk of reader.iterable) {
streamWriter.releaseLock(); streamWriter.write(chunk);
return reqStream.close(); }
}) } catch {
.catch((e: any) => {
streamWriter.releaseLock(); streamWriter.releaseLock();
reqStream.close(); reqStream.close();
}); }
})();
return {}; return {};
} }

View File

@ -1,117 +0,0 @@
import BaseProvider from "./baseProvider.js";
import {
BlockingResponse,
OnBeforeRequestDetailsType,
OnHeadersReceivedDetailsType,
OnRequestDetailsType,
} from "../types.js";
import { validSkylink } from "libskynet";
import { downloadSkylink, getRelayProxies } from "../util.js";
import browser from "@lumeweb/webextension-polyfill";
import { DNS_RECORD_TYPE, DNSResult } from "@lumeweb/libresolver";
export default class SkynetProvider extends BaseProvider {
async shouldHandleRequest(
details: OnBeforeRequestDetailsType
): Promise<boolean> {
let dnsResult: DNSResult | boolean | string = await this.resolveDns(
details,
[DNS_RECORD_TYPE.CONTENT, DNS_RECORD_TYPE.TEXT]
);
if (!dnsResult) {
return false;
}
let contentRecords = (dnsResult as DNSResult).records
.map((item) => {
item.value = item.value.replace("sia://", "");
return item;
})
.filter((item) => {
try {
return validSkylink(item.value);
} catch (e) {
return false;
}
});
if (!contentRecords.length) {
return false;
}
this.setData(details, "hash", contentRecords.shift()?.value);
return true;
}
async handleProxy(details: OnRequestDetailsType): Promise<any> {
return getRelayProxies();
}
async handleRequest(
details: OnBeforeRequestDetailsType
): Promise<BlockingResponse | boolean> {
const hash = this.getData(details, "hash");
let urlObj = new URL(details.url);
let path = urlObj.pathname;
let fileData: any, err;
if (urlObj.protocol == "https") {
urlObj.protocol = "http";
return { redirectUrl: urlObj.toString() };
}
try {
[fileData, err] = await downloadSkylink(hash, path);
} catch (e: any) {
debugger;
this.setData(details, "error", (e as Error).message);
return {};
}
if (err) {
this.setData(details, "error", err);
return {};
}
this.setData(details, "headers", fileData.response?.headers);
const filter = browser.webRequest.filterResponseData(details.requestId);
filter.ondata = () => {};
filter.onstop = () => {
fileData.response.arrayBuffer().then((data: any) => {
filter.write(data);
filter.close();
});
};
return true;
}
async handleHeaders(
details: OnHeadersReceivedDetailsType
): Promise<BlockingResponse | boolean> {
const err = this.getData(details, "error");
let headers: Headers = this.getData(details, "headers") as Headers;
if (err) {
return {
responseHeaders: [
{
name: "Status-Code",
value: err == "404" ? "404" : "400",
},
{
name: "Content-Type",
value: "text/html; charset=utf8",
},
],
};
}
return {
responseHeaders: Array.from(headers).map((item: string[]) => {
return { name: item[0], value: item[1] };
}),
};
}
}

View File

@ -2,20 +2,12 @@ import browser from "@lumeweb/webextension-polyfill";
import type WebEngine from "./webEngine.js"; import type WebEngine from "./webEngine.js";
import type { Menus, Tabs } from "./types.js"; import type { Menus, Tabs } from "./types.js";
import IpfsProvider from "./contentProviders/ipfsProvider.js"; import IpfsProvider from "./contentProviders/ipfsProvider.js";
import { cacheDb } from "./databases.js";
export default function setup(engine: WebEngine) { export default function setup(engine: WebEngine) {
browser.menus.create({ browser.menus.create({
title: "Clear Cache", title: "Clear Cache",
id: "clear-cache", id: "clear-cache",
onclick: async (info: Menus.OnClickData, tab: Tabs.Tab) => { onclick: async (info: Menus.OnClickData, tab: Tabs.Tab) => {
// @ts-ignore
await cacheDb.items
.where("url")
.startsWithIgnoreCase(
`http://${new URL(info.pageUrl as string).hostname}`
)
.delete();
browser.tabs.reload(tab.id); browser.tabs.reload(tab.id);
}, },
}); });

View File

@ -1,7 +0,0 @@
import Dexie from "dexie";
export const cacheDb = new Dexie("LumeWebIFSCache");
cacheDb.version(1).stores({
items: `url,contentType,data,timestamp`,
});

View File

@ -1,16 +1,13 @@
import NodeCache from "node-cache"; import NodeCache from "node-cache";
import {
ready as dnsReady,
resolve as resolveDns,
} from "@lumeweb/kernel-dns-client";
import { import {
DNS_RECORD_TYPE, DNS_RECORD_TYPE,
DNSRecord,
DNSResult, DNSResult,
ResolverOptions, ResolverOptions,
} from "@lumeweb/libresolver"; } from "@lumeweb/libresolver";
import { blake2b, bufToHex, Err } from "libskynet/dist"; import { blake2b, bufToHex, Err } from "libskynet/dist";
import { getDnsSetupPromise } from "./main/vars.js"; import { getDnsSetupPromise } from "./main/vars.js";
import { createClient, DnsClient } from "@lumeweb/kernel-dns-client";
import { dnsClient } from "./clients.js";
const cache = new NodeCache({ stdTTL: 60 }); const cache = new NodeCache({ stdTTL: 60 });
@ -32,7 +29,7 @@ export async function resolve(
let res; let res;
try { try {
res = await resolveDns(domain, options, bypassCache); res = await dnsClient.resolve(domain, options, bypassCache);
} catch (e: any) { } catch (e: any) {
return e as Error; return e as Error;
} }

View File

@ -1,11 +1,9 @@
import tldEnum from "@lumeweb/tld-enum"; import tldEnum from "@lumeweb/tld-enum";
import WebEngine from "../webEngine.js"; import WebEngine from "../webEngine.js";
import InternalProvider from "../contentProviders/internalProvider.js"; import InternalProvider from "../contentProviders/internalProvider.js";
import SkynetProvider from "../contentProviders/skynetProvider.js";
import ServerProvider from "../contentProviders/serverProvider.js"; import ServerProvider from "../contentProviders/serverProvider.js";
import { init } from "libkernel"; import { init, kernelLoaded } from "libkernel";
import IpfsProvider from "../contentProviders/ipfsProvider.js"; import IpfsProvider from "../contentProviders/ipfsProvider.js";
import { ready as dnsReady } from "@lumeweb/kernel-dns-client";
import { import {
addQuery, addQuery,
getAuthStatusResolve, getAuthStatusResolve,
@ -33,9 +31,11 @@ import {
setOpenPort, setOpenPort,
setTimer, setTimer,
} from "./vars.js"; } from "./vars.js";
// @ts-ignore
import browser from "@lumeweb/webextension-polyfill"; import browser from "@lumeweb/webextension-polyfill";
import setupContextMenus from "../contextMenu.js"; import setupContextMenus from "../contextMenu.js";
import { callModule } from "libkernel"; import { callModule } from "libkernel";
import { ipfsClient } from "../clients.js";
function logLargeObjects() { function logLargeObjects() {
let queriesLen = Object.keys(getQueries()).length; let queriesLen = Object.keys(getQueries()).length;
@ -49,6 +49,7 @@ function logLargeObjects() {
setTimer(getTimer() * 1.25); setTimer(getTimer() * 1.25);
setTimeout(logLargeObjects, getTimer()); setTimeout(logLargeObjects, getTimer());
} }
setTimeout(logLargeObjects, getTimer()); setTimeout(logLargeObjects, getTimer());
export function queryKernel(query: any): Promise<any> { export function queryKernel(query: any): Promise<any> {
@ -75,9 +76,12 @@ export function queryKernel(query: any): Promise<any> {
}); });
}); });
} }
function handleKernelMessage(event: MessageEvent) { function handleKernelMessage(event: MessageEvent) {
let data = event.data.data; let data = event.data.data;
console.log("handleKernelMessage debug", event.data);
if (event.data.method === "kernelBridgeVersion") { if (event.data.method === "kernelBridgeVersion") {
getBlockForBridge().then(() => { getBlockForBridge().then(() => {
for (let [, port] of Object.entries(getOpenPorts())) { for (let [, port] of Object.entries(getOpenPorts())) {
@ -152,6 +156,8 @@ function handleBridgeMessage(
data: any, data: any,
domain: string domain: string
) { ) {
console.log("handleBridgeMessage debug", data.data);
if (data.method === "bridgeLoaded") { if (data.method === "bridgeLoaded") {
getBridgeLoadedResolve()(); getBridgeLoadedResolve()();
return; return;
@ -174,8 +180,10 @@ function handleBridgeMessage(
}); });
data["domain"] = domain; data["domain"] = domain;
} }
getKernelIframe().contentWindow!.postMessage(data, "http://kernel.lume"); getKernelIframe().contentWindow!.postMessage(data, "http://kernel.lume");
} }
function bridgeListener(port: any) { function bridgeListener(port: any) {
let portNonce = getPortsNonce(); let portNonce = getPortsNonce();
increasePortsNonce(); increasePortsNonce();
@ -206,14 +214,24 @@ async function boot() {
const engine = new WebEngine(); const engine = new WebEngine();
engine.registerContentProvider(new InternalProvider(engine)); engine.registerContentProvider(new InternalProvider(engine));
engine.registerContentProvider(new SkynetProvider(engine));
engine.registerContentProvider(new IpfsProvider(engine)); engine.registerContentProvider(new IpfsProvider(engine));
engine.registerContentProvider(new ServerProvider(engine)); engine.registerContentProvider(new ServerProvider(engine));
setKernelIframe(document.createElement("iframe")); setKernelIframe(document.createElement("iframe"));
getKernelIframe().src = "http://kernel.lume"; getKernelIframe().src = "http://kernel.lume";
getKernelIframe().onload = init;
await new Promise((resolve) => {
getKernelIframe().onload = () => {
init().then(resolve);
};
document.body.appendChild(getKernelIframe()); document.body.appendChild(getKernelIframe());
});
// @ts-ignore
window.callModule = callModule;
await kernelLoaded();
await ipfsClient.ready();
setupContextMenus(engine); setupContextMenus(engine);
setDnsSetupPromise(dnsSetup()); setDnsSetupPromise(dnsSetup());
@ -222,19 +240,12 @@ async function boot() {
async function dnsSetup() { async function dnsSetup() {
const resolvers = [ const resolvers = [
"AQBXtVkPDbZ5Qmjl8dzJ0siSYaFcS3XbDZHapxmZCLfwfg", // icann "AQBXtVkPDbZ5Qmjl8dzJ0siSYaFcS3XbDZHapxmZCLfwfg", // icann
"AQAI3TbarrXRxWtrb_5XO-gMYg-UsjVAChue5JEoqywbAw", // eip137 "_B1zdE-P7e1csLVoT9w3DvgxWGdDdUj9tnkRGzXyYV-rkg", // ens
"AQD0s0wZNpZCVg_iO96E6Ff66WxGa2CZst_DCYR_DoQPxw", // solana "vAN0mq5cLYOK2e2Wk1Is980LYSW3reHKrd-w2-vqWfwNUw", // hns
"AQDtYcJGbquAHA-idtZ-gPOlNBgEVeCZtZUtsyL_J5ZiUA", // algorand
"AQDkqoCzCR6s5MP_k6Ee9QWfEwaH5-7XleCKFL1CdxExxQ", // avax
"AQC7ALr-OtkFT7qZby2BdMMNbTRXHNMGlpV6r96b35Z79Q", // evmos
"AQAmQoZLu1DqIiZaRWRpomvMarQ8Uc3kdHJQBo0r-9uYtg", // handshake
]; ];
for (const resolver of resolvers) { for (const resolver of resolvers) {
await callModule(resolver, "register"); await callModule(resolver, "register");
} }
await dnsReady();
} }
boot(); boot();

View File

@ -1,28 +1,14 @@
import { import {
addContextToErr, addContextToErr,
b64ToBuf,
bufToHex,
bufToStr, bufToStr,
computeRegistrySignature,
defaultPortalList,
deriveChildSeed,
deriveRegistryEntryID,
downloadSkylink,
Ed25519Keypair,
entryIDToSkylink,
Err, Err,
hexToBuf, hexToBuf,
progressiveFetch,
progressiveFetchResult,
taggedRegistryEntryKeys,
objAsString, objAsString,
verifyRegistryWriteResponse, } from "@siaweb/libweb";
} from "libskynet";
var browser: any; // tsc declare var browser: any; // tsc
const defaultKernelResolverLink = const defaultKernelLink = "RAAdkljTc2ZmgSNV5EKr-fJZSEEz8irbf2QEqBw9hoEIKA";
"AQDJDoXMJiiEMBxXodQvUV89qtQHsnXWyV1ViQ9M1pMjUg";
document.title = "kernel.lume"; document.title = "kernel.lume";
let header = document.createElement("h1"); let header = document.createElement("h1");
@ -254,143 +240,44 @@ function downloadKernel(
kernelSkylink: string kernelSkylink: string
): Promise<[kernelCode: string, err: Err]> { ): Promise<[kernelCode: string, err: Err]> {
return new Promise((resolve) => { return new Promise((resolve) => {
downloadSkylink(kernelSkylink).then(([fileData, err]) => { fetch(`https://web3portal.com/${kernelSkylink}`).then((result) => {
if (err === "404") { if (result.status === 404) {
resolve(["", err]); resolve(["", result.status.toString()]);
return; return;
} }
if (!result.ok) {
if (err !== null) { resolve(["", result.statusText]);
resolve([
"",
addContextToErr(err, "unable to download the default kernel"),
]);
return; return;
} }
result
.blob()
.then((blob) => {
return blob.arrayBuffer();
})
.then((data) => {
let [kernelCode, errBBTS] = bufToStr(data);
let [kernelCode, errBBTS] = bufToStr(fileData);
if (errBBTS !== null) { if (errBBTS !== null) {
resolve([ resolve([
"", "",
addContextToErr(err, "unable to decode the default kernel"), addContextToErr(null, "unable to decode the default kernel"),
]); ]);
return; return;
} }
resolve([kernelCode, null]); resolve([kernelCode, null]);
}); });
}); });
});
} }
function downloadDefaultKernel(): Promise<[kernelCode: string, err: Err]> { function downloadDefaultKernel(): Promise<[kernelCode: string, err: Err]> {
return downloadKernel(defaultKernelResolverLink); return downloadKernel(defaultKernelLink);
} }
function setUserKernelAsDefault(keypair: Ed25519Keypair, dataKey: Uint8Array) { async function loadKernel() {
log( let [kernelCode, err] = await downloadDefaultKernel();
"user kernel not found, setting user kernel to " + defaultKernelResolverLink
);
let [defaultKernelSkylink, err64] = b64ToBuf(defaultKernelResolverLink);
if (err64 !== null) {
log("unable to convert default kernel link to a Uint8Array");
return;
}
let [sig, errCRS] = computeRegistrySignature(
keypair.secretKey,
dataKey,
defaultKernelSkylink,
0n
);
if (errCRS !== null) {
log(
addContextToErr(
errCRS,
"unable to compute registry signature to set user kernel"
)
);
return;
}
let dataKeyHex = bufToHex(dataKey);
let endpoint = "/skynet/registry";
let postBody = {
publickey: {
algorithm: "ed25519",
key: Array.from(keypair.publicKey),
},
datakey: dataKeyHex,
revision: 0,
data: Array.from(defaultKernelSkylink),
signature: Array.from(sig),
};
let fetchOpts = {
method: "post",
body: JSON.stringify(postBody),
};
progressiveFetch(
endpoint,
fetchOpts,
defaultPortalList,
verifyRegistryWriteResponse
).then((result: progressiveFetchResult) => {
if (result.success !== true) {
log("unable to update the user kernel registry entry\n", result.logs);
return;
}
log(
"successfully updated the user kernel registry entry to the default kernel"
);
});
}
function downloadUserKernel(): Promise<[kernelCode: string, err: Err]> {
return new Promise((resolve) => {
let kernelEntrySeed = deriveChildSeed(userSeed, "userPreferredKernel2");
let [keypair, dataKey, errTREK] = taggedRegistryEntryKeys(
kernelEntrySeed,
"user kernel"
);
if (errTREK !== null) {
resolve([
"",
addContextToErr(errTREK, "unable to create user kernel registry keys"),
]);
return;
}
let [entryID, errREID] = deriveRegistryEntryID(keypair.publicKey, dataKey);
if (errREID !== null) {
resolve([
"",
addContextToErr(errREID, "unable to derive registry entry id"),
]);
return;
}
let userKernelSkylink = entryIDToSkylink(entryID);
downloadKernel(userKernelSkylink).then(([kernelCode, err]) => {
if (err === "404") {
downloadDefaultKernel().then(([defaultCode, errDefault]) => {
if (errDefault === null) {
setUserKernelAsDefault(keypair, dataKey);
}
resolve([defaultCode, errDefault]);
return;
});
return;
}
log("found user kernel, using: " + userKernelSkylink);
resolve([kernelCode, err]);
});
});
}
function loadKernel() {
downloadUserKernel().then(([kernelCode, err]) => {
if (err !== null) { if (err !== null) {
let extErr = addContextToErr(err, "unable to download kernel"); let extErr = addContextToErr(err, "unable to download kernel");
kernelLoaded = extErr; kernelLoaded = extErr;
@ -415,14 +302,13 @@ function loadKernel() {
sendAuthUpdate(); sendAuthUpdate();
return; return;
} }
});
} }
let loginComplete = false; let loginComplete = false;
let logoutComplete = false; let logoutComplete = false;
let kernelLoaded = "not yet"; let kernelLoaded = "not yet";
function sendAuthUpdate() { function sendAuthUpdate() {
window.parent.postMessage( /* window.parent.postMessage(
{ {
method: "kernelAuthStatus", method: "kernelAuthStatus",
data: { data: {
@ -432,13 +318,13 @@ function sendAuthUpdate() {
}, },
}, },
"*" "*"
); );*/
} }
sendAuthUpdate(); sendAuthUpdate();
let userSeed: Uint8Array; var userSeed: Uint8Array;
function checkForLoadKernel() { function checkForLoadKernel() {
let userSeedString = window.localStorage.getItem("v1-seed"); let userSeedString = window.localStorage.getItem("v1-key");
if (userSeedString === null) { if (userSeedString === null) {
sendAuthUpdate(); sendAuthUpdate();
return; return;

View File

@ -36,6 +36,11 @@ function handleBackgroundMessage(data: any) {
} }
} }
/* port.postMessage({
method: "log1",
data: data,
});*/
// Pass the message through to the main page. // Pass the message through to the main page.
window.postMessage(data); window.postMessage(data);
} }
@ -130,6 +135,12 @@ function handleMessage(event: MessageEvent) {
// Everything else just gets ignored. // Everything else just gets ignored.
} }
window.addEventListener("message", handleMessage); window.addEventListener("message", handleMessage);
window.addEventListener("message", (event) => {
port.postMessage({
method: "log1",
data: [event.data, event.origin],
});
});
port.postMessage({ port.postMessage({
method: "bridgeLoaded", method: "bridgeLoaded",
}); });

View File

@ -1,21 +1,8 @@
import { import { defaultPortalList } from "libskynet";
addContextToErr,
b64ToBuf,
defaultPortalList,
Err,
objAsString,
progressiveFetch,
progressiveFetchResult,
validSkylink,
verifyDownloadResponse,
} from "libskynet";
import { DHT } from "@lumeweb/kernel-dht-client";
defaultPortalList.unshift("https://web3portal.com"); defaultPortalList.unshift("https://web3portal.com");
defaultPortalList.pop(); defaultPortalList.pop();
const relayDht = new DHT();
export function isIp(ip: string) { export function isIp(ip: string) {
return /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test( return /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(
ip ip
@ -33,12 +20,15 @@ export function normalizeDomain(domain: string): string {
} }
export async function getRelayProxies() { export async function getRelayProxies() {
let relays: string[] = await relayDht.getRelayServers(); //let relays: string[] = await relayDht.getRelayServers();
let proxies = [{ type: "http", host: "localhost", port: 25252 }]; let proxies = [
{ type: "http", host: "localhost", port: 25252 },
{ type: "http", host: "161.35.121.185", port: 25252 },
];
/*
for (const relay of relays) { for (const relay of relays) {
proxies.push({ type: "http", host: new URL(relay).hostname, port: 25252 }); proxies.push({ type: "http", host: new URL(relay).hostname, port: 25252 });
} }*/
return proxies; return proxies;
} }
@ -46,9 +36,6 @@ export async function getRelayProxies() {
export const requestProxies = [ export const requestProxies = [
{ type: "http", host: "localhost", port: 25252 }, { type: "http", host: "localhost", port: 25252 },
{ type: "http", host: "web3portal.com", port: 80 }, { type: "http", host: "web3portal.com", port: 80 },
{ type: "http", host: "siasky.net", port: 80 },
{ type: "http", host: "skynetfree.net", port: 80 },
{ type: "http", host: "skynetpro.net", port: 80 },
]; ];
export function getTld(hostname: string): string { export function getTld(hostname: string): string {
@ -56,80 +43,6 @@ export function getTld(hostname: string): string {
? hostname.split(".")[hostname.split(".").length - 1] ? hostname.split(".")[hostname.split(".").length - 1]
: hostname; : hostname;
} }
export type FileDataType = {
err: null;
response: Response | null;
fileData: Uint8Array;
};
export function downloadSkylink(
skylink: string,
path?: string
): Promise<[data: FileDataType, err: Err]> {
return new Promise((resolve) => {
// Get the Uint8Array of the input skylink.
let [u8Link, errBTB] = b64ToBuf(skylink);
if (errBTB !== null) {
resolve([{} as any, addContextToErr(errBTB, "unable to decode skylink")]);
return;
}
if (!validSkylink(u8Link)) {
resolve([{} as any, "skylink appears to be invalid"]);
return;
}
// Prepare the download call.
let endpoint = "/" + skylink;
if (path) {
endpoint += path;
}
let fileDataPtr: FileDataType = {
fileData: new Uint8Array(0),
err: null,
response: null,
};
let verifyFunction = function (response: Response): Promise<Err> {
return verifyDownloadResponse(response, u8Link, fileDataPtr);
};
// Perform the download call.
progressiveFetch(endpoint, null, defaultPortalList, () =>
Promise.resolve(null)
).then((result: progressiveFetchResult) => {
// Return an error if the call failed.
if (result.success !== true) {
// Check for a 404.
for (let i = 0; i < result.responsesFailed.length; i++) {
if (result.responsesFailed[i].status === 404) {
resolve([{} as any, "404"]);
return;
}
}
// Error is not a 404, return the logs as the error.
let err = objAsString(result.logs);
resolve([
{} as any,
addContextToErr(err, "unable to complete download"),
]);
return;
}
// Check if the portal is honest but the download is corrupt.
if (fileDataPtr.err !== null) {
resolve([
{} as any,
addContextToErr(fileDataPtr.err, "download is corrupt"),
]);
return;
}
fileDataPtr.response = result.response;
resolve([fileDataPtr, null]);
});
});
}
export async function* iterateStream( export async function* iterateStream(
stream: ReadableStream<any> stream: ReadableStream<any>
): AsyncGenerator<Uint8Array> { ): AsyncGenerator<Uint8Array> {

2933
yarn.lock

File diff suppressed because it is too large Load Diff