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})
})