feat: add option to disable filtering for onion relays
This commit is contained in:
@@ -129,6 +129,13 @@ export default function Settings() {
|
||||
{copiedNcryptsec ? <Check /> : <Copy />}
|
||||
</SettingItem>
|
||||
)}
|
||||
<SettingItem className="clickable" onClick={() => push(toSystemSettings())}>
|
||||
<div className="flex items-center gap-4">
|
||||
<Cog />
|
||||
<div>{t('System')}</div>
|
||||
</div>
|
||||
<ChevronRight />
|
||||
</SettingItem>
|
||||
<AboutInfoDialog>
|
||||
<SettingItem className="clickable">
|
||||
<div className="flex items-center gap-4">
|
||||
@@ -143,13 +150,6 @@ export default function Settings() {
|
||||
</div>
|
||||
</SettingItem>
|
||||
</AboutInfoDialog>
|
||||
<SettingItem className="clickable" onClick={() => push(toSystemSettings())}>
|
||||
<div className="flex items-center gap-4">
|
||||
<Cog />
|
||||
<div>{t('System')}</div>
|
||||
</div>
|
||||
<ChevronRight />
|
||||
</SettingItem>
|
||||
<div className="px-4 mt-4">
|
||||
<Donation />
|
||||
</div>
|
||||
|
||||
@@ -40,6 +40,7 @@ export const StorageKey = {
|
||||
PRIMARY_COLOR: 'primaryColor',
|
||||
ENABLE_SINGLE_COLUMN_LAYOUT: 'enableSingleColumnLayout',
|
||||
FAVICON_URL_TEMPLATE: 'faviconUrlTemplate',
|
||||
FILTER_OUT_ONION_RELAYS: 'filterOutOnionRelays',
|
||||
MEDIA_UPLOAD_SERVICE: 'mediaUploadService', // deprecated
|
||||
HIDE_UNTRUSTED_EVENTS: 'hideUntrustedEvents', // deprecated
|
||||
ACCOUNT_RELAY_LIST_EVENT_MAP: 'accountRelayListEventMap', // deprecated
|
||||
|
||||
@@ -532,6 +532,7 @@ export default {
|
||||
'Failed to get invite code from relay': 'فشل الحصول على رمز الدعوة من المرحل',
|
||||
'Failed to get invite code': 'فشل الحصول على رمز الدعوة',
|
||||
'Invite code copied to clipboard': 'تم نسخ رمز الدعوة إلى الحافظة',
|
||||
'Favicon URL': 'رابط الأيقونة المفضلة'
|
||||
'Favicon URL': 'رابط الأيقونة المفضلة',
|
||||
'Filter out onion relays': 'تصفية مرحلات onion'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,6 +548,7 @@ export default {
|
||||
'Failed to get invite code from relay': 'Fehler beim Abrufen des Einladungscodes vom Relay',
|
||||
'Failed to get invite code': 'Fehler beim Abrufen des Einladungscodes',
|
||||
'Invite code copied to clipboard': 'Einladungscode in die Zwischenablage kopiert',
|
||||
'Favicon URL': 'Favicon-URL'
|
||||
'Favicon URL': 'Favicon-URL',
|
||||
'Filter out onion relays': 'Onion-Relays herausfiltern'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -533,6 +533,7 @@ export default {
|
||||
'Failed to get invite code from relay': 'Failed to get invite code from relay',
|
||||
'Failed to get invite code': 'Failed to get invite code',
|
||||
'Invite code copied to clipboard': 'Invite code copied to clipboard',
|
||||
'Favicon URL': 'Favicon URL'
|
||||
'Favicon URL': 'Favicon URL',
|
||||
'Filter out onion relays': 'Filter out onion relays'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,6 +542,7 @@ export default {
|
||||
'Failed to get invite code from relay': 'Error al obtener código de invitación del relay',
|
||||
'Failed to get invite code': 'Error al obtener código de invitación',
|
||||
'Invite code copied to clipboard': 'Código de invitación copiado al portapapeles',
|
||||
'Favicon URL': 'URL del Favicon'
|
||||
'Favicon URL': 'URL del Favicon',
|
||||
'Filter out onion relays': 'Filtrar relés onion'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,6 +537,7 @@ export default {
|
||||
'Failed to get invite code from relay': 'دریافت کد دعوت از رله ناموفق بود',
|
||||
'Failed to get invite code': 'دریافت کد دعوت ناموفق بود',
|
||||
'Invite code copied to clipboard': 'کد دعوت در کلیپبورد کپی شد',
|
||||
'Favicon URL': 'آدرس نماد سایت'
|
||||
'Favicon URL': 'آدرس نماد سایت',
|
||||
'Filter out onion relays': 'فیلتر کردن رلههای onion'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -547,6 +547,7 @@ export default {
|
||||
'Failed to get invite code from relay': "Échec de l'obtention du code d'invitation du relay",
|
||||
'Failed to get invite code': "Échec de l'obtention du code d'invitation",
|
||||
'Invite code copied to clipboard': "Code d'invitation copié dans le presse-papiers",
|
||||
'Favicon URL': 'URL du Favicon'
|
||||
'Favicon URL': 'URL du Favicon',
|
||||
'Filter out onion relays': 'Filtrer les relais onion'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,6 +539,7 @@ export default {
|
||||
'Failed to get invite code from relay': 'रिले से निमंत्रण कोड प्राप्त करने में विफल',
|
||||
'Failed to get invite code': 'निमंत्रण कोड प्राप्त करने में विफल',
|
||||
'Invite code copied to clipboard': 'निमंत्रण कोड क्लिपबोर्ड पर कॉपी किया गया',
|
||||
'Favicon URL': 'फ़ेविकॉन URL'
|
||||
'Favicon URL': 'फ़ेविकॉन URL',
|
||||
'Filter out onion relays': 'ओनियन रिले फ़िल्टर करें'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,6 +534,7 @@ export default {
|
||||
'Failed to get invite code from relay': 'Nem sikerült lekérni a meghívókódot a relay-től',
|
||||
'Failed to get invite code': 'Nem sikerült lekérni a meghívókódot',
|
||||
'Invite code copied to clipboard': 'Meghívókód vágólapra másolva',
|
||||
'Favicon URL': 'Favicon URL'
|
||||
'Favicon URL': 'Favicon URL',
|
||||
'Filter out onion relays': 'Onion relay-ek kiszűrése'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,6 +542,7 @@ export default {
|
||||
'Failed to get invite code from relay': 'Impossibile ottenere il codice di invito dal relay',
|
||||
'Failed to get invite code': 'Impossibile ottenere il codice di invito',
|
||||
'Invite code copied to clipboard': 'Codice di invito copiato negli appunti',
|
||||
'Favicon URL': 'URL Favicon'
|
||||
'Favicon URL': 'URL Favicon',
|
||||
'Filter out onion relays': 'Filtra relay onion'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,6 +536,7 @@ export default {
|
||||
'Failed to get invite code from relay': 'リレーから招待コードの取得に失敗しました',
|
||||
'Failed to get invite code': '招待コードの取得に失敗しました',
|
||||
'Invite code copied to clipboard': '招待コードをクリップボードにコピーしました',
|
||||
'Favicon URL': 'ファビコンURL'
|
||||
'Favicon URL': 'ファビコンURL',
|
||||
'Filter out onion relays': 'Onionリレーを除外'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,6 +536,7 @@ export default {
|
||||
'Failed to get invite code from relay': '릴레이에서 초대 코드 가져오기 실패',
|
||||
'Failed to get invite code': '초대 코드 가져오기 실패',
|
||||
'Invite code copied to clipboard': '초대 코드가 클립보드에 복사되었습니다',
|
||||
'Favicon URL': '파비콘 URL'
|
||||
'Favicon URL': '파비콘 URL',
|
||||
'Filter out onion relays': '어니언 릴레이 필터링'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,6 +542,7 @@ export default {
|
||||
'Failed to get invite code from relay': 'Nie udało się uzyskać kodu zaproszenia z przekaźnika',
|
||||
'Failed to get invite code': 'Nie udało się uzyskać kodu zaproszenia',
|
||||
'Invite code copied to clipboard': 'Kod zaproszenia skopiowany do schowka',
|
||||
'Favicon URL': 'URL Favicon'
|
||||
'Favicon URL': 'URL Favicon',
|
||||
'Filter out onion relays': 'Filtruj przekaźniki onion'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,6 +539,7 @@ export default {
|
||||
'Failed to get invite code from relay': 'Falha ao obter código de convite do relay',
|
||||
'Failed to get invite code': 'Falha ao obter código de convite',
|
||||
'Invite code copied to clipboard': 'Código de convite copiado para a área de transferência',
|
||||
'Favicon URL': 'URL do Favicon'
|
||||
'Favicon URL': 'URL do Favicon',
|
||||
'Filter out onion relays': 'Filtrar relays onion'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,6 +542,7 @@ export default {
|
||||
'Failed to get invite code from relay': 'Falha ao obter código de convite do relay',
|
||||
'Failed to get invite code': 'Falha ao obter código de convite',
|
||||
'Invite code copied to clipboard': 'Código de convite copiado para a área de transferência',
|
||||
'Favicon URL': 'URL do Favicon'
|
||||
'Favicon URL': 'URL do Favicon',
|
||||
'Filter out onion relays': 'Filtrar relays onion'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,6 +544,7 @@ export default {
|
||||
'Failed to get invite code from relay': 'Не удалось получить код приглашения от релея',
|
||||
'Failed to get invite code': 'Не удалось получить код приглашения',
|
||||
'Invite code copied to clipboard': 'Код приглашения скопирован в буфер обмена',
|
||||
'Favicon URL': 'URL фавикона'
|
||||
'Favicon URL': 'URL фавикона',
|
||||
'Filter out onion relays': 'Фильтровать onion-релеи'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -530,6 +530,7 @@ export default {
|
||||
'Failed to get invite code from relay': 'ไม่สามารถรับรหัสเชิญจากรีเลย์',
|
||||
'Failed to get invite code': 'ไม่สามารถรับรหัสเชิญ',
|
||||
'Invite code copied to clipboard': 'คัดลอกรหัสเชิญไปยังคลิปบอร์ดแล้ว',
|
||||
'Favicon URL': 'URL ไอคอน'
|
||||
'Favicon URL': 'URL ไอคอน',
|
||||
'Filter out onion relays': 'กรองรีเลย์ onion'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,6 +527,7 @@ export default {
|
||||
'Failed to get invite code from relay': '从中继器获取邀请码失败',
|
||||
'Failed to get invite code': '获取邀请码失败',
|
||||
'Invite code copied to clipboard': '邀请码已复制到剪贴板',
|
||||
'Favicon URL': '网站图标 URL'
|
||||
'Favicon URL': '网站图标 URL',
|
||||
'Filter out onion relays': '过滤洋葱中继'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,16 +5,17 @@ import { buildATag } from './draft-event'
|
||||
import { getReplaceableEventIdentifier } from './event'
|
||||
import { getAmountFromInvoice, getLightningAddressFromProfile } from './lightning'
|
||||
import { formatPubkey, pubkeyToNpub } from './pubkey'
|
||||
import { getEmojiInfosFromEmojiTags, generateBech32IdFromETag, tagNameEquals } from './tag'
|
||||
import { isWebsocketUrl, normalizeHttpUrl, normalizeUrl } from './url'
|
||||
import { isTorBrowser } from './utils'
|
||||
import { generateBech32IdFromETag, getEmojiInfosFromEmojiTags, tagNameEquals } from './tag'
|
||||
import { isOnionUrl, isWebsocketUrl, normalizeHttpUrl, normalizeUrl } from './url'
|
||||
|
||||
export function getRelayListFromEvent(event?: Event | null) {
|
||||
export function getRelayListFromEvent(
|
||||
event?: Event | null,
|
||||
filterOutOnionRelays: boolean = true
|
||||
): TRelayList {
|
||||
if (!event) {
|
||||
return { write: BIG_RELAY_URLS, read: BIG_RELAY_URLS, originalRelays: [] }
|
||||
}
|
||||
|
||||
const torBrowserDetected = isTorBrowser()
|
||||
const relayList = { write: [], read: [], originalRelays: [] } as TRelayList
|
||||
event.tags.filter(tagNameEquals('r')).forEach(([, url, type]) => {
|
||||
if (!url || !isWebsocketUrl(url)) return
|
||||
@@ -25,8 +26,7 @@ export function getRelayListFromEvent(event?: Event | null) {
|
||||
const scope = type === 'read' ? 'read' : type === 'write' ? 'write' : 'both'
|
||||
relayList.originalRelays.push({ url: normalizedUrl, scope })
|
||||
|
||||
// Filter out .onion URLs if not using Tor browser
|
||||
if (normalizedUrl.endsWith('.onion/') && !torBrowserDetected) return
|
||||
if (filterOutOnionRelays && isOnionUrl(normalizedUrl)) return
|
||||
|
||||
if (type === 'write') {
|
||||
relayList.write.push(normalizedUrl)
|
||||
|
||||
@@ -2,6 +2,15 @@ export function isWebsocketUrl(url: string): boolean {
|
||||
return /^wss?:\/\/.+$/.test(url)
|
||||
}
|
||||
|
||||
export function isOnionUrl(url: string): boolean {
|
||||
try {
|
||||
const hostname = new URL(url).hostname
|
||||
return hostname.endsWith('.onion')
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// copy from nostr-tools/utils
|
||||
export function normalizeUrl(url: string): string {
|
||||
try {
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
import { DEFAULT_FAVICON_URL_TEMPLATE } from '@/constants'
|
||||
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
|
||||
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
|
||||
import { forwardRef } from 'react'
|
||||
import storage from '@/services/local-storage.service'
|
||||
import { forwardRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const SystemSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
||||
const { t } = useTranslation()
|
||||
const { faviconUrlTemplate, setFaviconUrlTemplate } = useContentPolicy()
|
||||
const [filterOutOnionRelays, setFilterOutOnionRelays] = useState(
|
||||
storage.getFilterOutOnionRelays()
|
||||
)
|
||||
|
||||
return (
|
||||
<SecondaryPageLayout ref={ref} index={index} title={t('System')}>
|
||||
@@ -25,6 +30,19 @@ const SystemSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
||||
placeholder={DEFAULT_FAVICON_URL_TEMPLATE}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-between items-center px-4 min-h-9">
|
||||
<Label htmlFor="filter-out-onion-relays" className="text-base font-normal">
|
||||
{t('Filter out onion relays')}
|
||||
</Label>
|
||||
<Switch
|
||||
id="filter-out-onion-relays"
|
||||
checked={filterOutOnionRelays}
|
||||
onCheckedChange={(checked) => {
|
||||
storage.setFilterOutOnionRelays(checked)
|
||||
setFilterOutOnionRelays(checked)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</SecondaryPageLayout>
|
||||
)
|
||||
|
||||
@@ -207,7 +207,7 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
|
||||
indexedDb.getReplaceableEvent(account.pubkey, kinds.Pinlist)
|
||||
])
|
||||
if (storedRelayListEvent) {
|
||||
setRelayList(getRelayListFromEvent(storedRelayListEvent))
|
||||
setRelayList(getRelayListFromEvent(storedRelayListEvent, storage.getFilterOutOnionRelays()))
|
||||
}
|
||||
if (storedProfileEvent) {
|
||||
setProfileEvent(storedProfileEvent)
|
||||
@@ -237,7 +237,7 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
|
||||
authors: [account.pubkey]
|
||||
})
|
||||
const relayListEvent = getLatestEvent(relayListEvents) ?? storedRelayListEvent
|
||||
const relayList = getRelayListFromEvent(relayListEvent)
|
||||
const relayList = getRelayListFromEvent(relayListEvent, storage.getFilterOutOnionRelays())
|
||||
if (relayListEvent) {
|
||||
client.updateRelayListCache(relayListEvent)
|
||||
await indexedDb.putReplaceableEvent(relayListEvent)
|
||||
@@ -705,7 +705,7 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
|
||||
|
||||
const updateRelayListEvent = async (relayListEvent: Event) => {
|
||||
const newRelayList = await client.updateRelayListCache(relayListEvent)
|
||||
setRelayList(getRelayListFromEvent(newRelayList))
|
||||
setRelayList(getRelayListFromEvent(newRelayList, storage.getFilterOutOnionRelays()))
|
||||
}
|
||||
|
||||
const updateProfileEvent = async (profileEvent: Event) => {
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
} from 'nostr-tools'
|
||||
import { AbstractRelay } from 'nostr-tools/abstract-relay'
|
||||
import indexedDb from './indexed-db.service'
|
||||
import storage from './local-storage.service'
|
||||
|
||||
type TTimelineRef = [string, number]
|
||||
|
||||
@@ -1131,7 +1132,7 @@ class ClientService extends EventTarget {
|
||||
|
||||
return relayEvents.map((event) => {
|
||||
if (event) {
|
||||
return getRelayListFromEvent(event)
|
||||
return getRelayListFromEvent(event, storage.getFilterOutOnionRelays())
|
||||
}
|
||||
return {
|
||||
write: BIG_RELAY_URLS,
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from '@/constants'
|
||||
import { isSameAccount } from '@/lib/account'
|
||||
import { randomString } from '@/lib/random'
|
||||
import { isTorBrowser } from '@/lib/utils'
|
||||
import {
|
||||
TAccount,
|
||||
TAccountPointer,
|
||||
@@ -54,6 +55,7 @@ class LocalStorageService {
|
||||
private primaryColor: TPrimaryColor = 'DEFAULT'
|
||||
private enableSingleColumnLayout: boolean = true
|
||||
private faviconUrlTemplate: string = DEFAULT_FAVICON_URL_TEMPLATE
|
||||
private filterOutOnionRelays: boolean = !isTorBrowser()
|
||||
|
||||
constructor() {
|
||||
if (!LocalStorageService.instance) {
|
||||
@@ -210,6 +212,11 @@ class LocalStorageService {
|
||||
this.faviconUrlTemplate =
|
||||
window.localStorage.getItem(StorageKey.FAVICON_URL_TEMPLATE) ?? DEFAULT_FAVICON_URL_TEMPLATE
|
||||
|
||||
const filterOutOnionRelaysStr = window.localStorage.getItem(StorageKey.FILTER_OUT_ONION_RELAYS)
|
||||
if (filterOutOnionRelaysStr) {
|
||||
this.filterOutOnionRelays = filterOutOnionRelaysStr !== 'false'
|
||||
}
|
||||
|
||||
// Clean up deprecated data
|
||||
window.localStorage.removeItem(StorageKey.ACCOUNT_PROFILE_EVENT_MAP)
|
||||
window.localStorage.removeItem(StorageKey.ACCOUNT_FOLLOW_LIST_EVENT_MAP)
|
||||
@@ -529,6 +536,15 @@ class LocalStorageService {
|
||||
this.faviconUrlTemplate = template
|
||||
window.localStorage.setItem(StorageKey.FAVICON_URL_TEMPLATE, template)
|
||||
}
|
||||
|
||||
getFilterOutOnionRelays() {
|
||||
return this.filterOutOnionRelays
|
||||
}
|
||||
|
||||
setFilterOutOnionRelays(filterOut: boolean) {
|
||||
this.filterOutOnionRelays = filterOut
|
||||
window.localStorage.setItem(StorageKey.FILTER_OUT_ONION_RELAYS, filterOut.toString())
|
||||
}
|
||||
}
|
||||
|
||||
const instance = new LocalStorageService()
|
||||
|
||||
Reference in New Issue
Block a user