diff --git a/src/app/components/BunkerConnect.svelte b/src/app/components/BunkerConnect.svelte index 8755c61a..6d795a7c 100644 --- a/src/app/components/BunkerConnect.svelte +++ b/src/app/components/BunkerConnect.svelte @@ -1,4 +1,6 @@ {#if $url} @@ -20,6 +30,12 @@

Scan with your signer to log in, or click to copy.

+ {#if Capacitor.isNativePlatform()} +
+ + +
+ {/if}
{/if} {/if} diff --git a/src/app/util/nip46.ts b/src/app/util/nip46.ts index b7eaccad..5d1f1a01 100644 --- a/src/app/util/nip46.ts +++ b/src/app/util/nip46.ts @@ -1,4 +1,4 @@ -import {writable} from "svelte/store" +import {get, writable} from "svelte/store" import type {Nip46ResponseWithResult} from "@welshman/signer" import {Nip46Broker} from "@welshman/signer" import {makeSecret} from "@welshman/util" @@ -11,8 +11,28 @@ import { } from "@app/core/state" import {pushToast} from "@app/util/toast" +const APP_SCHEME = "social.flotilla" + +type NostrSignerScheme = "aegis" | "nostrsigner" + +const makeSignerCallbackUrl = (path: string, sourceAppScheme: string) => + `${sourceAppScheme}://x-callback-url/${path}` + +const makeSignerLaunchUrl = (scheme: NostrSignerScheme, nostrconnectUrl: string) => { + const params = new URLSearchParams({ + method: "connect", + nostrconnect: nostrconnectUrl, + "x-source": APP_SCHEME, + "x-success": makeSignerCallbackUrl("authSuccess", APP_SCHEME), + "x-error": makeSignerCallbackUrl("authError", APP_SCHEME), + }) + + return `${scheme}://x-callback-url/auth/nip46?${params.toString()}` +} + export class Nip46Controller { url = writable("") + signerUrls = writable<{aegis: string; nostrsigner: string} | undefined>(undefined) bunker = writable("") loading = writable(false) clientSecret = makeSecret() @@ -33,6 +53,10 @@ export class Nip46Controller { }) this.url.set(url) + this.signerUrls.set({ + aegis: makeSignerLaunchUrl("aegis", url), + nostrsigner: makeSignerLaunchUrl("nostrsigner", url), + }) let response try { @@ -54,6 +78,21 @@ export class Nip46Controller { } } + launchSigner(scheme: NostrSignerScheme) { + const signerUrl = get(this.signerUrls)?.[scheme] + + if (!signerUrl) { + pushToast({ + theme: "error", + message: "Unable to open signer app right now. Please try again.", + }) + + return + } + + window.location.href = signerUrl + } + stop() { this.broker.cleanup() this.abortController.abort() diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 9085728f..42b3f197 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -78,6 +78,21 @@ return } + if (url.host === "x-callback-url") { + if (url.pathname === "/authError") { + const errorMessage = url.searchParams.get("errorMessage") + + pushToast({ + theme: "error", + message: errorMessage || "Signer authorization failed.", + }) + } + + if (["/authSuccess", "/authError"].includes(url.pathname)) { + return + } + } + const target = `${url.pathname}${url.search}${url.hash}` goto(target, {replaceState: false, noScroll: false}) })