diff --git a/deno.json b/deno.json index a70a678..1e8f796 100644 --- a/deno.json +++ b/deno.json @@ -12,7 +12,7 @@ "@std/encoding": "jsr:@std/encoding@^1.0.5", "nostr-tools": "jsr:@nostr/tools@^2.10.4", "@std/assert": "jsr:@std/assert@1", - "@arx/utils": "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/c1d309ba097ada64cd072ec1e3e97edaaf8773b6/src/index.ts", + "@arx/utils": "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/d5e91a356d48016753f526930d4a50863641e8ce/src/index.ts", "smtp-server": "npm:smtp-server@^3.13.6", "winston": "npm:winston@^3.17.0" } diff --git a/deno.lock b/deno.lock index 4154e3b..64921fe 100644 --- a/deno.lock +++ b/deno.lock @@ -714,7 +714,12 @@ "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/c1d309ba097ada64cd072ec1e3e97edaaf8773b6/src/email.ts": "ee77141a139894b10bbd0bc68338ebf1a6261a241b97732de547c791e6b0462c", "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/c1d309ba097ada64cd072ec1e3e97edaaf8773b6/src/general.ts": "692b4c44ec137cf7ef7128337f63a4a96ef8b09057beb7ec9940a6939a615bb4", "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/c1d309ba097ada64cd072ec1e3e97edaaf8773b6/src/index.ts": "fae9d057707d0632a2d82611e773a9627f199fc038cf823bfc4ecca0cfa0f064", - "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/c1d309ba097ada64cd072ec1e3e97edaaf8773b6/src/nostr.ts": "c72faf0cb4a76a746f141965d366926868b8cbc36bec1b559f921481402521c4" + "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/c1d309ba097ada64cd072ec1e3e97edaaf8773b6/src/nostr.ts": "c72faf0cb4a76a746f141965d366926868b8cbc36bec1b559f921481402521c4", + "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/d5e91a356d48016753f526930d4a50863641e8ce/src/cashu.ts": "1e759c2a0095be1702d34cf6bdbe2408447329a6189bb111d04573a5e1d15bff", + "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/d5e91a356d48016753f526930d4a50863641e8ce/src/email.ts": "ee77141a139894b10bbd0bc68338ebf1a6261a241b97732de547c791e6b0462c", + "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/d5e91a356d48016753f526930d4a50863641e8ce/src/general.ts": "692b4c44ec137cf7ef7128337f63a4a96ef8b09057beb7ec9940a6939a615bb4", + "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/d5e91a356d48016753f526930d4a50863641e8ce/src/index.ts": "fae9d057707d0632a2d82611e773a9627f199fc038cf823bfc4ecca0cfa0f064", + "https://git.arx-ccn.com/Arx/ts-utils/raw/commit/d5e91a356d48016753f526930d4a50863641e8ce/src/nostr.ts": "c72faf0cb4a76a746f141965d366926868b8cbc36bec1b559f921481402521c4" }, "workspace": { "dependencies": [ diff --git a/src/httpServer.ts b/src/httpServer.ts index 997b897..02eb5fd 100644 --- a/src/httpServer.ts +++ b/src/httpServer.ts @@ -9,6 +9,7 @@ import {npubToPubKeyString, pubKeyStringToNpub, TokenInfoWithMailSubscriptionDur const NPUB_REGEX = /^npub1[023456789acdefghjklmnpqrstuvwxyz]{58}$/; const CASHU_REGEX = /^cashu[A-Za-z0-9+-_]*={0,3}$/; +const ALIAS_REGEX = /^(?=.{4,32}$)[a-z][a-z0-9](?:[.\-_]?[a-z0-9]+)*$/; export class HttpServer { private app: Hono; @@ -23,6 +24,7 @@ export class HttpServer { .get("/aliases/:npub", this.getAliasesForNpub) .get("/alias/:alias", this.getNpubForAlias) .post("/addAlias", this.addAlias) + .delete("/alias/:alias", this.deleteAlias) .post("/addTime/:npub", this.addTimeToNpub); Deno.serve({ port }, this.app.fetch); @@ -95,11 +97,47 @@ export class HttpServer { } }; + deleteAlias = async (c: HonoContext) => { + const alias = c.req.param("alias"); + + const unpacked = await this.getUnpackedAuthHeader( + c.req.header("Authorization"), + `/alias/${alias}`, + "DELETE", + ); + const unpackedKeyToNpub = pubKeyStringToNpub(unpacked.pubkey); + + const user = await getUserByNpub(this.db, unpackedKeyToNpub); + if (!user) { + return c.json({ error: "Unauthorized" }, 401); + } + + if (!user.aliases.includes(alias)) { + return c.json({ error: "Not found" }, 404); + } + + await this.db.execute({ + sql: ` + DELETE FROM aliases + WHERE alias = $alias AND npub = $npub; + `, + args: { alias, npub: unpackedKeyToNpub }, + }); + + return c.json({ success: true }); + }; + addAlias = async (c: HonoContext) => { - const { alias } = await c.req.json<{ + let { alias } = await c.req.json<{ alias: string; }>(); + alias = alias.trim(); + + if (!ALIAS_REGEX.test(alias)) { + return c.json({ error: "Invalid alias format" }, 400); + } + try { const unpacked = await this.getUnpackedAuthHeader( c.req.header("Authorization"), @@ -223,6 +261,7 @@ export class HttpServer { private getUnpackedAuthHeader = async ( auth: string | undefined, url: string, + method: string = "POST", ) => { if (!auth) { throw new Error("Unauthorized"); @@ -231,7 +270,7 @@ export class HttpServer { const validate = await nip98.validateToken( authHeader, `${Deno.env.get("PUBLIC_API_BASE_URL")!}${url}`, - "POST", + method, ); if (!validate) { throw new Error("Unauthorized");