diff --git a/config.ts b/config.ts index edc6a9c..9056495 100644 --- a/config.ts +++ b/config.ts @@ -1,12 +1,28 @@ import { load } from "@std/dotenv"; +import { parse } from "jsr:@std/yaml"; +import { log } from "./log.ts"; const dirname = new URL(".", import.meta.url).pathname; await load({ envPath: `${dirname}/.env`, export: true }); +let staticUsers; + +try { + const yamlContent = await Deno.readTextFile(`${dirname}/users.yaml`); + staticUsers = parse(yamlContent); + log("Static user config:", "blue"); + log(Deno.inspect(staticUsers), "blue"); +} catch { + staticUsers = {}; + log(`Could not find or parse a "users.yaml" config`, "yellow"); +} + const config = { port: Deno.env.get("PORT") || 8000, base_url: Deno.env.get("BASE_URL") || `http://localhost:8000`, home_relay_url: Deno.env.get("HOME_RELAY_URL") || "", + staticUsers: staticUsers, + ldapEnabled: !!Deno.env.get("LDAP_URL"), ldap: { url: Deno.env.get("LDAP_URL"), bindDN: Deno.env.get("LDAP_BIND_DN"), @@ -15,4 +31,6 @@ const config = { }, }; +log(`LDAP enabled: ${config.ldapEnabled}`, "blue"); + export default config; diff --git a/deno.json b/deno.json index 2be313f..2100288 100644 --- a/deno.json +++ b/deno.json @@ -10,6 +10,7 @@ "@std/dotenv": "jsr:@std/dotenv@^0.225.2", "@std/expect": "jsr:@std/expect@^1.0.5", "@std/testing": "jsr:@std/testing@^1.0.3", + "@std/yaml": "jsr:@std/yaml@^1.0.5", "ldapts": "npm:ldapts@^7.2.1" } } diff --git a/deno.lock b/deno.lock index 0bfb5b2..811b690 100644 --- a/deno.lock +++ b/deno.lock @@ -27,6 +27,8 @@ "jsr:@std/path@1": "1.0.6", "jsr:@std/path@^1.0.6": "1.0.6", "jsr:@std/testing@^1.0.3": "1.0.3", + "jsr:@std/yaml@*": "1.0.5", + "jsr:@std/yaml@^1.0.5": "1.0.5", "npm:@noble/ciphers@~0.5.1": "0.5.3", "npm:@noble/curves@1.2.0": "1.2.0", "npm:@noble/hashes@1.3.1": "1.3.1", @@ -186,6 +188,9 @@ "jsr:@std/internal", "jsr:@std/path@^1.0.6" ] + }, + "@std/yaml@1.0.5": { + "integrity": "71ba3d334305ee2149391931508b2c293a8490f94a337eef3a09cade1a2a2742" } }, "npm": { @@ -490,6 +495,7 @@ "jsr:@std/dotenv@~0.225.2", "jsr:@std/expect@^1.0.5", "jsr:@std/testing@^1.0.3", + "jsr:@std/yaml@^1.0.5", "npm:ldapts@^7.2.1" ] } diff --git a/directory.ts b/directory.ts new file mode 100644 index 0000000..c133f6c --- /dev/null +++ b/directory.ts @@ -0,0 +1,33 @@ +import config from "./config.ts"; +import { lookupUsernameByPubkey as ldapLookupUsername } from "./ldap.ts"; +import { lookupPubkeyByUsername as ldapLookupPubkey } from "./ldap.ts"; + +export function lookupUsernameByPubkey(pubkey: string) { + let username; + for (const [key, value] of Object.entries(config.staticUsers)) { + if (value === pubkey) { + username = key; + break; + } + } + + if (username) { + return username; + } else { + if (config.ldapEnabled) { + return ldapLookupUsername(pubkey); + } + } +} + +export function lookupPubkeyByUsername(username: string) { + const pubkey = config.staticUsers[username]; + + if (pubkey) { + return pubkey; + } else { + if (config.ldapEnabled) { + return ldapLookupPubkey(username); + } + } +} diff --git a/handlers/naddr.ts b/handlers/naddr.ts index 3295702..babed74 100644 --- a/handlers/naddr.ts +++ b/handlers/naddr.ts @@ -1,7 +1,7 @@ import { Context } from "@oak/oak"; import { nip19 } from "@nostr/tools"; import { log } from "../log.ts"; -import { lookupUsernameByPubkey } from "../ldap.ts"; +import { lookupUsernameByPubkey } from "../directory.ts"; import notFoundHandler from "../handlers/not-found.ts"; const naddrHandler = async function (ctx: Context) { diff --git a/handlers/nprofile.ts b/handlers/nprofile.ts index 250ce21..aefba0d 100644 --- a/handlers/nprofile.ts +++ b/handlers/nprofile.ts @@ -1,7 +1,7 @@ import { Context } from "@oak/oak"; import { nip19 } from "@nostr/tools"; import { log } from "../log.ts"; -import { lookupUsernameByPubkey } from "../ldap.ts"; +import { lookupUsernameByPubkey } from "../directory.ts"; import notFoundHandler from "../handlers/not-found.ts"; const nprofileHandler = async function (ctx: Context) { diff --git a/handlers/npub.ts b/handlers/npub.ts index 48ce9d7..ecbb354 100644 --- a/handlers/npub.ts +++ b/handlers/npub.ts @@ -1,7 +1,7 @@ import { Context } from "@oak/oak"; import { nip19 } from "@nostr/tools"; import { log } from "../log.ts"; -import { lookupUsernameByPubkey } from "../ldap.ts"; +import { lookupUsernameByPubkey } from "../directory.ts"; import notFoundHandler from "../handlers/not-found.ts"; const npubHandler = async function (ctx: Context) { diff --git a/handlers/user-atom-feed.ts b/handlers/user-atom-feed.ts index c1e317a..efc6a81 100644 --- a/handlers/user-atom-feed.ts +++ b/handlers/user-atom-feed.ts @@ -1,6 +1,6 @@ import { Context } from "@oak/oak"; import { log } from "../log.ts"; -import { lookupPubkeyByUsername } from "../ldap.ts"; +import { lookupPubkeyByUsername } from "../directory.ts"; import { fetchArticlesByAuthor, fetchProfileEvent } from "../nostr.ts"; import { profileAtomFeed } from "../feeds.ts"; import Article from "../models/article.ts"; diff --git a/handlers/user-event.ts b/handlers/user-event.ts index 4c37314..469861c 100644 --- a/handlers/user-event.ts +++ b/handlers/user-event.ts @@ -1,6 +1,6 @@ import { Context } from "@oak/oak"; import { log } from "../log.ts"; -import { lookupPubkeyByUsername } from "../ldap.ts"; +import { lookupPubkeyByUsername } from "../directory.ts"; import { fetchProfileEvent, fetchReplaceableEvent } from "../nostr.ts"; import Article from "../models/article.ts"; import Profile from "../models/profile.ts"; diff --git a/handlers/user-profile.ts b/handlers/user-profile.ts index 92a436f..17b77e5 100644 --- a/handlers/user-profile.ts +++ b/handlers/user-profile.ts @@ -1,6 +1,6 @@ import { Context } from "@oak/oak"; import { log } from "../log.ts"; -import { lookupPubkeyByUsername } from "../ldap.ts"; +import { lookupPubkeyByUsername } from "../directory.ts"; import { fetchArticlesByAuthor, fetchProfileEvent } from "../nostr.ts"; import Article from "../models/article.ts"; import Profile from "../models/profile.ts"; @@ -27,6 +27,7 @@ const userProfileHandler = async function (ctx: Context) { ctx.response.body = html; } else { + log(`No profile event found for @${username}`, "yellow"); notFoundHandler(ctx); } } catch (e) { diff --git a/ldap.ts b/ldap.ts index 8f59bd9..1a74a67 100644 --- a/ldap.ts +++ b/ldap.ts @@ -2,8 +2,12 @@ import { Client } from "ldapts"; import { log } from "./log.ts"; import config from "./config.ts"; -const { ldap } = config; -const client = new Client({ url: ldap.url }); +const { ldap, ldapEnabled } = config; + +let client; +if (ldapEnabled) { + client = new Client({ url: ldap.url }); +} export async function lookupPubkeyByUsername(username: string) { let pubkey; diff --git a/models/profile.ts b/models/profile.ts index 3345b37..c657af7 100644 --- a/models/profile.ts +++ b/models/profile.ts @@ -25,7 +25,8 @@ export default class Profile { } get name(): string { - return this.data.name || "Anonymous"; + return this.data.display_name || this.data.displayName || + this.data.name || "Anonymous"; } get about(): string { diff --git a/users.yaml b/users.yaml new file mode 100644 index 0000000..4f493d8 --- /dev/null +++ b/users.yaml @@ -0,0 +1,2 @@ +_: b3e1b7c0ef48294bd856203bfd460625de95d3afb894e5f09b14cd1f0e7097cf +accounts: b3e1b7c1660b7db0ecb93ec55c09e67961171a5c4e9e2602f1b47477ea61c50a