mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-11-10 12:07:11 +01:00
Merge branch 'main' into main
This commit is contained in:
@@ -57,7 +57,9 @@ dependencies {
|
||||
implementation 'net.java.dev.jna:jna:5.14.0@aar'
|
||||
|
||||
// Performant Parser of JSONs into Events
|
||||
api libs.jackson.module.kotlin
|
||||
api(libs.jackson.module.kotlin) {
|
||||
exclude(module: 'byte-buddy') // Workaround https://github.com/FasterXML/jackson-databind/issues/4428 until Jackson 2.17.1
|
||||
}
|
||||
|
||||
// immutable collections to avoid recomposition
|
||||
api libs.kotlinx.collections.immutable
|
||||
@@ -66,6 +68,7 @@ dependencies {
|
||||
api libs.url.detector
|
||||
|
||||
testImplementation libs.junit
|
||||
androidTestImplementation platform(libs.androidx.compose.bom)
|
||||
androidTestImplementation libs.androidx.junit
|
||||
androidTestImplementation libs.androidx.espresso.core
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# preserve the line number information for debugging stack traces.
|
||||
-dontobfuscate
|
||||
-keepattributes LocalVariableTable
|
||||
-keepattributes LocalVariableTypeTable
|
||||
-keepattributes *Annotation*
|
||||
-keepattributes SourceFile
|
||||
-keepattributes LineNumberTable
|
||||
-keepattributes Signature
|
||||
-keepattributes Exceptions
|
||||
-keepattributes InnerClasses
|
||||
-keepattributes EnclosingMethod
|
||||
-keepattributes MethodParameters
|
||||
-keepparameternames
|
||||
|
||||
-keepdirectories libs
|
||||
|
||||
# Keep all names
|
||||
-keepnames class ** { *; }
|
||||
|
||||
# Keep All enums
|
||||
-keep enum ** { *; }
|
||||
|
||||
# preserve access to native classses
|
||||
-keep class fr.acinq.secp256k1.** { *; }
|
||||
|
||||
# JNA For Libsodium
|
||||
-keep class com.goterl.lazysodium.** { *; }
|
||||
|
||||
# libscrypt
|
||||
-keep class com.lambdaworks.codec.** { *; }
|
||||
-keep class com.lambdaworks.crypto.** { *; }
|
||||
-keep class com.lambdaworks.jni.** { *; }
|
||||
|
||||
# JNA also requires AWT, which Android does not have. So the classes are broken down to filter AWT out
|
||||
-keep class com.sun.jna.ToNativeConverter { *; }
|
||||
-keep class com.sun.jna.NativeMapped { *; }
|
||||
-keep class com.sun.jna.CallbackReference { *; }
|
||||
-keep class com.sun.jna.ptr.IntByReference { *; }
|
||||
-keep class com.sun.jna.NativeLong { *; }
|
||||
-keep class com.sun.jna.Structure { *; }
|
||||
-keep class com.sun.jna.Structure$* { *; }
|
||||
-keep class com.sun.jna.Native$ffi_callback { *; }
|
||||
-keep class * implements com.sun.jna.Structure$* { *; }
|
||||
-keep class * implements com.sun.jna.Native$* { *; }
|
||||
-keep class com.sun.jna.Native {
|
||||
private static com.sun.jna.NativeMapped fromNative(java.lang.Class, java.lang.Object);
|
||||
private static com.sun.jna.NativeMapped fromNative(java.lang.reflect.Method, java.lang.Object);
|
||||
private static java.lang.Class nativeType(java.lang.Class);
|
||||
private static java.lang.Object toNative(com.sun.jna.ToNativeConverter, java.lang.Object);
|
||||
private static java.lang.Object fromNative(com.sun.jna.FromNativeConverter, java.lang.Object, java.lang.reflect.Method);
|
||||
}
|
||||
|
||||
# JSON parsing
|
||||
-keep class com.vitorpamplona.quartz.crypto.** { *; }
|
||||
-keep class com.vitorpamplona.quartz.encoders.** { *; }
|
||||
-keep class com.vitorpamplona.quartz.events.** { *; }
|
||||
-keep class com.vitorpamplona.quartz.signers.** { *; }
|
||||
-keep class com.vitorpamplona.quartz.utils.** { *; }
|
||||
|
||||
-keep class com.vitorpamplona.amethyst.model.** { *; }
|
||||
-keep class com.vitorpamplona.amethyst.service.** { *; }
|
||||
BIN
quartz/src/androidTest/assets/nostr_vitor_startup_data.json
Normal file
BIN
quartz/src/androidTest/assets/nostr_vitor_startup_data.json
Normal file
Binary file not shown.
@@ -30,6 +30,7 @@ import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.io.InputStreamReader
|
||||
import java.util.zip.GZIPInputStream
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class LargeDBSignatureCheck {
|
||||
@@ -49,6 +50,28 @@ class LargeDBSignatureCheck {
|
||||
counter++
|
||||
}
|
||||
|
||||
assertEquals(eventArray.size, counter)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun insertStartupDatabase() =
|
||||
runBlocking {
|
||||
// This file includes duplicates
|
||||
val fullDBInputStream = getInstrumentation().context.assets.open("nostr_vitor_startup_data.json")
|
||||
|
||||
val eventArray =
|
||||
Event.mapper.readValue<ArrayList<Event>>(
|
||||
GZIPInputStream(fullDBInputStream),
|
||||
) as List<Event>
|
||||
|
||||
var counter = 0
|
||||
eventArray.forEach {
|
||||
if (it.sig != "") {
|
||||
assertTrue(it.hasValidSignature())
|
||||
}
|
||||
counter++
|
||||
}
|
||||
|
||||
assertEquals(eventArray.size, counter)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ open class Event(
|
||||
val content: String,
|
||||
val sig: HexKey,
|
||||
) : EventInterface {
|
||||
override fun isContentEncoded() = false
|
||||
|
||||
override fun countMemory(): Long {
|
||||
return 12L +
|
||||
id.bytesUsedInMemory() +
|
||||
|
||||
@@ -27,6 +27,8 @@ import java.math.BigDecimal
|
||||
|
||||
@Immutable
|
||||
interface EventInterface {
|
||||
fun isContentEncoded(): Boolean
|
||||
|
||||
fun countMemory(): Long
|
||||
|
||||
fun id(): HexKey
|
||||
|
||||
@@ -36,6 +36,8 @@ class FileStorageEvent(
|
||||
content: String,
|
||||
sig: HexKey,
|
||||
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
override fun isContentEncoded() = true
|
||||
|
||||
fun type() = tags.firstOrNull { it.size > 1 && it[0] == TYPE }?.get(1)
|
||||
|
||||
fun decryptKey() = tags.firstOrNull { it.size > 2 && it[0] == DECRYPT }?.let { AESGCM(it[1], it[2]) }
|
||||
|
||||
@@ -42,6 +42,8 @@ abstract class GeneralListEvent(
|
||||
) : BaseAddressableEvent(id, pubKey, createdAt, kind, tags, content, sig) {
|
||||
@Transient private var privateTagsCache: Array<Array<String>>? = null
|
||||
|
||||
override fun isContentEncoded() = true
|
||||
|
||||
fun category() = dTag()
|
||||
|
||||
fun bookmarkedPosts() = taggedEvents()
|
||||
|
||||
@@ -38,6 +38,8 @@ class GiftWrapEvent(
|
||||
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
@Transient private var cachedInnerEvent: Map<HexKey, Event?> = mapOf()
|
||||
|
||||
override fun isContentEncoded() = true
|
||||
|
||||
fun preCachedGift(signer: NostrSigner): Event? {
|
||||
return cachedInnerEvent[signer.pubKey]
|
||||
}
|
||||
|
||||
@@ -34,13 +34,13 @@ class HighlightEvent(
|
||||
content: String,
|
||||
sig: HexKey,
|
||||
) : BaseTextNoteEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
fun inUrl() = taggedUrls().firstOrNull()
|
||||
fun inUrl() = firstTaggedUrl()
|
||||
|
||||
fun author() = taggedUsers().firstOrNull()
|
||||
fun author() = firstTaggedUser()
|
||||
|
||||
fun quote() = content
|
||||
|
||||
fun inPost() = taggedAddresses().firstOrNull()
|
||||
fun inPost() = firstTaggedAddress()
|
||||
|
||||
companion object {
|
||||
const val KIND = 9802
|
||||
|
||||
@@ -48,6 +48,8 @@ class OtsEvent(
|
||||
@Transient
|
||||
var verifiedTime: Long? = null
|
||||
|
||||
override fun isContentEncoded() = true
|
||||
|
||||
fun digestEvent() = tags.firstOrNull { it.size > 1 && it[0] == "e" }?.get(1)
|
||||
|
||||
fun digest() = digestEvent()?.hexToByteArray()
|
||||
|
||||
@@ -40,6 +40,8 @@ class PrivateDmEvent(
|
||||
) : Event(id, pubKey, createdAt, KIND, tags, content, sig), ChatroomKeyable {
|
||||
@Transient private var decryptedContent: Map<HexKey, String> = mapOf()
|
||||
|
||||
override fun isContentEncoded() = true
|
||||
|
||||
/**
|
||||
* This may or may not be the actual recipient's pub key. The event is intended to look like a
|
||||
* nip-04 EncryptedDmEvent but may omit the recipient, too. This value can be queried and used for
|
||||
|
||||
@@ -39,6 +39,8 @@ class SealedGossipEvent(
|
||||
) : WrappedEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
@Transient private var cachedInnerEvent: Map<HexKey, Event?> = mapOf()
|
||||
|
||||
override fun isContentEncoded() = true
|
||||
|
||||
fun preCachedGossip(signer: NostrSigner): Event? {
|
||||
return cachedInnerEvent[signer.pubKey]
|
||||
}
|
||||
|
||||
@@ -37,12 +37,12 @@ class Nip30Test {
|
||||
|
||||
assertEquals(
|
||||
"Alex Gleason ",
|
||||
(result!![0] as Nip30CustomEmoji.TextType).text,
|
||||
(result[0] as Nip30CustomEmoji.TextType).text,
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
"http://soapbox",
|
||||
(result!![1] as Nip30CustomEmoji.ImageUrlType).url,
|
||||
(result[1] as Nip30CustomEmoji.ImageUrlType).url,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -57,12 +57,12 @@ class Nip30Test {
|
||||
|
||||
assertEquals(
|
||||
"http://soapbox",
|
||||
(result!![0] as Nip30CustomEmoji.ImageUrlType).url,
|
||||
(result[0] as Nip30CustomEmoji.ImageUrlType).url,
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
"Alex Gleason",
|
||||
(result!![1] as Nip30CustomEmoji.TextType).text,
|
||||
(result[1] as Nip30CustomEmoji.TextType).text,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -80,19 +80,19 @@ class Nip30Test {
|
||||
|
||||
assertEquals(7, result!!.size)
|
||||
|
||||
assertEquals("Hello ", (result!![0] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals("Hello ", (result[0] as Nip30CustomEmoji.TextType).text)
|
||||
|
||||
assertEquals("http://gleasonator", (result!![1] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
assertEquals("http://gleasonator", (result[1] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
|
||||
assertEquals(" 😂 ", (result!![2] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals(" 😂 ", (result[2] as Nip30CustomEmoji.TextType).text)
|
||||
|
||||
assertEquals("http://ablobcatrainbow", (result!![3] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
assertEquals("http://ablobcatrainbow", (result[3] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
|
||||
assertEquals(" ", (result!![4] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals(" ", (result[4] as Nip30CustomEmoji.TextType).text)
|
||||
|
||||
assertEquals("http://disputed", (result!![5] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
assertEquals("http://disputed", (result[5] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
|
||||
assertEquals(" yolo", (result!![6] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals(" yolo", (result[6] as Nip30CustomEmoji.TextType).text)
|
||||
}
|
||||
|
||||
@Test()
|
||||
@@ -114,11 +114,11 @@ class Nip30Test {
|
||||
|
||||
assertEquals(3, result!!.size)
|
||||
|
||||
assertEquals("hello ", (result!![0] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals("hello ", (result[0] as Nip30CustomEmoji.TextType).text)
|
||||
|
||||
assertEquals("http://vitor", (result!![1] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
assertEquals("http://vitor", (result[1] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
|
||||
assertEquals(" how :can I help:", (result!![2] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals(" how :can I help:", (result[2] as Nip30CustomEmoji.TextType).text)
|
||||
}
|
||||
|
||||
@Test()
|
||||
@@ -130,9 +130,9 @@ class Nip30Test {
|
||||
|
||||
assertEquals(3, result!!.size)
|
||||
|
||||
assertEquals("\uD883\uDEDE\uD883\uDEDE麺の", (result!![0] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals("http://x30EDE", (result!![1] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
assertEquals("。:\uD883\uDEDE:(Violation of NIP-30)", (result!![2] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals("\uD883\uDEDE\uD883\uDEDE麺の", (result[0] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals("http://x30EDE", (result[1] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
assertEquals("。:\uD883\uDEDE:(Violation of NIP-30)", (result[2] as Nip30CustomEmoji.TextType).text)
|
||||
}
|
||||
|
||||
@Test()
|
||||
@@ -155,14 +155,14 @@ class Nip30Test {
|
||||
assertEquals(9, result!!.size)
|
||||
|
||||
var i = 0
|
||||
assertEquals("\u200B", (result!![i++] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals("https://media.misskeyusercontent.com/emoji/_ri.png", (result!![i++] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
assertEquals("\u200B\u200B", (result!![i++] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals("https://media.misskeyusercontent.com/emoji/_ri.png", (result!![i++] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
assertEquals("\u200Bはベイクドモチョチョ\u200B", (result!![i++] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals("https://media.misskeyusercontent.com/emoji/petthex_japanesecake.gif", (result!![i++] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
assertEquals("\u200Bを食べました\u200B", (result!![i++] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals("https://media.misskeyusercontent.com/misskey/f6294900-f678-43cc-bc36-3ee5deeca4c2.gif", (result!![i++] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
assertEquals("\u200B\n#ioメシヨソイゲーム\nhttps://misskey.io/play/9g3qza4jow", (result!![i++] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals("\u200B", (result[i++] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals("https://media.misskeyusercontent.com/emoji/_ri.png", (result[i++] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
assertEquals("\u200B\u200B", (result[i++] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals("https://media.misskeyusercontent.com/emoji/_ri.png", (result[i++] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
assertEquals("\u200Bはベイクドモチョチョ\u200B", (result[i++] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals("https://media.misskeyusercontent.com/emoji/petthex_japanesecake.gif", (result[i++] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
assertEquals("\u200Bを食べました\u200B", (result[i++] as Nip30CustomEmoji.TextType).text)
|
||||
assertEquals("https://media.misskeyusercontent.com/misskey/f6294900-f678-43cc-bc36-3ee5deeca4c2.gif", (result[i++] as Nip30CustomEmoji.ImageUrlType).url)
|
||||
assertEquals("\u200B\n#ioメシヨソイゲーム\nhttps://misskey.io/play/9g3qza4jow", (result[i] as Nip30CustomEmoji.TextType).text)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user