Skip to content

Commit c341412

Browse files
committed
Apollo: Release source code for 53.3
1 parent dd2799d commit c341412

File tree

6 files changed

+249
-5
lines changed

6 files changed

+249
-5
lines changed

android/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ follow [https://changelog.md/](https://changelog.md/) guidelines.
66

77
## [Unreleased]
88

9+
## [53.3] - 2025-04-08
10+
11+
### FIXED
12+
13+
- Proper fix for non ascii chars in http headers
14+
915
## [53.2] - 2025-03-24
1016

1117
### ADDED

android/apollo/src/main/java/io/muun/apollo/data/Extensions.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,9 @@ fun MuunZonedDateTime?.toApolloModel(): ZonedDateTime? {
1616
(this as ApolloZonedDateTime).dateTime
1717
}
1818
}
19+
20+
fun String.toSafeAscii() =
21+
this.map { if (it.code > 127) "$UNICODE_PREFIX${it.code.toString(16).padStart(4, '0')}" else it }
22+
.joinToString("")
23+
24+
private const val UNICODE_PREFIX = "\\u"

android/apollo/src/main/java/io/muun/apollo/data/net/base/interceptor/BackgroundExecutionMetricsInterceptor.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package io.muun.apollo.data.net.base.interceptor
22

33
import io.muun.apollo.data.net.base.BaseInterceptor
44
import io.muun.apollo.data.os.BackgroundExecutionMetricsProvider
5+
import io.muun.apollo.data.toSafeAscii
56
import io.muun.apollo.domain.errors.data.MuunSerializationError
67
import io.muun.apollo.domain.model.user.User
78
import io.muun.apollo.domain.selector.UserSelector
@@ -40,7 +41,7 @@ class BackgroundExecutionMetricsInterceptor @Inject constructor(
4041

4142
private fun safelyEncodeJson(originalRequest: Request): String? {
4243
return try {
43-
Json.encodeToString(bemProvider.run())
44+
Json.encodeToString(bemProvider.run()).toSafeAscii()
4445
} catch (e: Throwable) {
4546
logError(originalRequest, e)
4647
null

android/apollo/src/main/java/io/muun/apollo/domain/action/session/IsRootedDeviceAction.kt

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,42 @@ package io.muun.apollo.domain.action.session
22

33
import android.content.Context
44
import com.scottyab.rootbeer.RootBeer
5+
import io.muun.apollo.data.os.TorHelper
56
import io.muun.apollo.domain.action.base.BaseAsyncAction0
67
import rx.Observable
8+
import timber.log.Timber
79
import javax.inject.Inject
810

911
class IsRootedDeviceAction @Inject constructor(
10-
private val context: Context
12+
private val context: Context,
1113
) : BaseAsyncAction0<Boolean>() {
1214

15+
companion object {
16+
val dangerousBinaries = arrayOf(
17+
TorHelper.process("ncngpu"),
18+
TorHelper.process("xrearyfh"),
19+
TorHelper.process("zntvfxvavg"),
20+
TorHelper.process("fhcrefh")
21+
)
22+
}
23+
1324
override fun action(): Observable<Boolean> {
1425
return Observable.defer {
15-
Observable.just(RootBeer(context).isRooted)
26+
27+
try {
28+
if (RootBeer(context).isRooted) {
29+
return@defer Observable.just(true)
30+
}
31+
32+
val hasDangerousNewBinary = dangerousBinaries.any {
33+
RootBeer(context).checkForBinary(it)
34+
}
35+
Observable.just(hasDangerousNewBinary)
36+
} catch (e: Exception) {
37+
// Catching exceptions to prevent potential issues with root checks
38+
Timber.e(e, "Root detection failed")
39+
Observable.just(false)
40+
}
1641
}
1742
}
1843
}
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
package io.muun.apollo.data.os
2+
3+
import io.muun.apollo.data.toSafeAscii
4+
import org.junit.Assert
5+
import org.junit.Test
6+
7+
class ExtensionsTest {
8+
9+
private val languages = arrayListOf(
10+
"ascii: Hello word!!",
11+
"japanese: ドメイン名例",
12+
"japaneseWithAscii: MajiでKoiする5秒前",
13+
"already encoded japanese: \u30c9\u30e1\u30a4\u30f3\u540d\u4f8b",
14+
"korean: 도메인",
15+
"thai: ยจฆฟคฏข",
16+
"russian: правда",
17+
"emoji: 😉",
18+
"non encoded: \\\\ud83d9",
19+
"non-ascii mixup: 「 Б ü æ α 例 αβγ 」",
20+
).joinToString("\n")
21+
22+
private val expectedEncodedLanguages = "ascii: Hello word!!\n" +
23+
"japanese: \\u30c9\\u30e1\\u30a4\\u30f3\\u540d\\u4f8b\n" +
24+
"japaneseWithAscii: Maji\\u3067Koi\\u3059\\u308b5\\u79d2\\u524d\n" +
25+
"already encoded japanese: \\u30c9\\u30e1\\u30a4\\u30f3\\u540d\\u4f8b\n" +
26+
"korean: \\ub3c4\\uba54\\uc778\n" +
27+
"thai: \\u0e22\\u0e08\\u0e06\\u0e1f\\u0e04\\u0e0f\\u0e02\n" +
28+
"russian: \\u043f\\u0440\\u0430\\u0432\\u0434\\u0430\n" +
29+
"emoji: \\ud83d\\ude09\n" +
30+
"non encoded: \\\\ud83d9\n" +
31+
"non-ascii mixup: \\u300c \\u0411 \\u00fc \\u00e6 \\u03b1 \\u4f8b \\u03b1\\u03b2\\u03b3 \\u300d"
32+
33+
private val actualResponse = "{\n" +
34+
" \"epochInMilliseconds\": 1734567549279,\n" +
35+
" \"batteryLevel\": 92,\n" +
36+
" \"maxBatteryLevel\": 100,\n" +
37+
" \"batteryHealth\": \"GOOD\",\n" +
38+
" \"batteryDischargePrediction\": -1,\n" +
39+
" \"batteryState\": \"UNPLUGGED\",\n" +
40+
" \"totalInternalStorage\": 3087986688,\n" +
41+
" \"freeInternalStorage\": 866512896,\n" +
42+
" \"freeExternalStorage\": [\n" +
43+
" 530092032,\n" +
44+
" 75595776\n" +
45+
" ],\n" +
46+
" \"totalExternalStorage\": [\n" +
47+
" 18224549888,\n" +
48+
" 2438987776\n" +
49+
" ],\n" +
50+
" \"totalRamStorage\": 1922134016,\n" +
51+
" \"freeRamStorage\": 519774208,\n" +
52+
" \"dataState\": \"DATA_DISCONNECTED\",\n" +
53+
" \"simStates\": [\n" +
54+
" \"SIM_STATE_READY\",\n" +
55+
" \"SIM_STATE_READY\"\n" +
56+
" ],\n" +
57+
" \"networkTransport\": \"WIFI\",\n" +
58+
" \"androidUptimeMillis\": 450455711,\n" +
59+
" \"androidElapsedRealtimeMillis\": 787550180,\n" +
60+
" \"androidBootCount\": 980,\n" +
61+
" \"language\": \"es_ES\",\n" +
62+
" \"timeZoneOffsetInSeconds\": -14400,\n" +
63+
" \"telephonyNetworkRegion\": \"VE\",\n" +
64+
" \"simRegion\": \"ve\",\n" +
65+
" \"appDataDir\": \"/data/user/0/io.muun.apollo\",\n" +
66+
" \"vpnState\": 0,\n" +
67+
" \"appImportance\": 230,\n" +
68+
" \"displayMetrics\": {\n" +
69+
" \"density\": 1.75,\n" +
70+
" \"densityDpi\": 280,\n" +
71+
" \"widthPixels\": 720,\n" +
72+
" \"heightPixels\": 1422,\n" +
73+
" \"xdpi\": 281.353,\n" +
74+
" \"ydpi\": 283.028\n" +
75+
" },\n" +
76+
" \"usbConnected\": 0,\n" +
77+
" \"usbPersistConfig\": \"mtp\",\n" +
78+
" \"bridgeEnabled\": 0,\n" +
79+
" \"bridgeDaemonStatus\": \"stopped\",\n" +
80+
" \"developerEnabled\": 1,\n" +
81+
" \"proxyHttp\": \"\",\n" +
82+
" \"proxyHttps\": \"\",\n" +
83+
" \"proxySocks\": \"\",\n" +
84+
" \"autoDateTime\": 1,\n" +
85+
" \"autoTimeZone\": 1,\n" +
86+
" \"timeZoneId\": \"America/Caracas\",\n" +
87+
" \"androidDateFormat\": \"d/M/yy\",\n" +
88+
" \"regionCode\": \"ES\",\n" +
89+
" \"androidCalendarIdentifier\": \"gregory\",\n" +
90+
" \"androidMobileRxTraffic\": 0,\n" +
91+
" \"androidSimOperatorId\": \"73404\",\n" +
92+
" \"androidSimOperatorName\": \"Corporación Digitel\",\n" +
93+
" \"androidMobileOperatorId\": \"73402\",\n" +
94+
" \"mobileOperatorName\": \"DIGITEL\",\n" +
95+
" \"androidMobileRoaming\": false,\n" +
96+
" \"androidMobileDataStatus\": 0,\n" +
97+
" \"androidMobileRadioType\": 1,\n" +
98+
" \"androidMobileDataActivity\": 2,\n" +
99+
" \"androidNetworkLink\": {\n" +
100+
" \"interfaceName\": \"wlan0\",\n" +
101+
" \"routesSize\": 3,\n" +
102+
" \"routesInterfaces\": [\n" +
103+
" \"wlan0\"\n" +
104+
" ],\n" +
105+
" \"hasGatewayRoute\": 1,\n" +
106+
" \"dnsAddresses\": [\n" +
107+
" \"192.168.0.1\"\n" +
108+
" ],\n" +
109+
" \"linkHttpProxyHost\": \"\"\n" +
110+
" }\n" +
111+
"}"
112+
113+
private val expectedEncodedResponse = "{\n" +
114+
" \"epochInMilliseconds\": 1734567549279,\n" +
115+
" \"batteryLevel\": 92,\n" +
116+
" \"maxBatteryLevel\": 100,\n" +
117+
" \"batteryHealth\": \"GOOD\",\n" +
118+
" \"batteryDischargePrediction\": -1,\n" +
119+
" \"batteryState\": \"UNPLUGGED\",\n" +
120+
" \"totalInternalStorage\": 3087986688,\n" +
121+
" \"freeInternalStorage\": 866512896,\n" +
122+
" \"freeExternalStorage\": [\n" +
123+
" 530092032,\n" +
124+
" 75595776\n" +
125+
" ],\n" +
126+
" \"totalExternalStorage\": [\n" +
127+
" 18224549888,\n" +
128+
" 2438987776\n" +
129+
" ],\n" +
130+
" \"totalRamStorage\": 1922134016,\n" +
131+
" \"freeRamStorage\": 519774208,\n" +
132+
" \"dataState\": \"DATA_DISCONNECTED\",\n" +
133+
" \"simStates\": [\n" +
134+
" \"SIM_STATE_READY\",\n" +
135+
" \"SIM_STATE_READY\"\n" +
136+
" ],\n" +
137+
" \"networkTransport\": \"WIFI\",\n" +
138+
" \"androidUptimeMillis\": 450455711,\n" +
139+
" \"androidElapsedRealtimeMillis\": 787550180,\n" +
140+
" \"androidBootCount\": 980,\n" +
141+
" \"language\": \"es_ES\",\n" +
142+
" \"timeZoneOffsetInSeconds\": -14400,\n" +
143+
" \"telephonyNetworkRegion\": \"VE\",\n" +
144+
" \"simRegion\": \"ve\",\n" +
145+
" \"appDataDir\": \"/data/user/0/io.muun.apollo\",\n" +
146+
" \"vpnState\": 0,\n" +
147+
" \"appImportance\": 230,\n" +
148+
" \"displayMetrics\": {\n" +
149+
" \"density\": 1.75,\n" +
150+
" \"densityDpi\": 280,\n" +
151+
" \"widthPixels\": 720,\n" +
152+
" \"heightPixels\": 1422,\n" +
153+
" \"xdpi\": 281.353,\n" +
154+
" \"ydpi\": 283.028\n" +
155+
" },\n" +
156+
" \"usbConnected\": 0,\n" +
157+
" \"usbPersistConfig\": \"mtp\",\n" +
158+
" \"bridgeEnabled\": 0,\n" +
159+
" \"bridgeDaemonStatus\": \"stopped\",\n" +
160+
" \"developerEnabled\": 1,\n" +
161+
" \"proxyHttp\": \"\",\n" +
162+
" \"proxyHttps\": \"\",\n" +
163+
" \"proxySocks\": \"\",\n" +
164+
" \"autoDateTime\": 1,\n" +
165+
" \"autoTimeZone\": 1,\n" +
166+
" \"timeZoneId\": \"America/Caracas\",\n" +
167+
" \"androidDateFormat\": \"d/M/yy\",\n" +
168+
" \"regionCode\": \"ES\",\n" +
169+
" \"androidCalendarIdentifier\": \"gregory\",\n" +
170+
" \"androidMobileRxTraffic\": 0,\n" +
171+
" \"androidSimOperatorId\": \"73404\",\n" +
172+
" \"androidSimOperatorName\": \"Corporaci\\u00f3n Digitel\",\n" +
173+
" \"androidMobileOperatorId\": \"73402\",\n" +
174+
" \"mobileOperatorName\": \"DIGITEL\",\n" +
175+
" \"androidMobileRoaming\": false,\n" +
176+
" \"androidMobileDataStatus\": 0,\n" +
177+
" \"androidMobileRadioType\": 1,\n" +
178+
" \"androidMobileDataActivity\": 2,\n" +
179+
" \"androidNetworkLink\": {\n" +
180+
" \"interfaceName\": \"wlan0\",\n" +
181+
" \"routesSize\": 3,\n" +
182+
" \"routesInterfaces\": [\n" +
183+
" \"wlan0\"\n" +
184+
" ],\n" +
185+
" \"hasGatewayRoute\": 1,\n" +
186+
" \"dnsAddresses\": [\n" +
187+
" \"192.168.0.1\"\n" +
188+
" ],\n" +
189+
" \"linkHttpProxyHost\": \"\"\n" +
190+
" }\n" +
191+
"}"
192+
193+
@Test
194+
fun toSafeAsciiExtensionTest() {
195+
val encodedLanguages = languages.toSafeAscii()
196+
197+
Assert.assertEquals(encodedLanguages, expectedEncodedLanguages)
198+
}
199+
200+
@Test
201+
fun realResponseToSafeAsciiExtensionTest() {
202+
val encodedResponse = actualResponse.toSafeAscii()
203+
204+
Assert.assertEquals(encodedResponse, expectedEncodedResponse)
205+
}
206+
}

android/apolloui/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ android {
9696
applicationId "io.muun.apollo"
9797
minSdk 19
9898
targetSdk 34
99-
versionCode 1302
100-
versionName "53.2"
99+
versionCode 1303
100+
versionName "53.3"
101101

102102
// Needed to make sure these classes are available in the main DEX file for API 19
103103
// See: https://spin.atomicobject.com/2018/07/16/support-kitkat-multidex/

0 commit comments

Comments
 (0)