pull/159/head
Zef Hemel 2022-12-05 12:14:21 +01:00
parent b24c2996be
commit e780a838b6
8 changed files with 38 additions and 41 deletions

View File

@ -82,7 +82,7 @@ silverbullet <pages-path>
By default, SB will bind to port `3000`, to use a different port use the By default, SB will bind to port `3000`, to use a different port use the
`--port` flag. By default SB doesnt offer any sort of authentication, to add `--port` flag. By default SB doesnt offer any sort of authentication, to add
basic password authentication, pass the `--password` flag. basic password authentication, pass the `--user` flag (e.g. `--user pete:1234`).
Once downloaded and booted, SB will print out a URL to open SB in your browser Once downloaded and booted, SB will print out a URL to open SB in your browser
(spoiler alert: by default this will be http://localhost:3000 ). (spoiler alert: by default this will be http://localhost:3000 ).

View File

@ -21,7 +21,7 @@ export function serveCommand(options: any, folder: string) {
pagesPath: pagesPath, pagesPath: pagesPath,
dbPath: path.join(pagesPath, options.db), dbPath: path.join(pagesPath, options.db),
assetBundle: new AssetBundle(assetBundle as AssetJson), assetBundle: new AssetBundle(assetBundle as AssetJson),
password: options.password, user: options.user,
}); });
httpServer.start().catch((e) => { httpServer.start().catch((e) => {
console.error("HTTP Server error", e); console.error("HTTP Server error", e);

View File

@ -10,22 +10,16 @@ import { mime } from "../../plugos/deps.ts";
export class HttpSpacePrimitives implements SpacePrimitives { export class HttpSpacePrimitives implements SpacePrimitives {
fsUrl: string; fsUrl: string;
private plugUrl: string; private plugUrl: string;
token?: string;
constructor(url: string, token?: string) { constructor(url: string) {
this.fsUrl = url + "/fs"; this.fsUrl = url + "/fs";
this.plugUrl = url + "/plug"; this.plugUrl = url + "/plug";
this.token = token;
} }
private async authenticatedFetch( private async authenticatedFetch(
url: string, url: string,
options: any, options: any,
): Promise<Response> { ): Promise<Response> {
if (this.token) {
options.headers = options.headers || {};
options.headers["Authorization"] = `Bearer ${this.token}`;
}
const result = await fetch(url, options); const result = await fetch(url, options);
if (result.status === 401) { if (result.status === 401) {
throw Error("Unauthorized"); throw Error("Unauthorized");

View File

@ -11,7 +11,8 @@ export type ServerOptions = {
pagesPath: string; pagesPath: string;
dbPath: string; dbPath: string;
assetBundle: AssetBundle; assetBundle: AssetBundle;
password?: string; user?: string;
pass?: string;
}; };
const staticLastModified = new Date().toUTCString(); const staticLastModified = new Date().toUTCString();
@ -20,14 +21,14 @@ export class HttpServer {
app: Application; app: Application;
systemBoot: SpaceSystem; systemBoot: SpaceSystem;
private port: number; private port: number;
password?: string; user?: string;
settings: { [key: string]: any } = {}; settings: { [key: string]: any } = {};
abortController?: AbortController; abortController?: AbortController;
constructor(options: ServerOptions) { constructor(options: ServerOptions) {
this.port = options.port; this.port = options.port;
this.app = new Application(); //{ serverConstructor: FlashServer }); this.app = new Application(); //{ serverConstructor: FlashServer });
this.password = options.password; this.user = options.user;
this.systemBoot = new SpaceSystem( this.systemBoot = new SpaceSystem(
options.assetBundle, options.assetBundle,
options.pagesPath, options.pagesPath,
@ -63,6 +64,7 @@ export class HttpServer {
await this.systemBoot.start(); await this.systemBoot.start();
await this.systemBoot.ensureSpaceIndex(); await this.systemBoot.ensureSpaceIndex();
await this.ensureAndLoadSettings(); await this.ensureAndLoadSettings();
// Serve static files (javascript, css, html) // Serve static files (javascript, css, html)
this.app.use(async ({ request, response }, next) => { this.app.use(async ({ request, response }, next) => {
if (request.url.pathname === "/") { if (request.url.pathname === "/") {
@ -106,6 +108,8 @@ export class HttpServer {
} }
}); });
this.addPasswordAuth(this.app);
// Pages API // Pages API
const fsRouter = this.buildFsRouter(this.systemBoot.spacePrimitives); const fsRouter = this.buildFsRouter(this.systemBoot.spacePrimitives);
this.app.use(fsRouter.routes()); this.app.use(fsRouter.routes());
@ -163,15 +167,20 @@ export class HttpServer {
} }
} }
private addPasswordAuth(r: Router) { private addPasswordAuth(app: Application) {
if (this.password) { if (this.user) {
r.use(async ({ request, response }, next) => { app.use(async ({ request, response }, next) => {
if ( if (
request.headers.get("Authorization") === `Bearer ${this.password}` request.headers.get("Authorization") ===
`Basic ${btoa(this.user!)}`
) { ) {
await next(); await next();
} else { } else {
response.status = 401; response.status = 401;
response.headers.set(
"WWW-Authenticate",
`Basic realm="Please enter your username and password"`,
);
response.body = "Unauthorized"; response.body = "Unauthorized";
} }
}); });
@ -180,7 +189,6 @@ export class HttpServer {
private buildFsRouter(spacePrimitives: SpacePrimitives): Router { private buildFsRouter(spacePrimitives: SpacePrimitives): Router {
const fsRouter = new Router(); const fsRouter = new Router();
this.addPasswordAuth(fsRouter);
// File list // File list
fsRouter.get("/", async ({ response }) => { fsRouter.get("/", async ({ response }) => {
response.headers.set("Content-type", "application/json"); response.headers.set("Content-type", "application/json");
@ -276,7 +284,7 @@ export class HttpServer {
private buildPlugRouter(): Router { private buildPlugRouter(): Router {
const plugRouter = new Router(); const plugRouter = new Router();
this.addPasswordAuth(plugRouter); // this.addPasswordAuth(plugRouter);
const system = this.systemBoot.system; const system = this.systemBoot.system;
plugRouter.post( plugRouter.post(

View File

@ -23,7 +23,10 @@ await new Command()
.option("--db <dbfile:string>", "Filename for the database", { .option("--db <dbfile:string>", "Filename for the database", {
default: "data.db", default: "data.db",
}) })
.option("--password <password:string>", "Password for basic authentication") .option(
"--user <user:string>",
"'username:password' combo for BasicAuth authentication",
)
.action(serveCommand) .action(serveCommand)
// fix // fix
.command("fix", "Fix a broken space") .command("fix", "Fix a broken space")

View File

@ -8,28 +8,14 @@ import { SilverBulletHooks } from "../common/manifest.ts";
import { System } from "../plugos/system.ts"; import { System } from "../plugos/system.ts";
safeRun(async () => { safeRun(async () => {
let password: string | undefined = localStorage.getItem("password") || const httpPrimitives = new HttpSpacePrimitives("");
undefined;
let httpPrimitives = new HttpSpacePrimitives("", password);
let settingsPageText = ""; let settingsPageText = "";
while (true) { try {
try { settingsPageText = (
settingsPageText = ( await httpPrimitives.readFile("SETTINGS.md", "string")
await httpPrimitives.readFile("SETTINGS.md", "string") ).data as string;
).data as string; } catch (e: any) {
break; console.error("No settings page found", e.message);
} catch (e: any) {
if (e.message === "Unauthorized") {
password = prompt("Password: ") || undefined;
if (!password) {
alert("Sorry, need a password");
return;
}
localStorage.setItem("password", password!);
httpPrimitives = new HttpSpacePrimitives("", password);
}
}
} }
// Instantiate a PlugOS system for the client // Instantiate a PlugOS system for the client

View File

@ -3,6 +3,12 @@ release.
--- ---
## Next
* Replaced the `--password` flag with `--user` taking a basic auth combination of username and password, e.g. `--user pete:1234`. Authentication now uses standard basic auth. This should fix attachments not working with password protected setups.
---
## 0.2.2 ## 0.2.2
* New page link aliasing syntax (Obsidian compatible) is here: `[[page link|alias]]` e.g. [[CHANGELOG|this is a link to this changelog]]. Also supported for command links: `{[Plugs: Add|add a plug]}` * New page link aliasing syntax (Obsidian compatible) is here: `[[page link|alias]]` e.g. [[CHANGELOG|this is a link to this changelog]]. Also supported for command links: `{[Plugs: Add|add a plug]}`

View File

@ -103,7 +103,7 @@ To run Silver Bullet, create a folder for your pages (it can be empty, or be an
silverbullet <pages-path> silverbullet <pages-path>
``` ```
By default, Silver Bullet will bind to port `3000`, to use a different port use the the `--port` flag. By default Silver Bullet is unauthenticated, to password-protect it, specify a password with the `--password` flag. By default, Silver Bullet will bind to port `3000`, to use a different port use the the `--port` flag. By default Silver Bullet is unauthenticated, to password-protect it, specify a username and password with the `--user` flag (e.g. `--user pete:1234`).
Once downloaded and booted, Silver Bullet will print out a URL to open SB in your browser (by default this will be http://localhost:3000 ). Once downloaded and booted, Silver Bullet will print out a URL to open SB in your browser (by default this will be http://localhost:3000 ).