Merge branch 'vitorpamplona:main' into profiles-list-management
This commit is contained in:
@@ -61,13 +61,13 @@ jobs:
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Play Benchmark APK
|
||||
path: amethyst/build/outputs/apk/play/debug/amethyst-play-universal-benchmark.apk
|
||||
path: amethyst/build/outputs/apk/play/benchmark/amethyst-play-universal-benchmark.apk
|
||||
|
||||
- name: Upload FDroid APK Benchmark
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: FDroid Benchmark APK
|
||||
path: amethyst/build/outputs/apk/fdroid/debug/amethyst-fdroid-universal-benchmark.apk
|
||||
path: amethyst/build/outputs/apk/fdroid/benchmark/amethyst-fdroid-universal-benchmark.apk
|
||||
|
||||
- name: Upload Compose Reports
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -75,9 +75,6 @@ jobs:
|
||||
name: Compose Reports
|
||||
path: amethyst/build/compose_compiler
|
||||
|
||||
- name: Tests
|
||||
run: ./gradlew test --no-daemon
|
||||
|
||||
- name: Upload Test Results
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
||||
+23
@@ -27,13 +27,17 @@ import com.vitorpamplona.amethyst.model.AccountSettings
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.service.location.LocationState
|
||||
import com.vitorpamplona.amethyst.service.okhttp.OkHttpWebSocket
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.nwc.NWCPaymentFilterAssembler
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.dal.ThreadFeedFilter
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
|
||||
import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag
|
||||
import com.vitorpamplona.quartz.nip01Core.verify
|
||||
import com.vitorpamplona.quartz.nip03Timestamp.ots.okhttp.OkHttpOtsResolverBuilder
|
||||
import com.vitorpamplona.quartz.nip03Timestamp.ots.okhttp.OtsBlockHeightCache
|
||||
import junit.framework.TestCase
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -67,6 +71,25 @@ class ThreadDualAxisChartAssemblerTest {
|
||||
},
|
||||
CoroutineScope(Dispatchers.IO + SupervisorJob()),
|
||||
),
|
||||
nwcFilterAssembler =
|
||||
NWCPaymentFilterAssembler(
|
||||
NostrClient(
|
||||
OkHttpWebSocket.Builder {
|
||||
OkHttpClient
|
||||
.Builder()
|
||||
.followRedirects(true)
|
||||
.followSslRedirects(true)
|
||||
.build()
|
||||
},
|
||||
CoroutineScope(Dispatchers.IO + SupervisorJob()),
|
||||
),
|
||||
),
|
||||
otsResolverBuilder =
|
||||
OkHttpOtsResolverBuilder(
|
||||
okHttpClient = { OkHttpClient.Builder().build() },
|
||||
isTorActive = { false },
|
||||
cache = OtsBlockHeightCache(),
|
||||
),
|
||||
)
|
||||
|
||||
val db =
|
||||
|
||||
-1
@@ -27,7 +27,6 @@ import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.intPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import com.vitorpamplona.amethyst.ui.actions.MediaSaverToDisk.save
|
||||
import com.vitorpamplona.amethyst.ui.tor.TorSettings
|
||||
import com.vitorpamplona.amethyst.ui.tor.TorSettingsFlow
|
||||
import com.vitorpamplona.amethyst.ui.tor.TorType
|
||||
|
||||
-1
@@ -34,7 +34,6 @@ import kotlinx.coroutines.flow.emitAll
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.transformLatest
|
||||
import kotlin.collections.ifEmpty
|
||||
|
||||
class AccountsTorStateConnector(
|
||||
accountsCache: AccountCacheState,
|
||||
|
||||
+1
-1
@@ -172,7 +172,7 @@ class LightningAddressResolver {
|
||||
val messageNode = tree.get("message")
|
||||
val statusNode = tree.get("status")
|
||||
|
||||
if (tree.get("error").isBoolean && messageNode != null) {
|
||||
if (tree.get("error") != null && tree.get("error").isBoolean && messageNode != null) {
|
||||
if (errorNode.asBoolean()) {
|
||||
return messageNode.asText()
|
||||
}
|
||||
|
||||
-1
@@ -29,7 +29,6 @@ import com.vitorpamplona.amethyst.LocalPreferences
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.LocalCache.chatroomList
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.sendDMNotification
|
||||
import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.sendZapNotification
|
||||
|
||||
+22
-14
@@ -20,6 +20,8 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.service.okhttp
|
||||
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import okhttp3.Dispatcher
|
||||
import okhttp3.OkHttpClient
|
||||
import java.net.InetSocketAddress
|
||||
@@ -35,6 +37,22 @@ class OkHttpClientFactory(
|
||||
const val DEFAULT_IS_MOBILE: Boolean = false
|
||||
const val DEFAULT_TIMEOUT_ON_WIFI_SECS: Int = 10
|
||||
const val DEFAULT_TIMEOUT_ON_MOBILE_SECS: Int = 30
|
||||
|
||||
private fun isEmulator(): Boolean =
|
||||
Build.FINGERPRINT.startsWith("generic") ||
|
||||
Build.FINGERPRINT.lowercase().contains("emulator") ||
|
||||
Build.MODEL.contains("google_sdk") ||
|
||||
Build.MODEL.lowercase().contains("droid4x") ||
|
||||
Build.MODEL.contains("Emulator") ||
|
||||
Build.MODEL.contains("Android SDK built for x86") ||
|
||||
Build.MANUFACTURER.contains("Genymotion") ||
|
||||
(Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) ||
|
||||
"google_sdk" == Build.PRODUCT ||
|
||||
Build.HARDWARE.contains("goldfish") ||
|
||||
Build.HARDWARE.contains("ranchu") ||
|
||||
Build.HARDWARE.contains("vbox86") ||
|
||||
Build.HARDWARE.contains("nox") ||
|
||||
Build.HARDWARE.contains("cuttlefish")
|
||||
}
|
||||
|
||||
val logging = LoggingInterceptor()
|
||||
@@ -42,22 +60,12 @@ class OkHttpClientFactory(
|
||||
|
||||
val myDispatcher =
|
||||
Dispatcher().apply {
|
||||
maxRequests = 512
|
||||
}
|
||||
|
||||
/*
|
||||
DEBUG OK HTTP connections here.
|
||||
init {
|
||||
if (isDebug) {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
while (true) {
|
||||
Log.d("OkHttpClientFactory", "Active threads ${myDispatcher.runningCallsCount()}")
|
||||
delay(5000)
|
||||
}
|
||||
if (!isEmulator()) {
|
||||
maxRequests = 512
|
||||
} else {
|
||||
Log.i("OkHttpClientFactory", "Emulator detected, using default maxRequests: 64.")
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
private val rootClient =
|
||||
OkHttpClient
|
||||
|
||||
-1
@@ -26,7 +26,6 @@ import androidx.compose.runtime.remember
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.model.Channel
|
||||
import com.vitorpamplona.amethyst.model.ChannelState
|
||||
import com.vitorpamplona.amethyst.model.LocalCache.notes
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.model.nip28PublicChats.PublicChatChannel
|
||||
import com.vitorpamplona.amethyst.model.nip53LiveActivities.LiveActivitiesChannel
|
||||
|
||||
@@ -28,7 +28,6 @@ import androidx.activity.enableEdgeToEdge
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.Amethyst
|
||||
import com.vitorpamplona.amethyst.debugState
|
||||
|
||||
-1
@@ -33,7 +33,6 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.preferences.AccountPreferenceStores.Companion.torSettings
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.topbars.SavingTopBar
|
||||
import com.vitorpamplona.amethyst.ui.tor.PrivacySettingsBody
|
||||
|
||||
-2
@@ -41,12 +41,10 @@ import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.emitAll
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.transformLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.collections.map
|
||||
|
||||
@Stable
|
||||
class RelayFeedViewModel :
|
||||
|
||||
-1
@@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.relays
|
||||
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
-1
@@ -21,7 +21,6 @@
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
-1
@@ -32,7 +32,6 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.preferences.AccountPreferenceStores.Companion.torSettings
|
||||
import com.vitorpamplona.amethyst.ui.components.appendLink
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.tor.ConnectTorDialog
|
||||
|
||||
@@ -59,6 +59,16 @@ Prijavi se s privatnim ključem, za odstranitev iz seznama sledljivih</string>
|
||||
Prijavi se s privatnim ključem, za cenzuro besed ali stavkov</string>
|
||||
<string name="login_with_a_private_key_to_be_able_to_show_word">Uporabljaš javni ključ in javni ključi omogočajo le branje.
|
||||
Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="login_with_a_private_key_to_be_able_to_change_settings">Uporabljaš javni ključ in javni ključi omogočajo le branje.
|
||||
Za spreminjanje nastavitev, se prijavi s privatnim ključem</string>
|
||||
<string name="login_with_a_private_key_to_be_able_to_upload">Uporabljaš javni ključ in javni ključi omogočajo le branje.
|
||||
Za nalaganje se je potrebno prijaviti s privatnim ključem</string>
|
||||
<string name="login_with_a_private_key_to_be_able_to_sign_events">Uporabljaš javni ključ in javni ključi omogočajo le branje.
|
||||
Za podpisovanje se je potrebno prijaviti s privatnim ključem</string>
|
||||
<string name="unauthorized_exception">Dešifriranje nima pooblastila</string>
|
||||
<string name="unauthorized_exception_description">Podpisnik ni odobril dešifriranja, ki je potrebno za to operacijo. V aplikaciji za podpisovanje aktivirajte NIP-44 možnost dešifriranja in poskusite znova</string>
|
||||
<string name="signer_not_found_exception">Ne najdem podpisnika</string>
|
||||
<string name="signer_not_found_exception_description">Ali je bila aplikacija za podpisovanje odstranjena? Preverite, ali je aplikacija za podpisovanje nameščena in ima dostop do tega računa. Odjavite se in ponovno prijavite, če se je aplikacija morda spremenila.</string>
|
||||
<string name="zaps">Zapi</string>
|
||||
<string name="view_count">Števec vpogledov</string>
|
||||
<string name="boost">Posreduj</string>
|
||||
@@ -106,6 +116,7 @@ Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="my_awesome_group">Moja vrhunska skupina</string>
|
||||
<string name="picture_url">Url slike</string>
|
||||
<string name="description">Opis</string>
|
||||
<string name="no_description">Ne najdem opisa</string>
|
||||
<string name="about_us">"O nas.. "</string>
|
||||
<string name="what_s_on_your_mind">Kaj imaš v mislih?</string>
|
||||
<string name="write_a_message">Napiši sporočilo…</string>
|
||||
@@ -147,6 +158,11 @@ Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="video_saved_to_the_gallery">Video shranjen v video galerijo telefona</string>
|
||||
<string name="failed_to_save_the_video">Neuspešno shranjevanje videa</string>
|
||||
<string name="upload_image">Naloži sliko</string>
|
||||
<string name="take_a_picture">Zajemi sliko</string>
|
||||
<string name="record_a_video">Posnemi video</string>
|
||||
<string name="record_a_message">Posnemi sporočilo</string>
|
||||
<string name="record_a_message_title">Posnemi sporočilo</string>
|
||||
<string name="record_a_message_description">Klikni in drži za snemanje sporočila</string>
|
||||
<string name="uploading">Nalaganje …</string>
|
||||
<string name="user_does_not_have_a_lightning_address_setup_to_receive_sats">Uporabnik nima nastavljenega \"lightning\" naslova za sprejem satoshi-jev</string>
|
||||
<string name="reply_here">"odgovori tukaj.. "</string>
|
||||
@@ -159,6 +175,8 @@ Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="blocked_users">Blokirani uporabniki</string>
|
||||
<string name="new_threads">Nove objave</string>
|
||||
<string name="conversations">Pogovori</string>
|
||||
<string name="feed">Vir</string>
|
||||
<string name="mod_queue">Moderatorska vrsta</string>
|
||||
<string name="notes">Zapiski</string>
|
||||
<string name="replies">Pogovori</string>
|
||||
<string name="mutual">Tvoje</string>
|
||||
@@ -239,6 +257,8 @@ Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="public_chat_relays_title">Releji</string>
|
||||
<string name="public_chat_relays_explainer">Vnesi 1–3 releje, ki gostijo to skupino.
|
||||
Nostr odjemalci uporabljajo to nastavitev, da vedo, od kod prenesti tvoja sporočila in kam jih poslati.</string>
|
||||
<string name="paid_relay">Plačljiv rele</string>
|
||||
<string name="tor_relay">Vsili Tor pri povezovanju</string>
|
||||
<string name="posts_received">sprejete objave</string>
|
||||
<string name="remove">Odstrani</string>
|
||||
<string name="translations_auto">Avtomatsko</string>
|
||||
@@ -283,6 +303,7 @@ Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="biometric_error">Napaka</string>
|
||||
<string name="badge_created_by">"Ustvaril/a %1$s"</string>
|
||||
<string name="badge_award_image_for">"Slika nagradne značke za %1$s"</string>
|
||||
<string name="badge_award_image">\"Slika nagradne značke</string>
|
||||
<string name="new_badge_award_notif">Prejel/a si novo nagradno značko</string>
|
||||
<string name="award_granted_to">Nagradna zančka podeljena</string>
|
||||
<string name="copied_note_text_to_clipboard">Tekst zapiska kopiran v odložišče</string>
|
||||
@@ -308,6 +329,7 @@ Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="quick_action_unfollow">Prenehaj slediti</string>
|
||||
<string name="quick_action_follow">Sledi</string>
|
||||
<string name="quick_action_request_deletion_gallery_title">Izbris iz galerije</string>
|
||||
<string name="quick_action_request_deletion_gallery_alert_body_v2">Odstrani ta medij iz svoje galerije</string>
|
||||
<string name="quick_action_request_deletion_alert_title">Prošnja za izbris</string>
|
||||
<string name="quick_action_request_deletion_alert_body">Amethyst bo poslal prošnjo za izbris zapiska vsem relejem na katere ste povezani. Nobenega jamstva ni, da bo vaš zapisek trajno izbrisan iz teh relejev ali iz drugih relejev, kjer je morda shranjen.</string>
|
||||
<string name="quick_action_block_dialog_btn">Blokiraj</string>
|
||||
@@ -429,6 +451,8 @@ Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="no">Ne</string>
|
||||
<string name="follow_list_selection">Spisek komu sledimo</string>
|
||||
<string name="follow_list_kind3follows">Vse, čemur sledimo</string>
|
||||
<string name="follow_list_kind3follows_users_only">Vsi sledeni sledenih</string>
|
||||
<string name="follow_list_kind3follows_proxy">Sledi preko posrednika</string>
|
||||
<string name="follow_list_aroundme">V moji okolici</string>
|
||||
<string name="follow_list_global">Globalno</string>
|
||||
<string name="follow_list_mute_list">Spisek utišanih</string>
|
||||
@@ -568,7 +592,10 @@ Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="relay_setup">Releji</string>
|
||||
<string name="discover_follows">Sledi tropu</string>
|
||||
<string name="discover_reads">Branje</string>
|
||||
<string name="discover_content_v2">Algoritemski viri</string>
|
||||
<string name="discover_marketplace">Tržnica</string>
|
||||
<string name="discover_live_v2">Prenos v živo</string>
|
||||
<string name="discover_community_v2">Skupnosti</string>
|
||||
<string name="discover_chat">Pogovori</string>
|
||||
<string name="community_approved_posts">Odobrene objave</string>
|
||||
<string name="groups_no_descriptor">Ta skupina nima opisa ali pravil. Obrnite se na lastnika, da jih doda</string>
|
||||
@@ -576,6 +603,7 @@ Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="add_sensitive_content_label">Občutljiva vsebina</string>
|
||||
<string name="add_sensitive_content_description">Doda opozorilo o občutljivi vsebini pred prikazom te vsebine</string>
|
||||
<string name="preferences">Nastavitve aplikacije</string>
|
||||
<string name="user_preferences">Nastavitve uporabnika</string>
|
||||
<string name="settings">Nastavitve</string>
|
||||
<string name="connectivity_type_always">Vedno</string>
|
||||
<string name="connectivity_type_wifi_only">Samo Wifi</string>
|
||||
@@ -620,6 +648,8 @@ Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="geohash_explainer">Doda Geohash vaše lokacije k objavi. Javnost bo vedela, da se nahajate v radiju 5 km (3 milj) od trenutne lokacije</string>
|
||||
<string name="geohash_exclusive">Lokacijsko-ekskluzivna objava</string>
|
||||
<string name="geohash_exclusive_explainer">To bodo videli samo sledilci lokacije. Vaši splošni sledilci tega ne bodo videli.</string>
|
||||
<string name="hashtag_exclusive">Hashtag-ekskluzivna objava</string>
|
||||
<string name="hashtag_exclusive_explainer">Vidno bo le sledilcem tega hashtaga. Tvoji splošni sledilci tega ne bojo videli.</string>
|
||||
<string name="loading_location">Nalaganje lokacije</string>
|
||||
<string name="lack_location_permissions">Brez dovoljenj za lokacijo</string>
|
||||
<string name="add_sensitive_content_explainer">Doda opozorilo o občutljivi vsebini pred prikazom vaše vsebine. To je primerno za vsebino NSFW ali vsebino, ki jo nekateri lahko smatrajo za žaljivo ali vznemirjajočo</string>
|
||||
@@ -640,6 +670,8 @@ Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="messages_new_subject_message">Razlaga članom</string>
|
||||
<string name="messages_new_subject_message_placeholder">Spreminjanje imena za dosego novih ciljev.</string>
|
||||
<string name="paste_from_clipboard">Prilepi iz odložišča</string>
|
||||
<string name="invalid_nip47_uri_title">Napačen NIP-47 URI</string>
|
||||
<string name="invalid_nip47_uri_description">URI %1$s ni veljaven NIP-47 vpis URI.</string>
|
||||
<string name="language_description">Za vmesnik aplikacije</string>
|
||||
<string name="theme_description">Temna, svetla ali sistemska tema</string>
|
||||
<string name="automatically_load_images_gifs_description">Samodejno naloži slike in GIF-e</string>
|
||||
@@ -657,6 +689,9 @@ Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="media_added_to_profile_gallery">Medij dodan v galerijo profila</string>
|
||||
<string name="created_at">Ustvarjeno ob</string>
|
||||
<string name="rules">Pravila</string>
|
||||
<string name="community_description">O nas</string>
|
||||
<string name="guidelines">Smernice</string>
|
||||
<string name="moderators">Moderatorji</string>
|
||||
<string name="login_with_external_signer">Prijavi se z Amber</string>
|
||||
<string name="status_update">Posodobi svoj status</string>
|
||||
<string name="lightning_wallets_not_found">Napaka pri razčlembi sporočila o napaki</string>
|
||||
@@ -694,6 +729,7 @@ Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="wallet_number">Denarnica %1$s</string>
|
||||
<string name="error_opening_external_signer">Napaka pri odpiranju aplikacije za podpisovanje</string>
|
||||
<string name="error_opening_external_signer_description">Aplikacije za podpisovanje ni bilo mogoče najti. Preverite, ali aplikacija morda, ni bila odstranjena</string>
|
||||
<string name="sign_request_rejected2">Zahteva za vpis zavrnjena</string>
|
||||
<string name="sign_request_rejected">Podpisovanje je bilo zavrnjeno</string>
|
||||
<string name="sign_request_rejected_description">Prepričajte se, da je aplikacija za podpisovanje odobrila to transakcijo</string>
|
||||
<string name="no_wallet_found_with_error">Denarnica za plačilo z \"lightning\" ni najdena (Napaka: %1$s). Prosimo, namestite \"lightning\" denarnico da boste lahko Zap-ali ostale</string>
|
||||
@@ -822,6 +858,7 @@ Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="new_short">Novi kratki mediji: slike ali posnetki</string>
|
||||
<string name="new_community_note">Novo zapisek skupnosti</string>
|
||||
<string name="new_product">Nov produkt</string>
|
||||
<string name="new_exclusive_geo_note">Nova geo-ekskluzivna objava</string>
|
||||
<string name="open_all_reactions_to_this_post">Odpri vse odzive na to objavo</string>
|
||||
<string name="close_all_reactions_to_this_post">Zapri vse odzive na to objavo</string>
|
||||
<string name="reply_description">Odgovori</string>
|
||||
@@ -868,21 +905,41 @@ Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="dm_upload">Naloži ZS</string>
|
||||
<string name="relay_settings">Nastavitve relejev</string>
|
||||
<string name="public_home_section">Javni za odhajajočo pošto/domači releji</string>
|
||||
<string name="public_home_section_explainer_profile">Uporabnik pošilja objave na te releje</string>
|
||||
<string name="public_home_section_explainer">Ta tip releja shranjuje vse vaše vsebine. Amethyst bo sem pošiljal vaše objave, ostali uporabniki pa bodo te releje uporabljali za iskanje vaših vsebin. Vstavite 1–3 releje. To so lahko osebni releji, plačljivi releji ali javni releji.</string>
|
||||
<string name="public_notif_section">Javni releji za dospelo pošto</string>
|
||||
<string name="public_notif_section_explainer_profile">Uporabnik prejema obvestila na teh relejih</string>
|
||||
<string name="public_notif_section_explainer">Ta tip releja sprejema vsa odgovore, komentarje, všečke in zap-e na vaše objave. Ti releji so lahko plačljivi ali brezplačni. Omejitve, ki jih nastavi upravljavec releja, lahko omejijo obvestila, ki jih prejemate, tako v dobrem kot v slabem. Na primer, če ste tarča napada s spam komentarji, ki so nezaželeni, lahko plačljivi releji te nezaželene komentarje odstranijo. Vnesite med 1–3 releje.</string>
|
||||
<string name="private_inbox_section">Releji predala zasebnih sporočil</string>
|
||||
<string name="private_inbox_section_explainer_profile">Uporabnik prejema ZS prek teh relejev</string>
|
||||
<string name="private_inbox_section_explainer">Vnesite 1–3 releje, ki bodo služili kot vaš predal za zasebna sporočila. Drugi bodo te releje uporabljali za pošiljanje zasebnih sporočil vam. Releji za zasebna sporočila bi morali sprejeti katero koli sporočilo od kogar koli, vendar samo vam dovoliti njihov prenos. Dobre možnosti so:\n - inbox.nostr.wine (plačljiv)\n - auth.nostr1.com (brezplačen)\n - you.nostr1.com (osebni releji - plačljivi)</string>
|
||||
<string name="private_outbox_section">Zasebni domači releji</string>
|
||||
<string name="private_outbox_section_explainer">Vnesite 1–3 releje za shranjevanje dogodkov, ki jih nihče drug ne more videti, kot so vaši osnutki in/ali nastavitve aplikacije. Idealno je, da so ti releji bodisi lokalni ali zahtevajo preverjanje pristnosti pred prenosom vsebine posameznega uporabnika.</string>
|
||||
<string name="kind_3_section">Splošni releji</string>
|
||||
<string name="kind_3_section_description">Amethyst uporablja te releje za prenos objav za vas.</string>
|
||||
<string name="connected_section">Povezani releji</string>
|
||||
<string name="connected_section_description">Trenutni seznam relejev v uporabi</string>
|
||||
<string name="kind_3_recommended_section">Priporočljivi releji</string>
|
||||
<string name="kind_3_recommended_section_description">Dodajte naslednje releje na svoj seznam Splošnih relejev, da boste prejeli objave od navedenih uporabnikov.</string>
|
||||
<string name="search_section">Iskalni releji</string>
|
||||
<string name="search_section_explainer">Seznam relejev za uporabo pri iskanju vsebine ali uporabnikov. Označevanje in iskanje ne bosta delovala, če možnosti niso na voljo. Prepričajte se, da podpirajo NIP-50.</string>
|
||||
<string name="local_section">Lokalni releji</string>
|
||||
<string name="local_section_explainer">Seznam relejev, ki delujejo na tej napravi.</string>
|
||||
<string name="trusted_relays_title">Zaupanja vredni releji</string>
|
||||
<string name="trusted_section">Zaupanja vredni releji</string>
|
||||
<string name="trusted_section_explainer">Releji katerim zaupaš in zanje ne rabiš Tor povezave</string>
|
||||
<string name="proxy_relays_title">Proxy releji</string>
|
||||
<string name="proxy_section">Proxy releji</string>
|
||||
<string name="proxy_section_explainer">Agregatorji, ki jih mora aplikacija uporabljati za prenos vašega vira vsebin, na primer filter.nostr.wine. To nadomesti model odhodne pošte (outbox model) in bo prisililo aplikacijo k povezovanju prek relejev iz vašega seznama.</string>
|
||||
<string name="broadcast_relays_title">Oddajni releji</string>
|
||||
<string name="broadcast_section">Oddajni releji</string>
|
||||
<string name="broadcast_section_explainer">Releji specializirani za posredovanje vaših zapiskov na vse ostale releje kot npr. sendit.nosflare.com. Amethyst bo dodal ta rele k vsem vašim novim dogodkom.</string>
|
||||
<string name="indexer_relays_title">Indeksni releji</string>
|
||||
<string name="indexer_section">Indeksni releji</string>
|
||||
<string name="indexer_section_explainer">Releji, specializirani za gostovanje metapodatkov in seznamov relejev vseh uporabnikov, na primer purplepag.es. Amethyst bo te releje uporabil za iskanje uporabnikov, ki niso na vaših seznamih.</string>
|
||||
<string name="blocked_relays_title">Blokirani releji</string>
|
||||
<string name="blocked_section">Blokirani releji</string>
|
||||
<string name="blocked_section_explainer">Amethyst se ne bo nikoli povezal na te releje</string>
|
||||
<string name="zap_the_devs_title">Zap-ni ustvarjalce!</string>
|
||||
<string name="zap_the_devs_description">Vaša donacija nam pomaga narediti spremembo. Vsak satoši šteje!</string>
|
||||
<string name="donate_now">Doniraj sedaj</string>
|
||||
@@ -972,7 +1029,22 @@ Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov</string>
|
||||
<string name="select_list_to_filter">Izberite seznam za filtriranje vira</string>
|
||||
<string name="temporary_account">Odjava ob zaklepu naprave</string>
|
||||
<string name="private_message">Zasebno sporočilo</string>
|
||||
<string name="public_message">Javno sporočilo</string>
|
||||
<string name="group_relay">Rele za klepet</string>
|
||||
<string name="group_relay_explanation">Rele, na katerega so povezani vsi uporabniki tega klepeta</string>
|
||||
<string name="share_image">Deli sliko…</string>
|
||||
<string name="unable_to_share_image">Deljenje slike ni uspelo, prosimo poskusite znova…</string>
|
||||
<string name="search_by_hashtag">Išči hashtag: #%1$s</string>
|
||||
<string name="dont_translate_from">Ne prevajaj iz</string>
|
||||
<string name="dont_translate_from_description">Jeziki, ki so prikazani tukaj, ne bodo prevedeni. Izberite jezik, da ga odstranite in ga znova prevedete. </string>
|
||||
<string name="pause">Premor</string>
|
||||
<string name="play">Predvajaj</string>
|
||||
<string name="open_dropdown_menu">Odpri spustni meni</string>
|
||||
<string name="option_of">Možnost %1$s od %2$s</string>
|
||||
<string name="feed_filter_selected">Filter vira, %1$s izbran</string>
|
||||
<string name="feed_filter_select_an_option">Filter vira, %1$s</string>
|
||||
<string name="crashreport_found">Najdeno je poročilo o napaki</string>
|
||||
<string name="would_you_like_to_send_the_recent_crash_report_to_amethyst_in_a_dm_no_personal_information_will_be_shared">Želite poslati poročilo o napaki Amethyst-u preko zasebnega sporočila? Vaši osebni podatki NE bojo posredovani.</string>
|
||||
<string name="crashreport_found_send">Pošlji</string>
|
||||
<string name="this_message_will_disappear_in_days">To sporočilo bo izginilo čez %1$d dni</string>
|
||||
</resources>
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.benchmark
|
||||
|
||||
import androidx.benchmark.junit4.BenchmarkRule
|
||||
import androidx.benchmark.junit4.measureRepeated
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.crypto.EventHasher
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
/**
|
||||
* Benchmark, which will execute on an Android device.
|
||||
*
|
||||
* The body of [BenchmarkRule.measureRepeated] is measured in a loop, and Studio will output the
|
||||
* result. Modify your code to see how it affects performance.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class EventVerifySerializer {
|
||||
@get:Rule
|
||||
val benchmarkRule = BenchmarkRule()
|
||||
|
||||
@Test
|
||||
fun serializeToCheckId() {
|
||||
val event = Event.fromJson(largeKind1Event)
|
||||
benchmarkRule.measureRepeated {
|
||||
EventHasher.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun fastSerializeToCheckId() {
|
||||
val event = Event.fromJson(largeKind1Event)
|
||||
benchmarkRule.measureRepeated {
|
||||
EventHasher.fastMakeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,13 @@ class HexBenchmark {
|
||||
fr.acinq.secp256k1.Hex
|
||||
.decode(hex)
|
||||
|
||||
@Test
|
||||
fun hexIsEqual() {
|
||||
r.measureRepeated {
|
||||
assert(Hex.isEqual(hex, bytes))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hexDecodeOurs() {
|
||||
r.measureRepeated {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[versions]
|
||||
accompanistAdaptive = "0.37.3"
|
||||
activityCompose = "1.10.1"
|
||||
activityCompose = "1.11.0"
|
||||
agp = "8.13.0"
|
||||
android-compileSdk = "36"
|
||||
android-minSdk = "26"
|
||||
@@ -9,25 +9,25 @@ androidKotlinGeohash = "b481c6a64e"
|
||||
androidxJunit = "1.3.0"
|
||||
appcompat = "1.7.1"
|
||||
audiowaveform = "1.1.2"
|
||||
benchmark = "1.4.0"
|
||||
benchmarkJunit4 = "1.4.0"
|
||||
benchmark = "1.4.1"
|
||||
benchmarkJunit4 = "1.4.1"
|
||||
biometricKtx = "1.2.0-alpha05"
|
||||
coil = "3.3.0"
|
||||
composeBom = "2025.08.01"
|
||||
composeBom = "2025.09.00"
|
||||
coreKtx = "1.17.0"
|
||||
datastore = "1.1.7"
|
||||
espressoCore = "3.7.0"
|
||||
firebaseBom = "34.2.0"
|
||||
fragmentKtx = "1.8.9"
|
||||
gms = "4.4.3"
|
||||
jacksonModuleKotlin = "2.19.2"
|
||||
jacksonModuleKotlin = "2.20.0"
|
||||
jna = "5.17.0"
|
||||
jtorctl = "0.4.5.7"
|
||||
junit = "4.13.2"
|
||||
kotlin = "2.2.10"
|
||||
kotlin = "2.2.20"
|
||||
kotlinxCollectionsImmutable = "0.4.0"
|
||||
kotlinxSerialization = "1.9.0"
|
||||
kotlinxSerializationPlugin = "2.2.10"
|
||||
kotlinxSerializationPlugin = "2.2.20"
|
||||
languageId = "17.0.6"
|
||||
lazysodiumAndroid = "5.2.0"
|
||||
lifecycleRuntimeKtx = "2.9.3"
|
||||
@@ -36,7 +36,7 @@ markdown = "e1151c8"
|
||||
media3 = "1.8.0"
|
||||
mockk = "1.14.5"
|
||||
kotlinx-coroutines-test = "1.10.2"
|
||||
navigationCompose = "2.9.3"
|
||||
navigationCompose = "2.9.4"
|
||||
okhttp = "5.1.0"
|
||||
runner = "1.7.0"
|
||||
rfc3986 = "0.1.2"
|
||||
@@ -53,7 +53,7 @@ zoomable = "2.8.1"
|
||||
zxing = "3.5.3"
|
||||
zxingAndroidEmbedded = "4.3.0"
|
||||
windowCoreAndroid = "1.4.0"
|
||||
androidxCamera = "1.4.2"
|
||||
androidxCamera = "1.5.0"
|
||||
kotlinStdlib = "2.2.10"
|
||||
kotlinTest = "2.2.10"
|
||||
core = "1.7.0"
|
||||
|
||||
+101
@@ -21,7 +21,14 @@
|
||||
package com.vitorpamplona.quartz.nip01Core
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.vitorpamplona.quartz.EventFactory
|
||||
import com.vitorpamplona.quartz.nip01Core.crypto.EventHasher
|
||||
import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper
|
||||
import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||
import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import junit.framework.TestCase.assertTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@@ -58,4 +65,98 @@ class EventSigCheck {
|
||||
// Should pass
|
||||
event.checkSignature()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkSerializationWithEmojis() {
|
||||
val event =
|
||||
EventFactory.create<ReactionEvent>(
|
||||
id = "ac2fb0c9b72a6fefe60262fbce6eb8740380b7f964200cb8efdd2e72fcb1ddb0",
|
||||
pubKey = "460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c",
|
||||
createdAt = 1690288395,
|
||||
kind = 7,
|
||||
tags =
|
||||
arrayOf(
|
||||
arrayOf("e", "2cc5b6e012c5a64fcf580fc1b53bed25ed0d7f785fd896744524b1a114dcc86e"),
|
||||
arrayOf("p", "c80b5248fbe8f392bc3ba45091fb4e6e2b5872387601bf90f53992366b30d720"),
|
||||
),
|
||||
content = "🚀",
|
||||
sig = "6df6aeef98c21a0508a788cbe6a2a6825e5cc69e57dd843dc6e6d4ce2c28dd042947723fda3d8b24489305d86b1e81f9f66b390d6f7dabf9742cd3775e17e53f",
|
||||
)
|
||||
|
||||
val old = EventHasher.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content)
|
||||
val new = EventHasher.fastMakeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content)
|
||||
|
||||
assertEquals(old.toByteArray().joinToString(), new.joinToString())
|
||||
assertTrue(event.verifySignature())
|
||||
assertTrue(event.verifyId())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkSerializationWithUnicode() {
|
||||
val event =
|
||||
EventFactory.create<ClassifiedsEvent>(
|
||||
id = "e395a1a4cad5b9cf930533c48c2dd175a40331a1d33af8f11b776a0970bc1446",
|
||||
pubKey = "3fa2504f693c7f0fe71bded634339ae5383a8b14b4164d7c4935830b048dce12",
|
||||
createdAt = 1707335824,
|
||||
kind = 30402,
|
||||
tags =
|
||||
arrayOf(
|
||||
arrayOf("d", "b5dd96da-eb92-463a-9cfd-70f1c5ca7e64"),
|
||||
arrayOf("title", "Google Pixel 7A (NUOVO)\n8GB RAM/128GB MEMORIA"),
|
||||
arrayOf("summary", "📱Google Pixel 7A (NUOVO)\n👉 8GB RAM/128GB MEMORIA \n\nRete : 5G\nColore : Grigio antracite\n\n👤Sistema operativo : GrapheneOS \n\n🔥Riacquista la tua privacy🔥\n\nℹ️Spacchettato solo per modifica ROM.\n\nNessuna app google e servizi google\n\nSolo app opensource \n\nSet-up privacy oriented incluso dedicato in base a vostre esigenze con Profili dedicati personale/lavoro, Vpn e Tor\n\n🔸️Android 14\n🔸️GrapheneOS ROM !!!!!!!\n🔸️Adattatore incluso Usb c / Usb per passaggio dati\n🔸️Ricarica con connettore USB Type-C \n🔸Dual SIM (nano SIM singola ed eSIM)\n🔸️Schermo da 6.1 pollici\n🔸️Fotocamera da 64 megapixel\n🔸️8 gb memoria ram\n🔸️128 gb memoria interna\n🔸Dimensioni: 155 x 152 x 72.9 mm\n🔸Sblocco con l'impronta tramite sensore di impronte digitali integrato nel display\n🔸️Batteria da 4385 mAh (Ricarica veloce e Ricarica wireless)\n🔸Materiali: Rivestimento in vetro Corning Gorilla Glass 3 resistente ai graffi\n🔸Resistenza all'acqua e alla polvere di grado IP67 \n\n✅️Cover in slicone in omaggio🔥\n\n💶PREZZO💶 \n\n💰380 € ( SOLO IN BITCOIN) \n\n🚚spedizione privacy oriented da Punto di ritiro a Punto di ritiro (SOLO ITALIA) inclusa, solo scrivendo allo Zio il ref: \"Ziophone21\" \n\n🚚Spedizione Full Privacy ( PREMIUM) \nNessun dato da parte utente, per chi necessitasse di questa sped, la differenza si paga a parte.\n\nAccettati pagamenti:\nBTC 🔗\nBTC ⚡️\nBTC💧\nhttps://image.nostr.build/87c79c56f270ca04607bc6d72b21786837f81344a960a3787820dc0c482c6660.jpg#m=image%2Fjpeg&dim=1254x1280&blurhash=%7CWHB--yGi%5E4mR3IVV%40RhIT%25LIpf5t6RjofafofWBMcMxbH%25MbJofofogt7j%5Bt7azWBoeWVj%5BayayD%24RikCt8t8off7j%5DogWBoej%5BWCofayazayoeROV%40j%5DogfloebHa%7DkCj%3Fayj%5Bj%5Bj%5Bayj%5BWVj%40e-fPa%7Dj%5BWVj%40j%5Ba%23j%5B&x=17b7ff98875a6e6d6e6bddee30e0a1c18ccf4281db940ee8b5bcc0736d2137c6"),
|
||||
arrayOf("price", "1000", "SATS"),
|
||||
arrayOf("t", "Electronics"),
|
||||
arrayOf("location", "Brescia Italia"),
|
||||
arrayOf("publishedAt", "1707335824"),
|
||||
arrayOf("condition", "like new"),
|
||||
arrayOf("image", "https://image.nostr.build/87c79c56f270ca04607bc6d72b21786837f81344a960a3787820dc0c482c6660.jpg#m=image%2Fjpeg&dim=1254x1280&blurhash=%7CWHB--yGi%5E4mR3IVV%40RhIT%25LIpf5t6RjofafofWBMcMxbH%25MbJofofogt7j%5Bt7azWBoeWVj%5BayayD%24RikCt8t8off7j%5DogWBoej%5BWCofayazayoeROV%40j%5DogfloebHa%7DkCj%3Fayj%5Bj%5Bj%5Bayj%5BWVj%40e-fPa%7Dj%5BWVj%40j%5Ba%23j%5B&x=17b7ff98875a6e6d6e6bddee30e0a1c18ccf4281db940ee8b5bcc0736d2137c6"),
|
||||
arrayOf("r", "https://image.nostr.build/87c79c56f270ca04607bc6d72b21786837f81344a960a3787820dc0c482c6660.jpg#m=image%2Fjpeg&dim=1254x1280&blurhash=%7CWHB--yGi%5E4mR3IVV%40RhIT%25LIpf5t6RjofafofWBMcMxbH%25MbJofofogt7j%5Bt7azWBoeWVj%5BayayD%24RikCt8t8off7j%5DogWBoej%5BWCofayazayoeROV%40j%5DogfloebHa%7DkCj%3Fayj%5Bj%5Bj%5Bayj%5BWVj%40e-fPa%7Dj%5BWVj%40j%5Ba%23j%5B&x=17b7ff98875a6e6d6e6bddee30e0a1c18ccf4281db940ee8b5bcc0736d2137c6"),
|
||||
arrayOf("alt", "Classifieds listing"),
|
||||
),
|
||||
content = "📱Google Pixel 7A (NUOVO)\n👉 8GB RAM/128GB MEMORIA \n\nRete : 5G\nColore : Grigio antracite\n\n👤Sistema operativo : GrapheneOS \n\n🔥Riacquista la tua privacy🔥\n\nℹ️Spacchettato solo per modifica ROM.\n\nNessuna app google e servizi google\n\nSolo app opensource \n\nSet-up privacy oriented incluso dedicato in base a vostre esigenze con Profili dedicati personale/lavoro, Vpn e Tor\n\n🔸️Android 14\n🔸️GrapheneOS ROM !!!!!!!\n🔸️Adattatore incluso Usb c / Usb per passaggio dati\n🔸️Ricarica con connettore USB Type-C \n🔸Dual SIM (nano SIM singola ed eSIM)\n🔸️Schermo da 6.1 pollici\n🔸️Fotocamera da 64 megapixel\n🔸️8 gb memoria ram\n🔸️128 gb memoria interna\n🔸Dimensioni: 155 x 152 x 72.9 mm\n🔸Sblocco con l'impronta tramite sensore di impronte digitali integrato nel display\n🔸️Batteria da 4385 mAh (Ricarica veloce e Ricarica wireless)\n🔸Materiali: Rivestimento in vetro Corning Gorilla Glass 3 resistente ai graffi\n🔸Resistenza all'acqua e alla polvere di grado IP67 \n\n✅️Cover in slicone in omaggio🔥\n\n💶PREZZO💶 \n\n💰380 € ( SOLO IN BITCOIN) \n\n🚚spedizione privacy oriented da Punto di ritiro a Punto di ritiro (SOLO ITALIA) inclusa, solo scrivendo allo Zio il ref: \"Ziophone21\" \n\n🚚Spedizione Full Privacy ( PREMIUM) \nNessun dato da parte utente, per chi necessitasse di questa sped, la differenza si paga a parte.\n\nAccettati pagamenti:\nBTC 🔗\nBTC ⚡️\nBTC💧\nhttps://image.nostr.build/87c79c56f270ca04607bc6d72b21786837f81344a960a3787820dc0c482c6660.jpg#m=image%2Fjpeg&dim=1254x1280&blurhash=%7CWHB--yGi%5E4mR3IVV%40RhIT%25LIpf5t6RjofafofWBMcMxbH%25MbJofofogt7j%5Bt7azWBoeWVj%5BayayD%24RikCt8t8off7j%5DogWBoej%5BWCofayazayoeROV%40j%5DogfloebHa%7DkCj%3Fayj%5Bj%5Bj%5Bayj%5BWVj%40e-fPa%7Dj%5BWVj%40j%5Ba%23j%5B&x=17b7ff98875a6e6d6e6bddee30e0a1c18ccf4281db940ee8b5bcc0736d2137c6",
|
||||
sig = "e03c81ec2543e777583bfcf93c0d82d3055a47a541b1a961db010ed2390e56ddc59e4f891505672757b7ac0d52e891854fdd61f1a4e13b4e6aa563e94cb9368e",
|
||||
)
|
||||
|
||||
val old = EventHasher.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content)
|
||||
val new = EventHasher.fastMakeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content)
|
||||
|
||||
println(old)
|
||||
println(String(new))
|
||||
|
||||
assertEquals(old, String(new))
|
||||
assertTrue(event.verifySignature())
|
||||
assertTrue(event.verifyId())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkSerializationLargeZap() {
|
||||
val event =
|
||||
EventFactory.create<LnZapEvent>(
|
||||
id = "e7f09fddf39fc6cb604708b6af7b4d4adbb07b412847ebb004064040fe8c4b1e",
|
||||
pubKey = "79f00d3f5a19ec806189fcab03c1be4ff81d18ee4f653c88fac41fe03570f432",
|
||||
createdAt = 1728921077,
|
||||
kind = 9735,
|
||||
tags =
|
||||
arrayOf(
|
||||
arrayOf("p", "460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c"),
|
||||
arrayOf("e", "58f22b06a219f92fb535c71f7098e076751cf2798208acabbbdefbcb950585f5"),
|
||||
arrayOf("P", "21335073401a310cc9179fe3a77e9666710cfdf630dfd840f972c183a244b1ad"),
|
||||
arrayOf("bolt11", "lnbc420n1pns600jdqjfah8wctjvss0p8at5ynp4qtfc238rdkzsj26waa3l8zgag9damzltzsqcrlscj9gvpc7ch2qs2pp5ks03qwm8laa78hnh0xy0p78l6wmyuj3zfqas3gzc2a52lj2zrmtqsp539528j3tvvfzpk8n5v966zccvj3pq2l3etxqxh5qsp8emh29yw3q9qyysgqcqpcxqyz5vqrzjqvdnqyc82a9maxu6c7mee0shqr33u4z9z04wpdwhf96gxzpln8jcrapyqqqqqqp2rcqqqqlgqqqqqzsq2qrzjqw9fu4j39mycmg440ztkraa03u5qhtuc5zfgydsv6ml38qd4azymlapyqqqqqqqp9sqqqqlgqqqq86qqjqrzjq26922n6s5n5undqrf78rjjhgpcczafws45tx8237y7pzx3fg8wwxrgayyqq2mgqqqqqqqqqqqqqqqqq2quc90y7tgfxuauh0vjfvhxjgektaycfesne76jcuk4u9mt6a9l39pddzk3muwy03sjvfk0w8390xxnpzu2656jf2l73ya59ye2yx9aaqpdgxmaq"),
|
||||
arrayOf("preimage", "0718bf6ba9f503917a2568dac7fe7a5b9361eeb708cd5f57b700060a173ed652"),
|
||||
arrayOf("description", "{\"id\":\"1110d1216fff3200ed562439556be508a42e4202f66b55f09c9abeed06307d57\",\"pubkey\":\"21335073401a310cc9179fe3a77e9666710cfdf630dfd840f972c183a244b1ad\",\"created_at\":1728921073,\"kind\":9734,\"tags\":[[\"p\",\"460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c\"],[\"e\",\"58f22b06a219f92fb535c71f7098e076751cf2798208acabbbdefbcb950585f5\"],[\"amount\",\"42000\"],[\"relays\",\"wss://christpill.nostr1.com\",\"wss://relay.nostr.bg\",\"wss://relay.noderunners.network\",\"wss://relay.nostrplebs.com\",\"wss://relay.utxo.one\",\"wss://filter.nostr.wine\",\"wss://pyramid.fiatjaf.com\",\"wss://wot.utxo.one\",\"wss://relay.mostr.pub\",\"wss://relay.nostr.band\",\"wss://relay.primal.net\",\"wss://relay.snort.social\",\"wss://purplepag.es\",\"wss://wot.nostr.party\",\"wss://catstrr.swarmstr.com\",\"wss://nostr-relay.derekross.me\",\"wss://relay.damus.io\",\"wss://nos.lol\",\"wss://nostr.wine\",\"wss://relay.bitcoinpark.com\",\"wss://sendit.nosflare.com\",\"wss://nostrelites.org\",\"wss://relay.momostr.pink\",\"ws://localhost:4869\"]],\"content\":\"Onward 🫡\",\"sig\":\"82333a70103b6541f125ac64379a32ad0e9a51eb2769cf899c88df8406bdfa339693d530e640d1c701f4d9d7d847806e1ee2118655b7ba3f9795ce56747eff1b\"}"),
|
||||
),
|
||||
content = "Onward \uD83E\uDEE1",
|
||||
sig = "81d08765524bd8b774585a57c76d25b1d2c09eaa23efcb075226ba8b64f42e3d9d9403e5edf888e0e58702a24abc084259e21b97e24a275021c5e36186c65f0c",
|
||||
)
|
||||
|
||||
val old = EventHasher.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content)
|
||||
val new = EventHasher.fastMakeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content)
|
||||
|
||||
println(old)
|
||||
println(String(new))
|
||||
|
||||
assertEquals(old.toByteArray().joinToString(), new.joinToString())
|
||||
assertTrue(event.verifySignature())
|
||||
assertTrue(event.verifyId())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ fun Event.generateId(): String = EventHasher.hashId(pubKey, createdAt, kind, tag
|
||||
|
||||
fun Event.verifyId(): Boolean {
|
||||
if (id.isEmpty()) return false
|
||||
return id == generateId()
|
||||
return EventHasher.hashIdEquals(id, pubKey, createdAt, kind, tags, content)
|
||||
}
|
||||
|
||||
fun Event.verifySignature(): Boolean {
|
||||
|
||||
+66
-1
@@ -20,12 +20,20 @@
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip01Core.crypto
|
||||
|
||||
import com.fasterxml.jackson.core.JsonEncoding
|
||||
import com.fasterxml.jackson.core.JsonGenerator
|
||||
import com.fasterxml.jackson.core.JsonProcessingException
|
||||
import com.fasterxml.jackson.core.util.BufferRecycler
|
||||
import com.fasterxml.jackson.core.util.ByteArrayBuilder
|
||||
import com.fasterxml.jackson.databind.JsonMappingException
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper
|
||||
import com.vitorpamplona.quartz.utils.Hex
|
||||
import com.vitorpamplona.quartz.utils.sha256.sha256
|
||||
import java.io.IOException
|
||||
|
||||
class EventHasher {
|
||||
companion object {
|
||||
@@ -63,13 +71,58 @@ class EventHasher {
|
||||
content: String,
|
||||
): String = JsonMapper.toJson(makeJsonObjectForId(pubKey, createdAt, kind, tags, content))
|
||||
|
||||
fun fastMakeJsonForId(
|
||||
pubKey: HexKey,
|
||||
createdAt: Long,
|
||||
kind: Int,
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
): ByteArray {
|
||||
val br: BufferRecycler = JsonMapper.mapper.factory._getBufferRecycler()
|
||||
try {
|
||||
ByteArrayBuilder(br).use { bb ->
|
||||
val generator = JsonMapper.mapper.createGenerator(bb, JsonEncoding.UTF8)
|
||||
generator.enable(JsonGenerator.Feature.COMBINE_UNICODE_SURROGATES_IN_UTF8)
|
||||
generator.use {
|
||||
it.writeStartArray()
|
||||
it.writeNumber(0)
|
||||
it.writeString(pubKey)
|
||||
it.writeNumber(createdAt)
|
||||
it.writeNumber(kind)
|
||||
it.writeStartArray()
|
||||
tags.forEach { tag ->
|
||||
it.writeStartArray()
|
||||
tag.forEach { value ->
|
||||
it.writeString(value)
|
||||
}
|
||||
it.writeEndArray()
|
||||
}
|
||||
it.writeEndArray()
|
||||
it.writeString(content)
|
||||
it.writeEndArray()
|
||||
}
|
||||
|
||||
val result = bb.toByteArray()
|
||||
bb.release()
|
||||
return result
|
||||
}
|
||||
} catch (e: JsonProcessingException) {
|
||||
throw e
|
||||
} catch (e: IOException) {
|
||||
// shouldn't really happen, but is declared as possibility so:
|
||||
throw JsonMappingException.fromUnexpectedIOE(e)
|
||||
} finally {
|
||||
br.releaseToPool()
|
||||
}
|
||||
}
|
||||
|
||||
fun hashIdBytes(
|
||||
pubKey: HexKey,
|
||||
createdAt: Long,
|
||||
kind: Int,
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
): ByteArray = sha256(makeJsonForId(pubKey, createdAt, kind, tags, content).toByteArray())
|
||||
): ByteArray = sha256(fastMakeJsonForId(pubKey, createdAt, kind, tags, content))
|
||||
|
||||
fun hashId(serializedJsonAsBytes: ByteArray): String = sha256(serializedJsonAsBytes).toHexKey()
|
||||
|
||||
@@ -80,5 +133,17 @@ class EventHasher {
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
): String = hashIdBytes(pubKey, createdAt, kind, tags, content).toHexKey()
|
||||
|
||||
fun hashIdEquals(
|
||||
id: HexKey,
|
||||
pubKey: HexKey,
|
||||
createdAt: Long,
|
||||
kind: Int,
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
): Boolean {
|
||||
val outId = hashIdBytes(pubKey, createdAt, kind, tags, content)
|
||||
return Hex.isEqual(id, outId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
|
||||
object RelayStats {
|
||||
private val innerCache =
|
||||
object : LruCache<NormalizedRelayUrl, RelayStat>(100) {
|
||||
object : LruCache<NormalizedRelayUrl, RelayStat>(1000) {
|
||||
override fun create(key: NormalizedRelayUrl?) = RelayStat()
|
||||
}
|
||||
|
||||
|
||||
@@ -79,13 +79,13 @@ class PoWMiner(
|
||||
|
||||
val bytes =
|
||||
EventHasher
|
||||
.makeJsonForId(
|
||||
pubKey,
|
||||
template.createdAt,
|
||||
template.kind,
|
||||
template.tags + PoWTag.assemble(initialNonce, desiredPoW),
|
||||
template.content,
|
||||
).toByteArray()
|
||||
.fastMakeJsonForId(
|
||||
pubKey = pubKey,
|
||||
createdAt = template.createdAt,
|
||||
kind = template.kind,
|
||||
tags = template.tags + PoWTag.assemble(initialNonce, desiredPoW),
|
||||
content = template.content,
|
||||
)
|
||||
|
||||
val startIndex = bytes.indexOf(initialNonce.toByteArray())
|
||||
|
||||
|
||||
+4
@@ -23,6 +23,7 @@ package com.vitorpamplona.quartz.nip28PublicChat.admin
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.fasterxml.jackson.core.JsonParseException
|
||||
import com.fasterxml.jackson.databind.exc.MismatchedInputException
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
@@ -68,6 +69,9 @@ class ChannelCreateEvent(
|
||||
} catch (e: JsonParseException) {
|
||||
Log.w("ChannelCreateEvent", "Failure to parse ${this.toJson()}", e)
|
||||
ChannelDataNorm()
|
||||
} catch (e: MismatchedInputException) {
|
||||
Log.w("ChannelCreateEvent", "Failure to parse ${this.toJson()}", e)
|
||||
ChannelDataNorm()
|
||||
}
|
||||
|
||||
cache = newInfo
|
||||
|
||||
@@ -47,7 +47,6 @@ import com.vitorpamplona.quartz.nip19Bech32.eventIds
|
||||
import com.vitorpamplona.quartz.nip19Bech32.pubKeyHints
|
||||
import com.vitorpamplona.quartz.nip19Bech32.pubKeys
|
||||
import com.vitorpamplona.quartz.nip23LongContent.tags.PublishedAtTag
|
||||
import com.vitorpamplona.quartz.nip23LongContent.tags.PublishedAtTag.Companion.parse
|
||||
import com.vitorpamplona.quartz.nip31Alts.AltTag
|
||||
import com.vitorpamplona.quartz.nip50Search.SearchableEvent
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
-1
@@ -27,7 +27,6 @@ import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag
|
||||
import com.vitorpamplona.quartz.nip22Comments.RootScope
|
||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||
import com.vitorpamplona.quartz.nip71Video.videoIMetas
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import java.util.UUID
|
||||
|
||||
|
||||
@@ -74,4 +74,21 @@ object Hex {
|
||||
}
|
||||
return String(out)
|
||||
}
|
||||
|
||||
fun isEqual(
|
||||
id: String,
|
||||
ourId: ByteArray,
|
||||
): Boolean {
|
||||
var charIndex = 0
|
||||
for (i in 0 until ourId.size) {
|
||||
val chars = byteToHex[ourId[i].toInt() and 0xFF]
|
||||
if (
|
||||
id[charIndex++] != (chars shr 8).toChar() ||
|
||||
id[charIndex++] != (chars and 0xFF).toChar()
|
||||
) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user