-
-
Notifications
You must be signed in to change notification settings - Fork 6.1k
/
SignalServiceNetworkAccess.kt
317 lines (285 loc) · 14.8 KB
/
SignalServiceNetworkAccess.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
package org.thoughtcrime.securesms.push
import android.content.Context
import com.google.i18n.phonenumbers.PhoneNumberUtil
import okhttp3.CipherSuite
import okhttp3.ConnectionSpec
import okhttp3.Dns
import okhttp3.Interceptor
import okhttp3.TlsVersion
import org.signal.core.util.Base64
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.BuildConfig
import org.thoughtcrime.securesms.keyvalue.SettingsValues
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.net.CustomDns
import org.thoughtcrime.securesms.net.DeprecatedClientPreventionInterceptor
import org.thoughtcrime.securesms.net.DeviceTransferBlockingInterceptor
import org.thoughtcrime.securesms.net.RemoteDeprecationDetectorInterceptor
import org.thoughtcrime.securesms.net.SequentialDns
import org.thoughtcrime.securesms.net.StandardUserAgentInterceptor
import org.thoughtcrime.securesms.net.StaticDns
import org.whispersystems.signalservice.api.push.TrustStore
import org.whispersystems.signalservice.internal.configuration.SignalCdnUrl
import org.whispersystems.signalservice.internal.configuration.SignalCdsiUrl
import org.whispersystems.signalservice.internal.configuration.SignalKeyBackupServiceUrl
import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration
import org.whispersystems.signalservice.internal.configuration.SignalServiceUrl
import org.whispersystems.signalservice.internal.configuration.SignalStorageUrl
import org.whispersystems.signalservice.internal.configuration.SignalSvr2Url
import java.io.IOException
import java.util.Optional
/**
* Provides a [SignalServiceConfiguration] to be used with our service layer.
* If you're looking for a place to start, look at [getConfiguration].
*/
open class SignalServiceNetworkAccess(context: Context) {
companion object {
private val TAG = Log.tag(SignalServiceNetworkAccess::class.java)
@JvmField
val DNS: Dns = SequentialDns(
Dns.SYSTEM,
CustomDns("1.1.1.1"),
StaticDns(
mapOf(
BuildConfig.SIGNAL_URL.stripProtocol() to BuildConfig.SIGNAL_SERVICE_IPS.toSet(),
BuildConfig.STORAGE_URL.stripProtocol() to BuildConfig.SIGNAL_STORAGE_IPS.toSet(),
BuildConfig.SIGNAL_CDN_URL.stripProtocol() to BuildConfig.SIGNAL_CDN_IPS.toSet(),
BuildConfig.SIGNAL_CDN2_URL.stripProtocol() to BuildConfig.SIGNAL_CDN2_IPS.toSet(),
BuildConfig.SIGNAL_CDN3_URL.stripProtocol() to BuildConfig.SIGNAL_CDN3_IPS.toSet(),
BuildConfig.SIGNAL_SFU_URL.stripProtocol() to BuildConfig.SIGNAL_SFU_IPS.toSet(),
BuildConfig.CONTENT_PROXY_HOST.stripProtocol() to BuildConfig.SIGNAL_CONTENT_PROXY_IPS.toSet(),
BuildConfig.SIGNAL_CDSI_URL.stripProtocol() to BuildConfig.SIGNAL_CDSI_IPS.toSet(),
BuildConfig.SIGNAL_SVR2_URL.stripProtocol() to BuildConfig.SIGNAL_SVR2_IPS.toSet()
)
)
)
private fun String.stripProtocol(): String {
return this.removePrefix("https://")
}
private const val COUNTRY_CODE_EGYPT = 20
private const val COUNTRY_CODE_UAE = 971
private const val COUNTRY_CODE_OMAN = 968
private const val COUNTRY_CODE_QATAR = 974
private const val COUNTRY_CODE_IRAN = 98
private const val COUNTRY_CODE_CUBA = 53
private const val COUNTRY_CODE_UZBEKISTAN = 998
private const val G_HOST = "reflector-nrgwuv7kwq-uc.a.run.app"
private const val F_SERVICE_HOST = "chat-signal.global.ssl.fastly.net"
private const val F_STORAGE_HOST = "storage.signal.org.global.prod.fastly.net"
private const val F_CDN_HOST = "cdn.signal.org.global.prod.fastly.net"
private const val F_CDN2_HOST = "cdn2.signal.org.global.prod.fastly.net"
private const val F_CDN3_HOST = "cdn3-signal.global.ssl.fastly.net"
private const val F_CDSI_HOST = "cdsi-signal.global.ssl.fastly.net"
private const val F_SVR2_HOST = "svr2-signal.global.ssl.fastly.net"
private const val F_KBS_HOST = "api.backup.signal.org.global.prod.fastly.net"
private val GMAPS_CONNECTION_SPEC = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.cipherSuites(
CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA
)
.supportsTlsExtensions(true)
.build()
private val GMAIL_CONNECTION_SPEC = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.cipherSuites(
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA
)
.supportsTlsExtensions(true)
.build()
private val PLAY_CONNECTION_SPEC = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.cipherSuites(
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA
)
.supportsTlsExtensions(true)
.build()
private val APP_CONNECTION_SPEC = ConnectionSpec.MODERN_TLS
}
private val serviceTrustStore: TrustStore = SignalServiceTrustStore(context)
private val gTrustStore: TrustStore = DomainFrontingTrustStore(context)
private val fTrustStore: TrustStore = DomainFrontingDigicertTrustStore(context)
private val interceptors: List<Interceptor> = listOf(
StandardUserAgentInterceptor(),
RemoteDeprecationDetectorInterceptor(),
DeprecatedClientPreventionInterceptor(),
DeviceTransferBlockingInterceptor.getInstance()
)
private val zkGroupServerPublicParams: ByteArray = try {
Base64.decode(BuildConfig.ZKGROUP_SERVER_PUBLIC_PARAMS)
} catch (e: IOException) {
throw AssertionError(e)
}
private val genericServerPublicParams: ByteArray = try {
Base64.decode(BuildConfig.GENERIC_SERVER_PUBLIC_PARAMS)
} catch (e: IOException) {
throw AssertionError(e)
}
private val backupServerPublicParams: ByteArray = try {
Base64.decode(BuildConfig.BACKUP_SERVER_PUBLIC_PARAMS)
} catch (e: IOException) {
throw AssertionError(e)
}
private val baseGHostConfigs: List<HostConfig> = listOf(
HostConfig("https://www.google.com", G_HOST, GMAIL_CONNECTION_SPEC),
HostConfig("https://android.clients.google.com", G_HOST, PLAY_CONNECTION_SPEC),
HostConfig("https://clients3.google.com", G_HOST, GMAPS_CONNECTION_SPEC),
HostConfig("https://clients4.google.com", G_HOST, GMAPS_CONNECTION_SPEC),
HostConfig("https://inbox.google.com", G_HOST, GMAIL_CONNECTION_SPEC)
)
private val fUrls = arrayOf("https://github.githubassets.com", "https://pinterest.com", "https://www.redditstatic.com")
private val fConfig: SignalServiceConfiguration = SignalServiceConfiguration(
signalServiceUrls = fUrls.map { SignalServiceUrl(it, F_SERVICE_HOST, fTrustStore, APP_CONNECTION_SPEC) }.toTypedArray(),
signalCdnUrlMap = mapOf(
0 to fUrls.map { SignalCdnUrl(it, F_CDN_HOST, fTrustStore, APP_CONNECTION_SPEC) }.toTypedArray(),
2 to fUrls.map { SignalCdnUrl(it, F_CDN2_HOST, fTrustStore, APP_CONNECTION_SPEC) }.toTypedArray(),
3 to fUrls.map { SignalCdnUrl(it, F_CDN3_HOST, fTrustStore, APP_CONNECTION_SPEC) }.toTypedArray()
),
signalStorageUrls = fUrls.map { SignalStorageUrl(it, F_STORAGE_HOST, fTrustStore, APP_CONNECTION_SPEC) }.toTypedArray(),
signalCdsiUrls = fUrls.map { SignalCdsiUrl(it, F_CDSI_HOST, fTrustStore, APP_CONNECTION_SPEC) }.toTypedArray(),
signalSvr2Urls = fUrls.map { SignalSvr2Url(it, fTrustStore, F_SVR2_HOST, APP_CONNECTION_SPEC) }.toTypedArray(),
networkInterceptors = interceptors,
dns = Optional.of(DNS),
signalProxy = Optional.empty(),
zkGroupServerPublicParams = zkGroupServerPublicParams,
genericServerPublicParams = genericServerPublicParams,
backupServerPublicParams = backupServerPublicParams
)
private val censorshipConfiguration: Map<Int, SignalServiceConfiguration> = mapOf(
COUNTRY_CODE_EGYPT to buildGConfiguration(
listOf(HostConfig("https://www.google.com.eg", G_HOST, GMAIL_CONNECTION_SPEC)) + baseGHostConfigs
),
COUNTRY_CODE_UAE to buildGConfiguration(
listOf(HostConfig("https://www.google.ae", G_HOST, GMAIL_CONNECTION_SPEC)) + baseGHostConfigs
),
COUNTRY_CODE_OMAN to buildGConfiguration(
listOf(HostConfig("https://www.google.com.om", G_HOST, GMAIL_CONNECTION_SPEC)) + baseGHostConfigs
),
COUNTRY_CODE_QATAR to buildGConfiguration(
listOf(HostConfig("https://www.google.com.qa", G_HOST, GMAIL_CONNECTION_SPEC)) + baseGHostConfigs
),
COUNTRY_CODE_UZBEKISTAN to buildGConfiguration(
listOf(HostConfig("https://www.google.co.uz", G_HOST, GMAIL_CONNECTION_SPEC)) + baseGHostConfigs
),
COUNTRY_CODE_IRAN to fConfig,
COUNTRY_CODE_CUBA to fConfig
)
private val defaultCensoredConfiguration: SignalServiceConfiguration = buildGConfiguration(baseGHostConfigs)
private val defaultCensoredCountryCodes: Set<Int> = setOf(
COUNTRY_CODE_EGYPT,
COUNTRY_CODE_UAE,
COUNTRY_CODE_OMAN,
COUNTRY_CODE_QATAR,
COUNTRY_CODE_IRAN,
COUNTRY_CODE_CUBA,
COUNTRY_CODE_UZBEKISTAN
)
open val uncensoredConfiguration: SignalServiceConfiguration = SignalServiceConfiguration(
signalServiceUrls = arrayOf(SignalServiceUrl(BuildConfig.SIGNAL_URL, serviceTrustStore)),
signalCdnUrlMap = mapOf(
0 to arrayOf(SignalCdnUrl(BuildConfig.SIGNAL_CDN_URL, serviceTrustStore)),
2 to arrayOf(SignalCdnUrl(BuildConfig.SIGNAL_CDN2_URL, serviceTrustStore)),
3 to arrayOf(SignalCdnUrl(BuildConfig.SIGNAL_CDN3_URL, serviceTrustStore))
),
signalStorageUrls = arrayOf(SignalStorageUrl(BuildConfig.STORAGE_URL, serviceTrustStore)),
signalCdsiUrls = arrayOf(SignalCdsiUrl(BuildConfig.SIGNAL_CDSI_URL, serviceTrustStore)),
signalSvr2Urls = arrayOf(SignalSvr2Url(BuildConfig.SIGNAL_SVR2_URL, serviceTrustStore)),
networkInterceptors = interceptors,
dns = Optional.of(DNS),
signalProxy = if (SignalStore.proxy.isProxyEnabled) Optional.ofNullable(SignalStore.proxy.proxy) else Optional.empty(),
zkGroupServerPublicParams = zkGroupServerPublicParams,
genericServerPublicParams = genericServerPublicParams,
backupServerPublicParams = backupServerPublicParams
)
open fun getConfiguration(): SignalServiceConfiguration {
return getConfiguration(SignalStore.account.e164)
}
open fun getConfiguration(e164: String?): SignalServiceConfiguration {
if (e164 == null || SignalStore.proxy.isProxyEnabled) {
return uncensoredConfiguration
}
val countryCode: Int = PhoneNumberUtil.getInstance().parse(e164, null).countryCode
return when (SignalStore.settings.censorshipCircumventionEnabled) {
SettingsValues.CensorshipCircumventionEnabled.ENABLED -> {
censorshipConfiguration[countryCode] ?: defaultCensoredConfiguration
}
SettingsValues.CensorshipCircumventionEnabled.DISABLED -> {
uncensoredConfiguration
}
SettingsValues.CensorshipCircumventionEnabled.DEFAULT -> {
if (defaultCensoredCountryCodes.contains(countryCode)) {
censorshipConfiguration[countryCode] ?: defaultCensoredConfiguration
} else {
uncensoredConfiguration
}
}
}
}
fun isCensored(): Boolean {
return isCensored(SignalStore.account.e164)
}
fun isCensored(number: String?): Boolean {
return getConfiguration(number) != uncensoredConfiguration
}
fun isCountryCodeCensoredByDefault(countryCode: Int): Boolean {
return defaultCensoredCountryCodes.contains(countryCode)
}
private fun buildGConfiguration(
hostConfigs: List<HostConfig>
): SignalServiceConfiguration {
val serviceUrls: Array<SignalServiceUrl> = hostConfigs.map { SignalServiceUrl("${it.baseUrl}/service", it.host, gTrustStore, it.connectionSpec) }.toTypedArray()
val cdnUrls: Array<SignalCdnUrl> = hostConfigs.map { SignalCdnUrl("${it.baseUrl}/cdn", it.host, gTrustStore, it.connectionSpec) }.toTypedArray()
val cdn2Urls: Array<SignalCdnUrl> = hostConfigs.map { SignalCdnUrl("${it.baseUrl}/cdn2", it.host, gTrustStore, it.connectionSpec) }.toTypedArray()
val cdn3Urls: Array<SignalCdnUrl> = hostConfigs.map { SignalCdnUrl("${it.baseUrl}/cdn3", it.host, gTrustStore, it.connectionSpec) }.toTypedArray()
val kbsUrls: Array<SignalKeyBackupServiceUrl> = hostConfigs.map { SignalKeyBackupServiceUrl("${it.baseUrl}/backup", it.host, gTrustStore, it.connectionSpec) }.toTypedArray()
val storageUrls: Array<SignalStorageUrl> = hostConfigs.map { SignalStorageUrl("${it.baseUrl}/storage", it.host, gTrustStore, it.connectionSpec) }.toTypedArray()
val cdsiUrls: Array<SignalCdsiUrl> = hostConfigs.map { SignalCdsiUrl("${it.baseUrl}/cdsi", it.host, gTrustStore, it.connectionSpec) }.toTypedArray()
val svr2Urls: Array<SignalSvr2Url> = hostConfigs.map { SignalSvr2Url("${it.baseUrl}/svr2", gTrustStore, it.host, it.connectionSpec) }.toTypedArray()
return SignalServiceConfiguration(
signalServiceUrls = serviceUrls,
signalCdnUrlMap = mapOf(
0 to cdnUrls,
2 to cdn2Urls,
3 to cdn3Urls
),
signalStorageUrls = storageUrls,
signalCdsiUrls = cdsiUrls,
signalSvr2Urls = svr2Urls,
networkInterceptors = interceptors,
dns = Optional.of(DNS),
signalProxy = Optional.empty(),
zkGroupServerPublicParams = zkGroupServerPublicParams,
genericServerPublicParams = genericServerPublicParams,
backupServerPublicParams = backupServerPublicParams
)
}
private data class HostConfig(val baseUrl: String, val host: String, val connectionSpec: ConnectionSpec)
}