From 8d61812d0ec2666d01f92254d507c4142b43864c Mon Sep 17 00:00:00 2001 From: Zef Hemel Date: Mon, 11 Jul 2022 13:14:31 +0200 Subject: [PATCH] Cleanup of unused code, moving mounts to plug --- packages/plugs/core/core.plug.yaml | 27 --- packages/plugs/core/mount.ts | 296 ----------------------------- packages/server/auth.test.ts | 29 --- packages/server/auth.ts | 71 ------- packages/server/express_server.ts | 3 - packages/server/package.json | 4 +- 6 files changed, 1 insertion(+), 429 deletions(-) delete mode 100644 packages/plugs/core/mount.ts delete mode 100644 packages/server/auth.test.ts delete mode 100644 packages/server/auth.ts diff --git a/packages/plugs/core/core.plug.yaml b/packages/plugs/core/core.plug.yaml index 6aefa2f..fb00104 100644 --- a/packages/plugs/core/core.plug.yaml +++ b/packages/plugs/core/core.plug.yaml @@ -280,30 +280,3 @@ functions: name: "UI: Hide BHS" key: "Ctrl-Alt-b" mac: "Cmd-Alt-b" - - # Mounting - readPageMounted: - path: ./mount.ts:readPageMounted - pageNamespace: - pattern: "^🚪 .+" - operation: readPage - writePageMounted: - path: ./mount.ts:writePageMounted - pageNamespace: - pattern: "^🚪 .+" - operation: writePage - deletePageMounted: - path: ./mount.ts:deletePageMounted - pageNamespace: - pattern: "^🚪 .+" - operation: deletePage - getPageMetaMounted: - path: ./mount.ts:getPageMetaMounted - pageNamespace: - pattern: "^🚪 .+" - operation: getPageMeta - listPagesMounted: - path: ./mount.ts:listPagesMounted - pageNamespace: - pattern: "^🚪 .+" - operation: listPages diff --git a/packages/plugs/core/mount.ts b/packages/plugs/core/mount.ts deleted file mode 100644 index 04b74a8..0000000 --- a/packages/plugs/core/mount.ts +++ /dev/null @@ -1,296 +0,0 @@ -import { PageMeta } from "@silverbulletmd/common/types"; -import { - deleteFile, - getFileMeta, - listFiles, - readFile, - writeFile, -} from "@plugos/plugos-syscall/fs"; -import { parseMarkdown } from "@silverbulletmd/plugos-silverbullet-syscall/markdown"; -import { - findNodeOfType, - renderToText, - replaceNodesMatching, -} from "@silverbulletmd/common/tree"; -import { readPage } from "@silverbulletmd/plugos-silverbullet-syscall/space"; -import YAML from "yaml"; - -const globalMountPrefix = "🚪 "; - -type MountPoint = { - prefix: string; - path: string; - password?: string; - protocol: "file" | "http"; - perm: "rw" | "ro"; -}; - -let mountPointCache: MountPoint[] = []; - -async function updateMountPoints() { - let mountPointsText = ""; - try { - let { text } = await readPage("MOUNTS"); - mountPointsText = text; - } catch { - // No MOUNTS file, so that's all folks! - mountPointCache = []; - return; - } - - let tree = await parseMarkdown(mountPointsText); - - let codeTextNode = findNodeOfType(tree, "CodeText"); - if (!codeTextNode) { - console.error("Could not find yaml block in MOUNTS"); - return; - } - let mountsYaml = codeTextNode.children![0].text; - let mountList: Partial[] = YAML.parse(mountsYaml!); - if (!Array.isArray(mountList)) { - console.error("Invalid MOUNTS file, should have array of mount points"); - return; - } - // Let's validate this and fill in some of the blanks - for (let mountPoint of mountList) { - if (!mountPoint.prefix) { - console.error("Invalid mount point, no prefix specified", mountPoint); - return; - } - if (!mountPoint.path) { - console.error("Invalid mount point, no path specified", mountPoint); - return; - } - if (!mountPoint.perm) { - mountPoint.perm = "rw"; - } - if (mountPoint.path.startsWith("file:")) { - mountPoint.protocol = "file"; - mountPoint.path = mountPoint.path.substring("file:".length); - } else { - mountPoint.protocol = "http"; - mountPoint.path += "/fs"; // Add the /fs suffix to the path - } - } - - mountPointCache = mountList as MountPoint[]; -} - -async function translateLinksWithPrefix( - text: string, - prefix: string -): Promise { - prefix = `${globalMountPrefix}${prefix}`; - let tree = await parseMarkdown(text); - replaceNodesMatching(tree, (tree) => { - if (tree.type === "WikiLinkPage") { - // Add the prefix in the link text - tree.children![0].text = prefix + tree.children![0].text; - } - return undefined; - }); - text = renderToText(tree); - return text; -} - -async function translateLinksWithoutPrefix(text: string, prefix: string) { - prefix = `${globalMountPrefix}${prefix}`; - let tree = await parseMarkdown(text); - replaceNodesMatching(tree, (tree) => { - if (tree.type === "WikiLinkPage") { - // Remove the prefix in the link text - let text = tree.children![0].text!; - if (text.startsWith(prefix)) { - tree.children![0].text = text.substring(prefix.length); - } - } - return undefined; - }); - return renderToText(tree); -} - -function lookupMountPoint(fullPath: string): { - resolvedPath: string; - mountPoint: MountPoint; -} { - fullPath = fullPath.substring(globalMountPrefix.length); - for (let mp of mountPointCache) { - if (fullPath.startsWith(mp.prefix)) { - return { - resolvedPath: `${mp.path}/${fullPath.substring(mp.prefix.length)}`, - mountPoint: mp, - }; - } - } - throw new Error("No mount point found for " + fullPath); -} - -export async function readPageMounted( - name: string -): Promise<{ text: string; meta: PageMeta }> { - await updateMountPoints(); - let { resolvedPath, mountPoint } = lookupMountPoint(name); - if (mountPoint.protocol === "file") { - let { text, meta } = await readFile(`${resolvedPath}.md`); - return { - text: await translateLinksWithPrefix(text, mountPoint.prefix), - meta: { - name: name, - lastModified: meta.lastModified, - perm: mountPoint.perm, - }, - }; - } else { - let res = await fetch(resolvedPath, { - method: "GET", - headers: authHeaders(mountPoint), - }); - if (res.status !== 200) { - throw new Error( - `Failed to read page: ${res.status}: ${await res.text()}` - ); - } - if (res.headers.get("X-Status") === "404") { - throw new Error(`Page not found`); - } - let text = await res.text(); - return { - text: await translateLinksWithPrefix(text, mountPoint.prefix), - meta: { - name: name, - lastModified: +(res.headers.get("Last-Modified") || "0"), - perm: (res.headers.get("X-Permission") as "rw" | "ro") || "rw", - }, - }; - } -} - -export async function writePageMounted( - name: string, - text: string -): Promise { - await updateMountPoints(); - let { resolvedPath, mountPoint } = lookupMountPoint(name); - text = await translateLinksWithoutPrefix(text, mountPoint.prefix); - if (mountPoint.protocol === "file") { - let meta = await writeFile(`${resolvedPath}.md`, text); - return { - name: name, - lastModified: meta.lastModified, - perm: mountPoint.perm, - }; - } else { - let res = await fetch(resolvedPath, { - method: "PUT", - headers: authHeaders(mountPoint), - body: text, - }); - if (res.status !== 200) { - throw new Error( - `Failed to write page: ${res.status}: ${await res.text()}` - ); - } - return { - name: name, - lastModified: +(res.headers.get("Last-Modified") || "0"), - perm: (res.headers.get("X-Permission") as "rw" | "ro") || "rw", - }; - } -} - -export async function deletePageMounted(name: string): Promise { - await updateMountPoints(); - let { resolvedPath, mountPoint } = lookupMountPoint(name); - if (mountPoint.protocol === "file") { - if (mountPoint.perm === "rw") { - await deleteFile(`${resolvedPath}.md`); - } else { - throw new Error("Deleting read-only page"); - } - } else { - throw new Error("Not yet implemented"); - } -} - -function authHeaders(mountPoint: MountPoint): HeadersInit { - return { - Authorization: mountPoint.password ? `Bearer ${mountPoint.password}` : "", - }; -} - -export async function getPageMetaMounted(name: string): Promise { - await updateMountPoints(); - let { resolvedPath, mountPoint } = lookupMountPoint(name); - if (mountPoint.protocol === "file") { - let meta = await getFileMeta(`${resolvedPath}.md`); - return { - name, - lastModified: meta.lastModified, - perm: mountPoint.perm, - }; - } else { - // http/https - let res = await fetch(resolvedPath, { - method: "OPTIONS", - headers: authHeaders(mountPoint), - }); - if (res.status !== 200) { - throw new Error( - `Failed to list pages: ${res.status}: ${await res.text()}` - ); - } - if (res.headers.get("X-Status") === "404") { - throw new Error(`Page not found`); - } - return { - name: name, - lastModified: +(res.headers.get("Last-Modified") || "0"), - perm: (res.headers.get("X-Permission") as "rw" | "ro") || "rw", - }; - } -} - -export async function listPagesMounted(): Promise { - await updateMountPoints(); - let allPages: PageMeta[] = []; - for (let mp of mountPointCache) { - if (mp.protocol === "file") { - let files = await listFiles(mp.path, true); - for (let file of files) { - if (!file.name.endsWith(".md")) { - continue; - } - allPages.push({ - name: `${globalMountPrefix}${mp.prefix}${file.name.substring( - 0, - file.name.length - 3 - )}`, - lastModified: file.lastModified, - perm: mp.perm, - }); - } - } else { - let res = await fetch(mp.path, { - headers: authHeaders(mp), - }); - if (res.status !== 200) { - throw new Error( - `Failed to list pages: ${res.status}: ${await res.text()}` - ); - } - let remotePages: PageMeta[] = await res.json(); - // console.log("Remote pages", remotePages); - for (let pageMeta of remotePages) { - if (pageMeta.name.startsWith("_")) { - continue; - } - allPages.push({ - name: `${globalMountPrefix}${mp.prefix}${pageMeta.name}`, - lastModified: pageMeta.lastModified, - perm: mp.perm, - }); - } - } - } - return allPages; -} diff --git a/packages/server/auth.test.ts b/packages/server/auth.test.ts deleted file mode 100644 index 7855aaa..0000000 --- a/packages/server/auth.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { beforeEach, afterEach, expect, test } from "@jest/globals"; -import { unlink } from "fs/promises"; -import knex, { Knex } from "knex"; -import { Authenticator } from "./auth"; - -let db: Knex | undefined; - -beforeEach(async () => { - db = knex({ - client: "better-sqlite3", - connection: { - filename: "auth-test.db", - }, - useNullAsDefault: true, - }); -}); - -afterEach(async () => { - db!.destroy(); - await unlink("auth-test.db"); -}); - -test("Test auth", async () => { - let auth = new Authenticator(db!); - await auth.ensureTables(); - await auth.createAccount("admin", "admin"); - expect(await auth.verify("admin", "admin")).toBe(true); - expect(await auth.verify("admin", "sup")).toBe(false); -}); diff --git a/packages/server/auth.ts b/packages/server/auth.ts deleted file mode 100644 index 4099748..0000000 --- a/packages/server/auth.ts +++ /dev/null @@ -1,71 +0,0 @@ -import * as crypto from "crypto"; -import { Knex } from "knex"; -import { promisify } from "util"; -const pbkdf2 = promisify(crypto.pbkdf2); - -type Account = { - username: string; - hashed_password: any; - salt: any; -}; - -export class Authenticator { - tableName = "tokens"; - - constructor(private db: Knex) {} - - middleware(req: any, res: any, next: any) { - console.log("GOing through here", req.headers.authorization); - // if (req.headers) - next(); - } - - async ensureTables() { - if (!(await this.db.schema.hasTable(this.tableName))) { - await this.db.schema.createTable(this.tableName, (table) => { - table.string("username"); - table.binary("hashed_password"); - table.binary("salt"); - table.primary(["username"]); - }); - // await this.createAccount("admin", "admin"); - console.log(`Created table ${this.tableName}`); - } - } - - async createAccount(username: string, password: string) { - var salt = crypto.randomBytes(16); - let encryptedPassword = await pbkdf2(password, salt, 310000, 32, "sha256"); - await this.db(this.tableName).insert({ - username, - hashed_password: encryptedPassword, - salt, - }); - } - - async updatePassword(username: string, password: string) { - var salt = crypto.randomBytes(16); - let encryptedPassword = await pbkdf2(password, salt, 310000, 32, "sha256"); - await this.db(this.tableName).update({ - username, - hashed_password: encryptedPassword, - salt, - }); - } - - async verify(username: string, password: string): Promise { - let users = await this.db(this.tableName).where({ username }); - if (users.length === 0) { - throw new Error(`No such user: ${username}`); - } - let user = users[0]; - let encryptedPassword = await pbkdf2( - password, - user.salt, - 310000, - 32, - "sha256" - ); - return crypto.timingSafeEqual(user.hashed_password, encryptedPassword); - } -} diff --git a/packages/server/express_server.ts b/packages/server/express_server.ts index 9327c49..ba8f387 100644 --- a/packages/server/express_server.ts +++ b/packages/server/express_server.ts @@ -29,7 +29,6 @@ import { esbuildSyscalls } from "@plugos/plugos/syscalls/esbuild"; import { systemSyscalls } from "./syscalls/system"; import { plugPrefix } from "@silverbulletmd/common/spaces/constants"; -import { Authenticator } from "./auth"; import sandboxSyscalls from "@plugos/plugos/syscalls/sandbox"; // import globalModules from "../common/dist/global.plug.json"; @@ -265,8 +264,6 @@ export class ExpressServer { await ensureFTSTable(this.db, "fts"); await this.ensureIndexPage(); - let auth = new Authenticator(this.db); - // Serve static files (javascript, css, html) this.app.use("/", express.static(this.distDir)); diff --git a/packages/server/package.json b/packages/server/package.json index b379dfb..9aa64fd 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -27,9 +27,7 @@ ] }, "test": { - "source": [ - "auth.test.ts" - ], + "source": [], "outputFormat": "commonjs", "isLibrary": true, "context": "node"