mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-26 17:06:43 +00:00
Merge branch 'dev' into swap-video-views
This commit is contained in:
2
libsession-util/.gitignore
vendored
Normal file
2
libsession-util/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/build
|
||||
/.cxx/
|
||||
47
libsession-util/build.gradle
Normal file
47
libsession-util/build.gradle
Normal file
@@ -0,0 +1,47 @@
|
||||
plugins {
|
||||
id 'com.android.library'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
}
|
||||
|
||||
android {
|
||||
namespace 'network.loki.messenger.libsession_util'
|
||||
compileSdkVersion androidCompileSdkVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion androidMinimumSdkVersion
|
||||
targetSdkVersion androidCompileSdkVersion
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
}
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path "src/main/cpp/CMakeLists.txt"
|
||||
version "3.22.1+"
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
implementation(project(":libsignal"))
|
||||
implementation "com.google.protobuf:protobuf-java:$protobufVersion"
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
||||
}
|
||||
1
libsession-util/libsession-util
Submodule
1
libsession-util/libsession-util
Submodule
Submodule libsession-util/libsession-util added at e3ccf29db0
@@ -0,0 +1,584 @@
|
||||
package network.loki.messenger.libsession_util
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import network.loki.messenger.libsession_util.util.*
|
||||
import org.hamcrest.CoreMatchers.not
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.session.libsignal.utilities.Hex
|
||||
import org.session.libsignal.utilities.Log
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class InstrumentedTests {
|
||||
|
||||
val seed =
|
||||
Hex.fromStringCondensed("0123456789abcdef0123456789abcdef00000000000000000000000000000000")
|
||||
|
||||
private val keyPair: KeyPair
|
||||
get() {
|
||||
return Sodium.ed25519KeyPair(seed)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("network.loki.messenger.libsession_util.test", appContext.packageName)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun jni_test_sodium_kp_ed_curve() {
|
||||
val kp = keyPair
|
||||
val curvePkBytes = Sodium.ed25519PkToCurve25519(kp.pubKey)
|
||||
|
||||
val edPk = kp.pubKey
|
||||
val curvePk = curvePkBytes
|
||||
|
||||
assertArrayEquals(Hex.fromStringCondensed("4cb76fdc6d32278e3f83dbf608360ecc6b65727934b85d2fb86862ff98c46ab7"), edPk)
|
||||
assertArrayEquals(Hex.fromStringCondensed("d2ad010eeb72d72e561d9de7bd7b6989af77dcabffa03a5111a6c859ae5c3a72"), curvePk)
|
||||
assertArrayEquals(kp.secretKey.take(32).toByteArray(), seed)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDirtyEmptyString() {
|
||||
val contacts = Contacts.newInstance(keyPair.secretKey)
|
||||
val definitelyRealId = "050000000000000000000000000000000000000000000000000000000000000000"
|
||||
val contact = contacts.getOrConstruct(definitelyRealId)
|
||||
contacts.set(contact)
|
||||
assertTrue(contacts.dirty())
|
||||
contacts.set(contact.copy(name = "test"))
|
||||
assertTrue(contacts.dirty())
|
||||
val push = contacts.push()
|
||||
contacts.confirmPushed(push.seqNo, "abc123")
|
||||
contacts.dump()
|
||||
contacts.set(contact.copy(name = "test2"))
|
||||
contacts.set(contact.copy(name = "test"))
|
||||
assertTrue(contacts.dirty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun jni_contacts() {
|
||||
val contacts = Contacts.newInstance(keyPair.secretKey)
|
||||
val definitelyRealId = "050000000000000000000000000000000000000000000000000000000000000000"
|
||||
assertNull(contacts.get(definitelyRealId))
|
||||
|
||||
// Should be an uninitialized contact apart from ID
|
||||
val c = contacts.getOrConstruct(definitelyRealId)
|
||||
assertEquals(definitelyRealId, c.id)
|
||||
assertTrue(c.name.isEmpty())
|
||||
assertTrue(c.nickname.isEmpty())
|
||||
assertFalse(c.approved)
|
||||
assertFalse(c.approvedMe)
|
||||
assertFalse(c.blocked)
|
||||
assertEquals(UserPic.DEFAULT, c.profilePicture)
|
||||
|
||||
assertFalse(contacts.needsPush())
|
||||
assertFalse(contacts.needsDump())
|
||||
assertEquals(0, contacts.push().seqNo)
|
||||
|
||||
c.name = "Joe"
|
||||
c.nickname = "Joey"
|
||||
c.approved = true
|
||||
c.approvedMe = true
|
||||
|
||||
contacts.set(c)
|
||||
|
||||
val cSaved = contacts.get(definitelyRealId)!!
|
||||
assertEquals("Joe", cSaved.name)
|
||||
assertEquals("Joey", cSaved.nickname)
|
||||
assertTrue(cSaved.approved)
|
||||
assertTrue(cSaved.approvedMe)
|
||||
assertFalse(cSaved.blocked)
|
||||
assertEquals(UserPic.DEFAULT, cSaved.profilePicture)
|
||||
|
||||
val push1 = contacts.push()
|
||||
|
||||
assertEquals(1, push1.seqNo)
|
||||
contacts.confirmPushed(push1.seqNo, "fakehash1")
|
||||
assertFalse(contacts.needsPush())
|
||||
assertTrue(contacts.needsDump())
|
||||
|
||||
val contacts2 = Contacts.newInstance(keyPair.secretKey, contacts.dump())
|
||||
assertFalse(contacts.needsDump())
|
||||
assertFalse(contacts2.needsPush())
|
||||
assertFalse(contacts2.needsDump())
|
||||
|
||||
val anotherId = "051111111111111111111111111111111111111111111111111111111111111111"
|
||||
val c2 = contacts2.getOrConstruct(anotherId)
|
||||
contacts2.set(c2)
|
||||
val push2 = contacts2.push()
|
||||
assertEquals(2, push2.seqNo)
|
||||
contacts2.confirmPushed(push2.seqNo, "fakehash2")
|
||||
assertFalse(contacts2.needsPush())
|
||||
|
||||
contacts.merge("fakehash2" to push2.config)
|
||||
|
||||
|
||||
assertFalse(contacts.needsPush())
|
||||
assertEquals(push2.seqNo, contacts.push().seqNo)
|
||||
|
||||
val contactList = contacts.all().toList()
|
||||
assertEquals(definitelyRealId, contactList[0].id)
|
||||
assertEquals(anotherId, contactList[1].id)
|
||||
assertEquals("Joey", contactList[0].nickname)
|
||||
assertEquals("", contactList[1].nickname)
|
||||
|
||||
contacts.erase(definitelyRealId)
|
||||
|
||||
val thirdId ="052222222222222222222222222222222222222222222222222222222222222222"
|
||||
val third = Contact(
|
||||
id = thirdId,
|
||||
nickname = "Nickname 3",
|
||||
approved = true,
|
||||
blocked = true,
|
||||
profilePicture = UserPic("http://example.com/huge.bmp", "qwertyuio01234567890123456789012".encodeToByteArray()),
|
||||
expiryMode = ExpiryMode.NONE
|
||||
)
|
||||
contacts2.set(third)
|
||||
assertTrue(contacts.needsPush())
|
||||
assertTrue(contacts2.needsPush())
|
||||
val toPush = contacts.push()
|
||||
val toPush2 = contacts2.push()
|
||||
assertEquals(toPush.seqNo, toPush2.seqNo)
|
||||
assertThat(toPush2.config, not(equals(toPush.config)))
|
||||
|
||||
contacts.confirmPushed(toPush.seqNo, "fakehash3a")
|
||||
contacts2.confirmPushed(toPush2.seqNo, "fakehash3b")
|
||||
|
||||
contacts.merge("fakehash3b" to toPush2.config)
|
||||
contacts2.merge("fakehash3a" to toPush.config)
|
||||
|
||||
assertTrue(contacts.needsPush())
|
||||
assertTrue(contacts2.needsPush())
|
||||
|
||||
val mergePush = contacts.push()
|
||||
val mergePush2 = contacts2.push()
|
||||
|
||||
assertEquals(mergePush.seqNo, mergePush2.seqNo)
|
||||
assertArrayEquals(mergePush.config, mergePush2.config)
|
||||
|
||||
assertTrue(mergePush.obsoleteHashes.containsAll(listOf("fakehash3b", "fakehash3a")))
|
||||
assertTrue(mergePush2.obsoleteHashes.containsAll(listOf("fakehash3b", "fakehash3a")))
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun jni_accessible() {
|
||||
val userProfile = UserProfile.newInstance(keyPair.secretKey)
|
||||
assertNotNull(userProfile)
|
||||
userProfile.free()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun jni_user_profile_c_api() {
|
||||
val edSk = keyPair.secretKey
|
||||
val userProfile = UserProfile.newInstance(edSk)
|
||||
|
||||
// these should be false as empty config
|
||||
assertFalse(userProfile.needsPush())
|
||||
assertFalse(userProfile.needsDump())
|
||||
|
||||
// Since it's empty there shouldn't be a name
|
||||
assertNull(userProfile.getName())
|
||||
|
||||
// Don't need to push yet so this is just for testing
|
||||
val (_, seqNo) = userProfile.push() // disregarding encrypted
|
||||
assertEquals("UserProfile", userProfile.encryptionDomain())
|
||||
assertEquals(0, seqNo)
|
||||
|
||||
// This should also be unset:
|
||||
assertEquals(UserPic.DEFAULT, userProfile.getPic())
|
||||
|
||||
// Now let's go set a profile name and picture:
|
||||
// not sending keylen like c api so cutting off the NOTSECRET in key for testing purposes
|
||||
userProfile.setName("Kallie")
|
||||
val newUserPic = UserPic("http://example.org/omg-pic-123.bmp", "secret78901234567890123456789012".encodeToByteArray())
|
||||
userProfile.setPic(newUserPic)
|
||||
userProfile.setNtsPriority(9)
|
||||
|
||||
// Retrieve them just to make sure they set properly:
|
||||
assertEquals("Kallie", userProfile.getName())
|
||||
val pic = userProfile.getPic()
|
||||
assertEquals("http://example.org/omg-pic-123.bmp", pic.url)
|
||||
assertEquals("secret78901234567890123456789012", pic.key.decodeToString())
|
||||
|
||||
// Since we've made changes, we should need to push new config to the swarm, *and* should need
|
||||
// to dump the updated state:
|
||||
assertTrue(userProfile.needsPush())
|
||||
assertTrue(userProfile.needsDump())
|
||||
val (newToPush, newSeqNo) = userProfile.push()
|
||||
|
||||
val expHash0 =
|
||||
Hex.fromStringCondensed("ea173b57beca8af18c3519a7bbf69c3e7a05d1c049fa9558341d8ebb48b0c965")
|
||||
|
||||
val expectedPush1Decrypted = ("d" +
|
||||
"1:#"+ "i1e" +
|
||||
"1:&"+ "d"+
|
||||
"1:+"+ "i9e"+
|
||||
"1:n"+ "6:Kallie"+
|
||||
"1:p"+ "34:http://example.org/omg-pic-123.bmp"+
|
||||
"1:q"+ "32:secret78901234567890123456789012"+
|
||||
"e"+
|
||||
"1:<"+ "l"+
|
||||
"l"+ "i0e"+ "32:").encodeToByteArray() + expHash0 + ("de"+ "e"+
|
||||
"e"+
|
||||
"1:="+ "d"+
|
||||
"1:+" +"0:"+
|
||||
"1:n" +"0:"+
|
||||
"1:p" +"0:"+
|
||||
"1:q" +"0:"+
|
||||
"e"+
|
||||
"e").encodeToByteArray()
|
||||
|
||||
assertEquals(1, newSeqNo)
|
||||
// We haven't dumped, so still need to dump:
|
||||
assertTrue(userProfile.needsDump())
|
||||
// We did call push but we haven't confirmed it as stored yet, so this will still return true:
|
||||
assertTrue(userProfile.needsPush())
|
||||
|
||||
val dump = userProfile.dump()
|
||||
// (in a real client we'd now store this to disk)
|
||||
assertFalse(userProfile.needsDump())
|
||||
val expectedDump = ("d" +
|
||||
"1:!"+ "i2e" +
|
||||
"1:$").encodeToByteArray() + expectedPush1Decrypted.size.toString().encodeToByteArray() +
|
||||
":".encodeToByteArray() + expectedPush1Decrypted +
|
||||
"1:(0:1:)le".encodeToByteArray()+
|
||||
"e".encodeToByteArray()
|
||||
|
||||
assertArrayEquals(expectedDump, dump)
|
||||
|
||||
userProfile.confirmPushed(newSeqNo, "fakehash1")
|
||||
|
||||
val newConf = UserProfile.newInstance(edSk)
|
||||
|
||||
val accepted = newConf.merge("fakehash1" to newToPush)
|
||||
assertEquals(1, accepted)
|
||||
|
||||
assertTrue(newConf.needsDump())
|
||||
assertFalse(newConf.needsPush())
|
||||
val _ignore = newConf.dump()
|
||||
assertFalse(newConf.needsDump())
|
||||
|
||||
|
||||
userProfile.setName("Raz")
|
||||
newConf.setName("Nibbler")
|
||||
newConf.setPic(UserPic("http://new.example.com/pic", "qwertyuio01234567890123456789012".encodeToByteArray()))
|
||||
|
||||
val conf = userProfile.push()
|
||||
val conf2 = newConf.push()
|
||||
|
||||
userProfile.confirmPushed(conf.seqNo, "fakehash2")
|
||||
newConf.confirmPushed(conf2.seqNo, "fakehash3")
|
||||
|
||||
userProfile.dump()
|
||||
|
||||
assertFalse(conf.config.contentEquals(conf2.config))
|
||||
|
||||
newConf.merge("fakehash2" to conf.config)
|
||||
userProfile.merge("fakehash3" to conf2.config)
|
||||
|
||||
assertTrue(newConf.needsPush())
|
||||
assertTrue(userProfile.needsPush())
|
||||
|
||||
val newSeq1 = userProfile.push()
|
||||
|
||||
assertEquals(3, newSeq1.seqNo)
|
||||
|
||||
userProfile.confirmPushed(newSeq1.seqNo, "fakehash4")
|
||||
|
||||
// assume newConf push gets rejected as it was last to write and clear previous config by hash on oxenss
|
||||
newConf.merge("fakehash4" to newSeq1.config)
|
||||
|
||||
val newSeqMerge = newConf.push()
|
||||
|
||||
newConf.confirmPushed(newSeqMerge.seqNo, "fakehash5")
|
||||
|
||||
assertEquals("Raz", newConf.getName())
|
||||
assertEquals(3, newSeqMerge.seqNo)
|
||||
|
||||
// userProfile device polls and merges
|
||||
userProfile.merge("fakehash5" to newSeqMerge.config)
|
||||
|
||||
val userConfigMerge = userProfile.push()
|
||||
|
||||
assertEquals(3, userConfigMerge.seqNo)
|
||||
|
||||
assertEquals("Raz", newConf.getName())
|
||||
assertEquals("Raz", userProfile.getName())
|
||||
|
||||
userProfile.free()
|
||||
newConf.free()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun merge_resolves_conflicts() {
|
||||
val kp = keyPair
|
||||
val a = UserProfile.newInstance(kp.secretKey)
|
||||
val b = UserProfile.newInstance(kp.secretKey)
|
||||
a.setName("A")
|
||||
val (aPush, aSeq) = a.push()
|
||||
a.confirmPushed(aSeq, "hashfroma")
|
||||
b.setName("B")
|
||||
// polls and sees invalid state, has to merge
|
||||
b.merge("hashfroma" to aPush)
|
||||
val (bPush, bSeq) = b.push()
|
||||
b.confirmPushed(bSeq, "hashfromb")
|
||||
assertEquals("B", b.getName())
|
||||
assertEquals(1, aSeq)
|
||||
assertEquals(2, bSeq)
|
||||
a.merge("hashfromb" to bPush)
|
||||
assertEquals(2, a.push().seqNo)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun jni_setting_getting() {
|
||||
val userProfile = UserProfile.newInstance(keyPair.secretKey)
|
||||
val newName = "test"
|
||||
println("Name being set via JNI call: $newName")
|
||||
userProfile.setName(newName)
|
||||
val nameFromNative = userProfile.getName()
|
||||
assertEquals(newName, nameFromNative)
|
||||
println("Name received by JNI call: $nameFromNative")
|
||||
assertTrue(userProfile.dirty())
|
||||
userProfile.free()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun jni_remove_all_test() {
|
||||
val convos = ConversationVolatileConfig.newInstance(keyPair.secretKey)
|
||||
assertEquals(0 /* number removed */, convos.eraseAll { true /* 'erase' every item */ })
|
||||
|
||||
val definitelyRealId = "050000000000000000000000000000000000000000000000000000000000000000"
|
||||
val definitelyRealConvo = Conversation.OneToOne(definitelyRealId, System.currentTimeMillis(), false)
|
||||
convos.set(definitelyRealConvo)
|
||||
|
||||
val anotherDefinitelyReadId = "051111111111111111111111111111111111111111111111111111111111111111"
|
||||
val anotherDefinitelyRealConvo = Conversation.OneToOne(anotherDefinitelyReadId, System.currentTimeMillis(), false)
|
||||
convos.set(anotherDefinitelyRealConvo)
|
||||
|
||||
assertEquals(2, convos.sizeOneToOnes())
|
||||
|
||||
val numErased = convos.eraseAll { convo ->
|
||||
convo is Conversation.OneToOne && convo.sessionId == definitelyRealId
|
||||
}
|
||||
assertEquals(1, numErased)
|
||||
assertEquals(1, convos.sizeOneToOnes())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_open_group_urls() {
|
||||
val (base1, room1, pk1) = BaseCommunityInfo.parseFullUrl(
|
||||
"https://example.com/" +
|
||||
"someroom?public_key=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
)!!
|
||||
|
||||
val (base2, room2, pk2) = BaseCommunityInfo.parseFullUrl(
|
||||
"HTTPS://EXAMPLE.COM/" +
|
||||
"someroom?public_key=0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"
|
||||
)!!
|
||||
|
||||
val (base3, room3, pk3) = BaseCommunityInfo.parseFullUrl(
|
||||
"HTTPS://EXAMPLE.COM/r/" +
|
||||
"someroom?public_key=0123456789aBcdEF0123456789abCDEF0123456789ABCdef0123456789ABCDEF"
|
||||
)!!
|
||||
|
||||
val (base4, room4, pk4) = BaseCommunityInfo.parseFullUrl(
|
||||
"http://example.com/r/" +
|
||||
"someroom?public_key=0123456789aBcdEF0123456789abCDEF0123456789ABCdef0123456789ABCDEF"
|
||||
)!!
|
||||
|
||||
val (base5, room5, pk5) = BaseCommunityInfo.parseFullUrl(
|
||||
"HTTPS://EXAMPLE.com:443/r/" +
|
||||
"someroom?public_key=0123456789aBcdEF0123456789abCDEF0123456789ABCdef0123456789ABCDEF"
|
||||
)!!
|
||||
|
||||
val (base6, room6, pk6) = BaseCommunityInfo.parseFullUrl(
|
||||
"HTTP://EXAMPLE.com:80/r/" +
|
||||
"someroom?public_key=0123456789aBcdEF0123456789abCDEF0123456789ABCdef0123456789ABCDEF"
|
||||
)!!
|
||||
|
||||
val (base7, room7, pk7) = BaseCommunityInfo.parseFullUrl(
|
||||
"http://example.com:80/r/" +
|
||||
"someroom?public_key=ASNFZ4mrze8BI0VniavN7wEjRWeJq83vASNFZ4mrze8"
|
||||
)!!
|
||||
val (base8, room8, pk8) = BaseCommunityInfo.parseFullUrl(
|
||||
"http://example.com:80/r/" +
|
||||
"someroom?public_key=yrtwk3hjixg66yjdeiuauk6p7hy1gtm8tgih55abrpnsxnpm3zzo"
|
||||
)!!
|
||||
|
||||
assertEquals("https://example.com", base1)
|
||||
assertEquals("http://example.com", base4)
|
||||
assertEquals(base1, base2)
|
||||
assertEquals(base1, base3)
|
||||
assertNotEquals(base1, base4)
|
||||
assertEquals(base1, base5)
|
||||
assertEquals(base4, base6)
|
||||
assertEquals(base4, base7)
|
||||
assertEquals(base4, base8)
|
||||
assertEquals("someroom", room1)
|
||||
assertEquals("someroom", room2)
|
||||
assertEquals("someroom", room3)
|
||||
assertEquals("someroom", room4)
|
||||
assertEquals("someroom", room5)
|
||||
assertEquals("someroom", room6)
|
||||
assertEquals("someroom", room7)
|
||||
assertEquals("someroom", room8)
|
||||
assertEquals(Hex.toStringCondensed(pk1), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
assertEquals(Hex.toStringCondensed(pk2), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
assertEquals(Hex.toStringCondensed(pk3), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
assertEquals(Hex.toStringCondensed(pk4), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
assertEquals(Hex.toStringCondensed(pk5), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
assertEquals(Hex.toStringCondensed(pk6), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
assertEquals(Hex.toStringCondensed(pk7), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
assertEquals(Hex.toStringCondensed(pk8), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_conversations() {
|
||||
val convos = ConversationVolatileConfig.newInstance(keyPair.secretKey)
|
||||
val definitelyRealId = "055000000000000000000000000000000000000000000000000000000000000000"
|
||||
assertNull(convos.getOneToOne(definitelyRealId))
|
||||
assertTrue(convos.empty())
|
||||
assertEquals(0, convos.size())
|
||||
|
||||
val c = convos.getOrConstructOneToOne(definitelyRealId)
|
||||
|
||||
assertEquals(definitelyRealId, c.sessionId)
|
||||
assertEquals(0, c.lastRead)
|
||||
|
||||
assertFalse(convos.needsPush())
|
||||
assertFalse(convos.needsDump())
|
||||
assertEquals(0, convos.push().seqNo)
|
||||
|
||||
val nowMs = System.currentTimeMillis()
|
||||
|
||||
c.lastRead = nowMs
|
||||
|
||||
convos.set(c)
|
||||
|
||||
assertNull(convos.getLegacyClosedGroup(definitelyRealId))
|
||||
assertNotNull(convos.getOneToOne(definitelyRealId))
|
||||
assertEquals(nowMs, convos.getOneToOne(definitelyRealId)?.lastRead)
|
||||
|
||||
assertTrue(convos.needsPush())
|
||||
assertTrue(convos.needsDump())
|
||||
|
||||
val openGroupPubKey = Hex.fromStringCondensed("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
|
||||
val og = convos.getOrConstructCommunity("http://Example.ORG:5678", "SudokuRoom", openGroupPubKey)
|
||||
val ogCommunity = og.baseCommunityInfo
|
||||
|
||||
assertEquals("http://example.org:5678", ogCommunity.baseUrl) // Note: lower-case
|
||||
assertEquals("sudokuroom", ogCommunity.room) // Note: lower-case
|
||||
assertEquals(64, ogCommunity.pubKeyHex.length)
|
||||
assertEquals("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", ogCommunity.pubKeyHex)
|
||||
|
||||
og.unread = true
|
||||
|
||||
convos.set(og)
|
||||
|
||||
val (_, seqNo) = convos.push()
|
||||
|
||||
assertEquals(1, seqNo)
|
||||
|
||||
convos.confirmPushed(seqNo, "fakehash1")
|
||||
|
||||
assertTrue(convos.needsDump())
|
||||
assertFalse(convos.needsPush())
|
||||
|
||||
val convos2 = ConversationVolatileConfig.newInstance(keyPair.secretKey, convos.dump())
|
||||
assertFalse(convos.needsPush())
|
||||
assertFalse(convos.needsDump())
|
||||
assertEquals(1, convos.push().seqNo)
|
||||
assertFalse(convos.needsDump())
|
||||
|
||||
val x1 = convos2.getOneToOne(definitelyRealId)!!
|
||||
assertEquals(nowMs, x1.lastRead)
|
||||
assertEquals(definitelyRealId, x1.sessionId)
|
||||
assertEquals(false, x1.unread)
|
||||
|
||||
val x2 = convos2.getCommunity("http://EXAMPLE.org:5678", "sudokuRoom")!!
|
||||
val x2Info = x2.baseCommunityInfo
|
||||
assertEquals("http://example.org:5678", x2Info.baseUrl)
|
||||
assertEquals("sudokuroom", x2Info.room)
|
||||
assertEquals(x2Info.pubKeyHex, Hex.toStringCondensed(openGroupPubKey))
|
||||
assertTrue(x2.unread)
|
||||
|
||||
val anotherId = "051111111111111111111111111111111111111111111111111111111111111111"
|
||||
val c2 = convos.getOrConstructOneToOne(anotherId)
|
||||
c2.unread = true
|
||||
convos2.set(c2)
|
||||
|
||||
val c3 = convos.getOrConstructLegacyGroup(
|
||||
"05cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
|
||||
)
|
||||
c3.lastRead = nowMs - 50
|
||||
convos2.set(c3)
|
||||
|
||||
assertTrue(convos2.needsPush())
|
||||
|
||||
val (toPush2, seqNo2) = convos2.push()
|
||||
assertEquals(2, seqNo2)
|
||||
|
||||
convos2.confirmPushed(seqNo2, "fakehash2")
|
||||
convos.merge("fakehash2" to toPush2)
|
||||
|
||||
assertFalse(convos.needsPush())
|
||||
assertEquals(seqNo2, convos.push().seqNo)
|
||||
|
||||
val seen = mutableListOf<String>()
|
||||
for ((ind, conv) in listOf(convos, convos2).withIndex()) {
|
||||
Log.e("Test","Testing seen from convo #$ind")
|
||||
seen.clear()
|
||||
assertEquals(4, conv.size())
|
||||
assertEquals(2, conv.sizeOneToOnes())
|
||||
assertEquals(1, conv.sizeCommunities())
|
||||
assertEquals(1, conv.sizeLegacyClosedGroups())
|
||||
assertFalse(conv.empty())
|
||||
val allConvos = conv.all()
|
||||
for (convo in allConvos) {
|
||||
when (convo) {
|
||||
is Conversation.OneToOne -> seen.add("1-to-1: ${convo.sessionId}")
|
||||
is Conversation.Community -> seen.add("og: ${convo.baseCommunityInfo.baseUrl}/r/${convo.baseCommunityInfo.room}")
|
||||
is Conversation.LegacyGroup -> seen.add("cl: ${convo.groupId}")
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue(seen.contains("1-to-1: 051111111111111111111111111111111111111111111111111111111111111111"))
|
||||
assertTrue(seen.contains("1-to-1: 055000000000000000000000000000000000000000000000000000000000000000"))
|
||||
assertTrue(seen.contains("og: http://example.org:5678/r/sudokuroom"))
|
||||
assertTrue(seen.contains("cl: 05cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"))
|
||||
assertTrue(seen.size == 4) // for some reason iterative checks aren't working in test cases
|
||||
}
|
||||
|
||||
assertFalse(convos.needsPush())
|
||||
convos.eraseOneToOne("052000000000000000000000000000000000000000000000000000000000000000")
|
||||
assertFalse(convos.needsPush())
|
||||
convos.eraseOneToOne("055000000000000000000000000000000000000000000000000000000000000000")
|
||||
assertTrue(convos.needsPush())
|
||||
|
||||
assertEquals(1, convos.allOneToOnes().size)
|
||||
assertEquals("051111111111111111111111111111111111111111111111111111111111111111",
|
||||
convos.allOneToOnes().map(Conversation.OneToOne::sessionId).first()
|
||||
)
|
||||
assertEquals(1, convos.allCommunities().size)
|
||||
assertEquals("http://example.org:5678",
|
||||
convos.allCommunities().map { it.baseCommunityInfo.baseUrl }.first()
|
||||
)
|
||||
assertEquals(1, convos.allLegacyClosedGroups().size)
|
||||
assertEquals("05cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
|
||||
convos.allLegacyClosedGroups().map(Conversation.LegacyGroup::groupId).first()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
5
libsession-util/src/main/AndroidManifest.xml
Normal file
5
libsession-util/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="network.loki.messenger.libsession_util">
|
||||
|
||||
</manifest>
|
||||
67
libsession-util/src/main/cpp/CMakeLists.txt
Normal file
67
libsession-util/src/main/cpp/CMakeLists.txt
Normal file
@@ -0,0 +1,67 @@
|
||||
# For more information about using CMake with Android Studio, read the
|
||||
# documentation: https://d.android.com/studio/projects/add-native-code.html
|
||||
|
||||
# Sets the minimum version of CMake required to build the native library.
|
||||
|
||||
cmake_minimum_required(VERSION 3.18.1)
|
||||
|
||||
# Declares and names the project.
|
||||
|
||||
project("session_util")
|
||||
|
||||
# Compiles in C++17 mode
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
|
||||
# Creates and names a library, sets it as either STATIC
|
||||
# or SHARED, and provides the relative paths to its source code.
|
||||
# You can define multiple libraries, and CMake builds them for you.
|
||||
# Gradle automatically packages shared libraries with your APK.
|
||||
|
||||
set(STATIC_BUNDLE ON)
|
||||
add_subdirectory(../../../libsession-util libsession)
|
||||
|
||||
set(SOURCES
|
||||
user_profile.cpp
|
||||
user_groups.cpp
|
||||
config_base.cpp
|
||||
contacts.cpp
|
||||
conversation.cpp
|
||||
util.cpp)
|
||||
|
||||
add_library( # Sets the name of the library.
|
||||
session_util
|
||||
# Sets the library as a shared library.
|
||||
SHARED
|
||||
# Provides a relative path to your source file(s).
|
||||
${SOURCES})
|
||||
|
||||
# Searches for a specified prebuilt library and stores the path as a
|
||||
# variable. Because CMake includes system libraries in the search path by
|
||||
# default, you only need to specify the name of the public NDK library
|
||||
# you want to add. CMake verifies that the library exists before
|
||||
# completing its build.
|
||||
|
||||
find_library( # Sets the name of the path variable.
|
||||
log-lib
|
||||
|
||||
# Specifies the name of the NDK library that
|
||||
# you want CMake to locate.
|
||||
log)
|
||||
|
||||
# Specifies libraries CMake should link to your target library. You
|
||||
# can link multiple libraries, such as libraries you define in this
|
||||
# build script, prebuilt third-party libraries, or system libraries.
|
||||
|
||||
target_link_libraries( # Specifies the target library.
|
||||
session_util
|
||||
PUBLIC
|
||||
libsession::config
|
||||
libsession::crypto
|
||||
libsodium::sodium-internal
|
||||
# Links the target library to the log library
|
||||
# included in the NDK.
|
||||
${log-lib})
|
||||
158
libsession-util/src/main/cpp/config_base.cpp
Normal file
158
libsession-util/src/main/cpp/config_base.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
#include "config_base.h"
|
||||
#include "util.h"
|
||||
|
||||
extern "C" {
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConfigBase_dirty(JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto* configBase = ptrToConfigBase(env, thiz);
|
||||
return configBase->is_dirty();
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConfigBase_needsPush(JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto config = ptrToConfigBase(env, thiz);
|
||||
return config->needs_push();
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConfigBase_needsDump(JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto config = ptrToConfigBase(env, thiz);
|
||||
return config->needs_dump();
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConfigBase_push(JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto config = ptrToConfigBase(env, thiz);
|
||||
auto push_tuple = config->push();
|
||||
auto to_push_str = std::get<1>(push_tuple);
|
||||
auto to_delete = std::get<2>(push_tuple);
|
||||
|
||||
jbyteArray returnByteArray = util::bytes_from_ustring(env, to_push_str);
|
||||
jlong seqNo = std::get<0>(push_tuple);
|
||||
jclass returnObjectClass = env->FindClass("network/loki/messenger/libsession_util/util/ConfigPush");
|
||||
jclass stackClass = env->FindClass("java/util/Stack");
|
||||
jmethodID methodId = env->GetMethodID(returnObjectClass, "<init>", "([BJLjava/util/List;)V");
|
||||
jmethodID stack_init = env->GetMethodID(stackClass, "<init>", "()V");
|
||||
jobject our_stack = env->NewObject(stackClass, stack_init);
|
||||
jmethodID push_stack = env->GetMethodID(stackClass, "push", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
for (auto entry : to_delete) {
|
||||
auto entry_jstring = env->NewStringUTF(entry.data());
|
||||
env->CallObjectMethod(our_stack, push_stack, entry_jstring);
|
||||
}
|
||||
jobject returnObject = env->NewObject(returnObjectClass, methodId, returnByteArray, seqNo, our_stack);
|
||||
return returnObject;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConfigBase_free(JNIEnv *env, jobject thiz) {
|
||||
auto config = ptrToConfigBase(env, thiz);
|
||||
delete config;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConfigBase_dump(JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto config = ptrToConfigBase(env, thiz);
|
||||
auto dumped = config->dump();
|
||||
jbyteArray bytes = util::bytes_from_ustring(env, dumped);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConfigBase_encryptionDomain(JNIEnv *env,
|
||||
jobject thiz) {
|
||||
auto conf = ptrToConfigBase(env, thiz);
|
||||
return env->NewStringUTF(conf->encryption_domain());
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConfigBase_confirmPushed(JNIEnv *env, jobject thiz,
|
||||
jlong seq_no,
|
||||
jstring new_hash_jstring) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToConfigBase(env, thiz);
|
||||
auto new_hash = env->GetStringUTFChars(new_hash_jstring, nullptr);
|
||||
conf->confirm_pushed(seq_no, new_hash);
|
||||
env->ReleaseStringUTFChars(new_hash_jstring, new_hash);
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConfigBase_merge___3Lkotlin_Pair_2(JNIEnv *env, jobject thiz,
|
||||
jobjectArray to_merge) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToConfigBase(env, thiz);
|
||||
size_t number = env->GetArrayLength(to_merge);
|
||||
std::vector<std::pair<std::string,session::ustring>> configs = {};
|
||||
for (int i = 0; i < number; i++) {
|
||||
auto jElement = (jobject) env->GetObjectArrayElement(to_merge, i);
|
||||
auto pair = extractHashAndData(env, jElement);
|
||||
configs.push_back(pair);
|
||||
}
|
||||
auto returned = conf->merge(configs);
|
||||
auto string_stack = util::build_string_stack(env, returned);
|
||||
return string_stack;
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConfigBase_merge__Lkotlin_Pair_2(JNIEnv *env, jobject thiz,
|
||||
jobject to_merge) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToConfigBase(env, thiz);
|
||||
std::vector<std::pair<std::string, session::ustring>> configs = {extractHashAndData(env, to_merge)};
|
||||
auto returned = conf->merge(configs);
|
||||
auto string_stack = util::build_string_stack(env, returned);
|
||||
return string_stack;
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConfigBase_configNamespace(JNIEnv *env, jobject thiz) {
|
||||
auto conf = ptrToConfigBase(env, thiz);
|
||||
return (std::int16_t) conf->storage_namespace();
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jclass JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConfigBase_00024Companion_kindFor(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jint config_namespace) {
|
||||
auto user_class = env->FindClass("network/loki/messenger/libsession_util/UserProfile");
|
||||
auto contact_class = env->FindClass("network/loki/messenger/libsession_util/Contacts");
|
||||
auto convo_volatile_class = env->FindClass("network/loki/messenger/libsession_util/ConversationVolatileConfig");
|
||||
auto group_list_class = env->FindClass("network/loki/messenger/libsession_util/UserGroupsConfig");
|
||||
switch (config_namespace) {
|
||||
case (int)session::config::Namespace::UserProfile:
|
||||
return user_class;
|
||||
case (int)session::config::Namespace::Contacts:
|
||||
return contact_class;
|
||||
case (int)session::config::Namespace::ConvoInfoVolatile:
|
||||
return convo_volatile_class;
|
||||
case (int)session::config::Namespace::UserGroups:
|
||||
return group_list_class;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConfigBase_currentHashes(JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToConfigBase(env, thiz);
|
||||
jclass stack = env->FindClass("java/util/Stack");
|
||||
jmethodID init = env->GetMethodID(stack, "<init>", "()V");
|
||||
jobject our_stack = env->NewObject(stack, init);
|
||||
jmethodID push = env->GetMethodID(stack, "push", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
auto vec = conf->current_hashes();
|
||||
for (std::string element: vec) {
|
||||
env->CallObjectMethod(our_stack, push, env->NewStringUTF(element.data()));
|
||||
}
|
||||
return our_stack;
|
||||
}
|
||||
28
libsession-util/src/main/cpp/config_base.h
Normal file
28
libsession-util/src/main/cpp/config_base.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef SESSION_ANDROID_CONFIG_BASE_H
|
||||
#define SESSION_ANDROID_CONFIG_BASE_H
|
||||
|
||||
#include "session/config/base.hpp"
|
||||
#include "util.h"
|
||||
#include <jni.h>
|
||||
#include <string>
|
||||
|
||||
inline session::config::ConfigBase* ptrToConfigBase(JNIEnv *env, jobject obj) {
|
||||
jclass baseClass = env->FindClass("network/loki/messenger/libsession_util/ConfigBase");
|
||||
jfieldID pointerField = env->GetFieldID(baseClass, "pointer", "J");
|
||||
return (session::config::ConfigBase*) env->GetLongField(obj, pointerField);
|
||||
}
|
||||
|
||||
inline std::pair<std::string, session::ustring> extractHashAndData(JNIEnv *env, jobject kotlin_pair) {
|
||||
jclass pair = env->FindClass("kotlin/Pair");
|
||||
jfieldID first = env->GetFieldID(pair, "first", "Ljava/lang/Object;");
|
||||
jfieldID second = env->GetFieldID(pair, "second", "Ljava/lang/Object;");
|
||||
jstring hash_as_jstring = static_cast<jstring>(env->GetObjectField(kotlin_pair, first));
|
||||
jbyteArray data_as_jbytes = static_cast<jbyteArray>(env->GetObjectField(kotlin_pair, second));
|
||||
auto hash_as_string = env->GetStringUTFChars(hash_as_jstring, nullptr);
|
||||
auto data_as_ustring = util::ustring_from_bytes(env, data_as_jbytes);
|
||||
auto ret_pair = std::pair<std::string, session::ustring>{hash_as_string, data_as_ustring};
|
||||
env->ReleaseStringUTFChars(hash_as_jstring, hash_as_string);
|
||||
return ret_pair;
|
||||
}
|
||||
|
||||
#endif
|
||||
100
libsession-util/src/main/cpp/contacts.cpp
Normal file
100
libsession-util/src/main/cpp/contacts.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
#include "contacts.h"
|
||||
#include "util.h"
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_Contacts_get(JNIEnv *env, jobject thiz,
|
||||
jstring session_id) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto contacts = ptrToContacts(env, thiz);
|
||||
auto session_id_chars = env->GetStringUTFChars(session_id, nullptr);
|
||||
auto contact = contacts->get(session_id_chars);
|
||||
env->ReleaseStringUTFChars(session_id, session_id_chars);
|
||||
if (!contact) return nullptr;
|
||||
jobject j_contact = serialize_contact(env, contact.value());
|
||||
return j_contact;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_Contacts_getOrConstruct(JNIEnv *env, jobject thiz,
|
||||
jstring session_id) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto contacts = ptrToContacts(env, thiz);
|
||||
auto session_id_chars = env->GetStringUTFChars(session_id, nullptr);
|
||||
auto contact = contacts->get_or_construct(session_id_chars);
|
||||
env->ReleaseStringUTFChars(session_id, session_id_chars);
|
||||
return serialize_contact(env, contact);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_Contacts_set(JNIEnv *env, jobject thiz,
|
||||
jobject contact) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto contacts = ptrToContacts(env, thiz);
|
||||
auto contact_info = deserialize_contact(env, contact, contacts);
|
||||
contacts->set(contact_info);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_Contacts_erase(JNIEnv *env, jobject thiz,
|
||||
jstring session_id) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto contacts = ptrToContacts(env, thiz);
|
||||
auto session_id_chars = env->GetStringUTFChars(session_id, nullptr);
|
||||
|
||||
bool result = contacts->erase(session_id_chars);
|
||||
env->ReleaseStringUTFChars(session_id, session_id_chars);
|
||||
return result;
|
||||
}
|
||||
extern "C"
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_Contacts_00024Companion_newInstance___3B(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jbyteArray ed25519_secret_key) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto secret_key = util::ustring_from_bytes(env, ed25519_secret_key);
|
||||
auto* contacts = new session::config::Contacts(secret_key, std::nullopt);
|
||||
|
||||
jclass contactsClass = env->FindClass("network/loki/messenger/libsession_util/Contacts");
|
||||
jmethodID constructor = env->GetMethodID(contactsClass, "<init>", "(J)V");
|
||||
jobject newConfig = env->NewObject(contactsClass, constructor, reinterpret_cast<jlong>(contacts));
|
||||
|
||||
return newConfig;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_Contacts_00024Companion_newInstance___3B_3B(
|
||||
JNIEnv *env, jobject thiz, jbyteArray ed25519_secret_key, jbyteArray initial_dump) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto secret_key = util::ustring_from_bytes(env, ed25519_secret_key);
|
||||
auto initial = util::ustring_from_bytes(env, initial_dump);
|
||||
|
||||
auto* contacts = new session::config::Contacts(secret_key, initial);
|
||||
|
||||
jclass contactsClass = env->FindClass("network/loki/messenger/libsession_util/Contacts");
|
||||
jmethodID constructor = env->GetMethodID(contactsClass, "<init>", "(J)V");
|
||||
jobject newConfig = env->NewObject(contactsClass, constructor, reinterpret_cast<jlong>(contacts));
|
||||
|
||||
return newConfig;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_Contacts_all(JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto contacts = ptrToContacts(env, thiz);
|
||||
jclass stack = env->FindClass("java/util/Stack");
|
||||
jmethodID init = env->GetMethodID(stack, "<init>", "()V");
|
||||
jobject our_stack = env->NewObject(stack, init);
|
||||
jmethodID push = env->GetMethodID(stack, "push", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
for (const auto& contact : *contacts) {
|
||||
auto contact_obj = serialize_contact(env, contact);
|
||||
env->CallObjectMethod(our_stack, push, contact_obj);
|
||||
}
|
||||
return our_stack;
|
||||
}
|
||||
108
libsession-util/src/main/cpp/contacts.h
Normal file
108
libsession-util/src/main/cpp/contacts.h
Normal file
@@ -0,0 +1,108 @@
|
||||
#ifndef SESSION_ANDROID_CONTACTS_H
|
||||
#define SESSION_ANDROID_CONTACTS_H
|
||||
|
||||
#include <jni.h>
|
||||
#include "session/config/contacts.hpp"
|
||||
#include "util.h"
|
||||
|
||||
inline session::config::Contacts *ptrToContacts(JNIEnv *env, jobject obj) {
|
||||
jclass contactsClass = env->FindClass("network/loki/messenger/libsession_util/Contacts");
|
||||
jfieldID pointerField = env->GetFieldID(contactsClass, "pointer", "J");
|
||||
return (session::config::Contacts *) env->GetLongField(obj, pointerField);
|
||||
}
|
||||
|
||||
inline jobject serialize_contact(JNIEnv *env, session::config::contact_info info) {
|
||||
jclass contactClass = env->FindClass("network/loki/messenger/libsession_util/util/Contact");
|
||||
jmethodID constructor = env->GetMethodID(contactClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZLnetwork/loki/messenger/libsession_util/util/UserPic;ILnetwork/loki/messenger/libsession_util/util/ExpiryMode;)V");
|
||||
jstring id = env->NewStringUTF(info.session_id.data());
|
||||
jstring name = env->NewStringUTF(info.name.data());
|
||||
jstring nickname = env->NewStringUTF(info.nickname.data());
|
||||
jboolean approved, approvedMe, blocked;
|
||||
approved = info.approved;
|
||||
approvedMe = info.approved_me;
|
||||
blocked = info.blocked;
|
||||
auto created = info.created;
|
||||
jobject profilePic = util::serialize_user_pic(env, info.profile_picture);
|
||||
jobject returnObj = env->NewObject(contactClass, constructor, id, name, nickname, approved,
|
||||
approvedMe, blocked, profilePic, info.priority,
|
||||
util::serialize_expiry(env, info.exp_mode, info.exp_timer));
|
||||
return returnObj;
|
||||
}
|
||||
|
||||
inline session::config::contact_info deserialize_contact(JNIEnv *env, jobject info, session::config::Contacts *conf) {
|
||||
jclass contactClass = env->FindClass("network/loki/messenger/libsession_util/util/Contact");
|
||||
|
||||
jfieldID getId, getName, getNick, getApproved, getApprovedMe, getBlocked, getUserPic, getPriority, getExpiry, getHidden;
|
||||
getId = env->GetFieldID(contactClass, "id", "Ljava/lang/String;");
|
||||
getName = env->GetFieldID(contactClass, "name", "Ljava/lang/String;");
|
||||
getNick = env->GetFieldID(contactClass, "nickname", "Ljava/lang/String;");
|
||||
getApproved = env->GetFieldID(contactClass, "approved", "Z");
|
||||
getApprovedMe = env->GetFieldID(contactClass, "approvedMe", "Z");
|
||||
getBlocked = env->GetFieldID(contactClass, "blocked", "Z");
|
||||
getUserPic = env->GetFieldID(contactClass, "profilePicture",
|
||||
"Lnetwork/loki/messenger/libsession_util/util/UserPic;");
|
||||
getPriority = env->GetFieldID(contactClass, "priority", "I");
|
||||
getExpiry = env->GetFieldID(contactClass, "expiryMode", "Lnetwork/loki/messenger/libsession_util/util/ExpiryMode;");
|
||||
jstring name, nickname, session_id;
|
||||
session_id = static_cast<jstring>(env->GetObjectField(info, getId));
|
||||
name = static_cast<jstring>(env->GetObjectField(info, getName));
|
||||
nickname = static_cast<jstring>(env->GetObjectField(info, getNick));
|
||||
bool approved, approvedMe, blocked, hidden;
|
||||
int priority = env->GetIntField(info, getPriority);
|
||||
approved = env->GetBooleanField(info, getApproved);
|
||||
approvedMe = env->GetBooleanField(info, getApprovedMe);
|
||||
blocked = env->GetBooleanField(info, getBlocked);
|
||||
jobject user_pic = env->GetObjectField(info, getUserPic);
|
||||
jobject expiry_mode = env->GetObjectField(info, getExpiry);
|
||||
|
||||
auto expiry_pair = util::deserialize_expiry(env, expiry_mode);
|
||||
|
||||
std::string url;
|
||||
session::ustring key;
|
||||
|
||||
if (user_pic != nullptr) {
|
||||
auto deserialized_pic = util::deserialize_user_pic(env, user_pic);
|
||||
auto url_jstring = deserialized_pic.first;
|
||||
auto url_bytes = env->GetStringUTFChars(url_jstring, nullptr);
|
||||
url = std::string(url_bytes);
|
||||
env->ReleaseStringUTFChars(url_jstring, url_bytes);
|
||||
key = util::ustring_from_bytes(env, deserialized_pic.second);
|
||||
}
|
||||
|
||||
auto session_id_bytes = env->GetStringUTFChars(session_id, nullptr);
|
||||
auto name_bytes = name ? env->GetStringUTFChars(name, nullptr) : nullptr;
|
||||
auto nickname_bytes = nickname ? env->GetStringUTFChars(nickname, nullptr) : nullptr;
|
||||
|
||||
auto contact_info = conf->get_or_construct(session_id_bytes);
|
||||
if (name_bytes) {
|
||||
contact_info.name = name_bytes;
|
||||
}
|
||||
if (nickname_bytes) {
|
||||
contact_info.nickname = nickname_bytes;
|
||||
}
|
||||
contact_info.approved = approved;
|
||||
contact_info.approved_me = approvedMe;
|
||||
contact_info.blocked = blocked;
|
||||
if (!url.empty() && !key.empty()) {
|
||||
contact_info.profile_picture = session::config::profile_pic(url, key);
|
||||
} else {
|
||||
contact_info.profile_picture = session::config::profile_pic();
|
||||
}
|
||||
|
||||
env->ReleaseStringUTFChars(session_id, session_id_bytes);
|
||||
if (name_bytes) {
|
||||
env->ReleaseStringUTFChars(name, name_bytes);
|
||||
}
|
||||
if (nickname_bytes) {
|
||||
env->ReleaseStringUTFChars(nickname, nickname_bytes);
|
||||
}
|
||||
|
||||
contact_info.priority = priority;
|
||||
contact_info.exp_mode = expiry_pair.first;
|
||||
contact_info.exp_timer = std::chrono::seconds(expiry_pair.second);
|
||||
|
||||
return contact_info;
|
||||
}
|
||||
|
||||
|
||||
#endif //SESSION_ANDROID_CONTACTS_H
|
||||
352
libsession-util/src/main/cpp/conversation.cpp
Normal file
352
libsession-util/src/main/cpp/conversation.cpp
Normal file
@@ -0,0 +1,352 @@
|
||||
#include <jni.h>
|
||||
#include "conversation.h"
|
||||
|
||||
#pragma clang diagnostic push
|
||||
|
||||
extern "C"
|
||||
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_00024Companion_newInstance___3B(
|
||||
JNIEnv *env, jobject thiz, jbyteArray ed25519_secret_key) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto secret_key = util::ustring_from_bytes(env, ed25519_secret_key);
|
||||
auto* convo_info_volatile = new session::config::ConvoInfoVolatile(secret_key, std::nullopt);
|
||||
|
||||
jclass convoClass = env->FindClass("network/loki/messenger/libsession_util/ConversationVolatileConfig");
|
||||
jmethodID constructor = env->GetMethodID(convoClass, "<init>", "(J)V");
|
||||
jobject newConfig = env->NewObject(convoClass, constructor, reinterpret_cast<jlong>(convo_info_volatile));
|
||||
|
||||
return newConfig;
|
||||
}
|
||||
extern "C"
|
||||
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_00024Companion_newInstance___3B_3B(
|
||||
JNIEnv *env, jobject thiz, jbyteArray ed25519_secret_key, jbyteArray initial_dump) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto secret_key = util::ustring_from_bytes(env, ed25519_secret_key);
|
||||
auto initial = util::ustring_from_bytes(env, initial_dump);
|
||||
auto* convo_info_volatile = new session::config::ConvoInfoVolatile(secret_key, initial);
|
||||
|
||||
jclass convoClass = env->FindClass("network/loki/messenger/libsession_util/ConversationVolatileConfig");
|
||||
jmethodID constructor = env->GetMethodID(convoClass, "<init>", "(J)V");
|
||||
jobject newConfig = env->NewObject(convoClass, constructor, reinterpret_cast<jlong>(convo_info_volatile));
|
||||
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_sizeOneToOnes(JNIEnv *env,
|
||||
jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conversations = ptrToConvoInfo(env, thiz);
|
||||
return conversations->size_1to1();
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseAll(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jobject predicate) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conversations = ptrToConvoInfo(env, thiz);
|
||||
|
||||
jclass predicate_class = env->FindClass("kotlin/jvm/functions/Function1");
|
||||
jmethodID predicate_call = env->GetMethodID(predicate_class, "invoke", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
|
||||
jclass bool_class = env->FindClass("java/lang/Boolean");
|
||||
jmethodID bool_get = env->GetMethodID(bool_class, "booleanValue", "()Z");
|
||||
|
||||
int removed = 0;
|
||||
auto to_erase = std::vector<session::config::convo::any>();
|
||||
|
||||
for (auto it = conversations->begin(); it != conversations->end(); ++it) {
|
||||
auto result = env->CallObjectMethod(predicate, predicate_call, serialize_any(env, *it));
|
||||
bool bool_result = env->CallBooleanMethod(result, bool_get);
|
||||
if (bool_result) {
|
||||
to_erase.push_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto & entry : to_erase) {
|
||||
if (conversations->erase(entry)) {
|
||||
removed++;
|
||||
}
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_size(JNIEnv *env,
|
||||
jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto config = ptrToConvoInfo(env, thiz);
|
||||
return (jint)config->size();
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_empty(JNIEnv *env,
|
||||
jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto config = ptrToConvoInfo(env, thiz);
|
||||
return config->empty();
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_set(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jobject to_store) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
|
||||
jclass one_to_one = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$OneToOne");
|
||||
jclass open_group = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$Community");
|
||||
jclass legacy_closed_group = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$LegacyGroup");
|
||||
|
||||
jclass to_store_class = env->GetObjectClass(to_store);
|
||||
if (env->IsSameObject(to_store_class, one_to_one)) {
|
||||
// store as 1to1
|
||||
convos->set(deserialize_one_to_one(env, to_store, convos));
|
||||
} else if (env->IsSameObject(to_store_class,open_group)) {
|
||||
// store as open_group
|
||||
convos->set(deserialize_community(env, to_store, convos));
|
||||
} else if (env->IsSameObject(to_store_class,legacy_closed_group)) {
|
||||
// store as legacy_closed_group
|
||||
convos->set(deserialize_legacy_closed_group(env, to_store, convos));
|
||||
}
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOneToOne(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jstring pub_key_hex) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
auto param = env->GetStringUTFChars(pub_key_hex, nullptr);
|
||||
auto internal = convos->get_1to1(param);
|
||||
env->ReleaseStringUTFChars(pub_key_hex, param);
|
||||
if (internal) {
|
||||
return serialize_one_to_one(env, *internal);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOrConstructOneToOne(
|
||||
JNIEnv *env, jobject thiz, jstring pub_key_hex) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
auto param = env->GetStringUTFChars(pub_key_hex, nullptr);
|
||||
auto internal = convos->get_or_construct_1to1(param);
|
||||
env->ReleaseStringUTFChars(pub_key_hex, param);
|
||||
return serialize_one_to_one(env, internal);
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseOneToOne(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jstring pub_key_hex) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
auto param = env->GetStringUTFChars(pub_key_hex, nullptr);
|
||||
auto result = convos->erase_1to1(param);
|
||||
env->ReleaseStringUTFChars(pub_key_hex, param);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getCommunity__Ljava_lang_String_2Ljava_lang_String_2(
|
||||
JNIEnv *env, jobject thiz, jstring base_url, jstring room) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
auto base_url_chars = env->GetStringUTFChars(base_url, nullptr);
|
||||
auto room_chars = env->GetStringUTFChars(room, nullptr);
|
||||
auto open = convos->get_community(base_url_chars, room_chars);
|
||||
if (open) {
|
||||
auto serialized = serialize_open_group(env, *open);
|
||||
return serialized;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOrConstructCommunity__Ljava_lang_String_2Ljava_lang_String_2_3B(
|
||||
JNIEnv *env, jobject thiz, jstring base_url, jstring room, jbyteArray pub_key) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
auto base_url_chars = env->GetStringUTFChars(base_url, nullptr);
|
||||
auto room_chars = env->GetStringUTFChars(room, nullptr);
|
||||
auto pub_key_ustring = util::ustring_from_bytes(env, pub_key);
|
||||
auto open = convos->get_or_construct_community(base_url_chars, room_chars, pub_key_ustring);
|
||||
auto serialized = serialize_open_group(env, open);
|
||||
return serialized;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOrConstructCommunity__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2(
|
||||
JNIEnv *env, jobject thiz, jstring base_url, jstring room, jstring pub_key_hex) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
auto base_url_chars = env->GetStringUTFChars(base_url, nullptr);
|
||||
auto room_chars = env->GetStringUTFChars(room, nullptr);
|
||||
auto hex_chars = env->GetStringUTFChars(pub_key_hex, nullptr);
|
||||
auto open = convos->get_or_construct_community(base_url_chars, room_chars, hex_chars);
|
||||
env->ReleaseStringUTFChars(base_url, base_url_chars);
|
||||
env->ReleaseStringUTFChars(room, room_chars);
|
||||
env->ReleaseStringUTFChars(pub_key_hex, hex_chars);
|
||||
auto serialized = serialize_open_group(env, open);
|
||||
return serialized;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseCommunity__Lnetwork_loki_messenger_libsession_1util_util_Conversation_Community_2(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jobject open_group) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
auto deserialized = deserialize_community(env, open_group, convos);
|
||||
return convos->erase(deserialized);
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseCommunity__Ljava_lang_String_2Ljava_lang_String_2(
|
||||
JNIEnv *env, jobject thiz, jstring base_url, jstring room) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
auto base_url_chars = env->GetStringUTFChars(base_url, nullptr);
|
||||
auto room_chars = env->GetStringUTFChars(room, nullptr);
|
||||
auto result = convos->erase_community(base_url_chars, room_chars);
|
||||
env->ReleaseStringUTFChars(base_url, base_url_chars);
|
||||
env->ReleaseStringUTFChars(room, room_chars);
|
||||
return result;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getLegacyClosedGroup(
|
||||
JNIEnv *env, jobject thiz, jstring group_id) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
auto id_chars = env->GetStringUTFChars(group_id, nullptr);
|
||||
auto lgc = convos->get_legacy_group(id_chars);
|
||||
env->ReleaseStringUTFChars(group_id, id_chars);
|
||||
if (lgc) {
|
||||
auto serialized = serialize_legacy_group(env, *lgc);
|
||||
return serialized;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_getOrConstructLegacyGroup(
|
||||
JNIEnv *env, jobject thiz, jstring group_id) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
auto id_chars = env->GetStringUTFChars(group_id, nullptr);
|
||||
auto lgc = convos->get_or_construct_legacy_group(id_chars);
|
||||
env->ReleaseStringUTFChars(group_id, id_chars);
|
||||
return serialize_legacy_group(env, lgc);
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseLegacyClosedGroup(
|
||||
JNIEnv *env, jobject thiz, jstring group_id) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
auto id_chars = env->GetStringUTFChars(group_id, nullptr);
|
||||
auto result = convos->erase_legacy_group(id_chars);
|
||||
env->ReleaseStringUTFChars(group_id, id_chars);
|
||||
return result;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_erase(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jobject conversation) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
auto deserialized = deserialize_any(env, conversation, convos);
|
||||
if (!deserialized.has_value()) return false;
|
||||
return convos->erase(*deserialized);
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_sizeCommunities(JNIEnv *env,
|
||||
jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
return convos->size_communities();
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_sizeLegacyClosedGroups(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
return convos->size_legacy_groups();
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_all(JNIEnv *env,
|
||||
jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
jclass stack = env->FindClass("java/util/Stack");
|
||||
jmethodID init = env->GetMethodID(stack, "<init>", "()V");
|
||||
jobject our_stack = env->NewObject(stack, init);
|
||||
jmethodID push = env->GetMethodID(stack, "push", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
for (const auto& convo : *convos) {
|
||||
auto contact_obj = serialize_any(env, convo);
|
||||
env->CallObjectMethod(our_stack, push, contact_obj);
|
||||
}
|
||||
return our_stack;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_allOneToOnes(JNIEnv *env,
|
||||
jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
jclass stack = env->FindClass("java/util/Stack");
|
||||
jmethodID init = env->GetMethodID(stack, "<init>", "()V");
|
||||
jobject our_stack = env->NewObject(stack, init);
|
||||
jmethodID push = env->GetMethodID(stack, "push", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
for (auto contact = convos->begin_1to1(); contact != convos->end(); ++contact)
|
||||
env->CallObjectMethod(our_stack, push, serialize_one_to_one(env, *contact));
|
||||
return our_stack;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_allCommunities(JNIEnv *env,
|
||||
jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
jclass stack = env->FindClass("java/util/Stack");
|
||||
jmethodID init = env->GetMethodID(stack, "<init>", "()V");
|
||||
jobject our_stack = env->NewObject(stack, init);
|
||||
jmethodID push = env->GetMethodID(stack, "push", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
for (auto contact = convos->begin_communities(); contact != convos->end(); ++contact)
|
||||
env->CallObjectMethod(our_stack, push, serialize_open_group(env, *contact));
|
||||
return our_stack;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_allLegacyClosedGroups(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
jclass stack = env->FindClass("java/util/Stack");
|
||||
jmethodID init = env->GetMethodID(stack, "<init>", "()V");
|
||||
jobject our_stack = env->NewObject(stack, init);
|
||||
jmethodID push = env->GetMethodID(stack, "push", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
for (auto contact = convos->begin_legacy_groups(); contact != convos->end(); ++contact)
|
||||
env->CallObjectMethod(our_stack, push, serialize_legacy_group(env, *contact));
|
||||
return our_stack;
|
||||
}
|
||||
122
libsession-util/src/main/cpp/conversation.h
Normal file
122
libsession-util/src/main/cpp/conversation.h
Normal file
@@ -0,0 +1,122 @@
|
||||
#ifndef SESSION_ANDROID_CONVERSATION_H
|
||||
#define SESSION_ANDROID_CONVERSATION_H
|
||||
|
||||
#include <jni.h>
|
||||
#include "util.h"
|
||||
#include "session/config/convo_info_volatile.hpp"
|
||||
|
||||
inline session::config::ConvoInfoVolatile *ptrToConvoInfo(JNIEnv *env, jobject obj) {
|
||||
jclass contactsClass = env->FindClass("network/loki/messenger/libsession_util/ConversationVolatileConfig");
|
||||
jfieldID pointerField = env->GetFieldID(contactsClass, "pointer", "J");
|
||||
return (session::config::ConvoInfoVolatile *) env->GetLongField(obj, pointerField);
|
||||
}
|
||||
|
||||
inline jobject serialize_one_to_one(JNIEnv *env, session::config::convo::one_to_one one_to_one) {
|
||||
jclass clazz = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$OneToOne");
|
||||
jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Ljava/lang/String;JZ)V");
|
||||
auto session_id = env->NewStringUTF(one_to_one.session_id.data());
|
||||
auto last_read = one_to_one.last_read;
|
||||
auto unread = one_to_one.unread;
|
||||
jobject serialized = env->NewObject(clazz, constructor, session_id, last_read, unread);
|
||||
return serialized;
|
||||
}
|
||||
|
||||
inline jobject serialize_open_group(JNIEnv *env, session::config::convo::community community) {
|
||||
jclass clazz = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$Community");
|
||||
auto base_community = util::serialize_base_community(env, community);
|
||||
jmethodID constructor = env->GetMethodID(clazz, "<init>",
|
||||
"(Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;JZ)V");
|
||||
auto last_read = community.last_read;
|
||||
auto unread = community.unread;
|
||||
jobject serialized = env->NewObject(clazz, constructor, base_community, last_read, unread);
|
||||
return serialized;
|
||||
}
|
||||
|
||||
inline jobject serialize_legacy_group(JNIEnv *env, session::config::convo::legacy_group group) {
|
||||
jclass clazz = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$LegacyGroup");
|
||||
jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Ljava/lang/String;JZ)V");
|
||||
auto group_id = env->NewStringUTF(group.id.data());
|
||||
auto last_read = group.last_read;
|
||||
auto unread = group.unread;
|
||||
jobject serialized = env->NewObject(clazz, constructor, group_id, last_read, unread);
|
||||
return serialized;
|
||||
}
|
||||
|
||||
inline jobject serialize_any(JNIEnv *env, session::config::convo::any any) {
|
||||
if (auto* dm = std::get_if<session::config::convo::one_to_one>(&any)) {
|
||||
return serialize_one_to_one(env, *dm);
|
||||
} else if (auto* og = std::get_if<session::config::convo::community>(&any)) {
|
||||
return serialize_open_group(env, *og);
|
||||
} else if (auto* lgc = std::get_if<session::config::convo::legacy_group>(&any)) {
|
||||
return serialize_legacy_group(env, *lgc);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline session::config::convo::one_to_one deserialize_one_to_one(JNIEnv *env, jobject info, session::config::ConvoInfoVolatile *conf) {
|
||||
auto clazz = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$OneToOne");
|
||||
auto id_getter = env->GetFieldID(clazz, "sessionId", "Ljava/lang/String;");
|
||||
auto last_read_getter = env->GetFieldID(clazz, "lastRead", "J");
|
||||
auto unread_getter = env->GetFieldID(clazz, "unread", "Z");
|
||||
jstring id = static_cast<jstring>(env->GetObjectField(info, id_getter));
|
||||
auto id_chars = env->GetStringUTFChars(id, nullptr);
|
||||
std::string id_string = std::string{id_chars};
|
||||
auto deserialized = conf->get_or_construct_1to1(id_string);
|
||||
deserialized.last_read = env->GetLongField(info, last_read_getter);
|
||||
deserialized.unread = env->GetBooleanField(info, unread_getter);
|
||||
env->ReleaseStringUTFChars(id, id_chars);
|
||||
return deserialized;
|
||||
}
|
||||
|
||||
inline session::config::convo::community deserialize_community(JNIEnv *env, jobject info, session::config::ConvoInfoVolatile *conf) {
|
||||
auto clazz = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$Community");
|
||||
auto base_community_getter = env->GetFieldID(clazz, "baseCommunityInfo", "Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;");
|
||||
auto last_read_getter = env->GetFieldID(clazz, "lastRead", "J");
|
||||
auto unread_getter = env->GetFieldID(clazz, "unread", "Z");
|
||||
|
||||
auto base_community_info = env->GetObjectField(info, base_community_getter);
|
||||
|
||||
auto base_community_deserialized = util::deserialize_base_community(env, base_community_info);
|
||||
auto deserialized = conf->get_or_construct_community(
|
||||
base_community_deserialized.base_url(),
|
||||
base_community_deserialized.room(),
|
||||
base_community_deserialized.pubkey()
|
||||
);
|
||||
|
||||
deserialized.last_read = env->GetLongField(info, last_read_getter);
|
||||
deserialized.unread = env->GetBooleanField(info, unread_getter);
|
||||
|
||||
return deserialized;
|
||||
}
|
||||
|
||||
inline session::config::convo::legacy_group deserialize_legacy_closed_group(JNIEnv *env, jobject info, session::config::ConvoInfoVolatile *conf) {
|
||||
auto clazz = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$LegacyGroup");
|
||||
auto group_id_getter = env->GetFieldID(clazz, "groupId", "Ljava/lang/String;");
|
||||
auto last_read_getter = env->GetFieldID(clazz, "lastRead", "J");
|
||||
auto unread_getter = env->GetFieldID(clazz, "unread", "Z");
|
||||
auto group_id = static_cast<jstring>(env->GetObjectField(info, group_id_getter));
|
||||
auto group_id_bytes = env->GetStringUTFChars(group_id, nullptr);
|
||||
auto group_id_string = std::string{group_id_bytes};
|
||||
auto deserialized = conf->get_or_construct_legacy_group(group_id_string);
|
||||
deserialized.last_read = env->GetLongField(info, last_read_getter);
|
||||
deserialized.unread = env->GetBooleanField(info, unread_getter);
|
||||
env->ReleaseStringUTFChars(group_id, group_id_bytes);
|
||||
return deserialized;
|
||||
}
|
||||
|
||||
inline std::optional<session::config::convo::any> deserialize_any(JNIEnv *env, jobject convo, session::config::ConvoInfoVolatile *conf) {
|
||||
auto oto_class = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$OneToOne");
|
||||
auto og_class = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$Community");
|
||||
auto lgc_class = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$LegacyGroup");
|
||||
auto object_class = env->GetObjectClass(convo);
|
||||
if (env->IsSameObject(object_class, oto_class)) {
|
||||
return session::config::convo::any{deserialize_one_to_one(env, convo, conf)};
|
||||
} else if (env->IsSameObject(object_class, og_class)) {
|
||||
return session::config::convo::any{deserialize_community(env, convo, conf)};
|
||||
} else if (env->IsSameObject(object_class, lgc_class)) {
|
||||
return session::config::convo::any{deserialize_legacy_closed_group(env, convo, conf)};
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
#endif //SESSION_ANDROID_CONVERSATION_H
|
||||
274
libsession-util/src/main/cpp/user_groups.cpp
Normal file
274
libsession-util/src/main/cpp/user_groups.cpp
Normal file
@@ -0,0 +1,274 @@
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
|
||||
#include "user_groups.h"
|
||||
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_00024Companion_newInstance___3B(
|
||||
JNIEnv *env, jobject thiz, jbyteArray ed25519_secret_key) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto secret_key = util::ustring_from_bytes(env, ed25519_secret_key);
|
||||
|
||||
auto* user_groups = new session::config::UserGroups(secret_key, std::nullopt);
|
||||
|
||||
jclass contactsClass = env->FindClass("network/loki/messenger/libsession_util/UserGroupsConfig");
|
||||
jmethodID constructor = env->GetMethodID(contactsClass, "<init>", "(J)V");
|
||||
jobject newConfig = env->NewObject(contactsClass, constructor, reinterpret_cast<jlong>(user_groups));
|
||||
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_00024Companion_newInstance___3B_3B(
|
||||
JNIEnv *env, jobject thiz, jbyteArray ed25519_secret_key, jbyteArray initial_dump) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto secret_key = util::ustring_from_bytes(env, ed25519_secret_key);
|
||||
auto initial = util::ustring_from_bytes(env, initial_dump);
|
||||
|
||||
auto* user_groups = new session::config::UserGroups(secret_key, initial);
|
||||
|
||||
jclass contactsClass = env->FindClass("network/loki/messenger/libsession_util/UserGroupsConfig");
|
||||
jmethodID constructor = env->GetMethodID(contactsClass, "<init>", "(J)V");
|
||||
jobject newConfig = env->NewObject(contactsClass, constructor, reinterpret_cast<jlong>(user_groups));
|
||||
|
||||
return newConfig;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_util_GroupInfo_00024LegacyGroupInfo_00024Companion_NAME_1MAX_1LENGTH(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
return session::config::legacy_group_info::NAME_MAX_LENGTH;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getCommunityInfo(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jstring base_url,
|
||||
jstring room) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToUserGroups(env, thiz);
|
||||
auto base_url_bytes = env->GetStringUTFChars(base_url, nullptr);
|
||||
auto room_bytes = env->GetStringUTFChars(room, nullptr);
|
||||
|
||||
auto community = conf->get_community(base_url_bytes, room_bytes);
|
||||
|
||||
jobject community_info = nullptr;
|
||||
|
||||
if (community) {
|
||||
community_info = serialize_community_info(env, *community);
|
||||
}
|
||||
env->ReleaseStringUTFChars(base_url, base_url_bytes);
|
||||
env->ReleaseStringUTFChars(room, room_bytes);
|
||||
return community_info;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getLegacyGroupInfo(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jstring session_id) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToUserGroups(env, thiz);
|
||||
auto id_bytes = env->GetStringUTFChars(session_id, nullptr);
|
||||
auto legacy_group = conf->get_legacy_group(id_bytes);
|
||||
jobject return_group = nullptr;
|
||||
if (legacy_group) {
|
||||
return_group = serialize_legacy_group_info(env, *legacy_group);
|
||||
}
|
||||
env->ReleaseStringUTFChars(session_id, id_bytes);
|
||||
return return_group;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getOrConstructCommunityInfo(
|
||||
JNIEnv *env, jobject thiz, jstring base_url, jstring room, jstring pub_key_hex) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToUserGroups(env, thiz);
|
||||
auto base_url_bytes = env->GetStringUTFChars(base_url, nullptr);
|
||||
auto room_bytes = env->GetStringUTFChars(room, nullptr);
|
||||
auto pub_hex_bytes = env->GetStringUTFChars(pub_key_hex, nullptr);
|
||||
|
||||
auto group = conf->get_or_construct_community(base_url_bytes, room_bytes, pub_hex_bytes);
|
||||
|
||||
env->ReleaseStringUTFChars(base_url, base_url_bytes);
|
||||
env->ReleaseStringUTFChars(room, room_bytes);
|
||||
env->ReleaseStringUTFChars(pub_key_hex, pub_hex_bytes);
|
||||
return serialize_community_info(env, group);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_getOrConstructLegacyGroupInfo(
|
||||
JNIEnv *env, jobject thiz, jstring session_id) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToUserGroups(env, thiz);
|
||||
auto id_bytes = env->GetStringUTFChars(session_id, nullptr);
|
||||
auto group = conf->get_or_construct_legacy_group(id_bytes);
|
||||
env->ReleaseStringUTFChars(session_id, id_bytes);
|
||||
return serialize_legacy_group_info(env, group);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_set__Lnetwork_loki_messenger_libsession_1util_util_GroupInfo_2(
|
||||
JNIEnv *env, jobject thiz, jobject group_info) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToUserGroups(env, thiz);
|
||||
auto community_info = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$CommunityGroupInfo");
|
||||
auto legacy_info = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$LegacyGroupInfo");
|
||||
auto object_class = env->GetObjectClass(group_info);
|
||||
if (env->IsSameObject(community_info, object_class)) {
|
||||
auto deserialized = deserialize_community_info(env, group_info, conf);
|
||||
conf->set(deserialized);
|
||||
} else if (env->IsSameObject(legacy_info, object_class)) {
|
||||
auto deserialized = deserialize_legacy_group_info(env, group_info, conf);
|
||||
conf->set(deserialized);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_erase__Lnetwork_loki_messenger_libsession_1util_util_GroupInfo_2(
|
||||
JNIEnv *env, jobject thiz, jobject group_info) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToUserGroups(env, thiz);
|
||||
auto communityInfo = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$CommunityGroupInfo");
|
||||
auto legacyInfo = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$LegacyGroupInfo");
|
||||
auto group_object = env->GetObjectClass(group_info);
|
||||
if (env->IsSameObject(group_object, communityInfo)) {
|
||||
auto deserialized = deserialize_community_info(env, group_info, conf);
|
||||
conf->erase(deserialized);
|
||||
} else if (env->IsSameObject(group_object, legacyInfo)) {
|
||||
auto deserialized = deserialize_legacy_group_info(env, group_info, conf);
|
||||
conf->erase(deserialized);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_sizeCommunityInfo(JNIEnv *env,
|
||||
jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToUserGroups(env, thiz);
|
||||
return conf->size_communities();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_sizeLegacyGroupInfo(JNIEnv *env,
|
||||
jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToUserGroups(env, thiz);
|
||||
return conf->size_legacy_groups();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_size(JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToConvoInfo(env, thiz);
|
||||
return conf->size();
|
||||
}
|
||||
|
||||
inline jobject iterator_as_java_stack(JNIEnv *env, const session::config::UserGroups::iterator& begin, const session::config::UserGroups::iterator& end) {
|
||||
jclass stack = env->FindClass("java/util/Stack");
|
||||
jmethodID init = env->GetMethodID(stack, "<init>", "()V");
|
||||
jobject our_stack = env->NewObject(stack, init);
|
||||
jmethodID push = env->GetMethodID(stack, "push", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
for (auto it = begin; it != end;) {
|
||||
// do something with it
|
||||
auto item = *it;
|
||||
jobject serialized = nullptr;
|
||||
if (auto* lgc = std::get_if<session::config::legacy_group_info>(&item)) {
|
||||
serialized = serialize_legacy_group_info(env, *lgc);
|
||||
} else if (auto* community = std::get_if<session::config::community_info>(&item)) {
|
||||
serialized = serialize_community_info(env, *community);
|
||||
}
|
||||
if (serialized != nullptr) {
|
||||
env->CallObjectMethod(our_stack, push, serialized);
|
||||
}
|
||||
it++;
|
||||
}
|
||||
return our_stack;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_all(JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToUserGroups(env, thiz);
|
||||
jobject all_stack = iterator_as_java_stack(env, conf->begin(), conf->end());
|
||||
return all_stack;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_allCommunityInfo(JNIEnv *env,
|
||||
jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToUserGroups(env, thiz);
|
||||
jobject community_stack = iterator_as_java_stack(env, conf->begin_communities(), conf->end());
|
||||
return community_stack;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_allLegacyGroupInfo(JNIEnv *env,
|
||||
jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToUserGroups(env, thiz);
|
||||
jobject legacy_stack = iterator_as_java_stack(env, conf->begin_legacy_groups(), conf->end());
|
||||
return legacy_stack;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_eraseCommunity__Lnetwork_loki_messenger_libsession_1util_util_BaseCommunityInfo_2(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jobject base_community_info) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToUserGroups(env, thiz);
|
||||
auto base_community = util::deserialize_base_community(env, base_community_info);
|
||||
return conf->erase_community(base_community.base_url(),base_community.room());
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_eraseCommunity__Ljava_lang_String_2Ljava_lang_String_2(
|
||||
JNIEnv *env, jobject thiz, jstring server, jstring room) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToUserGroups(env, thiz);
|
||||
auto server_bytes = env->GetStringUTFChars(server, nullptr);
|
||||
auto room_bytes = env->GetStringUTFChars(room, nullptr);
|
||||
auto community = conf->get_community(server_bytes, room_bytes);
|
||||
bool deleted = false;
|
||||
if (community) {
|
||||
deleted = conf->erase(*community);
|
||||
}
|
||||
env->ReleaseStringUTFChars(server, server_bytes);
|
||||
env->ReleaseStringUTFChars(room, room_bytes);
|
||||
return deleted;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_eraseLegacyGroup(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jstring session_id) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto conf = ptrToUserGroups(env, thiz);
|
||||
auto session_id_bytes = env->GetStringUTFChars(session_id, nullptr);
|
||||
bool return_bool = conf->erase_legacy_group(session_id_bytes);
|
||||
env->ReleaseStringUTFChars(session_id, session_id_bytes);
|
||||
return return_bool;
|
||||
}
|
||||
139
libsession-util/src/main/cpp/user_groups.h
Normal file
139
libsession-util/src/main/cpp/user_groups.h
Normal file
@@ -0,0 +1,139 @@
|
||||
|
||||
#ifndef SESSION_ANDROID_USER_GROUPS_H
|
||||
#define SESSION_ANDROID_USER_GROUPS_H
|
||||
|
||||
#include "jni.h"
|
||||
#include "util.h"
|
||||
#include "conversation.h"
|
||||
#include "session/config/user_groups.hpp"
|
||||
|
||||
inline session::config::UserGroups* ptrToUserGroups(JNIEnv *env, jobject obj) {
|
||||
jclass configClass = env->FindClass("network/loki/messenger/libsession_util/UserGroupsConfig");
|
||||
jfieldID pointerField = env->GetFieldID(configClass, "pointer", "J");
|
||||
return (session::config::UserGroups*) env->GetLongField(obj, pointerField);
|
||||
}
|
||||
|
||||
inline void deserialize_members_into(JNIEnv *env, jobject members_map, session::config::legacy_group_info& to_append_group) {
|
||||
jclass map_class = env->FindClass("java/util/Map");
|
||||
jclass map_entry_class = env->FindClass("java/util/Map$Entry");
|
||||
jclass set_class = env->FindClass("java/util/Set");
|
||||
jclass iterator_class = env->FindClass("java/util/Iterator");
|
||||
jclass boxed_bool = env->FindClass("java/lang/Boolean");
|
||||
|
||||
jmethodID get_entry_set = env->GetMethodID(map_class, "entrySet", "()Ljava/util/Set;");
|
||||
jmethodID get_at = env->GetMethodID(set_class, "iterator", "()Ljava/util/Iterator;");
|
||||
jmethodID has_next = env->GetMethodID(iterator_class, "hasNext", "()Z");
|
||||
jmethodID next = env->GetMethodID(iterator_class, "next", "()Ljava/lang/Object;");
|
||||
jmethodID get_key = env->GetMethodID(map_entry_class, "getKey", "()Ljava/lang/Object;");
|
||||
jmethodID get_value = env->GetMethodID(map_entry_class, "getValue", "()Ljava/lang/Object;");
|
||||
jmethodID get_bool_value = env->GetMethodID(boxed_bool, "booleanValue", "()Z");
|
||||
|
||||
jobject entry_set = env->CallObjectMethod(members_map, get_entry_set);
|
||||
jobject iterator = env->CallObjectMethod(entry_set, get_at);
|
||||
|
||||
while (env->CallBooleanMethod(iterator, has_next)) {
|
||||
jobject entry = env->CallObjectMethod(iterator, next);
|
||||
jstring key = static_cast<jstring>(env->CallObjectMethod(entry, get_key));
|
||||
jobject boxed = env->CallObjectMethod(entry, get_value);
|
||||
bool is_admin = env->CallBooleanMethod(boxed, get_bool_value);
|
||||
auto member_string = env->GetStringUTFChars(key, nullptr);
|
||||
to_append_group.insert(member_string, is_admin);
|
||||
env->ReleaseStringUTFChars(key, member_string);
|
||||
}
|
||||
}
|
||||
|
||||
inline session::config::legacy_group_info deserialize_legacy_group_info(JNIEnv *env, jobject info, session::config::UserGroups* conf) {
|
||||
auto clazz = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$LegacyGroupInfo");
|
||||
auto id_field = env->GetFieldID(clazz, "sessionId", "Ljava/lang/String;");
|
||||
auto name_field = env->GetFieldID(clazz, "name", "Ljava/lang/String;");
|
||||
auto members_field = env->GetFieldID(clazz, "members", "Ljava/util/Map;");
|
||||
auto enc_pub_key_field = env->GetFieldID(clazz, "encPubKey", "[B");
|
||||
auto enc_sec_key_field = env->GetFieldID(clazz, "encSecKey", "[B");
|
||||
auto priority_field = env->GetFieldID(clazz, "priority", "I");
|
||||
auto disappearing_timer_field = env->GetFieldID(clazz, "disappearingTimer", "J");
|
||||
auto joined_at_field = env->GetFieldID(clazz, "joinedAt", "J");
|
||||
jstring id = static_cast<jstring>(env->GetObjectField(info, id_field));
|
||||
jstring name = static_cast<jstring>(env->GetObjectField(info, name_field));
|
||||
jobject members_map = env->GetObjectField(info, members_field);
|
||||
jbyteArray enc_pub_key = static_cast<jbyteArray>(env->GetObjectField(info, enc_pub_key_field));
|
||||
jbyteArray enc_sec_key = static_cast<jbyteArray>(env->GetObjectField(info, enc_sec_key_field));
|
||||
int priority = env->GetIntField(info, priority_field);
|
||||
long joined_at = env->GetLongField(info, joined_at_field);
|
||||
|
||||
auto id_bytes = env->GetStringUTFChars(id, nullptr);
|
||||
auto name_bytes = env->GetStringUTFChars(name, nullptr);
|
||||
auto enc_pub_key_bytes = util::ustring_from_bytes(env, enc_pub_key);
|
||||
auto enc_sec_key_bytes = util::ustring_from_bytes(env, enc_sec_key);
|
||||
|
||||
auto info_deserialized = conf->get_or_construct_legacy_group(id_bytes);
|
||||
|
||||
auto current_members = info_deserialized.members();
|
||||
for (auto member = current_members.begin(); member != current_members.end(); ++member) {
|
||||
info_deserialized.erase(member->first);
|
||||
}
|
||||
deserialize_members_into(env, members_map, info_deserialized);
|
||||
info_deserialized.name = name_bytes;
|
||||
info_deserialized.enc_pubkey = enc_pub_key_bytes;
|
||||
info_deserialized.enc_seckey = enc_sec_key_bytes;
|
||||
info_deserialized.priority = priority;
|
||||
info_deserialized.disappearing_timer = std::chrono::seconds(env->GetLongField(info, disappearing_timer_field));
|
||||
info_deserialized.joined_at = joined_at;
|
||||
env->ReleaseStringUTFChars(id, id_bytes);
|
||||
env->ReleaseStringUTFChars(name, name_bytes);
|
||||
return info_deserialized;
|
||||
}
|
||||
|
||||
inline session::config::community_info deserialize_community_info(JNIEnv *env, jobject info, session::config::UserGroups* conf) {
|
||||
auto clazz = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$CommunityGroupInfo");
|
||||
auto base_info = env->GetFieldID(clazz, "community", "Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;");
|
||||
auto priority = env->GetFieldID(clazz, "priority", "I");
|
||||
jobject base_community_info = env->GetObjectField(info, base_info);
|
||||
auto deserialized_base_info = util::deserialize_base_community(env, base_community_info);
|
||||
int deserialized_priority = env->GetIntField(info, priority);
|
||||
auto community_info = conf->get_or_construct_community(deserialized_base_info.base_url(), deserialized_base_info.room(), deserialized_base_info.pubkey_hex());
|
||||
community_info.priority = deserialized_priority;
|
||||
return community_info;
|
||||
}
|
||||
|
||||
inline jobject serialize_members(JNIEnv *env, std::map<std::string, bool> members_map) {
|
||||
jclass map_class = env->FindClass("java/util/HashMap");
|
||||
jclass boxed_bool = env->FindClass("java/lang/Boolean");
|
||||
jmethodID map_constructor = env->GetMethodID(map_class, "<init>", "()V");
|
||||
jmethodID insert = env->GetMethodID(map_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
jmethodID new_bool = env->GetMethodID(boxed_bool, "<init>", "(Z)V");
|
||||
|
||||
jobject new_map = env->NewObject(map_class, map_constructor);
|
||||
for (auto it = members_map.begin(); it != members_map.end(); it++) {
|
||||
auto session_id = env->NewStringUTF(it->first.data());
|
||||
bool is_admin = it->second;
|
||||
auto jbool = env->NewObject(boxed_bool, new_bool, is_admin);
|
||||
env->CallObjectMethod(new_map, insert, session_id, jbool);
|
||||
}
|
||||
return new_map;
|
||||
}
|
||||
|
||||
inline jobject serialize_legacy_group_info(JNIEnv *env, session::config::legacy_group_info info) {
|
||||
jstring session_id = env->NewStringUTF(info.session_id.data());
|
||||
jstring name = env->NewStringUTF(info.name.data());
|
||||
jobject members = serialize_members(env, info.members());
|
||||
jbyteArray enc_pubkey = util::bytes_from_ustring(env, info.enc_pubkey);
|
||||
jbyteArray enc_seckey = util::bytes_from_ustring(env, info.enc_seckey);
|
||||
int priority = info.priority;
|
||||
long joined_at = info.joined_at;
|
||||
|
||||
jclass legacy_group_class = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$LegacyGroupInfo");
|
||||
jmethodID constructor = env->GetMethodID(legacy_group_class, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;[B[BIJJ)V");
|
||||
jobject serialized = env->NewObject(legacy_group_class, constructor, session_id, name, members, enc_pubkey, enc_seckey, priority, (jlong) info.disappearing_timer.count(), joined_at);
|
||||
return serialized;
|
||||
}
|
||||
|
||||
inline jobject serialize_community_info(JNIEnv *env, session::config::community_info info) {
|
||||
auto priority = info.priority;
|
||||
auto serialized_info = util::serialize_base_community(env, info);
|
||||
auto clazz = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$CommunityGroupInfo");
|
||||
jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;I)V");
|
||||
jobject serialized = env->NewObject(clazz, constructor, serialized_info, priority);
|
||||
return serialized;
|
||||
}
|
||||
|
||||
#endif //SESSION_ANDROID_USER_GROUPS_H
|
||||
152
libsession-util/src/main/cpp/user_profile.cpp
Normal file
152
libsession-util/src/main/cpp/user_profile.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
#include "user_profile.h"
|
||||
#include "util.h"
|
||||
|
||||
extern "C" {
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserProfile_00024Companion_newInstance___3B_3B(
|
||||
JNIEnv *env, jobject thiz, jbyteArray ed25519_secret_key, jbyteArray initial_dump) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto secret_key = util::ustring_from_bytes(env, ed25519_secret_key);
|
||||
auto initial = util::ustring_from_bytes(env, initial_dump);
|
||||
auto* profile = new session::config::UserProfile(secret_key, std::optional(initial));
|
||||
|
||||
jclass userClass = env->FindClass("network/loki/messenger/libsession_util/UserProfile");
|
||||
jmethodID constructor = env->GetMethodID(userClass, "<init>", "(J)V");
|
||||
jobject newConfig = env->NewObject(userClass, constructor, reinterpret_cast<jlong>(profile));
|
||||
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserProfile_00024Companion_newInstance___3B(
|
||||
JNIEnv* env,
|
||||
jobject,
|
||||
jbyteArray secretKey) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto* profile = new session::config::UserProfile(util::ustring_from_bytes(env, secretKey), std::nullopt);
|
||||
|
||||
jclass userClass = env->FindClass("network/loki/messenger/libsession_util/UserProfile");
|
||||
jmethodID constructor = env->GetMethodID(userClass, "<init>", "(J)V");
|
||||
jobject newConfig = env->NewObject(userClass, constructor, reinterpret_cast<jlong>(profile));
|
||||
|
||||
return newConfig;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserProfile_setName(
|
||||
JNIEnv* env,
|
||||
jobject thiz,
|
||||
jstring newName) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto profile = ptrToProfile(env, thiz);
|
||||
auto name_chars = env->GetStringUTFChars(newName, nullptr);
|
||||
profile->set_name(name_chars);
|
||||
env->ReleaseStringUTFChars(newName, name_chars);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserProfile_getName(JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto profile = ptrToProfile(env, thiz);
|
||||
auto name = profile->get_name();
|
||||
if (name == std::nullopt) return nullptr;
|
||||
jstring returnString = env->NewStringUTF(name->data());
|
||||
return returnString;
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserProfile_getPic(JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto profile = ptrToProfile(env, thiz);
|
||||
auto pic = profile->get_profile_pic();
|
||||
|
||||
jobject returnObject = util::serialize_user_pic(env, pic);
|
||||
|
||||
return returnObject;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserProfile_setPic(JNIEnv *env, jobject thiz,
|
||||
jobject user_pic) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto profile = ptrToProfile(env, thiz);
|
||||
auto pic = util::deserialize_user_pic(env, user_pic);
|
||||
auto url = env->GetStringUTFChars(pic.first, nullptr);
|
||||
auto key = util::ustring_from_bytes(env, pic.second);
|
||||
profile->set_profile_pic(url, key);
|
||||
env->ReleaseStringUTFChars(pic.first, url);
|
||||
}
|
||||
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserProfile_setNtsPriority(JNIEnv *env, jobject thiz,
|
||||
jint priority) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto profile = ptrToProfile(env, thiz);
|
||||
profile->set_nts_priority(priority);
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserProfile_getNtsPriority(JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto profile = ptrToProfile(env, thiz);
|
||||
return profile->get_nts_priority();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserProfile_setNtsExpiry(JNIEnv *env, jobject thiz,
|
||||
jobject expiry_mode) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto profile = ptrToProfile(env, thiz);
|
||||
auto expiry = util::deserialize_expiry(env, expiry_mode);
|
||||
profile->set_nts_expiry(std::chrono::seconds (expiry.second));
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserProfile_getNtsExpiry(JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto profile = ptrToProfile(env, thiz);
|
||||
auto nts_expiry = profile->get_nts_expiry();
|
||||
if (nts_expiry == std::nullopt) {
|
||||
auto expiry = util::serialize_expiry(env, session::config::expiration_mode::none, std::chrono::seconds(0));
|
||||
return expiry;
|
||||
}
|
||||
auto expiry = util::serialize_expiry(env, session::config::expiration_mode::after_send, std::chrono::seconds(*nts_expiry));
|
||||
return expiry;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserProfile_getCommunityMessageRequests(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto profile = ptrToProfile(env, thiz);
|
||||
auto blinded_msg_requests = profile->get_blinded_msgreqs();
|
||||
if (blinded_msg_requests.has_value()) {
|
||||
return *blinded_msg_requests;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserProfile_setCommunityMessageRequests(
|
||||
JNIEnv *env, jobject thiz, jboolean blocks) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto profile = ptrToProfile(env, thiz);
|
||||
profile->set_blinded_msgreqs(std::optional{(bool)blocks});
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserProfile_isBlockCommunityMessageRequestsSet(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto profile = ptrToProfile(env, thiz);
|
||||
return profile->get_blinded_msgreqs().has_value();
|
||||
}
|
||||
14
libsession-util/src/main/cpp/user_profile.h
Normal file
14
libsession-util/src/main/cpp/user_profile.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef SESSION_ANDROID_USER_PROFILE_H
|
||||
#define SESSION_ANDROID_USER_PROFILE_H
|
||||
|
||||
#include "session/config/user_profile.hpp"
|
||||
#include <jni.h>
|
||||
#include <string>
|
||||
|
||||
inline session::config::UserProfile* ptrToProfile(JNIEnv* env, jobject obj) {
|
||||
jclass configClass = env->FindClass("network/loki/messenger/libsession_util/UserProfile");
|
||||
jfieldID pointerField = env->GetFieldID(configClass, "pointer", "J");
|
||||
return (session::config::UserProfile*) env->GetLongField(obj, pointerField);
|
||||
}
|
||||
|
||||
#endif
|
||||
178
libsession-util/src/main/cpp/util.cpp
Normal file
178
libsession-util/src/main/cpp/util.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
#include "util.h"
|
||||
#include <string>
|
||||
#include <sodium/crypto_sign.h>
|
||||
|
||||
namespace util {
|
||||
|
||||
std::mutex util_mutex_ = std::mutex();
|
||||
|
||||
jbyteArray bytes_from_ustring(JNIEnv* env, session::ustring_view from_str) {
|
||||
size_t length = from_str.length();
|
||||
auto jlength = (jsize)length;
|
||||
jbyteArray new_array = env->NewByteArray(jlength);
|
||||
env->SetByteArrayRegion(new_array, 0, jlength, (jbyte*)from_str.data());
|
||||
return new_array;
|
||||
}
|
||||
|
||||
session::ustring ustring_from_bytes(JNIEnv* env, jbyteArray byteArray) {
|
||||
size_t len = env->GetArrayLength(byteArray);
|
||||
auto bytes = env->GetByteArrayElements(byteArray, nullptr);
|
||||
|
||||
session::ustring st{reinterpret_cast<const unsigned char *>(bytes), len};
|
||||
env->ReleaseByteArrayElements(byteArray, bytes, 0);
|
||||
return st;
|
||||
}
|
||||
|
||||
jobject serialize_user_pic(JNIEnv *env, session::config::profile_pic pic) {
|
||||
jclass returnObjectClass = env->FindClass("network/loki/messenger/libsession_util/util/UserPic");
|
||||
jmethodID constructor = env->GetMethodID(returnObjectClass, "<init>", "(Ljava/lang/String;[B)V");
|
||||
jstring url = env->NewStringUTF(pic.url.data());
|
||||
jbyteArray byteArray = util::bytes_from_ustring(env, pic.key);
|
||||
return env->NewObject(returnObjectClass, constructor, url, byteArray);
|
||||
}
|
||||
|
||||
std::pair<jstring, jbyteArray> deserialize_user_pic(JNIEnv *env, jobject user_pic) {
|
||||
jclass userPicClass = env->FindClass("network/loki/messenger/libsession_util/util/UserPic");
|
||||
jfieldID picField = env->GetFieldID(userPicClass, "url", "Ljava/lang/String;");
|
||||
jfieldID keyField = env->GetFieldID(userPicClass, "key", "[B");
|
||||
auto pic = (jstring)env->GetObjectField(user_pic, picField);
|
||||
auto key = (jbyteArray)env->GetObjectField(user_pic, keyField);
|
||||
return {pic, key};
|
||||
}
|
||||
|
||||
jobject serialize_base_community(JNIEnv *env, const session::config::community& community) {
|
||||
jclass base_community_clazz = env->FindClass("network/loki/messenger/libsession_util/util/BaseCommunityInfo");
|
||||
jmethodID base_community_constructor = env->GetMethodID(base_community_clazz, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
|
||||
auto base_url = env->NewStringUTF(community.base_url().data());
|
||||
auto room = env->NewStringUTF(community.room().data());
|
||||
auto pubkey_jstring = env->NewStringUTF(community.pubkey_hex().data());
|
||||
jobject ret = env->NewObject(base_community_clazz, base_community_constructor, base_url, room, pubkey_jstring);
|
||||
return ret;
|
||||
}
|
||||
|
||||
session::config::community deserialize_base_community(JNIEnv *env, jobject base_community) {
|
||||
jclass base_community_clazz = env->FindClass("network/loki/messenger/libsession_util/util/BaseCommunityInfo");
|
||||
jfieldID base_url_field = env->GetFieldID(base_community_clazz, "baseUrl", "Ljava/lang/String;");
|
||||
jfieldID room_field = env->GetFieldID(base_community_clazz, "room", "Ljava/lang/String;");
|
||||
jfieldID pubkey_hex_field = env->GetFieldID(base_community_clazz, "pubKeyHex", "Ljava/lang/String;");
|
||||
auto base_url = (jstring)env->GetObjectField(base_community,base_url_field);
|
||||
auto room = (jstring)env->GetObjectField(base_community, room_field);
|
||||
auto pub_key_hex = (jstring)env->GetObjectField(base_community, pubkey_hex_field);
|
||||
auto base_url_chars = env->GetStringUTFChars(base_url, nullptr);
|
||||
auto room_chars = env->GetStringUTFChars(room, nullptr);
|
||||
auto pub_key_hex_chars = env->GetStringUTFChars(pub_key_hex, nullptr);
|
||||
|
||||
auto community = session::config::community(base_url_chars, room_chars, pub_key_hex_chars);
|
||||
|
||||
env->ReleaseStringUTFChars(base_url, base_url_chars);
|
||||
env->ReleaseStringUTFChars(room, room_chars);
|
||||
env->ReleaseStringUTFChars(pub_key_hex, pub_key_hex_chars);
|
||||
return community;
|
||||
}
|
||||
|
||||
jobject serialize_expiry(JNIEnv *env, const session::config::expiration_mode& mode, const std::chrono::seconds& time_seconds) {
|
||||
jclass none = env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$NONE");
|
||||
jfieldID none_instance = env->GetStaticFieldID(none, "INSTANCE", "Lnetwork/loki/messenger/libsession_util/util/ExpiryMode$NONE;");
|
||||
jclass after_send = env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$AfterSend");
|
||||
jmethodID send_init = env->GetMethodID(after_send, "<init>", "(J)V");
|
||||
jclass after_read = env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$AfterRead");
|
||||
jmethodID read_init = env->GetMethodID(after_read, "<init>", "(J)V");
|
||||
|
||||
if (mode == session::config::expiration_mode::none) {
|
||||
return env->GetStaticObjectField(none, none_instance);
|
||||
} else if (mode == session::config::expiration_mode::after_send) {
|
||||
return env->NewObject(after_send, send_init, time_seconds.count());
|
||||
} else if (mode == session::config::expiration_mode::after_read) {
|
||||
return env->NewObject(after_read, read_init, time_seconds.count());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::pair<session::config::expiration_mode, long> deserialize_expiry(JNIEnv *env, jobject expiry_mode) {
|
||||
jclass parent = env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode");
|
||||
jclass after_read = env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$AfterRead");
|
||||
jclass after_send = env->FindClass("network/loki/messenger/libsession_util/util/ExpiryMode$AfterSend");
|
||||
jfieldID duration_seconds = env->GetFieldID(parent, "expirySeconds", "J");
|
||||
|
||||
jclass object_class = env->GetObjectClass(expiry_mode);
|
||||
|
||||
if (env->IsSameObject(object_class, after_read)) {
|
||||
return std::pair(session::config::expiration_mode::after_read, env->GetLongField(expiry_mode, duration_seconds));
|
||||
} else if (env->IsSameObject(object_class, after_send)) {
|
||||
return std::pair(session::config::expiration_mode::after_send, env->GetLongField(expiry_mode, duration_seconds));
|
||||
}
|
||||
return std::pair(session::config::expiration_mode::none, 0);
|
||||
}
|
||||
|
||||
jobject build_string_stack(JNIEnv* env, std::vector<std::string> to_add) {
|
||||
jclass stack_class = env->FindClass("java/util/Stack");
|
||||
jmethodID constructor = env->GetMethodID(stack_class,"<init>", "()V");
|
||||
jmethodID add = env->GetMethodID(stack_class, "push", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
jobject our_stack = env->NewObject(stack_class, constructor);
|
||||
for (std::basic_string_view<char> string: to_add) {
|
||||
env->CallObjectMethod(our_stack, add, env->NewStringUTF(string.data()));
|
||||
}
|
||||
return our_stack;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_util_Sodium_ed25519KeyPair(JNIEnv *env, jobject thiz, jbyteArray seed) {
|
||||
std::array<unsigned char, 32> ed_pk; // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
std::array<unsigned char, 64> ed_sk; // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
auto seed_bytes = util::ustring_from_bytes(env, seed);
|
||||
crypto_sign_ed25519_seed_keypair(ed_pk.data(), ed_sk.data(), seed_bytes.data());
|
||||
|
||||
jclass kp_class = env->FindClass("network/loki/messenger/libsession_util/util/KeyPair");
|
||||
jmethodID kp_constructor = env->GetMethodID(kp_class, "<init>", "([B[B)V");
|
||||
|
||||
jbyteArray pk_jarray = util::bytes_from_ustring(env, session::ustring_view {ed_pk.data(), ed_pk.size()});
|
||||
jbyteArray sk_jarray = util::bytes_from_ustring(env, session::ustring_view {ed_sk.data(), ed_sk.size()});
|
||||
|
||||
jobject return_obj = env->NewObject(kp_class, kp_constructor, pk_jarray, sk_jarray);
|
||||
return return_obj;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_util_Sodium_ed25519PkToCurve25519(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jbyteArray pk) {
|
||||
auto ed_pk = util::ustring_from_bytes(env, pk);
|
||||
std::array<unsigned char, 32> curve_pk; // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
int success = crypto_sign_ed25519_pk_to_curve25519(curve_pk.data(), ed_pk.data());
|
||||
if (success != 0) {
|
||||
jclass exception = env->FindClass("java/lang/Exception");
|
||||
env->ThrowNew(exception, "Invalid crypto_sign_ed25519_pk_to_curve25519 operation");
|
||||
return nullptr;
|
||||
}
|
||||
jbyteArray curve_pk_jarray = util::bytes_from_ustring(env, session::ustring_view {curve_pk.data(), curve_pk.size()});
|
||||
return curve_pk_jarray;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_util_BaseCommunityInfo_00024Companion_parseFullUrl(
|
||||
JNIEnv *env, jobject thiz, jstring full_url) {
|
||||
auto bytes = env->GetStringUTFChars(full_url, nullptr);
|
||||
auto [base, room, pk] = session::config::community::parse_full_url(bytes);
|
||||
env->ReleaseStringUTFChars(full_url, bytes);
|
||||
|
||||
jclass clazz = env->FindClass("kotlin/Triple");
|
||||
jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V");
|
||||
|
||||
auto base_j = env->NewStringUTF(base.data());
|
||||
auto room_j = env->NewStringUTF(room.data());
|
||||
auto pk_jbytes = util::bytes_from_ustring(env, pk);
|
||||
|
||||
jobject triple = env->NewObject(clazz, constructor, base_j, room_j, pk_jbytes);
|
||||
return triple;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_util_BaseCommunityInfo_fullUrl(JNIEnv *env,
|
||||
jobject thiz) {
|
||||
auto deserialized = util::deserialize_base_community(env, thiz);
|
||||
auto full_url = deserialized.full_url();
|
||||
return env->NewStringUTF(full_url.data());
|
||||
}
|
||||
25
libsession-util/src/main/cpp/util.h
Normal file
25
libsession-util/src/main/cpp/util.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef SESSION_ANDROID_UTIL_H
|
||||
#define SESSION_ANDROID_UTIL_H
|
||||
|
||||
#include <jni.h>
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include "session/types.hpp"
|
||||
#include "session/config/profile_pic.hpp"
|
||||
#include "session/config/user_groups.hpp"
|
||||
#include "session/config/expiring.hpp"
|
||||
|
||||
namespace util {
|
||||
extern std::mutex util_mutex_;
|
||||
jbyteArray bytes_from_ustring(JNIEnv* env, session::ustring_view from_str);
|
||||
session::ustring ustring_from_bytes(JNIEnv* env, jbyteArray byteArray);
|
||||
jobject serialize_user_pic(JNIEnv *env, session::config::profile_pic pic);
|
||||
std::pair<jstring, jbyteArray> deserialize_user_pic(JNIEnv *env, jobject user_pic);
|
||||
jobject serialize_base_community(JNIEnv *env, const session::config::community& base_community);
|
||||
session::config::community deserialize_base_community(JNIEnv *env, jobject base_community);
|
||||
jobject serialize_expiry(JNIEnv *env, const session::config::expiration_mode& mode, const std::chrono::seconds& time_seconds);
|
||||
std::pair<session::config::expiration_mode, long> deserialize_expiry(JNIEnv *env, jobject expiry_mode);
|
||||
jobject build_string_stack(JNIEnv* env, std::vector<std::string> to_add);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,207 @@
|
||||
package network.loki.messenger.libsession_util
|
||||
|
||||
import network.loki.messenger.libsession_util.util.BaseCommunityInfo
|
||||
import network.loki.messenger.libsession_util.util.ConfigPush
|
||||
import network.loki.messenger.libsession_util.util.Contact
|
||||
import network.loki.messenger.libsession_util.util.Conversation
|
||||
import network.loki.messenger.libsession_util.util.ExpiryMode
|
||||
import network.loki.messenger.libsession_util.util.GroupInfo
|
||||
import network.loki.messenger.libsession_util.util.UserPic
|
||||
import org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Kind
|
||||
import org.session.libsignal.utilities.IdPrefix
|
||||
import org.session.libsignal.utilities.Log
|
||||
import java.util.Stack
|
||||
|
||||
|
||||
sealed class ConfigBase(protected val /* yucky */ pointer: Long) {
|
||||
companion object {
|
||||
init {
|
||||
System.loadLibrary("session_util")
|
||||
}
|
||||
external fun kindFor(configNamespace: Int): Class<ConfigBase>
|
||||
|
||||
fun ConfigBase.protoKindFor(): Kind = when (this) {
|
||||
is UserProfile -> Kind.USER_PROFILE
|
||||
is Contacts -> Kind.CONTACTS
|
||||
is ConversationVolatileConfig -> Kind.CONVO_INFO_VOLATILE
|
||||
is UserGroupsConfig -> Kind.GROUPS
|
||||
}
|
||||
|
||||
// TODO: time in future to activate (hardcoded to 1st jan 2024 for testing, change before release)
|
||||
private const val ACTIVATE_TIME = 1690761600000
|
||||
|
||||
fun isNewConfigEnabled(forced: Boolean, currentTime: Long) =
|
||||
forced || currentTime >= ACTIVATE_TIME
|
||||
|
||||
const val PRIORITY_HIDDEN = -1
|
||||
const val PRIORITY_VISIBLE = 0
|
||||
const val PRIORITY_PINNED = 1
|
||||
|
||||
}
|
||||
|
||||
external fun dirty(): Boolean
|
||||
external fun needsPush(): Boolean
|
||||
external fun needsDump(): Boolean
|
||||
external fun push(): ConfigPush
|
||||
external fun dump(): ByteArray
|
||||
external fun encryptionDomain(): String
|
||||
external fun confirmPushed(seqNo: Long, newHash: String)
|
||||
external fun merge(toMerge: Array<Pair<String,ByteArray>>): Stack<String>
|
||||
external fun currentHashes(): List<String>
|
||||
|
||||
external fun configNamespace(): Int
|
||||
|
||||
// Singular merge
|
||||
external fun merge(toMerge: Pair<String,ByteArray>): Stack<String>
|
||||
|
||||
external fun free()
|
||||
|
||||
}
|
||||
|
||||
class Contacts(pointer: Long) : ConfigBase(pointer) {
|
||||
companion object {
|
||||
init {
|
||||
System.loadLibrary("session_util")
|
||||
}
|
||||
external fun newInstance(ed25519SecretKey: ByteArray): Contacts
|
||||
external fun newInstance(ed25519SecretKey: ByteArray, initialDump: ByteArray): Contacts
|
||||
}
|
||||
|
||||
external fun get(sessionId: String): Contact?
|
||||
external fun getOrConstruct(sessionId: String): Contact
|
||||
external fun all(): List<Contact>
|
||||
external fun set(contact: Contact)
|
||||
external fun erase(sessionId: String): Boolean
|
||||
|
||||
/**
|
||||
* Similar to [updateIfExists], but will create the underlying contact if it doesn't exist before passing to [updateFunction]
|
||||
*/
|
||||
fun upsertContact(sessionId: String, updateFunction: Contact.()->Unit = {}) {
|
||||
if (sessionId.startsWith(IdPrefix.BLINDED.value)) {
|
||||
Log.w("Loki", "Trying to create a contact with a blinded ID prefix")
|
||||
return
|
||||
} else if (sessionId.startsWith(IdPrefix.UN_BLINDED.value)) {
|
||||
Log.w("Loki", "Trying to create a contact with an un-blinded ID prefix")
|
||||
return
|
||||
} else if (sessionId.startsWith(IdPrefix.BLINDEDV2.value)) {
|
||||
Log.w("Loki", "Trying to create a contact with a blindedv2 ID prefix")
|
||||
return
|
||||
}
|
||||
val contact = getOrConstruct(sessionId)
|
||||
updateFunction(contact)
|
||||
set(contact)
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the contact by sessionId with a given [updateFunction], and applies to the underlying config.
|
||||
* the [updateFunction] doesn't run if there is no contact
|
||||
*/
|
||||
fun updateIfExists(sessionId: String, updateFunction: Contact.()->Unit) {
|
||||
if (sessionId.startsWith(IdPrefix.BLINDED.value)) {
|
||||
Log.w("Loki", "Trying to create a contact with a blinded ID prefix")
|
||||
return
|
||||
} else if (sessionId.startsWith(IdPrefix.UN_BLINDED.value)) {
|
||||
Log.w("Loki", "Trying to create a contact with an un-blinded ID prefix")
|
||||
return
|
||||
} else if (sessionId.startsWith(IdPrefix.BLINDEDV2.value)) {
|
||||
Log.w("Loki", "Trying to create a contact with a blindedv2 ID prefix")
|
||||
return
|
||||
}
|
||||
val contact = get(sessionId) ?: return
|
||||
updateFunction(contact)
|
||||
set(contact)
|
||||
}
|
||||
}
|
||||
|
||||
class UserProfile(pointer: Long) : ConfigBase(pointer) {
|
||||
companion object {
|
||||
init {
|
||||
System.loadLibrary("session_util")
|
||||
}
|
||||
external fun newInstance(ed25519SecretKey: ByteArray): UserProfile
|
||||
external fun newInstance(ed25519SecretKey: ByteArray, initialDump: ByteArray): UserProfile
|
||||
}
|
||||
|
||||
external fun setName(newName: String)
|
||||
external fun getName(): String?
|
||||
external fun getPic(): UserPic
|
||||
external fun setPic(userPic: UserPic)
|
||||
external fun setNtsPriority(priority: Int)
|
||||
external fun getNtsPriority(): Int
|
||||
external fun setNtsExpiry(expiryMode: ExpiryMode)
|
||||
external fun getNtsExpiry(): ExpiryMode
|
||||
external fun getCommunityMessageRequests(): Boolean
|
||||
external fun setCommunityMessageRequests(blocks: Boolean)
|
||||
external fun isBlockCommunityMessageRequestsSet(): Boolean
|
||||
}
|
||||
|
||||
class ConversationVolatileConfig(pointer: Long): ConfigBase(pointer) {
|
||||
companion object {
|
||||
init {
|
||||
System.loadLibrary("session_util")
|
||||
}
|
||||
external fun newInstance(ed25519SecretKey: ByteArray): ConversationVolatileConfig
|
||||
external fun newInstance(ed25519SecretKey: ByteArray, initialDump: ByteArray): ConversationVolatileConfig
|
||||
}
|
||||
|
||||
external fun getOneToOne(pubKeyHex: String): Conversation.OneToOne?
|
||||
external fun getOrConstructOneToOne(pubKeyHex: String): Conversation.OneToOne
|
||||
external fun eraseOneToOne(pubKeyHex: String): Boolean
|
||||
|
||||
external fun getCommunity(baseUrl: String, room: String): Conversation.Community?
|
||||
external fun getOrConstructCommunity(baseUrl: String, room: String, pubKeyHex: String): Conversation.Community
|
||||
external fun getOrConstructCommunity(baseUrl: String, room: String, pubKey: ByteArray): Conversation.Community
|
||||
external fun eraseCommunity(community: Conversation.Community): Boolean
|
||||
external fun eraseCommunity(baseUrl: String, room: String): Boolean
|
||||
|
||||
external fun getLegacyClosedGroup(groupId: String): Conversation.LegacyGroup?
|
||||
external fun getOrConstructLegacyGroup(groupId: String): Conversation.LegacyGroup
|
||||
external fun eraseLegacyClosedGroup(groupId: String): Boolean
|
||||
external fun erase(conversation: Conversation): Boolean
|
||||
|
||||
external fun set(toStore: Conversation)
|
||||
|
||||
/**
|
||||
* Erase all conversations that do not satisfy the `predicate`, similar to [MutableList.removeAll]
|
||||
*/
|
||||
external fun eraseAll(predicate: (Conversation) -> Boolean): Int
|
||||
|
||||
external fun sizeOneToOnes(): Int
|
||||
external fun sizeCommunities(): Int
|
||||
external fun sizeLegacyClosedGroups(): Int
|
||||
external fun size(): Int
|
||||
|
||||
external fun empty(): Boolean
|
||||
|
||||
external fun allOneToOnes(): List<Conversation.OneToOne>
|
||||
external fun allCommunities(): List<Conversation.Community>
|
||||
external fun allLegacyClosedGroups(): List<Conversation.LegacyGroup>
|
||||
external fun all(): List<Conversation>
|
||||
|
||||
}
|
||||
|
||||
class UserGroupsConfig(pointer: Long): ConfigBase(pointer) {
|
||||
companion object {
|
||||
init {
|
||||
System.loadLibrary("session_util")
|
||||
}
|
||||
external fun newInstance(ed25519SecretKey: ByteArray): UserGroupsConfig
|
||||
external fun newInstance(ed25519SecretKey: ByteArray, initialDump: ByteArray): UserGroupsConfig
|
||||
}
|
||||
|
||||
external fun getCommunityInfo(baseUrl: String, room: String): GroupInfo.CommunityGroupInfo?
|
||||
external fun getLegacyGroupInfo(sessionId: String): GroupInfo.LegacyGroupInfo?
|
||||
external fun getOrConstructCommunityInfo(baseUrl: String, room: String, pubKeyHex: String): GroupInfo.CommunityGroupInfo
|
||||
external fun getOrConstructLegacyGroupInfo(sessionId: String): GroupInfo.LegacyGroupInfo
|
||||
external fun set(groupInfo: GroupInfo)
|
||||
external fun erase(communityInfo: GroupInfo)
|
||||
external fun eraseCommunity(baseCommunityInfo: BaseCommunityInfo): Boolean
|
||||
external fun eraseCommunity(server: String, room: String): Boolean
|
||||
external fun eraseLegacyGroup(sessionId: String): Boolean
|
||||
external fun sizeCommunityInfo(): Int
|
||||
external fun sizeLegacyGroupInfo(): Int
|
||||
external fun size(): Int
|
||||
external fun all(): List<GroupInfo>
|
||||
external fun allCommunityInfo(): List<GroupInfo.CommunityGroupInfo>
|
||||
external fun allLegacyGroupInfo(): List<GroupInfo.LegacyGroupInfo>
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package network.loki.messenger.libsession_util.util
|
||||
|
||||
data class BaseCommunityInfo(val baseUrl: String, val room: String, val pubKeyHex: String) {
|
||||
companion object {
|
||||
init {
|
||||
System.loadLibrary("session_util")
|
||||
}
|
||||
external fun parseFullUrl(fullUrl: String): Triple<String, String, ByteArray>?
|
||||
}
|
||||
external fun fullUrl(): String
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package network.loki.messenger.libsession_util.util
|
||||
|
||||
data class Contact(
|
||||
val id: String,
|
||||
var name: String = "",
|
||||
var nickname: String = "",
|
||||
var approved: Boolean = false,
|
||||
var approvedMe: Boolean = false,
|
||||
var blocked: Boolean = false,
|
||||
var profilePicture: UserPic = UserPic.DEFAULT,
|
||||
var priority: Int = 0,
|
||||
var expiryMode: ExpiryMode,
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
package network.loki.messenger.libsession_util.util
|
||||
|
||||
sealed class Conversation {
|
||||
|
||||
abstract var lastRead: Long
|
||||
abstract var unread: Boolean
|
||||
|
||||
data class OneToOne(
|
||||
val sessionId: String,
|
||||
override var lastRead: Long,
|
||||
override var unread: Boolean
|
||||
): Conversation()
|
||||
|
||||
data class Community(
|
||||
val baseCommunityInfo: BaseCommunityInfo,
|
||||
override var lastRead: Long,
|
||||
override var unread: Boolean
|
||||
) : Conversation()
|
||||
|
||||
data class LegacyGroup(
|
||||
val groupId: String,
|
||||
override var lastRead: Long,
|
||||
override var unread: Boolean
|
||||
): Conversation()
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package network.loki.messenger.libsession_util.util
|
||||
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
sealed class ExpiryMode(val expirySeconds: Long) {
|
||||
object NONE: ExpiryMode(0)
|
||||
data class Legacy(private val seconds: Long = 0L): ExpiryMode(seconds)
|
||||
data class AfterSend(private val seconds: Long = 0L): ExpiryMode(seconds)
|
||||
data class AfterRead(private val seconds: Long = 0L): ExpiryMode(seconds)
|
||||
|
||||
val duration get() = expirySeconds.seconds
|
||||
|
||||
val expiryMillis get() = expirySeconds * 1000L
|
||||
|
||||
fun coerceSendToRead(coerce: Boolean = true) = if (coerce && this is AfterSend) AfterRead(expirySeconds) else this
|
||||
}
|
||||
|
||||
fun afterSend(seconds: Long) = seconds.takeIf { it > 0 }?.let(ExpiryMode::AfterSend) ?: ExpiryMode.NONE
|
||||
@@ -0,0 +1,53 @@
|
||||
package network.loki.messenger.libsession_util.util
|
||||
|
||||
sealed class GroupInfo {
|
||||
|
||||
data class CommunityGroupInfo(val community: BaseCommunityInfo, val priority: Int) : GroupInfo()
|
||||
|
||||
data class LegacyGroupInfo(
|
||||
val sessionId: String,
|
||||
val name: String,
|
||||
val members: Map<String, Boolean>,
|
||||
val encPubKey: ByteArray,
|
||||
val encSecKey: ByteArray,
|
||||
val priority: Int,
|
||||
val disappearingTimer: Long,
|
||||
val joinedAt: Long
|
||||
): GroupInfo() {
|
||||
companion object {
|
||||
@Suppress("FunctionName")
|
||||
external fun NAME_MAX_LENGTH(): Int
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as LegacyGroupInfo
|
||||
|
||||
if (sessionId != other.sessionId) return false
|
||||
if (name != other.name) return false
|
||||
if (members != other.members) return false
|
||||
if (!encPubKey.contentEquals(other.encPubKey)) return false
|
||||
if (!encSecKey.contentEquals(other.encSecKey)) return false
|
||||
if (priority != other.priority) return false
|
||||
if (disappearingTimer != other.disappearingTimer) return false
|
||||
if (joinedAt != other.joinedAt) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = sessionId.hashCode()
|
||||
result = 31 * result + name.hashCode()
|
||||
result = 31 * result + members.hashCode()
|
||||
result = 31 * result + encPubKey.contentHashCode()
|
||||
result = 31 * result + encSecKey.contentHashCode()
|
||||
result = 31 * result + priority
|
||||
result = 31 * result + disappearingTimer.hashCode()
|
||||
result = 31 * result + joinedAt.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package network.loki.messenger.libsession_util.util
|
||||
|
||||
object Sodium {
|
||||
init {
|
||||
System.loadLibrary("session_util")
|
||||
}
|
||||
external fun ed25519KeyPair(seed: ByteArray): KeyPair
|
||||
external fun ed25519PkToCurve25519(pk: ByteArray): ByteArray
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package network.loki.messenger.libsession_util.util
|
||||
|
||||
data class ConfigPush(val config: ByteArray, val seqNo: Long, val obsoleteHashes: List<String>) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as ConfigPush
|
||||
|
||||
if (!config.contentEquals(other.config)) return false
|
||||
if (seqNo != other.seqNo) return false
|
||||
if (obsoleteHashes != other.obsoleteHashes) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = config.contentHashCode()
|
||||
result = 31 * result + seqNo.hashCode()
|
||||
result = 31 * result + obsoleteHashes.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data class UserPic(val url: String, val key: ByteArray) {
|
||||
companion object {
|
||||
val DEFAULT = UserPic("", byteArrayOf())
|
||||
}
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as UserPic
|
||||
|
||||
if (url != other.url) return false
|
||||
if (!key.contentEquals(other.key)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = url.hashCode()
|
||||
result = 31 * result + key.contentHashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
data class KeyPair(val pubKey: ByteArray, val secretKey: ByteArray) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as KeyPair
|
||||
|
||||
if (!pubKey.contentEquals(other.pubKey)) return false
|
||||
if (!secretKey.contentEquals(other.secretKey)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = pubKey.contentHashCode()
|
||||
result = 31 * result + secretKey.contentHashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package network.loki.messenger.libsession_util
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user