Add name processing for signup, add pow to nip98 and to sendName, minor UI changes
This commit is contained in:
parent
9c18310fd9
commit
5b57b42111
2
.env
2
.env
@ -2,5 +2,5 @@
|
||||
# change if you're using a different noauthd server
|
||||
REACT_APP_WEB_PUSH_PUBKEY=BNW_39YcKbV4KunFxFhvMW5JUs8AljfFnGUeZpaerO-gwCoWyQat5ol0xOGB8MLaqqCbz0iptd2Qv3SToSGynMk
|
||||
#REACT_APP_NOAUTHD_URL=http://localhost:8000
|
||||
REACT_APP_NOAUTHD_URL=https://noauthd.login.nostrapps.org
|
||||
REACT_APP_NOAUTHD_URL=https://noauthd.nsec.app
|
||||
REACT_APP_DOMAIN=nsec.app
|
@ -28,7 +28,8 @@ export const ModalImportKeys = () => {
|
||||
e.preventDefault()
|
||||
try {
|
||||
if (!enteredNsec.trim().length) return
|
||||
const k: any = await swicCall('importKey', enteredNsec)
|
||||
const enteredName = '' // FIXME get from input
|
||||
const k: any = await swicCall('importKey', enteredName, enteredNsec)
|
||||
notify('Key imported!', 'success')
|
||||
navigate(`/key/${k.npub}`)
|
||||
} catch (error: any) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { useEnqueueSnackbar } from '@/hooks/useEnqueueSnackbar'
|
||||
import { useModalSearchParams } from '@/hooks/useModalSearchParams'
|
||||
import { swicCall } from '@/modules/swic'
|
||||
@ -6,7 +6,6 @@ import { Modal } from '@/shared/Modal/Modal'
|
||||
import { MODAL_PARAMS_KEYS } from '@/types/modal'
|
||||
import { IconButton, Stack, Typography } from '@mui/material'
|
||||
import { StyledAppLogo } from './styled'
|
||||
import { nip19 } from 'nostr-tools'
|
||||
import { Input } from '@/shared/Input/Input'
|
||||
import { Button } from '@/shared/Button/Button'
|
||||
import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined'
|
||||
@ -15,6 +14,8 @@ import { useNavigate } from 'react-router-dom'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { FormInputType, schema } from './const'
|
||||
import { yupResolver } from '@hookform/resolvers/yup'
|
||||
import { DOMAIN } from '@/utils/consts'
|
||||
import { fetchNip05 } from '@/utils/helpers/helpers'
|
||||
|
||||
export const ModalLogin = () => {
|
||||
const { getModalOpened, createHandleCloseReplace } = useModalSearchParams()
|
||||
@ -51,18 +52,15 @@ export const ModalLogin = () => {
|
||||
|
||||
const submitHandler = async (values: FormInputType) => {
|
||||
try {
|
||||
const [username, domain] = values.username.split('@')
|
||||
const response = await fetch(
|
||||
`https://${domain}/.well-known/nostr.json?name=${username}`,
|
||||
)
|
||||
const getNpub: {
|
||||
names: {
|
||||
[name: string]: string
|
||||
}
|
||||
} = await response.json()
|
||||
|
||||
const pubkey = getNpub.names[username]
|
||||
const npub = nip19.npubEncode(pubkey)
|
||||
let npub = values.username
|
||||
if (!npub.startsWith('npub1') && !npub.includes('@')) {
|
||||
npub += '@' + DOMAIN
|
||||
}
|
||||
if (npub.includes('@')) {
|
||||
const npubNip05 = await fetchNip05(npub)
|
||||
if (!npubNip05) throw new Error(`Username ${npub} not found`)
|
||||
npub = npubNip05
|
||||
}
|
||||
const passphrase = values.password
|
||||
|
||||
console.log('fetch', npub, passphrase)
|
||||
@ -103,9 +101,9 @@ export const ModalLogin = () => {
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Input
|
||||
label='Enter a Username'
|
||||
label='Username or nip05 or npub'
|
||||
fullWidth
|
||||
placeholder='user@nsec.app'
|
||||
placeholder='name or name@domain.com or npub1...'
|
||||
{...register('username')}
|
||||
error={!!errors.username}
|
||||
/>
|
||||
@ -130,7 +128,7 @@ export const ModalLogin = () => {
|
||||
error={!!errors.password}
|
||||
/>
|
||||
<Button type='submit' fullWidth>
|
||||
Login
|
||||
Add account
|
||||
</Button>
|
||||
</Stack>
|
||||
</Modal>
|
||||
|
@ -10,6 +10,8 @@ import { Button } from '@/shared/Button/Button'
|
||||
import { CheckmarkIcon } from '@/assets'
|
||||
import { swicCall } from '@/modules/swic'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { DOMAIN, NOAUTHD_URL } from '@/utils/consts'
|
||||
import { fetchNip05 } from '@/utils/helpers/helpers'
|
||||
|
||||
export const ModalSignUp = () => {
|
||||
const { getModalOpened, createHandleCloseReplace } = useModalSearchParams()
|
||||
@ -21,27 +23,41 @@ export const ModalSignUp = () => {
|
||||
const navigate = useNavigate()
|
||||
|
||||
const [enteredValue, setEnteredValue] = useState('')
|
||||
const [isAvailable, setIsAvailable] = useState(false)
|
||||
|
||||
const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const handleInputChange = async (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setEnteredValue(e.target.value)
|
||||
const name = e.target.value.trim()
|
||||
if (name) {
|
||||
const npubNip05 = await fetchNip05(`${name}@${DOMAIN}`)
|
||||
setIsAvailable(!npubNip05)
|
||||
} else {
|
||||
setIsAvailable(false)
|
||||
}
|
||||
}
|
||||
|
||||
const isAvailable = enteredValue.trim().length > 2
|
||||
|
||||
const inputHelperText = isAvailable ? (
|
||||
<>
|
||||
<CheckmarkIcon /> Available
|
||||
</>
|
||||
const inputHelperText = enteredValue
|
||||
? (
|
||||
isAvailable ? (
|
||||
<>
|
||||
<CheckmarkIcon /> Available
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
Already taken
|
||||
</>
|
||||
)
|
||||
) : (
|
||||
"Don't worry, username can be changed later."
|
||||
)
|
||||
);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
if (!enteredValue.trim().length) return
|
||||
const name = enteredValue.trim()
|
||||
if (!name.length) return
|
||||
e.preventDefault()
|
||||
try {
|
||||
const k: any = await swicCall('generateKey')
|
||||
notify(`New key ${k.npub}`, 'success')
|
||||
const k: any = await swicCall('generateKey', name)
|
||||
notify(`Account created for "${name}"`, 'success')
|
||||
navigate(`/key/${k.npub}`)
|
||||
} catch (error: any) {
|
||||
notify(error.message, 'error')
|
||||
@ -73,22 +89,26 @@ export const ModalSignUp = () => {
|
||||
placeholder='Username'
|
||||
helperText={inputHelperText}
|
||||
endAdornment={
|
||||
<Typography color={'#FFFFFFA8'}>@nsec.app</Typography>
|
||||
<Typography color={'#FFFFFFA8'}>@{DOMAIN}</Typography>
|
||||
}
|
||||
onChange={handleInputChange}
|
||||
value={enteredValue}
|
||||
helperTextProps={{
|
||||
sx: {
|
||||
'&.helper_text': {
|
||||
color: isAvailable
|
||||
color: enteredValue && isAvailable
|
||||
? theme.palette.success.main
|
||||
: theme.palette.textSecondaryDecorate.main,
|
||||
: (enteredValue && !isAvailable
|
||||
? theme.palette.error.main
|
||||
: theme.palette.textSecondaryDecorate.main
|
||||
)
|
||||
,
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Button fullWidth type='submit'>
|
||||
Sign up
|
||||
Create account
|
||||
</Button>
|
||||
</Stack>
|
||||
</Modal>
|
||||
|
@ -8,9 +8,10 @@ import NDK, {
|
||||
NDKPrivateKeySigner,
|
||||
NDKSigner,
|
||||
} from '@nostr-dev-kit/ndk'
|
||||
import { NOAUTHD_URL, WEB_PUSH_PUBKEY, NIP46_RELAYS } from '../utils/consts'
|
||||
import { NOAUTHD_URL, WEB_PUSH_PUBKEY, NIP46_RELAYS, MIN_POW, MAX_POW } from '../utils/consts'
|
||||
import { Nip04 } from './nip04'
|
||||
import { getReqPerm, getShortenNpub, isPackagePerm } from '@/utils/helpers/helpers'
|
||||
import { NostrPowEvent, minePow } from './pow'
|
||||
//import { PrivateKeySigner } from './signer'
|
||||
|
||||
//const PERF_TEST = false
|
||||
@ -286,7 +287,8 @@ export class NoauthBackend {
|
||||
})
|
||||
if (r.status !== 200 && r.status !== 201) {
|
||||
console.log('Fetch error', url, method, r.status)
|
||||
throw new Error('Failed to fetch ' + url)
|
||||
const body = await r.json()
|
||||
throw new Error('Failed to fetch ' + url, { cause: body })
|
||||
}
|
||||
|
||||
return await r.json()
|
||||
@ -297,11 +299,13 @@ export class NoauthBackend {
|
||||
url,
|
||||
method = 'GET',
|
||||
body = '',
|
||||
pow = 0
|
||||
}: {
|
||||
npub: string
|
||||
url: string
|
||||
method: string
|
||||
body: string
|
||||
pow?: number
|
||||
}) {
|
||||
const { data: pubkey } = nip19.decode(npub)
|
||||
|
||||
@ -320,6 +324,15 @@ export class NoauthBackend {
|
||||
})
|
||||
if (body) authEvent.tags.push(['payload', await this.sha256(body)])
|
||||
|
||||
// generate pow on auth evevnt
|
||||
if (pow) {
|
||||
const start = Date.now()
|
||||
const powEvent: NostrPowEvent = authEvent.rawEvent()
|
||||
const minedEvent = minePow(powEvent, pow)
|
||||
console.log("mined pow of", pow, "in", Date.now() - start, "ms", minedEvent)
|
||||
authEvent.tags = minedEvent.tags
|
||||
}
|
||||
|
||||
authEvent.sig = await authEvent.sign(key.signer)
|
||||
|
||||
const auth = this.swg.btoa(JSON.stringify(authEvent.rawEvent()))
|
||||
@ -354,6 +367,7 @@ export class NoauthBackend {
|
||||
body,
|
||||
})
|
||||
}
|
||||
|
||||
private async sendKeyToServer(npub: string, enckey: string, pwh: string) {
|
||||
const body = JSON.stringify({
|
||||
npub,
|
||||
@ -389,6 +403,38 @@ export class NoauthBackend {
|
||||
})
|
||||
}
|
||||
|
||||
private async sendNameToServer(npub: string, name: string) {
|
||||
const body = JSON.stringify({
|
||||
npub,
|
||||
name
|
||||
})
|
||||
|
||||
const method = 'POST'
|
||||
const url = `${NOAUTHD_URL}/name`
|
||||
|
||||
// mas pow should be 21 or something like that
|
||||
let pow = MIN_POW;
|
||||
while(pow <= MAX_POW) {
|
||||
console.log("Try name", name, "pow", pow);
|
||||
try {
|
||||
return await this.sendPostAuthd({
|
||||
npub,
|
||||
url,
|
||||
method,
|
||||
body,
|
||||
pow
|
||||
})
|
||||
} catch (e: any) {
|
||||
console.log("error", e.cause);
|
||||
if (e.cause && e.cause.minPow > pow)
|
||||
pow = e.cause.minPow
|
||||
else
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
throw new Error("Too many requests, retry later")
|
||||
}
|
||||
|
||||
private notify() {
|
||||
// FIXME collect info from accessBuffer and confirmBuffer
|
||||
// and update the notifications
|
||||
@ -475,7 +521,11 @@ export class NoauthBackend {
|
||||
return generatePrivateKey()
|
||||
}
|
||||
|
||||
public async addKey(nsec?: string): Promise<KeyInfo> {
|
||||
public async addKey(name: string, nsec?: string): Promise<KeyInfo> {
|
||||
|
||||
// lowercase
|
||||
name = name.trim().toLocaleLowerCase()
|
||||
|
||||
let sk = ''
|
||||
if (nsec) {
|
||||
const { type, data } = nip19.decode(nsec)
|
||||
@ -486,14 +536,22 @@ export class NoauthBackend {
|
||||
}
|
||||
const pubkey = getPublicKey(sk)
|
||||
const npub = nip19.npubEncode(pubkey)
|
||||
|
||||
const localKey = await this.keysModule.generateLocalKey()
|
||||
const enckey = await this.keysModule.encryptKeyLocal(sk, localKey)
|
||||
// @ts-ignore
|
||||
const dbKey: DbKey = { npub, enckey, localKey }
|
||||
const dbKey: DbKey = { npub, name, enckey, localKey }
|
||||
await dbi.addKey(dbKey)
|
||||
this.enckeys.push(dbKey)
|
||||
await this.startKey({ npub, sk })
|
||||
|
||||
// assign nip05 before adding the key
|
||||
// FIXME set name to db and if this call to 'send' fails
|
||||
// then retry later
|
||||
console.log("adding key", npub, name)
|
||||
if (name)
|
||||
await this.sendNameToServer(npub, name)
|
||||
|
||||
const sub = await this.swg.registration.pushManager.getSubscription()
|
||||
if (sub) await this.sendSubscriptionToServer(npub, sub)
|
||||
|
||||
@ -766,14 +824,14 @@ export class NoauthBackend {
|
||||
await this.startKey({ npub, sk })
|
||||
}
|
||||
|
||||
private async generateKey() {
|
||||
const k = await this.addKey()
|
||||
private async generateKey(name: string) {
|
||||
const k = await this.addKey(name)
|
||||
this.updateUI()
|
||||
return k
|
||||
}
|
||||
|
||||
private async importKey(nsec: string) {
|
||||
const k = await this.addKey(nsec)
|
||||
private async importKey(name: string, nsec: string) {
|
||||
const k = await this.addKey(name, nsec)
|
||||
this.updateUI()
|
||||
return k
|
||||
}
|
||||
@ -879,9 +937,9 @@ export class NoauthBackend {
|
||||
//console.log("UI message", id, method, args)
|
||||
let result = undefined
|
||||
if (method === 'generateKey') {
|
||||
result = await this.generateKey()
|
||||
result = await this.generateKey(args[0])
|
||||
} else if (method === 'importKey') {
|
||||
result = await this.importKey(args[0])
|
||||
result = await this.importKey(args[0], args[1])
|
||||
} else if (method === 'saveKey') {
|
||||
result = await this.saveKey(args[0], args[1])
|
||||
} else if (method === 'fetchKey') {
|
||||
@ -902,6 +960,7 @@ export class NoauthBackend {
|
||||
result,
|
||||
})
|
||||
} catch (e: any) {
|
||||
console.log("backend error", e)
|
||||
event.source.postMessage({
|
||||
id,
|
||||
error: e.toString(),
|
||||
|
51
src/modules/pow.ts
Normal file
51
src/modules/pow.ts
Normal file
@ -0,0 +1,51 @@
|
||||
// based on https://git.v0l.io/Kieran/snort/src/branch/main/packages/system/src/pow-util.ts
|
||||
|
||||
import { sha256 } from "@noble/hashes/sha256";
|
||||
import { bytesToHex } from "@noble/hashes/utils";
|
||||
|
||||
export interface NostrPowEvent {
|
||||
id?: string;
|
||||
pubkey: string;
|
||||
created_at: number;
|
||||
kind?: number;
|
||||
tags: Array<Array<string>>;
|
||||
content: string;
|
||||
sig?: string;
|
||||
}
|
||||
|
||||
export function minePow(e: NostrPowEvent, target: number) {
|
||||
let ctr = 0;
|
||||
|
||||
let nonceTagIdx = e.tags.findIndex(a => a[0] === "nonce");
|
||||
if (nonceTagIdx === -1) {
|
||||
nonceTagIdx = e.tags.length;
|
||||
e.tags.push(["nonce", ctr.toString(), target.toString()]);
|
||||
}
|
||||
do {
|
||||
e.tags[nonceTagIdx][1] = (++ctr).toString();
|
||||
e.id = createId(e);
|
||||
} while (countLeadingZeros(e.id) < target);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
function createId(e: NostrPowEvent) {
|
||||
const payload = [0, e.pubkey, e.created_at, e.kind, e.tags, e.content];
|
||||
return bytesToHex(sha256(JSON.stringify(payload)));
|
||||
}
|
||||
|
||||
export function countLeadingZeros(hex: string) {
|
||||
let count = 0;
|
||||
|
||||
for (let i = 0; i < hex.length; i++) {
|
||||
const nibble = parseInt(hex[i], 16);
|
||||
if (nibble === 0) {
|
||||
count += 4;
|
||||
} else {
|
||||
count += Math.clz32(nibble) - 28;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
@ -24,7 +24,7 @@ const HomePage = () => {
|
||||
return (
|
||||
<Stack maxHeight={'100%'} overflow={'auto'}>
|
||||
<SectionTitle marginBottom={'0.5rem'}>
|
||||
{isNoKeys ? 'Welcome' : 'Keys:'}
|
||||
{isNoKeys ? 'Welcome' : 'Accounts:'}
|
||||
</SectionTitle>
|
||||
<Stack gap={'0.5rem'} overflow={'auto'}>
|
||||
{isNoKeys && (
|
||||
|
@ -18,18 +18,22 @@ import UserValueSection from './components/UserValueSection'
|
||||
import { useTriggerConfirmModal } from './hooks/useTriggerConfirmModal'
|
||||
import { useLiveQuery } from 'dexie-react-hooks'
|
||||
import { checkNpubSyncQuerier } from './utils'
|
||||
import { DOMAIN } from '@/utils/consts'
|
||||
|
||||
const KeyPage = () => {
|
||||
const { npub = '' } = useParams<{ npub: string }>()
|
||||
const { apps, pending, perms } = useAppSelector((state) => state.content)
|
||||
const { keys, apps, pending, perms } = useAppSelector((state) => state.content)
|
||||
const isSynced = useLiveQuery(checkNpubSyncQuerier(npub), [npub], false)
|
||||
|
||||
const { handleOpen } = useModalSearchParams()
|
||||
|
||||
const { userNameWithPrefix } = useProfile(npub)
|
||||
// const { userNameWithPrefix } = useProfile(npub)
|
||||
const { handleEnableBackground, showWarning, isEnabling } =
|
||||
useBackgroundSigning()
|
||||
|
||||
const key = keys.find(k => k.npub === npub)
|
||||
const username = key?.name ? `${key?.name}@${DOMAIN}` : ''
|
||||
|
||||
const filteredApps = apps.filter((a) => a.npub === npub)
|
||||
const { prepareEventPendings } = useTriggerConfirmModal(
|
||||
npub,
|
||||
@ -53,8 +57,8 @@ const KeyPage = () => {
|
||||
)}
|
||||
<UserValueSection
|
||||
title='Your login'
|
||||
value={userNameWithPrefix}
|
||||
copyValue={npub + '@nsec.app'}
|
||||
value={username}
|
||||
copyValue={username}
|
||||
explanationType={EXPLANATION_MODAL_KEYS.NPUB}
|
||||
/>
|
||||
<UserValueSection
|
||||
|
27
src/shared/DebounceInput/DebounceInput.tsx
Normal file
27
src/shared/DebounceInput/DebounceInput.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import { forwardRef, useRef } from "react";
|
||||
import { Input, InputProps } from "../Input/Input";
|
||||
|
||||
export type DebounceProps = {
|
||||
handleDebounce: (value: string) => void;
|
||||
debounceTimeout: number;
|
||||
};
|
||||
|
||||
export const DebounceInput = (props: InputProps & DebounceProps) => {
|
||||
const { handleDebounce, debounceTimeout, ...rest } = props;
|
||||
|
||||
const timerRef = useRef<number>();
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (timerRef.current) {
|
||||
clearTimeout(timerRef.current);
|
||||
}
|
||||
|
||||
timerRef.current = window.setTimeout(() => {
|
||||
handleDebounce(event.target.value);
|
||||
}, debounceTimeout);
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
return <Input {...rest} onChange={handleChange} />;
|
||||
}
|
||||
|
@ -3,6 +3,9 @@ export const NOAUTHD_URL = process.env.REACT_APP_NOAUTHD_URL
|
||||
export const WEB_PUSH_PUBKEY = process.env.REACT_APP_WEB_PUSH_PUBKEY
|
||||
export const DOMAIN = process.env.REACT_APP_DOMAIN
|
||||
|
||||
export const MIN_POW = 14
|
||||
export const MAX_POW = 19
|
||||
|
||||
export enum ACTION_TYPE {
|
||||
BASIC = 'basic',
|
||||
ADVANCED = 'advanced',
|
||||
|
@ -1,82 +1,101 @@
|
||||
import { nip19 } from 'nostr-tools'
|
||||
import { ACTION_TYPE, NIP46_RELAYS } from '../consts'
|
||||
import { DbPending } from '@/modules/db'
|
||||
import { MetaEvent } from '@/types/meta-event'
|
||||
import { nip19 } from "nostr-tools";
|
||||
import { ACTION_TYPE, NIP46_RELAYS } from "../consts";
|
||||
import { DbPending } from "@/modules/db";
|
||||
import { MetaEvent } from "@/types/meta-event";
|
||||
|
||||
export async function call(cb: () => any) {
|
||||
try {
|
||||
return await cb()
|
||||
} catch (e) {
|
||||
console.log(`Error: ${e}`)
|
||||
}
|
||||
try {
|
||||
return await cb();
|
||||
} catch (e) {
|
||||
console.log(`Error: ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
export const getShortenNpub = (npub = '') => {
|
||||
return npub.substring(0, 10) + '...' + npub.slice(-4)
|
||||
}
|
||||
export const getShortenNpub = (npub = "") => {
|
||||
return npub.substring(0, 10) + "..." + npub.slice(-4);
|
||||
};
|
||||
|
||||
export const getProfileUsername = (profile: MetaEvent | null, npub: string) => {
|
||||
return (
|
||||
profile?.info?.name ||
|
||||
profile?.info?.display_name ||
|
||||
getShortenNpub(npub)
|
||||
)
|
||||
}
|
||||
return (
|
||||
profile?.info?.name || profile?.info?.display_name || getShortenNpub(npub)
|
||||
);
|
||||
};
|
||||
|
||||
export const getBunkerLink = (npub = '') => {
|
||||
if (!npub) return ''
|
||||
const { data: pubkey } = nip19.decode(npub)
|
||||
return `bunker://${pubkey}?relay=${NIP46_RELAYS[0]}`
|
||||
}
|
||||
export const getBunkerLink = (npub = "") => {
|
||||
if (!npub) return "";
|
||||
const { data: pubkey } = nip19.decode(npub);
|
||||
return `bunker://${pubkey}?relay=${NIP46_RELAYS[0]}`;
|
||||
};
|
||||
|
||||
export async function askNotificationPermission() {
|
||||
return new Promise<void>((ok, rej) => {
|
||||
// Let's check if the browser supports notifications
|
||||
if (!('Notification' in window)) {
|
||||
rej('This browser does not support notifications.')
|
||||
} else {
|
||||
Notification.requestPermission().then(() => {
|
||||
if (Notification.permission === 'granted') ok()
|
||||
else rej()
|
||||
})
|
||||
}
|
||||
})
|
||||
return new Promise<void>((ok, rej) => {
|
||||
// Let's check if the browser supports notifications
|
||||
if (!("Notification" in window)) {
|
||||
rej("This browser does not support notifications.");
|
||||
} else {
|
||||
Notification.requestPermission().then(() => {
|
||||
if (Notification.permission === "granted") ok();
|
||||
else rej();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function getSignReqKind(req: DbPending): number | undefined {
|
||||
try {
|
||||
const data = JSON.parse(JSON.parse(req.params)[0])
|
||||
return data.kind
|
||||
} catch {}
|
||||
return undefined
|
||||
try {
|
||||
const data = JSON.parse(JSON.parse(req.params)[0]);
|
||||
return data.kind;
|
||||
} catch {}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function getReqPerm(req: DbPending): string {
|
||||
if (req.method === 'sign_event') {
|
||||
const kind = getSignReqKind(req)
|
||||
if (kind !== undefined) return `${req.method}:${kind}`
|
||||
}
|
||||
return req.method
|
||||
if (req.method === "sign_event") {
|
||||
const kind = getSignReqKind(req);
|
||||
if (kind !== undefined) return `${req.method}:${kind}`;
|
||||
}
|
||||
return req.method;
|
||||
}
|
||||
|
||||
export function isPackagePerm(perm: string, reqPerm: string) {
|
||||
if (perm === ACTION_TYPE.BASIC) {
|
||||
switch (reqPerm) {
|
||||
case 'connect':
|
||||
case 'get_public_key':
|
||||
case 'nip04_decrypt':
|
||||
case 'nip04_encrypt':
|
||||
case 'sign_event:0':
|
||||
case 'sign_event:1':
|
||||
case 'sign_event:3':
|
||||
case 'sign_event:6':
|
||||
case 'sign_event:7':
|
||||
case 'sign_event:9734':
|
||||
case 'sign_event:10002':
|
||||
case 'sign_event:30023':
|
||||
case 'sign_event:10000':
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
if (perm === ACTION_TYPE.BASIC) {
|
||||
switch (reqPerm) {
|
||||
case "connect":
|
||||
case "get_public_key":
|
||||
case "nip04_decrypt":
|
||||
case "nip04_encrypt":
|
||||
case "sign_event:0":
|
||||
case "sign_event:1":
|
||||
case "sign_event:3":
|
||||
case "sign_event:6":
|
||||
case "sign_event:7":
|
||||
case "sign_event:9734":
|
||||
case "sign_event:10002":
|
||||
case "sign_event:30023":
|
||||
case "sign_event:10000":
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function fetchNip05(value: string, origin?: string) {
|
||||
try {
|
||||
const [username, domain] = value.split("@");
|
||||
if (!origin) origin = `https://${domain}`
|
||||
const response = await fetch(
|
||||
`${origin}/.well-known/nostr.json?name=${username}`
|
||||
);
|
||||
const getNpub: {
|
||||
names: {
|
||||
[name: string]: string;
|
||||
};
|
||||
} = await response.json();
|
||||
|
||||
const pubkey = getNpub.names[username];
|
||||
return nip19.npubEncode(pubkey);
|
||||
} catch (e) {
|
||||
console.log("Failed to fetch nip05", value, "error: " + e);
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user