snort/packages/app/src/Pages/settings/wallet/Alby.tsx

95 lines
2.9 KiB
TypeScript
Raw Normal View History

2024-01-03 16:46:18 +00:00
import PageSpinner from "@/Element/PageSpinner";
import { sha256 } from "@noble/hashes/sha256";
import { randomBytes } from "@noble/hashes/utils";
import { base64, base64urlnopad, hex } from "@scure/base";
import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
export default function AlbyOAuth() {
2024-01-03 16:49:44 +00:00
const location = useLocation();
const alby = getAlbyOAuth();
const [error, setError] = useState("");
2024-01-03 16:46:18 +00:00
2024-01-03 16:49:44 +00:00
async function setupWallet(token: string) {
const auth = await alby.getToken(token);
console.debug(auth);
}
2024-01-03 16:46:18 +00:00
2024-01-03 16:49:44 +00:00
useEffect(() => {
if (location.search) {
const params = new URLSearchParams(location.search);
const token = params.get("code");
if (token) {
setupWallet(token).catch(e => {
setError((e as Error).message);
});
}
}
}, [location]);
2024-01-03 16:46:18 +00:00
2024-01-03 16:49:44 +00:00
if (!location.search) return;
return (
<>
<h1>Alby Wallet Connection</h1>
{!error && <PageSpinner />}
{error && <b className="warning">{error}</b>}
2024-01-03 16:46:18 +00:00
</>
2024-01-03 16:49:44 +00:00
);
2024-01-03 16:46:18 +00:00
}
export function getAlbyOAuth() {
2024-01-03 16:49:44 +00:00
const clientId = "35EQp6crss";
const clientSecret = "DTUPIqOjsjwxZXcJwF5C";
const redirectUrl = `${window.location.protocol}//${window.location.host}/settings/wallet/alby`;
const scopes = ["invoices:create", "invoices:read", "transactions:read", "balance:read", "payments:send"];
2024-01-03 16:46:18 +00:00
2024-01-03 16:49:44 +00:00
const ec = new TextEncoder();
const code_verifier = hex.encode(randomBytes(64));
window.sessionStorage.setItem("alby-code", code_verifier);
2024-01-03 16:46:18 +00:00
2024-01-03 16:49:44 +00:00
const params = new URLSearchParams();
params.set("client_id", clientId);
params.set("response_type", "code");
params.set("code_challenge", base64urlnopad.encode(sha256(code_verifier)));
params.set("code_challenge_method", "S256");
params.set("redirect_uri", redirectUrl);
params.set("scope", scopes.join(" "));
2024-01-03 16:46:18 +00:00
2024-01-03 16:49:44 +00:00
const tokenUrl = "https://api.getalby.com/oauth/token";
const authUrl = `https://getalby.com/oauth?${params}`;
2024-01-03 16:46:18 +00:00
2024-01-03 16:49:44 +00:00
return {
tokenUrl,
authUrl,
getToken: async (token: string) => {
const code = window.sessionStorage.getItem("alby-code");
if (!code) throw new Error("Alby code is missing!");
window.sessionStorage.removeItem("alby-code");
2024-01-03 16:46:18 +00:00
2024-01-03 16:49:44 +00:00
const form = new URLSearchParams();
form.set("client_id", clientId);
form.set("code_verifier", code);
form.set("grant_type", "authorization_code");
form.set("redirect_uri", redirectUrl);
form.set("code", token);
2024-01-03 16:46:18 +00:00
2024-01-03 16:49:44 +00:00
const req = await fetch(tokenUrl, {
method: "POST",
headers: {
accept: "application/json",
"content-type": "application/x-www-form-urlencoded",
authorization: `Basic ${base64.encode(ec.encode(`${clientId}:${clientSecret}`))}`,
},
body: form,
});
2024-01-03 16:46:18 +00:00
2024-01-03 16:49:44 +00:00
const data = await req.json();
if (req.ok) {
return data.access_token as string;
} else {
throw new Error(data.error_description as string);
}
},
};
}