feat: initial version

This commit is contained in:
Derrick Hammer 2023-07-20 15:43:41 -04:00
parent 7e418e22a5
commit 3e9e5eda97
Signed by: pcfreak30
GPG Key ID: C997C339BE476FF2
9 changed files with 20206 additions and 0 deletions

23
.presetterrc.json Normal file
View File

@ -0,0 +1,23 @@
{
"preset": [
"@lumeweb/presetter-kernel-module-preset"
],
"config": {
"official": true,
"vite": {
"build": {
"lib": {
"formats": {
"0": "umd"
}
}
}
}
},
"scripts": {
"build": "cross-env NODE_ENV=production run-s clean build:typescript:* build:vite build:html",
"build:vite": "vite build && shx mv lib/*.cjs lib/bootloader.js",
"build:html": "shx cp src/index.html lib/index.html"
}
}

19840
npm-shrinkwrap.json generated Normal file

File diff suppressed because it is too large Load Diff

23
package.json Normal file
View File

@ -0,0 +1,23 @@
{
"name": "@lumeweb/hosted-kernel",
"version": "0.1.0",
"type": "module",
"readme": "ERROR: No README data found!",
"_id": "@lumeweb/hosted-kernel@0.1.0",
"repository": {
"type": "git",
"url": "gitea@git.lumeweb.com:LumeWeb/libkernel.git"
},
"scripts": {
"prepare": "presetter bootstrap",
"build": "run build",
"semantic-release": "semantic-release"
},
"devDependencies": {
"@lumeweb/presetter-kernel-module-preset": "^0.1.0-develop.43"
},
"dependencies": {
"@lumeweb/libweb": "^0.2.0-develop.26",
"binconv": "^0.2.0"
}
}

13
src/index.html Normal file
View File

@ -0,0 +1,13 @@
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="text/javascript" src="./bootloader.js"></script>
</body>
</html>

9
src/index.ts Normal file
View File

@ -0,0 +1,9 @@
import { boot } from "./kernel.js";
document.title = "Hosted Lume Kernel";
let header = document.createElement("h1");
header.textContent =
"Something went wrong! You should not be visiting this page, this page should only be accessed via an invisible iframe.";
document.body.appendChild(header);
boot();

116
src/kernel.ts Normal file
View File

@ -0,0 +1,116 @@
import {
addContextToErr,
downloadObject,
Err,
maybeInitDefaultPortals,
setActivePortalMasterKey,
} from "@lumeweb/libweb";
import { log, logErr, sendAuthUpdate } from "./util.js";
import {
defaultKernelLink,
setKernelLoaded,
setLoginComplete,
} from "./vars.js";
import { getStoredUserKey } from "./storage.js";
import { readableStreamToBlob } from "binconv";
export function boot() {
let userKey;
try {
userKey = getStoredUserKey();
} catch (e) {
logErr(addContextToErr(e, "user key could not be fetched"));
sendAuthUpdate();
return;
}
if (!userKey) {
sendAuthUpdate();
return;
}
log("user is already logged in, attempting to load kernel");
setActivePortalMasterKey(userKey);
setLoginComplete(true);
sendAuthUpdate();
loadKernel();
}
export async function loadKernel() {
let [, portalLoadErr] = maybeInitDefaultPortals();
if (portalLoadErr) {
let err = addContextToErr(portalLoadErr, "unable to init portals");
setKernelLoaded(err);
logErr(err);
sendAuthUpdate();
return;
}
let [kernelCode, err] = await downloadDefaultKernel();
if (err !== null) {
let extErr = addContextToErr(err, "unable to download kernel");
setKernelLoaded(extErr);
logErr(extErr);
sendAuthUpdate();
return;
}
try {
await new Promise(async (resolve, reject) => {
const url = URL.createObjectURL(await readableStreamToBlob(kernelCode));
const el = document.createElement("script");
el.src = url;
el.onload = () => {
URL.revokeObjectURL(url);
resolve(null);
};
el.onerror = (
event: Event | string,
source?: string,
lineno?: number,
colno?: number,
error?: Error,
) => {
URL.revokeObjectURL(url);
reject(error);
};
document.head.appendChild(el);
});
setKernelLoaded("success");
sendAuthUpdate();
log("kernel successfully loaded");
return;
} catch (err: any) {
let extErr = addContextToErr(err, "unable to eval kernel");
setKernelLoaded(extErr);
logErr(extErr);
logErr(err.toString());
console.error(extErr);
console.error(err);
sendAuthUpdate();
return;
}
}
async function downloadKernel(
kernelCid: string,
): Promise<[kernelCode: ReadableStream, err: Err]> {
const [code, err] = await downloadObject(kernelCid);
if (err != null) {
return [null as any, err];
}
return [code, null];
}
function downloadDefaultKernel(): Promise<
[kernelCode: ReadableStream, err: Err]
> {
return downloadKernel(defaultKernelLink);
}

75
src/storage.ts Normal file
View File

@ -0,0 +1,75 @@
import {
addContextToErr,
bytesToHex,
hexToBytes,
setActivePortalMasterKey,
} from "@lumeweb/libweb";
import {
getLoginComplete,
getLogoutComplete,
setLoginComplete,
setLogoutComplete,
} from "./vars.js";
import { log, logErr, reloadKernel, sendAuthUpdate } from "./util.js";
import { loadKernel } from "./kernel.js";
function handleStorage(event: StorageEvent) {
if (event.key !== null && event.key !== "key") {
return;
}
if (getLogoutComplete()) {
reloadKernel();
return;
}
if (event.key === null && getLoginComplete()) {
return;
}
if (event.key === "key" && !getLoginComplete()) {
let userKey;
try {
userKey = getStoredUserKey();
} catch (e) {
logErr(addContextToErr(e, "user key could not be fetched"));
sendAuthUpdate();
return;
}
if (userKey === null) {
sendAuthUpdate();
return;
}
log("user is now logged in, attempting to load kernel");
setActivePortalMasterKey(userKey);
setLoginComplete(true);
loadKernel();
sendAuthUpdate();
return;
}
setLogoutComplete(true);
sendAuthUpdate();
log("attempting to do a page reload");
reloadKernel();
}
window.addEventListener("storage", handleStorage);
export function saveUserKey(key: Uint8Array) {
window.localStorage.setItem("key", bytesToHex(key));
const event = new StorageEvent("storage", {
key: "key",
});
window.dispatchEvent(event);
}
export function getStoredUserKey() {
const key = window.localStorage.getItem("key");
if (key) {
return hexToBytes(key);
}
return null;
}

53
src/util.ts Normal file
View File

@ -0,0 +1,53 @@
import {
getKernelLoaded,
getLoginComplete,
getLogoutComplete,
} from "./vars.js";
import { objAsString } from "@lumeweb/libweb";
export function sendAuthUpdate() {
window.parent.postMessage(
{
method: "kernelAuthStatus",
data: {
loginComplete: getLoginComplete(),
kernelLoaded: getKernelLoaded(),
logoutComplete: getLogoutComplete(),
},
},
"*",
);
}
function bootloaderWLog(isErr: boolean, ...inputs: any) {
// Build the message, each item gets its own line. We do this because items
// are often full objects.
let message = "[lumeweb-kernel-bootloader]";
for (let i = 0; i < inputs.length; i++) {
message += "\n";
message += objAsString(inputs[i]);
}
// Create the log by sending it to the parent.
window.parent.postMessage(
{
method: "log",
data: {
isErr,
message,
},
},
"*",
);
}
export function log(...inputs: any) {
bootloaderWLog(false, ...inputs);
}
export function logErr(...inputs: any) {
bootloaderWLog(true, ...inputs);
}
export function reloadKernel() {
window.location.reload();
}

54
src/vars.ts Normal file
View File

@ -0,0 +1,54 @@
import { x25519 } from "@noble/curves/ed25519";
export const defaultKernelLink =
"zduQ9EzFDZLM7z7RKbGex8duA29tHKk5gqriPvRRLcr1CUCvi6BYPoxHN7";
const store = new Map<string, any>(
Object.entries({
loginComplete: false,
logoutComplete: false,
kernelLoaded: "not yet",
communicationKey: null,
frontendCommunicationPubKey: null,
}),
);
export function setLoginComplete(status: boolean) {
store.set("loginComplete", status);
}
export function getLoginComplete(): boolean {
return store.get("loginComplete");
}
export function setLogoutComplete(status: boolean) {
store.set("logoutComplete", status);
}
export function getLogoutComplete(): boolean {
return store.get("logoutComplete");
}
export function setKernelLoaded(status: string) {
store.set("kernelLoaded", status);
}
export function getKernelLoaded(): string {
return store.get("kernelLoaded");
}
export function getCommunicationKey(): Uint8Array {
if (!store.get("communicationKey")) {
store.set("communicationKey", x25519.utils.randomPrivateKey());
}
return store.get("communicationKey");
}
export function getCommunicationPubKey() {
return x25519.getPublicKey(getCommunicationKey());
}
export function getFrontendCommunicationPubkey(): Uint8Array {
return store.get("frontendCommunicationPubKey");
}
export function setFrontendCommunicationPubkey(key: Uint8Array) {
store.set("frontendCommunicationPubKey", key);
}