diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml
index 18105c04d..65829028f 100644
--- a/.github/workflows/create-release.yml
+++ b/.github/workflows/create-release.yml
@@ -227,4 +227,9 @@ jobs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: app/build/outputs/bundle/fdroidRelease/app-fdroid-release.aab
asset_name: amethyst-fdroid-${{ github.ref_name }}.aab
- asset_content_type: application/zip
\ No newline at end of file
+ asset_content_type: application/zip
+
+ - name: Drafts a description for the release
+ uses: release-drafter/release-drafter@v5
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index f8467b458..8d81632f8 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
+# Amethyst
-Amethyst brings the best social network to your Android phone. Just insert your Nostr private key and start posting.
+## Nostr Client for Android
+
+Join the social network you control.
+
+[](https://github.com/vitorpamplona/amethyst/releases)
+[](https://play.google.com/store/apps/details?id=com.vitorpamplona.amethyst)
+
+[](https://github.com/vitorpamplona/amethyst)
+[](https://jitpack.io/#vitorpamplona/amethyst)
+[](https://github.com/vitorpamplona/amethyst/actions/workflows/build.yml)
+[](/LICENSE)
+
+## Download and Install
[
](https://github.com/ImranR98/Obtainium)
+height="70">](https://github.com/ImranR98/Obtainium)
[
](https://github.com/vitorpamplona/amethyst/releases)
+height="70">](https://github.com/vitorpamplona/amethyst/releases)
[
](https://f-droid.org/packages/com.vitorpamplona.amethyst/)
+ height="70">](https://f-droid.org/packages/com.vitorpamplona.amethyst/)
[
](https://play.google.com/store/apps/details?id=com.vitorpamplona.amethyst)
+ height="70">](https://play.google.com/store/apps/details?id=com.vitorpamplona.amethyst)
-# Current Features
+
- [x] Events / Relay Subscriptions (NIP-01)
- [x] Follow List (NIP-02)
@@ -27,7 +47,7 @@ height="80">](https://github.com/vitorpamplona/amethyst/releases)
- [ ] WebBrowser Signer (NIP-07, Not applicable)
- [x] Old-style mentions (NIP-08)
- [x] Event Deletion (NIP-09)
-- [x] Replies, mentions, Threads and Notifications (NIP-10)
+- [x] Replies, mentions, Threads, and Notifications (NIP-10)
- [x] Relay Information Document (NIP-11)
- [x] Generic Tag Queries (NIP-12)
- [x] Proof of Work Display (NIP-13)
@@ -59,6 +79,7 @@ height="80">](https://github.com/vitorpamplona/amethyst/releases)
- [ ] Nostr Connect (NIP-46)
- [x] Wallet Connect API (NIP-47)
- [ ] Proxy Tags (NIP-48, Not applicable)
+- [x] Private key encryption for import/export (NIP-49)
- [x] Online Relay Search (NIP-50)
- [x] Lists (NIP-51)
- [ ] Calendar Events (NIP-52)
@@ -69,6 +90,7 @@ height="80">](https://github.com/vitorpamplona/amethyst/releases)
- [x] Zaps (NIP-57)
- [x] Private Zaps
- [x] Zap Splits (NIP-57)
+- [x] Gift Wraps & Seals (NIP-59)
- [x] Zapraiser (NIP-TBD)
- [x] Badges (NIP-58)
- [ ] Relay List Metadata (NIP-65)
@@ -79,13 +101,13 @@ height="80">](https://github.com/vitorpamplona/amethyst/releases)
- [x] Highlights (NIP-84)
- [x] Recommended Application Handlers (NIP-89)
- [ ] Data Vending Machine (NIP-90)
+- [x] Inline Metadata (NIP-92)
- [x] Verifiable file URLs (NIP-94)
- [x] Binary Blobs (NIP-95)
- [x] HTTP File Storage Integration (NIP-96 Draft)
- [x] HTTP Auth (NIP-98)
- [x] Classifieds (NIP-99)
- [x] Private Messages and Small Groups (NIP-24/Draft)
-- [x] Gift Wraps & Seals (NIP-59/Draft)
- [x] Versioned Encrypted Payloads (NIP-44/Draft)
- [x] Audio Tracks (zapstr.live) (Kind:31337)
- [x] Push Notifications (Google and Unified Push)
@@ -101,40 +123,50 @@ height="80">](https://github.com/vitorpamplona/amethyst/releases)
- [ ] Workspaces
- [ ] Infinity Scroll
+## Privacy and Information Permanence
+
+Relays know your IP address, your name, your location (guessed from IP), your pub key, all your contacts, and other relays, and can read every action you do (post, like, boost, quote, report, etc) except for Private Zaps and Private DMs. While the content of direct messages (DMs) is only visible to you and your DM counterparty, everyone can see when you and your counterparty DM each other.
+
+If you want to improve your privacy, consider utilizing a service that masks your IP address (e.g. a VPN or Tor) from trackers online.
+
+The relay also learns which public keys you are requesting, meaning your public key will be tied to your IP address.
+
+Information shared on Nostr can be re-broadcasted to other servers and should be assumed permanent for privacy purposes. There is no way to guarantee the deletion of any content once posted.
+
# Development Overview
-## Overall Architecture
+This repository is split between Amethyst and Quartz:
+- Amethyst is a native Android app made with Kotlin and Jetpack Compose.
+- Quartz is our own Nostr-commons library to host classes that are of interest to other Nostr Clients.
-This is a native Android app made with Kotlin and Jetpack Compose.
-The app uses a modified version of the [nostrpostrlib](https://github.com/Giszmo/NostrPostr/tree/master/nostrpostrlib) to talk to Nostr relays.
-The overall architecture consists of the UI, which uses the usual State/ViewModel/Composition, the service layer that connects with Nostr relays,
+The app architecture consists of the UI, which uses the usual State/ViewModel/Composition, the service layer that connects with Nostr relays,
and the model/repository layer, which keeps all Nostr objects in memory, in a full OO graph.
-The repository layer stores Nostr Events as Notes and Users separately. Those classes use LiveData objects to
-allow the UI and other parts of the app to subscribe to each individual Note/User and receive updates when they happen.
-They are also responsible for updating viewModels when needed. Filters react to changes in the screen. As the user
-sees different Events, the Datasource classes are used to receive more information about those particular Events.
+The repository layer stores Nostr Events as Notes and Users separately. Those classes use LiveData and Flow objects to
+allow the UI and other parts of the app to subscribe to each Note/User and receive updates when they happen.
+They are also responsible for updating viewModels when needed. As the user scrolls through Events, the Datasource classes
+are updated to receive more information about those particular Events.
Most of the UI is reactive to changes in the repository classes. The service layer assembles Nostr filters for each need of the app,
receives the data from the Relay, and sends it to the repository. Connection with relays is never closed during the use of the app.
-The UI receives a notification that objects were updated. Instances of User and Notes are mutable directly.
+The UI receives a notification that objects have been updated. Instances of User and Notes are mutable directly.
There will never be two Notes with the same ID or two User instances with the same pubkey.
-Lastly, the user's account information (priv key/pub key) is stored in the Android KeyStore for security.
+Lastly, the user's account information (private key/pub key) is stored in the Android KeyStore for security.
## Setup
Make sure to have the following pre-requisites installed:
-1. Java 17
+1. Java 17+
2. Android Studio
3. Android 8.0+ Phone or Emulation setup
-Fork and clone this repository and import into Android Studio
+Fork and clone this repository and import it into Android Studio
```bash
git clone https://github.com/vitorpamplona/amethyst.git
```
-Use one of the Android Studio builds to install and run the app in your device or a simulator.
+Use an Android Studio build action to install and run the app on your device or a simulator.
## Building
Build the app:
@@ -166,7 +198,7 @@ For the Play build:
./gradlew installPlayDebug
```
-## How to Deploy
+## Deploying
1. Generate a new signing key
```
@@ -183,25 +215,37 @@ openssl base64 < Copyright (c) 2023 Vitor Pamplona Permission is hereby granted, free of charge, to any person obtaining a copy @@ -240,3 +281,4 @@ 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. +diff --git a/app/build.gradle b/app/build.gradle index e068e8fa1..7f6f5be40 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,9 @@ android { applicationId "com.vitorpamplona.amethyst" minSdk 26 targetSdk 34 - versionCode 348 - versionName "0.83.7" + versionCode 358 + versionName "0.84.3" + buildConfigField "String", "RELEASE_NOTES_ID", "\"4d5a05aec61d8798f30f76b2efab81b98d75a03f935fb82823a1080bd56473cd\"" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { @@ -26,7 +27,7 @@ android { 'cy-rGB', 'da-rDK', 'de', - 'el-rGB', + 'el-rGR', 'en-rGB', 'eo', 'es', @@ -141,13 +142,15 @@ android { } composeOptions { - kotlinCompilerExtensionVersion "1.5.3" + // Should match compose version : https://developer.android.com/jetpack/androidx/releases/compose-kotlin + kotlinCompilerExtensionVersion "1.5.8" } packagingOptions { resources { excludes += '/META-INF/{AL2.0,LGPL2.1}' } + exclude '**/libscrypt.dylib' } lint { @@ -161,6 +164,7 @@ android { dependencies { implementation project(path: ':quartz') + implementation project(path: ':commons') implementation "androidx.core:core-ktx:$core_ktx_version" implementation 'androidx.activity:activity-compose:1.8.2' implementation "androidx.compose.ui:ui:$compose_ui_version" @@ -181,7 +185,7 @@ dependencies { // Adaptive Layout / Two Pane implementation "androidx.compose.material3:material3-window-size-class:${material3_version}" - implementation "com.google.accompanist:accompanist-adaptive:0.32.0" + implementation 'com.google.accompanist:accompanist-adaptive:0.34.0' // Lifecycle @@ -191,7 +195,7 @@ dependencies { implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" // Zoomable images - implementation 'net.engawapg.lib:zoomable:1.5.3' + implementation 'net.engawapg.lib:zoomable:1.6.0' // Biometrics implementation "androidx.biometric:biometric-ktx:1.2.0-alpha05" @@ -228,7 +232,7 @@ dependencies { implementation "com.google.accompanist:accompanist-permissions:$accompanist_version" // For QR generation - implementation 'com.google.zxing:core:3.5.2' + implementation 'com.google.zxing:core:3.5.3' implementation 'com.journeyapps:zxing-android-embedded:4.3.0' // Markdown @@ -251,7 +255,7 @@ dependencies { playImplementation 'com.google.mlkit:translate:17.0.2' // PushNotifications - playImplementation platform('com.google.firebase:firebase-bom:32.7.0') + playImplementation platform('com.google.firebase:firebase-bom:32.7.2') playImplementation 'com.google.firebase:firebase-messaging-ktx' //PushNotifications(FDroid) @@ -276,8 +280,8 @@ dependencies { testImplementation 'junit:junit:4.13.2' testImplementation 'io.mockk:mockk:1.13.9' - androidTestImplementation 'androidx.test.ext:junit:1.2.0-alpha02' - androidTestImplementation 'androidx.test.ext:junit-ktx:1.2.0-alpha02' + androidTestImplementation 'androidx.test.ext:junit:1.2.0-alpha03' + androidTestImplementation 'androidx.test.ext:junit-ktx:1.2.0-alpha03' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_ui_version" debugImplementation "androidx.compose.ui:ui-tooling:$compose_ui_version" diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 97496bbf1..5b1f59d16 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -33,6 +33,11 @@ # 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 { *; } diff --git a/app/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt b/app/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt index d9d10c024..c87fb572a 100644 --- a/app/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt +++ b/app/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023 Vitor Pamplona + * Copyright (c) 2024 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 diff --git a/app/src/androidTest/java/com/vitorpamplona/amethyst/OkHttpOtsTest.kt b/app/src/androidTest/java/com/vitorpamplona/amethyst/OkHttpOtsTest.kt new file mode 100644 index 000000000..f09f8964b --- /dev/null +++ b/app/src/androidTest/java/com/vitorpamplona/amethyst/OkHttpOtsTest.kt @@ -0,0 +1,95 @@ +/** + * Copyright (c) 2024 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.amethyst + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.vitorpamplona.amethyst.service.ots.OkHttpBlockstreamExplorer +import com.vitorpamplona.amethyst.service.ots.OkHttpCalendarBuilder +import com.vitorpamplona.quartz.crypto.KeyPair +import com.vitorpamplona.quartz.events.Event +import com.vitorpamplona.quartz.events.OtsEvent +import com.vitorpamplona.quartz.ots.OpenTimestamps +import com.vitorpamplona.quartz.signers.NostrSignerInternal +import junit.framework.TestCase.assertEquals +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit + +@RunWith(AndroidJUnit4::class) +class OkHttpOtsTest { + val otsEvent = "{\"content\":\"AE9wZW5UaW1lc3RhbXBzAABQcm9vZgC/ieLohOiSlAEIqCiiW0FlsU9lqK5f1A+cL6CGJ1Ah4V/A1yNJY/stUE3wECJz6ng/QxU5Z6xwaMx97qkI//AQqJv8bEMrGTplGWRv5qm4DgjxIHkcQqzpL0Fjr9VBAAijDe0IsQYpOhw1SIjZIgQa6i16CPEEZck7CvAIxR0AloJzCZoAg9/jDS75DI4uLWh0dHBzOi8vYWxpY2UuYnRjLmNhbGVuZGFyLm9wZW50aW1lc3RhbXBzLm9yZ//wEOwPtjIkKI1hmtv9t1kuxZcI8QRlyTsK8Ahl0wrCSggZzgCD3+MNLvkMjiwraHR0cHM6Ly9ib2IuYnRjLmNhbGVuZGFyLm9wZW50aW1lc3RhbXBzLm9yZ//wEE1dVGa8JCuf2ek0c5ybDKII8SCBoVz8Sal45Kd1O8STWIGJTcl5JPtAZBZitqk3BE9MqAjxBGXJOwrwCHoGVgAZi9q9AIPf4w0u+QyOKShodHRwczovL2Zpbm5leS5jYWxlbmRhci5ldGVybml0eXdhbGwuY29t8BAFZFXFYg7DJJ0OzjmJ0FKWCPEEZck7CvAI0M49IcBR5bf/AIPf4w0u+QyOIyJodHRwczovL2J0Yy5jYWxlbmRhci5jYXRhbGxheHkuY29tCPEgoE3IfYTmxxo4W/x/QYp/NGX6Wu93gSQkwbpjpOhZORcI8SDWLLurVQaXHdUuwivCfTfuxYCaq+AzypSGqLDAVocrEgjwIBfgjta16y13Gp4etQOCa9YiKEcM+/9AieG/vZolr3IDCPAgMR2zFCb384CEi8tVuI2fHgLT3I9zpe7oqJTzCcEqxWEI8SAJSdgeeosr7IxdOt8r7f0ipWc8FI6GAhgep8zSRgWikAjxIGxYmtCsC79Tx4z4YsT1WuMo+ycMkwhGQsQltF597cchCPAgCLrBf9vR1Aex6yY+vSkXAvLjMKdMqM/a1g8zNPwLeJcI8SBDCbTk4CczTuiIyZeUyYRVh31BZdjaSd2nU/pBQxu+6QjwIOwqE9/WqGC6CHH0i+tr7edvYX5PstSDf08KmnMqsqCoCPEgQIdEBg358vfek3Qjfyrgl51iCU6WUWmThsGLPDTcB0QI8SAX4dp64iI8pBx+zBqAQwUN6XgZ1cEfT8+2vha/9I1vzwjxWQEAAAAB8YJxvxJJth8OnxIV6UOXveIZAcJPTHcAkWgnucpuYqYAAAAAAP3///8CRhoMAAAAAAAWABTUUZK82uAvbU3vVyaaPIOddZBicwAAAAAAAAAAImog8ARCqgwACAjwIB9TcMDLhzgeS1Uw647lNvCfWECkkUvfrrOe6nay0sGdCAjwICYfs90sbPggoMICyOHGYbmOzop2L9mlnh4xqiBLY7yPCAjxINDiVWOBHnRmGJleQdB9myvJAJbNJ9kciZlTOkgJy89mCAjwIHfxqDLdwycj1Vtyth2CaSDdLQwiey9oV6Xov4stLpWNCAjxIGurJYpKJnKp9+y7MAdC+gXgHOiAu5P3RRUFW9l5hGaCCAjxICXqs9hdY0QMP/MNeqlt6s7xaIYtEXZ1CLvou5gaZNEICAjxIHdYxVeI76NXbT2zHcv6lw+v819Ooib7KWxc1GAsiX2fCAjwICPWdi3uBXOlIdmYi+V9C7wAqLyGE4DMoHD+GtvLizqiCAjwIOF2vENtWN5okEMMS+JSf1SGTY9yYP9j0JjXLbC1s+N1CAjxINWsgCtsPxhRNbe372k8/20WDbiL9e8934hGF256DvRECAjwII3mi+Li06j10ORxg0dYMkcsyGb115Jiqq1YEV3K/u+aCAgABYiWDXPXGQEDw9Qy\",\"created_at\":1707690688,\"id\":\"759f9da5846e936fab06766a524b36ba71c03bbc69ad0944fb8ee4bb1f3dd705\",\"kind\":1040,\"pubkey\":\"82fbb08c8ef45c4d71c88368d0ae805bc62fb92f166ab04a0b7a0c83d8cbc29a\",\"sig\":\"07c7896c8cbb97b5d7483097590c9d31b73f35c1ad9e752002bb5c1776cbd852e1d32704333d6930c9bc3e40f8b899a1f2e9f91cc3bf797d86acdecba7792576\",\"tags\":[[\"e\",\"a828a25b4165b14f65a8ae5fd40f9c2fa086275021e15fc0d7234963fb2d504d\"],[\"p\",\"595ca8eaace5899cb6ab7e2542bfc972136376f2eabc09287f1857eb8f167e53\"],[\"alt\",\"NIP-03 time stamp\"]]}" + val otsEvent2 = "{\"content\":\"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\",\"created_at\":1706324334,\"id\":\"2ad074ddb7724eb13b4244b49cf2321b1057f37fdf8ce102e6329b839cf763a9\",\"kind\":1040,\"pubkey\":\"82fbb08c8ef45c4d71c88368d0ae805bc62fb92f166ab04a0b7a0c83d8cbc29a\",\"sig\":\"ad7274bb32ba9e9cfdbd52f4887e8a2fda1047c75a7185b2ab7ff254ebac14ed48a2b60737494d655e24c9400eeeec7e29293a77bfcaafaecd94b350c9a2c22b\",\"tags\":[[\"e\",\"a8634f5368e17789e8fb3836cad0e4b9fe4f2288afafc28723c04bebc68a18d6\"],[\"p\",\"c31e22c3715c1bde5608b7e0d04904f22f5fc453ba1806d21c9f2382e1e58c6c\"],[\"alt\",\"NIP-03 time stamp\"]]}" + val otsPendingEvent = "{\"id\":\"12fa15ad4b4cf9dc5940389325b69b93c5c1f59c049c701ee669b275299fdaf1\",\"pubkey\":\"dcaa6c8a2f47b6fef4a34b20e8843c59dbe7c5f07a402338c09fd147dd01d22b\",\"created_at\":1708877521,\"kind\":1040,\"tags\":[[\"e\",\"a8634f5368e17789e8fb3836cad0e4b9fe4f2288afafc28723c04bebc68a18d6\"],[\"alt\",\"Opentimestamps Attestation\"]],\"content\":\"AE9wZW5UaW1lc3RhbXBzAABQcm9vZgC/ieLohOiSlAEIqGNPU2jhd4no+zg2ytDkuf5PIoivr8KHI8BL68aKGNbwELidvzr0usf55CkpKf6OABQI//AQK3sWd2tq+7KO8YNJIARJugjxBGXbZtPwCL0H4/7GL5+SAIPf4w0u+QyOLCtodHRwczovL2JvYi5idGMuY2FsZW5kYXIub3BlbnRpbWVzdGFtcHMub3Jn//AQPDZsJgN1TnJXoUzlsgo93wjwIIfBc7LUqkCbC1BLZRZ+6LXztK50UdH5xe7fn40bupkrCPEEZdtm0/AI0CADXN5ZIncAg9/jDS75DI4uLWh0dHBzOi8vYWxpY2UuYnRjLmNhbGVuZGFyLm9wZW50aW1lc3RhbXBzLm9yZ/AQcELcSrE04cuGKlZQf2LeVwjwILUDSf9vK2GaefKTpn/LV2oUsQaA5WbqaP3C+1ZxQfRNCPEEZdtm0/AIbCtb+yRXFqUAg9/jDS75DI4pKGh0dHBzOi8vZmlubmV5LmNhbGVuZGFyLmV0ZXJuaXR5d2FsbC5jb20=\",\"sig\":\"f6854c0228c15c08aeb70bbabe9ed87bbb7289fab31b13cabac15138bb71179553e06080b83f4a813fbdaf614f63293beea3fc73fe865da6551193fa4d38de04\"}" + + val otsEvent2Digest = "a8634f5368e17789e8fb3836cad0e4b9fe4f2288afafc28723c04bebc68a18d6" + + @Before + fun setup() { + OtsEvent.otsInstance = OpenTimestamps(OkHttpBlockstreamExplorer(), OkHttpCalendarBuilder()) + } + + @Test + fun verifyNostrEvent() { + val ots = Event.fromJson(otsEvent) as OtsEvent + println(ots.info()) + assertEquals(1707688818L, ots.verify()) + } + + @Test + fun verifyNostrEvent2() { + val ots = Event.fromJson(otsEvent2) as OtsEvent + println(ots.info()) + assertEquals(1706322179L, ots.verify()) + } + + @Test + fun verifyNostrPendingEvent() { + val ots = Event.fromJson(otsPendingEvent) as OtsEvent + println(ots.info()) + assertEquals(null, ots.verify()) + } + + @Test + fun createOTSEventAndVerify() { + val signer = NostrSignerInternal(KeyPair()) + var ots: OtsEvent? = null + + val countDownLatch = CountDownLatch(1) + + val otsFile = OtsEvent.stamp(otsEvent2Digest) + + OtsEvent.create(otsEvent2Digest, otsFile, signer) { + ots = it + countDownLatch.countDown() + } + + Assert.assertTrue(countDownLatch.await(1, TimeUnit.SECONDS)) + + println(ots!!.toJson()) + println(ots!!.info()) + + // Should not be valid because we need to wait for confirmations + assertEquals(null, ots!!.verify()) + } +} diff --git a/app/src/androidTest/java/com/vitorpamplona/amethyst/ThreadAssemblerTest.kt b/app/src/androidTest/java/com/vitorpamplona/amethyst/ThreadAssemblerTest.kt index 9c878d65e..39cf69711 100644 --- a/app/src/androidTest/java/com/vitorpamplona/amethyst/ThreadAssemblerTest.kt +++ b/app/src/androidTest/java/com/vitorpamplona/amethyst/ThreadAssemblerTest.kt @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023 Vitor Pamplona + * Copyright (c) 2024 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 diff --git a/app/src/androidTest/java/com/vitorpamplona/amethyst/UrlUserTagTransformationTest.kt b/app/src/androidTest/java/com/vitorpamplona/amethyst/UrlUserTagTransformationTest.kt index 3fa4da42a..92f0af91b 100644 --- a/app/src/androidTest/java/com/vitorpamplona/amethyst/UrlUserTagTransformationTest.kt +++ b/app/src/androidTest/java/com/vitorpamplona/amethyst/UrlUserTagTransformationTest.kt @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023 Vitor Pamplona + * Copyright (c) 2024 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 diff --git a/app/src/androidTestPlay/java/com/vitorpamplona/amethyst/TranslationsTest.kt b/app/src/androidTestPlay/java/com/vitorpamplona/amethyst/TranslationsTest.kt index ae00af4db..3d22f9ae0 100644 --- a/app/src/androidTestPlay/java/com/vitorpamplona/amethyst/TranslationsTest.kt +++ b/app/src/androidTestPlay/java/com/vitorpamplona/amethyst/TranslationsTest.kt @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023 Vitor Pamplona + * Copyright (c) 2024 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 diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt b/app/src/fdroid/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt index 8c12f0172..3b9ddaebe 100644 --- a/app/src/fdroid/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt +++ b/app/src/fdroid/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023 Vitor Pamplona + * Copyright (c) 2024 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 diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushDistributorHandler.kt b/app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushDistributorHandler.kt index f08af58f9..d7a28413f 100644 --- a/app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushDistributorHandler.kt +++ b/app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushDistributorHandler.kt @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023 Vitor Pamplona + * Copyright (c) 2024 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 diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushMessageReceiver.kt b/app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushMessageReceiver.kt index 951f6e8c6..b6313df50 100644 --- a/app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushMessageReceiver.kt +++ b/app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushMessageReceiver.kt @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023 Vitor Pamplona + * Copyright (c) 2024 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 @@ -32,6 +32,7 @@ import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.getOrC import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.getOrCreateZapChannel import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.GiftWrapEvent +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob @@ -60,6 +61,7 @@ class PushMessageReceiver : MessagingReceiver() { try { parseMessage(messageStr)?.let { receiveIfNew(it) } } catch (e: Exception) { + if (e is CancellationException) throw e Log.d(TAG, "Message could not be parsed: ${e.message}") } } diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt b/app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt index 6a25767b0..0b8f85f93 100644 --- a/app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt +++ b/app/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023 Vitor Pamplona + * Copyright (c) 2024 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 @@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.service.notifications import android.util.Log import com.vitorpamplona.amethyst.AccountInfo +import kotlinx.coroutines.CancellationException object PushNotificationUtils { var hasInit: Boolean = false @@ -36,6 +37,7 @@ object PushNotificationUtils { RegisterAccounts(accounts).go(pushHandler.getSavedEndpoint()) } } catch (e: Exception) { + if (e is CancellationException) throw e Log.d("Amethyst-OSSPushUtils", "Failed to get endpoint.") } } diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt index 6fba6039e..c008764ca 100644 --- a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt +++ b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023 Vitor Pamplona + * Copyright (c) 2024 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 diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt index 7d211335a..fe225dcaf 100644 --- a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt +++ b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023 Vitor Pamplona + * Copyright (c) 2024 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 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b30c56b1d..8b30f6ee1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,8 +3,11 @@ xmlns:tools="http://schemas.android.com/tools">