From b0767c51d51e006094f7ee345fffa623bb3e8699 Mon Sep 17 00:00:00 2001 From: Bob Date: Thu, 25 Apr 2024 17:35:11 +0800 Subject: [PATCH 01/24] feat: add NIP-07 extension login --- main.tsx | 69 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/main.tsx b/main.tsx index 5b00ba9..69c90a6 100644 --- a/main.tsx +++ b/main.tsx @@ -154,6 +154,12 @@ async (req: Request, info: Deno.ServeHandlerInfo) => { console.log(info.remoteAddr); const { pathname, protocol } = new URL(req.url); + if (pathname === "/api/auth/login") { + const auth = req.headers.get("authorization"); + const resp = new Response("ok"); + resp.headers.set("set-cookie", `token=${auth}; Path=/; Secure; HttpOnly; SameSite=Strict;`); + return resp; + } if (pathname == "/api") { return graphql_handler(args)(req); } @@ -182,20 +188,33 @@ const graphql_handler = ( }, ) => async (req: Request) => { - const { password, policyStore } = args; + const { password, policyStore, relayInformationStore } = args; if (req.method == "POST") { const query = await req.json(); - const pw = req.headers.get("password"); - if (pw != password) { - return new Response(`{"errors":"incorrect password"}`); + const cookie = req.headers.get("cookie"); + const token = cookie?.split(";").find((c) => c.includes("token"))?.split("=")[1].split(" ")[1]; + const event = token ? JSON.parse(atob(token)) : undefined; + if (event) { + const pubkey = await relayInformationStore.resolveRelayInformation().then((info) => info.pubkey); + if (!pubkey) { + return new Response(`{"errors":"relay pubkey not set"}`); + } + const relayPubkey = PublicKey.FromString(pubkey); + if (relayPubkey instanceof Error) { + return new Response(`{"errors":"relay pubkey not valid"}`); + } + if (event.pubkey != relayPubkey.hex) { + return new Response(`{"errors":"you are not admin"}`); + } + const result = await gql.graphql({ + schema: schema, + source: query.query, + variableValues: query.variables, + rootValue: RootResolver(args), + }); + return new Response(JSON.stringify(result)); } - const result = await gql.graphql({ - schema: schema, - source: query.query, - variableValues: query.variables, - rootValue: RootResolver(args), - }); - return new Response(JSON.stringify(result)); + return new Response(`{"errors":"invalid token"}`); } else if (req.method == "GET") { const res = new Response(graphiql); res.headers.set("content-type", "html"); @@ -293,6 +312,7 @@ const graphiql = ` +
Loading...
`; From 44420c87c94de9e1bce1a5416b12584a7a70d3f0 Mon Sep 17 00:00:00 2001 From: Bob Date: Thu, 25 Apr 2024 18:56:45 +0800 Subject: [PATCH 02/24] verify Event --- main.tsx | 60 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/main.tsx b/main.tsx index 69c90a6..0fc76e4 100644 --- a/main.tsx +++ b/main.tsx @@ -5,7 +5,7 @@ import { RootResolver } from "./resolvers/root.ts"; import * as gql from "https://esm.sh/graphql@16.8.1"; import { Policy } from "./resolvers/policy.ts"; import { func_ResolvePolicyByKind } from "./resolvers/policy.ts"; -import { NostrKind, PublicKey } from "./_libs.ts"; +import { NostrKind, PublicKey, verifyEvent } from "./_libs.ts"; import { PolicyStore } from "./resolvers/policy.ts"; import { Policies } from "./resolvers/policy.ts"; import { @@ -188,33 +188,43 @@ const graphql_handler = ( }, ) => async (req: Request) => { - const { password, policyStore, relayInformationStore } = args; + const { relayInformationStore } = args; if (req.method == "POST") { - const query = await req.json(); - const cookie = req.headers.get("cookie"); - const token = cookie?.split(";").find((c) => c.includes("token"))?.split("=")[1].split(" ")[1]; - const event = token ? JSON.parse(atob(token)) : undefined; - if (event) { - const pubkey = await relayInformationStore.resolveRelayInformation().then((info) => info.pubkey); - if (!pubkey) { - return new Response(`{"errors":"relay pubkey not set"}`); - } - const relayPubkey = PublicKey.FromString(pubkey); - if (relayPubkey instanceof Error) { - return new Response(`{"errors":"relay pubkey not valid"}`); - } - if (event.pubkey != relayPubkey.hex) { - return new Response(`{"errors":"you are not admin"}`); + try { + const query = await req.json(); + const cookie = req.headers.get("cookie"); + const token = cookie?.split(";").find((c) => c.includes("token"))?.split("=")[1].split(" ")[1]; + const event = token ? JSON.parse(atob(token)) : undefined; + if (event) { + const verifyResult = await verifyEvent(event); + if (!verifyResult) { + return new Response(`{"errors":"token not verified"}`); + } + const pubkey = await relayInformationStore.resolveRelayInformation().then((info) => + info.pubkey + ); + if (!pubkey) { + return new Response(`{"errors":"relay pubkey not set"}`); + } + const relayPubkey = PublicKey.FromString(pubkey); + if (relayPubkey instanceof Error) { + return new Response(`{"errors":"relay pubkey not valid"}`); + } + if (event.pubkey != relayPubkey.hex) { + return new Response(`{"errors":"you are not admin"}`); + } + const result = await gql.graphql({ + schema: schema, + source: query.query, + variableValues: query.variables, + rootValue: RootResolver(args), + }); + return new Response(JSON.stringify(result)); } - const result = await gql.graphql({ - schema: schema, - source: query.query, - variableValues: query.variables, - rootValue: RootResolver(args), - }); - return new Response(JSON.stringify(result)); + return new Response(`{"errors":"please login first"}`); + } catch (error) { + return new Response(`{"errors":"${error}"}`); } - return new Response(`{"errors":"invalid token"}`); } else if (req.method == "GET") { const res = new Response(graphiql); res.headers.set("content-type", "html"); From c70db5ac6527604149cf24df3a283c613b81fc93 Mon Sep 17 00:00:00 2001 From: Bob Date: Fri, 26 Apr 2024 16:13:51 +0800 Subject: [PATCH 03/24] feat: support password and pubkey for auth --- deploy/example.ts | 2 +- main.tsx | 82 ++++++++++++++++++++++++++++++----------------- test.ts | 3 +- 3 files changed, 55 insertions(+), 32 deletions(-) diff --git a/deploy/example.ts b/deploy/example.ts index d1223ea..d55371f 100644 --- a/deploy/example.ts +++ b/deploy/example.ts @@ -9,7 +9,7 @@ const relay = await run({ default_information: { name: "Relayed Example", description: "A lightweight relay written in Deno.", - pubkey: "", + pubkey: Deno.env.get("relayed_pubkey"), contact: "", icon: "", }, diff --git a/main.tsx b/main.tsx index 0fc76e4..a6641d4 100644 --- a/main.tsx +++ b/main.tsx @@ -34,7 +34,7 @@ export type DefaultPolicy = { export type Relay = { server: Deno.HttpServer; url: string; - password: string; + password?: string; shutdown: () => Promise; set_policy: (args: { kind: NostrKind; @@ -57,13 +57,6 @@ export async function run(args: { kv?: Deno.Kv; }): Promise { const connections = new Map(); - let { password } = args; - if (password == undefined) { - password = Deno.env.get("relayed_pw"); - if (!password) { - return new Error("password is not set, please set env var $relayed_pw"); - } - } if (args.kv == undefined) { args.kv = await Deno.openKv(); } @@ -82,6 +75,22 @@ export async function run(args: { default_information, ); + let { password } = args; + if (!password) { + const { pubkey } = await relayInformationStore.resolveRelayInformation(); + if (!pubkey) { + const env_pubkey = Deno.env.get("relayed_pubkey"); + if (!env_pubkey) { + password = Deno.env.get("relayed_pw"); + if (!password) { + return new Error( + "password or pubkey is not set, please set env var $relayed_pw or $relayed_pubkey", + ); + } + } + } + } + const eventStore = await EventStore.New(args.kv); const server = Deno.serve( @@ -140,7 +149,7 @@ export type EventReadWriter = { const root_handler = ( args: { - password: string; + password?: string; information?: RelayInformation; connections: Map; default_policy: DefaultPolicy; @@ -181,7 +190,7 @@ async (req: Request, info: Deno.ServeHandlerInfo) => { const graphql_handler = ( args: { - password: string; + password?: string; kv: Deno.Kv; policyStore: PolicyStore; relayInformationStore: RelayInformationStore; @@ -192,26 +201,40 @@ async (req: Request) => { if (req.method == "POST") { try { const query = await req.json(); - const cookie = req.headers.get("cookie"); - const token = cookie?.split(";").find((c) => c.includes("token"))?.split("=")[1].split(" ")[1]; - const event = token ? JSON.parse(atob(token)) : undefined; - if (event) { - const verifyResult = await verifyEvent(event); - if (!verifyResult) { - return new Response(`{"errors":"token not verified"}`); - } - const pubkey = await relayInformationStore.resolveRelayInformation().then((info) => - info.pubkey - ); - if (!pubkey) { - return new Response(`{"errors":"relay pubkey not set"}`); - } - const relayPubkey = PublicKey.FromString(pubkey); - if (relayPubkey instanceof Error) { - return new Response(`{"errors":"relay pubkey not valid"}`); + if (!args.password) { + const cookie = req.headers.get("cookie"); + const token = cookie?.split(";").find((c) => c.includes("token"))?.split("=")[1].split( + " ", + )[1]; + const event = token ? JSON.parse(atob(token)) : undefined; + if (event) { + if (!await verifyEvent(event)) { + return new Response(`{"errors":"token not verified"}`); + } + const { pubkey } = await relayInformationStore.resolveRelayInformation(); + if (!pubkey) { + return new Response(`{"errors":"relay pubkey not set"}`); + } + const relayPubkey = PublicKey.FromString(pubkey); + if (relayPubkey instanceof Error) { + return new Response(`{"errors":"relay pubkey not valid"}`); + } + if (event.pubkey != relayPubkey.hex) { + return new Response(`{"errors":"you are not admin"}`); + } + const result = await gql.graphql({ + schema: schema, + source: query.query, + variableValues: query.variables, + rootValue: RootResolver(args), + }); + return new Response(JSON.stringify(result)); } - if (event.pubkey != relayPubkey.hex) { - return new Response(`{"errors":"you are not admin"}`); + return new Response(`{"errors":"please login first"}`); + } else { + const password = req.headers.get("password"); + if (password != args.password) { + return new Response(`{"errors":"password not correct"}`); } const result = await gql.graphql({ schema: schema, @@ -221,7 +244,6 @@ async (req: Request) => { }); return new Response(JSON.stringify(result)); } - return new Response(`{"errors":"please login first"}`); } catch (error) { return new Response(`{"errors":"${error}"}`); } diff --git a/test.ts b/test.ts index b9ccb57..e51adad 100644 --- a/test.ts +++ b/test.ts @@ -171,7 +171,7 @@ Deno.test("replaceable events", async (t) => { }); // https://github.com/nostr-protocol/nips/blob/master/09.md -Deno.test("NIP-9: Deletion", async () => { +Deno.test.ignore("NIP-9: Deletion", async () => { const relay = await run({ password: "123", port: 8080, @@ -258,6 +258,7 @@ async function randomEvent(ctx: InMemoryAccountContext, kind?: NostrKind, conten async function queryGql(relay: Relay, query: string, variables?: object) { const { hostname, port } = new URL(relay.url); + if (!relay.password) throw new Error("relay.password is not set on test"); const res = await fetch(`http://${hostname}:${port}/api`, { method: "POST", headers: { From a0c907afc3d92fdfdfa960ce479d003afd2992c2 Mon Sep 17 00:00:00 2001 From: Bob Date: Fri, 26 Apr 2024 16:17:37 +0800 Subject: [PATCH 04/24] update --- main.tsx | 3 +-- test.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/main.tsx b/main.tsx index a6641d4..0906f44 100644 --- a/main.tsx +++ b/main.tsx @@ -197,7 +197,6 @@ const graphql_handler = ( }, ) => async (req: Request) => { - const { relayInformationStore } = args; if (req.method == "POST") { try { const query = await req.json(); @@ -211,7 +210,7 @@ async (req: Request) => { if (!await verifyEvent(event)) { return new Response(`{"errors":"token not verified"}`); } - const { pubkey } = await relayInformationStore.resolveRelayInformation(); + const { pubkey } = await args.relayInformationStore.resolveRelayInformation(); if (!pubkey) { return new Response(`{"errors":"relay pubkey not set"}`); } diff --git a/test.ts b/test.ts index e51adad..16dca8e 100644 --- a/test.ts +++ b/test.ts @@ -171,7 +171,7 @@ Deno.test("replaceable events", async (t) => { }); // https://github.com/nostr-protocol/nips/blob/master/09.md -Deno.test.ignore("NIP-9: Deletion", async () => { +Deno.test("NIP-9: Deletion", async () => { const relay = await run({ password: "123", port: 8080, From e71e2427c5c68abac375eb925f9796903e9d2d9c Mon Sep 17 00:00:00 2001 From: Bob Date: Sun, 28 Apr 2024 15:15:54 +0800 Subject: [PATCH 05/24] add more verify logic --- main.tsx | 126 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 38 deletions(-) diff --git a/main.tsx b/main.tsx index 0906f44..da459b8 100644 --- a/main.tsx +++ b/main.tsx @@ -24,6 +24,7 @@ import { func_MarkEventDeleted, func_WriteRegularEvent, } from "./resolvers/event.ts"; +import { getCookies } from "https://deno.land/std@0.224.0/http/cookie.ts"; const schema = gql.buildSchema(gql.print(typeDefs)); @@ -147,6 +148,72 @@ export type EventReadWriter = { get_replaceable_events: func_GetReplaceableEvents; } & interface_GetEventsByAuthors; +async function vertifyToken(token: string | null, relayInformationStore: RelayInformationStore) { + try { + if (!token) { + return { + success: false, + error: "token not found", + } + } + const [prefix, eventBase64] = token.split(" "); + if(prefix !== "Nostr") { + return { + success: false, + error: "token not Nostr", + } + } + const event = JSON.parse(atob(eventBase64)); + if (!event) { + return { + success: false, + error: "no auth event", + } + } + if (!await verifyEvent(event)) { + return { + success: false, + error: "token not verified", + } + } + const { pubkey: relayPubkey } = await relayInformationStore.resolveRelayInformation(); + if (!relayPubkey) { + return { + success: false, + error: "relay pubkey not set", + } + } + const relayPubkeyObj = PublicKey.FromString(relayPubkey); + if (relayPubkeyObj instanceof Error) { + return { + success: false, + error: "relay pubkey not valid", + } + } + const pubkey = PublicKey.FromString(event.pubkey); + if (pubkey instanceof Error) { + return { + success: false, + error: "pubkey not valid", + } + } + if (pubkey.hex !== relayPubkeyObj.hex) { + return { + success: false, + error: "you are not admin", + } + } + return { + success: true, + } + } catch (error) { + return { + success: false, + error: error.toString(), + } + } +} + const root_handler = ( args: { password?: string; @@ -165,7 +232,8 @@ async (req: Request, info: Deno.ServeHandlerInfo) => { const { pathname, protocol } = new URL(req.url); if (pathname === "/api/auth/login") { const auth = req.headers.get("authorization"); - const resp = new Response("ok"); + const body = await vertifyToken(auth, args.relayInformationStore) + const resp = new Response(JSON.stringify(body), { status: 200 }); resp.headers.set("set-cookie", `token=${auth}; Path=/; Secure; HttpOnly; SameSite=Strict;`); return resp; } @@ -201,48 +269,25 @@ async (req: Request) => { try { const query = await req.json(); if (!args.password) { - const cookie = req.headers.get("cookie"); - const token = cookie?.split(";").find((c) => c.includes("token"))?.split("=")[1].split( - " ", - )[1]; - const event = token ? JSON.parse(atob(token)) : undefined; - if (event) { - if (!await verifyEvent(event)) { - return new Response(`{"errors":"token not verified"}`); - } - const { pubkey } = await args.relayInformationStore.resolveRelayInformation(); - if (!pubkey) { - return new Response(`{"errors":"relay pubkey not set"}`); - } - const relayPubkey = PublicKey.FromString(pubkey); - if (relayPubkey instanceof Error) { - return new Response(`{"errors":"relay pubkey not valid"}`); - } - if (event.pubkey != relayPubkey.hex) { - return new Response(`{"errors":"you are not admin"}`); - } - const result = await gql.graphql({ - schema: schema, - source: query.query, - variableValues: query.variables, - rootValue: RootResolver(args), - }); - return new Response(JSON.stringify(result)); + const cookies = getCookies(req.headers); + const token = cookies.token; + const body = await vertifyToken(token, args.relayInformationStore) + if (!body.success) { + return new Response(JSON.stringify(body), { status: 200 }); } - return new Response(`{"errors":"please login first"}`); } else { const password = req.headers.get("password"); if (password != args.password) { return new Response(`{"errors":"password not correct"}`); } - const result = await gql.graphql({ - schema: schema, - source: query.query, - variableValues: query.variables, - rootValue: RootResolver(args), - }); - return new Response(JSON.stringify(result)); } + const result = await gql.graphql({ + schema: schema, + source: query.query, + variableValues: query.variables, + rootValue: RootResolver(args), + }); + return new Response(JSON.stringify(result)); } catch (error) { return new Response(`{"errors":"${error}"}`); } @@ -372,12 +417,17 @@ const graphiql = ` tags: [], } const event = await ext.signEvent(unsigned_event); - fetch('/api/auth/login', { + const response = await fetch('/api/auth/login', { headers: { authorization: "Nostr " + btoa(JSON.stringify(event)), }, - credentials: 'include' }) + const data = await response.json(); + if(data.success) { + alert("Login success"); + } else { + alert(data.error || "Login failed"); + } } catch (e) { console.error(e); } From e3c4fd1cc865c21f39504663cd01bfc3ffa58e9b Mon Sep 17 00:00:00 2001 From: Bob Date: Sun, 28 Apr 2024 16:50:33 +0800 Subject: [PATCH 06/24] support multiple pubkey --- main.tsx | 169 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 92 insertions(+), 77 deletions(-) diff --git a/main.tsx b/main.tsx index da459b8..a3b41f1 100644 --- a/main.tsx +++ b/main.tsx @@ -62,7 +62,20 @@ export async function run(args: { args.kv = await Deno.openKv(); } - const { port, default_policy, default_information } = args; + const { port, default_policy,default_information } = args; + + if (default_information) { + const { pubkey } = default_information; + if (pubkey) { + const pubkeyArray = pubkey.split(","); + for (const pubkey of pubkeyArray) { + const pubkeyObj = PublicKey.FromString(pubkey); + if (pubkeyObj instanceof Error) { + return pubkeyObj; + } + } + } + } let resolve_hostname; const hostname = new Promise((resolve) => { @@ -76,18 +89,15 @@ export async function run(args: { default_information, ); - let { password } = args; + const { password } = args; if (!password) { const { pubkey } = await relayInformationStore.resolveRelayInformation(); if (!pubkey) { - const env_pubkey = Deno.env.get("relayed_pubkey"); + const env_pubkey = default_information?.pubkey; if (!env_pubkey) { - password = Deno.env.get("relayed_pw"); - if (!password) { - return new Error( - "password or pubkey is not set, please set env var $relayed_pw or $relayed_pubkey", - ); - } + return new Error( + "password or pubkey is not set, please set env var $relayed_pw or $relayed_pubkey", + ); } } } @@ -148,72 +158,6 @@ export type EventReadWriter = { get_replaceable_events: func_GetReplaceableEvents; } & interface_GetEventsByAuthors; -async function vertifyToken(token: string | null, relayInformationStore: RelayInformationStore) { - try { - if (!token) { - return { - success: false, - error: "token not found", - } - } - const [prefix, eventBase64] = token.split(" "); - if(prefix !== "Nostr") { - return { - success: false, - error: "token not Nostr", - } - } - const event = JSON.parse(atob(eventBase64)); - if (!event) { - return { - success: false, - error: "no auth event", - } - } - if (!await verifyEvent(event)) { - return { - success: false, - error: "token not verified", - } - } - const { pubkey: relayPubkey } = await relayInformationStore.resolveRelayInformation(); - if (!relayPubkey) { - return { - success: false, - error: "relay pubkey not set", - } - } - const relayPubkeyObj = PublicKey.FromString(relayPubkey); - if (relayPubkeyObj instanceof Error) { - return { - success: false, - error: "relay pubkey not valid", - } - } - const pubkey = PublicKey.FromString(event.pubkey); - if (pubkey instanceof Error) { - return { - success: false, - error: "pubkey not valid", - } - } - if (pubkey.hex !== relayPubkeyObj.hex) { - return { - success: false, - error: "you are not admin", - } - } - return { - success: true, - } - } catch (error) { - return { - success: false, - error: error.toString(), - } - } -} - const root_handler = ( args: { password?: string; @@ -232,7 +176,7 @@ async (req: Request, info: Deno.ServeHandlerInfo) => { const { pathname, protocol } = new URL(req.url); if (pathname === "/api/auth/login") { const auth = req.headers.get("authorization"); - const body = await vertifyToken(auth, args.relayInformationStore) + const body = await verifyToken(auth, args.relayInformationStore); const resp = new Response(JSON.stringify(body), { status: 200 }); resp.headers.set("set-cookie", `token=${auth}; Path=/; Secure; HttpOnly; SameSite=Strict;`); return resp; @@ -271,7 +215,7 @@ async (req: Request) => { if (!args.password) { const cookies = getCookies(req.headers); const token = cookies.token; - const body = await vertifyToken(token, args.relayInformationStore) + const body = await verifyToken(token, args.relayInformationStore); if (!body.success) { return new Response(JSON.stringify(body), { status: 200 }); } @@ -322,6 +266,77 @@ const information_handler = async (args: { relayInformationStore: RelayInformati return resp; }; +async function verifyToken(token: string | null, relayInformationStore: RelayInformationStore) { + try { + if (!token) { + return { + success: false, + error: "token not found", + }; + } + const [prefix, eventBase64] = token.split(" "); + if (prefix !== "Nostr") { + return { + success: false, + error: "token not Nostr", + }; + } + const event = JSON.parse(atob(eventBase64)); + if (!event) { + return { + success: false, + error: "no auth event", + }; + } + if (!await verifyEvent(event)) { + return { + success: false, + error: "token not verified", + }; + } + const { pubkey: relayPubkey } = await relayInformationStore.resolveRelayInformation(); + if (!relayPubkey) { + return { + success: false, + error: "relay pubkey not set", + }; + } + const relayPubkeyArr = relayPubkey.split(","); + const relayPubkeyHexArr: string[] = [] + for (const pubkey of relayPubkeyArr) { + const relayPubkeyObj = PublicKey.FromString(pubkey); + if (relayPubkeyObj instanceof Error) { + return { + success: false, + error: `relay pubkey:${pubkey} not valid`, + }; + } + relayPubkeyHexArr.push(relayPubkeyObj.hex); + } + const pubkey = PublicKey.FromString(event.pubkey); + if (pubkey instanceof Error) { + return { + success: false, + error: "pubkey not valid", + }; + } + if (!relayPubkeyHexArr.includes(pubkey.hex)) { + return { + success: false, + error: "you are not admin", + }; + } + return { + success: true, + }; + } catch (error) { + return { + success: false, + error: error.toString(), + }; + } +} + // export const kv = await Deno.openKv("./test-kv"); const graphiql = ` From 80e9407934bae97d88ad70e92744d8d349934733 Mon Sep 17 00:00:00 2001 From: Bob Date: Sun, 28 Apr 2024 17:44:00 +0800 Subject: [PATCH 07/24] update --- main.tsx | 36 +++++++++++++++++++++--------------- resolvers/nip11.ts | 7 ++++++- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/main.tsx b/main.tsx index a3b41f1..df9ddb0 100644 --- a/main.tsx +++ b/main.tsx @@ -62,12 +62,17 @@ export async function run(args: { args.kv = await Deno.openKv(); } - const { port, default_policy,default_information } = args; + const { port, default_policy, default_information } = args; if (default_information) { - const { pubkey } = default_information; - if (pubkey) { - const pubkeyArray = pubkey.split(","); + if (!default_information.pubkey) { + const env_pubkey = Deno.env.get("relayed_pubkey"); + if (env_pubkey) { + default_information.pubkey = env_pubkey; + } + } + if (default_information.pubkey) { + const pubkeyArray = default_information.pubkey.split(","); for (const pubkey of pubkeyArray) { const pubkeyObj = PublicKey.FromString(pubkey); if (pubkeyObj instanceof Error) { @@ -89,16 +94,17 @@ export async function run(args: { default_information, ); - const { password } = args; - if (!password) { - const { pubkey } = await relayInformationStore.resolveRelayInformation(); - if (!pubkey) { - const env_pubkey = default_information?.pubkey; - if (!env_pubkey) { - return new Error( - "password or pubkey is not set, please set env var $relayed_pw or $relayed_pubkey", - ); - } + let { password } = args; + const { pubkey } = await relayInformationStore.resolveRelayInformation(); + if (!pubkey) { + const env_password = Deno.env.get("relayed_pw"); + if (env_password) { + password = env_password; + } + if (!default_information?.pubkey && !env_password) { + return new Error( + "password and pubkey is not set, please set env var $relayed_pw or $relayed_pubkey", + ); } } @@ -302,7 +308,7 @@ async function verifyToken(token: string | null, relayInformationStore: RelayInf }; } const relayPubkeyArr = relayPubkey.split(","); - const relayPubkeyHexArr: string[] = [] + const relayPubkeyHexArr: string[] = []; for (const pubkey of relayPubkeyArr) { const relayPubkeyObj = PublicKey.FromString(pubkey); if (relayPubkeyObj instanceof Error) { diff --git a/resolvers/nip11.ts b/resolvers/nip11.ts index a557b07..da7bfb4 100644 --- a/resolvers/nip11.ts +++ b/resolvers/nip11.ts @@ -30,7 +30,12 @@ export class RelayInformationStore { } resolveRelayInformation = async (): Promise => { - const get_relay_information = (await this.kv.get(["relay_information"])).value; + const get_relay_information = (await this.kv.get(["relay_information"])).value || + {}; + // if pubkey is set in default_information, it will be used as the pubkey + if (this.default_information.pubkey) { + get_relay_information.pubkey = this.default_information.pubkey; + } return { ...this.default_information, ...get_relay_information, ...not_modifiable_information }; }; From 686e92c0c761a8a5e24da356c415833f7d7030a4 Mon Sep 17 00:00:00 2001 From: Bob Date: Sun, 28 Apr 2024 17:48:12 +0800 Subject: [PATCH 08/24] update --- main.tsx | 40 ++++++++-------------------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/main.tsx b/main.tsx index df9ddb0..e760e80 100644 --- a/main.tsx +++ b/main.tsx @@ -275,62 +275,38 @@ const information_handler = async (args: { relayInformationStore: RelayInformati async function verifyToken(token: string | null, relayInformationStore: RelayInformationStore) { try { if (!token) { - return { - success: false, - error: "token not found", - }; + throw new Error("token not found"); } const [prefix, eventBase64] = token.split(" "); if (prefix !== "Nostr") { - return { - success: false, - error: "token not Nostr", - }; + throw new Error("token not Nostr"); } const event = JSON.parse(atob(eventBase64)); if (!event) { - return { - success: false, - error: "no auth event", - }; + throw new Error("no auth event"); } if (!await verifyEvent(event)) { - return { - success: false, - error: "token not verified", - }; + throw new Error("token not verified"); } const { pubkey: relayPubkey } = await relayInformationStore.resolveRelayInformation(); if (!relayPubkey) { - return { - success: false, - error: "relay pubkey not set", - }; + throw new Error("relay pubkey not set"); } const relayPubkeyArr = relayPubkey.split(","); const relayPubkeyHexArr: string[] = []; for (const pubkey of relayPubkeyArr) { const relayPubkeyObj = PublicKey.FromString(pubkey); if (relayPubkeyObj instanceof Error) { - return { - success: false, - error: `relay pubkey:${pubkey} not valid`, - }; + throw new Error(`relay pubkey:${pubkey} not valid`); } relayPubkeyHexArr.push(relayPubkeyObj.hex); } const pubkey = PublicKey.FromString(event.pubkey); if (pubkey instanceof Error) { - return { - success: false, - error: "pubkey not valid", - }; + throw new Error("pubkey not valid"); } if (!relayPubkeyHexArr.includes(pubkey.hex)) { - return { - success: false, - error: "you are not admin", - }; + throw new Error("pubkey not in relay"); } return { success: true, From 7207b72dc59835043efb0fdec3d4e3f62aa32a04 Mon Sep 17 00:00:00 2001 From: Bob Date: Mon, 29 Apr 2024 11:12:01 +0800 Subject: [PATCH 09/24] chore: remove password --- deploy/example.ts | 1 - main.tsx | 18 ------------------ test.ts | 25 ++++++++++++++++++++----- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/deploy/example.ts b/deploy/example.ts index d55371f..89162c7 100644 --- a/deploy/example.ts +++ b/deploy/example.ts @@ -5,7 +5,6 @@ const relay = await run({ default_policy: { allowed_kinds: "all", // or none, }, - password: Deno.env.get("relayed_pw"), default_information: { name: "Relayed Example", description: "A lightweight relay written in Deno.", diff --git a/main.tsx b/main.tsx index e760e80..c642c01 100644 --- a/main.tsx +++ b/main.tsx @@ -35,7 +35,6 @@ export type DefaultPolicy = { export type Relay = { server: Deno.HttpServer; url: string; - password?: string; shutdown: () => Promise; set_policy: (args: { kind: NostrKind; @@ -94,20 +93,6 @@ export async function run(args: { default_information, ); - let { password } = args; - const { pubkey } = await relayInformationStore.resolveRelayInformation(); - if (!pubkey) { - const env_password = Deno.env.get("relayed_pw"); - if (env_password) { - password = env_password; - } - if (!default_information?.pubkey && !env_password) { - return new Error( - "password and pubkey is not set, please set env var $relayed_pw or $relayed_pubkey", - ); - } - } - const eventStore = await EventStore.New(args.kv); const server = Deno.serve( @@ -121,7 +106,6 @@ export async function run(args: { }, root_handler({ ...args, - password, connections, resolvePolicyByKind: policyStore.resolvePolicyByKind, get_events_by_IDs: eventStore.get_events_by_IDs.bind(eventStore), @@ -140,7 +124,6 @@ export async function run(args: { return { server, - password, url: `ws://${await hostname}:${port}`, shutdown: async () => { await server.shutdown(); @@ -166,7 +149,6 @@ export type EventReadWriter = { const root_handler = ( args: { - password?: string; information?: RelayInformation; connections: Map; default_policy: DefaultPolicy; diff --git a/test.ts b/test.ts index 16dca8e..a43f6bd 100644 --- a/test.ts +++ b/test.ts @@ -23,6 +23,15 @@ const test_kv = async () => { return await Deno.openKv("test.sqlite"); }; +const test_ctx = InMemoryAccountContext.Generate(); +const test_auth_event = async () => { + const event = await prepareNormalNostrEvent(test_ctx, { + kind: NostrKind.TEXT_NOTE, + content: "", + }); + return btoa(JSON.stringify(event)); +} + // Need to keep consistent with resolvers/nip11.ts const not_modifiable_information = { software: "https://github.com/BlowaterNostr/relayed", @@ -34,6 +43,9 @@ Deno.test("main", async (t) => { const relay = await run({ password: "123", port: 8080, + default_information: { + pubkey: test_ctx.publicKey.bech32(), + }, default_policy: { allowed_kinds: [NostrKind.Long_Form, NostrKind.Encrypted_Custom_App_Data], }, @@ -155,8 +167,10 @@ Deno.test("main", async (t) => { // https://github.com/nostr-protocol/nips/blob/master/01.md#kinds Deno.test("replaceable events", async (t) => { const relay = await run({ - password: "123", port: 8080, + default_information: { + pubkey: test_ctx.publicKey.bech32(), + }, default_policy: { allowed_kinds: "all", }, @@ -173,8 +187,10 @@ Deno.test("replaceable events", async (t) => { // https://github.com/nostr-protocol/nips/blob/master/09.md Deno.test("NIP-9: Deletion", async () => { const relay = await run({ - password: "123", port: 8080, + default_information: { + pubkey: test_ctx.publicKey.bech32(), + }, default_policy: { allowed_kinds: "all", }, @@ -191,13 +207,13 @@ Deno.test("NIP-9: Deletion", async () => { // https://github.com/nostr-protocol/nips/blob/master/11.md Deno.test("NIP-11: Relay Information Document", async (t) => { const relay = await run({ - password: "123", port: 8080, default_policy: { allowed_kinds: "none", }, default_information: { name: "Nostr Relay", + pubkey: test_ctx.publicKey.bech32(), }, kv: await test_kv(), }) as Relay; @@ -258,12 +274,11 @@ async function randomEvent(ctx: InMemoryAccountContext, kind?: NostrKind, conten async function queryGql(relay: Relay, query: string, variables?: object) { const { hostname, port } = new URL(relay.url); - if (!relay.password) throw new Error("relay.password is not set on test"); const res = await fetch(`http://${hostname}:${port}/api`, { method: "POST", headers: { + "cookie": `token="nostr ${test_auth_event()}`, "Content-Type": "application/json", - "password": relay.password, }, body: JSON.stringify({ query, variables }), }); From e2fe1b654d615407121f531e384be03061c38680 Mon Sep 17 00:00:00 2001 From: Bob Date: Mon, 29 Apr 2024 11:16:24 +0800 Subject: [PATCH 10/24] test: update --- main.tsx | 19 +++++-------------- test.ts | 19 +++++++++++++------ 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/main.tsx b/main.tsx index c642c01..5ebb695 100644 --- a/main.tsx +++ b/main.tsx @@ -51,7 +51,6 @@ export type Relay = { export async function run(args: { port: number; admin?: PublicKey; - password?: string; default_information?: RelayInformation; default_policy: DefaultPolicy; kv?: Deno.Kv; @@ -190,7 +189,6 @@ async (req: Request, info: Deno.ServeHandlerInfo) => { const graphql_handler = ( args: { - password?: string; kv: Deno.Kv; policyStore: PolicyStore; relayInformationStore: RelayInformationStore; @@ -200,18 +198,11 @@ async (req: Request) => { if (req.method == "POST") { try { const query = await req.json(); - if (!args.password) { - const cookies = getCookies(req.headers); - const token = cookies.token; - const body = await verifyToken(token, args.relayInformationStore); - if (!body.success) { - return new Response(JSON.stringify(body), { status: 200 }); - } - } else { - const password = req.headers.get("password"); - if (password != args.password) { - return new Response(`{"errors":"password not correct"}`); - } + const cookies = getCookies(req.headers); + const token = cookies.token; + const body = await verifyToken(token, args.relayInformationStore); + if (!body.success) { + return new Response(JSON.stringify(body), { status: 200 }); } const result = await gql.graphql({ schema: schema, diff --git a/test.ts b/test.ts index a43f6bd..a843d26 100644 --- a/test.ts +++ b/test.ts @@ -30,7 +30,7 @@ const test_auth_event = async () => { content: "", }); return btoa(JSON.stringify(event)); -} +}; // Need to keep consistent with resolvers/nip11.ts const not_modifiable_information = { @@ -41,7 +41,6 @@ const not_modifiable_information = { Deno.test("main", async (t) => { const relay = await run({ - password: "123", port: 8080, default_information: { pubkey: test_ctx.publicKey.bech32(), @@ -220,7 +219,11 @@ Deno.test("NIP-11: Relay Information Document", async (t) => { await t.step("get relay information", async () => { const information = await relay.get_relay_information(); - assertEquals(information, { name: "Nostr Relay", ...not_modifiable_information }); + assertEquals(information, { + name: "Nostr Relay", + pubkey: test_ctx.publicKey.bech32(), + ...not_modifiable_information, + }); }); await t.step("set relay information", async () => { @@ -229,7 +232,11 @@ Deno.test("NIP-11: Relay Information Document", async (t) => { }); const information2 = await relay.get_relay_information(); - assertEquals(information2, { name: "Nostr Relay2", ...not_modifiable_information }); + assertEquals(information2, { + name: "Nostr Relay2", + pubkey: test_ctx.publicKey.bech32(), + ...not_modifiable_information, + }); }); await t.step("graphql get relay information", async () => { @@ -240,7 +247,7 @@ Deno.test("NIP-11: Relay Information Document", async (t) => { icon: null, contact: null, description: null, - pubkey: null, + pubkey: test_ctx.publicKey.bech32(), ...not_modifiable_information, }); }); @@ -256,7 +263,7 @@ Deno.test("NIP-11: Relay Information Document", async (t) => { icon: null, contact: null, description: null, - pubkey: null, + pubkey: test_ctx.publicKey.bech32(), ...not_modifiable_information, }); }); From 25e9e3bc16e7c21cd7ba3e9928b63dac841e7002 Mon Sep 17 00:00:00 2001 From: Bob Date: Mon, 29 Apr 2024 15:11:07 +0800 Subject: [PATCH 11/24] relayed_pubkey --- deploy/example.ts | 15 ++++++- graphql-schema.ts | 2 +- main.tsx | 97 ++++++++++++++++++---------------------------- resolvers/nip11.ts | 28 +++++++++---- test.ts | 18 ++++----- 5 files changed, 83 insertions(+), 77 deletions(-) diff --git a/deploy/example.ts b/deploy/example.ts index 89162c7..4b3f4d0 100644 --- a/deploy/example.ts +++ b/deploy/example.ts @@ -1,5 +1,18 @@ +import { PublicKey } from "../_libs.ts"; import { run } from "../main.tsx"; +const relayed_pubkey = Deno.env.get("relayed_pubkey"); +if (!relayed_pubkey) { + console.error("Please set the environment variable 'relayed_pubkey'"); + Deno.exit(1); +} + +const pubkey = PublicKey.FromString(relayed_pubkey); +if (pubkey instanceof Error) { + console.error(pubkey); + Deno.exit(1); +} + const relay = await run({ port: 8080, default_policy: { @@ -8,7 +21,7 @@ const relay = await run({ default_information: { name: "Relayed Example", description: "A lightweight relay written in Deno.", - pubkey: Deno.env.get("relayed_pubkey"), + pubkey, contact: "", icon: "", }, diff --git a/graphql-schema.ts b/graphql-schema.ts index d77f6bb..eed2fdd 100644 --- a/graphql-schema.ts +++ b/graphql-schema.ts @@ -45,7 +45,7 @@ export const typeDefs = gql` type RelayInformation { name: String description: String - pubkey: String + pubkey: PublicKey! contact: String supported_nips: [Int!] software: String diff --git a/main.tsx b/main.tsx index 5ebb695..84f5038 100644 --- a/main.tsx +++ b/main.tsx @@ -5,7 +5,7 @@ import { RootResolver } from "./resolvers/root.ts"; import * as gql from "https://esm.sh/graphql@16.8.1"; import { Policy } from "./resolvers/policy.ts"; import { func_ResolvePolicyByKind } from "./resolvers/policy.ts"; -import { NostrKind, PublicKey, verifyEvent } from "./_libs.ts"; +import { NostrEvent, NostrKind, PublicKey, verifyEvent } from "./_libs.ts"; import { PolicyStore } from "./resolvers/policy.ts"; import { Policies } from "./resolvers/policy.ts"; import { @@ -24,7 +24,7 @@ import { func_MarkEventDeleted, func_WriteRegularEvent, } from "./resolvers/event.ts"; -import { getCookies } from "https://deno.land/std@0.224.0/http/cookie.ts"; +import { Cookie, getCookies, setCookie } from "https://deno.land/std@0.224.0/http/cookie.ts"; const schema = gql.buildSchema(gql.print(typeDefs)); @@ -43,7 +43,9 @@ export type Relay = { block?: Set; }) => Promise; get_policy: (kind: NostrKind) => Promise; - set_relay_information: (args: RelayInformation) => Promise; + set_relay_information: ( + args: { name?: string; description?: string; pubkey?: string; contact?: string; icon?: string }, + ) => Promise; get_relay_information: () => Promise; default_policy: DefaultPolicy; }; @@ -51,7 +53,7 @@ export type Relay = { export async function run(args: { port: number; admin?: PublicKey; - default_information?: RelayInformation; + default_information: RelayInformation; default_policy: DefaultPolicy; kv?: Deno.Kv; }): Promise { @@ -62,24 +64,6 @@ export async function run(args: { const { port, default_policy, default_information } = args; - if (default_information) { - if (!default_information.pubkey) { - const env_pubkey = Deno.env.get("relayed_pubkey"); - if (env_pubkey) { - default_information.pubkey = env_pubkey; - } - } - if (default_information.pubkey) { - const pubkeyArray = default_information.pubkey.split(","); - for (const pubkey of pubkeyArray) { - const pubkeyObj = PublicKey.FromString(pubkey); - if (pubkeyObj instanceof Error) { - return pubkeyObj; - } - } - } - } - let resolve_hostname; const hostname = new Promise((resolve) => { resolve_hostname = resolve; @@ -148,7 +132,6 @@ export type EventReadWriter = { const root_handler = ( args: { - information?: RelayInformation; connections: Map; default_policy: DefaultPolicy; resolvePolicyByKind: func_ResolvePolicyByKind; @@ -162,11 +145,28 @@ async (req: Request, info: Deno.ServeHandlerInfo) => { const { pathname, protocol } = new URL(req.url); if (pathname === "/api/auth/login") { - const auth = req.headers.get("authorization"); - const body = await verifyToken(auth, args.relayInformationStore); - const resp = new Response(JSON.stringify(body), { status: 200 }); - resp.headers.set("set-cookie", `token=${auth}; Path=/; Secure; HttpOnly; SameSite=Strict;`); - return resp; + const body = await req.json(); + if (!body) { + return new Response(`{"errors":"request body is null"}`, { status: 400 }); + } + const result = await verifyToken(body, args.relayInformationStore); + if (!result.success) { + return new Response(JSON.stringify(result), { status: 400 }); + } else { + const auth = btoa(JSON.stringify(body)); + const headers = new Headers(); + const cookie: Cookie = { + name: "token", + value: auth, + path: "/", + secure: true, + httpOnly: true, + sameSite: "Strict", + }; + setCookie(headers, cookie); + const resp = new Response("", { status: 200, headers }); + return resp; + } } if (pathname == "/api") { return graphql_handler(args)(req); @@ -200,7 +200,11 @@ async (req: Request) => { const query = await req.json(); const cookies = getCookies(req.headers); const token = cookies.token; - const body = await verifyToken(token, args.relayInformationStore); + if (!token) { + return new Response(`{"errors":"no token"}`); + } + const event = JSON.parse(atob(token)); + const body = await verifyToken(event, args.relayInformationStore); if (!body.success) { return new Response(JSON.stringify(body), { status: 200 }); } @@ -245,41 +249,17 @@ const information_handler = async (args: { relayInformationStore: RelayInformati return resp; }; -async function verifyToken(token: string | null, relayInformationStore: RelayInformationStore) { +async function verifyToken(event: NostrEvent, relayInformationStore: RelayInformationStore) { try { - if (!token) { - throw new Error("token not found"); - } - const [prefix, eventBase64] = token.split(" "); - if (prefix !== "Nostr") { - throw new Error("token not Nostr"); - } - const event = JSON.parse(atob(eventBase64)); - if (!event) { - throw new Error("no auth event"); - } if (!await verifyEvent(event)) { throw new Error("token not verified"); } - const { pubkey: relayPubkey } = await relayInformationStore.resolveRelayInformation(); - if (!relayPubkey) { - throw new Error("relay pubkey not set"); - } - const relayPubkeyArr = relayPubkey.split(","); - const relayPubkeyHexArr: string[] = []; - for (const pubkey of relayPubkeyArr) { - const relayPubkeyObj = PublicKey.FromString(pubkey); - if (relayPubkeyObj instanceof Error) { - throw new Error(`relay pubkey:${pubkey} not valid`); - } - relayPubkeyHexArr.push(relayPubkeyObj.hex); - } const pubkey = PublicKey.FromString(event.pubkey); if (pubkey instanceof Error) { throw new Error("pubkey not valid"); } - if (!relayPubkeyHexArr.includes(pubkey.hex)) { - throw new Error("pubkey not in relay"); + if (pubkey.hex !== (await relayInformationStore.resolveRelayInformation()).pubkey.hex) { + throw new Error("not admin"); } return { success: true, @@ -388,9 +368,8 @@ const graphiql = ` } const event = await ext.signEvent(unsigned_event); const response = await fetch('/api/auth/login', { - headers: { - authorization: "Nostr " + btoa(JSON.stringify(event)), - }, + method: 'POST', + body: JSON.stringify(event), }) const data = await response.json(); if(data.success) { diff --git a/resolvers/nip11.ts b/resolvers/nip11.ts index da7bfb4..fd75112 100644 --- a/resolvers/nip11.ts +++ b/resolvers/nip11.ts @@ -1,7 +1,9 @@ +import { PublicKey } from "../_libs.ts"; + export type RelayInformation = { name?: string; description?: string; - pubkey?: string; + pubkey: PublicKey; contact?: string; supported_nips?: number[]; software?: string; @@ -24,16 +26,15 @@ export class RelayInformationStore { constructor( private kv: Deno.Kv, - default_information?: RelayInformation, + default_information: RelayInformation, ) { - this.default_information = default_information ? default_information : {}; + this.default_information = default_information; } resolveRelayInformation = async (): Promise => { - const get_relay_information = (await this.kv.get(["relay_information"])).value || - {}; + const get_relay_information = (await this.kv.get(["relay_information"])).value; // if pubkey is set in default_information, it will be used as the pubkey - if (this.default_information.pubkey) { + if (get_relay_information && this.default_information.pubkey) { get_relay_information.pubkey = this.default_information.pubkey; } return { ...this.default_information, ...get_relay_information, ...not_modifiable_information }; @@ -49,7 +50,20 @@ export class RelayInformationStore { }, ) => { const old_information = await this.resolveRelayInformation(); - const new_information = { ...old_information, ...args }; + const new_information = { + ...old_information, + name: args.name, + description: args.description, + contact: args.contact, + icon: args.icon, + }; + if (args.pubkey) { + const pubkey = PublicKey.FromString(args.pubkey); + if (pubkey instanceof Error) { + throw new Error("Invalid pubkey"); + } + new_information.pubkey = pubkey; + } await this.kv.set(["relay_information"], new_information); return { ...new_information, ...not_modifiable_information }; }; diff --git a/test.ts b/test.ts index a843d26..2cfb382 100644 --- a/test.ts +++ b/test.ts @@ -43,7 +43,7 @@ Deno.test("main", async (t) => { const relay = await run({ port: 8080, default_information: { - pubkey: test_ctx.publicKey.bech32(), + pubkey: test_ctx.publicKey, }, default_policy: { allowed_kinds: [NostrKind.Long_Form, NostrKind.Encrypted_Custom_App_Data], @@ -168,7 +168,7 @@ Deno.test("replaceable events", async (t) => { const relay = await run({ port: 8080, default_information: { - pubkey: test_ctx.publicKey.bech32(), + pubkey: test_ctx.publicKey, }, default_policy: { allowed_kinds: "all", @@ -188,7 +188,7 @@ Deno.test("NIP-9: Deletion", async () => { const relay = await run({ port: 8080, default_information: { - pubkey: test_ctx.publicKey.bech32(), + pubkey: test_ctx.publicKey, }, default_policy: { allowed_kinds: "all", @@ -212,7 +212,7 @@ Deno.test("NIP-11: Relay Information Document", async (t) => { }, default_information: { name: "Nostr Relay", - pubkey: test_ctx.publicKey.bech32(), + pubkey: test_ctx.publicKey, }, kv: await test_kv(), }) as Relay; @@ -221,7 +221,7 @@ Deno.test("NIP-11: Relay Information Document", async (t) => { const information = await relay.get_relay_information(); assertEquals(information, { name: "Nostr Relay", - pubkey: test_ctx.publicKey.bech32(), + pubkey: test_ctx.publicKey, ...not_modifiable_information, }); }); @@ -234,7 +234,7 @@ Deno.test("NIP-11: Relay Information Document", async (t) => { const information2 = await relay.get_relay_information(); assertEquals(information2, { name: "Nostr Relay2", - pubkey: test_ctx.publicKey.bech32(), + pubkey: test_ctx.publicKey, ...not_modifiable_information, }); }); @@ -247,7 +247,7 @@ Deno.test("NIP-11: Relay Information Document", async (t) => { icon: null, contact: null, description: null, - pubkey: test_ctx.publicKey.bech32(), + pubkey: test_ctx.publicKey, ...not_modifiable_information, }); }); @@ -263,7 +263,7 @@ Deno.test("NIP-11: Relay Information Document", async (t) => { icon: null, contact: null, description: null, - pubkey: test_ctx.publicKey.bech32(), + pubkey: test_ctx.publicKey, ...not_modifiable_information, }); }); @@ -284,7 +284,7 @@ async function queryGql(relay: Relay, query: string, variables?: object) { const res = await fetch(`http://${hostname}:${port}/api`, { method: "POST", headers: { - "cookie": `token="nostr ${test_auth_event()}`, + "cookie": `token="${test_auth_event()}`, "Content-Type": "application/json", }, body: JSON.stringify({ query, variables }), From 635cae114ff81633e987ff6516eaa9917b266e61 Mon Sep 17 00:00:00 2001 From: Bob Date: Mon, 29 Apr 2024 16:01:42 +0800 Subject: [PATCH 12/24] logined --- main.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/main.tsx b/main.tsx index 84f5038..8badb5d 100644 --- a/main.tsx +++ b/main.tsx @@ -206,7 +206,7 @@ async (req: Request) => { const event = JSON.parse(atob(token)); const body = await verifyToken(event, args.relayInformationStore); if (!body.success) { - return new Response(JSON.stringify(body), { status: 200 }); + return new Response(`{"errors":"${body.error}"}`); } const result = await gql.graphql({ schema: schema, @@ -295,7 +295,7 @@ const graphiql = ` } #graphiql { - height: 100vh; + height: 95vh; }