diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index 4d755123e..921e6003a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -112,7 +112,7 @@ class Account( val content = blockList?.content ?: "" if (content.isEmpty()) return@launch AmberUtils.content = "" - AmberUtils.decryptBookmark( + AmberUtils.decrypt( content, keyPair.pubKey.toHexKey() ) @@ -823,31 +823,75 @@ class Account( } fun createNip95(byteArray: ByteArray, headerInfo: FileHeader): Pair? { - if (!isWriteable()) return null + if (!isWriteable() && !loginWithAmber) return null - val data = FileStorageEvent.create( - mimeType = headerInfo.mimeType ?: "", - data = byteArray, - privateKey = keyPair.privKey!! - ) + if (loginWithAmber) { + val unsignedData = FileStorageEvent.create( + mimeType = headerInfo.mimeType ?: "", + data = byteArray, + pubKey = keyPair.pubKey.toHexKey() + ) - val signedEvent = FileStorageHeaderEvent.create( - data, - mimeType = headerInfo.mimeType, - hash = headerInfo.hash, - size = headerInfo.size.toString(), - dimensions = headerInfo.dim, - blurhash = headerInfo.blurHash, - description = headerInfo.description, - sensitiveContent = headerInfo.sensitiveContent, - privateKey = keyPair.privKey!! - ) + AmberUtils.openAmber(unsignedData) + if (AmberUtils.content.isBlank()) return null + val data = FileStorageEvent( + unsignedData.id, + unsignedData.pubKey, + unsignedData.createdAt, + unsignedData.tags, + unsignedData.content, + AmberUtils.content + ) - return Pair(data, signedEvent) + val unsignedEvent = FileStorageHeaderEvent.create( + data, + mimeType = headerInfo.mimeType, + hash = headerInfo.hash, + size = headerInfo.size.toString(), + dimensions = headerInfo.dim, + blurhash = headerInfo.blurHash, + description = headerInfo.description, + sensitiveContent = headerInfo.sensitiveContent, + pubKey = keyPair.pubKey.toHexKey() + ) + + AmberUtils.openAmber(unsignedEvent) + if (AmberUtils.content.isBlank()) return null + val signedEvent = FileStorageHeaderEvent( + unsignedEvent.id, + unsignedEvent.pubKey, + unsignedEvent.createdAt, + unsignedEvent.tags, + unsignedEvent.content, + AmberUtils.content + ) + + return Pair(data, signedEvent) + } else { + val data = FileStorageEvent.create( + mimeType = headerInfo.mimeType ?: "", + data = byteArray, + privateKey = keyPair.privKey!! + ) + + val signedEvent = FileStorageHeaderEvent.create( + data, + mimeType = headerInfo.mimeType, + hash = headerInfo.hash, + size = headerInfo.size.toString(), + dimensions = headerInfo.dim, + blurhash = headerInfo.blurHash, + description = headerInfo.description, + sensitiveContent = headerInfo.sensitiveContent, + privateKey = keyPair.privKey!! + ) + + return Pair(data, signedEvent) + } } fun sendNip95(data: FileStorageEvent, signedEvent: FileStorageHeaderEvent, relayList: List? = null): Note? { - if (!isWriteable()) return null + if (!isWriteable() && !loginWithAmber) return null Client.send(data, relayList = relayList) LocalCache.consume(data, null) @@ -1312,7 +1356,7 @@ class Account( } val msg = Event.mapper.writeValueAsString(privTags) - AmberUtils.encryptBookmark(msg, keyPair.pubKey.toHexKey()) + AmberUtils.encrypt(msg, keyPair.pubKey.toHexKey()) if (AmberUtils.content.isBlank()) { return null @@ -1357,7 +1401,7 @@ class Account( } val msg = Event.mapper.writeValueAsString(privTags) - AmberUtils.encryptBookmark(msg, keyPair.pubKey.toHexKey()) + AmberUtils.encrypt(msg, keyPair.pubKey.toHexKey()) if (AmberUtils.content.isBlank()) { return null @@ -1432,7 +1476,7 @@ class Account( } val msg = Event.mapper.writeValueAsString(privTags) - AmberUtils.encryptBookmark(msg, keyPair.pubKey.toHexKey()) + AmberUtils.encrypt(msg, keyPair.pubKey.toHexKey()) if (AmberUtils.content.isBlank()) { return null @@ -1597,7 +1641,7 @@ class Account( } val msg = Event.mapper.writeValueAsString(privTags) - AmberUtils.encryptBookmark(msg, keyPair.pubKey.toHexKey()) + AmberUtils.encrypt(msg, keyPair.pubKey.toHexKey()) if (AmberUtils.content.isBlank()) { return null diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/AmberUtils.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/AmberUtils.kt index 62fb453cb..26a049695 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/AmberUtils.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/AmberUtils.kt @@ -6,6 +6,7 @@ import androidx.activity.result.ActivityResultLauncher import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.ui.actions.SignerType import com.vitorpamplona.quartz.encoders.HexKey +import com.vitorpamplona.quartz.events.EventInterface object AmberUtils { var content: String = "" @@ -33,7 +34,20 @@ object AmberUtils { intentResult.launch(intent) } - fun decryptBookmark(encryptedContent: String, pubKey: HexKey) { + fun openAmber(event: EventInterface) { + isActivityRunning = true + openAmber( + event.toJson(), + SignerType.SIGN_EVENT, + IntentUtils.decryptActivityResultLauncher, + "" + ) + while (isActivityRunning) { + Thread.sleep(250) + } + } + + fun decrypt(encryptedContent: String, pubKey: HexKey) { if (content.isBlank()) { isActivityRunning = true openAmber( @@ -48,7 +62,7 @@ object AmberUtils { } } - fun encryptBookmark(decryptedContent: String, pubKey: HexKey) { + fun encrypt(decryptedContent: String, pubKey: HexKey) { if (content.isBlank()) { isActivityRunning = true openAmber( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt index 98e27e05f..d774fafe4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt @@ -285,7 +285,14 @@ open class NewPostViewModel() : ViewModel() { } } - fun upload(galleryUri: Uri, description: String, sensitiveContent: Boolean, server: ServersAvailable, context: Context, relayList: List? = null) { + fun upload( + galleryUri: Uri, + description: String, + sensitiveContent: Boolean, + server: ServersAvailable, + context: Context, + relayList: List? = null + ) { isUploadingImage = true contentToAddUrl = null diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPrivateFeedFilter.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPrivateFeedFilter.kt index b059bd829..fdd1b1a8c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPrivateFeedFilter.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/BookmarkPrivateFeedFilter.kt @@ -18,7 +18,7 @@ object BookmarkPrivateFeedFilter : FeedFilter() { if (account.loginWithAmber) { if (AmberUtils.content.isBlank()) { - AmberUtils.decryptBookmark(bookmarks?.content ?: "", account.keyPair.pubKey.toHexKey()) + AmberUtils.decrypt(bookmarks?.content ?: "", account.keyPair.pubKey.toHexKey()) bookmarks?.decryptedContent = AmberUtils.content } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt index b023f8162..d6c4c6c5e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt @@ -481,7 +481,7 @@ fun NoteDropDownMenu(note: Note, popupExpanded: MutableState, accountVi scope.launch(Dispatchers.IO) { if (accountViewModel.loggedInWithAmber()) { val bookmarks = accountViewModel.userProfile().latestBookmarkList - AmberUtils.decryptBookmark( + AmberUtils.decrypt( bookmarks?.content ?: "", accountViewModel.account.keyPair.pubKey.toHexKey() ) @@ -503,7 +503,7 @@ fun NoteDropDownMenu(note: Note, popupExpanded: MutableState, accountVi scope.launch(Dispatchers.IO) { if (accountViewModel.loggedInWithAmber()) { val bookmarks = accountViewModel.userProfile().latestBookmarkList - AmberUtils.decryptBookmark( + AmberUtils.decrypt( bookmarks?.content ?: "", accountViewModel.account.keyPair.pubKey.toHexKey() ) @@ -526,7 +526,7 @@ fun NoteDropDownMenu(note: Note, popupExpanded: MutableState, accountVi scope.launch(Dispatchers.IO) { if (accountViewModel.loggedInWithAmber()) { val bookmarks = accountViewModel.userProfile().latestBookmarkList - AmberUtils.decryptBookmark( + AmberUtils.decrypt( bookmarks?.content ?: "", accountViewModel.account.keyPair.pubKey.toHexKey() ) @@ -551,7 +551,7 @@ fun NoteDropDownMenu(note: Note, popupExpanded: MutableState, accountVi scope.launch(Dispatchers.IO) { if (accountViewModel.loggedInWithAmber()) { val bookmarks = accountViewModel.userProfile().latestBookmarkList - AmberUtils.decryptBookmark( + AmberUtils.decrypt( bookmarks?.content ?: "", accountViewModel.account.keyPair.pubKey.toHexKey() ) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/FileStorageEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/FileStorageEvent.kt index 68de6b62a..010864f9e 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/FileStorageEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/FileStorageEvent.kt @@ -40,6 +40,21 @@ class FileStorageEvent( return Base64.getEncoder().encodeToString(bytes) } + fun create( + mimeType: String, + data: ByteArray, + pubKey: HexKey, + createdAt: Long = TimeUtils.now() + ): FileStorageEvent { + val tags = listOfNotNull( + listOf(TYPE, mimeType) + ) + + val content = encode(data) + val id = generateId(pubKey, createdAt, kind, tags, content) + return FileStorageEvent(id.toHexKey(), pubKey, createdAt, tags, content, "") + } + fun create( mimeType: String, data: ByteArray, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/FileStorageHeaderEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/FileStorageHeaderEvent.kt index 6f4644240..2554ac1ad 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/FileStorageHeaderEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/FileStorageHeaderEvent.kt @@ -39,6 +39,45 @@ class FileStorageHeaderEvent( private const val TORRENT_INFOHASH = "i" private const val BLUR_HASH = "blurhash" + fun create( + storageEvent: FileStorageEvent, + mimeType: String? = null, + description: String? = null, + hash: String? = null, + size: String? = null, + dimensions: String? = null, + blurhash: String? = null, + magnetURI: String? = null, + torrentInfoHash: String? = null, + encryptionKey: AESGCM? = null, + sensitiveContent: Boolean? = null, + pubKey: HexKey, + createdAt: Long = TimeUtils.now() + ): FileStorageHeaderEvent { + val tags = listOfNotNull( + listOf("e", storageEvent.id), + mimeType?.let { listOf(MIME_TYPE, mimeType) }, + hash?.let { listOf(HASH, it) }, + size?.let { listOf(FILE_SIZE, it) }, + dimensions?.let { listOf(DIMENSION, it) }, + blurhash?.let { listOf(BLUR_HASH, it) }, + magnetURI?.let { listOf(MAGNET_URI, it) }, + torrentInfoHash?.let { listOf(TORRENT_INFOHASH, it) }, + encryptionKey?.let { listOf(ENCRYPTION_KEY, it.key, it.nonce) }, + sensitiveContent?.let { + if (it) { + listOf("content-warning", "") + } else { + null + } + } + ) + + val content = description ?: "" + val id = generateId(pubKey, createdAt, kind, tags, content) + return FileStorageHeaderEvent(id.toHexKey(), pubKey, createdAt, tags, content, "") + } + fun create( storageEvent: FileStorageEvent, mimeType: String? = null,