From a108956aafd906c5ce582cdcafab968a980c439a Mon Sep 17 00:00:00 2001 From: escapedcat Date: Tue, 22 Nov 2022 17:53:04 +0100 Subject: [PATCH] feat(nostr): support permission vor signMessage #1727 --- src/app/screens/Nostr/ConfirmSignMessage.tsx | 22 ++++- .../actions/nostr/signEventOrPrompt.ts | 80 ++++++++++++++++--- .../actions/permissions/__tests__/add.test.ts | 4 +- .../actions/webln/sendPaymentOrPrompt.ts | 4 + src/types.ts | 19 +++-- 5 files changed, 107 insertions(+), 22 deletions(-) diff --git a/src/app/screens/Nostr/ConfirmSignMessage.tsx b/src/app/screens/Nostr/ConfirmSignMessage.tsx index 274f989d79..f2f168a698 100644 --- a/src/app/screens/Nostr/ConfirmSignMessage.tsx +++ b/src/app/screens/Nostr/ConfirmSignMessage.tsx @@ -1,9 +1,9 @@ -//import Checkbox from "../../components/Form/Checkbox"; import ConfirmOrCancel from "@components/ConfirmOrCancel"; import Container from "@components/Container"; import ContentMessage from "@components/ContentMessage"; import PublisherCard from "@components/PublisherCard"; import SuccessMessage from "@components/SuccessMessage"; +import Checkbox from "@components/form/Checkbox"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; @@ -27,13 +27,16 @@ function ConfirmSignMessage() { const origin = navState.origin as OriginData; const [loading, setLoading] = useState(false); const [successMessage, setSuccessMessage] = useState(""); + const [rememberPermission, setRememberPermission] = useState(false); // TODO: refactor: the success message and loading will not be displayed because after the reply the prompt is closed. + // escapedcat: is this ok because we only show these in the popup usually? async function confirm() { try { setLoading(true); msg.reply({ confirm: true, + rememberPermission, }); setSuccessMessage(tCommon("success")); } catch (e) { @@ -73,6 +76,23 @@ function ConfirmSignMessage() { heading={t("content", { host: origin.host })} content={event.content} /> +
+ { + setRememberPermission(event.target.checked); + }} + /> + +
{ }; } + console.log("message.args.event", message.args.event); + + const dbPermissions = await db.permissions + .where("host") + .equalsIgnoreCase(message.origin.host) + .toArray(); + + const hasPermission = dbPermissions + .filter((permission) => permission.enabled) + .map(({ method }) => method) + .includes("signMessage"); + try { - const response = await utils.openPrompt<{ - confirm: boolean; - }>({ - ...message, - action: "public/nostr/confirmSignMessage", - }); - if (!response.data.confirm) { - throw new Error("User rejected"); + if (!hasPermission) { + const response = await utils.openPrompt<{ + confirm: boolean; + rememberPermission: boolean; + }>({ + ...message, + action: "public/nostr/confirmSignMessage", + }); + + if (!response.data.confirm) { + throw new Error("User rejected"); + } + + const matchingAllowance = await db.allowances + .where("host") + .equalsIgnoreCase(message.origin.host) + .first(); + let allowanceId = matchingAllowance?.id; + + if (!allowanceId) { + console.log("mno matching allowance"); + + const dbAllowance: DbAllowance = { + createdAt: Date.now().toString(), + enabled: true, + host: message.origin.host, + imageURL: "", // need to get the image + lastPaymentAt: 0, + lnurlAuth: false, + name: "", + remainingBudget: 0, + tag: "", + totalBudget: 0, + }; + allowanceId = await db.allowances.add(dbAllowance); + } + + console.log("matching allowance!"); + + if (response.data.rememberPermission) { + console.log("rememberme?"); + + const permission: DbPermission = { + createdAt: Date.now().toString(), + allowanceId, + host: message.origin.host, + method: "signMessage", + enabled: true, + blocked: false, + }; + console.log("rememberme!", permission); + + await db.permissions.add(permission); + } } + console.log("SO HAZ permissions - message: ", message); const signedEvent = await state .getState() .getNostr() .signEvent(message.args.event); + console.log("SO HAZ permissions - signedEvent: ", signedEvent); + return { data: signedEvent }; } catch (e) { console.error("signEvent cancelled", e); diff --git a/src/extension/background-script/actions/permissions/__tests__/add.test.ts b/src/extension/background-script/actions/permissions/__tests__/add.test.ts index a0d28478b7..c21e6c5a74 100644 --- a/src/extension/background-script/actions/permissions/__tests__/add.test.ts +++ b/src/extension/background-script/actions/permissions/__tests__/add.test.ts @@ -45,7 +45,7 @@ describe("add permission", () => { }, args: { host: stackerNews.host, - method: "listinvoices", + method: "signMessage", enabled: true, blocked: false, }, @@ -61,7 +61,7 @@ describe("add permission", () => { allowanceId: 3, createdAt: "1487076708000", host: "stacker.news", - method: "listinvoices", + method: "signMessage", blocked: false, enabled: true, }, diff --git a/src/extension/background-script/actions/webln/sendPaymentOrPrompt.ts b/src/extension/background-script/actions/webln/sendPaymentOrPrompt.ts index fabf27e97b..4b7f38d192 100644 --- a/src/extension/background-script/actions/webln/sendPaymentOrPrompt.ts +++ b/src/extension/background-script/actions/webln/sendPaymentOrPrompt.ts @@ -6,6 +6,8 @@ import db from "../../db"; import sendPayment from "../ln/sendPayment"; const sendPaymentOrPrompt = async (message: Message) => { + console.log("sendPaymentOrPrompt"); + if (!("host" in message.origin)) return; const paymentRequest = message.args.paymentRequest; @@ -38,6 +40,8 @@ async function checkAllowance(host: string, amount: number) { } async function sendPaymentWithAllowance(message: Message) { + console.log("sendPaymentWithAllowance"); + try { const response = await sendPayment(message); return response; diff --git a/src/types.ts b/src/types.ts index 92b0d56f43..07251cca4e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -194,10 +194,10 @@ export interface MessageAccountAll extends MessageDefault { export interface MessagePermissionAdd extends MessageDefault { args: { - host: string; - method: string; - enabled: boolean; - blocked: boolean; + host: DbPermission["host"]; + method: DbPermission["method"]; + enabled: DbPermission["enabled"]; + blocked: DbPermission["blocked"]; }; action: "addPermission"; } @@ -497,21 +497,20 @@ export interface DbPayment { totalFees: number; } +export interface Payment extends Omit { + id: number; +} + export interface DbPermission { id?: number; createdAt: string; allowanceId: number; host: string; - method: string; + method: "signMessage"; enabled: boolean; blocked: boolean; } -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface Payment extends Omit { - id: number; -} - export interface PaymentResponse extends Pick { route: {