Nip7os interface

Light theme tweaks
This commit is contained in:
Kieran 2023-08-29 14:55:30 +01:00
parent 8a3133af70
commit ec2b11bd75
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
9 changed files with 99 additions and 18 deletions

View File

@ -33,4 +33,4 @@ declare module "translations/*.json" {
declare module "emojilib" { declare module "emojilib" {
const value: Record<string, string>; const value: Record<string, string>;
export default value; export default value;
} }

View File

@ -36,6 +36,7 @@ export const ProxyImg = (props: ProxyImgProps) => {
<img <img
{...props} {...props}
src={props.src ? proxy(props.src, props.size) : ""} src={props.src ? proxy(props.src, props.size) : ""}
width={props.size} height={props.size}
onError={e => { onError={e => {
if (props.onError) { if (props.onError) {
props.onError(e); props.onError(e);

View File

@ -16,6 +16,7 @@ export default function useLoginHandler() {
defaultMessage: defaultMessage:
"Can't login with private key on an insecure connection, please use a Nostr key manager extension instead", "Can't login with private key on an insecure connection, please use a Nostr key manager extension instead",
}); });
// private key logins
if (key.startsWith("nsec")) { if (key.startsWith("nsec")) {
if (!hasSubtleCrypto) { if (!hasSubtleCrypto) {
throw new Error(insecureMsg); throw new Error(insecureMsg);
@ -26,12 +27,6 @@ export default function useLoginHandler() {
} else { } else {
throw new Error("INVALID PRIVATE KEY"); throw new Error("INVALID PRIVATE KEY");
} }
} else if (key.startsWith("npub")) {
const hexKey = bech32ToHex(key);
LoginStore.loginWithPubkey(hexKey, LoginSessionType.PublicKey);
} else if (key.match(EmailRegex)) {
const hexKey = await getNip05PubKey(key);
LoginStore.loginWithPubkey(hexKey, LoginSessionType.PublicKey);
} else if (key.match(MnemonicRegex)?.length === 24) { } else if (key.match(MnemonicRegex)?.length === 24) {
if (!hasSubtleCrypto) { if (!hasSubtleCrypto) {
throw new Error(insecureMsg); throw new Error(insecureMsg);
@ -44,6 +39,15 @@ export default function useLoginHandler() {
throw new Error(insecureMsg); throw new Error(insecureMsg);
} }
LoginStore.loginWithPrivateKey(key); LoginStore.loginWithPrivateKey(key);
}
// public key logins
if (key.startsWith("npub")) {
const hexKey = bech32ToHex(key);
LoginStore.loginWithPubkey(hexKey, LoginSessionType.PublicKey);
} else if (key.match(EmailRegex)) {
const hexKey = await getNip05PubKey(key);
LoginStore.loginWithPubkey(hexKey, LoginSessionType.PublicKey);
} else if (key.startsWith("bunker://")) { } else if (key.startsWith("bunker://")) {
const nip46 = new Nip46Signer(key); const nip46 = new Nip46Signer(key);
await nip46.init(); await nip46.init();

View File

@ -15,6 +15,7 @@ export enum LoginSessionType {
PublicKey = "public_key", PublicKey = "public_key",
Nip7 = "nip7", Nip7 = "nip7",
Nip46 = "nip46", Nip46 = "nip46",
Nip7os = "nip7_os"
} }
export interface LoginSession { export interface LoginSession {

View File

@ -7,6 +7,7 @@ import { deepClone, sanitizeRelayUrl, unwrap, ExternalStore } from "@snort/share
import { DefaultRelays } from "Const"; import { DefaultRelays } from "Const";
import { LoginSession, LoginSessionType } from "Login"; import { LoginSession, LoginSessionType } from "Login";
import { DefaultPreferences, UserPreferences } from "./Preferences"; import { DefaultPreferences, UserPreferences } from "./Preferences";
import { Nip7OsSigner } from "./Nip7OsSigner";
const AccountStoreKey = "sessions"; const AccountStoreKey = "sessions";
const LoggedOut = { const LoggedOut = {
@ -146,6 +147,12 @@ export class MultiAccountStore extends ExternalStore<LoginSession> {
}, },
preferences: deepClone(DefaultPreferences), preferences: deepClone(DefaultPreferences),
} as LoginSession; } as LoginSession;
if("nostr_os" in window && window.nostr_os) {
window.nostr_os.saveKey(key);
newSession.type = LoginSessionType.Nip7os;
newSession.privateKey = undefined;
}
newSession.publisher = this.#createPublisher(newSession); newSession.publisher = this.#createPublisher(newSession);
this.#accounts.set(pubKey, newSession); this.#accounts.set(pubKey, newSession);
@ -190,6 +197,9 @@ export class MultiAccountStore extends ExternalStore<LoginSession> {
const nip46 = new Nip46Signer(`bunker://${unwrap(l.publicKey)}?${[...relayArgs].join("&")}`, inner); const nip46 = new Nip46Signer(`bunker://${unwrap(l.publicKey)}?${[...relayArgs].join("&")}`, inner);
return new EventPublisher(nip46, unwrap(l.publicKey)); return new EventPublisher(nip46, unwrap(l.publicKey));
} }
case LoginSessionType.Nip7os: {
return new EventPublisher(new Nip7OsSigner(), unwrap(l.publicKey));
}
default: { default: {
if (l.publicKey) { if (l.publicKey) {
return new EventPublisher(new Nip7Signer(), l.publicKey); return new EventPublisher(new Nip7Signer(), l.publicKey);

View File

@ -0,0 +1,44 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { EventSigner, NostrEvent } from "@snort/system";
import { Nip7os } from "Login";
export class Nip7OsSigner implements EventSigner {
#interface: Nip7os;
constructor() {
if("nostr_os" in window && window.nostr_os) {
this.#interface = window.nostr_os;
} else {
throw new Error("Nost OS extension not available")
}
}
init(): Promise<void> {
return Promise.resolve();
}
getPubKey(): string | Promise<string> {
return this.#interface.getPublicKey();
}
nip4Encrypt(content: string, key: string): Promise<string> {
return Promise.resolve(this.#interface.nip04_encrypt(content, key));
}
nip4Decrypt(content: string, otherKey: string): Promise<string> {
return Promise.resolve(this.#interface.nip04_decrypt(content, otherKey));
}
nip44Encrypt(content: string, key: string): Promise<string> {
throw new Error("Method not implemented.");
}
nip44Decrypt(content: string, otherKey: string): Promise<string> {
throw new Error("Method not implemented.");
}
sign(ev: NostrEvent): Promise<NostrEvent> {
const ret = this.#interface.signEvent(JSON.stringify(ev));
return Promise.resolve(JSON.parse(ret) as NostrEvent);
}
}

View File

@ -1,6 +1,20 @@
import { MultiAccountStore } from "./MultiAccountStore"; import { MultiAccountStore } from "./MultiAccountStore";
export const LoginStore = new MultiAccountStore(); export const LoginStore = new MultiAccountStore();
export interface Nip7os {
getPublicKey: () => string
signEvent: (ev: string) => string
saveKey: (key: string) => void
nip04_encrypt: (content:string, to: string) => string
nip04_decrypt: (content:string, from: string) => string
}
declare global {
interface Window {
nostr_os?: Nip7os;
}
}
export * from "./Preferences"; export * from "./Preferences";
export * from "./LoginSession"; export * from "./LoginSession";
export * from "./Functions"; export * from "./Functions";

View File

@ -8,7 +8,7 @@ import { hexToBech32 } from "SnortUtils";
import { hexToMnemonic } from "nip6"; import { hexToMnemonic } from "nip6";
import useLogin from "Hooks/useLogin"; import useLogin from "Hooks/useLogin";
import { PROFILE } from "."; import { PROFILE } from ".";
import { DefaultPreferences, updatePreferences } from "Login"; import { DefaultPreferences, LoginStore, updatePreferences } from "Login";
import { AllLanguageCodes } from "Pages/settings/Preferences"; import { AllLanguageCodes } from "Pages/settings/Preferences";
import messages from "./messages"; import messages from "./messages";
@ -136,7 +136,13 @@ export default function NewUserFlow() {
</h2> </h2>
<Copy text={hexToMnemonic(login.generatedEntropy ?? "")} /> <Copy text={hexToMnemonic(login.generatedEntropy ?? "")} />
<div className="next-actions"> <div className="next-actions">
<button type="button" onClick={() => navigate(PROFILE)}> <button type="button" onClick={() => {
LoginStore.updateSession({
...login,
generatedEntropy: undefined
})
navigate(PROFILE)
}}>
<FormattedMessage {...messages.KeysSaved} />{" "} <FormattedMessage {...messages.KeysSaved} />{" "}
</button> </button>
</div> </div>

View File

@ -3,7 +3,7 @@
--font-color: #fff; --font-color: #fff;
--font-secondary-color: #a7a7a7; --font-secondary-color: #a7a7a7;
--font-tertiary-color: #a3a3a3; --font-tertiary-color: #a3a3a3;
--border-color: rgba(163, 163, 163, 0.3); --border-color: var(--gray-superdark);
--font-size: 15px; --font-size: 15px;
--font-size-small: 13px; --font-size-small: 13px;
--font-size-tiny: 11px; --font-size-tiny: 11px;
@ -71,21 +71,22 @@ html {
html.light { html.light {
--bg-color: #f8f8f8; --bg-color: #f8f8f8;
--font-color: #27272a; --font-color: #2F3F64;
--font-secondary-color: #71717a; --font-secondary-color: #71717a;
--font-tertiary-color: #52525b; --font-tertiary-color: #52525b;
--border-color: rgba(167, 167, 167, 0.3); --border-color: #DEE1E8;
--highlight: #7139f1; --highlight: #7139f1;
--modal-bg-color: rgba(240, 240, 240, 0.8); --modal-bg-color: rgba(240, 240, 240, 0.8);
--gray: #aaa; --gray: #999;
--gray-secondary: #bbb; --gray-secondary: #aaa;
--gray-tertiary: #ccc; --gray-tertiary: #bbb;
--gray-superlight: #333; --gray-superlight: #333;
--gray-light: #555; --gray-light: #555;
--gray-dark: #2b2b2b; --gray-dark: #ccc;
--gray-superdark: #eee; --gray-superdark: #ddd;
--gray-ultradark: #eee;
--dm-gradient: var(--gray); --dm-gradient: var(--gray);
--invoice-gradient: linear-gradient(45deg, var(--gray-superdark) 50%, #f7b73333, #fc4a1a33); --invoice-gradient: linear-gradient(45deg, var(--gray-superdark) 50%, #f7b73333, #fc4a1a33);
@ -125,7 +126,7 @@ code {
} }
.main-content { .main-content {
border: 1px solid var(--gray-superdark); border: 1px solid var(--border-color);
} }
} }