2023-06-30 14:05:57 +00:00
|
|
|
/** @jsx h */
|
2023-09-07 13:11:59 +00:00
|
|
|
import { Component, h } from "https://esm.sh/preact@10.17.1";
|
2023-06-30 14:05:57 +00:00
|
|
|
import { tw } from "https://esm.sh/twind@0.16.16";
|
2023-07-09 07:06:13 +00:00
|
|
|
import { GetLocalStorageAccountContext, Nip7ExtensionContext } from "./account-context.ts";
|
2023-06-30 14:05:57 +00:00
|
|
|
import { ButtonClass, CenterClass, DividerClass } from "./components/tw.ts";
|
|
|
|
import KeyView from "./key-view.tsx";
|
2023-08-28 17:58:05 +00:00
|
|
|
import { PrivateKey } from "../lib/nostr-ts/key.ts";
|
2023-09-07 13:11:59 +00:00
|
|
|
import { InMemoryAccountContext } from "../lib/nostr-ts/nostr.ts";
|
|
|
|
import { emitFunc, EventEmitter } from "../event-bus.ts";
|
2023-06-30 14:05:57 +00:00
|
|
|
|
|
|
|
export type SignInEvent = {
|
|
|
|
type: "signin";
|
|
|
|
privateKey?: PrivateKey; // undefined means sign in with extentions
|
|
|
|
} | {
|
|
|
|
type: "editSignInPrivateKey";
|
|
|
|
privateKey: string;
|
|
|
|
};
|
|
|
|
|
|
|
|
const AlbyURL = "https://getalby.com/";
|
|
|
|
|
|
|
|
type SignInState = "none" | "nip07" | "local";
|
|
|
|
|
|
|
|
export function getSignInState(): SignInState {
|
|
|
|
const state = localStorage.getItem("SignInState");
|
|
|
|
if (state === null) {
|
|
|
|
return "none";
|
|
|
|
}
|
|
|
|
return state as SignInState;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function setSignInState(state: SignInState) {
|
|
|
|
localStorage.setItem("SignInState", state);
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////
|
|
|
|
// Check Login Status //
|
|
|
|
////////////////////////
|
2023-07-09 08:06:49 +00:00
|
|
|
export async function getCurrentSignInCtx() {
|
2023-06-30 14:05:57 +00:00
|
|
|
if (getSignInState() === "nip07") {
|
2023-07-09 07:06:13 +00:00
|
|
|
const albyCtx = await Nip7ExtensionContext.New();
|
2023-06-30 14:05:57 +00:00
|
|
|
if (albyCtx instanceof Error) {
|
2023-07-09 12:43:03 +00:00
|
|
|
return albyCtx;
|
2023-06-30 14:05:57 +00:00
|
|
|
}
|
|
|
|
if (albyCtx === undefined) {
|
|
|
|
setSignInState("none");
|
|
|
|
}
|
|
|
|
return albyCtx;
|
|
|
|
}
|
|
|
|
if (getSignInState() === "local") {
|
|
|
|
const ctx = GetLocalStorageAccountContext();
|
|
|
|
if (ctx instanceof Error) {
|
|
|
|
throw ctx;
|
|
|
|
}
|
|
|
|
if (ctx === undefined) {
|
|
|
|
console.log("GetLocalStorageAccountContext is undefined");
|
|
|
|
setSignInState("none");
|
|
|
|
}
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function signInWithExtension() {
|
2023-07-09 07:06:13 +00:00
|
|
|
const albyCtx = await Nip7ExtensionContext.New();
|
2023-06-30 14:05:57 +00:00
|
|
|
if (albyCtx instanceof Error) {
|
|
|
|
return albyCtx;
|
|
|
|
}
|
|
|
|
if (albyCtx === undefined) {
|
|
|
|
open(AlbyURL);
|
|
|
|
}
|
|
|
|
return albyCtx;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function signInWithPrivateKey(privateKey: PrivateKey) {
|
|
|
|
const ctx = InMemoryAccountContext.New(privateKey);
|
|
|
|
if (ctx instanceof Error) {
|
|
|
|
throw ctx;
|
|
|
|
}
|
|
|
|
localStorage.setItem("MPK", privateKey.hex);
|
|
|
|
setSignInState("local");
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
2023-09-07 13:11:59 +00:00
|
|
|
type Props = {
|
|
|
|
eventBus: EventEmitter<SignInEvent>;
|
|
|
|
} & SignInModel;
|
|
|
|
|
|
|
|
export type SignInModel = {
|
|
|
|
privateKey: string;
|
|
|
|
warningString?: string;
|
|
|
|
};
|
|
|
|
|
|
|
|
type State = { state: "newAccount" | "enterPrivateKey" };
|
|
|
|
export class SignIn extends Component<Props, State> {
|
|
|
|
render() {
|
|
|
|
const props = this.props;
|
|
|
|
|
|
|
|
if (this.state.state == "newAccount") {
|
|
|
|
const privateKey = PrivateKey.Generate();
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
class={tw`fixed inset-0 bg-[#313338] flex items-center justify-center px-4`}
|
|
|
|
>
|
|
|
|
<div class={tw`flex flex-col w-[40rem]`}>
|
|
|
|
<KeyView
|
|
|
|
privateKey={privateKey}
|
|
|
|
publicKey={privateKey.toPublicKey()}
|
|
|
|
/>
|
|
|
|
<button
|
|
|
|
onClick={on_BackToSignInPage_click(this.setState.bind(this))}
|
|
|
|
class={tw`w-full mt-8 bg-[#404249] hover:bg-[#2B2D31] ${ButtonClass}`}
|
|
|
|
>
|
|
|
|
Back
|
|
|
|
</button>
|
|
|
|
<button
|
|
|
|
onClick={() => {
|
|
|
|
props.eventBus.emit({
|
|
|
|
type: "signin",
|
|
|
|
privateKey: privateKey,
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
class={tw`w-full mt-8 bg-[#ED4545] hover:bg-[#E03030] ${ButtonClass}`}
|
|
|
|
>
|
|
|
|
Sign In
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
let privateKey = PrivateKey.FromHex(props.privateKey);
|
|
|
|
if (privateKey instanceof Error) {
|
|
|
|
privateKey = PrivateKey.FromBech32(props.privateKey);
|
|
|
|
}
|
|
|
|
|
2023-06-30 14:05:57 +00:00
|
|
|
return (
|
|
|
|
<div
|
2023-09-07 13:11:59 +00:00
|
|
|
class={tw`h-screen w-screen bg-[#313338] flex items-center justify-center p-4 overflow-y-auto`}
|
2023-06-30 14:05:57 +00:00
|
|
|
>
|
2023-09-07 13:11:59 +00:00
|
|
|
<div class={tw`w-[40rem]`}>
|
|
|
|
<img
|
|
|
|
class={tw`w-32 h-32 mx-auto`}
|
|
|
|
src="logo.png"
|
|
|
|
alt="Logo"
|
|
|
|
/>
|
|
|
|
<h1
|
|
|
|
class={tw`text-[#F3F4EA] text-center text-[2rem]`}
|
|
|
|
>
|
|
|
|
Welcome to Blowater
|
|
|
|
</h1>
|
|
|
|
<input
|
|
|
|
onInput={on_EditSignInPrivateKey_clicked(props.eventBus.emit)}
|
|
|
|
placeholder="Input your private key here"
|
|
|
|
type="password"
|
|
|
|
class={tw`w-full px-4 py-2 focus-visible:outline-none rounded-lg mt-8`}
|
2023-06-30 14:05:57 +00:00
|
|
|
/>
|
2023-09-07 13:11:59 +00:00
|
|
|
{privateKey instanceof Error
|
|
|
|
? (
|
|
|
|
<p class={tw`text-[#F3F4EA] mt-2`}>
|
|
|
|
Private Key has to be 64 letters hex-decimal or 63 letters nsec string
|
|
|
|
</p>
|
|
|
|
)
|
|
|
|
: undefined}
|
2023-06-30 14:05:57 +00:00
|
|
|
<button
|
2023-09-07 13:11:59 +00:00
|
|
|
onClick={on_SignIn_clicked(privateKey, props.eventBus.emit)}
|
|
|
|
disabled={privateKey instanceof Error}
|
|
|
|
class={tw`w-full bg-[#2B2D31] hover:bg-[#404249] mt-4 disabled:bg-[#404249] ${ButtonClass}`}
|
2023-06-30 14:05:57 +00:00
|
|
|
>
|
2023-09-07 13:11:59 +00:00
|
|
|
Sign In
|
2023-06-30 14:05:57 +00:00
|
|
|
</button>
|
2023-09-07 13:11:59 +00:00
|
|
|
|
|
|
|
<div class={tw`h-16 w-full relative ${CenterClass}`}>
|
|
|
|
<div class={tw`${DividerClass}`}></div>
|
|
|
|
<div class={tw`absolute w-full h-full ${CenterClass}`}>
|
|
|
|
<span class={tw`bg-[#313338] px-2 text-[#F3F4EA]`}>Or you can</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
2023-06-30 14:05:57 +00:00
|
|
|
<button
|
|
|
|
onClick={() => {
|
|
|
|
props.eventBus.emit({
|
|
|
|
type: "signin",
|
|
|
|
});
|
|
|
|
}}
|
2023-09-07 13:11:59 +00:00
|
|
|
class={tw`${ButtonClass} ${CenterClass} w-full bg-[#F8C455] text-[#313338] hover:bg-[#FFDF6F] py-0`}
|
2023-06-30 14:05:57 +00:00
|
|
|
>
|
2023-09-07 13:11:59 +00:00
|
|
|
<img
|
|
|
|
class={tw`h-10`}
|
|
|
|
src="alby-logo.svg"
|
|
|
|
alt="Alby Logo"
|
|
|
|
/>
|
|
|
|
Sign in with Alby
|
2023-06-30 14:05:57 +00:00
|
|
|
</button>
|
2023-09-07 13:11:59 +00:00
|
|
|
<button
|
|
|
|
onClick={on_CreateAccount_clicked(this.setState.bind(this))}
|
|
|
|
class={tw`${ButtonClass} w-full bg-[#2B2D31] hover:bg-[#404249] mt-4`}
|
|
|
|
>
|
|
|
|
Create an account
|
|
|
|
</button>
|
|
|
|
|
|
|
|
{props.warningString
|
|
|
|
? <p class={tw`text-[#F3F4EA] mt-2`}>{props.warningString}</p>
|
|
|
|
: undefined}
|
2023-06-30 14:05:57 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
2023-09-07 13:11:59 +00:00
|
|
|
}
|
2023-06-30 14:05:57 +00:00
|
|
|
|
2023-09-07 13:11:59 +00:00
|
|
|
const on_CreateAccount_clicked = (setState: (state: State) => void) => () => {
|
|
|
|
setState({ state: "newAccount" });
|
|
|
|
};
|
2023-06-30 14:05:57 +00:00
|
|
|
|
2023-09-07 13:11:59 +00:00
|
|
|
const on_SignIn_clicked = (privateKey: PrivateKey | Error, emit: emitFunc<SignInEvent>) => () => {
|
|
|
|
if (privateKey instanceof PrivateKey) {
|
|
|
|
emit({
|
|
|
|
type: "signin",
|
|
|
|
privateKey: privateKey,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
2023-06-30 14:05:57 +00:00
|
|
|
|
2023-09-07 13:11:59 +00:00
|
|
|
const on_EditSignInPrivateKey_clicked =
|
|
|
|
(emit: emitFunc<SignInEvent>) => (e: h.JSX.TargetedEvent<HTMLInputElement, Event>) => {
|
|
|
|
emit({
|
|
|
|
type: "editSignInPrivateKey",
|
|
|
|
privateKey: e.currentTarget.value,
|
|
|
|
});
|
|
|
|
};
|
2023-06-30 14:05:57 +00:00
|
|
|
|
2023-09-07 13:11:59 +00:00
|
|
|
const on_BackToSignInPage_click = (setState: (state: State) => void) => () => {
|
|
|
|
setState({ state: "enterPrivateKey" });
|
|
|
|
};
|