1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
import { PUBLIC_DOMAIN } from "$env/static/public";
import { decode } from "$lib/bip21";
import { auth, get, isLiquid, post, sats } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
let validatePromise: Promise<typeof import("bitcoin-address-validation")> | undefined;
const loadValidate = () => (validatePromise ||= import("bitcoin-address-validation"));
export default async (s, host, cookies) => {
if (!s) return;
let t = s.trim();
let amount;
let invoice;
let user;
const aid = cookies.get("aid");
if (t.startsWith("ark") || t.startsWith("tark")) redirect(303, `/send/ark/${t}${aid ? `?aid=${aid}` : ""}`);
if (t.startsWith("http")) redirect(303, t);
if (t.startsWith(host)) redirect(303, `http://${t}`);
if (t.includes("lightning=")) {
const url = new URL(t);
const params = new URLSearchParams(url.search);
t = params.get("lightning");
}
if (t.startsWith("lightning:")) t = t.replace("lightning:", "");
if (t.includes("@") && t.split("@").pop() === PUBLIC_DOMAIN) t = t.split("@")[0];
if (t.includes("@") && t.includes(".")) {
try {
t = await get(`/encode?address=${t}`);
} catch {}
}
if (t.toLowerCase().startsWith("nostr:")) {
t = t.split(":")[1];
}
if (["note", "nevent"].some((p) => t.startsWith(p))) redirect(303, `/e/${t}`);
if (["nprofile", "npub"].some((p) => t.startsWith(p))) redirect(303, `/${t}`);
// bitcoin
if (t.toLowerCase().startsWith("bitcoin:") || t.toLowerCase().startsWith("liquidnetwork:")) {
const { address: addr, options } = decode(t);
amount = options.amount;
if (options.ark) {
let r = `/send/ark/${options.ark}`;
if (amount) r += `/${Math.round(Number(amount) * sats)}`;
redirect(303, r);
}
t = addr;
}
const { validate } = await loadValidate();
if (validate(t) || isLiquid(t) || t.startsWith("bcrt1")) {
let r = `/send/bitcoin/${t}`;
if (amount) r += `/${Math.round(amount * sats)}`;
redirect(303, r);
}
// lightning
if (t.toLowerCase().startsWith("lightning:")) t = t.toLowerCase().replace("lightning:", "");
if (t.toLowerCase().startsWith("lnurl")) redirect(303, `/ln/${t}`);
if (t.includes(":")) t = t.split(":")[1];
if (t.toLowerCase().startsWith("lnr")) {
const { iid } = await post("/sendinvoice", { invreq: t }, auth(cookies));
invoice = { id: iid };
} else if (t.toLowerCase().startsWith("ln")) {
try {
const aid = cookies.get("aid");
invoice = await get(`/invoice/${t}`);
if (invoice.user.username === "mint") throw new Error("mint payment");
if (aid && aid !== invoice.aid) throw new Error("cross-account");
} catch {
if (t.toLowerCase().startsWith("lno")) {
const { offer_amount_msat: a } = await get(`/decode/${t}`);
if (a) ({ invoice: t } = await post("/fetchinvoice", { offer: t }));
}
redirect(303, `/send/lightning/${t}`);
}
}
if (invoice) redirect(303, `/invoice/${invoice.id}`);
if (t.match(/^🥜([\uFE00-\uFE0F]|[\uE0100-\uE01EF]+)$/)) {
t = (Array.from(t) as string[])
.slice(1)
.map((char: string) => {
const codePoint = char.codePointAt(0)!;
// Handle Variation Selectors (VS1-VS16): U+FE00 to U+FE0F
if (codePoint >= 0xfe00 && codePoint <= 0xfe0f) {
const byteValue = codePoint - 0xfe00; // Maps FE00->0, FE01->1, ..., FE0F->15
return String.fromCharCode(byteValue);
}
// Handle Variation Selectors Supplement (VS17-VS256): U+E0100 to U+E01EF
if (codePoint >= 0xe0100 && codePoint <= 0xe01ef) {
const byteValue = codePoint - 0xe0100 + 16; // Maps E0100->16, E0101->17, ..., E01EF->255
return String.fromCharCode(byteValue);
}
})
.join("");
}
if (t.startsWith("cashu")) {
const { id } = await post("/cash", { token: t });
redirect(303, `/ecash/${id}`);
}
if (t.startsWith("creq")) redirect(303, `/send/ecash/${t}`);
// user
try {
user = await get(`/users/${t.split("/")[0]}`);
if (user.anon) user = null;
} catch {}
if (user) redirect(303, `/pay/${t}`);
let fund;
if (t.includes("/fund")) redirect(303, t.substring(t.indexOf("/fund")));
try {
fund = await get(`/fund/${t}`);
} catch {}
if (fund) redirect(303, `/send/fund/${t}`);
};
|