Skip to content

Commit 6354c0c

Browse files
[SES-4752] - Add alternative fileservers to debug menu (#1634)
1 parent d93041e commit 6354c0c

File tree

10 files changed

+138
-40
lines changed

10 files changed

+138
-40
lines changed

app/src/main/java/org/session/libsession/messaging/file_server/FileServer.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
package org.session.libsession.messaging.file_server
22

3+
import kotlinx.serialization.Serializable
34
import okhttp3.HttpUrl
45
import okhttp3.HttpUrl.Companion.toHttpUrl
6+
import org.session.libsession.utilities.serializable.HttpSerializer
57

8+
@Serializable
69
data class FileServer(
10+
@Serializable(with = HttpSerializer::class)
711
val url: HttpUrl,
812
val publicKeyHex: String
913
) {
1014
constructor(url: String, publicKeyHex: String) : this(url.toHttpUrl(), publicKeyHex)
11-
1215
}
1316

1417
val HttpUrl.isOfficial: Boolean

app/src/main/java/org/session/libsession/messaging/file_server/FileServerApi.kt

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,10 @@ class FileServerApi @Inject constructor(
3434
companion object {
3535
const val MAX_FILE_SIZE = 10_000_000 // 10 MB
3636

37-
val DEFAULT_FILE_SERVER: FileServer by lazy {
38-
FileServer(
39-
url = "http://filev2.getsession.org",
40-
publicKeyHex = "da21e1d886c6fbaea313f75298bd64aab03a97ce985b46bb2dad9f2089c8ee59"
41-
)
42-
}
37+
val DEFAULT_FILE_SERVER: FileServer = FileServer(
38+
url = "http://filev2.getsession.org",
39+
publicKeyHex = "da21e1d886c6fbaea313f75298bd64aab03a97ce985b46bb2dad9f2089c8ee59"
40+
)
4341
}
4442

4543
sealed class Error(message: String) : Exception(message) {
@@ -126,7 +124,7 @@ class FileServerApi @Inject constructor(
126124
suspend fun upload(
127125
file: ByteArray,
128126
usedDeterministicEncryption: Boolean,
129-
fileServer: FileServer = DEFAULT_FILE_SERVER,
127+
fileServer: FileServer,
130128
customExpiresDuration: Duration? = null
131129
): UploadResult {
132130
val request = Request(
@@ -194,7 +192,7 @@ class FileServerApi @Inject constructor(
194192
): HttpUrl {
195193
val urlFragment = sequenceOf(
196194
"d".takeIf { usesDeterministicEncryption },
197-
if (!fileServer.url.isOfficial) {
195+
if (!fileServer.url.isOfficial || fileServer.publicKeyHex != DEFAULT_FILE_SERVER.publicKeyHex) {
198196
"p=${fileServer.publicKeyHex}"
199197
} else {
200198
null

app/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ class AttachmentUploadJob @AssistedInject constructor(
8080
}
8181
handleSuccess(dispatcherName, attachment, keyAndResult.first, keyAndResult.second)
8282
} else {
83-
val fileServer = FileServerApi.DEFAULT_FILE_SERVER
83+
val fileServer = preferences.alternativeFileServer ?: FileServerApi.DEFAULT_FILE_SERVER
8484
val keyAndResult = upload(
8585
attachment = attachment,
8686
encrypt = true

app/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ import kotlinx.coroutines.flow.MutableStateFlow
1717
import kotlinx.coroutines.flow.StateFlow
1818
import kotlinx.coroutines.flow.asSharedFlow
1919
import kotlinx.coroutines.flow.update
20+
import kotlinx.serialization.json.Json
2021
import network.loki.messenger.BuildConfig
2122
import network.loki.messenger.R
2223
import org.session.libsession.messaging.MessagingModuleConfiguration
24+
import org.session.libsession.messaging.file_server.FileServer
2325
import org.session.libsession.utilities.TextSecurePreferences.Companion.AUTOPLAY_AUDIO_MESSAGES
2426
import org.session.libsession.utilities.TextSecurePreferences.Companion.CALL_NOTIFICATIONS_ENABLED
2527
import org.session.libsession.utilities.TextSecurePreferences.Companion.CLASSIC_DARK
@@ -228,6 +230,7 @@ interface TextSecurePreferences {
228230
var inAppReviewState: String?
229231
var forcesDeterministicAttachmentEncryption: Boolean
230232
var debugAvatarReupload: Boolean
233+
var alternativeFileServer: FileServer?
231234

232235

233236
companion object {
@@ -964,7 +967,8 @@ interface TextSecurePreferences {
964967

965968
@Singleton
966969
class AppTextSecurePreferences @Inject constructor(
967-
@ApplicationContext private val context: Context
970+
@param:ApplicationContext private val context: Context,
971+
private val json: Json,
968972
): TextSecurePreferences {
969973
private val localNumberState = MutableStateFlow(getStringPreference(TextSecurePreferences.LOCAL_NUMBER_PREF, null))
970974
private val postProLaunchState = MutableStateFlow(getBooleanPreference(SET_FORCE_POST_PRO, false))
@@ -1765,4 +1769,15 @@ class AppTextSecurePreferences @Inject constructor(
17651769
setBooleanPreference(TextSecurePreferences.DEBUG_AVATAR_REUPLOAD, value)
17661770
_events.tryEmit(TextSecurePreferences.DEBUG_AVATAR_REUPLOAD)
17671771
}
1772+
1773+
override var alternativeFileServer: FileServer?
1774+
get() = getStringPreference("alternative_file_server", null)?.let {
1775+
json.decodeFromString(it)
1776+
}
1777+
1778+
set(value) {
1779+
setStringPreference("alternative_file_server", value?.let {
1780+
json.encodeToString(it)
1781+
})
1782+
}
17681783
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.session.libsession.utilities.serializable
2+
3+
import kotlinx.serialization.KSerializer
4+
import kotlinx.serialization.descriptors.PrimitiveKind
5+
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
6+
import kotlinx.serialization.descriptors.SerialDescriptor
7+
import kotlinx.serialization.encoding.Decoder
8+
import kotlinx.serialization.encoding.Encoder
9+
import okhttp3.HttpUrl
10+
import okhttp3.HttpUrl.Companion.toHttpUrl
11+
12+
class HttpSerializer : KSerializer<HttpUrl> {
13+
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(
14+
serialName = HttpUrl::javaClass.name,
15+
kind = PrimitiveKind.STRING
16+
)
17+
18+
override fun serialize(
19+
encoder: Encoder,
20+
value: HttpUrl
21+
) {
22+
encoder.encodeString(value.toString())
23+
}
24+
25+
override fun deserialize(decoder: Decoder): HttpUrl {
26+
return decoder.decodeString().toHttpUrl()
27+
}
28+
}

app/src/main/java/org/thoughtcrime/securesms/attachments/AvatarUploadManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class AvatarUploadManager @Inject constructor(
104104

105105
val uploadResult = fileServerApi.upload(
106106
file = result.ciphertext,
107+
fileServer = prefs.alternativeFileServer ?: FileServerApi.DEFAULT_FILE_SERVER,
107108
usedDeterministicEncryption = usesDeterministicEncryption,
108109
customExpiresDuration = DEBUG_AVATAR_TTL.takeIf { prefs.forcedShortTTL() }
109110
)
@@ -154,7 +155,6 @@ class AvatarUploadManager @Inject constructor(
154155

155156
private const val PROFILE_KEY_LENGTH = 32
156157

157-
private val DEFAULT_AVATAR_TTL: Duration = 14.days
158158
private val DEBUG_AVATAR_TTL: Duration = 30.seconds
159159
}
160160
}

app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenu.kt

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,9 @@ fun DebugMenu(
243243
selected = null,
244244
modifier = modifier,
245245
values = uiState.debugProPlans,
246-
onValueSelected = { sendCommand(DebugMenuViewModel.Commands.PurchaseDebugPlan(it)) },
247-
labeler = { it?.label ?: "Select a plan to buy" }
246+
onValueSelected = { sendCommand(DebugMenuViewModel.Commands.PurchaseDebugPlan(it!!)) },
247+
labeler = { it?.label ?: "Select a plan to buy" },
248+
allowSelectingNullValue = false,
248249
)
249250

250251
Spacer(modifier = Modifier.height(LocalDimensions.current.xsSpacing))
@@ -351,15 +352,6 @@ fun DebugMenu(
351352
}
352353
)
353354

354-
Spacer(modifier = Modifier.height(LocalDimensions.current.xsSpacing))
355-
DebugSwitchRow(
356-
text = "Force 30sec TTL avatar",
357-
checked = uiState.forceShortTTl,
358-
onCheckedChange = {
359-
sendCommand(DebugMenuViewModel.Commands.ForceShortTTl(it))
360-
}
361-
)
362-
363355
Spacer(modifier = Modifier.height(LocalDimensions.current.xsSpacing))
364356
Row(
365357
verticalAlignment = Alignment.CenterVertically,
@@ -463,14 +455,38 @@ fun DebugMenu(
463455
}
464456
)
465457

458+
SlimOutlineButton(
459+
modifier = Modifier.fillMaxWidth(),
460+
text = "Clear All Trusted Downloads",
461+
) {
462+
sendCommand(ClearTrustedDownloads)
463+
}
464+
}
465+
466+
DebugCell("Fileserver, avatar & attachment") {
467+
Text("Alternative file server")
468+
469+
DropDown(
470+
modifier = Modifier.fillMaxWidth(),
471+
selected = uiState.alternativeFileServer,
472+
values = uiState.availableAltFileServers,
473+
onValueSelected = { sendCommand(DebugMenuViewModel.Commands.SelectAltFileServer(it)) },
474+
labeler = { it?.url?.host ?: "Do not use" },
475+
allowSelectingNullValue = true,
476+
)
477+
478+
Spacer(modifier = Modifier.height(LocalDimensions.current.xsSpacing))
479+
466480
DebugSwitchRow(
467-
text = "Force using deterministic attachment uploads",
468-
checked = uiState.forceDeterministicAttachment,
481+
text = "Uses deterministic encryption for both avatar and attachment uploads",
482+
checked = uiState.forceDeterministicEncryption,
469483
onCheckedChange = {
470-
sendCommand(DebugMenuViewModel.Commands.ToggleDeterministicAttachmentUpload)
484+
sendCommand(DebugMenuViewModel.Commands.ToggleDeterministicEncryption)
471485
}
472486
)
473487

488+
Spacer(modifier = Modifier.height(LocalDimensions.current.xsSpacing))
489+
474490
DebugSwitchRow(
475491
text = "Debug avatar reupload (shorten interval, and toast messages)",
476492
checked = uiState.debugAvatarReupload,
@@ -479,6 +495,15 @@ fun DebugMenu(
479495
}
480496
)
481497

498+
Spacer(modifier = Modifier.height(LocalDimensions.current.xsSpacing))
499+
DebugSwitchRow(
500+
text = "Force 30sec TTL avatar",
501+
checked = uiState.forceShortTTl,
502+
onCheckedChange = {
503+
sendCommand(DebugMenuViewModel.Commands.ForceShortTTl(it))
504+
}
505+
)
506+
482507
SlimOutlineButton(
483508
modifier = Modifier.fillMaxWidth(),
484509
text = "Reset Push Token",
@@ -774,7 +799,7 @@ fun PreviewDebugMenu() {
774799
debugSubscriptionStatuses = setOf(DebugMenuViewModel.DebugSubscriptionStatus.AUTO_GOOGLE),
775800
selectedDebugSubscriptionStatus = DebugMenuViewModel.DebugSubscriptionStatus.AUTO_GOOGLE,
776801
debugProPlans = emptyList(),
777-
forceDeterministicAttachment = false,
802+
forceDeterministicEncryption = false,
778803
debugAvatarReupload = true,
779804
),
780805
sendCommand = {},

app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenuViewModel.kt

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_HIDD
2222
import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_VISIBLE
2323
import network.loki.messenger.libsession_util.util.BlindKeyAPI
2424
import org.session.libsession.database.StorageProtocol
25+
import org.session.libsession.messaging.file_server.FileServer
2526
import org.session.libsession.messaging.file_server.FileServerApi
2627
import org.session.libsession.messaging.groups.LegacyGroupDeprecationManager
2728
import org.session.libsession.messaging.notifications.TokenFetcher
@@ -76,7 +77,7 @@ class DebugMenuViewModel @Inject constructor(
7677
hideMessageRequests = textSecurePreferences.hasHiddenMessageRequests(),
7778
hideNoteToSelf = configFactory.withUserConfigs { it.userProfile.getNtsPriority() == PRIORITY_HIDDEN },
7879
forceDeprecationState = deprecationManager.deprecationStateOverride.value,
79-
forceDeterministicAttachment = textSecurePreferences.forcesDeterministicAttachmentEncryption,
80+
forceDeterministicEncryption = textSecurePreferences.forcesDeterministicAttachmentEncryption,
8081
availableDeprecationState = listOf(null) + LegacyGroupDeprecationManager.DeprecationState.entries.toList(),
8182
deprecatedTime = deprecationManager.deprecatedTime.value,
8283
deprecatingStartTime = deprecationManager.deprecatingStartTime.value,
@@ -99,6 +100,8 @@ class DebugMenuViewModel @Inject constructor(
99100
debugProPlans = subscriptionManagers.asSequence()
100101
.flatMap { it.availablePlans.asSequence().map { plan -> DebugProPlan(it, plan) } }
101102
.toList(),
103+
availableAltFileServers = TEST_FILE_SERVERS,
104+
alternativeFileServer = textSecurePreferences.alternativeFileServer,
102105
)
103106
)
104107
val uiState: StateFlow<UIState>
@@ -309,9 +312,9 @@ class DebugMenuViewModel @Inject constructor(
309312
command.plan.apply { manager.purchasePlan(plan) }
310313
}
311314

312-
is Commands.ToggleDeterministicAttachmentUpload -> {
313-
val newValue = !_uiState.value.forceDeterministicAttachment
314-
_uiState.update { it.copy(forceDeterministicAttachment = newValue) }
315+
is Commands.ToggleDeterministicEncryption -> {
316+
val newValue = !_uiState.value.forceDeterministicEncryption
317+
_uiState.update { it.copy(forceDeterministicEncryption = newValue) }
315318
textSecurePreferences.forcesDeterministicAttachmentEncryption = newValue
316319
}
317320

@@ -326,6 +329,11 @@ class DebugMenuViewModel @Inject constructor(
326329
tokenFetcher.resetToken()
327330
}
328331
}
332+
333+
is Commands.SelectAltFileServer -> {
334+
_uiState.update { it.copy(alternativeFileServer = command.fileServer) }
335+
textSecurePreferences.alternativeFileServer = command.fileServer
336+
}
329337
}
330338
}
331339

@@ -418,7 +426,7 @@ class DebugMenuViewModel @Inject constructor(
418426
val showDeprecatedStateWarningDialog: Boolean,
419427
val hideMessageRequests: Boolean,
420428
val hideNoteToSelf: Boolean,
421-
val forceDeterministicAttachment: Boolean,
429+
val forceDeterministicEncryption: Boolean,
422430
val forceCurrentUserAsPro: Boolean,
423431
val forceOtherUsersAsPro: Boolean,
424432
val forceIncomingMessagesAsPro: Boolean,
@@ -434,6 +442,8 @@ class DebugMenuViewModel @Inject constructor(
434442
val debugSubscriptionStatuses: Set<DebugSubscriptionStatus>,
435443
val selectedDebugSubscriptionStatus: DebugSubscriptionStatus,
436444
val debugProPlans: List<DebugProPlan>,
445+
val alternativeFileServer: FileServer? = null,
446+
val availableAltFileServers: List<FileServer> = emptyList(),
437447
)
438448

439449
enum class DatabaseInspectorState {
@@ -475,8 +485,22 @@ class DebugMenuViewModel @Inject constructor(
475485
data object ToggleDatabaseInspector : Commands()
476486
data class SetDebugSubscriptionStatus(val status: DebugSubscriptionStatus) : Commands()
477487
data class PurchaseDebugPlan(val plan: DebugProPlan) : Commands()
478-
data object ToggleDeterministicAttachmentUpload : Commands()
488+
data object ToggleDeterministicEncryption : Commands()
479489
data object ToggleDebugAvatarReupload : Commands()
480490
data object ResetPushToken : Commands()
491+
data class SelectAltFileServer(val fileServer: FileServer?) : Commands()
492+
}
493+
494+
companion object {
495+
private val TEST_FILE_SERVERS: List<FileServer> = listOf(
496+
FileServer(
497+
url = "http://potatofiles.getsession.org",
498+
publicKeyHex = "fc097b06821c98a2db75ce02e521cef5fd9d3446e42e81d843c4c8c4e9260f48",
499+
),
500+
FileServer(
501+
url = "http://superduperfiles.oxen.io",
502+
publicKeyHex = "16d6c60aebb0851de7e6f4dc0a4734671dbf80f73664c008596511454cb6576d",
503+
)
504+
)
481505
}
482506
}

app/src/main/java/org/thoughtcrime/securesms/recoverypassword/RecoveryPasswordViewModel.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,17 @@ import kotlinx.coroutines.flow.filterNotNull
1515
import kotlinx.coroutines.flow.map
1616
import kotlinx.coroutines.flow.stateIn
1717
import kotlinx.coroutines.launch
18-
import org.session.libsession.utilities.AppTextSecurePreferences
18+
import org.session.libsession.utilities.TextSecurePreferences
1919
import org.session.libsignal.crypto.MnemonicCodec
2020
import org.session.libsignal.utilities.hexEncodedPrivateKey
2121
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
2222
import org.thoughtcrime.securesms.crypto.MnemonicUtilities
2323

2424
@HiltViewModel
2525
class RecoveryPasswordViewModel @Inject constructor(
26-
private val application: Application
26+
private val application: Application,
27+
private val prefs: TextSecurePreferences,
2728
): AndroidViewModel(application) {
28-
val prefs = AppTextSecurePreferences(application)
2929

3030
val seed = MutableStateFlow<String?>(null)
3131
val mnemonic = seed.filterNotNull()

0 commit comments

Comments
 (0)