diff --git a/commons/build.gradle.kts b/commons/build.gradle.kts index 427ed28b4..90ccd7d18 100644 --- a/commons/build.gradle.kts +++ b/commons/build.gradle.kts @@ -104,6 +104,9 @@ kotlin { // Desktop-specific Compose implementation(compose.desktop.currentOs) implementation(compose.uiTooling) + + // Secure key storage via OS keychain (macOS/Windows/Linux) + implementation(libs.java.keyring) } } @@ -112,6 +115,10 @@ kotlin { dependencies { // Android-specific Compose tooling implementation(libs.androidx.ui.tooling.preview) + + // Secure key storage via Android Keystore + implementation(libs.androidx.security.crypto.ktx) + implementation(libs.androidx.datastore.preferences) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/KeyStoreEncryption.kt b/commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/keystorage/KeyStoreEncryption.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/KeyStoreEncryption.kt rename to commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/keystorage/KeyStoreEncryption.kt index 548ad6b21..34813cb6e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/KeyStoreEncryption.kt +++ b/commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/keystorage/KeyStoreEncryption.kt @@ -18,7 +18,7 @@ * 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.nip01Core.crypto +package com.vitorpamplona.amethyst.commons.keystorage import android.os.Build import android.security.keystore.KeyGenParameterSpec diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/SecureKeyStorage.kt b/commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/keystorage/SecureKeyStorage.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/SecureKeyStorage.kt rename to commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/keystorage/SecureKeyStorage.kt index 771c7e971..9ee5d1f57 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/SecureKeyStorage.kt +++ b/commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/keystorage/SecureKeyStorage.kt @@ -18,7 +18,7 @@ * 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.nip01Core.crypto +package com.vitorpamplona.amethyst.commons.keystorage import android.content.Context import androidx.security.crypto.EncryptedSharedPreferences diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/filters/FilterBuilders.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/filters/FilterBuilders.kt index 33bee5095..a93c6cf52 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/filters/FilterBuilders.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/filters/FilterBuilders.kt @@ -276,6 +276,7 @@ class FilterBuilder { private var authors: List? = null private var kinds: List? = null private var tags: MutableMap>? = null + private var tagsAll: MutableMap>? = null private var since: Long? = null private var until: Long? = null private var limit: Int? = null @@ -313,6 +314,14 @@ class FilterBuilder { tags!![name] = values } + fun tagAll( + name: String, + values: List, + ) { + if (tagsAll == null) tagsAll = mutableMapOf() + tagsAll!![name] = values + } + fun pTag(vararg pubKeys: String) { tag("p", pubKeys.toList()) } @@ -337,7 +346,7 @@ class FilterBuilder { this.search = search } - fun build(): Filter = Filter(ids, authors, kinds, tags, since, until, limit, search) + fun build(): Filter = Filter(ids, authors, kinds, tags, tagsAll, since, until, limit, search) } /** diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/SecureKeyStorage.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/keystorage/SecureKeyStorage.kt similarity index 98% rename from quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/SecureKeyStorage.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/keystorage/SecureKeyStorage.kt index d94171404..6dc292df1 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/SecureKeyStorage.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/keystorage/SecureKeyStorage.kt @@ -18,7 +18,7 @@ * 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.nip01Core.crypto +package com.vitorpamplona.amethyst.commons.keystorage /** * Secure storage for private keys using platform-specific secure storage mechanisms. diff --git a/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/filters/FilterBuildersTest.kt b/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/filters/FilterBuildersTest.kt index 655c4d99f..e88092656 100644 --- a/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/filters/FilterBuildersTest.kt +++ b/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/filters/FilterBuildersTest.kt @@ -418,7 +418,7 @@ class FilterBuildersTest { fun testGlobalFeedScenario() { val filter = FilterBuilders.textNotesGlobal(limit = 50) - assertTrue(filter.isFilledFilter()) + assertTrue(!filter.isEmpty()) assertEquals(listOf(1), filter.kinds) assertEquals(50, filter.limit) } @@ -428,7 +428,7 @@ class FilterBuildersTest { val followedUsers = listOf(testPubKey, testPubKey2) val filter = FilterBuilders.textNotesFromAuthors(followedUsers, limit = 50) - assertTrue(filter.isFilledFilter()) + assertTrue(!filter.isEmpty()) assertEquals(listOf(1), filter.kinds) assertEquals(followedUsers, filter.authors) assertEquals(50, filter.limit) @@ -440,9 +440,9 @@ class FilterBuildersTest { val postsFilter = FilterBuilders.textNotesFromAuthors(listOf(testPubKey), limit = 50) val contactListFilter = FilterBuilders.contactList(testPubKey) - assertTrue(metadataFilter.isFilledFilter()) - assertTrue(postsFilter.isFilledFilter()) - assertTrue(contactListFilter.isFilledFilter()) + assertTrue(!metadataFilter.isEmpty()) + assertTrue(!postsFilter.isEmpty()) + assertTrue(!contactListFilter.isEmpty()) assertEquals(listOf(0), metadataFilter.kinds) assertEquals(listOf(1), postsFilter.kinds) @@ -453,7 +453,7 @@ class FilterBuildersTest { fun testNotificationsScenario() { val filter = FilterBuilders.notificationsForUser(testPubKey, limit = 100) - assertTrue(filter.isFilledFilter()) + assertTrue(!filter.isEmpty()) assertEquals(listOf(1, 7, 6, 16, 9735), filter.kinds) assertNotNull(filter.tags) assertEquals(listOf(testPubKey), filter.tags!!["p"]) @@ -470,7 +470,7 @@ class FilterBuildersTest { limit(100) } - assertTrue(filter.isFilledFilter()) + assertTrue(!filter.isEmpty()) assertEquals(listOf(1), filter.kinds) assertNotNull(filter.tags) assertEquals(listOf(testEventId), filter.tags!!["e"]) @@ -485,7 +485,7 @@ class FilterBuildersTest { limit(50) } - assertTrue(filter.isFilledFilter()) + assertTrue(!filter.isEmpty()) assertEquals(listOf(7), filter.kinds) assertNotNull(filter.tags) assertEquals(listOf(testEventId), filter.tags!!["e"]) @@ -500,7 +500,7 @@ class FilterBuildersTest { limit(50) } - assertTrue(filter.isFilledFilter()) + assertTrue(!filter.isEmpty()) assertEquals(listOf(1), filter.kinds) assertNotNull(filter.tags) assertEquals(listOf("bitcoin"), filter.tags!!["t"]) diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/account/AccountManager.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/account/AccountManager.kt index 4730eafcf..a2cffbd11 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/account/AccountManager.kt +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/account/AccountManager.kt @@ -21,11 +21,11 @@ package com.vitorpamplona.amethyst.commons.account import androidx.compose.runtime.Stable +import com.vitorpamplona.amethyst.commons.keystorage.SecureKeyStorage +import com.vitorpamplona.amethyst.commons.keystorage.SecureStorageException import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair -import com.vitorpamplona.quartz.nip01Core.crypto.SecureKeyStorage -import com.vitorpamplona.quartz.nip01Core.crypto.SecureStorageException import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.nip19Bech32.decodePrivateKeyAsHexOrNull diff --git a/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/SecureKeyStorage.kt b/commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/keystorage/SecureKeyStorage.kt similarity index 99% rename from quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/SecureKeyStorage.kt rename to commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/keystorage/SecureKeyStorage.kt index f64a8a755..9a74a4adf 100644 --- a/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/SecureKeyStorage.kt +++ b/commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/keystorage/SecureKeyStorage.kt @@ -18,7 +18,7 @@ * 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.nip01Core.crypto +package com.vitorpamplona.amethyst.commons.keystorage import com.github.javakeyring.BackendNotSupportedException import com.github.javakeyring.Keyring diff --git a/quartz/build.gradle.kts b/quartz/build.gradle.kts index 7bf19ba52..a9f1d39e6 100644 --- a/quartz/build.gradle.kts +++ b/quartz/build.gradle.kts @@ -166,9 +166,6 @@ kotlin { // LibSodium for ChaCha encryption (NIP-44) implementation (libs.lazysodium.java) implementation (libs.jna) - - // Secure key storage via OS keychain (macOS/Windows/Linux) - implementation(libs.java.keyring) } } @@ -191,10 +188,6 @@ kotlin { // LibSodium for ChaCha encryption (NIP-44) implementation ("com.goterl:lazysodium-android:5.2.0@aar") implementation ("net.java.dev.jna:jna:5.18.1@aar") - - // Secure key storage via Android Keystore - implementation(libs.androidx.security.crypto.ktx) - implementation(libs.androidx.datastore.preferences) } }