Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nostr #238

Merged
merged 6 commits into from
Sep 25, 2023
Merged

Nostr #238

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
768 changes: 384 additions & 384 deletions package-lock.json

Large diffs are not rendered by default.

44 changes: 19 additions & 25 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
"author": "Agron Kadriaj <[email protected]> (https://agron.dev)",
"scripts": {
"s:debug:full": "npx -y cross-env@latest DEBUG=full expo start -c",
"s:c:dev": "expo start -c --dev-client",
"s:c": "expo start -c --go",
"start": "expo start --go",
"start:d": "expo start",
"lint:eslint": "npx eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts,.json --fix",
"lint:eslint": "npx eslint ./src --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts,.json --fix",
"lint": "npm run lint:eslint && npx tsc && npm run fmtJson",
"ts:check": "npx tsc",
"dep:update": "npx -y npm-check-updates --pre -u -u && npm i && npm audit fix || true && npx expo install --fix && npm run lint",
Expand All @@ -31,10 +29,6 @@
"web": "expo start --web",
"test": "npx jest -c ./config/jest.config.ts --passWithNoTests ",
"test:coverage": "npm run test -- --collectCoverage",
"test:ts": "npm run test --testPathIgnorePatterns=tsx$",
"test:ts:coverage": "npm run test:ts -- --collectCoverageFrom=src/**/*.ts",
"test:tsx": "npm run test --testPathIgnorePatterns=ts$",
"test:tsx:coverage": "npm run test:tsx -- --collectCoverageFrom=components/**/*.tsx",
"test:dev": "npm run test -- --detectOpenHandles",
"cpd:ts": "npx -y jscpd -c config/cpd.config.ts.json src config",
"cpd:tsx": "npx -y jscpd -c config/cpd.config.tsx.json src",
Expand All @@ -49,12 +43,12 @@
"@react-native-async-storage/async-storage": "1.18.2",
"@react-native-community/netinfo": "9.3.10",
"@react-navigation/core": "^6.4.9",
"@react-navigation/native": "^6.1.7",
"@react-navigation/native-stack": "^6.9.13",
"@react-navigation/native": "^6.1.8",
"@react-navigation/native-stack": "^6.9.14",
"@sentry/react-native": "5.5.0",
"@shopify/flash-list": "1.4.3",
"crypto-js": "4.1.1",
"expo": "^49.0.9",
"expo": "^49.0.11",
"expo-application": "~5.3.0",
"expo-asset": "~8.10.1",
"expo-barcode-scanner": "~12.5.3",
Expand All @@ -64,7 +58,7 @@
"expo-crypto": "~12.4.1",
"expo-device": "~5.4.0",
"expo-file-system": "~15.4.4",
"expo-insights": "^0.2.0",
"expo-insights": "~0.2.0",
"expo-localization": "~14.3.0",
"expo-secure-store": "~12.3.1",
"expo-splash-screen": "~0.20.5",
Expand Down Expand Up @@ -92,25 +86,25 @@
"@babel/plugin-proposal-private-methods": "^7.18.6",
"@getify/eslint-plugin-proper-arrows": "^11.0.3",
"@testing-library/react-native": "^12.3.0",
"@types/babel__core": "^7.20.1",
"@types/babel__core": "^7.20.2",
"@types/crypto-js": "^4.1.2",
"@types/eslint": "^8.44.2",
"@types/jest": "^29.5.4",
"@types/node": "^20.6.0",
"@types/react": "~18.2.21",
"@types/eslint": "^8.44.3",
"@types/jest": "^29.5.5",
"@types/node": "^20.6.5",
"@types/react": "~18.2.22",
"@types/react-native-onboarding-swiper": "^1.1.4",
"@types/sqlite3": "^3.1.8",
"@typescript-eslint/eslint-plugin": "^6.6.0",
"@typescript-eslint/parser": "^6.6.0",
"@types/sqlite3": "^3.1.9",
"@typescript-eslint/eslint-plugin": "^6.7.2",
"@typescript-eslint/parser": "^6.7.2",
"dotenv": "^16.3.1",
"eslint": "^8.49.0",
"eslint-plugin-deprecate": "^0.8.2",
"eslint": "^8.50.0",
"eslint-plugin-deprecate": "^0.8.3",
"eslint-plugin-es5": "^1.5.0",
"eslint-plugin-eslint-plugin": "^5.1.1",
"eslint-plugin-html": "^7.1.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-jest": "^27.2.3",
"eslint-plugin-jsdoc": "^46.6.0",
"eslint-plugin-jest": "^27.4.0",
"eslint-plugin-jsdoc": "^46.8.2",
"eslint-plugin-json": "^3.1.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.1.1",
Expand All @@ -119,9 +113,9 @@
"eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-tsdoc": "^0.2.17",
"expo-dev-client": "~2.4.10",
"jest": "^29.6.4",
"jest": "^29.7.0",
"jest-expo": "^49.0.0",
"metro-config": "^0.79.0",
"metro-config": "^0.79.1",
"prettier": "^3.0.3",
"reactotron-react-native": "^5.0.3",
"ts-jest": "^29.1.1",
Expand Down
8 changes: 6 additions & 2 deletions src/components/Balance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default function Balance({ balance, nav }: IBalanceProps) {
const { pref, color, highlight } = useThemeContext()
// State to indicate token claim from clipboard after app comes to the foreground, to re-render total balance
const { claimed } = useFocusClaimContext()
const { hidden } = usePrivacyContext()
const { hidden, handleLogoPress } = usePrivacyContext()
const [formatSats, setFormatSats] = useState(pref?.formatBalance)
const [history, setHistory] = useState<IHistoryEntry[]>([])

Expand Down Expand Up @@ -75,7 +75,11 @@ export default function Balance({ balance, nav }: IBalanceProps) {
styles.board,
{ borderColor: color.BORDER, backgroundColor: hi[highlight] }
]}>
<Logo size={hidden.balance ? 100 : 40} style={{ marginTop: hidden.balance ? 40 : 0, marginBottom: hidden.balance ? 40 : 10 }} />
<TouchableOpacity
onPress={() => void handleLogoPress()}
>
<Logo size={hidden.balance ? 100 : 40} style={{ marginTop: hidden.balance ? 40 : 0, marginBottom: hidden.balance ? 40 : 10 }} />
</TouchableOpacity>
{/* balance */}
{!hidden.balance &&
<TouchableOpacity
Expand Down
49 changes: 47 additions & 2 deletions src/context/Privacy.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable no-return-await */
/* eslint-disable @typescript-eslint/await-thenable */
import { l } from '@log'
import { store } from '@store'
import { STORE_KEYS } from '@store/consts'
Expand All @@ -8,6 +10,42 @@ const usePrivacy = () => {
balance: false,
txs: false
})

const handleHiddenBalance = async () => {
setHidden({ balance: !hidden.balance, txs: hidden.txs })
if (hidden.balance) {
await store.delete(STORE_KEYS.hiddenBal)
return
}
await store.set(STORE_KEYS.hiddenBal, '1')
}

const handleHiddenTxs = async () => {
setHidden({ balance: hidden.balance, txs: !hidden.txs })
if (hidden.txs) {
await store.delete(STORE_KEYS.hiddenTxs)
return
}
await store.set(STORE_KEYS.hiddenTxs, '1')
}

const handleLogoPress = async () => {
// both hidden, show both
if (hidden.balance && hidden.txs) {
setHidden({ balance: false, txs: false })
await Promise.all([
store.delete(STORE_KEYS.hiddenTxs),
store.delete(STORE_KEYS.hiddenBal)
])
return
}
setHidden({ balance: true, txs: true })
await Promise.all([
store.set(STORE_KEYS.hiddenTxs, '1'),
store.set(STORE_KEYS.hiddenBal, '1')
])
}

useEffect(() => {
void (async () => {
// init privacy preferences
Expand All @@ -21,15 +59,22 @@ const usePrivacy = () => {
})
})()
}, [])

return {
hidden,
setHidden
setHidden,
handleHiddenBalance,
handleHiddenTxs,
handleLogoPress
}
}
type usePrivacyType = ReturnType<typeof usePrivacy>
const PrivacyContext = createContext<usePrivacyType>({
hidden: { balance: false, txs: false },
setHidden: () => l('')
setHidden: () => l(''),
handleHiddenBalance: async () => await l(''),
handleHiddenTxs: async () => await l(''),
handleLogoPress: async () => await l('')
})

export const usePrivacyContext = () => useContext(PrivacyContext)
Expand Down
25 changes: 23 additions & 2 deletions src/nostr/consts.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

/**
* Default bootstrap relays
*/
Expand Down Expand Up @@ -68,5 +69,25 @@ export const enutsPubkey = 'npub1dx5q2el8nd4eh3eg9t2e25fd7zuqg7zxz6ldkc3uzgh66ss
// export const defaultConnectTimeout = 2000


export const imgProxy = (url: string, width = 40) =>
`https://cf-worker-images.enuts.workers.dev/?_=${encodeURIComponent(url)}&s=${width ?? 40}`
const PREFIX = 'https://cf-worker-images.enuts.workers.dev'
export function imgProxy(
hex: string,
url: string,
width: number,
kind: 'picture',
size: 64 | 192): string
export function imgProxy(
hex: string,
url: string,
width: number,
kind: 'banner',
size: 600 | 1200): string
export function imgProxy(
hex: string,
url: string,
width = 40,
kind: 'picture' | 'banner' = 'picture',
size: 64 | 192 | 600 | 1200 = 64
): string {
return `${PREFIX}/hex/${hex}/${kind}/${size}?_=${encodeURIComponent(url)}&s=${width ?? 40}`
}
18 changes: 13 additions & 5 deletions src/screens/Addressbook/ProfilePic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ import { Image } from 'expo-image'
import { useState } from 'react'
import { StyleSheet, View } from 'react-native'

export type TNostrImg = INostrImgBanner & INostrImgPicture & { url: string }
interface INostrImgBanner {
hex?: string
kind?: 'banner'
width?: 600 | 1200
}
interface INostrImgPicture {
hex?: string
kind?: 'picture'
width?: 64 | 192
}
interface IProfilePicProps {
uri?: string
size?: number
Expand All @@ -24,11 +35,7 @@ export default function ProfilePic({ uri, size, isUser, withPlusIcon, overlayCol
height: size || defaultSize,
borderRadius: size ? size / 2 : defaultSize / 2
}
// useEffect(() => {
// if (!isStr(uri) || !uri?.length) { return }
// void Image.prefetch(`${imgProxy(uri, circleStyle?.width ?? 40)}`)
// .catch(e => l('img preload', uri, e))
// }, [circleStyle?.width, uri])

return (
<>
{isStr(uri) && uri?.length && !isErr ?
Expand All @@ -38,6 +45,7 @@ export default function ProfilePic({ uri, size, isUser, withPlusIcon, overlayCol
// l({ uri, err })
setIsErr(true)
})}
// TODO FIXME
// source={`${imgProxy(uri, circleStyle?.width ?? 40)}`}
cachePolicy='memory-disk'
transition={200}
Expand Down
2 changes: 1 addition & 1 deletion src/screens/Addressbook/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default function AddressbookPage({ navigation, route }: TAddressBookPageP
const [newNpubModal, setNewNpubModal] = useState(false)
const ref = useRef<NostrData>()
const isSending = route.params?.isMelt || route.params?.isSendEcash

const initNostr = useCallback((hex: string) => {
if (!hex) { return l('no hex') }
if (!ref?.current?.hex || hex !== ref.current.hex) {
Expand Down
22 changes: 1 addition & 21 deletions src/screens/Settings/Privacy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,14 @@ import BottomNav from '@nav/BottomNav'
import { usePrivacyContext } from '@src/context/Privacy'
import { useThemeContext } from '@src/context/Theme'
import { NS } from '@src/i18n'
import { store } from '@store'
import { STORE_KEYS } from '@store/consts'
import { globals, highlight as hi } from '@styles'
import { useTranslation } from 'react-i18next'
import { StyleSheet, Switch, Text, View } from 'react-native'

export default function PrivacySettings({ navigation, route }: TPrivacySettingsPageProps) {
const { t } = useTranslation([NS.topNav])
const { color, highlight } = useThemeContext()
const { hidden, setHidden } = usePrivacyContext()

const handleHiddenBalance = async () => {
setHidden({ balance: !hidden.balance, txs: hidden.txs })
if (hidden.balance) {
await store.delete(STORE_KEYS.hiddenBal)
return
}
await store.set(STORE_KEYS.hiddenBal, '1')
}

const handleHiddenTxs = async () => {
setHidden({ balance: hidden.balance, txs: !hidden.txs })
if (hidden.txs) {
await store.delete(STORE_KEYS.hiddenTxs)
return
}
await store.set(STORE_KEYS.hiddenTxs, '1')
}
const { hidden, handleHiddenBalance, handleHiddenTxs } = usePrivacyContext()

return (
<Screen
Expand Down
4 changes: 3 additions & 1 deletion src/util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,11 @@
if (!isLnurl(address)) { throw new Error('invalid address') }
const [user, host] = address.split('@')
amount *= 1000
const { tag, callback, minSendable, maxSendable } = await (await fetch(`https://${host}/.well-known/lnurlp/${user}`)).json<ILnUrl>()

Check failure on line 147 in src/util/index.ts

View workflow job for this annotation

GitHub Actions / build (16.x)

Unsafe assignment of an `any` value

Check failure on line 147 in src/util/index.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Unsafe assignment of an `any` value

Check failure on line 147 in src/util/index.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Unsafe assignment of an `any` value
if (tag === 'payRequest' && minSendable <= amount && amount <= maxSendable) {
const resp = await (await fetch(`${callback}?amount=${amount}`)).json<{ pr: string }>()

Check failure on line 149 in src/util/index.ts

View workflow job for this annotation

GitHub Actions / build (16.x)

Unsafe assignment of an `any` value

Check failure on line 149 in src/util/index.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Unsafe assignment of an `any` value

Check failure on line 149 in src/util/index.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Unsafe assignment of an `any` value
if (!resp?.pr) { l('[getInvoiceFromLnurl]', { resp }) }

Check failure on line 150 in src/util/index.ts

View workflow job for this annotation

GitHub Actions / build (16.x)

Unsafe member access .pr on an `any` value

Check failure on line 150 in src/util/index.ts

View workflow job for this annotation

GitHub Actions / build (16.x)

Unsafe assignment of an `any` value

Check failure on line 150 in src/util/index.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Unsafe member access .pr on an `any` value

Check failure on line 150 in src/util/index.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Unsafe assignment of an `any` value

Check failure on line 150 in src/util/index.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Unsafe member access .pr on an `any` value

Check failure on line 150 in src/util/index.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Unsafe assignment of an `any` value
return resp?.pr || ''

Check failure on line 151 in src/util/index.ts

View workflow job for this annotation

GitHub Actions / build (16.x)

Unsafe return of an `any` typed value

Check failure on line 151 in src/util/index.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Unsafe return of an `any` typed value

Check failure on line 151 in src/util/index.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Unsafe return of an `any` typed value
}
} catch (err) { l('[getInvoiceFromLnurl]', err) }
return ''
Expand All @@ -157,6 +157,8 @@
export function isCashuToken(token: string) {
if (!token || !isStr(token)) { return }
token = token.trim()
const idx = token.indexOf('cashuA')
if (idx !== -1) { token = token.slice(idx) }
const uriPrefixes = [
'https://wallet.nutstash.app/#',
'https://wallet.cashu.me/?token=',
Expand Down Expand Up @@ -224,7 +226,7 @@
}

export function openUrl(url: string) {
if (!url?.trim()||!isUrl(url)) { return }
if (!url?.trim() || !isUrl(url)) { return }
return Linking.openURL(url)
}

Expand Down
Binary file removed utils/verification/enuts-v0.0.3-beta.apk.sig
Binary file not shown.
Binary file added utils/verification/enuts-v0.0.4-beta.apk.sig
Binary file not shown.
1 change: 1 addition & 0 deletions utils/verification/hash_list.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Not approved by apple store enuts-v0.0.1-beta.apk
a0ad78925f5ba81f0014cd29221ba0f8a15b877189507afdde2675d11c879c0c enuts-v0.0.2-beta.apk
69fc6947e8640d259d1b33e8e658380e4bd8dd648eb368f422ccf420067299c3 enuts-v0.0.3-beta.apk
7cc47301f2fb811205c722b440a0f929451a79e27d693f8b5b1d9fd63788f364 enuts-v0.0.4-beta.apk
8 changes: 4 additions & 4 deletions utils/verification/hash_list.txt.asc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-----BEGIN PGP SIGNATURE-----

iHUEABYIAB0WIQRxIGdR0e37DdxD88y7iol1g7/RhQUCZPsRNwAKCRC7iol1g7/R
hSHeAP9R53nlYl28Jk6Uex0UV9Qo95DodQN4SE+mF0mTQG0uWAD/e00/d2zfBCbz
1qGB0EJcNMocmPXK+GArt0ccFA0sWwI=
=r4GD
iHUEABYIAB0WIQRxIGdR0e37DdxD88y7iol1g7/RhQUCZQ1WAAAKCRC7iol1g7/R
hQ+9AQDDd3cSDmeohltze5Wpw+pUPaFymzmNAHTkbj2ExntlCQD/V+QvkP6cpriR
fXmfuy6YvuDnTph8dtPv3BS9J9cLsgo=
=Gkv9
-----END PGP SIGNATURE-----
Loading