mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-17 08:25:46 +00:00
Compare commits
268 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16b71aa0a8 | ||
|
|
437ffba4b1 | ||
|
|
2be8a9bf12 | ||
|
|
833fcd10ab | ||
|
|
40ca2575da | ||
|
|
68234959c4 | ||
|
|
338caf7da9 | ||
|
|
d3fb7b3c06 | ||
|
|
693deda18f | ||
|
|
686be81226 | ||
|
|
e62528d3e2 | ||
|
|
2d8de5291e | ||
|
|
4011208db3 | ||
|
|
4ad9d6b5cc | ||
|
|
417a4b86b6 | ||
|
|
41cad291f9 | ||
|
|
356d9949b7 | ||
|
|
a21e38e334 | ||
|
|
8332342d75 | ||
|
|
cdd7a1042a | ||
|
|
72f3f79016 | ||
|
|
ab82ff0b69 | ||
|
|
b354825150 | ||
|
|
a585bce38e | ||
|
|
b37c81ddf1 | ||
|
|
37c4079098 | ||
|
|
0c79b09a10 | ||
|
|
8f002bd68d | ||
|
|
3fe676a3dd | ||
|
|
26c4d746d2 | ||
|
|
d0008b57b5 | ||
|
|
08cf364ee6 | ||
|
|
b3707021b1 | ||
|
|
7b3bd2fbf7 | ||
|
|
a330f6f689 | ||
|
|
d8521637bb | ||
|
|
424a463b21 | ||
|
|
790c6980fe | ||
|
|
27a5b7dd5c | ||
|
|
95a94eeebf | ||
|
|
bcd9aa84d6 | ||
|
|
c6a4877391 | ||
|
|
a413346610 | ||
|
|
f42d100f15 | ||
|
|
9ba19df2af | ||
|
|
dbc28746c0 | ||
|
|
28232fc2a5 | ||
|
|
efcdb7eb66 | ||
|
|
8550b4b051 | ||
|
|
7ba75c3291 | ||
|
|
55ba57d056 | ||
|
|
8de695585d | ||
|
|
7724964a36 | ||
|
|
64fc83326f | ||
|
|
c1af7557b5 | ||
|
|
262c1e47ad | ||
|
|
3e29bf4e54 | ||
|
|
6d2b87d385 | ||
|
|
a28408b29f | ||
|
|
4a9028aedd | ||
|
|
7aaedf500f | ||
|
|
cb84cc39ce | ||
|
|
1c90b59bb8 | ||
|
|
b9541a65b0 | ||
|
|
77e846d24e | ||
|
|
568c69c9be | ||
|
|
ffe35bef93 | ||
|
|
9b9363f18a | ||
|
|
58664fcddb | ||
|
|
857135aab1 | ||
|
|
1cc581aed8 | ||
|
|
f5724795cf | ||
|
|
e4e24f7ae5 | ||
|
|
1f9a0fab3c | ||
|
|
b692d48b98 | ||
|
|
01020c1c09 | ||
|
|
39e0639b4b | ||
|
|
86253f3772 | ||
|
|
efb4f388a5 | ||
|
|
b77afa8903 | ||
|
|
794197c068 | ||
|
|
34fa05cccc | ||
|
|
1a5bd37849 | ||
|
|
da03b38c84 | ||
|
|
1d71a32b41 | ||
|
|
0efdada928 | ||
|
|
0c7dba6d43 | ||
|
|
c50658a4f5 | ||
|
|
afd6ab75f8 | ||
|
|
597f7bbafd | ||
|
|
87760a795d | ||
|
|
f4fe024e50 | ||
|
|
797b296f3a | ||
|
|
b8a231c40f | ||
|
|
5cb94f02b3 | ||
|
|
db7a657001 | ||
|
|
ca2c8b961e | ||
|
|
4e4538f4e8 | ||
|
|
796c5de5d5 | ||
|
|
beceee846a | ||
|
|
8573316fdf | ||
|
|
6c59eb052e | ||
|
|
0ff99258ac | ||
|
|
141ee6565d | ||
|
|
38fa4e91fa | ||
|
|
2f20bb89f3 | ||
|
|
c04b675a1a | ||
|
|
e70298e624 | ||
|
|
6181dc4037 | ||
|
|
9b0cae1d45 | ||
|
|
491440094b | ||
|
|
e6b2d31db7 | ||
|
|
0ca8a480c5 | ||
|
|
349faf18fa | ||
|
|
88ed8f3887 | ||
|
|
6a6f900b7d | ||
|
|
17383ddfe0 | ||
|
|
1b846c0842 | ||
|
|
dbda758841 | ||
|
|
c6b3bb9f13 | ||
|
|
bdeeea2e46 | ||
|
|
427c9a6b21 | ||
|
|
dfda2f733c | ||
|
|
6f600a80b8 | ||
|
|
62181a3d7f | ||
|
|
6c386d3fc9 | ||
|
|
b9e6cff20c | ||
|
|
d65a7f1a25 | ||
|
|
76d0f45b9b | ||
|
|
3a19ac432b | ||
|
|
6ec9ee89a7 | ||
|
|
472179b550 | ||
|
|
f38bd7b187 | ||
|
|
b73143d7a7 | ||
|
|
9a2c372c23 | ||
|
|
b21369b7bc | ||
|
|
5939a1f995 | ||
|
|
e4b73e90e1 | ||
|
|
073d019103 | ||
|
|
761ccf4b3f | ||
|
|
7a023b9fdc | ||
|
|
9f804047f5 | ||
|
|
a625727853 | ||
|
|
e0737451db | ||
|
|
0f572d1e5d | ||
|
|
142f84703b | ||
|
|
b47bd97e9e | ||
|
|
4099303d1f | ||
|
|
71eeb7ca83 | ||
|
|
186a5e4dfc | ||
|
|
0d84ec51a8 | ||
|
|
6c9ed77e5f | ||
|
|
fc3aaed8a8 | ||
|
|
c72cc1b49c | ||
|
|
13227b6aa5 | ||
|
|
cc65fab226 | ||
|
|
dee2e0906e | ||
|
|
e142cb6d26 | ||
|
|
4185006147 | ||
|
|
a4e18c515c | ||
|
|
2011391e65 | ||
|
|
96896bf8f1 | ||
|
|
ac312ff5d5 | ||
|
|
b3552ee347 | ||
|
|
b998c5f86c | ||
|
|
0b8430ff43 | ||
|
|
3e80032c18 | ||
|
|
41fadc3437 | ||
|
|
c1fe585ffb | ||
|
|
078df0f029 | ||
|
|
9f9293cd61 | ||
|
|
4e87513867 | ||
|
|
c05aca19ae | ||
|
|
db2c7fabe1 | ||
|
|
e7eb0ec2b3 | ||
|
|
da75268545 | ||
|
|
49ab1e7bd5 | ||
|
|
b5a2d7882a | ||
|
|
534df06794 | ||
|
|
e31ddf0599 | ||
|
|
ce22e54359 | ||
|
|
7ce7ec56eb | ||
|
|
2b39728ea0 | ||
|
|
2af5c7f02e | ||
|
|
d6e0199e05 | ||
|
|
301ed0b255 | ||
|
|
ac5306be5b | ||
|
|
9de62d0286 | ||
|
|
067b14d551 | ||
|
|
03110c9870 | ||
|
|
a2b5bf54c8 | ||
|
|
5602a3dfc0 | ||
|
|
ed5b3f8679 | ||
|
|
7bf7acb1ff | ||
|
|
ffa5dc549b | ||
|
|
a59feb7ad4 | ||
|
|
753a1c7219 | ||
|
|
004f050741 | ||
|
|
fcde642563 | ||
|
|
ac0a1c0bc1 | ||
|
|
3f93731300 | ||
|
|
00d7b5c284 | ||
|
|
4397b55ceb | ||
|
|
b87abcc2c1 | ||
|
|
79dbf2746f | ||
|
|
a4bd9fae9a | ||
|
|
d4493e700e | ||
|
|
83d65228e9 | ||
|
|
8a2caeef3d | ||
|
|
6280ef4ab8 | ||
|
|
899afa2092 | ||
|
|
7c6b965969 | ||
|
|
5fac189736 | ||
|
|
d3271f548c | ||
|
|
023195dd4b | ||
|
|
299dd86c77 | ||
|
|
f818cfa32b | ||
|
|
fc21d2038f | ||
|
|
8277e4e102 | ||
|
|
242dbef54e | ||
|
|
9ffd84ce05 | ||
|
|
cb37ce0f5f | ||
|
|
7ab739b22b | ||
|
|
224b06f05a | ||
|
|
d36d33f837 | ||
|
|
724dced820 | ||
|
|
b8ca0e57ad | ||
|
|
fe5fc411a7 | ||
|
|
20d43bbfcb | ||
|
|
442f56cdc3 | ||
|
|
35dabaf1e5 | ||
|
|
1aec794a34 | ||
|
|
5bd8d6c69d | ||
|
|
aa26785c00 | ||
|
|
f450b37cfd | ||
|
|
b88e470594 | ||
|
|
f38677794a | ||
|
|
ac4db41435 | ||
|
|
3a9d521ffe | ||
|
|
b1bf33b13b | ||
|
|
352418d2d7 | ||
|
|
fb523985ed | ||
|
|
7ffe6f053c | ||
|
|
ea77191b70 | ||
|
|
e0b882d4d2 | ||
|
|
10a74d6d08 | ||
|
|
f092e85b62 | ||
|
|
8aa0f15740 | ||
|
|
18d4d4de24 | ||
|
|
b3c42dee7e | ||
|
|
5836f35291 | ||
|
|
dbd8a4083c | ||
|
|
0fd52ad1fe | ||
|
|
8031c788d9 | ||
|
|
10a29db93d | ||
|
|
8f3f2e6921 | ||
|
|
65c262acef | ||
|
|
d586893402 | ||
|
|
ba62e018db | ||
|
|
57c17e705f | ||
|
|
2e253fb6a8 | ||
|
|
0c32001fe4 | ||
|
|
48f6c2c526 | ||
|
|
39fd1e8f46 | ||
|
|
810abe0275 | ||
|
|
62816ee51a | ||
|
|
a0599c1639 | ||
|
|
8a4a1b385d |
@@ -1,6 +1,6 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
lang_map = fr_CA:fr-rCA,pt_BR:pt-rBR,pt_PT:pt,zh_CN:zh-rCN,zh_HK:zh-rHK,zh_TW:zh-rTW,da_DK:da-rDK,de_DE:de,tr_TR:tr,fr_FR:fr,es_ES:es,hu_HU:hu,sv_SE:sv-rSE,bg_BG:bg,el_GR:el,kn_IN:kn-rIN,cs_CZ:cs,sr:sr
|
||||
lang_map = fr_CA:fr-rCA,pt_BR:pt-rBR,pt_PT:pt,zh_CN:zh-rCN,zh_HK:zh-rHK,zh_TW:zh-rTW,da_DK:da-rDK,de_DE:de,tr_TR:tr,fr_FR:fr,es_ES:es,hu_HU:hu,sv_SE:sv-rSE,bg_BG:bg,el_GR:el,kn_IN:kn-rIN,cs_CZ:cs,sr:sr,he:iw,id:in
|
||||
|
||||
|
||||
[textsecure-official.master]
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="org.thoughtcrime.securesms"
|
||||
android:versionCode="90"
|
||||
android:versionName="2.4.2">
|
||||
android:versionCode="117"
|
||||
android:versionName="2.14.3">
|
||||
|
||||
<uses-sdk tools:overrideLibrary="com.amulyakhare.textdrawable"/>
|
||||
|
||||
<permission android:name="org.thoughtcrime.securesms.ACCESS_SECRETS"
|
||||
android:label="Access to TextSecure Secrets"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<uses-permission android:name="org.thoughtcrime.securesms.ACCESS_SECRETS"/>
|
||||
<uses-permission android:name="org.thoughtcrime.securesms.ACCESS_SECRETS"/>
|
||||
<uses-permission android:name="android.permission.READ_PROFILE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_PROFILE"/>
|
||||
<uses-permission android:name="android.permission.BROADCAST_WAP_PUSH"
|
||||
@@ -42,41 +44,14 @@
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/TextSecure.LightTheme">
|
||||
|
||||
<meta-data android:name="com.google.android.gms.version"
|
||||
android:value="@integer/google_play_services_version" />
|
||||
<meta-data android:name="com.google.android.gms.version"
|
||||
android:value="@integer/google_play_services_version" />
|
||||
|
||||
<activity android:name=".RoutingActivity"
|
||||
android:theme="@style/NoAnimation.Theme.BlackScreen"
|
||||
android:launchMode="singleTask"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SENDTO"/>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="sms" />
|
||||
<data android:scheme="smsto" />
|
||||
<data android:scheme="mms" />
|
||||
<data android:scheme="mmsto" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:mimeType="audio/*" />
|
||||
<data android:mimeType="image/*" />
|
||||
<data android:mimeType="text/plain" />
|
||||
<data android:mimeType="video/*" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
<meta-data android:name="org.thoughtcrime.securesms.mms.TextSecureGlideModule"
|
||||
android:value="GlideModule" />
|
||||
|
||||
<activity android:name=".RegistrationProblemsActivity"
|
||||
android:theme="@style/TextSecure.Light.Dialog"
|
||||
android:theme="@style/Theme.AppCompat.Light.DialogWhenLarge"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".CountrySelectionActivity"
|
||||
@@ -90,11 +65,18 @@
|
||||
android:windowSoftInputMode="stateUnchanged"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".ConfirmIdentityActivity"
|
||||
android:theme="@style/TextSecure.Light.Dialog"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
<activity android:name=".DeviceProvisioningActivity"
|
||||
android:theme="@style/TextSecure.DialogActivity"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="tsdevice"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".MmsPreferencesActivity"
|
||||
<activity android:name=".preferences.MmsPreferencesActivity"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".ShareActivity"
|
||||
@@ -102,21 +84,50 @@
|
||||
android:launchMode="singleTask"
|
||||
android:noHistory="true"
|
||||
android:windowSoftInputMode="stateHidden"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:mimeType="audio/*" />
|
||||
<data android:mimeType="image/*" />
|
||||
<data android:mimeType="text/plain" />
|
||||
<data android:mimeType="video/*" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<activity android:name=".ConversationListActivity"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTask"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
android:exported="true" />
|
||||
|
||||
<activity-alias android:name=".RoutingActivity"
|
||||
android:targetActivity=".ConversationListActivity"
|
||||
android:exported="true">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
</activity-alias>
|
||||
|
||||
<activity android:name=".ConversationActivity"
|
||||
android:windowSoftInputMode="stateUnchanged"
|
||||
android:launchMode="singleTask"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
|
||||
|
||||
<activity android:name=".MessageDetailsActivity"
|
||||
android:label="@string/AndroidManifest__message_details"
|
||||
android:windowSoftInputMode="stateHidden"
|
||||
android:launchMode="singleTask"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".GroupCreateActivity"
|
||||
android:windowSoftInputMode="stateVisible"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
android:windowSoftInputMode="stateVisible"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".DatabaseMigrationActivity"
|
||||
android:theme="@style/NoAnimation.Theme.AppCompat.Light.DarkActionBar"
|
||||
@@ -132,12 +143,12 @@
|
||||
android:label="@string/AndroidManifest__create_passphrase"
|
||||
android:windowSoftInputMode="stateUnchanged"
|
||||
android:theme="@style/TextSecure.IntroTheme"
|
||||
android:launchMode="singleTop"
|
||||
android:launchMode="singleTask"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".PassphrasePromptActivity"
|
||||
android:label="@string/AndroidManifest__enter_passphrase"
|
||||
android:launchMode="singleTop"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/TextSecure.IntroTheme"
|
||||
android:windowSoftInputMode="stateAlwaysVisible"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
@@ -152,11 +163,6 @@
|
||||
android:windowSoftInputMode="stateHidden"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".AutoInitiateActivity"
|
||||
android:theme="@style/TextSecure.Light.Dialog"
|
||||
android:label="@string/AndroidManifest__textsecure_detected"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".ViewIdentityActivity"
|
||||
android:label="@string/AndroidManifest__public_identity_key"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
@@ -173,8 +179,7 @@
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".ReceiveKeyActivity"
|
||||
android:label="@string/AndroidManifest__complete_key_exchange"
|
||||
android:theme="@style/TextSecure.Light.Dialog"
|
||||
android:theme="@style/Theme.AppCompat.Light.DialogWhenLarge"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".ApplicationPreferencesActivity"
|
||||
@@ -194,6 +199,11 @@
|
||||
|
||||
<activity android:name=".MediaPreviewActivity"
|
||||
android:label="@string/AndroidManifest__media_preview"
|
||||
android:windowSoftInputMode="stateHidden"
|
||||
android:launchMode="singleTask"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".MediaOverviewActivity"
|
||||
android:windowSoftInputMode="stateHidden"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
@@ -212,9 +222,25 @@
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".SmsSendtoActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SENDTO" />
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="sms" />
|
||||
<data android:scheme="smsto" />
|
||||
<data android:scheme="mms" />
|
||||
<data android:scheme="mmsto" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.soundcloud.android.crop.CropImageActivity" />
|
||||
|
||||
<service android:enabled="true" android:name=".service.ApplicationMigrationService"/>
|
||||
<service android:enabled="true" android:name=".service.KeyCachingService"/>
|
||||
<service android:enabled="true" android:name=".service.RegistrationService"/>
|
||||
<service android:enabled="true" android:name=".service.MessageRetrievalService"/>
|
||||
|
||||
<service android:name=".service.QuickResponseService"
|
||||
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
|
||||
@@ -230,14 +256,6 @@
|
||||
</service>
|
||||
|
||||
|
||||
<!-- <receiver android:name=".service.BootListener" -->
|
||||
<!-- android:enabled="true" -->
|
||||
<!-- android:exported="false">-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.intent.action.BOOT_COMPLETED" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </receiver>-->
|
||||
|
||||
<receiver android:name=".gcm.GcmBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND" >
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
|
||||
@@ -290,6 +308,10 @@
|
||||
android:grantUriPermissions="true"
|
||||
android:authorities="org.thoughtcrime.provider.securesms" />
|
||||
|
||||
<provider android:name=".providers.MmsBodyProvider"
|
||||
android:grantUriPermissions="true"
|
||||
android:authorities="org.thoughtcrime.provider.securesms.mms" />
|
||||
|
||||
<receiver android:name=".service.RegistrationNotifier"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
@@ -315,6 +337,6 @@
|
||||
<action android:name="org.thoughtcrime.securesms.MessageNotifier.DELETE_REMINDER_ACTION"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<uses-library android:name="android.test.runner" />
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
12
BUILDING.md
12
BUILDING.md
@@ -30,6 +30,18 @@ The following steps should help you (re)build TextSecure from the command line.
|
||||
|
||||
./gradlew build
|
||||
|
||||
Visual assets
|
||||
----------------------
|
||||
|
||||
Source assets tend to be large binary blobs, which are best stored outside of git repositories. We host ours in a [Pixelapse repository](https://www.pixelapse.com/openwhispersystems/projects/signal-android/). Some source files are SVGs that can be auto-colored and sized using a tool like [android-res-utils](https://github.com/sebkur/android-res-utils).
|
||||
|
||||
Sample command for generating our audio placeholder image:
|
||||
|
||||
```bash
|
||||
pngs_from_svg.py ic_audio.svg /path/to/TextSecure/res/ 150 "#000" 0.54 _light
|
||||
pngs_from_svg.py ic_audio.svg /path/to/TextSecure/res/ 150 "#fff" 1.0 _dark
|
||||
```
|
||||
|
||||
Setting up a development environment
|
||||
------------------------------------
|
||||
|
||||
|
||||
15
README.md
15
README.md
@@ -1,9 +1,8 @@
|
||||
# TextSecure [](https://travis-ci.org/WhisperSystems/TextSecure)
|
||||
|
||||
TextSecure is a messaging app for easy private communicate with friends.
|
||||
TextSecure is a messaging app for simple private communication with friends.
|
||||
|
||||
TextSecure can use either data (WiFi/3G/4G) or SMS to communicate securely, and all TextSecure
|
||||
messages can also be encrypted locally on your device.
|
||||
TextSecure uses your phone's data connection (WiFi/3G/4G) to communicate securely, optionally supports plain SMS/MMS to function as a unified messenger, and can also encrypt the stored messages on your phone.
|
||||
|
||||
Currently available on the Play store.
|
||||
|
||||
@@ -14,6 +13,16 @@ We use GitHub for bug tracking. Please search the existing issues for your bug a
|
||||
|
||||
https://github.com/WhisperSystems/TextSecure/issues
|
||||
|
||||
## Joining the Beta
|
||||
Want to live life on the bleeding edge and help out with testing?
|
||||
|
||||
You can subscribe to TextSecure Beta releases in two steps:
|
||||
|
||||
1. Join the [TextSecure Beta Google+ Community](https://plus.google.com/communities/114424213916773497091).
|
||||
1. After you've joined the community, [subscribe to the beta](https://play.google.com/apps/testing/org.thoughtcrime.securesms).
|
||||
|
||||
If you're interested in a life of peace and tranquility, stick with the standard releases.
|
||||
|
||||
## Contributing Translations
|
||||
Interested in helping to translate TextSecure? Contribute here:
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package org.thoughtcrime.securesms.database;
|
||||
|
||||
import org.thoughtcrime.securesms.TextSecureTestCase;
|
||||
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class CanonicalAddressDatabaseTest extends TextSecureTestCase {
|
||||
private static final String AMBIGUOUS_NUMBER = "222-3333";
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
import org.thoughtcrime.securesms.TextSecureTestCase;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.api.TextSecureMessageSender;
|
||||
import org.whispersystems.textsecure.api.push.PushAddress;
|
||||
import org.whispersystems.textsecure.api.push.TextSecureAddress;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.NotFoundException;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.PushNetworkException;
|
||||
|
||||
@@ -38,10 +36,10 @@ public class DeliveryReceiptJobTest extends TextSecureTestCase {
|
||||
|
||||
deliveryReceiptJob.onRun();
|
||||
|
||||
ArgumentCaptor<PushAddress> captor = ArgumentCaptor.forClass(PushAddress.class);
|
||||
ArgumentCaptor<TextSecureAddress> captor = ArgumentCaptor.forClass(TextSecureAddress.class);
|
||||
verify(textSecureMessageSender).sendDeliveryReceipt(captor.capture(), eq(timestamp));
|
||||
|
||||
assertTrue(captor.getValue().getRelay().equals("foo"));
|
||||
assertTrue(captor.getValue().getRelay().get().equals("foo"));
|
||||
assertTrue(captor.getValue().getNumber().equals("+14152222222"));
|
||||
}
|
||||
|
||||
@@ -51,7 +49,7 @@ public class DeliveryReceiptJobTest extends TextSecureTestCase {
|
||||
|
||||
Mockito.doThrow(new PushNetworkException("network error"))
|
||||
.when(textSecureMessageSender)
|
||||
.sendDeliveryReceipt(any(PushAddress.class), eq(timestamp));
|
||||
.sendDeliveryReceipt(any(TextSecureAddress.class), eq(timestamp));
|
||||
|
||||
|
||||
DeliveryReceiptJob deliveryReceiptJob = new DeliveryReceiptJob(getContext(),
|
||||
@@ -70,7 +68,7 @@ public class DeliveryReceiptJobTest extends TextSecureTestCase {
|
||||
|
||||
Mockito.doThrow(new NotFoundException("not found"))
|
||||
.when(textSecureMessageSender)
|
||||
.sendDeliveryReceipt(any(PushAddress.class), eq(timestamp));
|
||||
.sendDeliveryReceipt(any(TextSecureAddress.class), eq(timestamp));
|
||||
|
||||
try {
|
||||
deliveryReceiptJob.onRun();
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Copyright (C) 2015 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.service;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Telephony;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.thoughtcrime.securesms.TextSecureTestCase;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
import static org.mockito.Matchers.anyBoolean;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.contains;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class SmsListenerTest extends TextSecureTestCase {
|
||||
|
||||
private static final String CHALLENGE_SMS_3_3 = "Your TextSecure verification code: 337-337";
|
||||
private static final String CHALLENGE_SMS_3_4 = "Your TextSecure verification code: 337-1337";
|
||||
private static final String CHALLENGE_SMS_4_3 = "Your TextSecure verification code: 1337-337";
|
||||
private static final String CHALLENGE_SMS_4_4 = "Your TextSecure verification code: 1337-1337";
|
||||
private static final String CHALLENGE_SMS_4_4_PREPEND = "XXXYour TextSecure verification code: 1337-1337";
|
||||
private static final String CHALLENGE_SMS_4_4_APPEND = "Your TextSecure verification code: 1337-1337XXX";
|
||||
private static final String[] CHALLENGE_SMS = {
|
||||
CHALLENGE_SMS_3_3, CHALLENGE_SMS_3_4, CHALLENGE_SMS_4_3,
|
||||
CHALLENGE_SMS_4_4, CHALLENGE_SMS_4_4_PREPEND, CHALLENGE_SMS_4_4_APPEND
|
||||
};
|
||||
|
||||
private static final String CHALLENGE_3_3 = "337337";
|
||||
private static final String CHALLENGE_3_4 = "3371337";
|
||||
private static final String CHALLENGE_4_3 = "1337337";
|
||||
private static final String CHALLENGE_4_4 = "13371337";
|
||||
private static final String[] CHALLENGES = {
|
||||
CHALLENGE_3_3, CHALLENGE_3_4, CHALLENGE_4_3,
|
||||
CHALLENGE_4_4, CHALLENGE_4_4, CHALLENGE_4_4,
|
||||
};
|
||||
|
||||
/*
|
||||
credit :D
|
||||
http://stackoverflow.com/a/12338541
|
||||
*/
|
||||
private static byte[] buildSmsPdu(String sender, String body) throws Exception{
|
||||
byte[] scBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD("0000000000");
|
||||
byte[] senderBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(sender);
|
||||
int lsmcs = scBytes.length;
|
||||
byte[] dateBytes = new byte[7];
|
||||
Calendar calendar = new GregorianCalendar();
|
||||
|
||||
dateBytes[0] = reverseByte((byte) (calendar.get(Calendar.YEAR)));
|
||||
dateBytes[1] = reverseByte((byte) (calendar.get(Calendar.MONTH) + 1));
|
||||
dateBytes[2] = reverseByte((byte) (calendar.get(Calendar.DAY_OF_MONTH)));
|
||||
dateBytes[3] = reverseByte((byte) (calendar.get(Calendar.HOUR_OF_DAY)));
|
||||
dateBytes[4] = reverseByte((byte) (calendar.get(Calendar.MINUTE)));
|
||||
dateBytes[5] = reverseByte((byte) (calendar.get(Calendar.SECOND)));
|
||||
dateBytes[6] = reverseByte((byte) ((calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET)) / (60 * 1000 * 15)));
|
||||
|
||||
ByteArrayOutputStream bo = new ByteArrayOutputStream();
|
||||
bo.write(lsmcs);
|
||||
bo.write(scBytes);
|
||||
bo.write(0x04);
|
||||
bo.write((byte) sender.length());
|
||||
bo.write(senderBytes);
|
||||
bo.write(0x00);
|
||||
bo.write(0x00);
|
||||
bo.write(dateBytes);
|
||||
|
||||
String sReflectedClassName = "com.android.internal.telephony.GsmAlphabet";
|
||||
Class cReflectedNFCExtras = Class.forName(sReflectedClassName);
|
||||
Method stringToGsm7BitPacked = cReflectedNFCExtras.getMethod("stringToGsm7BitPacked", new Class[] { String.class });
|
||||
|
||||
stringToGsm7BitPacked.setAccessible(true);
|
||||
byte[] bodybytes = (byte[]) stringToGsm7BitPacked.invoke(null, body);
|
||||
bo.write(bodybytes);
|
||||
|
||||
return bo.toByteArray();
|
||||
}
|
||||
|
||||
private static byte reverseByte(byte b) {
|
||||
return (byte) ((b & 0xF0) >> 4 | (b & 0x0F) << 4);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private Intent buildSmsReceivedIntent(String smsBody) throws Exception {
|
||||
final Intent smsIntent = mock(Intent.class);
|
||||
final Bundle smsExtras = new Bundle();
|
||||
final byte[] smsPdu = buildSmsPdu("15555555555", smsBody);
|
||||
|
||||
smsExtras.putSerializable("pdus", new Object[]{smsPdu});
|
||||
|
||||
when(smsIntent.getAction()).thenReturn(Telephony.Sms.Intents.SMS_RECEIVED_ACTION);
|
||||
when(smsIntent.getExtras()).thenReturn(smsExtras);
|
||||
|
||||
return smsIntent;
|
||||
}
|
||||
|
||||
public void testReceiveChallenges() throws Exception {
|
||||
final SmsListener smsListener = new SmsListener();
|
||||
|
||||
for (int i = 0; i < CHALLENGES.length; i++) {
|
||||
final String CHALLENGE = CHALLENGES[i];
|
||||
final String CHALLENGE_SMS = SmsListenerTest.CHALLENGE_SMS[i];
|
||||
|
||||
final Context mockContext = mock(Context.class);
|
||||
final SharedPreferences mockPreferences = mock(SharedPreferences.class);
|
||||
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||
|
||||
when(mockContext.getPackageName()).thenReturn(getContext().getPackageName());
|
||||
when(mockContext.getSharedPreferences(anyString(), anyInt())).thenReturn(mockPreferences);
|
||||
when(mockPreferences.getBoolean(contains("pref_verifying"), anyBoolean())).thenReturn(true);
|
||||
|
||||
try {
|
||||
smsListener.onReceive(mockContext, buildSmsReceivedIntent(CHALLENGE_SMS));
|
||||
} catch (IllegalStateException e) {
|
||||
Log.d(getClass().getName(), "some api levels are picky with abortBroadcast()");
|
||||
}
|
||||
|
||||
verify(mockContext, times(1)).sendBroadcast(intentCaptor.capture());
|
||||
|
||||
final Intent sendIntent = intentCaptor.getValue();
|
||||
assertTrue(sendIntent.getAction().equals(RegistrationService.CHALLENGE_EVENT));
|
||||
assertTrue(sendIntent.getStringExtra(RegistrationService.CHALLENGE_EXTRA).equals(CHALLENGE));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import org.thoughtcrime.securesms.TextSecureTestCase;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
public class ListPartitionTest extends TextSecureTestCase {
|
||||
|
||||
public void testPartitionEven() {
|
||||
List<Integer> list = new LinkedList<>();
|
||||
|
||||
for (int i=0;i<100;i++) {
|
||||
list.add(i);
|
||||
}
|
||||
|
||||
List<List<Integer>> partitions = Util.partition(list, 10);
|
||||
|
||||
assertEquals(partitions.size(), 10);
|
||||
|
||||
int counter = 0;
|
||||
|
||||
for (int i=0;i<partitions.size();i++) {
|
||||
List<Integer> partition = partitions.get(i);
|
||||
assertEquals(partition.size(), 10);
|
||||
|
||||
for (int j=0;j<partition.size();j++) {
|
||||
assertEquals((int)partition.get(j), counter++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testPartitionOdd() {
|
||||
List<Integer> list = new LinkedList<>();
|
||||
|
||||
for (int i=0;i<100;i++) {
|
||||
list.add(i);
|
||||
}
|
||||
|
||||
list.add(100);
|
||||
|
||||
List<List<Integer>> partitions = Util.partition(list, 10);
|
||||
|
||||
assertEquals(partitions.size(), 11);
|
||||
|
||||
int counter = 0;
|
||||
|
||||
for (int i=0;i<partitions.size()-1;i++) {
|
||||
List<Integer> partition = partitions.get(i);
|
||||
assertEquals(partition.size(), 10);
|
||||
|
||||
for (int j=0;j<partition.size();j++) {
|
||||
assertEquals((int)partition.get(j), counter++);
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(partitions.get(10).size(), 1);
|
||||
assertEquals((int)partitions.get(10).get(0), 100);
|
||||
}
|
||||
|
||||
public void testPathological() {
|
||||
List<Integer> list = new LinkedList<>();
|
||||
|
||||
for (int i=0;i<100;i++) {
|
||||
list.add(i);
|
||||
}
|
||||
|
||||
List<List<Integer>> partitions = Util.partition(list, 1);
|
||||
|
||||
assertEquals(partitions.size(), 100);
|
||||
|
||||
int counter = 0;
|
||||
|
||||
for (int i=0;i<partitions.size();i++) {
|
||||
List<Integer> partition = partitions.get(i);
|
||||
assertEquals(partition.size(), 1);
|
||||
|
||||
for (int j=0;j<partition.size();j++) {
|
||||
assertEquals((int)partition.get(j), counter++);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,8 @@ import junit.framework.AssertionFailedError;
|
||||
import org.thoughtcrime.securesms.TextSecureTestCase;
|
||||
import org.whispersystems.textsecure.api.util.InvalidNumberException;
|
||||
import org.whispersystems.textsecure.api.util.PhoneNumberFormatter;
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class PhoneNumberFormatterTest extends TextSecureTestCase {
|
||||
private static final String LOCAL_NUMBER = "+15555555555";
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.TextSecureTestCase;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
public class Rfc5724UriTest extends TextSecureTestCase {
|
||||
|
||||
private static final String TAG = Rfc5724UriTest.class.getSimpleName();
|
||||
|
||||
public void testInvalidPath() throws Exception {
|
||||
final String[] invalidSchemaUris = {
|
||||
"",
|
||||
":",
|
||||
"sms:",
|
||||
":sms",
|
||||
"sms:?goto=fail",
|
||||
"sms:?goto=fail&fail=goto"
|
||||
};
|
||||
|
||||
for (String uri : invalidSchemaUris) {
|
||||
try {
|
||||
new Rfc5724Uri(uri);
|
||||
Log.e(TAG, "uri " + uri + " should have failed path check");
|
||||
assertTrue(false);
|
||||
} catch (URISyntaxException e) { }
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetSchema() throws Exception {
|
||||
final String[][] uriTestPairs = {
|
||||
{"sms:+15555555555", "sms"},
|
||||
{"sMs:+15555555555", "sMs"},
|
||||
{"smsto:+15555555555?", "smsto"},
|
||||
{"mms:+15555555555?a=b", "mms"},
|
||||
{"mmsto:+15555555555?a=b&c=d", "mmsto"}
|
||||
};
|
||||
|
||||
for (String[] uriTestPair : uriTestPairs) {
|
||||
final Rfc5724Uri testUri = new Rfc5724Uri(uriTestPair[0]);
|
||||
Log.d(TAG, testUri.getSchema() + " ?= " + uriTestPair[1]);
|
||||
assertTrue(testUri.getSchema().equals(uriTestPair[1]));
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetPath() throws Exception {
|
||||
final String[][] uriTestPairs = {
|
||||
{"sms:+15555555555", "+15555555555"},
|
||||
{"smsto:+15555555555?", "+15555555555"},
|
||||
{"mms:+15555555555?a=b", "+15555555555"},
|
||||
{"mmsto:+15555555555?a=b&c=d", "+15555555555"},
|
||||
{"sms:+15555555555,+14444444444", "+15555555555,+14444444444"},
|
||||
{"sms:+15555555555,+14444444444?", "+15555555555,+14444444444"},
|
||||
{"sms:+15555555555,+14444444444?a=b", "+15555555555,+14444444444"},
|
||||
{"sms:+15555555555,+14444444444?a=b&c=d", "+15555555555,+14444444444"}
|
||||
};
|
||||
|
||||
for (String[] uriTestPair : uriTestPairs) {
|
||||
final Rfc5724Uri testUri = new Rfc5724Uri(uriTestPair[0]);
|
||||
Log.d(TAG, testUri.getPath() + " ?= " + uriTestPair[1]);
|
||||
assertTrue(testUri.getPath().equals(uriTestPair[1]));
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetQueryParams() throws Exception {
|
||||
final String[][] uriTestPairs = {
|
||||
{"sms:+15555555555", "a", null},
|
||||
{"mms:+15555555555?b=", "a", null},
|
||||
{"mmsto:+15555555555?a=", "a", ""},
|
||||
{"sms:+15555555555?a=b", "a", "b"},
|
||||
{"sms:+15555555555?a=b&c=d", "a", "b"},
|
||||
{"sms:+15555555555?a=b&c=d", "b", null},
|
||||
{"sms:+15555555555?a=b&c=d", "c", "d"},
|
||||
{"sms:+15555555555?a=b&c=d", "d", null}
|
||||
};
|
||||
|
||||
for (String[] uriTestPair : uriTestPairs) {
|
||||
final Rfc5724Uri testUri = new Rfc5724Uri(uriTestPair[0]);
|
||||
final String paramResult = testUri.getQueryParams().get(uriTestPair[1]);
|
||||
|
||||
Log.d(TAG, paramResult + " ?= " + uriTestPair[2]);
|
||||
if (paramResult == null) assertTrue(uriTestPair[2] == null);
|
||||
else assertTrue(paramResult.equals(uriTestPair[2]));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
|
||||
public class UtilTest extends AndroidTestCase {
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package org.thoughtcrime.securesms.service;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.test.InstrumentationTestCase;
|
||||
|
||||
import static org.fest.assertions.api.Assertions.*;
|
||||
|
||||
public class MmsReceiverTest extends InstrumentationTestCase {
|
||||
|
||||
private MmsReceiver mmsReceiver;
|
||||
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mmsReceiver = new MmsReceiver(getInstrumentation().getContext());
|
||||
}
|
||||
|
||||
public void tearDown() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
public void testProcessMalformedData() throws Exception {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(SendReceiveService.RECEIVE_MMS_ACTION);
|
||||
intent.putExtra("data", new byte[]{0x00});
|
||||
mmsReceiver.process(null, intent);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -122,10 +122,13 @@
|
||||
<apn carrier="Orange MMS" mcc="214" mnc="03" apn="orangemms" proxy="172.22.188.25" port="8080" user="orange" password="orange" mmsc="http://mms.orange.es" mmsproxy="172.22.188.25" mmsport="8080" authtype="2" type="mms" />
|
||||
<apn carrier="Yoigo" mcc="214" mnc="04" apn="internet" proxy="010.008.000.036" port="8080" type="default,supl" />
|
||||
<apn carrier="Yoigo MMS" mcc="214" mnc="04" apn="mms" mmsc="http://mms" mmsproxy="193.209.134.141" mmsport="80" type="mms" />
|
||||
<apn carrier="Pepephone 4G Internet" mcc="214" mnc="05" apn="gprsmov.pepephone.com" type="default,supl" />
|
||||
<apn carrier="Pepephone 4G MMS" mcc="214" mnc="05" apn="gprs.pepephone.com" mmsc="http://www.pepephone.com" mmsproxy="10.138.255.43" mmsport="8080" authtype="1" type="mms" />
|
||||
<apn carrier="Pepephone 4G (Public)" mcc="214" mnc="05" apn="gprs.pepephone.com" type="default,supl" />
|
||||
<apn carrier="Tuenti" mcc="214" mnc="05" apn="tuenti.com" user="tuenti" password="tuenti" mmsc="http://tuenti.com" mmsproxy="10.138.255.43" mmsport="8080" type="default,supl,mms" />
|
||||
<apn carrier="Pepephone Internet" mcc="214" mnc="06" apn="gprsmov.pepephone.com" type="default,supl" />
|
||||
<apn carrier="Pepephone MMS" mcc="214" mnc="06" apn="mms.pepephone.com" user="wap@wap" password="wap125" mmsproxy="212.073.032.010" mmsport="80" type="mms" />
|
||||
<apn carrier="Pepephone (Public)" mcc="214" mnc="06" apn="gprs.pepephone.com" type="default,supl" />
|
||||
<apn carrier="Pepephone 3G Internet" mcc="214" mnc="06" apn="gprsmov.pepephone.com" type="default,supl" />
|
||||
<apn carrier="Pepephone 3G MMS" mcc="214" mnc="06" apn="mms.pepephone.com" user="wap@wap" password="wap125" mmsproxy="212.073.032.010" mmsport="80" type="mms" />
|
||||
<apn carrier="Pepephone 3G (Public)" mcc="214" mnc="06" apn="gprs.pepephone.com" type="default,supl" />
|
||||
<apn carrier="Vodafone GPRS" mcc="214" mnc="06" apn="airtelnet.es" user="vodafone" password="vodafone" type="default,supl" />
|
||||
<apn carrier="Vodafone MMS" mcc="214" mnc="06" apn="mms.vodafone.net" user="wap@wap" password="wap125" mmsc="http://mmsc.vodafone.es/servlets/mms" mmsproxy="212.73.32.10" mmsport="80" type="mms" />
|
||||
<apn carrier="Movistar ES" mcc="214" mnc="07" apn="movistar.es" user="MOVISTAR" password="MOVISTAR" type="default,supl" />
|
||||
@@ -141,6 +144,7 @@
|
||||
<apn carrier="Jazztel MMS" mcc="214" mnc="21" apn="jazzmms" mmsc="http://jazztelmms.com:8081" mmsproxy="217.18.32.183" mmsport="8081" type="mms" />
|
||||
<apn carrier="Lycamobile ES" mcc="214" mnc="25" apn="data.lycamobile.es" user="lmes" password="plus" type="default,supl" />
|
||||
<apn carrier="Truphone ES" mcc="214" mnc="27" apn="truphone.com" type="default,supl" />
|
||||
<apn carrier="Tuenti" mcc="214" mnc="32" apn="tuenti.com" user="tuenti" password="tuenti" type="default,supl" />
|
||||
<apn carrier="Pannon MMS" mcc="216" mnc="01" apn="mms" mmsc="http://mmsc.pgsm.hu/" mmsproxy="193.225.154.22" mmsport="8080" type="mms" />
|
||||
<apn carrier="Pannon" mcc="216" mnc="01" apn="net" type="default,supl" />
|
||||
<apn carrier="Telenor Net" mcc="216" mnc="01" apn="net" type="default,supl" />
|
||||
@@ -169,7 +173,8 @@
|
||||
<apn carrier="VIPnet MMS" mcc="219" mnc="10" apn="mms.vipnet.hr" mmsc="http://mms.vipnet.hr/servlets/mms" mmsproxy="212.91.99.91" mmsport="8080" type="mms" />
|
||||
<apn carrier="Telenor RS" mcc="220" mnc="01" apn="internet" user="telenor" password="gprs" proxy="217.65.192.33" port="8080" type="default,supl" />
|
||||
<apn carrier="Telenor RS MMS" mcc="220" mnc="01" apn="mms" mmsc="http://mms.telenor.rs/servlets/mms" mmsproxy="217.65.192.33" mmsport="8080" type="mms" />
|
||||
<apn carrier="MTS RS" mcc="220" mnc="03" apn="gprswap" user="mts" password="064" proxy="172.017.088.198" port="8080" type="default,supl" />
|
||||
<apn carrier="MTS RS INTERNET" mcc="220" mnc="03" apn="gprsinternet" user="mts" password="064" proxy="" port="" type="default,supl" />
|
||||
<apn carrier="MTS RS WAP" mcc="220" mnc="03" apn="gprswap" user="mts" password="064" server="http://m.mondo.rs" proxy="172.017.088.198" port="8080" type="default,supl" />
|
||||
<apn carrier="MTS RS MMS" mcc="220" mnc="03" apn="mms" user="mts" password="064" mmsc="http://mms.mts064.telekom.rs/mms/wapenc" mmsproxy="172.017.085.131" mmsport="8080" type="mms" />
|
||||
<apn carrier="VIP MMS" mcc="220" mnc="05" apn="vipmobile.mms" user="vipmobile" password="vipmobile" mmsc="http://mmsc.vipmobile.rs/" mmsproxy="212.15.182.82" mmsport="8080" type="mms" />
|
||||
<apn carrier="VIP" mcc="220" mnc="05" apn="vipmobile" user="vipmobile" password="vipmobile" proxy="212.15.182.82" port="8080" type="default,supl" />
|
||||
@@ -181,6 +186,7 @@
|
||||
<apn carrier="Tiscali MMS" mcc="222" mnc="01" apn="tiscalimobilemms" mmsc="http://mms.tiscali.mobi/servlets/mms" mmsproxy="213.230.130.89" mmsport="80" type="mms" />
|
||||
<apn carrier="iTIM" mcc="222" mnc="01" apn="unico.tim.it" proxy="213.230.130.89" port="80" mmsc="http://mms.tim.it/servlets/mms" mmsproxy="213.230.130.89" mmsport="80" type="mms" />
|
||||
<apn carrier="NOVERCA WEB" mcc="222" mnc="01" apn="web.noverca.it" type="default,supl" />
|
||||
<apn carrier="COOPVOCE" mcc="222" mnc="01" apn="web.coopvoce.it" type="default,supl" />
|
||||
<apn carrier="Vodafone IT MMS" mcc="222" mnc="10" apn="mms.vodafone.it" mmsc="http://mms.vodafone.it/servlets/mms" mmsproxy="10.128.224.10" mmsport="80" type="mms" />
|
||||
<apn carrier="Vodafone IT" mcc="222" mnc="10" apn="mobile.vodafone.it" type="default,supl" />
|
||||
<apn carrier="Vodafone WEB" mcc="222" mnc="10" apn="web.omnitel.it" type="default,supl" />
|
||||
@@ -245,7 +251,7 @@
|
||||
<apn carrier="UBIQUISYS" mcc="234" mnc="01" apn="internet" type="default,supl,mms" />
|
||||
<apn carrier="Tesco UK" mcc="234" mnc="01" apn="prepay.tesco-mobile.com" user="tescowap" password="password" server="http://wap.tesco-mobile.com/" proxy="193.113.200.195" port="9201" type="default,supl,mms" />
|
||||
<apn carrier="O2 UK" mcc="234" mnc="10" apn="mobile.o2.co.uk" user="o2web" password="password" mmsc="http://mmsc.mms.o2.co.uk:8002" mmsproxy="193.113.200.195" mmsport="8080" authtype="1" type="default,supl,mms" />
|
||||
<apn carrier="Giffgaff" mcc="234" mnc="10" apn="giffgaff.com" user="giffgaff" password="password" mmsc="http://mmsc.mediamessaging.co.uk:8002" mmsproxy="82.132.254.1" mmsport="8080" type="default,supl,mms" />
|
||||
<apn carrier="giffgaff" mcc="234" mnc="10" apn="giffgaff.com" user="giffgaff" password="password" mmsc="http://mmsc.mediamessaging.co.uk:8002" mmsproxy="82.132.254.1" mmsport="8080" type="default,supl,mms" />
|
||||
<apn carrier="Tesco" mcc="234" mnc="10" apn="prepay.tesco-mobile.com" user="tescowap" password="tescowap" proxy="193.113.200.195" port="8080" mmsc="http://mmsc.mms.02.co.uk:8002" mmsproxy="193.113.200.195" mmsport="8080" type="default,supl,mms" />
|
||||
<apn carrier="Vodafone UK Contract Internet" mcc="234" mnc="15" apn="Internet" user="web" password="web" server="*" mmsc="http://mms.vodafone.co.uk/servlets/mms" mmsproxy="212.183.137.012" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Vodafone Post-pay ISP" mcc="234" mnc="15" apn="internet" user="web" password="web" type="default,supl" />
|
||||
@@ -282,26 +288,24 @@
|
||||
<apn carrier="Sure Mobile" mcc="234" mnc="55" apn="internet" type="default,supl" />
|
||||
<apn carrier="Sure Picture Messaging" mcc="234" mnc="55" apn="mms" mmsc="http://mmsc.gprs.cw.com/" mmsproxy="10.0.3.101" mmsport="80" type="mms" />
|
||||
<apn carrier="Manx Telecom" mcc="234" mnc="58" apn="3gpronto" proxy="195.010.099.046" port="8080" mmsc="http://mms.manxpronto.net:8002" type="default,supl,mms" />
|
||||
<apn carrier="3G HSDPA" mcc="234" mnc="58" apn="3gpronto" type="default,supl" />
|
||||
<apn carrier="Manx Telecom Contract MMS" mcc="234" mnc="58" apn="mms.manxpronto.net" user="mms" password="mms" mmsc="http://mms.manxpronto.net:8002" mmsproxy="195.10.99.46" mmsport="8080" type="mms" />
|
||||
<apn carrier="Manx Telecom Prepay MMS" mcc="234" mnc="58" apn="mms.prontogo.net" user="mmsgo" password="mmsgo" mmsc="http://mms.manxpronto.net:8002" mmsproxy="195.10.99.41" mmsport="8080" type="mms" />
|
||||
<apn carrier="Manx Telecom Contract WEB" mcc="234" mnc="58" apn="web.manxpronto.net" user="gprs" password="gprs" type="default,supl" />
|
||||
<apn carrier="EE Internet" mcc="234" mnc="86" apn="everywhere" user="eesecure" password="secure" authtype="1" type="default,supl,dun" />
|
||||
<apn carrier="EE MMS" mcc="234" mnc="86" apn="eezone" user="eesecure" password="secure" mmsc="http://mms/" mmsproxy="149.254.201.135" mmsport="8080" authtype="1" type="mms" />
|
||||
<apn carrier="TDC Internet" mcc="238" mnc="01" apn="internet" proxy="62.135.173.214" authtype="1" type="default,supl" />
|
||||
<apn carrier="TDC MMS" mcc="238" mnc="01" apn="mms" mmsc="http://mmsc.tdc.dk:8002" mmsproxy="194.182.251.15" mmsport="8080" authtype="1" type="mms" />
|
||||
<apn carrier="TDC Internet" mcc="238" mnc="01" apn="internet" proxy="62.135.173.214" authtype="1" mvno_match_data="2380101xxxxxxxx" mvno_type="imsi" type="default,supl" />
|
||||
<apn carrier="TDC MMS" mcc="238" mnc="01" apn="mms" mmsc="http://mmsc.tdc.dk:8002" mmsproxy="194.182.251.15" mmsport="8080" authtype="1" mvno_match_data="2380101xxxxxxxx" mvno_type="imsi" type="mms" />
|
||||
<apn carrier="coop mobil MMS" mcc="238" mnc="01" apn="mms" mmsc="http://192.168.241.114:8002" mmsproxy="194.182.251.15" mmsport="8080" type="mms" />
|
||||
<apn carrier="Telenor Internet" mcc="238" mnc="02" apn="Internet" type="default,supl" />
|
||||
<apn carrier="Bibob internet DK" mcc="238" mnc="02" apn="internet.bibob.dk" port="8080" type="default,supl,mms" />
|
||||
<apn carrier="Bibob MMS DK" mcc="238" mnc="02" apn="mms.bibob.dk" proxy="212.88.64.8" port="8080" mmsc="http://mms.telenor.dk" mmsport="8080" type="mms" />
|
||||
<apn carrier="Telenor DK MMS" mcc="238" mnc="02" apn="telenor" mmsc="http://mms.telenor.dk" mmsproxy="212.88.64.8" mmsport="8080" authtype="1" type="mms" />
|
||||
<apn carrier="Bibob internet DK" mcc="238" mnc="02" apn="internet.bibob.dk" port="8080" mvno_match_data="BiBoB" mvno_type="spn" type="default,supl,mms" />
|
||||
<apn carrier="Bibob MMS DK" mcc="238" mnc="02" apn="mms.bibob.dk" proxy="212.88.64.8" port="8080" mmsc="http://mms.telenor.dk" mmsport="8080" mvno_match_data="BiBoB" mvno_type="spn" type="mms" />
|
||||
<apn carrier="Telenor Internet" mcc="238" mnc="02" apn="Internet" mvno_match_data="TELMORE" mvno_type="spn" type="default,supl" />
|
||||
<apn carrier="Telenor DK MMS" mcc="238" mnc="02" apn="telenor" mmsc="http://mms.telenor.dk" mmsproxy="212.88.64.8" mmsport="8080" authtype="1" mvno_match_data="TELMORE" mvno_type="spn" type="mms" />
|
||||
<apn carrier="3 DK" mcc="238" mnc="06" apn="data.tre.dk" mmsc="http://mms.3.dk" mmsproxy="mmsproxy.3.dk" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="3 Danmark" mcc="238" mnc="06" apn="data.tre.dk" mmsc="http://mms.3.dk/" mmsproxy="172.16.1.25" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Lycamobile DK" mcc="238" mnc="12" apn="data.lycamobile.dk" user="lmdk" password="plus" type="default,supl" />
|
||||
<apn carrier="Telia DK" mcc="238" mnc="20" apn="www.internet.mtelia.dk" type="default,supl" />
|
||||
<apn carrier="Telia DK MMS" mcc="238" mnc="20" apn="www.mms.mtelia.dk" mmsc="http://mms.telia.dk" mmsproxy="193.209.134.131" mmsport="8080" type="mms" />
|
||||
<apn carrier="Call me Internet" mcc="238" mnc="20" apn="websp" authtype="2" type="default,supl" />
|
||||
<apn carrier="Call me MMS" mcc="238" mnc="20" apn="mmssp" mmsc="http://mms.telia.dk" mmsproxy="193.209.134.131" mmsport="8080" authtype="2" type="mms" />
|
||||
<apn carrier="Telia DK" mcc="238" mnc="20" apn="www.internet.mtelia.dk" mvno_match_data="2382010x" mvno_type="imsi" type="default,supl" />
|
||||
<apn carrier="Telia DK MMS" mcc="238" mnc="20" apn="www.mms.mtelia.dk" mmsc="http://mms.telia.dk" mmsproxy="193.209.134.131" mmsport="8080" mvno_match_data="2382010x" mvno_type="imsi" type="mms" />
|
||||
<apn carrier="Call me Internet" mcc="238" mnc="20" apn="websp" authtype="2" mvno_match_data="Call me" mvno_type="spn" type="default,supl" />
|
||||
<apn carrier="Call me MMS" mcc="238" mnc="20" apn="mmssp" mmsc="http://mms.telia.dk" mmsproxy="193.209.134.131" mmsport="8080" authtype="2" mvno_match_data="Call me" mvno_type="spn" type="mms" />
|
||||
<apn carrier="Telenor Internet" mcc="238" mnc="77" apn="Internet" type="default,supl" />
|
||||
<apn carrier="Telenor MMS" mcc="238" mnc="77" apn="telenor" mmsc="http://mms.telenor.dk" mmsproxy="212.88.64.8" mmsport="8080" type="mms" />
|
||||
<apn carrier="Halebop Internet" mcc="240" mnc="01" apn="halebop.telia.se" type="default,supl" />
|
||||
@@ -329,7 +333,7 @@
|
||||
<apn carrier="Lycamobile SE" mcc="240" mnc="12" apn="data.lycamobile.se" user="lmse" password="plus" type="default,supl" />
|
||||
<apn carrier="Ventelo Internet" mcc="242" mnc="01" apn="internet.ventelo.no" type="default,supl" />
|
||||
<apn carrier="Ventelo MMS" mcc="242" mnc="01" apn="mms.ventelo.no" user="ventelo" password="1111" mmsc="http://mmsc/" mmsproxy="10.10.10.11" mmsport="8080" type="mms" />
|
||||
<apn carrier="Telenor" mcc="242" mnc="01" apn="telenor" proxy="10.10.10.10" port="8080" mmsc="http://mmsc/" mmsproxy="10.10.10.11" mmsport="8080" authtype="1" type="default,supl,mms" />
|
||||
<apn carrier="Telenor" mcc="242" mnc="01" apn="telenor" proxy="10.10.10.10" port="8080" mmsc="http://mmsc/" mmsproxy="10.10.10.11" mmsport="8080" type="default,supl,mms" />
|
||||
<apn carrier="Mobitalk" mcc="242" mnc="01" apn="telenor" user="dj" password="dj" proxy="10.10.10.10" port="8080" mmsc="http://mmsc/" mmsproxy="10.10.10.11" mmsport="8080" type="default,supl,mms" />
|
||||
<apn carrier="Talkmore" mcc="242" mnc="01" apn="telenor" type="default,supl,mms" />
|
||||
<apn carrier="NetCom MMS" mcc="242" mnc="02" apn="mms.netcom.no" mmsc="http://mm/" mmsproxy="212.169.66.4" mmsport="8080" type="mms" />
|
||||
@@ -367,10 +371,8 @@
|
||||
<apn carrier="Bite LT Internet" mcc="246" mnc="02" apn="banga" type="default,supl" />
|
||||
<apn carrier="Bite MMS" mcc="246" mnc="02" apn="mms" user="mms@mms" password="mms" mmsc="http://mmsc" mmsproxy="192.168.150.2" mmsport="8080" type="mms" />
|
||||
<apn carrier="Bite" mcc="246" mnc="02" apn="wap" server="213.226.131.133" type="default,supl" />
|
||||
<apn carrier="Tele2 Internet LT" mcc="246" mnc="03" apn="internet.tele2.lt" proxy="130.244.196.090" port="8080" type="default,supl" />
|
||||
<apn carrier="Tele2 LT" mcc="246" mnc="03" apn="internet.vodafone.net" type="default,supl" />
|
||||
<apn carrier="Tele2 MMS LT" mcc="246" mnc="03" apn="mms.tele2.lt" mmsc="http://mmsc.tele2.lt/" mmsproxy="193.012.040.029" mmsport="8080" type="mms" />
|
||||
<apn carrier="Tele2 LT MMS" mcc="246" mnc="03" apn="wap.tele2.lt" mmsc="http://mmsc.tele2.lt" mmsproxy="193.12.40.29" mmsport="8080" type="mms" />
|
||||
<apn carrier="Tele2 Internetas" mcc="246" mnc="03" apn="internet.tele2.lt" proxy="" port="" type="default,supl" />
|
||||
<apn carrier="Tele2 LT MMS" mcc="246" mnc="03" apn="mms.tele2.lt" user="wap" password="wap" mmsc="http://mmsc.tele2.lt" mmsproxy="193.12.40.29" mmsport="8080" type="mms" />
|
||||
<apn carrier="VZW Test Internet" mcc="246" mnc="81" apn="VZWINTERNET" type="default,dun,supl" protocol="IPV4V6" roaming_protocol="IPV4V6" />
|
||||
<apn carrier="VZW Test FOTA" mcc="246" mnc="81" apn="VZWADMIN" type="fota" protocol="IPV4V6" roaming_protocol="IPV4V6" />
|
||||
<apn carrier="VZW Test IMS" mcc="246" mnc="81" apn="VZWIMS" type="ims" protocol="IPV4V6" roaming_protocol="IPV4V6" />
|
||||
@@ -576,8 +578,9 @@
|
||||
<apn carrier="M-Tel MMS" mcc="284" mnc="01" apn="mms-gprs.mtel.bg" user="mtel" password="mtel" mmsc="http://mmsc/" mmsproxy="10.150.0.33" mmsport="8080" type="mms" />
|
||||
<apn carrier="VIVACOM Internet" mcc="284" mnc="03" apn="internet.vivacom.bg" user="VIVACOM" password="VIVACOM" authtype="0" type="default,supl" />
|
||||
<apn carrier="VIVACOM MMS" mcc="284" mnc="03" apn="mms.vivacom.bg" user="mms" password="mms" mmsc="http://mmsc.vivacom.bg" mmsproxy="192.168.123.123" mmsport="8080" authtype="0" type="mms" />
|
||||
<apn carrier="GLOBUL Internet" mcc="284" mnc="05" apn="globul" user="globul" type="default,supl" />
|
||||
<apn carrier="GLOBUL MMS" mcc="284" mnc="05" apn="mms.globul.bg" user="mms" mmsc="http://mmsc1.mms.globul.bg:8002" mmsproxy="192.168.87.11" mmsport="8004" type="mms" />
|
||||
<apn carrier="Telenor Internet" mcc="284" mnc="05" apn="telenor" user="telenor" type="default,supl" />
|
||||
<apn carrier="Telenor MMS" mcc="284" mnc="05" apn="mms.telenor.bg" user="mms" mmsc="http://mmsc1.mms.telenor.bg:8002" mmsproxy="192.168.87.11" mmsport="8004" type="mms" />
|
||||
<apn carrier="Bulsatcom" mcc="284" mnc="11" apn="bulsat.com" type="default,supl" />
|
||||
<apn carrier="Turkcell" mcc="286" mnc="01" apn="internet" type="default,supl" />
|
||||
<apn carrier="Turkcell MMS" mcc="286" mnc="01" apn="mms" user="mms" password="mms" mmsc="http://mms.turkcell.com.tr/servlets/mms" mmsproxy="212.252.169.217" mmsport="8080" type="mms" />
|
||||
<apn carrier="Vodafone TR" mcc="286" mnc="02" apn="internet" user="vodafone" password="vodafone" type="default,supl" />
|
||||
@@ -600,10 +603,10 @@
|
||||
<apn carrier="ProMonte MMS" mcc="297" mnc="01" apn="mms.promonte.com" user="mms" password="mms" mmsc=" http://mm.vor.promonte.com" mmsproxy="192.168.246.005" mmsport="8080" type="mms" />
|
||||
<apn carrier="T-Mobile CG MMS" mcc="297" mnc="02" apn="mms" user="38267" password="38267" mmsc="http://192.168.180.100/servlets/mms" mmsproxy="10.0.5.19" mmsport="8080" type="mms" />
|
||||
<apn carrier="T-Mobile CG" mcc="297" mnc="02" apn="tmcg-wnw" user="38267" password="38267" type="default,supl" />
|
||||
<apn carrier="Telus SP" mcc="302" mnc="220" apn="sp.telus.com" mmsc="http://aliasredirect.net/proxy/mmsc" mmsproxy="74.49.0.18" mmsport="80" type="default,supl,mms" />
|
||||
<apn carrier="Telus SP" mcc="302" mnc="220" apn="sp.telus.com" mmsc="http://aliasredirect.net/proxy/mmsc" mmsproxy="74.49.0.18" mmsport="80" mvno_match_data="54" mvno_type="gid" type="default,supl,mms" />
|
||||
<apn carrier="Telus SP Tether" mcc="302" mnc="220" apn="isp.telus.com" mmsc="http://aliasredirect.net/proxy/mmsc" mmsproxy="74.49.0.18" mmsport="80" type="default,supl,mms" />
|
||||
<apn carrier="Koodo SP" mcc="302" mnc="220" apn="sp.koodo.com" proxy="74.49.0.18" port="80" mmsc="http://aliasredirect.net/proxy/koodo/mmsc" mmsproxy="74.49.0.18" mmsport="80" type="default,supl,mms" />
|
||||
<apn carrier="Public Mobile" mcc="302" mnc="220" apn="sp.mb.com" mmsc="http://aliasredirect.net/proxy/mb/mmsc" mmsproxy="74.49.0.18" mmsport="80" type="default,supl,mms" />
|
||||
<apn carrier="Koodo SP" mcc="302" mnc="220" apn="sp.koodo.com" proxy="74.49.0.18" port="80" mmsc="http://aliasredirect.net/proxy/koodo/mmsc" mmsproxy="74.49.0.18" mmsport="80" mvno_match_data="4B" mvno_type="gid" type="default,supl,mms" />
|
||||
<apn carrier="Public Mobile" mcc="302" mnc="220" apn="sp.mb.com" mmsc="http://aliasredirect.net/proxy/mb/mmsc" mmsproxy="74.49.0.18" mmsport="80" mvno_match_data="50" mvno_type="gid" type="default,supl,mms" />
|
||||
<apn carrier="Eastlink Internet" mcc="302" mnc="270" apn="wisp.mobi.eastlink.ca" type="default,supl" />
|
||||
<apn carrier="Eastlink MMS" mcc="302" mnc="270" apn="mms.mobi.eastlink.ca" mmsc="http://mmss.mobi.eastlink.ca" mmsproxy="10.232.12.49" mmsport="8080" type="mms" />
|
||||
<apn carrier="Mobilicity MMS" mcc="302" mnc="320" apn="mms.davewireless.com" mmsc="http://mms.mobilicity.net" mmsproxy="10.100.3.4" mmsport="8080" type="mms" />
|
||||
@@ -683,12 +686,11 @@
|
||||
<apn carrier="Sprint EHRPD ota" mcc="310" mnc="120" apn="otasn" type="fota" protocol="IPV4V6" roaming_protocol="IPV4V6" bearer="13" />
|
||||
<apn carrier="Sprint LTE internet" mcc="310" mnc="120" apn="n.ispsn" type="default,mms,supl,hipri" mmsc="http://mms.sprintpcs.com" mmsproxy="68.28.31.7" mmsport="80" protocol="IPV4V6" roaming_protocol="IPV4V6" bearer="14" />
|
||||
<apn carrier="Sprint EHRPD internet" mcc="310" mnc="120" apn="n.ispsn" type="default,mms,supl,hipri" mmsc="http://mms.sprintpcs.com" mmsproxy="68.28.31.7" mmsport="80" protocol="IPV4V6" roaming_protocol="IPV4V6" bearer="13" />
|
||||
<apn carrier="Sprint internet" mcc="310" mnc="120" apn="n.ispsn" type="default,mms,supl,hipri" mmsc="http://mms.sprintpcs.com" mmsproxy="68.28.31.7" mmsport="80" protocol="IPV4V6" roaming_protocol="IPV4V6" />
|
||||
<apn carrier="Boost" mcc="310" mnc="120" apn="cinet.spcs" type="default,supl,mms,dun,fota" mmsc="http://mm.myboostmobile.com" mmsproxy="68.28.31.7" mmsport="80" protocol="IPV4V6" roaming_protocol="IPV4V6" />
|
||||
<apn carrier="Credo Mobile" mcc="310" mnc="120" apn="n.w1.ispsn" type="default,mms" mmsc="http://mms.plspictures.com" mmsproxy="68.28.31.7" mmsport="80" protocol="IPV4V6" roaming_protocol="IPV4V6" />
|
||||
<apn carrier="Ting" mcc="310" mnc="120" apn="n.t8.ispsn" type="default,mms" mmsc="http://mms.plspictures.com" mmsproxy="68.28.31.7" mmsport="80" protocol="IPV4V6" roaming_protocol="IPV4V6" />
|
||||
<apn carrier="FreedomPop" mcc="310" mnc="120" apn="n.f6.ispsn" type="default,mms" mmsc="http://mms.sprintpcs.com" mmsproxy="68.28.31.7" mmsport="80" protocol="IPV4V6" roaming_protocol="IPV4V6" />
|
||||
<apn carrier="Virgin Mobile" mcc="310" mnc="120" apn="n.vmu.ispsn" user="Sprint" password="*" mmsproxy="68.28.31.7" mmsport="80" mmsc="http://mmsc.vmobl.com:8088/mms?" type="default,supl,mms,fota,dun" />
|
||||
<apn carrier="Sprint internet" mcc="310" mnc="120" apn="n.ispsn" type="mms,supl,hipri" mmsc="http://mms.sprintpcs.com" mmsproxy="68.28.31.7" mmsport="80" protocol="IPV4V6" roaming_protocol="IPV4V6" />
|
||||
<apn carrier="Boost" mcc="310" mnc="120" apn="cinet.spcs" type="supl,mms,dun,fota" mmsc="http://mm.myboostmobile.com" mmsproxy="68.28.31.7" mmsport="80" protocol="IPV4V6" roaming_protocol="IPV4V6" />
|
||||
<apn carrier="Credo Mobile" mcc="310" mnc="120" apn="n.w1.ispsn" type="mms" mmsc="http://mms.plspictures.com" mmsproxy="68.28.31.7" mmsport="80" protocol="IPV4V6" roaming_protocol="IPV4V6" />
|
||||
<apn carrier="Ting" mcc="310" mnc="120" apn="n.t8.ispsn" type="mms" mmsc="http://mms.plspictures.com" mmsproxy="68.28.31.7" mmsport="80" protocol="IPV4V6" roaming_protocol="IPV4V6" />
|
||||
<apn carrier="Virgin Mobile" mcc="310" mnc="120" apn="n.vmu.ispsn" user="Sprint" password="*" mmsproxy="68.28.31.7" mmsport="80" mmsc="http://mmsc.vmobl.com:8088/mms?" type="supl,mms,fota,dun" />
|
||||
<apn carrier="My Multi Media" mcc="310" mnc="130" apn="mms.c1.ama" user="cell1mms" password="cell1" mmsc="http://mms.iot1.com/amarillo/mms.php" type="mms" />
|
||||
<apn carrier="Cricket AIO" mcc="310" mnc="150" apn="ndo" mmsc="http://mmsc.aiowireless.net" mmsproxy="proxy.aiowireless.net" mmsport="80" type="default,mms,fota,supl" />
|
||||
<apn carrier="T-Mobile US 160" mcc="310" mnc="160" apn="epc.tmobile.com" user="none" password="none" server="*" mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc" type="default,supl,mms" />
|
||||
@@ -706,6 +708,7 @@
|
||||
<apn carrier="Simple" mcc="310" mnc="260" apn="simple" mmsc="http://smpl.mms.msg.eng.t-mobile.com/mms/wapenc" type="default,supl,mms" />
|
||||
<apn carrier="StraightTalk T-Mobile" mcc="310" mnc="260" apn="wap.tracfone" port="8080" mmsc="http://mms.tracfone.com" type="default,supl,mms" />
|
||||
<apn carrier="Walmart Family Mobile" mcc="310" mnc="260" apn="web.omwtoday.com" mmsproxy="216.155.165.50" mmsport="8080" mmsc="http://wirelessfour.mmsmvno.com/mms/wapenc" type="default,supl,mms" />
|
||||
<apn carrier="Wholesale" mcc="310" mnc="260" apn="wholesale" mmsc="http://wholesale.mmsmvno.com/mms/wapenc" type="default,supl,mms" />
|
||||
<apn carrier="T-Mobile US 270" mcc="310" mnc="270" apn="epc.tmobile.com" user="none" password="none" server="*" mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc" type="default,supl,mms" />
|
||||
<apn carrier="T-Mobile US 310" mcc="310" mnc="310" apn="epc.tmobile.com" user="none" password="none" server="*" mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc" type="default,supl,mms" />
|
||||
<apn carrier="Cingular 380 ATT" mcc="310" mnc="380" apn="proxy" proxy="wireless.cingular.com" port="80" mmsc="http://mmsc.cingular.com/" mmsproxy="wireless.cingular.com" type="default,supl,mms" />
|
||||
@@ -830,7 +833,7 @@
|
||||
<apn carrier="LIME" mcc="344" mnc="920" apn="internet" type="default,supl" />
|
||||
<apn carrier="Digicel VC" mcc="360" mnc="070" apn="wap.digiceloecs.com" user="wapoecs" password="wap03oecs" type="default,supl" />
|
||||
<apn carrier="Setar MMS" mcc="363" mnc="01" apn="mms.setar.aw" mmsc="http://mms.setar.aw" mmsproxy="209.88.130.210" mmsport="8081" type="mms" />
|
||||
<apn carrier="Setar" mcc="363" mnc="01" apn="wap.setar.aw" type="default,supl" />
|
||||
<apn carrier="Setar" mcc="363" mnc="01" apn="internet.setar.aw" type="default,supl" />
|
||||
<apn carrier="BATELCO BS" mcc="364" mnc="390" apn="internet.btcbahamas.com" type="default,supl" />
|
||||
<apn carrier="Orange net" mcc="370" mnc="01" apn="orangenet.com.do" user="" password="" authtype="1" type="default,supl,dun" />
|
||||
<apn carrier="Orange MMS" mcc="370" mnc="01" apn="orangeworld" user="orange" password="orange" mmsproxy="172.16.126.70" mmsport="8080" mmsc="http://mms.orange.com.do/servlets/mms" authtype="1" type="mms" />
|
||||
@@ -841,6 +844,7 @@
|
||||
<apn carrier="BMobile Prepaid" mcc="374" mnc="12" apn="bconnected" type="default" port="8080" />
|
||||
<apn carrier="BMobile MMS" mcc="374" mnc="12" apn="mms" type="mms" mmsc="http://192.168.210.104/mmrelay.app" mmsproxy="192.168.210.104" mmsport="8080"/>
|
||||
<apn carrier="BMobile Buzz" mcc="374" mnc="12" apn="buzz" type="default,mms" proxy="192.168.210.104" port="8080" mmsc="http://192.168.210.103/operator/wap" />
|
||||
<apn carrier="Digicel TT" mcc="374" mnc="13" apn="web.digiceltt.com" type="default,supl" />
|
||||
<apn carrier="Azercell" mcc="400" mnc="01" apn="internet" type="default,supl" />
|
||||
<apn carrier="Azercell MMS" mcc="400" mnc="01" apn="mms" mmsc="http://mms.azercell.com/cMMSC/post" mmsproxy="10.0.154.101" mmsport="8080" type="mms" />
|
||||
<apn carrier="Bakcell" mcc="400" mnc="02" apn="mms" mmsc="http://mms.bakcell.com/mms/wapenc" mmsproxy="213.172.091.046" mmsport="8080" type="default,supl,mms" />
|
||||
@@ -850,17 +854,27 @@
|
||||
<apn carrier="Kcell MMS" mcc="401" mnc="02" apn="mms" mmsc="http://mms.kcell.kz/post" mmsproxy="195.047.255.007" mmsport="8080" type="mms" />
|
||||
<apn carrier="Vodafone IN MMS" mcc="404" mnc="01" apn="portalnmms" mmsc="http://mms1.live.vodafone.in/mms/" mmsproxy="10.10.1.100" mmsport="9401" type="mms" />
|
||||
<apn carrier="Vodafone IN" mcc="404" mnc="01" apn="www" type="default,supl" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="02" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="03" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="02" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="02" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="02" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="03" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="03" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="03" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="IDEA" mcc="404" mnc="04" apn="internet" type="default,supl" />
|
||||
<apn carrier="IDEA MMS" mcc="404" mnc="04" apn="mmsc" mmsc="http://10.4.42.21:8002/" mmsproxy="10.4.42.15" mmsport="8080" type="mms" />
|
||||
<apn carrier="Vodafone IN MMS" mcc="404" mnc="05" apn="portalnmms" mmsc="http://mms1.live.vodafone.in/mms/" mmsproxy="10.10.1.100" mmsport="9401" type="mms" />
|
||||
<apn carrier="Vodafone IN" mcc="404" mnc="05" apn="www" type="default,supl" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="06" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="06" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="06" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="IDEA" mcc="404" mnc="07" apn="internet" type="default,supl" />
|
||||
<apn carrier="IDEA MMS" mcc="404" mnc="07" apn="mmsc" mmsc="http://10.4.42.21:8002/" mmsproxy="10.4.42.15" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance MMS" mcc="404" mnc="09" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="404" mnc="09" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="10" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Reliance RTel MMS" mcc="404" mnc="09" apn="MMS" mmsc="http://10.239.221.47/mms/" mmsproxy="10.239.221.7" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance RTel" mcc="404" mnc="09" apn="SMARTNET" type="default,supl" />
|
||||
<apn carrier="Reliance WAP" mcc="404" mnc="09" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="10" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="10" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="10" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Vodafone IN MMS" mcc="404" mnc="11" apn="portalnmms" mmsc="http://mms1.live.vodafone.in/mms/" mmsproxy="10.10.1.100" mmsport="9401" type="mms" />
|
||||
<apn carrier="Vodafone IN" mcc="404" mnc="11" apn="www" type="default,supl" />
|
||||
<apn carrier="IDEA" mcc="404" mnc="12" apn="internet" type="default,supl" />
|
||||
@@ -874,11 +888,14 @@
|
||||
<apn carrier="SPICE MMS" mcc="404" mnc="14" apn="spicemms" user="User Mobile number" password="spice" mmsc="http://10.200.200.3:8514" mmsproxy="10.200.200.3" mmsport="8080" type="mms" />
|
||||
<apn carrier="Vodafone IN MMS" mcc="404" mnc="15" apn="portalnmms" mmsc="http://mms1.live.vodafone.in/mms/" mmsproxy="10.10.1.100" mmsport="9401" type="mms" />
|
||||
<apn carrier="Vodafone IN" mcc="404" mnc="15" apn="www" type="default,supl" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="16" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="16" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="16" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="16" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Aircel" mcc="404" mnc="17" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="17" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Reliance MMS" mcc="404" mnc="18" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="17" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance MMS" mcc="404" mnc="18" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="404" mnc="18" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance WAP" mcc="404" mnc="18" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="IDEA" mcc="404" mnc="19" apn="internet" type="default,supl" />
|
||||
<apn carrier="IDEA MMS" mcc="404" mnc="19" apn="mmsc" mmsc="http://10.4.42.21:8002/" mmsproxy="10.4.42.15" mmsport="8080" type="mms" />
|
||||
<apn carrier="Vodafone IN MMS" mcc="404" mnc="20" apn="portalnmms" mmsc="http://mms1.live.vodafone.in/mms/" mmsproxy="10.10.1.100" mmsport="9401" type="mms" />
|
||||
@@ -890,49 +907,60 @@
|
||||
<apn carrier="IDEA" mcc="404" mnc="24" apn="internet" type="default,supl" />
|
||||
<apn carrier="IDEA MMS" mcc="404" mnc="24" apn="mmsc" mmsc="http://10.4.42.21:8002/" mmsproxy="10.4.42.15" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="404" mnc="25" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="25" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="25" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Vodafone IN MMS" mcc="404" mnc="27" apn="portalnmms" mmsc="http://mms1.live.vodafone.in/mms/" mmsproxy="10.10.1.100" mmsport="9401" type="mms" />
|
||||
<apn carrier="Vodafone IN" mcc="404" mnc="27" apn="www" type="default,supl" />
|
||||
<apn carrier="Aircel" mcc="404" mnc="28" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="28" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="28" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="404" mnc="29" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="29" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="29" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Vodafone IN MMS" mcc="404" mnc="30" apn="portalnmms" mmsc="http://mms1.live.vodafone.in/mms/" mmsproxy="10.10.1.100" mmsport="9401" type="mms" />
|
||||
<apn carrier="Vodafone IN" mcc="404" mnc="30" apn="www" type="default,supl" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="31" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="31" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="31" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="31" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Aircel" mcc="404" mnc="33" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="33" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="33" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="BSNL" mcc="404" mnc="34" apn="bsnlnet" user="MSISDN" password="MSISDN" type="default,supl" />
|
||||
<apn carrier="BSNL MMS" mcc="404" mnc="34" apn="mmssouth.cellone.in" user="MSISDN" password="mmsc" mmsc="http://10.7.236.11:8514" mmsproxy="10.7.236.11" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="404" mnc="35" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="35" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Reliance MMS" mcc="404" mnc="36" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="35" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance MMS" mcc="404" mnc="36" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="404" mnc="36" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance WAP" mcc="404" mnc="36" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Aircel" mcc="404" mnc="37" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="37" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="37" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="BSNL" mcc="404" mnc="38" apn="bsnlnet" user="MSISDN" password="MSISDN" type="default,supl" />
|
||||
<apn carrier="BSNL MMS" mcc="404" mnc="38" apn="mmssouth.cellone.in" user="MSISDN" password="mmsc" mmsc="http://10.7.236.11:8514" mmsproxy="10.7.236.11" mmsport="8080" type="mms" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="40" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="40" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="40" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="40" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Aircel" mcc="404" mnc="41" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="41" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="41" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="404" mnc="42" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="42" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="42" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Vodafone IN MMS" mcc="404" mnc="43" apn="portalnmms" mmsc="http://mms1.live.vodafone.in/mms/" mmsproxy="10.10.1.100" mmsport="9401" type="mms" />
|
||||
<apn carrier="Vodafone IN" mcc="404" mnc="43" apn="www" type="default,supl" />
|
||||
<apn carrier="IDEA" mcc="404" mnc="44" apn="internet" type="default,supl" />
|
||||
<apn carrier="IDEA MMS" mcc="404" mnc="44" apn="mmsc" mmsc="http://10.4.42.21:8002/" mmsproxy="10.4.42.15" mmsport="8080" type="mms" />
|
||||
<apn carrier="SPICE" mcc="404" mnc="44" apn="spicegprs" type="default,supl" />
|
||||
<apn carrier="SPICE MMS" mcc="404" mnc="44" apn="spicemms" user="User Mobile number" password="spice" mmsc="http://10.200.200.3:8514" mmsproxy="10.200.200.3" mmsport="8080" type="mms" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="45" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="45" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="45" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="45" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="BPL MMS" mcc="404" mnc="46" apn="mizone" user="MSISDN" password="bplmmsc" mmsc="http://mms.bplmobile.com:8080" mmsproxy="10.0.0.10" mmsport="8080" type="mms" />
|
||||
<apn carrier="BPL" mcc="404" mnc="46" apn="www" user="MSISDN" password="bplmmsc" type="default,supl" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="49" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Reliance MMS" mcc="404" mnc="50" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="49" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="49" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="49" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Reliance MMS" mcc="404" mnc="50" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="404" mnc="50" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance WAP" mcc="404" mnc="50" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="BSNL" mcc="404" mnc="51" apn="bsnlnet" user="MSISDN" password="MSISDN" type="default,supl" />
|
||||
<apn carrier="BSNL MMS" mcc="404" mnc="51" apn="mmssouth.cellone.in" user="MSISDN" password="mmsc" mmsc="http://10.7.236.11:8514" mmsproxy="10.7.236.11" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance MMS" mcc="404" mnc="52" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance MMS" mcc="404" mnc="52" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="404" mnc="52" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance WAP" mcc="404" mnc="52" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="BSNL" mcc="404" mnc="53" apn="bsnlnet" user="MSISDN" password="MSISDN" type="default,supl" />
|
||||
<apn carrier="BSNL MMS" mcc="404" mnc="53" apn="mmssouth.cellone.in" user="MSISDN" password="mmsc" mmsc="http://10.7.236.11:8514" mmsproxy="10.7.236.11" mmsport="8080" type="mms" />
|
||||
<apn carrier="BSNL" mcc="404" mnc="54" apn="bsnlnet" user="MSISDN" password="MSISDN" type="default,supl" />
|
||||
@@ -949,19 +977,25 @@
|
||||
<apn carrier="BSNL MMS" mcc="404" mnc="59" apn="mmssouth.cellone.in" user="MSISDN" password="mmsc" mmsc="http://10.7.236.11:8514" mmsproxy="10.7.236.11" mmsport="8080" type="mms" />
|
||||
<apn carrier="Vodafone IN MMS" mcc="404" mnc="60" apn="portalnmms" mmsc="http://mms1.live.vodafone.in/mms/" mmsproxy="10.10.1.100" mmsport="9401" type="mms" />
|
||||
<apn carrier="Vodafone IN" mcc="404" mnc="60" apn="www" type="default,supl" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="61" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="61" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="61" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.001.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="BSNL" mcc="404" mnc="62" apn="bsnlnet" user="MSISDN" password="MSISDN" type="default,supl" />
|
||||
<apn carrier="BSNL MMS" mcc="404" mnc="62" apn="mmssouth.cellone.in" user="MSISDN" password="mmsc" mmsc="http://10.7.236.11:8514" mmsproxy="10.7.236.11" mmsport="8080" type="mms" />
|
||||
<apn carrier="BSNL" mcc="404" mnc="64" apn="bsnlnet" user="MSISDN" password="MSISDN" type="default,supl" />
|
||||
<apn carrier="BSNL MMS" mcc="404" mnc="64" apn="mmssouth.cellone.in" user="MSISDN" password="mmsc" mmsc="http://10.7.236.11:8514" mmsproxy="10.7.236.11" mmsport="8080" type="mms" />
|
||||
<apn carrier="BSNL" mcc="404" mnc="66" apn="bsnlnet" user="MSISDN" password="MSISDN" type="default,supl" />
|
||||
<apn carrier="BSNL MMS" mcc="404" mnc="66" apn="mmssouth.cellone.in" user="MSISDN" password="mmsc" mmsc="http://10.7.236.11:8514" mmsproxy="10.7.236.11" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance MMS" mcc="404" mnc="67" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance MMS" mcc="404" mnc="67" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="404" mnc="67" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance WAP" mcc="404" mnc="67" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="MTNL" mcc="404" mnc="68" apn="mtnl.net" user="mtnl" password="mtnl123" proxy="10.10.10.10" port="9401" type="default,supl" />
|
||||
<apn carrier="MTNL MMS" mcc="404" mnc="68" apn="mtnl.net" user="mtnl" password="mtnl123" mmsc="http://mtnlmms/" mmsproxy="10.10.10.10" mmsport="9401" type="mms" />
|
||||
<apn carrier="MTNL" mcc="404" mnc="69" apn="mtnl.net" user="mtnl" password="mtnl123" proxy="10.10.10.10" port="9401" type="default,supl" />
|
||||
<apn carrier="MTNL MMS" mcc="404" mnc="69" apn="mtnl.net" user="mtnl" password="mtnl123" mmsc="http://mtnlmms/" mmsproxy="10.10.10.10" mmsport="9401" type="mms" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="70" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="70" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="70" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="70" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="BSNL" mcc="404" mnc="71" apn="bsnlnet" user="MSISDN" password="MSISDN" type="default,supl" />
|
||||
<apn carrier="BSNL MMS" mcc="404" mnc="71" apn="mmssouth.cellone.in" user="MSISDN" password="mmsc" mmsc="http://10.7.236.11:8514" mmsproxy="10.7.236.11" mmsport="8080" type="mms" />
|
||||
<apn carrier="BSNL" mcc="404" mnc="72" apn="bsnlnet" user="MSISDN" password="MSISDN" type="default,supl" />
|
||||
@@ -984,13 +1018,14 @@
|
||||
<apn carrier="BSNL MMS" mcc="404" mnc="81" apn="mmssouth.cellone.in" user="MSISDN" password="mmsc" mmsc="http://10.7.236.11:8514" mmsproxy="10.7.236.11" mmsport="8080" type="mms" />
|
||||
<apn carrier="IDEA" mcc="404" mnc="82" apn="internet" type="default,supl" />
|
||||
<apn carrier="IDEA MMS" mcc="404" mnc="82" apn="mmsc" mmsc="http://10.4.42.21:8002/" mmsproxy="10.4.42.15" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance MMS" mcc="404" mnc="83" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance MMS" mcc="404" mnc="83" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="404" mnc="83" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance WAP" mcc="404" mnc="83" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Vodafone IN MMS" mcc="404" mnc="84" apn="portalnmms" mmsc="http://mms1.live.vodafone.in/mms/" mmsproxy="10.10.1.100" mmsport="9401" type="mms" />
|
||||
<apn carrier="Vodafone IN" mcc="404" mnc="84" apn="www" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="404" mnc="85" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance MMS" mcc="404" mnc="85" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="404" mnc="85" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="India Hutch" mcc="404" mnc="86" apn="portalnmms" proxy="10.10.1.100" port="9401" mmsc="http://mms1.hutchworld.co.in/mms/" type="default,supl,mms" />
|
||||
<apn carrier="Reliance WAP" mcc="404" mnc="85" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Vodafone IN MMS" mcc="404" mnc="86" apn="portalnmms" mmsc="http://mms1.live.vodafone.in/mms/" mmsproxy="10.10.1.100" mmsport="9401" type="mms" />
|
||||
<apn carrier="Vodafone IN" mcc="404" mnc="86" apn="www" type="default,supl" />
|
||||
<apn carrier="IDEA" mcc="404" mnc="87" apn="internet" type="default,supl" />
|
||||
@@ -999,57 +1034,92 @@
|
||||
<apn carrier="Vodafone IN" mcc="404" mnc="88" apn="www" type="default,supl" />
|
||||
<apn carrier="IDEA" mcc="404" mnc="89" apn="internet" type="default,supl" />
|
||||
<apn carrier="IDEA MMS" mcc="404" mnc="89" apn="mmsc" mmsc="http://10.4.42.21:8002/" mmsproxy="10.4.42.15" mmsport="8080" type="mms" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="90" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="90" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="90" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="90" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Aircel" mcc="404" mnc="91" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="91" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="92" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="93" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="94" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="95" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="96" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="97" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel" mcc="404" mnc="98" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Vodafone IN MMS" mcc="404" mnc="751" apn="portalnmms" mmsc="http://mms1.live.vodafone.in/mms/" mmsproxy="10.10.1.100" mmsport="9401" type="mms" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="01" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="404" mnc="91" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="92" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="92" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="92" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="93" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="93" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="93" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="94" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="94" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="94" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="95" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="95" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="95" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="96" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="96" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="96" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="97" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="97" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="97" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="404" mnc="98" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="404" mnc="98" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="404" mnc="98" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="01" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://10.239.221.47/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="01" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="03" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="01" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="03" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="03" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="05" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="03" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="05" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="05" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="06" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="05" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="06" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="06" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="07" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="06" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="07" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="07" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="08" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="07" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="08" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="08" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="09" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="08" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="09" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="09" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="10" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="09" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="10" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="10" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="11" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="10" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="11" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="11" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="12" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="11" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="12" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="12" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="13" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="12" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="13" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="13" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="14" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="13" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="14" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="14" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="15" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="14" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="15" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="15" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="17" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="15" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="17" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="17" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="18" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="17" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="18" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="18" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="19" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="18" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="19" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="19" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="20" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="19" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="20" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="20" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="21" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="20" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="21" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="21" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="22" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="21" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="22" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="22" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="23" apn="rcommms" mmsc="http://mms.rcom.co.in:6081/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="22" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="Reliance MMS" mcc="405" mnc="23" apn="rcommms" proxy="10.239.221.5" port="8080" mmsc="http://mms.rcom.co.in/mms" mmsproxy="10.239.221.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Reliance" mcc="405" mnc="23" apn="rcomnet" type="default,supl" />
|
||||
<apn carrier="Reliance WAP" mcc="405" mnc="23" apn="rcomwap" proxy="10.239.221.5" port="8080" type="default,supl" />
|
||||
<apn carrier="TA TA DoCoMo" mcc="405" mnc="025" apn="TATA.DOCOMO.INTERNET" type="default,supl" />
|
||||
<apn carrier="TA TA DoCoMo MMS" mcc="405" mnc="025" apn="TATA.DOCOMO.MMS" mmsc="http://mmsc/" mmsproxy="10.124.26.94" mmsport="8799" type="mms" />
|
||||
<apn carrier="TA TA DoCoMo" mcc="405" mnc="026" apn="TATA.DOCOMO.INTERNET" type="default,supl" />
|
||||
@@ -1094,12 +1164,24 @@
|
||||
<apn carrier="TA TA DoCoMo MMS" mcc="405" mnc="046" apn="TATA.DOCOMO.MMS" mmsc="http://mmsc/" mmsproxy="10.124.26.94" mmsport="8799" type="mms" />
|
||||
<apn carrier="TA TA DoCoMo" mcc="405" mnc="047" apn="TATA.DOCOMO.INTERNET" type="default,supl" />
|
||||
<apn carrier="TA TA DoCoMo MMS" mcc="405" mnc="047" apn="TATA.DOCOMO.MMS" mmsc="http://mmsc/" mmsproxy="10.124.26.94" mmsport="8799" type="mms" />
|
||||
<apn carrier="Airtel" mcc="405" mnc="51" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel" mcc="405" mnc="52" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel" mcc="405" mnc="53" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel" mcc="405" mnc="54" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel" mcc="405" mnc="55" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel" mcc="405" mnc="56" apn="airtelgprs.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="default,supl,mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="405" mnc="51" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="405" mnc="51" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="405" mnc="51" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="405" mnc="52" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="405" mnc="52" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="405" mnc="52" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="405" mnc="53" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="405" mnc="53" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="405" mnc="53" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="405" mnc="54" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="405" mnc="54" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="405" mnc="54" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="405" mnc="55" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="405" mnc="55" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="405" mnc="55" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Airtel GPRS" mcc="405" mnc="56" apn="airtelgprs.com" type="default,supl" />
|
||||
<apn carrier="Airtel Live" mcc="405" mnc="56" apn="airtelfun.com" proxy="100.1.200.99" port="8080" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="405" mnc="56" apn="airtelmms.com" mmsc="http://100.1.201.171:10021/mmsc" mmsproxy="100.1.201.172" mmsport="8799" type="mms" />
|
||||
<apn carrier="Vodafone IN MMS" mcc="405" mnc="66" apn="portalnmms" mmsc="http://mms1.live.vodafone.in/mms/" mmsproxy="10.10.1.100" mmsport="9401" type="mms" />
|
||||
<apn carrier="Vodafone IN" mcc="405" mnc="66" apn="www" type="default,supl" />
|
||||
<apn carrier="Vodafone IN MMS" mcc="405" mnc="67" apn="portalnmms" mmsc="http://mms1.live.vodafone.in/mms/" mmsproxy="10.10.1.100" mmsport="9401" type="mms" />
|
||||
@@ -1122,29 +1204,31 @@
|
||||
<apn carrier="IDEA" mcc="405" mnc="799" apn="internet" type="default,supl" />
|
||||
<apn carrier="IDEA MMS" mcc="405" mnc="799" apn="mmsc" mmsc="http://10.4.42.21:8002/" mmsproxy="10.4.42.15" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="405" mnc="800" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="800" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="800" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="405" mnc="801" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="801" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="801" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="405" mnc="802" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="802" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="802" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="405" mnc="803" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="803" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="803" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="405" mnc="804" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="804" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="804" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="405" mnc="805" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="805" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="805" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="405" mnc="806" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="806" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="405" mnc="807" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="807" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="807" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="405" mnc="808" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="808" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="808" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="405" mnc="809" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="809" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="809" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="405" mnc="810" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="810" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="810" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="405" mnc="811" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="811" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="811" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="Aircel" mcc="405" mnc="812" apn="aircelgprs" type="default,supl" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="812" apn="aircelmms" mmsc="http://mmsc/mmrelay.app" mmsproxy="192.168.35.196" mmsport="8081" type="mms" />
|
||||
<apn carrier="Aircel MMS" mcc="405" mnc="812" apn="aircelmms" proxy="172.17.83.69" port="8080" mmsc="http://172.17.83.67//servlets/mms" mmsproxy="172.17.83.69" mmsport="8080" type="mms" />
|
||||
<apn carrier="IDEA" mcc="405" mnc="845" apn="internet" type="default,supl" />
|
||||
<apn carrier="IDEA MMS" mcc="405" mnc="845" apn="mmsc" mmsc="http://10.4.42.21:8002/" mmsproxy="10.4.42.15" mmsport="8080" type="mms" />
|
||||
<apn carrier="IDEA" mcc="405" mnc="846" apn="internet" type="default,supl" />
|
||||
@@ -1193,11 +1277,24 @@
|
||||
<apn carrier="Etisalat MMS" mcc="412" mnc="50" apn="etisalat.af.mms" proxy="10.0.0.172" port="80" type="mms" />
|
||||
<apn carrier="Mobitel" mcc="413" mnc="01" apn="mobitel3g" type="default,supl" />
|
||||
<apn carrier="Mobitel MMS" mcc="413" mnc="01" apn="wapmms" mmsc="http://192.168.50.165" mmsproxy="192.168.50.163" mmsport="8080" type="mms" />
|
||||
<apn carrier="Mobitel WAP" mcc="413" mnc="01" apn="mobitel3g" proxy="192.168.050.163" port="8080" type="default,supl" />
|
||||
<apn carrier="Dialog Mobile Broadband" mcc="413" mnc="02" apn="dialogbb" server="dialog" mmsc="http://mms.dialog.lk:3130/mmsc" mmsproxy="192.168.122.2" mmsport="8080" type="default,supl,mms" />
|
||||
<apn carrier="Dialog WAP Prepaid" mcc="413" mnc="02" apn="ppwap" proxy="192.168.122.2" mmsport="8080" type="default,supl" />
|
||||
<apn carrier="Dialog Internet Prepaid" mcc="413" mnc="02" apn="www.dialogsl.com" proxy="192.168.122.2" port="8080" type="default,supl" />
|
||||
<apn carrier="Dialog Internet Postpaid" mcc="413" mnc="02" apn="dialogbb" type="default,supl" />
|
||||
<apn carrier="Dialog MMS Prepaid" mcc="413" mnc="02" apn="ppwap" mmsc="http://mms.dialog.lk:3130/mmsc" mmsproxy="192.168.122.2" type="mms" />
|
||||
<apn carrier="Dialog MMS Postpaid" mcc="413" mnc="02" apn="www.dialogsl.com" mmsc="http://mms.dialog.lk:3130/mmsc" mmsproxy="192.168.122.2" type="mms" />
|
||||
<apn carrier="Etisalat" mcc="413" mnc="03" apn="ebb" type="default,supl" />
|
||||
<apn carrier="Etisalat MMS" mcc="413" mnc="03" apn="mms" mmsc="http://mms.etisalt.lk:8085" mmsproxy="192.168.104.4" mmsport="9401" type="mms" />
|
||||
<apn carrier="Etisalat Internet Prepaid" mcc="413" mnc="03" apn="web" type="default,supl" />
|
||||
<apn carrier="Etisalat Internet Postpaid" mcc="413" mnc="03" apn="internet" type="default,supl" />
|
||||
<apn carrier="Etisalat WAP" mcc="413" mnc="03" apn="wap" proxy="192.168.104.4" port="9401" type="default,supl" />
|
||||
<apn carrier="Airtel Postpaid" mcc="413" mnc="05" apn="airteldata" type="default,supl" />
|
||||
<apn carrier="Airtel MMS" mcc="413" mnc="05" apn="airtellive" mmsc="http://mms.airtel.lk" mmsproxy="10.200.184.86" mmsport="8080" type="mms" />
|
||||
<apn carrier="Airtel Prepaid" mcc="413" mnc="05" apn="airtellive" type="default,supl" />
|
||||
<apn carrier="Airtel" mcc="413" mnc="05" apn="default" type="default,supl" />
|
||||
<apn carrier="Hutch3G" mcc="413" mnc="08" apn="hutch3g" type="default,supl" />
|
||||
<apn carrier="Hutch WAP" mcc="413" mnc="08" apn="hutch3g" proxy="10.220.135.249" port="8080" type="default,supl" />
|
||||
<apn carrier="MPT" mcc="414" mnc="01" apn="mptnet" user="mptnet" password="mptnet" type="default,supl" />
|
||||
<apn carrier="Alfa" mcc="415" mnc="01" apn="internet.mic1.com.lb" user="mic1" password="mic1" type="default,supl" />
|
||||
<apn carrier="Alfa MMS" mcc="415" mnc="01" apn="mms.mic1.com.lb" user="mic1" password="mic1" mmsc="http://mms.mic1.com.lb" mmsproxy="192.168.23.51" mmsport="9201" type="mms" />
|
||||
@@ -1256,7 +1353,7 @@
|
||||
<apn carrier="3G Portal" mcc="425" mnc="01" apn="uwap.orange.co.il" port="8080" type="default,supl" />
|
||||
<apn carrier="MMS 3G" mcc="425" mnc="01" apn="uwap.orange.co.il" mmsc="http://192.168.220.15/servlets/mms" mmsport="8080" type="mms" />
|
||||
<apn carrier="Internet 3G" mcc="425" mnc="01" apn="modem.orange.net.il" type="default,supl" />
|
||||
<apn carrier="CellCOM" mcc="425" mnc="02" apn="internetg" type="default,supl" />
|
||||
<apn carrier="CellCOM" mcc="425" mnc="02" apn="sphone" type="default,supl" />
|
||||
<apn carrier="CellCOM MMS" mcc="425" mnc="02" apn="mms" user="" password="" mmsc="http://mms.cellcom.co.il" mmsproxy="172.31.29.38" mmsport="8080" type="mms" />
|
||||
<apn carrier="Pelephone" mcc="425" mnc="03" apn="internet.pelephone.net.il" user="pcl@3g" password="pcl" type="default,supl" />
|
||||
<apn carrier="Pelephone MMS" mcc="425" mnc="03" apn="mms.pelephone.net.il" user="pcl@3g" password="pcl" server="pelephone" mmsc="http://mmsu.pelephone.net.il" mmsproxy="10.170.9.54" mmsport="9093" type="mms" />
|
||||
@@ -1281,20 +1378,29 @@
|
||||
<apn carrier="Q-tel" mcc="427" mnc="01" apn="web.qtel" user="gprs" password="gprs" type="default,supl" />
|
||||
<apn carrier="Vodafone QA MMS" mcc="427" mnc="02" apn="vodafone.com.qa" mmsc="http://mms.vodafone.com.qa/mmsc" mmsproxy="10.101.97.102" mmsport="80" type="mms" />
|
||||
<apn carrier="Vodafone QA" mcc="427" mnc="02" apn="web.vodafone.com.qa" type="default,supl" />
|
||||
<apn carrier="Nepal Telecom Internet" mcc="429" mnc="01" apn="ntnet" type="default,supl" />
|
||||
<apn carrier="Nepal Telecom MMS" mcc="429" mnc="01" apn="ntmms" mmsc="http://192.80.11.180" mmsproxy="192.80.7.133" mmsport="8000" type="mms" />
|
||||
<apn carrier="Nepal Telecom WAP" mcc="429" mnc="02" apn="ntwap" proxy="192.80.7.133" port="8000" type="default,supl" />
|
||||
<apn carrier="Ncell Internet" mcc="429" mnc="02" apn="web" type="default,supl" />
|
||||
<apn carrier="Ncell MMS" mcc="429" mnc="02" apn="mms" mmsc="http://192.168.19.15" mmsproxy="192.168.19.15" mmsport="8080" type="mms" />
|
||||
<apn carrier="Ncell WAP" mcc="429" mnc="02" apn="web" proxy="192.168.19.15" port="8080" type="default,supl" />
|
||||
<apn carrier="Beeline UZ" mcc="434" mnc="04" apn="internet.beeline.uz" user="beeline" password="beeline" type="default,supl" />
|
||||
<apn carrier="Beeline UZ MMS" mcc="434" mnc="04" apn="mms.beeline.uz" user="beeline" password="beeline" mmsc="http://mms" mmsproxy="172.30.30.166" mmsport="8080" type="mms" />
|
||||
<apn carrier="em.std" mcc="440" mnc="00" apn="em.std" user="em" password="em" type="default,supl" bearer="14"/>
|
||||
<apn carrier="@nifty" mcc="440" mnc="10" apn="lte.fenics.jp" user="nifty@lte.nifty.com" password="nifty" authtype="3" type="default,supl" />
|
||||
<apn carrier="@nifty do LTE" mcc="440" mnc="10" apn="lte.fenics.jp" user="nifty@lte.nifty.com" password="nifty" authtype="3" type="default,supl" />
|
||||
<apn carrier="BB.excite" mcc="440" mnc="10" apn="vmobile.jp" user="bb@excite.co.jp" password="excite" authtype="3" type="default,supl" />
|
||||
<apn carrier="BIGLOBE" mcc="440" mnc="10" apn="biglobe.jp" user="user" password="0000" authtype="2" type="default,supl" />
|
||||
<apn carrier="DMM mobile" mcc="440" mnc="10" apn="vmobile.jp" user="dmm@dmm.com" password="dmm" authtype="3" type="default,supl" />
|
||||
<apn carrier="DTI" mcc="440" mnc="10" apn="dream.jp" user="user@dream.jp" password="dti" authtype="2" type="default,supl" />
|
||||
<apn carrier="IIJmio/BIC SIM" mcc="440" mnc="10" apn="iijmio.jp" user="mio@iij" server="" password="iij" authtype="3" type="default,supl" />
|
||||
<apn carrier="IIJmio/BIC SIM" mcc="440" mnc="10" apn="iijmio.jp" user="mio@iij" password="iij" authtype="3" type="default,supl" />
|
||||
<apn carrier="NifMo" mcc="440" mnc="10" apn="mda.nifty.com" user="mda@nifty" password="nifty" authtype="3" type="default,supl" />
|
||||
<apn carrier="OCN 3G" mcc="440" mnc="10" apn="3g-d-2.ocn.ne.jp" user="mobileid@ocn" password="mobile" authtype="2" type="default,supl" />
|
||||
<apn carrier="OCN LTE" mcc="440" mnc="10" apn="lte-d.ocn.ne.jp" user="mobileid@ocn" password="mobile" authtype="2" type="default,supl" />
|
||||
<apn carrier="So-net" mcc="440" mnc="10" apn="so-net.jp" user="nuro" password="nuro" authtype="2" type="default,supl" />
|
||||
<apn carrier="U-mobile" mcc="440" mnc="10" apn="umobile.jp" user="umobile@umobile.jp" password="umobile" authtype="3" type="default,supl" />
|
||||
<apn carrier="U-mobile/freetel" mcc="440" mnc="10" apn="umobile.jp" user="umobile@umobile.jp" password="umobile" authtype="3" type="default,supl" />
|
||||
<apn carrier="Wi-Ho!" mcc="440" mnc="10" apn="bbnw.jp" user="user" password="0000" authtype="3" type="default,supl" />
|
||||
<apn carrier="WirelessGate 3G" mcc="440" mnc="10" apn="foma01.wi-gate.net" user="wg@sim" password="wg" authtype="3" type="default,supl" />
|
||||
<apn carrier="WirelessGate LTE" mcc="440" mnc="10" apn="foma01.wi-gate.net" user="wg@sim" password="wg" authtype="3" type="default,supl" />
|
||||
<apn carrier="WirelessGate LTE" mcc="440" mnc="10" apn="xi01.wi-gate.net" user="wg@sim" password="wg" authtype="3" type="default,supl" />
|
||||
<apn carrier="b-mobile 4g" mcc="440" mnc="10" apn="bmobile.ne.jp" user="bmobile@4g" password="bmobile" authtype="3" type="default,supl" />
|
||||
<apn carrier="b-mobile aeon" mcc="440" mnc="10" apn="bmobile.ne.jp" user="bmobile@aeon" password="bmobile" authtype="3" type="default,supl" />
|
||||
<apn carrier="b-mobile am" mcc="440" mnc="10" apn="bmobile.ne.jp" user="bmobile@am" password="bmobile" authtype="3" type="default,supl" />
|
||||
@@ -1310,9 +1416,11 @@
|
||||
<apn carrier="mopera U FF" mcc="440" mnc="10" apn="open.mopera.net" type="default,supl" />
|
||||
<apn carrier="mopera U Flat" mcc="440" mnc="10" apn="mopera.flat.foma.ne.jp" type="default,supl" />
|
||||
<apn carrier="spモード" mcc="440" mnc="10" apn="spmode.ne.jp" type="default,supl" />
|
||||
<apn carrier="楽天" mcc="440" mnc="10" apn="dm.jplat.net" user="mobile@rakutenbb.jp" password="rakutenbb" authtype="3" type="default,supl" />
|
||||
<apn carrier="楽天ブロードバンド" mcc="440" mnc="10" apn="dm.jplat.net" user="mobile@rakutenbb.jp" password="rakutenbb" authtype="3" type="default,supl" />
|
||||
<apn carrier="楽天モバイル" mcc="440" mnc="10" apn="vdm.jp" user="rakuten@vdm" password="vrkt" authtype="3" type="default,supl" />
|
||||
<apn carrier="Y!mobile" mcc="440" mnc="20" apn="plus.acs.jp" user="ym" password="ym" mmsc="http://mms-s" mmsproxy="andmms.plusacs.ne.jp" mmsport="8080" authtype="2" type="default,supl,mms" />
|
||||
<apn carrier="andoworld" mcc="440" mnc="20" apn="andoworld.softbank.ne.jp" mmsc="http://mms/" mmsproxy="andmms.softbank.ne.jp" mmsport="8080" authtype="2" type="default,supl,mms" />
|
||||
<apn carrier="fourgsmartphone" mcc="440" mnc="20" apn="fourgsmartphone" user="" password="" mmsc="http://mms/" mmsproxy="andmms.softbank.ne.jp" mmsport="8080" authtype="2" type="default,supl,mms" />
|
||||
<apn carrier="jpspir" mcc="440" mnc="20" apn="jpspir" user="sirobit" password="amstkoi" mmsc="http://mms/" mmsproxy="smilemms.softbank.ne.jp" mmsport="8080" type="default,supl,mms" />
|
||||
<apn carrier="open" mcc="440" mnc="20" apn="open.softbank.ne.jp" user="opensoftbank" password="ebMNuX1FIHg9d3DA" mmsc="http://mms/" mmsproxy="mmsopen.softbank.ne.jp" mmsport="8080" type="default,supl,mms" />
|
||||
<apn carrier="plus" mcc="440" mnc="20" apn="plus.softbank" user="plus" password="softbank" mmsc="http://mms/" mmsproxy="andmms.softbank.ne.jp" mmsport="8080" authtype="3" type="default,supl,mms" />
|
||||
@@ -1321,6 +1429,7 @@
|
||||
<apn carrier="smile.world" mcc="440" mnc="20" apn="smile.world" user="dna1trop" password="so2t3k3m2a" mmsc="http://mms/" mmsproxy="smilemms.softbank.ne.jp" mmsport="8080" authtype="1" type="default,supl,mms" />
|
||||
<apn carrier="LTE NET" mcc="440" mnc="50" apn="uno.au-net.ne.jp" user="685840734641020@uno.au-net.ne.jp" password="KpyrR6BP" authtype="2" type="default,mms,supl,hipri" protocol="IPV4V6" roaming_protocol="IP" />
|
||||
<apn carrier="LTE NET for DATA" mcc="440" mnc="50" apn="au.au-net.ne.jp" user="user@au.au-net.ne.jp" password="au" authtype="2" type="default,mms,supl,hipri" protocol="IPV4V6" roaming_protocol="IP" />
|
||||
<apn carrier="UQ mobile" mcc="440" mnc="50" apn="uqmobile.jp" user="uq@uqmobile.jp" password="uq" mmsc="http://mms.ezweb.ne.jp/MMS" mmsport="80" authtype="2" type="default,supl,hipri,dun" />
|
||||
<apn carrier="mineo" mcc="440" mnc="50" apn="mineo.jp" user="mineo@k-opti.com" password="mineo" authtype="2" type="default,supl,hipri" />
|
||||
<apn carrier="SKT3G" mcc="450" mnc="05" apn="web.sktelecom.com" mmsc="http://omms.nate.com:9082/oma_mms" mmsproxy="smart.nate.com" mmsport="9093" type="default,supl,mms" />
|
||||
<apn carrier="SK Telecom (Roaming)" mcc="450" mnc="05" apn="roaming.sktelecom.com" server="*" mmsc="vmms.nate.com" mmsport="8082" type="default,supl,mms" />
|
||||
@@ -1428,11 +1537,20 @@
|
||||
<apn carrier="TransAsia" mcc="466" mnc="99" apn="internet" type="default,supl" />
|
||||
<apn carrier="TransAsia MMS" mcc="466" mnc="99" apn="mms" mmsc="http://mms" mmsproxy="10.1.1.2" mmsport="80" type="mms" />
|
||||
<apn carrier="台灣大哥大(TW Mobile) (twm)" mcc="466" mnc="99" apn="twm" type="default,supl" />
|
||||
<apn carrier="Grameenphone" mcc="470" mnc="01" apn="gpinterneth" type="default,supl" />
|
||||
<apn carrier="Robi MMS" mcc="470" mnc="02" apn="WAP" mmsc="http://192.168.23.4/was" mmsproxy="192.168.023.007" mmsport="9028" type="mms" />
|
||||
<apn carrier="Robi" mcc="470" mnc="02" apn="internet" port="9201" type="default,supl" />
|
||||
<apn carrier="Grameenphone" mcc="470" mnc="01" apn="gpinternet" type="default,supl" />
|
||||
<apn carrier="Grameenphone MMS" mcc="470" mnc="01" apn="gpmms" mmsc="http://mms.gpsurf.net/servlets/mms" mmsproxy="10.128.1.2" mmsport="8080" type="mms" />
|
||||
<apn carrier="Grameenphone WAP" mcc="470" mnc="01" apn="gpinternet" proxy="10.128.1.2" port="8080" type="default,supl" />
|
||||
<apn carrier="Robi MMS" mcc="470" mnc="02" apn="wap" mmsc="http://192.168.23.4/was" mmsproxy="192.168.023.007" mmsport="9028" type="mms" />
|
||||
<apn carrier="Robi" mcc="470" mnc="02" apn="internet" type="default,supl" />
|
||||
<apn carrier="Robi WAP" mcc="470" mnc="02" apn="wap" proxy="10.128.1.2" port="9208" type="default,supl" />
|
||||
<apn carrier="Banglalink MMS" mcc="470" mnc="03" apn="blmms" mmsc="http://" mmsproxy="10.10.55.34" mmsport="8799" type="mms" />
|
||||
<apn carrier="Banglalink" mcc="470" mnc="03" apn="blweb" type="default,supl" />
|
||||
<apn carrier="Banglalink WAP" mcc="470" mnc="03" apn="blwap" proxy="10.10.55.34" port="8799" type="default,supl" />
|
||||
<apn carrier="Tele Talk" mcc="470" mnc="04" apn="wap" type="default,supl" />
|
||||
<apn carrier="Tele Talk WAP" mcc="470" mnc="04" apn="wap" proxy="192.168.145.101" port="9201" type="default,supl" />
|
||||
<apn carrier="Airtel BD" mcc="470" mnc="07" apn="internet" type="default,supl" />
|
||||
<apn carrier="Airtel BD MMS" mcc="470" mnc="07" apn="mms" mmsc="http://10.6.0.21/servlets/mms" mmsproxy="10.6.0.2" mmsport="8080" type="mms" />
|
||||
<apn carrier="Airtel BD WAP" mcc="470" mnc="07" apn="wap" proxy="10.6.0.2" port="8080" type="default,supl" />
|
||||
<apn carrier="Warid BD" mcc="470" mnc="07" apn="internet" type="default,supl" />
|
||||
<apn carrier="Warid BD MMS" mcc="470" mnc="07" apn="mms" mmsc="http://mms.waridtel.com.bd/index.jsp" mmsproxy="10.128.5.6" mmsport="8080" type="mms" />
|
||||
<apn carrier="Maxis 2G Internet" mcc="502" mnc="12" apn="net" user="maxis" password="wap" type="default,supl" />
|
||||
@@ -1569,6 +1687,8 @@
|
||||
<apn carrier="Orange TN" mcc="605" mnc="01" apn="keypro" type="default,supl" />
|
||||
<apn carrier="weborange" mcc="605" mnc="01" apn="weborange" type="default,supl" />
|
||||
<apn carrier="Orange MMS" mcc="605" mnc="01" apn="mms.otun" mmsc="http://mms.orange.tn" mmsproxy="10.12.1.52" mmsport="8080" type="mms" />
|
||||
<apn carrier="Tunisie Télécom TN" mcc="605" mnc="02" apn="internet.tn" type="default,supl" />
|
||||
<apn carrier="Ooredoo TN" mcc="605" mnc="03" apn="internet.ooredoo.tn" type="default,supl" />
|
||||
<apn carrier="Libyana MMS" mcc="606" mnc="00" apn="mms" mmsc="http://62.240.62.180:80" mmsproxy="192.168.8.148" mmsport="8000" type="mms" />
|
||||
<apn carrier="Libyana" mcc="606" mnc="00" apn="wap" proxy="192.168.8.148" port="8000" type="default,supl" />
|
||||
<apn carrier="Al-Madar MMS" mcc="606" mnc="01" apn="almadar.mms" mmsc="http://almadar.mms/servlets/mms" mmsproxy="41.208.82.50" mmsport="8080" type="mms" />
|
||||
@@ -1592,7 +1712,8 @@
|
||||
<apn carrier="Zain NG" mcc="621" mnc="20" apn="internet.ng.zain.com" type="default,supl" />
|
||||
<apn carrier="MTN NG" mcc="621" mnc="30" apn="web.gprs.mtnnigeria.net" user="web" password="web" proxy="10.199.212.2" type="default,supl" />
|
||||
<apn carrier="MTN NG MMS" mcc="621" mnc="30" apn="web.gprs.mtnnigeria.net" user="web" password="web" mmsc="http://10.199.212.8/servlets/mms" mmsproxy="10.199.212.2" mmsport="8080" type="mms" />
|
||||
<apn carrier="Glo" mcc="621" mnc="50" apn="glo3gvideo" proxy="10.100.98.22" type="default,supl" />
|
||||
<apn carrier="Glo Mobile Internet" mcc="621" mnc="50" apn="gloflat" user="flat" password="flat" proxy="10.100.98.22" type="default,supl" />
|
||||
<apn cariier="Glo PAYU" mcc="621" mnc="50" apn="glosecure" type="default,supl" />
|
||||
<apn carrier="Glo MMS" mcc="621" mnc="50" apn="glomms" user="mms" password="mms" mmsc="http://mms.gloworld.com/mmsc" mmsproxy="010.100.082.004" mmsport="3130" type="mms" />
|
||||
<apn carrier="Etisalat NG" mcc="621" mnc="60" apn="etisalat" type="default,supl" />
|
||||
<apn carrier="Etisalat NG MMS" mcc="621" mnc="60" apn="etisalat" mmsc="http://10.71.170.30:38090/was" mmsproxy="10.71.170.5" mmsport="8080" type="mms" />
|
||||
@@ -1662,6 +1783,10 @@
|
||||
<apn carrier="Movistar MMS" mcc="710" mnc="300" apn="mms.movistar.ni" user="movistarni" password="movistarni" mmsproxy="10.12.23.1" mmsport="80" mmsc="http://mms.movistar.ni" authtype="1" type="mms" />
|
||||
<apn carrier="Enitel" mcc="710" mnc="730" apn="internet.ideasalo.ni" user="internet" password="internet" authtype="1" type="default,supl,dun" />
|
||||
<apn carrier="Enitel MMS" mcc="710" mnc="730" apn="mms.indeasalo.ni" user="mms" password="mms" mmsproxy="10.6.32.2" mmsport="8080" mmsc="http://10.6.32.27/servlets/mms" authtype="1" type="mms" />
|
||||
<apn carrier="Claro" mcc="712" mnc="03" apn="internet.ideasclaro" type="default,supl" />
|
||||
<apn carrier="Claro MMS" mcc="712" mnc="03" apn="mms.ideasclaro" mmsproxy="216.230.133.66" mmsport="8080" mmsc="http://mms.ideasclaro.com:8002" type="mms" />
|
||||
<apn carrier="Movistar Internet" mcc="712" mnc="04" apn="internet.movistart.cr" user="movistarcr" password="movistarcr" authtype="1" type="default,supl" />
|
||||
<apn carrier="Movistar MMS" mcc="712" mnc="04" apn="mms.movistar.cr" user="movistarcr" password="movistarcr" mmsc="http://mms.movistar.cr" mmsproxy="10.221.79.83" mmsport="80" authtype="1" type="mms" />
|
||||
<apn carrier="Cable and Wireless Panama" mcc="714" mnc="01" apn="apn01.cwpanama.com.pa" type="default,supl" />
|
||||
<apn carrier="Cable and Wireless Panama MMS" mcc="714" mnc="01" apn="apn02.cwpanama.com.pa" mmsc="http://mms.zonamovil.com.pa:80/i.bin" mmsproxy="172.25.3.5" mmsport="8080" type="mms" />
|
||||
<apn carrier="Movistar PA" mcc="714" mnc="02" apn="internet.movistar.pa" user="movistarpa" password="movistarpa" type="default,supl"/>
|
||||
|
||||
@@ -562,6 +562,7 @@
|
||||
<apn mcc="310" mnc="0" carrier="Sprint" apn="cinet.spcs" mmsc="http://mms.sprintpcs.com" mmsproxy="68.28.31.7" mmsport="80" type="default,mms" user="none" password="none" bearer="9" server="*" />
|
||||
<apn mcc="310" mnc="0" carrier="Sprint" apn="cinet.spcs" mmsc="http://mms.sprintpcs.com" mmsproxy="68.28.31.7" mmsport="80" type="default,mms" user="none" password="none" bearer="3" server="*" />
|
||||
<apn mcc="310" mnc="0" carrier="Sprint" apn="cinet.spcs" mmsc="http://mms.sprintpcs.com" mmsproxy="68.28.31.7" mmsport="80" type="default,mms" user="none" password="none" bearer="1" server="*" />
|
||||
<apn mcc="310" mnc="000" carrier="Verizon CDMA HRPD" mmsc="http://mms.vzwreseller.com/servlets/mms" type="default,mms,hipri,dun,supl" authtype="3" mvno_type="spn" mvno_match_data="Tracfone" />
|
||||
<apn mcc="310" mnc="4" carrier="Verizon CBS" apn="VZWAPP" mmsc="http://mms.vtext.com/servlets/mms" type="cbs,hipri" protocol="IPV4V6" bearer="13" roaming_protocol="IPV4V6" carrier_enabled="TRUE" />
|
||||
<apn mcc="310" mnc="4" carrier="Verizon CBS" apn="VZWAPP" mmsc="http://mms.vtext.com/servlets/mms" type="cbs,hipri" protocol="IPV4V6" bearer="14" roaming_protocol="IPV4V6" carrier_enabled="TRUE" />
|
||||
<apn mcc="310" mnc="4" carrier="Verizon CDMA HRPD" apn="CdmaNai" mmsc="http://mms.vtext.com/servlets/mms" type="default,mms,hipri,dun,stdhipri,supl" protocol="IPV4V6" bearer="6" carrier_enabled="FALSE" />
|
||||
@@ -1717,8 +1718,6 @@
|
||||
<apn mcc="434" mnc="4" carrier="Beeline-UZB MMS" apn="mms.beeline.uz" mmsc="http://mms" mmsproxy="172.30.30.166" mmsport="8080" type="mms" user="beeline" password="beeline" authtype="1" />
|
||||
<apn mcc="434" mnc="5" carrier="UCELL MMS" apn="mms" mmsc="http://mmsc:8002/" mmsproxy="10.64.164.10" mmsport="8080" type="mms" />
|
||||
<apn mcc="434" mnc="07" carrier="MTS-UZB MMS" apn="mms.mts.uz" mmsc="http://mmsc/was" mmsproxy="10.10.0.10" mmsport="8080" type="mms" />
|
||||
<apn mcc="440" mnc="20" carrier="Application" apn="plus.acs.jp" mmsc="http://mms-s" mmsproxy="andmms.plusacs.ne.jp" mmsport="8080" type="default,mms,supl" user="plusw6q9tattkmpk" password="msfbbam83bsdetxb" authtype="2" />
|
||||
<apn mcc="440" mnc="20" carrier="Application" apn="andoworld.softbank.ne.jp" mmsc="http://mms/" mmsproxy="andmms.softbank.ne.jp" mmsport="8080" type="default,mms,supl,hpri" authtype="0" />
|
||||
<apn mcc="450" mnc="5" carrier="SKT LTE INTERNET" apn="lte.sktelecom.com" mmsc="http://omms.nate.com:9082/oma_mms" mmsproxy="smart.nate.com" mmsport="9093" type="default,mms,supl,fota,cbs" authtype="0" server="*" />
|
||||
<apn mcc="450" mnc="5" carrier="SKT-Home" apn="lte.sktelecom.com" mmsc="http://omms.nate.com:9082/oma_mms" mmsproxy="smart.nate.com" mmsport="9093" type="default,mms" authtype="0" server="*" />
|
||||
<apn mcc="450" mnc="05" carrier="SKT LTE INTERNET" apn="lte.sktelecom.com" mmsc="http://omms.nate.com:9082/oma_mms" mmsproxy="smart.nate.com" mmsport="9093" type="ia,default,mms,supl,fota,cbs" server="*" />
|
||||
|
||||
@@ -1,19 +1,31 @@
|
||||
import sys
|
||||
import re
|
||||
import argparse
|
||||
import sqlite3
|
||||
import gzip
|
||||
from progressbar import ProgressBar, Counter, Timer
|
||||
from lxml import etree
|
||||
|
||||
parser = argparse.ArgumentParser(prog='apntool', description="""Process Android's apn xml files and drop them into an easily
|
||||
queryable SQLite db. Tested up to version 9 of their APN file.""")
|
||||
parser.add_argument('-v', '--version', action='version', version='%(prog)s v1.0')
|
||||
parser = argparse.ArgumentParser(prog='apntool', description="""Process Android's apn xml files and drop them into an
|
||||
easily queryable SQLite db. Tested up to version 9 of
|
||||
their APN file.""")
|
||||
parser.add_argument('-v', '--version', action='version', version='%(prog)s v1.1')
|
||||
parser.add_argument('-i', '--input', help='the xml file to parse', default='apns.xml', required=False)
|
||||
parser.add_argument('-o', '--output', help='the sqlite db output file', default='apns.db', required=False)
|
||||
parser.add_argument('--quiet', help='do not show progress or verbose instructions', action='store_true', required=False)
|
||||
parser.add_argument('--no-gzip', help="do not gzip after creation", action='store_true', required=False)
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
def normalized(target):
|
||||
o2_typo = re.compile(r"02\.co\.uk")
|
||||
port_typo = re.compile(r"(\d+\.\d+\.\d+\.\d+)\.(\d+)")
|
||||
leading_zeros = re.compile(r"(/|\.|^)0+(\d+)")
|
||||
subbed = o2_typo.sub(r'o2.co.uk', target)
|
||||
subbed = port_typo.sub(r'\1:\2', subbed)
|
||||
subbed = leading_zeros.sub(r'\1\2', subbed)
|
||||
return subbed
|
||||
|
||||
try:
|
||||
connection = sqlite3.connect(args.output)
|
||||
cursor = connection.cursor()
|
||||
@@ -28,26 +40,39 @@ try:
|
||||
cursor.execute("PRAGMA page_size=32768")
|
||||
cursor.execute("VACUUM")
|
||||
cursor.execute("DROP TABLE IF EXISTS apns")
|
||||
cursor.execute("""CREATE TABLE apns(_id INTEGER PRIMARY KEY, mccmnc TEXT, mcc TEXT, mnc TEXT, carrier TEXT, apn TEXT,
|
||||
mmsc TEXT, port INTEGER, type TEXT, protocol TEXT, bearer TEXT, roaming_protocol TEXT,
|
||||
cursor.execute("""CREATE TABLE apns(_id INTEGER PRIMARY KEY, mccmnc TEXT, mcc TEXT, mnc TEXT, carrier TEXT,
|
||||
apn TEXT, mmsc TEXT, port INTEGER, type TEXT, protocol TEXT, bearer TEXT, roaming_protocol TEXT,
|
||||
carrier_enabled INTEGER, mmsproxy TEXT, mmsport INTEGER, proxy TEXT, mvno_match_data TEXT,
|
||||
mvno_type TEXT, authtype INTEGER, user TEXT, password TEXT, server TEXT)""")
|
||||
|
||||
apns = etree.parse(args.input)
|
||||
root = apns.getroot()
|
||||
pbar = ProgressBar(widgets=['Processed: ', Counter(), ' apns (', Timer(), ')'], maxval=len(list(root))).start() if not args.quiet else None
|
||||
pbar = None
|
||||
if not args.quiet:
|
||||
pbar = ProgressBar(widgets=['Processed: ', Counter(), ' apns (', Timer(), ')'], maxval=len(list(root))).start()
|
||||
|
||||
count = 0
|
||||
for apn in root.iter("apn"):
|
||||
if apn.get("mmsc") == None:
|
||||
if apn.get("mmsc") is None:
|
||||
continue
|
||||
sqlvars = ["?" for x in apn.attrib.keys()] + ["?"]
|
||||
mccmnc = "%s%s" % (apn.get("mcc"), apn.get("mnc"))
|
||||
values = [apn.get(attrib) for attrib in apn.attrib.keys()] + [mccmnc]
|
||||
keys = apn.attrib.keys() + ["mccmnc"]
|
||||
mccmnc = "%s%s" % (apn.get("mcc"), apn.get("mnc"))
|
||||
normalized_mmsc = normalized(apn.get("mmsc"))
|
||||
if normalized_mmsc != apn.get("mmsc"):
|
||||
print("normalize MMSC: %s => %s" % (apn.get("mmsc"), normalized_mmsc))
|
||||
apn.set("mmsc", normalized_mmsc)
|
||||
|
||||
if not apn.get("mmsproxy") is None:
|
||||
normalized_mmsproxy = normalized(apn.get("mmsproxy"))
|
||||
if normalized_mmsproxy != apn.get("mmsproxy"):
|
||||
print("normalize proxy: %s => %s" % (apn.get("mmsproxy"), normalized_mmsproxy))
|
||||
apn.set("mmsproxy", normalized_mmsproxy)
|
||||
|
||||
values = [apn.get(attrib) for attrib in apn.attrib.keys()] + [mccmnc]
|
||||
keys = apn.attrib.keys() + ["mccmnc"]
|
||||
|
||||
cursor.execute("SELECT 1 FROM apns WHERE mccmnc = ? AND apn = ?", [mccmnc, apn.get("apn")])
|
||||
if cursor.fetchone() == None:
|
||||
if cursor.fetchone() is None:
|
||||
statement = "INSERT INTO apns (%s) VALUES (%s)" % (", ".join(keys), ", ".join(sqlvars))
|
||||
cursor.execute(statement, values)
|
||||
|
||||
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
31036
artwork/icon.ai
31036
artwork/icon.ai
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 496 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 93 KiB |
BIN
artwork/logo-512.png
Normal file
BIN
artwork/logo-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
155
build.gradle
155
build.gradle
@@ -5,13 +5,12 @@ buildscript {
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.0.0'
|
||||
classpath 'com.android.tools.build:gradle:1.0.1'
|
||||
classpath files('libs/gradle-witness.jar')
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply from: 'strip_play_services.gradle'
|
||||
apply plugin: 'witness'
|
||||
|
||||
repositories {
|
||||
@@ -21,84 +20,129 @@ repositories {
|
||||
maven {
|
||||
url "https://raw.github.com/whispersystems/maven/master/preferencefragment/releases/"
|
||||
}
|
||||
maven {
|
||||
url "https://raw.github.com/whispersystems/maven/master/gson/releases/"
|
||||
}
|
||||
maven {
|
||||
url "https://raw.github.com/whispersystems/maven/master/smil/releases/"
|
||||
}
|
||||
maven {
|
||||
url "https://raw.github.com/whispersystems/maven/master/shortcutbadger/releases/"
|
||||
}
|
||||
maven { // textdrawable
|
||||
url 'https://dl.bintray.com/amulyakhare/maven'
|
||||
}
|
||||
jcenter()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'me.leolin:ShortcutBadger:1.0.2-WS2'
|
||||
compile 'me.leolin:ShortcutBadger:1.1.0-WS1'
|
||||
compile 'se.emilsjolander:stickylistheaders:2.2.0'
|
||||
compile 'com.google.android.gms:play-services:6.1.71'
|
||||
compile 'com.google.android.gms:play-services-base:6.5.87'
|
||||
compile 'com.astuetz:pagerslidingtabstrip:1.0.1'
|
||||
compile 'org.w3c:smil:1.0.0'
|
||||
compile 'org.apache.httpcomponents:httpclient-android:4.3.5'
|
||||
compile 'com.github.chrisbanes.photoview:library:1.2.3'
|
||||
compile 'com.android.support:appcompat-v7:20.0.0'
|
||||
compile 'com.madgag.spongycastle:prov:1.51.0.0'
|
||||
compile 'com.github.bumptech.glide:glide:3.5.2'
|
||||
compile 'com.makeramen:roundedimageview:1.5.0'
|
||||
compile ('com.afollestad:material-dialogs:0.7.3.1') {
|
||||
exclude module: 'appcompat-v7'
|
||||
exclude module: 'recyclerview-v7'
|
||||
exclude module: 'support-annotations'
|
||||
}
|
||||
|
||||
compile 'com.soundcloud.android:android-crop:0.9.10@aar'
|
||||
compile 'com.android.support:appcompat-v7:22.1.1'
|
||||
compile 'com.android.support:recyclerview-v7:21.0.3'
|
||||
compile 'com.melnykov:floatingactionbutton:1.1.0'
|
||||
compile 'com.google.zxing:android-integration:3.1.0'
|
||||
compile ('com.android.support:support-v4-preferencefragment:1.0.0@aar'){
|
||||
exclude module: 'support-v4'
|
||||
}
|
||||
compile 'com.squareup.dagger:dagger:1.2.2'
|
||||
compile ("com.doomonafireball.betterpickers:library:1.5.2") {
|
||||
compile ("com.doomonafireball.betterpickers:library:1.5.3") {
|
||||
exclude group: 'com.android.support', module: 'support-v4'
|
||||
}
|
||||
compile 'com.madgag.spongycastle:prov:1.51.0.0'
|
||||
provided 'com.squareup.dagger:dagger-compiler:1.2.2'
|
||||
|
||||
compile 'org.whispersystems:jobmanager:0.10.0'
|
||||
compile 'org.whispersystems:libpastelog:1.0.2'
|
||||
compile 'org.whispersystems:jobmanager:0.11.0'
|
||||
compile 'org.whispersystems:libpastelog:1.0.6'
|
||||
compile 'org.whispersystems:textsecure-android:1.3.0'
|
||||
compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
|
||||
|
||||
androidTestCompile 'com.squareup:fest-android:1.0.8'
|
||||
androidTestCompile 'com.google.dexmaker:dexmaker:1.1'
|
||||
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.1'
|
||||
androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
|
||||
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
|
||||
|
||||
compile project(':libtextsecure')
|
||||
androidTestCompile ('org.assertj:assertj-core:1.7.1') {
|
||||
exclude group: 'org.hamcrest', module: 'hamcrest-core'
|
||||
}
|
||||
androidTestCompile ('com.squareup.assertj:assertj-android:1.0.0') {
|
||||
exclude group: 'org.hamcrest', module: 'hamcrest-core'
|
||||
}
|
||||
androidTestCompile ('com.android.support.test.espresso:espresso-core:2.0') {
|
||||
exclude group: 'javax.inject'
|
||||
}
|
||||
androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
|
||||
}
|
||||
|
||||
dependencyVerification {
|
||||
verify = [
|
||||
'me.leolin:ShortcutBadger:027977c718035e5997035e04e05152d6c72d94df645e8b7099a274ada722bd14',
|
||||
'me.leolin:ShortcutBadger:3142d017234bfa0cdd69ccded7cc5ea63f13b97574803c8c616c9bbeaad33ad9',
|
||||
'se.emilsjolander:stickylistheaders:89146b46c96fea0e40200474a2625cda10fe94891e4128f53cdb42375091b9b6',
|
||||
'com.google.android.gms:play-services:32e7d1834a1cf8fa4b17e8d359db580c286e26c1eefbf84fdb9996eac8d74919',
|
||||
'com.google.android.gms:play-services-base:832cb6b3130e871db6a412c4ab585656dbcc5e7948101f190186757785703f75',
|
||||
'com.astuetz:pagerslidingtabstrip:f1641396732c7132a7abb837e482e5ee2b0ebb8d10813fc52bbaec2c15c184c2',
|
||||
'org.w3c:smil:085dc40f2bb249651578bfa07499fd08b16ad0886dbe2c4078586a408da62f9b',
|
||||
'org.apache.httpcomponents:httpclient-android:6f56466a9bd0d42934b90bfbfe9977a8b654c058bf44a12bdc2877c4e1f033f1',
|
||||
'com.github.chrisbanes.photoview:library:8b5344e206f125e7ba9d684008f36c4992d03853c57e5814125f88496126e3cc',
|
||||
'com.android.support:appcompat-v7:736f576ab0b68d27bdf18b1e7931566e6d8254b73965175313e87f8866b91547',
|
||||
'com.madgag.spongycastle:prov:b8c3fec3a59aac1aa04ccf4dad7179351e54ef7672f53f508151b614c131398a',
|
||||
'com.github.bumptech.glide:glide:16936352b96aa604b030f2d2263fb0cc656933e6cdda0bf6ac681282d1f7f196',
|
||||
'com.makeramen:roundedimageview:7dda2e78c406760e5c356ccce59b0df46b5b171cf18abb891998594405021548',
|
||||
'com.afollestad:material-dialogs:c17205f0d300baa307599c428a5473a6659684c94a5f68ae3c2b84b5e4741172',
|
||||
'com.soundcloud.android:android-crop:ffd4b973cf6e97f7d64118a0dc088df50e9066fd5634fe6911dd0c0c5d346177',
|
||||
'com.android.support:appcompat-v7:9a2355537c2f01cf0b95523605c18606b8d824017e6e94a05c77b0cfc8f21c96',
|
||||
'com.android.support:recyclerview-v7:e525ad3f33c84bb12b73d2dc975b55364a53f0f2d0697e043efba59ba73e22d2',
|
||||
'com.melnykov:floatingactionbutton:0679ad9f7d61eb7aeab91e8dc56358cdedd5b1c1b9c48464499ffa05c40d3985',
|
||||
'com.google.zxing:android-integration:89e56aadf1164bd71e57949163c53abf90af368b51669c0d4a47a163335f95c4',
|
||||
'com.android.support:support-v4-preferencefragment:5470f5872514a6226fa1fc6f4e000991f38805691c534cf0bd2778911fc773ad',
|
||||
'com.squareup.dagger:dagger:789aca24537022e49f91fc6444078d9de8f1dd99e1bfb090f18491b186967883',
|
||||
'com.doomonafireball.betterpickers:library:1c2dd66b0f4555e9e68427b28eed8826b7cd2e7074b8c038c88836a6aa9abe64',
|
||||
'org.whispersystems:libpastelog:9798b3c93a91082c2c68542ce5b5c182e18556aebdcb7c8cebbd89eb48ac4047',
|
||||
'org.whispersystems:jobmanager:01f35586c43aa3806f1c18d3d6a5a972def98103ba1a5a9ca3eec08d15f974b7',
|
||||
'com.android.support:support-v4:81f2b1c2c94efd5a4ec7fcd97b6cdcd00e87a933905c5c86103c7319eb024572',
|
||||
'com.madgag.spongycastle:core:8d6240b974b0aca4d3da9c7dd44d42339d8a374358aca5fc98e50a995764511f',
|
||||
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||
'com.doomonafireball.betterpickers:library:132ecd685c95a99e7377c4e27bfadbb2d7ed0bea995944060cd62d4369fdaf3d',
|
||||
'com.madgag.spongycastle:prov:b8c3fec3a59aac1aa04ccf4dad7179351e54ef7672f53f508151b614c131398a',
|
||||
'org.whispersystems:jobmanager:ea9cb943c4892fb90c1eea1be30efeb85cefca213d52c788419553b58d0ed70d',
|
||||
'org.whispersystems:libpastelog:550d33c565380d90f4c671e7b8ed5f3a6da55a9fda468373177106b2eb5220b2',
|
||||
'org.whispersystems:textsecure-android:df4c1ac9ee8f7cd43c8c07d64b16e31875e04632afc3fe73f2a47292a86c79a1',
|
||||
'com.amulyakhare:com.amulyakhare.textdrawable:54c92b5fba38cfd316a07e5a30528068f45ce8515a6890f1297df4c401af5dcb',
|
||||
'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a',
|
||||
'org.whispersystems:gson:08f4f7498455d1539c9233e5aac18e9b1805815ef29221572996508eb512fe51',
|
||||
'com.google.protobuf:protobuf-java:e0c1c64575c005601725e7c6a02cebf9e1285e888f756b2a1d73ffa8d725cc74',
|
||||
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||
'com.madgag.spongycastle:core:8d6240b974b0aca4d3da9c7dd44d42339d8a374358aca5fc98e50a995764511f',
|
||||
'org.whispersystems:textsecure-java:59d7c998c83a0f96bbc84db36719c9be8007bce16ee1ba9748af5610ab429656',
|
||||
'org.whispersystems:axolotl-android:40d3db5004a84749a73f68d2f0d01b2ae35a73c54df96d8c6c6723b96efb6fc0',
|
||||
'com.googlecode.libphonenumber:libphonenumber:eba17eae81dd622ea89a00a3a8c025b2f25d342e0d9644c5b62e16f15687c3ab',
|
||||
'org.whispersystems:axolotl-android:7617256d05aaecd7b5475cd55e42773d7079167a22ca48512bcb0f84f8473cc9',
|
||||
'com.android.support:support-annotations:1aa96ef0cc4a445bfc2f93ccf762305bc57fa107b12afe9d11f3863ae8a11036',
|
||||
'com.google.protobuf:protobuf-java:e0c1c64575c005601725e7c6a02cebf9e1285e888f756b2a1d73ffa8d725cc74',
|
||||
'com.squareup.okhttp:okhttp:89b7f63e2e5b6c410266abc14f50fe52ea8d2d8a57260829e499b1cd9f0e61af',
|
||||
'com.fasterxml.jackson.core:jackson-databind:835097bcdd11f5bc8a08378c70d4c8054dfa4b911691cc2752063c75534d198d',
|
||||
'org.whispersystems:axolotl-java:6daee739b89d8d7101de6d98f77132fee48495c6ea647d880e77def842f999ea',
|
||||
'org.whispersystems:curve25519-android:3c29a4131a69b0d16baaa3d707678deb39602c3a3ffd75805ce7f9db252e5d0d',
|
||||
'com.squareup.okio:okio:5e1098bd3fdee4c3347f5ab815b40ba851e4ab1b348c5e49a5b0362f0ce6e978',
|
||||
'com.fasterxml.jackson.core:jackson-annotations:0ca408c24202a7626ec8b861e99d85eca5e38b73311dd6dd12e3e9deecc3fe94',
|
||||
'com.fasterxml.jackson.core:jackson-core:cbf4604784b4de226262845447a1ad3bb38a6728cebe86562e2c5afada8be2c0',
|
||||
'org.whispersystems:curve25519-java:9ccef8f5aba05d9942336f023c589d6278b4f9135bdc34a7bade1f4e7ad65fa3',
|
||||
'com.android.support:support-v4:1e2e4d35ac7fd30db5ce3bc177b92e4d5af86acef2ef93e9221599d733346f56',
|
||||
'com.android.support:support-annotations:7bc07519aa613b186001160403bcfd68260fa82c61cc7e83adeedc9b862b94ae',
|
||||
]
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 21
|
||||
buildToolsVersion '21.1.2'
|
||||
compileSdkVersion 22
|
||||
buildToolsVersion '22.0.1'
|
||||
testBuildType "testing"
|
||||
|
||||
dexOptions {
|
||||
javaMaxHeapSize "4g"
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 9
|
||||
targetSdkVersion 19
|
||||
targetSdkVersion 22
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
buildConfigField "long", "BUILD_TIMESTAMP", System.currentTimeMillis() + "L"
|
||||
}
|
||||
|
||||
@@ -107,18 +151,55 @@ android {
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
exclude 'LICENSE.txt'
|
||||
exclude 'LICENSE'
|
||||
exclude 'NOTICE'
|
||||
exclude 'asm-license.txt'
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
minifyEnabled false
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'),
|
||||
'proguard-google-play-services.pro',
|
||||
'proguard-dagger.pro',
|
||||
'proguard-jackson.pro',
|
||||
'proguard-sqlite.pro',
|
||||
'proguard-appcompat-v7.pro',
|
||||
'proguard-square-okhttp.pro',
|
||||
'proguard-square-okio.pro',
|
||||
'proguard-spongycastle.pro',
|
||||
'proguard-rounded-image-view.pro',
|
||||
'proguard-glide.pro',
|
||||
'proguard-shortcutbadger.pro',
|
||||
'proguard.cfg'
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'),
|
||||
'proguard-google-play-services.pro',
|
||||
'proguard-dagger.pro',
|
||||
'proguard-jackson.pro',
|
||||
'proguard-sqlite.pro',
|
||||
'proguard-appcompat-v7.pro',
|
||||
'proguard-square-okhttp.pro',
|
||||
'proguard-square-okio.pro',
|
||||
'proguard-spongycastle.pro',
|
||||
'proguard-rounded-image-view.pro',
|
||||
'proguard-glide.pro',
|
||||
'proguard-shortcutbadger.pro',
|
||||
'proguard.cfg'
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
testing.initWith(buildTypes.debug)
|
||||
testing {
|
||||
proguardFile 'proguard-testing.pro'
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
@@ -139,6 +220,10 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
exclude 'META-INF/LICENSE'
|
||||
exclude 'META-INF/NOTICE'
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
|
||||
@@ -28,3 +28,4 @@ Truths which we believe to be self-evident:
|
||||
1. **There is no such thing as time.** Protocol ideas that require synchronized
|
||||
clocks are doomed to failure.
|
||||
|
||||
Before you submit a pull request, please check if your code follows the [Code style Guidelines](https://github.com/WhisperSystems/RedPhone/wiki/Code-style-Guidelines).
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.0.0'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'maven'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
url "https://raw.github.com/whispersystems/maven/master/gson/releases/"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.google.protobuf:protobuf-java:2.5.0'
|
||||
compile 'com.googlecode.libphonenumber:libphonenumber:6.1'
|
||||
compile 'org.whispersystems:gson:2.2.4'
|
||||
compile 'org.whispersystems:axolotl-android:1.0.0'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 21
|
||||
buildToolsVersion '21.1.2'
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
}
|
||||
|
||||
tasks.whenTaskAdded { task ->
|
||||
if (task.name.equals("lint")) {
|
||||
task.enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
version '0.1'
|
||||
group 'org.whispersystems.textsecure'
|
||||
archivesBaseName = 'libtextsecure'
|
||||
|
||||
uploadArchives {
|
||||
repositories {
|
||||
mavenDeployer {
|
||||
repository(url: mavenLocal().getUrl())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package textsecure;
|
||||
|
||||
option java_package = "org.whispersystems.textsecure.internal.push";
|
||||
option java_outer_classname = "PushMessageProtos";
|
||||
|
||||
message IncomingPushMessageSignal {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
CIPHERTEXT = 1;
|
||||
KEY_EXCHANGE = 2;
|
||||
PREKEY_BUNDLE = 3;
|
||||
PLAINTEXT = 4;
|
||||
RECEIPT = 5;
|
||||
}
|
||||
optional Type type = 1;
|
||||
optional string source = 2;
|
||||
optional uint32 sourceDevice = 7;
|
||||
optional string relay = 3;
|
||||
optional uint64 timestamp = 5;
|
||||
optional bytes message = 6; // Contains an encrypted PushMessageContent
|
||||
// repeated string destinations = 4; // No longer supported
|
||||
}
|
||||
|
||||
message PushMessageContent {
|
||||
message AttachmentPointer {
|
||||
optional fixed64 id = 1;
|
||||
optional string contentType = 2;
|
||||
optional bytes key = 3;
|
||||
}
|
||||
|
||||
message GroupContext {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
UPDATE = 1;
|
||||
DELIVER = 2;
|
||||
QUIT = 3;
|
||||
}
|
||||
optional bytes id = 1;
|
||||
optional Type type = 2;
|
||||
optional string name = 3;
|
||||
repeated string members = 4;
|
||||
optional AttachmentPointer avatar = 5;
|
||||
}
|
||||
|
||||
enum Flags {
|
||||
END_SESSION = 1;
|
||||
}
|
||||
|
||||
optional string body = 1;
|
||||
repeated AttachmentPointer attachments = 2;
|
||||
optional GroupContext group = 3;
|
||||
optional uint32 flags = 4;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
|
||||
all:
|
||||
protoc --java_out=../src/main/java/ IncomingPushMessageSignal.proto
|
||||
@@ -1,35 +0,0 @@
|
||||
package org.whispersystems.textsecure.push;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import org.whispersystems.textsecure.internal.push.PushTransportDetails;
|
||||
|
||||
public class PushTransportDetailsTest extends AndroidTestCase {
|
||||
|
||||
private final PushTransportDetails transportV2 = new PushTransportDetails(2);
|
||||
private final PushTransportDetails transportV3 = new PushTransportDetails(3);
|
||||
|
||||
public void testV3Padding() {
|
||||
for (int i=0;i<159;i++) {
|
||||
byte[] message = new byte[i];
|
||||
assertEquals(transportV3.getPaddedMessageBody(message).length, 159);
|
||||
}
|
||||
|
||||
for (int i=159;i<319;i++) {
|
||||
byte[] message = new byte[i];
|
||||
assertEquals(transportV3.getPaddedMessageBody(message).length, 319);
|
||||
}
|
||||
|
||||
for (int i=319;i<479;i++) {
|
||||
byte[] message = new byte[i];
|
||||
assertEquals(transportV3.getPaddedMessageBody(message).length, 479);
|
||||
}
|
||||
}
|
||||
|
||||
public void testV2Padding() {
|
||||
for (int i=0;i<480;i++) {
|
||||
byte[] message = new byte[i];
|
||||
assertTrue(transportV2.getPaddedMessageBody(message).length == message.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.whispersystems.textsecure"
|
||||
android:versionCode="1"
|
||||
android:versionName="0.1">
|
||||
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="16"/>
|
||||
<application />
|
||||
</manifest>
|
||||
@@ -1,97 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api;
|
||||
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.state.PreKeyRecord;
|
||||
import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
import org.whispersystems.textsecure.api.push.ContactTokenDetails;
|
||||
import org.whispersystems.textsecure.api.push.TrustStore;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.NonSuccessfulResponseCodeException;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.PushNetworkException;
|
||||
import org.whispersystems.textsecure.internal.push.PushServiceSocket;
|
||||
import org.whispersystems.textsecure.api.push.SignedPreKeyEntity;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class TextSecureAccountManager {
|
||||
|
||||
private final PushServiceSocket pushServiceSocket;
|
||||
|
||||
public TextSecureAccountManager(String url, TrustStore trustStore,
|
||||
String user, String password)
|
||||
{
|
||||
this.pushServiceSocket = new PushServiceSocket(url, trustStore, user, password);
|
||||
}
|
||||
|
||||
public void setGcmId(Optional<String> gcmRegistrationId) throws IOException {
|
||||
if (gcmRegistrationId.isPresent()) {
|
||||
this.pushServiceSocket.registerGcmId(gcmRegistrationId.get());
|
||||
} else {
|
||||
this.pushServiceSocket.unregisterGcmId();
|
||||
}
|
||||
}
|
||||
|
||||
public void requestSmsVerificationCode() throws IOException {
|
||||
this.pushServiceSocket.createAccount(false);
|
||||
}
|
||||
|
||||
public void requestVoiceVerificationCode() throws IOException {
|
||||
this.pushServiceSocket.createAccount(true);
|
||||
}
|
||||
|
||||
public void verifyAccount(String verificationCode, String signalingKey,
|
||||
boolean supportsSms, int axolotlRegistrationId)
|
||||
throws IOException
|
||||
{
|
||||
this.pushServiceSocket.verifyAccount(verificationCode, signalingKey,
|
||||
supportsSms, axolotlRegistrationId);
|
||||
}
|
||||
|
||||
public void setPreKeys(IdentityKey identityKey, PreKeyRecord lastResortKey,
|
||||
SignedPreKeyRecord signedPreKey, List<PreKeyRecord> oneTimePreKeys)
|
||||
throws IOException
|
||||
{
|
||||
this.pushServiceSocket.registerPreKeys(identityKey, lastResortKey, signedPreKey, oneTimePreKeys);
|
||||
}
|
||||
|
||||
public int getPreKeysCount() throws IOException {
|
||||
return this.pushServiceSocket.getAvailablePreKeys();
|
||||
}
|
||||
|
||||
public void setSignedPreKey(SignedPreKeyRecord signedPreKey) throws IOException {
|
||||
this.pushServiceSocket.setCurrentSignedPreKey(signedPreKey);
|
||||
}
|
||||
|
||||
public SignedPreKeyEntity getSignedPreKey() throws IOException {
|
||||
return this.pushServiceSocket.getCurrentSignedPreKey();
|
||||
}
|
||||
|
||||
public Optional<ContactTokenDetails> getContact(String contactToken) throws IOException {
|
||||
return Optional.fromNullable(this.pushServiceSocket.getContactTokenDetails(contactToken));
|
||||
}
|
||||
|
||||
public List<ContactTokenDetails> getContacts(Set<String> contactTokens)
|
||||
throws IOException
|
||||
{
|
||||
return this.pushServiceSocket.retrieveDirectory(contactTokens);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api;
|
||||
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.api.crypto.AttachmentCipherInputStream;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureAttachmentPointer;
|
||||
import org.whispersystems.textsecure.api.push.TrustStore;
|
||||
import org.whispersystems.textsecure.internal.push.PushServiceSocket;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class TextSecureMessageReceiver {
|
||||
|
||||
private final PushServiceSocket socket;
|
||||
|
||||
public TextSecureMessageReceiver(String url, TrustStore trustStore,
|
||||
String user, String password)
|
||||
{
|
||||
this.socket = new PushServiceSocket(url, trustStore, user, password);
|
||||
}
|
||||
|
||||
public InputStream retrieveAttachment(TextSecureAttachmentPointer pointer, File destination)
|
||||
throws IOException, InvalidMessageException
|
||||
{
|
||||
socket.retrieveAttachment(pointer.getRelay().orNull(), pointer.getId(), destination);
|
||||
return new AttachmentCipherInputStream(destination, pointer.getKey());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,323 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.SessionBuilder;
|
||||
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||
import org.whispersystems.libaxolotl.state.AxolotlStore;
|
||||
import org.whispersystems.libaxolotl.state.PreKeyBundle;
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
import org.whispersystems.textsecure.api.crypto.TextSecureCipher;
|
||||
import org.whispersystems.textsecure.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureAttachment;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureAttachmentStream;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureGroup;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureMessage;
|
||||
import org.whispersystems.textsecure.api.push.PushAddress;
|
||||
import org.whispersystems.textsecure.api.push.TrustStore;
|
||||
import org.whispersystems.textsecure.internal.push.MismatchedDevices;
|
||||
import org.whispersystems.textsecure.internal.push.OutgoingPushMessage;
|
||||
import org.whispersystems.textsecure.internal.push.OutgoingPushMessageList;
|
||||
import org.whispersystems.textsecure.internal.push.PushAttachmentData;
|
||||
import org.whispersystems.textsecure.internal.push.PushBody;
|
||||
import org.whispersystems.textsecure.internal.push.PushServiceSocket;
|
||||
import org.whispersystems.textsecure.internal.push.StaleDevices;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.UnregisteredUserException;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.EncapsulatedExceptions;
|
||||
import org.whispersystems.textsecure.internal.push.exceptions.MismatchedDevicesException;
|
||||
import org.whispersystems.textsecure.internal.push.exceptions.StaleDevicesException;
|
||||
import org.whispersystems.textsecure.internal.util.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.whispersystems.textsecure.internal.push.PushMessageProtos.IncomingPushMessageSignal.Type;
|
||||
import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent;
|
||||
import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent.AttachmentPointer;
|
||||
import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent.GroupContext;
|
||||
|
||||
public class TextSecureMessageSender {
|
||||
|
||||
private static final String TAG = TextSecureMessageSender.class.getSimpleName();
|
||||
|
||||
private final PushServiceSocket socket;
|
||||
private final AxolotlStore store;
|
||||
private final Optional<EventListener> eventListener;
|
||||
|
||||
public TextSecureMessageSender(String url, TrustStore trustStore,
|
||||
String user, String password, AxolotlStore store,
|
||||
Optional<EventListener> eventListener)
|
||||
{
|
||||
this.socket = new PushServiceSocket(url, trustStore, user, password);
|
||||
this.store = store;
|
||||
this.eventListener = eventListener;
|
||||
}
|
||||
|
||||
public void sendDeliveryReceipt(PushAddress recipient, long messageId) throws IOException {
|
||||
this.socket.sendReceipt(recipient.getNumber(), messageId, recipient.getRelay());
|
||||
}
|
||||
|
||||
public void sendMessage(PushAddress recipient, TextSecureMessage message)
|
||||
throws UntrustedIdentityException, IOException
|
||||
{
|
||||
byte[] content = createMessageContent(message);
|
||||
sendMessage(recipient, message.getTimestamp(), content);
|
||||
|
||||
if (message.isEndSession()) {
|
||||
store.deleteAllSessions(recipient.getRecipientId());
|
||||
|
||||
if (eventListener.isPresent()) {
|
||||
eventListener.get().onSecurityEvent(recipient.getRecipientId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMessage(List<PushAddress> recipients, TextSecureMessage message)
|
||||
throws IOException, EncapsulatedExceptions
|
||||
{
|
||||
byte[] content = createMessageContent(message);
|
||||
sendMessage(recipients, message.getTimestamp(), content);
|
||||
}
|
||||
|
||||
private byte[] createMessageContent(TextSecureMessage message) throws IOException {
|
||||
PushMessageContent.Builder builder = PushMessageContent.newBuilder();
|
||||
List<AttachmentPointer> pointers = createAttachmentPointers(message.getAttachments());
|
||||
|
||||
if (!pointers.isEmpty()) {
|
||||
builder.addAllAttachments(pointers);
|
||||
}
|
||||
|
||||
if (message.getBody().isPresent()) {
|
||||
builder.setBody(message.getBody().get());
|
||||
}
|
||||
|
||||
if (message.getGroupInfo().isPresent()) {
|
||||
builder.setGroup(createGroupContent(message.getGroupInfo().get()));
|
||||
}
|
||||
|
||||
if (message.isEndSession()) {
|
||||
builder.setFlags(PushMessageContent.Flags.END_SESSION_VALUE);
|
||||
}
|
||||
|
||||
return builder.build().toByteArray();
|
||||
}
|
||||
|
||||
private GroupContext createGroupContent(TextSecureGroup group) throws IOException {
|
||||
GroupContext.Builder builder = GroupContext.newBuilder();
|
||||
builder.setId(ByteString.copyFrom(group.getGroupId()));
|
||||
|
||||
if (group.getType() != TextSecureGroup.Type.DELIVER) {
|
||||
if (group.getType() == TextSecureGroup.Type.UPDATE) builder.setType(GroupContext.Type.UPDATE);
|
||||
else if (group.getType() == TextSecureGroup.Type.QUIT) builder.setType(GroupContext.Type.QUIT);
|
||||
else throw new AssertionError("Unknown type: " + group.getType());
|
||||
|
||||
if (group.getName().isPresent()) builder.setName(group.getName().get());
|
||||
if (group.getMembers().isPresent()) builder.addAllMembers(group.getMembers().get());
|
||||
|
||||
if (group.getAvatar().isPresent() && group.getAvatar().get().isStream()) {
|
||||
AttachmentPointer pointer = createAttachmentPointer(group.getAvatar().get().asStream());
|
||||
builder.setAvatar(pointer);
|
||||
}
|
||||
} else {
|
||||
builder.setType(GroupContext.Type.DELIVER);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void sendMessage(List<PushAddress> recipients, long timestamp, byte[] content)
|
||||
throws IOException, EncapsulatedExceptions
|
||||
{
|
||||
List<UntrustedIdentityException> untrustedIdentities = new LinkedList<>();
|
||||
List<UnregisteredUserException> unregisteredUsers = new LinkedList<>();
|
||||
|
||||
for (PushAddress recipient : recipients) {
|
||||
try {
|
||||
sendMessage(recipient, timestamp, content);
|
||||
} catch (UntrustedIdentityException e) {
|
||||
Log.w(TAG, e);
|
||||
untrustedIdentities.add(e);
|
||||
} catch (UnregisteredUserException e) {
|
||||
Log.w(TAG, e);
|
||||
unregisteredUsers.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!untrustedIdentities.isEmpty() || !unregisteredUsers.isEmpty()) {
|
||||
throw new EncapsulatedExceptions(untrustedIdentities, unregisteredUsers);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendMessage(PushAddress recipient, long timestamp, byte[] content)
|
||||
throws UntrustedIdentityException, IOException
|
||||
{
|
||||
for (int i=0;i<3;i++) {
|
||||
try {
|
||||
OutgoingPushMessageList messages = getEncryptedMessages(socket, recipient, timestamp, content);
|
||||
socket.sendMessage(messages);
|
||||
|
||||
return;
|
||||
} catch (MismatchedDevicesException mde) {
|
||||
Log.w(TAG, mde);
|
||||
handleMismatchedDevices(socket, recipient, mde.getMismatchedDevices());
|
||||
} catch (StaleDevicesException ste) {
|
||||
Log.w(TAG, ste);
|
||||
handleStaleDevices(recipient, ste.getStaleDevices());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<AttachmentPointer> createAttachmentPointers(Optional<List<TextSecureAttachment>> attachments) throws IOException {
|
||||
List<AttachmentPointer> pointers = new LinkedList<>();
|
||||
|
||||
if (!attachments.isPresent() || attachments.get().isEmpty()) {
|
||||
Log.w(TAG, "No attachments present...");
|
||||
return pointers;
|
||||
}
|
||||
|
||||
for (TextSecureAttachment attachment : attachments.get()) {
|
||||
if (attachment.isStream()) {
|
||||
Log.w(TAG, "Found attachment, creating pointer...");
|
||||
pointers.add(createAttachmentPointer(attachment.asStream()));
|
||||
}
|
||||
}
|
||||
|
||||
return pointers;
|
||||
}
|
||||
|
||||
private AttachmentPointer createAttachmentPointer(TextSecureAttachmentStream attachment)
|
||||
throws IOException
|
||||
{
|
||||
byte[] attachmentKey = Util.getSecretBytes(64);
|
||||
PushAttachmentData attachmentData = new PushAttachmentData(attachment.getContentType(),
|
||||
attachment.getInputStream(),
|
||||
attachment.getLength(),
|
||||
attachmentKey);
|
||||
|
||||
long attachmentId = socket.sendAttachment(attachmentData);
|
||||
|
||||
return AttachmentPointer.newBuilder()
|
||||
.setContentType(attachment.getContentType())
|
||||
.setId(attachmentId)
|
||||
.setKey(ByteString.copyFrom(attachmentKey))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
private OutgoingPushMessageList getEncryptedMessages(PushServiceSocket socket,
|
||||
PushAddress recipient,
|
||||
long timestamp,
|
||||
byte[] plaintext)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
PushBody masterBody = getEncryptedMessage(socket, recipient, plaintext);
|
||||
|
||||
List<OutgoingPushMessage> messages = new LinkedList<>();
|
||||
messages.add(new OutgoingPushMessage(recipient, masterBody));
|
||||
|
||||
for (int deviceId : store.getSubDeviceSessions(recipient.getRecipientId())) {
|
||||
PushAddress device = new PushAddress(recipient.getRecipientId(), recipient.getNumber(), deviceId, recipient.getRelay());
|
||||
PushBody body = getEncryptedMessage(socket, device, plaintext);
|
||||
|
||||
messages.add(new OutgoingPushMessage(device, body));
|
||||
}
|
||||
|
||||
return new OutgoingPushMessageList(recipient.getNumber(), timestamp, recipient.getRelay(), messages);
|
||||
}
|
||||
|
||||
private PushBody getEncryptedMessage(PushServiceSocket socket, PushAddress recipient, byte[] plaintext)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
if (!store.containsSession(recipient.getRecipientId(), recipient.getDeviceId())) {
|
||||
try {
|
||||
List<PreKeyBundle> preKeys = socket.getPreKeys(recipient);
|
||||
|
||||
for (PreKeyBundle preKey : preKeys) {
|
||||
try {
|
||||
SessionBuilder sessionBuilder = new SessionBuilder(store, recipient.getRecipientId(), recipient.getDeviceId());
|
||||
sessionBuilder.process(preKey);
|
||||
} catch (org.whispersystems.libaxolotl.UntrustedIdentityException e) {
|
||||
throw new UntrustedIdentityException("Untrusted identity key!", recipient.getNumber(), preKey.getIdentityKey());
|
||||
}
|
||||
}
|
||||
|
||||
if (eventListener.isPresent()) {
|
||||
eventListener.get().onSecurityEvent(recipient.getRecipientId());
|
||||
}
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
TextSecureCipher cipher = new TextSecureCipher(store, recipient.getRecipientId(), recipient.getDeviceId());
|
||||
CiphertextMessage message = cipher.encrypt(plaintext);
|
||||
int remoteRegistrationId = cipher.getRemoteRegistrationId();
|
||||
|
||||
if (message.getType() == CiphertextMessage.PREKEY_TYPE) {
|
||||
return new PushBody(Type.PREKEY_BUNDLE_VALUE, remoteRegistrationId, message.serialize());
|
||||
} else if (message.getType() == CiphertextMessage.WHISPER_TYPE) {
|
||||
return new PushBody(Type.CIPHERTEXT_VALUE, remoteRegistrationId, message.serialize());
|
||||
} else {
|
||||
throw new AssertionError("Unknown ciphertext type: " + message.getType());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleMismatchedDevices(PushServiceSocket socket, PushAddress recipient,
|
||||
MismatchedDevices mismatchedDevices)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
try {
|
||||
for (int extraDeviceId : mismatchedDevices.getExtraDevices()) {
|
||||
store.deleteSession(recipient.getRecipientId(), extraDeviceId);
|
||||
}
|
||||
|
||||
for (int missingDeviceId : mismatchedDevices.getMissingDevices()) {
|
||||
PushAddress device = new PushAddress(recipient.getRecipientId(), recipient.getNumber(),
|
||||
missingDeviceId, recipient.getRelay());
|
||||
PreKeyBundle preKey = socket.getPreKey(device);
|
||||
|
||||
try {
|
||||
SessionBuilder sessionBuilder = new SessionBuilder(store, device.getRecipientId(), device.getDeviceId());
|
||||
sessionBuilder.process(preKey);
|
||||
} catch (org.whispersystems.libaxolotl.UntrustedIdentityException e) {
|
||||
throw new UntrustedIdentityException("Untrusted identity key!", recipient.getNumber(), preKey.getIdentityKey());
|
||||
}
|
||||
}
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleStaleDevices(PushAddress recipient, StaleDevices staleDevices) {
|
||||
long recipientId = recipient.getRecipientId();
|
||||
|
||||
for (int staleDeviceId : staleDevices.getStaleDevices()) {
|
||||
store.deleteSession(recipientId, staleDeviceId);
|
||||
}
|
||||
}
|
||||
|
||||
public static interface EventListener {
|
||||
public void onSecurityEvent(long recipientId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,220 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2013-2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.crypto;
|
||||
|
||||
import org.whispersystems.libaxolotl.InvalidMacException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.internal.util.Util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.ShortBufferException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* Class for streaming an encrypted push attachment off disk.
|
||||
*
|
||||
* @author Moxie Marlinspike
|
||||
*/
|
||||
|
||||
public class AttachmentCipherInputStream extends FileInputStream {
|
||||
|
||||
private static final int BLOCK_SIZE = 16;
|
||||
private static final int CIPHER_KEY_SIZE = 32;
|
||||
private static final int MAC_KEY_SIZE = 32;
|
||||
|
||||
private Cipher cipher;
|
||||
private boolean done;
|
||||
private long totalDataSize;
|
||||
private long totalRead;
|
||||
private byte[] overflowBuffer;
|
||||
|
||||
public AttachmentCipherInputStream(File file, byte[] combinedKeyMaterial)
|
||||
throws IOException, InvalidMessageException
|
||||
{
|
||||
super(file);
|
||||
|
||||
try {
|
||||
byte[][] parts = Util.split(combinedKeyMaterial, CIPHER_KEY_SIZE, MAC_KEY_SIZE);
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
|
||||
mac.init(new SecretKeySpec(parts[1], "HmacSHA256"));
|
||||
|
||||
if (file.length() <= BLOCK_SIZE + mac.getMacLength()) {
|
||||
throw new InvalidMessageException("Message shorter than crypto overhead!");
|
||||
}
|
||||
|
||||
verifyMac(file, mac);
|
||||
|
||||
byte[] iv = new byte[BLOCK_SIZE];
|
||||
readFully(iv);
|
||||
|
||||
this.cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
this.cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(parts[0], "AES"), new IvParameterSpec(iv));
|
||||
|
||||
this.done = false;
|
||||
this.totalRead = 0;
|
||||
this.totalDataSize = file.length() - cipher.getBlockSize() - mac.getMacLength();
|
||||
} catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException | InvalidAlgorithmParameterException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (InvalidMacException e) {
|
||||
throw new InvalidMessageException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer) throws IOException {
|
||||
return read(buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer, int offset, int length) throws IOException {
|
||||
if (totalRead != totalDataSize) return readIncremental(buffer, offset, length);
|
||||
else if (!done) return readFinal(buffer, offset, length);
|
||||
else return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long byteCount) throws IOException {
|
||||
long skipped = 0L;
|
||||
while (skipped < byteCount) {
|
||||
byte[] buf = new byte[Math.min(4096, (int)(byteCount-skipped))];
|
||||
int read = read(buf);
|
||||
|
||||
skipped += read;
|
||||
}
|
||||
|
||||
return skipped;
|
||||
}
|
||||
|
||||
private int readFinal(byte[] buffer, int offset, int length) throws IOException {
|
||||
try {
|
||||
int flourish = cipher.doFinal(buffer, offset);
|
||||
|
||||
done = true;
|
||||
return flourish;
|
||||
} catch (IllegalBlockSizeException | BadPaddingException | ShortBufferException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private int readIncremental(byte[] buffer, int offset, int length) throws IOException {
|
||||
int readLength = 0;
|
||||
if (null != overflowBuffer) {
|
||||
if (overflowBuffer.length > length) {
|
||||
System.arraycopy(overflowBuffer, 0, buffer, offset, length);
|
||||
overflowBuffer = Arrays.copyOfRange(overflowBuffer, length, overflowBuffer.length);
|
||||
return length;
|
||||
} else if (overflowBuffer.length == length) {
|
||||
System.arraycopy(overflowBuffer, 0, buffer, offset, length);
|
||||
overflowBuffer = null;
|
||||
return length;
|
||||
} else {
|
||||
System.arraycopy(overflowBuffer, 0, buffer, offset, overflowBuffer.length);
|
||||
readLength += overflowBuffer.length;
|
||||
offset += readLength;
|
||||
length -= readLength;
|
||||
overflowBuffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (length + totalRead > totalDataSize)
|
||||
length = (int)(totalDataSize - totalRead);
|
||||
|
||||
byte[] internalBuffer = new byte[length];
|
||||
int read = super.read(internalBuffer, 0, internalBuffer.length <= cipher.getBlockSize() ? internalBuffer.length : internalBuffer.length - cipher.getBlockSize());
|
||||
totalRead += read;
|
||||
|
||||
try {
|
||||
int outputLen = cipher.getOutputSize(read);
|
||||
|
||||
if (outputLen <= length) {
|
||||
readLength += cipher.update(internalBuffer, 0, read, buffer, offset);
|
||||
return readLength;
|
||||
}
|
||||
|
||||
byte[] transientBuffer = new byte[outputLen];
|
||||
outputLen = cipher.update(internalBuffer, 0, read, transientBuffer, 0);
|
||||
if (outputLen <= length) {
|
||||
System.arraycopy(transientBuffer, 0, buffer, offset, outputLen);
|
||||
readLength += outputLen;
|
||||
} else {
|
||||
System.arraycopy(transientBuffer, 0, buffer, offset, length);
|
||||
overflowBuffer = Arrays.copyOfRange(transientBuffer, length, outputLen);
|
||||
readLength += length;
|
||||
}
|
||||
return readLength;
|
||||
} catch (ShortBufferException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyMac(File file, Mac mac) throws FileNotFoundException, InvalidMacException {
|
||||
try {
|
||||
FileInputStream fin = new FileInputStream(file);
|
||||
int remainingData = (int) file.length() - mac.getMacLength();
|
||||
byte[] buffer = new byte[4096];
|
||||
|
||||
while (remainingData > 0) {
|
||||
int read = fin.read(buffer, 0, Math.min(buffer.length, remainingData));
|
||||
mac.update(buffer, 0, read);
|
||||
remainingData -= read;
|
||||
}
|
||||
|
||||
byte[] ourMac = mac.doFinal();
|
||||
byte[] theirMac = new byte[mac.getMacLength()];
|
||||
Util.readFully(fin, theirMac);
|
||||
|
||||
if (!Arrays.equals(ourMac, theirMac)) {
|
||||
throw new InvalidMacException("MAC doesn't match!");
|
||||
}
|
||||
} catch (IOException e1) {
|
||||
throw new InvalidMacException(e1);
|
||||
}
|
||||
}
|
||||
|
||||
private void readFully(byte[] buffer) throws IOException {
|
||||
int offset = 0;
|
||||
|
||||
for (;;) {
|
||||
int read = super.read(buffer, offset, buffer.length - offset);
|
||||
|
||||
if (read + offset < buffer.length) offset += read;
|
||||
else return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.crypto;
|
||||
|
||||
import org.whispersystems.textsecure.internal.util.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class AttachmentCipherOutputStream extends OutputStream {
|
||||
|
||||
private final Cipher cipher;
|
||||
private final Mac mac;
|
||||
private final OutputStream outputStream;
|
||||
|
||||
private long ciphertextLength = 0;
|
||||
|
||||
public AttachmentCipherOutputStream(byte[] combinedKeyMaterial,
|
||||
OutputStream outputStream)
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
this.outputStream = outputStream;
|
||||
this.cipher = initializeCipher();
|
||||
this.mac = initializeMac();
|
||||
|
||||
byte[][] keyParts = Util.split(combinedKeyMaterial, 32, 32);
|
||||
|
||||
this.cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyParts[0], "AES"));
|
||||
this.mac.init(new SecretKeySpec(keyParts[1], "HmacSHA256"));
|
||||
|
||||
mac.update(cipher.getIV());
|
||||
outputStream.write(cipher.getIV());
|
||||
ciphertextLength += cipher.getIV().length;
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer) throws IOException {
|
||||
write(buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer, int offset, int length) throws IOException {
|
||||
byte[] ciphertext = cipher.update(buffer, offset, length);
|
||||
|
||||
if (ciphertext != null) {
|
||||
mac.update(ciphertext);
|
||||
outputStream.write(ciphertext);
|
||||
ciphertextLength += ciphertext.length;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) {
|
||||
throw new AssertionError("NYI");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
try {
|
||||
byte[] ciphertext = cipher.doFinal();
|
||||
byte[] auth = mac.doFinal(ciphertext);
|
||||
|
||||
outputStream.write(ciphertext);
|
||||
outputStream.write(auth);
|
||||
|
||||
ciphertextLength += ciphertext.length;
|
||||
ciphertextLength += auth.length;
|
||||
|
||||
outputStream.flush();
|
||||
} catch (IllegalBlockSizeException | BadPaddingException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static long getCiphertextLength(long plaintextLength) {
|
||||
return 16 + (((plaintextLength / 16) +1) * 16) + 32;
|
||||
}
|
||||
|
||||
private Mac initializeMac() {
|
||||
try {
|
||||
return Mac.getInstance("HmacSHA256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Cipher initializeCipher() {
|
||||
try {
|
||||
return Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.crypto;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import org.whispersystems.libaxolotl.DuplicateMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyIdException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
import org.whispersystems.libaxolotl.NoSessionException;
|
||||
import org.whispersystems.libaxolotl.SessionCipher;
|
||||
import org.whispersystems.libaxolotl.UntrustedIdentityException;
|
||||
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||
import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage;
|
||||
import org.whispersystems.libaxolotl.protocol.WhisperMessage;
|
||||
import org.whispersystems.libaxolotl.state.AxolotlStore;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureAttachment;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureAttachmentPointer;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureEnvelope;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureGroup;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureMessage;
|
||||
import org.whispersystems.textsecure.internal.push.PushTransportDetails;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent;
|
||||
import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent.GroupContext.Type.DELIVER;
|
||||
|
||||
public class TextSecureCipher {
|
||||
|
||||
private final SessionCipher sessionCipher;
|
||||
|
||||
public TextSecureCipher(AxolotlStore axolotlStore, long recipientId, int deviceId) {
|
||||
this.sessionCipher = new SessionCipher(axolotlStore, recipientId, deviceId);
|
||||
}
|
||||
|
||||
public CiphertextMessage encrypt(byte[] unpaddedMessage) {
|
||||
PushTransportDetails transportDetails = new PushTransportDetails(sessionCipher.getSessionVersion());
|
||||
return sessionCipher.encrypt(transportDetails.getPaddedMessageBody(unpaddedMessage));
|
||||
}
|
||||
|
||||
public TextSecureMessage decrypt(TextSecureEnvelope envelope)
|
||||
throws InvalidVersionException, InvalidMessageException, InvalidKeyException,
|
||||
DuplicateMessageException, InvalidKeyIdException, UntrustedIdentityException,
|
||||
LegacyMessageException, NoSessionException
|
||||
{
|
||||
try {
|
||||
byte[] paddedMessage;
|
||||
|
||||
if (envelope.isPreKeyWhisperMessage()) {
|
||||
paddedMessage = sessionCipher.decrypt(new PreKeyWhisperMessage(envelope.getMessage()));
|
||||
} else if (envelope.isWhisperMessage()) {
|
||||
paddedMessage = sessionCipher.decrypt(new WhisperMessage(envelope.getMessage()));
|
||||
} else if (envelope.isPlaintext()) {
|
||||
paddedMessage = envelope.getMessage();
|
||||
} else {
|
||||
throw new InvalidMessageException("Unknown type: " + envelope.getType());
|
||||
}
|
||||
|
||||
PushTransportDetails transportDetails = new PushTransportDetails(sessionCipher.getSessionVersion());
|
||||
PushMessageContent content = PushMessageContent.parseFrom(transportDetails.getStrippedPaddingMessageBody(paddedMessage));
|
||||
|
||||
return createTextSecureMessage(envelope, content);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw new InvalidMessageException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public int getRemoteRegistrationId() {
|
||||
return sessionCipher.getRemoteRegistrationId();
|
||||
}
|
||||
|
||||
private TextSecureMessage createTextSecureMessage(TextSecureEnvelope envelope, PushMessageContent content) {
|
||||
TextSecureGroup groupInfo = createGroupInfo(envelope, content);
|
||||
List<TextSecureAttachment> attachments = new LinkedList<>();
|
||||
boolean endSession = ((content.getFlags() & PushMessageContent.Flags.END_SESSION_VALUE) != 0);
|
||||
boolean secure = envelope.isWhisperMessage() || envelope.isPreKeyWhisperMessage();
|
||||
|
||||
for (PushMessageContent.AttachmentPointer pointer : content.getAttachmentsList()) {
|
||||
attachments.add(new TextSecureAttachmentPointer(pointer.getId(),
|
||||
pointer.getContentType(),
|
||||
pointer.getKey().toByteArray(),
|
||||
envelope.getRelay()));
|
||||
}
|
||||
|
||||
return new TextSecureMessage(envelope.getTimestamp(), groupInfo, attachments,
|
||||
content.getBody(), secure, endSession);
|
||||
}
|
||||
|
||||
private TextSecureGroup createGroupInfo(TextSecureEnvelope envelope, PushMessageContent content) {
|
||||
if (!content.hasGroup()) return null;
|
||||
|
||||
TextSecureGroup.Type type;
|
||||
|
||||
switch (content.getGroup().getType()) {
|
||||
case DELIVER: type = TextSecureGroup.Type.DELIVER; break;
|
||||
case UPDATE: type = TextSecureGroup.Type.UPDATE; break;
|
||||
case QUIT: type = TextSecureGroup.Type.QUIT; break;
|
||||
default: type = TextSecureGroup.Type.UNKNOWN; break;
|
||||
}
|
||||
|
||||
if (content.getGroup().getType() != DELIVER) {
|
||||
String name = null;
|
||||
List<String> members = null;
|
||||
TextSecureAttachmentPointer avatar = null;
|
||||
|
||||
if (content.getGroup().hasName()) {
|
||||
name = content.getGroup().getName();
|
||||
}
|
||||
|
||||
if (content.getGroup().getMembersCount() > 0) {
|
||||
members = content.getGroup().getMembersList();
|
||||
}
|
||||
|
||||
if (content.getGroup().hasAvatar()) {
|
||||
avatar = new TextSecureAttachmentPointer(content.getGroup().getAvatar().getId(),
|
||||
content.getGroup().getAvatar().getContentType(),
|
||||
content.getGroup().getAvatar().getKey().toByteArray(),
|
||||
envelope.getRelay());
|
||||
}
|
||||
|
||||
return new TextSecureGroup(type, content.getGroup().getId().toByteArray(), name, members, avatar);
|
||||
}
|
||||
|
||||
return new TextSecureGroup(content.getGroup().getId().toByteArray());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.crypto;
|
||||
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
|
||||
public class UntrustedIdentityException extends Exception {
|
||||
|
||||
private final IdentityKey identityKey;
|
||||
private final String e164number;
|
||||
|
||||
public UntrustedIdentityException(String s, String e164number, IdentityKey identityKey) {
|
||||
super(s);
|
||||
this.e164number = e164number;
|
||||
this.identityKey = identityKey;
|
||||
}
|
||||
|
||||
public UntrustedIdentityException(UntrustedIdentityException e) {
|
||||
this(e.getMessage(), e.getE164Number(), e.getIdentityKey());
|
||||
}
|
||||
|
||||
public IdentityKey getIdentityKey() {
|
||||
return identityKey;
|
||||
}
|
||||
|
||||
public String getE164Number() {
|
||||
return e164number;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.messages;
|
||||
|
||||
public abstract class TextSecureAttachment {
|
||||
|
||||
private final String contentType;
|
||||
|
||||
protected TextSecureAttachment(String contentType) {
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public abstract boolean isStream();
|
||||
public abstract boolean isPointer();
|
||||
|
||||
public TextSecureAttachmentStream asStream() {
|
||||
return (TextSecureAttachmentStream)this;
|
||||
}
|
||||
|
||||
public TextSecureAttachmentPointer asPointer() {
|
||||
return (TextSecureAttachmentPointer)this;
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.messages;
|
||||
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
|
||||
public class TextSecureAttachmentPointer extends TextSecureAttachment {
|
||||
|
||||
private final long id;
|
||||
private final byte[] key;
|
||||
private final Optional<String> relay;
|
||||
|
||||
public TextSecureAttachmentPointer(long id, String contentType, byte[] key, String relay) {
|
||||
super(contentType);
|
||||
this.id = id;
|
||||
this.key = key;
|
||||
this.relay = Optional.fromNullable(relay);
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public byte[] getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStream() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPointer() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Optional<String> getRelay() {
|
||||
return relay;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.messages;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public class TextSecureAttachmentStream extends TextSecureAttachment {
|
||||
|
||||
private final InputStream inputStream;
|
||||
private final long length;
|
||||
|
||||
public TextSecureAttachmentStream(InputStream inputStream, String contentType, long length) {
|
||||
super(contentType);
|
||||
this.inputStream = inputStream;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStream() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPointer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
public long getLength() {
|
||||
return length;
|
||||
}
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.messages;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.textsecure.internal.push.PushMessageProtos.IncomingPushMessageSignal;
|
||||
import org.whispersystems.textsecure.internal.util.Base64;
|
||||
import org.whispersystems.textsecure.internal.util.Hex;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class TextSecureEnvelope {
|
||||
|
||||
private static final String TAG = TextSecureEnvelope.class.getSimpleName();
|
||||
|
||||
private static final int SUPPORTED_VERSION = 1;
|
||||
private static final int CIPHER_KEY_SIZE = 32;
|
||||
private static final int MAC_KEY_SIZE = 20;
|
||||
private static final int MAC_SIZE = 10;
|
||||
|
||||
private static final int VERSION_OFFSET = 0;
|
||||
private static final int VERSION_LENGTH = 1;
|
||||
private static final int IV_OFFSET = VERSION_OFFSET + VERSION_LENGTH;
|
||||
private static final int IV_LENGTH = 16;
|
||||
private static final int CIPHERTEXT_OFFSET = IV_OFFSET + IV_LENGTH;
|
||||
|
||||
private final IncomingPushMessageSignal signal;
|
||||
|
||||
public TextSecureEnvelope(String message, String signalingKey)
|
||||
throws IOException, InvalidVersionException
|
||||
{
|
||||
byte[] ciphertext = Base64.decode(message);
|
||||
|
||||
if (ciphertext.length < VERSION_LENGTH || ciphertext[VERSION_OFFSET] != SUPPORTED_VERSION)
|
||||
throw new InvalidVersionException("Unsupported version!");
|
||||
|
||||
SecretKeySpec cipherKey = getCipherKey(signalingKey);
|
||||
SecretKeySpec macKey = getMacKey(signalingKey);
|
||||
|
||||
verifyMac(ciphertext, macKey);
|
||||
|
||||
this.signal = IncomingPushMessageSignal.parseFrom(getPlaintext(ciphertext, cipherKey));
|
||||
}
|
||||
|
||||
public TextSecureEnvelope(int type, String source, int sourceDevice,
|
||||
String relay, long timestamp, byte[] message)
|
||||
{
|
||||
this.signal = IncomingPushMessageSignal.newBuilder()
|
||||
.setType(IncomingPushMessageSignal.Type.valueOf(type))
|
||||
.setSource(source)
|
||||
.setSourceDevice(sourceDevice)
|
||||
.setRelay(relay)
|
||||
.setTimestamp(timestamp)
|
||||
.setMessage(ByteString.copyFrom(message))
|
||||
.build();
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return signal.getSource();
|
||||
}
|
||||
|
||||
public int getSourceDevice() {
|
||||
return signal.getSourceDevice();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return signal.getType().getNumber();
|
||||
}
|
||||
|
||||
public String getRelay() {
|
||||
return signal.getRelay();
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return signal.getTimestamp();
|
||||
}
|
||||
|
||||
public byte[] getMessage() {
|
||||
return signal.getMessage().toByteArray();
|
||||
}
|
||||
|
||||
public boolean isWhisperMessage() {
|
||||
return signal.getType().getNumber() == IncomingPushMessageSignal.Type.CIPHERTEXT_VALUE;
|
||||
}
|
||||
|
||||
public boolean isPreKeyWhisperMessage() {
|
||||
return signal.getType().getNumber() == IncomingPushMessageSignal.Type.PREKEY_BUNDLE_VALUE;
|
||||
}
|
||||
|
||||
public boolean isPlaintext() {
|
||||
return signal.getType().getNumber() == IncomingPushMessageSignal.Type.PLAINTEXT_VALUE;
|
||||
}
|
||||
|
||||
public boolean isReceipt() {
|
||||
return signal.getType().getNumber() == IncomingPushMessageSignal.Type.RECEIPT_VALUE;
|
||||
}
|
||||
|
||||
private byte[] getPlaintext(byte[] ciphertext, SecretKeySpec cipherKey) throws IOException {
|
||||
try {
|
||||
byte[] ivBytes = new byte[IV_LENGTH];
|
||||
System.arraycopy(ciphertext, IV_OFFSET, ivBytes, 0, ivBytes.length);
|
||||
IvParameterSpec iv = new IvParameterSpec(ivBytes);
|
||||
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, cipherKey, iv);
|
||||
|
||||
return cipher.doFinal(ciphertext, CIPHERTEXT_OFFSET,
|
||||
ciphertext.length - VERSION_LENGTH - IV_LENGTH - MAC_SIZE);
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (BadPaddingException e) {
|
||||
Log.w(TAG, e);
|
||||
throw new IOException("Bad padding?");
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyMac(byte[] ciphertext, SecretKeySpec macKey) throws IOException {
|
||||
try {
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(macKey);
|
||||
|
||||
if (ciphertext.length < MAC_SIZE + 1)
|
||||
throw new IOException("Invalid MAC!");
|
||||
|
||||
mac.update(ciphertext, 0, ciphertext.length - MAC_SIZE);
|
||||
|
||||
byte[] ourMacFull = mac.doFinal();
|
||||
byte[] ourMacBytes = new byte[MAC_SIZE];
|
||||
System.arraycopy(ourMacFull, 0, ourMacBytes, 0, ourMacBytes.length);
|
||||
|
||||
byte[] theirMacBytes = new byte[MAC_SIZE];
|
||||
System.arraycopy(ciphertext, ciphertext.length-MAC_SIZE, theirMacBytes, 0, theirMacBytes.length);
|
||||
|
||||
Log.w(TAG, "Our MAC: " + Hex.toString(ourMacBytes));
|
||||
Log.w(TAG, "Thr MAC: " + Hex.toString(theirMacBytes));
|
||||
|
||||
if (!Arrays.equals(ourMacBytes, theirMacBytes)) {
|
||||
throw new IOException("Invalid MAC compare!");
|
||||
}
|
||||
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private SecretKeySpec getCipherKey(String signalingKey) throws IOException {
|
||||
byte[] signalingKeyBytes = Base64.decode(signalingKey);
|
||||
byte[] cipherKey = new byte[CIPHER_KEY_SIZE];
|
||||
System.arraycopy(signalingKeyBytes, 0, cipherKey, 0, cipherKey.length);
|
||||
|
||||
return new SecretKeySpec(cipherKey, "AES");
|
||||
}
|
||||
|
||||
|
||||
private SecretKeySpec getMacKey(String signalingKey) throws IOException {
|
||||
byte[] signalingKeyBytes = Base64.decode(signalingKey);
|
||||
byte[] macKey = new byte[MAC_KEY_SIZE];
|
||||
System.arraycopy(signalingKeyBytes, CIPHER_KEY_SIZE, macKey, 0, macKey.length);
|
||||
|
||||
return new SecretKeySpec(macKey, "HmacSHA256");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.messages;
|
||||
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TextSecureGroup {
|
||||
|
||||
public enum Type {
|
||||
UNKNOWN,
|
||||
UPDATE,
|
||||
DELIVER,
|
||||
QUIT
|
||||
}
|
||||
|
||||
private final byte[] groupId;
|
||||
private final Type type;
|
||||
private final Optional<String> name;
|
||||
private final Optional<List<String>> members;
|
||||
private final Optional<TextSecureAttachment> avatar;
|
||||
|
||||
|
||||
public TextSecureGroup(byte[] groupId) {
|
||||
this(Type.DELIVER, groupId, null, null, null);
|
||||
}
|
||||
|
||||
public TextSecureGroup(Type type, byte[] groupId, String name,
|
||||
List<String> members,
|
||||
TextSecureAttachment avatar)
|
||||
{
|
||||
this.type = type;
|
||||
this.groupId = groupId;
|
||||
this.name = Optional.fromNullable(name);
|
||||
this.members = Optional.fromNullable(members);
|
||||
this.avatar = Optional.fromNullable(avatar);
|
||||
}
|
||||
|
||||
public byte[] getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Optional<String> getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Optional<List<String>> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
public Optional<TextSecureAttachment> getAvatar() {
|
||||
return avatar;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.messages;
|
||||
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TextSecureMessage {
|
||||
|
||||
private final long timestamp;
|
||||
private final Optional<List<TextSecureAttachment>> attachments;
|
||||
private final Optional<String> body;
|
||||
private final Optional<TextSecureGroup> group;
|
||||
private final boolean secure;
|
||||
private final boolean endSession;
|
||||
|
||||
public TextSecureMessage(long timestamp, String body) {
|
||||
this(timestamp, null, body);
|
||||
}
|
||||
|
||||
public TextSecureMessage(long timestamp, List<TextSecureAttachment> attachments, String body) {
|
||||
this(timestamp, null, attachments, body);
|
||||
}
|
||||
|
||||
public TextSecureMessage(long timestamp, TextSecureGroup group, List<TextSecureAttachment> attachments, String body) {
|
||||
this(timestamp, group, attachments, body, true, false);
|
||||
}
|
||||
|
||||
public TextSecureMessage(long timestamp, TextSecureGroup group, List<TextSecureAttachment> attachments, String body, boolean secure, boolean endSession) {
|
||||
this.timestamp = timestamp;
|
||||
this.body = Optional.fromNullable(body);
|
||||
this.group = Optional.fromNullable(group);
|
||||
this.secure = secure;
|
||||
this.endSession = endSession;
|
||||
|
||||
if (attachments != null && !attachments.isEmpty()) {
|
||||
this.attachments = Optional.of(attachments);
|
||||
} else {
|
||||
this.attachments = Optional.absent();
|
||||
}
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public Optional<List<TextSecureAttachment>> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
public Optional<String> getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public Optional<TextSecureGroup> getGroupInfo() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public boolean isSecure() {
|
||||
return secure;
|
||||
}
|
||||
|
||||
public boolean isEndSession() {
|
||||
return endSession;
|
||||
}
|
||||
|
||||
public boolean isGroupUpdate() {
|
||||
return group.isPresent() && group.get().getType() != TextSecureGroup.Type.DELIVER;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.push;
|
||||
|
||||
public class ContactTokenDetails {
|
||||
|
||||
private String token;
|
||||
private String relay;
|
||||
private String number;
|
||||
private boolean supportsSms;
|
||||
|
||||
public ContactTokenDetails() {}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public String getRelay() {
|
||||
return relay;
|
||||
}
|
||||
|
||||
public boolean isSupportsSms() {
|
||||
return supportsSms;
|
||||
}
|
||||
|
||||
public void setNumber(String number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.push;
|
||||
|
||||
public class PushAddress {
|
||||
|
||||
public static final int DEFAULT_DEVICE_ID = 1;
|
||||
|
||||
private final long recipientId;
|
||||
private final String e164number;
|
||||
private final int deviceId;
|
||||
private final String relay;
|
||||
|
||||
public PushAddress(long recipientId, String e164number, int deviceId, String relay) {
|
||||
this.recipientId = recipientId;
|
||||
this.e164number = e164number;
|
||||
this.deviceId = deviceId;
|
||||
this.relay = relay;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return e164number;
|
||||
}
|
||||
|
||||
public String getRelay() {
|
||||
return relay;
|
||||
}
|
||||
|
||||
public long getRecipientId() {
|
||||
return recipientId;
|
||||
}
|
||||
|
||||
public int getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.push;
|
||||
|
||||
import com.google.thoughtcrimegson.GsonBuilder;
|
||||
import com.google.thoughtcrimegson.JsonDeserializationContext;
|
||||
import com.google.thoughtcrimegson.JsonDeserializer;
|
||||
import com.google.thoughtcrimegson.JsonElement;
|
||||
import com.google.thoughtcrimegson.JsonParseException;
|
||||
import com.google.thoughtcrimegson.JsonPrimitive;
|
||||
import com.google.thoughtcrimegson.JsonSerializationContext;
|
||||
import com.google.thoughtcrimegson.JsonSerializer;
|
||||
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.textsecure.internal.util.Base64;
|
||||
import org.whispersystems.textsecure.internal.push.PreKeyEntity;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class SignedPreKeyEntity extends PreKeyEntity {
|
||||
|
||||
private byte[] signature;
|
||||
|
||||
public SignedPreKeyEntity() {}
|
||||
|
||||
public SignedPreKeyEntity(int keyId, ECPublicKey publicKey, byte[] signature) {
|
||||
super(keyId, publicKey);
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public byte[] getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public static String toJson(SignedPreKeyEntity entity) {
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
return forBuilder(builder).create().toJson(entity);
|
||||
}
|
||||
|
||||
public static SignedPreKeyEntity fromJson(String serialized) {
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
return forBuilder(builder).create().fromJson(serialized, SignedPreKeyEntity.class);
|
||||
}
|
||||
|
||||
public static GsonBuilder forBuilder(GsonBuilder builder) {
|
||||
return PreKeyEntity.forBuilder(builder)
|
||||
.registerTypeAdapter(byte[].class, new ByteArrayJsonAdapter());
|
||||
|
||||
}
|
||||
|
||||
private static class ByteArrayJsonAdapter
|
||||
implements JsonSerializer<byte[]>, JsonDeserializer<byte[]>
|
||||
{
|
||||
@Override
|
||||
public JsonElement serialize(byte[] signature, Type type,
|
||||
JsonSerializationContext jsonSerializationContext)
|
||||
{
|
||||
return new JsonPrimitive(Base64.encodeBytesWithoutPadding(signature));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] deserialize(JsonElement jsonElement, Type type,
|
||||
JsonDeserializationContext jsonDeserializationContext)
|
||||
throws JsonParseException
|
||||
{
|
||||
try {
|
||||
return Base64.decodeWithoutPadding(jsonElement.getAsJsonPrimitive().getAsString());
|
||||
} catch (IOException e) {
|
||||
throw new JsonParseException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.push;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public interface TrustStore {
|
||||
public InputStream getKeyStoreInputStream();
|
||||
public String getKeyStorePassword();
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.push.exceptions;
|
||||
|
||||
public class AuthorizationFailedException extends NonSuccessfulResponseCodeException {
|
||||
public AuthorizationFailedException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.push.exceptions;
|
||||
|
||||
import org.whispersystems.textsecure.api.crypto.UntrustedIdentityException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EncapsulatedExceptions extends Throwable {
|
||||
|
||||
private final List<UntrustedIdentityException> untrustedIdentityExceptions;
|
||||
private final List<UnregisteredUserException> unregisteredUserExceptions;
|
||||
|
||||
public EncapsulatedExceptions(List<UntrustedIdentityException> untrustedIdentities,
|
||||
List<UnregisteredUserException> unregisteredUsers)
|
||||
{
|
||||
this.untrustedIdentityExceptions = untrustedIdentities;
|
||||
this.unregisteredUserExceptions = unregisteredUsers;
|
||||
}
|
||||
|
||||
public List<UntrustedIdentityException> getUntrustedIdentityExceptions() {
|
||||
return untrustedIdentityExceptions;
|
||||
}
|
||||
|
||||
public List<UnregisteredUserException> getUnregisteredUserExceptions() {
|
||||
return unregisteredUserExceptions;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.push.exceptions;
|
||||
|
||||
public class ExpectationFailedException extends NonSuccessfulResponseCodeException {
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.push.exceptions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class NonSuccessfulResponseCodeException extends IOException {
|
||||
|
||||
public NonSuccessfulResponseCodeException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public NonSuccessfulResponseCodeException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.push.exceptions;
|
||||
|
||||
public class NotFoundException extends NonSuccessfulResponseCodeException {
|
||||
public NotFoundException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.push.exceptions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class PushNetworkException extends IOException {
|
||||
public PushNetworkException(Exception exception) {
|
||||
super(exception);
|
||||
}
|
||||
|
||||
public PushNetworkException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.push.exceptions;
|
||||
|
||||
public class RateLimitException extends NonSuccessfulResponseCodeException {
|
||||
public RateLimitException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.push.exceptions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class UnregisteredUserException extends IOException {
|
||||
|
||||
private final String e164number;
|
||||
|
||||
public UnregisteredUserException(String e164number, Exception exception) {
|
||||
super(exception);
|
||||
this.e164number = e164number;
|
||||
}
|
||||
|
||||
public String getE164Number() {
|
||||
return e164number;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.util;
|
||||
|
||||
public class InvalidNumberException extends Throwable {
|
||||
public InvalidNumberException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.i18n.phonenumbers.NumberParseException;
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
|
||||
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Phone number formats are a pain.
|
||||
*
|
||||
* @author Moxie Marlinspike
|
||||
*
|
||||
*/
|
||||
public class PhoneNumberFormatter {
|
||||
|
||||
private static final String TAG = PhoneNumberFormatter.class.getSimpleName();
|
||||
|
||||
public static boolean isValidNumber(String number) {
|
||||
return number.matches("^\\+[0-9]{10,}");
|
||||
}
|
||||
|
||||
private static String impreciseFormatNumber(String number, String localNumber)
|
||||
throws InvalidNumberException
|
||||
{
|
||||
number = number.replaceAll("[^0-9+]", "");
|
||||
|
||||
if (number.charAt(0) == '+')
|
||||
return number;
|
||||
|
||||
if (localNumber.charAt(0) == '+')
|
||||
localNumber = localNumber.substring(1);
|
||||
|
||||
if (localNumber.length() == number.length() || number.length() > localNumber.length())
|
||||
return "+" + number;
|
||||
|
||||
int difference = localNumber.length() - number.length();
|
||||
|
||||
return "+" + localNumber.substring(0, difference) + number;
|
||||
}
|
||||
|
||||
public static String formatNumberInternational(String number) {
|
||||
try {
|
||||
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
|
||||
PhoneNumber parsedNumber = util.parse(number, null);
|
||||
return util.format(parsedNumber, PhoneNumberFormat.INTERNATIONAL);
|
||||
} catch (NumberParseException e) {
|
||||
Log.w(TAG, e);
|
||||
return number;
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatNumber(String number, String localNumber)
|
||||
throws InvalidNumberException
|
||||
{
|
||||
if (number.contains("@")) {
|
||||
throw new InvalidNumberException("Possible attempt to use email address.");
|
||||
}
|
||||
|
||||
number = number.replaceAll("[^0-9+]", "");
|
||||
|
||||
if (number.length() == 0) {
|
||||
throw new InvalidNumberException("No valid characters found.");
|
||||
}
|
||||
|
||||
if (number.charAt(0) == '+')
|
||||
return number;
|
||||
|
||||
try {
|
||||
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
|
||||
PhoneNumber localNumberObject = util.parse(localNumber, null);
|
||||
|
||||
String localCountryCode = util.getRegionCodeForNumber(localNumberObject);
|
||||
Log.w(TAG, "Got local CC: " + localCountryCode);
|
||||
|
||||
PhoneNumber numberObject = util.parse(number, localCountryCode);
|
||||
return util.format(numberObject, PhoneNumberFormat.E164);
|
||||
} catch (NumberParseException e) {
|
||||
Log.w(TAG, e);
|
||||
return impreciseFormatNumber(number, localNumber);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getRegionDisplayName(String regionCode) {
|
||||
return (regionCode == null || regionCode.equals("ZZ") || regionCode.equals(PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY))
|
||||
? "Unknown country" : new Locale("", regionCode).getDisplayCountry(Locale.getDefault());
|
||||
}
|
||||
|
||||
public static String formatE164(String countryCode, String number) {
|
||||
try {
|
||||
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
|
||||
int parsedCountryCode = Integer.parseInt(countryCode);
|
||||
PhoneNumber parsedNumber = util.parse(number,
|
||||
util.getRegionCodeForCountryCode(parsedCountryCode));
|
||||
|
||||
return util.format(parsedNumber, PhoneNumberUtil.PhoneNumberFormat.E164);
|
||||
} catch (NumberParseException | NumberFormatException npe) {
|
||||
Log.w(TAG, npe);
|
||||
}
|
||||
|
||||
return "+" +
|
||||
countryCode.replaceAll("[^0-9]", "").replaceAll("^0*", "") +
|
||||
number.replaceAll("[^0-9]", "");
|
||||
}
|
||||
|
||||
public static String getInternationalFormatFromE164(String e164number) {
|
||||
try {
|
||||
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
|
||||
PhoneNumber parsedNumber = util.parse(e164number, null);
|
||||
return util.format(parsedNumber, PhoneNumberFormat.INTERNATIONAL);
|
||||
} catch (NumberParseException e) {
|
||||
Log.w(TAG, e);
|
||||
return e164number;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push;
|
||||
|
||||
public class AccountAttributes {
|
||||
|
||||
private String signalingKey;
|
||||
private boolean supportsSms;
|
||||
private int registrationId;
|
||||
|
||||
public AccountAttributes(String signalingKey, boolean supportsSms, int registrationId) {
|
||||
this.signalingKey = signalingKey;
|
||||
this.supportsSms = supportsSms;
|
||||
this.registrationId = registrationId;
|
||||
}
|
||||
|
||||
public AccountAttributes() {}
|
||||
|
||||
public String getSignalingKey() {
|
||||
return signalingKey;
|
||||
}
|
||||
|
||||
public boolean isSupportsSms() {
|
||||
return supportsSms;
|
||||
}
|
||||
|
||||
public int getRegistrationId() {
|
||||
return registrationId;
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push;
|
||||
|
||||
import org.whispersystems.textsecure.api.push.ContactTokenDetails;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ContactTokenDetailsList {
|
||||
|
||||
private List<ContactTokenDetails> contacts;
|
||||
|
||||
public ContactTokenDetailsList() {}
|
||||
|
||||
public List<ContactTokenDetails> getContacts() {
|
||||
return contacts;
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ContactTokenList {
|
||||
|
||||
private List<String> contacts;
|
||||
|
||||
public ContactTokenList(List<String> contacts) {
|
||||
this.contacts = contacts;
|
||||
}
|
||||
|
||||
public ContactTokenList() {}
|
||||
|
||||
public List<String> getContacts() {
|
||||
return contacts;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MismatchedDevices {
|
||||
private List<Integer> missingDevices;
|
||||
|
||||
private List<Integer> extraDevices;
|
||||
|
||||
public List<Integer> getMissingDevices() {
|
||||
return missingDevices;
|
||||
}
|
||||
|
||||
public List<Integer> getExtraDevices() {
|
||||
return extraDevices;
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2013 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push;
|
||||
|
||||
|
||||
import org.whispersystems.textsecure.api.push.PushAddress;
|
||||
import org.whispersystems.textsecure.internal.util.Base64;
|
||||
|
||||
public class OutgoingPushMessage {
|
||||
|
||||
private int type;
|
||||
private int destinationDeviceId;
|
||||
private int destinationRegistrationId;
|
||||
private String body;
|
||||
|
||||
public OutgoingPushMessage(PushAddress address, PushBody body) {
|
||||
this.type = body.getType();
|
||||
this.destinationDeviceId = address.getDeviceId();
|
||||
this.destinationRegistrationId = body.getRemoteRegistrationId();
|
||||
this.body = Base64.encodeBytes(body.getBody());
|
||||
}
|
||||
|
||||
public int getDestinationDeviceId() {
|
||||
return destinationDeviceId;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getDestinationRegistrationId() {
|
||||
return destinationRegistrationId;
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class OutgoingPushMessageList {
|
||||
|
||||
private String destination;
|
||||
|
||||
private String relay;
|
||||
|
||||
private long timestamp;
|
||||
|
||||
private List<OutgoingPushMessage> messages;
|
||||
|
||||
public OutgoingPushMessageList(String destination, long timestamp, String relay,
|
||||
List<OutgoingPushMessage> messages)
|
||||
{
|
||||
this.timestamp = timestamp;
|
||||
this.destination = destination;
|
||||
this.relay = relay;
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
public String getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public List<OutgoingPushMessage> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
public String getRelay() {
|
||||
return relay;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push;
|
||||
|
||||
import com.google.thoughtcrimegson.GsonBuilder;
|
||||
import com.google.thoughtcrimegson.JsonDeserializationContext;
|
||||
import com.google.thoughtcrimegson.JsonDeserializer;
|
||||
import com.google.thoughtcrimegson.JsonElement;
|
||||
import com.google.thoughtcrimegson.JsonParseException;
|
||||
import com.google.thoughtcrimegson.JsonPrimitive;
|
||||
import com.google.thoughtcrimegson.JsonSerializationContext;
|
||||
import com.google.thoughtcrimegson.JsonSerializer;
|
||||
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.textsecure.internal.util.Base64;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class PreKeyEntity {
|
||||
|
||||
private int keyId;
|
||||
private ECPublicKey publicKey;
|
||||
|
||||
public PreKeyEntity() {}
|
||||
|
||||
public PreKeyEntity(int keyId, ECPublicKey publicKey) {
|
||||
this.keyId = keyId;
|
||||
this.publicKey = publicKey;
|
||||
}
|
||||
|
||||
public int getKeyId() {
|
||||
return keyId;
|
||||
}
|
||||
|
||||
public ECPublicKey getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
public static GsonBuilder forBuilder(GsonBuilder builder) {
|
||||
return builder.registerTypeAdapter(ECPublicKey.class, new ECPublicKeyJsonAdapter());
|
||||
}
|
||||
|
||||
|
||||
private static class ECPublicKeyJsonAdapter
|
||||
implements JsonSerializer<ECPublicKey>, JsonDeserializer<ECPublicKey>
|
||||
{
|
||||
@Override
|
||||
public JsonElement serialize(ECPublicKey preKeyPublic, Type type,
|
||||
JsonSerializationContext jsonSerializationContext)
|
||||
{
|
||||
return new JsonPrimitive(Base64.encodeBytesWithoutPadding(preKeyPublic.serialize()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ECPublicKey deserialize(JsonElement jsonElement, Type type,
|
||||
JsonDeserializationContext jsonDeserializationContext)
|
||||
throws JsonParseException
|
||||
{
|
||||
try {
|
||||
return Curve.decodePoint(Base64.decodeWithoutPadding(jsonElement.getAsJsonPrimitive().getAsString()), 0);
|
||||
} catch (InvalidKeyException | IOException e) {
|
||||
throw new JsonParseException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push;
|
||||
|
||||
import com.google.thoughtcrimegson.GsonBuilder;
|
||||
import com.google.thoughtcrimegson.JsonDeserializationContext;
|
||||
import com.google.thoughtcrimegson.JsonDeserializer;
|
||||
import com.google.thoughtcrimegson.JsonElement;
|
||||
import com.google.thoughtcrimegson.JsonParseException;
|
||||
import com.google.thoughtcrimegson.JsonPrimitive;
|
||||
import com.google.thoughtcrimegson.JsonSerializationContext;
|
||||
import com.google.thoughtcrimegson.JsonSerializer;
|
||||
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.internal.util.Base64;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
public class PreKeyResponse {
|
||||
|
||||
private IdentityKey identityKey;
|
||||
private List<PreKeyResponseItem> devices;
|
||||
|
||||
public IdentityKey getIdentityKey() {
|
||||
return identityKey;
|
||||
}
|
||||
|
||||
public List<PreKeyResponseItem> getDevices() {
|
||||
return devices;
|
||||
}
|
||||
|
||||
public static PreKeyResponse fromJson(String serialized) {
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
return PreKeyResponseItem.forBuilder(builder)
|
||||
.registerTypeAdapter(IdentityKey.class, new IdentityKeyJsonAdapter())
|
||||
.create().fromJson(serialized, PreKeyResponse.class);
|
||||
}
|
||||
|
||||
public static class IdentityKeyJsonAdapter
|
||||
implements JsonSerializer<IdentityKey>, JsonDeserializer<IdentityKey>
|
||||
{
|
||||
@Override
|
||||
public JsonElement serialize(IdentityKey identityKey, Type type,
|
||||
JsonSerializationContext jsonSerializationContext)
|
||||
{
|
||||
return new JsonPrimitive(Base64.encodeBytesWithoutPadding(identityKey.serialize()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentityKey deserialize(JsonElement jsonElement, Type type,
|
||||
JsonDeserializationContext jsonDeserializationContext)
|
||||
throws JsonParseException
|
||||
{
|
||||
try {
|
||||
return new IdentityKey(Base64.decodeWithoutPadding(jsonElement.getAsJsonPrimitive().getAsString()), 0);
|
||||
} catch (InvalidKeyException | IOException e) {
|
||||
throw new JsonParseException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push;
|
||||
|
||||
import com.google.thoughtcrimegson.GsonBuilder;
|
||||
|
||||
import org.whispersystems.textsecure.api.push.SignedPreKeyEntity;
|
||||
|
||||
public class PreKeyResponseItem {
|
||||
|
||||
private int deviceId;
|
||||
private int registrationId;
|
||||
private SignedPreKeyEntity signedPreKey;
|
||||
private PreKeyEntity preKey;
|
||||
|
||||
public int getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public int getRegistrationId() {
|
||||
return registrationId;
|
||||
}
|
||||
|
||||
public SignedPreKeyEntity getSignedPreKey() {
|
||||
return signedPreKey;
|
||||
}
|
||||
|
||||
public PreKeyEntity getPreKey() {
|
||||
return preKey;
|
||||
}
|
||||
|
||||
public static GsonBuilder forBuilder(GsonBuilder builder) {
|
||||
return SignedPreKeyEntity.forBuilder(builder);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package org.whispersystems.textsecure.internal.push;
|
||||
|
||||
import com.google.thoughtcrimegson.GsonBuilder;
|
||||
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.textsecure.api.push.SignedPreKeyEntity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PreKeyState {
|
||||
|
||||
private IdentityKey identityKey;
|
||||
private List<PreKeyEntity> preKeys;
|
||||
private PreKeyEntity lastResortKey;
|
||||
private SignedPreKeyEntity signedPreKey;
|
||||
|
||||
|
||||
public PreKeyState(List<PreKeyEntity> preKeys, PreKeyEntity lastResortKey,
|
||||
SignedPreKeyEntity signedPreKey, IdentityKey identityKey)
|
||||
{
|
||||
this.preKeys = preKeys;
|
||||
this.lastResortKey = lastResortKey;
|
||||
this.signedPreKey = signedPreKey;
|
||||
this.identityKey = identityKey;
|
||||
}
|
||||
|
||||
public static String toJson(PreKeyState state) {
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
return SignedPreKeyEntity.forBuilder(builder)
|
||||
.registerTypeAdapter(IdentityKey.class, new PreKeyResponse.IdentityKeyJsonAdapter())
|
||||
.create().toJson(state);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public class PushAttachmentData {
|
||||
|
||||
private final String contentType;
|
||||
private final InputStream data;
|
||||
private final long dataSize;
|
||||
private final byte[] key;
|
||||
|
||||
public PushAttachmentData(String contentType, InputStream data, long dataSize, byte[] key) {
|
||||
this.contentType = contentType;
|
||||
this.data = data;
|
||||
this.dataSize = dataSize;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public InputStream getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public long getDataSize() {
|
||||
return dataSize;
|
||||
}
|
||||
|
||||
public byte[] getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push;
|
||||
|
||||
public class PushBody {
|
||||
|
||||
private final int type;
|
||||
private final int remoteRegistrationId;
|
||||
private final byte[] body;
|
||||
|
||||
public PushBody(int type, int remoteRegistrationId, byte[] body) {
|
||||
this.type = type;
|
||||
this.remoteRegistrationId = remoteRegistrationId;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public byte[] getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public int getRemoteRegistrationId() {
|
||||
return remoteRegistrationId;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,568 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.thoughtcrimegson.Gson;
|
||||
import com.google.thoughtcrimegson.JsonParseException;
|
||||
|
||||
import org.apache.http.conn.ssl.StrictHostnameVerifier;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.libaxolotl.state.PreKeyBundle;
|
||||
import org.whispersystems.libaxolotl.state.PreKeyRecord;
|
||||
import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
|
||||
import org.whispersystems.textsecure.api.push.PushAddress;
|
||||
import org.whispersystems.textsecure.api.crypto.AttachmentCipherOutputStream;
|
||||
import org.whispersystems.textsecure.api.push.ContactTokenDetails;
|
||||
import org.whispersystems.textsecure.api.push.SignedPreKeyEntity;
|
||||
import org.whispersystems.textsecure.api.push.TrustStore;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.UnregisteredUserException;
|
||||
import org.whispersystems.textsecure.internal.push.exceptions.MismatchedDevicesException;
|
||||
import org.whispersystems.textsecure.internal.push.exceptions.StaleDevicesException;
|
||||
import org.whispersystems.textsecure.internal.util.Base64;
|
||||
import org.whispersystems.textsecure.internal.util.Util;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.AuthorizationFailedException;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.ExpectationFailedException;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.NonSuccessfulResponseCodeException;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.NotFoundException;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.PushNetworkException;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.RateLimitException;
|
||||
import org.whispersystems.textsecure.internal.util.BlacklistingTrustManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* Network interface to the TextSecure server API.
|
||||
*
|
||||
* @author Moxie Marlinspike
|
||||
*/
|
||||
public class PushServiceSocket {
|
||||
|
||||
private static final String CREATE_ACCOUNT_SMS_PATH = "/v1/accounts/sms/code/%s";
|
||||
private static final String CREATE_ACCOUNT_VOICE_PATH = "/v1/accounts/voice/code/%s";
|
||||
private static final String VERIFY_ACCOUNT_PATH = "/v1/accounts/code/%s";
|
||||
private static final String REGISTER_GCM_PATH = "/v1/accounts/gcm/";
|
||||
private static final String PREKEY_METADATA_PATH = "/v2/keys/";
|
||||
private static final String PREKEY_PATH = "/v2/keys/%s";
|
||||
private static final String PREKEY_DEVICE_PATH = "/v2/keys/%s/%s";
|
||||
private static final String SIGNED_PREKEY_PATH = "/v2/keys/signed";
|
||||
|
||||
private static final String DIRECTORY_TOKENS_PATH = "/v1/directory/tokens";
|
||||
private static final String DIRECTORY_VERIFY_PATH = "/v1/directory/%s";
|
||||
private static final String MESSAGE_PATH = "/v1/messages/%s";
|
||||
private static final String RECEIPT_PATH = "/v1/receipt/%s/%d";
|
||||
private static final String ATTACHMENT_PATH = "/v1/attachments/%s";
|
||||
|
||||
private static final boolean ENFORCE_SSL = true;
|
||||
|
||||
private final String serviceUrl;
|
||||
private final String localNumber;
|
||||
private final String password;
|
||||
private final TrustManager[] trustManagers;
|
||||
|
||||
public PushServiceSocket(String serviceUrl, TrustStore trustStore,
|
||||
String localNumber, String password)
|
||||
{
|
||||
this.serviceUrl = serviceUrl;
|
||||
this.localNumber = localNumber;
|
||||
this.password = password;
|
||||
this.trustManagers = initializeTrustManager(trustStore);
|
||||
}
|
||||
|
||||
public void createAccount(boolean voice) throws IOException {
|
||||
String path = voice ? CREATE_ACCOUNT_VOICE_PATH : CREATE_ACCOUNT_SMS_PATH;
|
||||
makeRequest(String.format(path, localNumber), "GET", null);
|
||||
}
|
||||
|
||||
public void verifyAccount(String verificationCode, String signalingKey,
|
||||
boolean supportsSms, int registrationId)
|
||||
throws IOException
|
||||
{
|
||||
AccountAttributes signalingKeyEntity = new AccountAttributes(signalingKey, supportsSms, registrationId);
|
||||
makeRequest(String.format(VERIFY_ACCOUNT_PATH, verificationCode),
|
||||
"PUT", new Gson().toJson(signalingKeyEntity));
|
||||
}
|
||||
|
||||
public void sendReceipt(String destination, long messageId, String relay) throws IOException {
|
||||
String path = String.format(RECEIPT_PATH, destination, messageId);
|
||||
|
||||
if (!Util.isEmpty(relay)) {
|
||||
path += "?relay=" + relay;
|
||||
}
|
||||
|
||||
makeRequest(path, "PUT", null);
|
||||
}
|
||||
|
||||
public void registerGcmId(String gcmRegistrationId) throws IOException {
|
||||
GcmRegistrationId registration = new GcmRegistrationId(gcmRegistrationId);
|
||||
makeRequest(REGISTER_GCM_PATH, "PUT", new Gson().toJson(registration));
|
||||
}
|
||||
|
||||
public void unregisterGcmId() throws IOException {
|
||||
makeRequest(REGISTER_GCM_PATH, "DELETE", null);
|
||||
}
|
||||
|
||||
public void sendMessage(OutgoingPushMessageList bundle)
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
makeRequest(String.format(MESSAGE_PATH, bundle.getDestination()), "PUT", new Gson().toJson(bundle));
|
||||
} catch (NotFoundException nfe) {
|
||||
throw new UnregisteredUserException(bundle.getDestination(), nfe);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerPreKeys(IdentityKey identityKey,
|
||||
PreKeyRecord lastResortKey,
|
||||
SignedPreKeyRecord signedPreKey,
|
||||
List<PreKeyRecord> records)
|
||||
throws IOException
|
||||
{
|
||||
List<PreKeyEntity> entities = new LinkedList<>();
|
||||
|
||||
for (PreKeyRecord record : records) {
|
||||
PreKeyEntity entity = new PreKeyEntity(record.getId(),
|
||||
record.getKeyPair().getPublicKey());
|
||||
|
||||
entities.add(entity);
|
||||
}
|
||||
|
||||
PreKeyEntity lastResortEntity = new PreKeyEntity(lastResortKey.getId(),
|
||||
lastResortKey.getKeyPair().getPublicKey());
|
||||
|
||||
SignedPreKeyEntity signedPreKeyEntity = new SignedPreKeyEntity(signedPreKey.getId(),
|
||||
signedPreKey.getKeyPair().getPublicKey(),
|
||||
signedPreKey.getSignature());
|
||||
|
||||
makeRequest(String.format(PREKEY_PATH, ""), "PUT",
|
||||
PreKeyState.toJson(new PreKeyState(entities, lastResortEntity,
|
||||
signedPreKeyEntity, identityKey)));
|
||||
}
|
||||
|
||||
public int getAvailablePreKeys() throws IOException {
|
||||
String responseText = makeRequest(PREKEY_METADATA_PATH, "GET", null);
|
||||
PreKeyStatus preKeyStatus = new Gson().fromJson(responseText, PreKeyStatus.class);
|
||||
|
||||
return preKeyStatus.getCount();
|
||||
}
|
||||
|
||||
public List<PreKeyBundle> getPreKeys(PushAddress destination) throws IOException {
|
||||
try {
|
||||
String deviceId = String.valueOf(destination.getDeviceId());
|
||||
|
||||
if (deviceId.equals("1"))
|
||||
deviceId = "*";
|
||||
|
||||
String path = String.format(PREKEY_DEVICE_PATH, destination.getNumber(), deviceId);
|
||||
|
||||
if (!Util.isEmpty(destination.getRelay())) {
|
||||
path = path + "?relay=" + destination.getRelay();
|
||||
}
|
||||
|
||||
String responseText = makeRequest(path, "GET", null);
|
||||
PreKeyResponse response = PreKeyResponse.fromJson(responseText);
|
||||
List<PreKeyBundle> bundles = new LinkedList<>();
|
||||
|
||||
for (PreKeyResponseItem device : response.getDevices()) {
|
||||
ECPublicKey preKey = null;
|
||||
ECPublicKey signedPreKey = null;
|
||||
byte[] signedPreKeySignature = null;
|
||||
int preKeyId = -1;
|
||||
int signedPreKeyId = -1;
|
||||
|
||||
if (device.getSignedPreKey() != null) {
|
||||
signedPreKey = device.getSignedPreKey().getPublicKey();
|
||||
signedPreKeyId = device.getSignedPreKey().getKeyId();
|
||||
signedPreKeySignature = device.getSignedPreKey().getSignature();
|
||||
}
|
||||
|
||||
if (device.getPreKey() != null) {
|
||||
preKeyId = device.getPreKey().getKeyId();
|
||||
preKey = device.getPreKey().getPublicKey();
|
||||
}
|
||||
|
||||
bundles.add(new PreKeyBundle(device.getRegistrationId(), device.getDeviceId(), preKeyId,
|
||||
preKey, signedPreKeyId, signedPreKey, signedPreKeySignature,
|
||||
response.getIdentityKey()));
|
||||
}
|
||||
|
||||
return bundles;
|
||||
} catch (JsonParseException e) {
|
||||
throw new IOException(e);
|
||||
} catch (NotFoundException nfe) {
|
||||
throw new UnregisteredUserException(destination.getNumber(), nfe);
|
||||
}
|
||||
}
|
||||
|
||||
public PreKeyBundle getPreKey(PushAddress destination) throws IOException {
|
||||
try {
|
||||
String path = String.format(PREKEY_DEVICE_PATH, destination.getNumber(),
|
||||
String.valueOf(destination.getDeviceId()));
|
||||
|
||||
if (!Util.isEmpty(destination.getRelay())) {
|
||||
path = path + "?relay=" + destination.getRelay();
|
||||
}
|
||||
|
||||
String responseText = makeRequest(path, "GET", null);
|
||||
PreKeyResponse response = PreKeyResponse.fromJson(responseText);
|
||||
|
||||
if (response.getDevices() == null || response.getDevices().size() < 1)
|
||||
throw new IOException("Empty prekey list");
|
||||
|
||||
PreKeyResponseItem device = response.getDevices().get(0);
|
||||
ECPublicKey preKey = null;
|
||||
ECPublicKey signedPreKey = null;
|
||||
byte[] signedPreKeySignature = null;
|
||||
int preKeyId = -1;
|
||||
int signedPreKeyId = -1;
|
||||
|
||||
if (device.getPreKey() != null) {
|
||||
preKeyId = device.getPreKey().getKeyId();
|
||||
preKey = device.getPreKey().getPublicKey();
|
||||
}
|
||||
|
||||
if (device.getSignedPreKey() != null) {
|
||||
signedPreKeyId = device.getSignedPreKey().getKeyId();
|
||||
signedPreKey = device.getSignedPreKey().getPublicKey();
|
||||
signedPreKeySignature = device.getSignedPreKey().getSignature();
|
||||
}
|
||||
|
||||
return new PreKeyBundle(device.getRegistrationId(), device.getDeviceId(), preKeyId, preKey,
|
||||
signedPreKeyId, signedPreKey, signedPreKeySignature, response.getIdentityKey());
|
||||
} catch (JsonParseException e) {
|
||||
throw new IOException(e);
|
||||
} catch (NotFoundException nfe) {
|
||||
throw new UnregisteredUserException(destination.getNumber(), nfe);
|
||||
}
|
||||
}
|
||||
|
||||
public SignedPreKeyEntity getCurrentSignedPreKey() throws IOException {
|
||||
try {
|
||||
String responseText = makeRequest(SIGNED_PREKEY_PATH, "GET", null);
|
||||
return SignedPreKeyEntity.fromJson(responseText);
|
||||
} catch (NotFoundException e) {
|
||||
Log.w("PushServiceSocket", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setCurrentSignedPreKey(SignedPreKeyRecord signedPreKey) throws IOException {
|
||||
SignedPreKeyEntity signedPreKeyEntity = new SignedPreKeyEntity(signedPreKey.getId(),
|
||||
signedPreKey.getKeyPair().getPublicKey(),
|
||||
signedPreKey.getSignature());
|
||||
makeRequest(SIGNED_PREKEY_PATH, "PUT", SignedPreKeyEntity.toJson(signedPreKeyEntity));
|
||||
}
|
||||
|
||||
public long sendAttachment(PushAttachmentData attachment) throws IOException {
|
||||
String response = makeRequest(String.format(ATTACHMENT_PATH, ""), "GET", null);
|
||||
AttachmentDescriptor attachmentKey = new Gson().fromJson(response, AttachmentDescriptor.class);
|
||||
|
||||
if (attachmentKey == null || attachmentKey.getLocation() == null) {
|
||||
throw new IOException("Server failed to allocate an attachment key!");
|
||||
}
|
||||
|
||||
Log.w("PushServiceSocket", "Got attachment content location: " + attachmentKey.getLocation());
|
||||
|
||||
uploadAttachment("PUT", attachmentKey.getLocation(), attachment.getData(),
|
||||
attachment.getDataSize(), attachment.getKey());
|
||||
|
||||
return attachmentKey.getId();
|
||||
}
|
||||
|
||||
public void retrieveAttachment(String relay, long attachmentId, File destination) throws IOException {
|
||||
String path = String.format(ATTACHMENT_PATH, String.valueOf(attachmentId));
|
||||
|
||||
if (!Util.isEmpty(relay)) {
|
||||
path = path + "?relay=" + relay;
|
||||
}
|
||||
|
||||
String response = makeRequest(path, "GET", null);
|
||||
AttachmentDescriptor descriptor = new Gson().fromJson(response, AttachmentDescriptor.class);
|
||||
|
||||
Log.w("PushServiceSocket", "Attachment: " + attachmentId + " is at: " + descriptor.getLocation());
|
||||
|
||||
downloadExternalFile(descriptor.getLocation(), destination);
|
||||
}
|
||||
|
||||
public List<ContactTokenDetails> retrieveDirectory(Set<String> contactTokens)
|
||||
throws NonSuccessfulResponseCodeException, PushNetworkException
|
||||
{
|
||||
ContactTokenList contactTokenList = new ContactTokenList(new LinkedList<>(contactTokens));
|
||||
String response = makeRequest(DIRECTORY_TOKENS_PATH, "PUT", new Gson().toJson(contactTokenList));
|
||||
ContactTokenDetailsList activeTokens = new Gson().fromJson(response, ContactTokenDetailsList.class);
|
||||
|
||||
return activeTokens.getContacts();
|
||||
}
|
||||
|
||||
public ContactTokenDetails getContactTokenDetails(String contactToken) throws IOException {
|
||||
try {
|
||||
String response = makeRequest(String.format(DIRECTORY_VERIFY_PATH, contactToken), "GET", null);
|
||||
return new Gson().fromJson(response, ContactTokenDetails.class);
|
||||
} catch (NotFoundException nfe) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadExternalFile(String url, File localDestination)
|
||||
throws IOException
|
||||
{
|
||||
URL downloadUrl = new URL(url);
|
||||
HttpURLConnection connection = (HttpURLConnection) downloadUrl.openConnection();
|
||||
connection.setRequestProperty("Content-Type", "application/octet-stream");
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setDoInput(true);
|
||||
|
||||
try {
|
||||
if (connection.getResponseCode() != 200) {
|
||||
throw new NonSuccessfulResponseCodeException("Bad response: " + connection.getResponseCode());
|
||||
}
|
||||
|
||||
OutputStream output = new FileOutputStream(localDestination);
|
||||
InputStream input = connection.getInputStream();
|
||||
byte[] buffer = new byte[4096];
|
||||
int read;
|
||||
|
||||
while ((read = input.read(buffer)) != -1) {
|
||||
output.write(buffer, 0, read);
|
||||
}
|
||||
|
||||
output.close();
|
||||
Log.w("PushServiceSocket", "Downloaded: " + url + " to: " + localDestination.getAbsolutePath());
|
||||
} catch (IOException ioe) {
|
||||
throw new PushNetworkException(ioe);
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private void uploadAttachment(String method, String url, InputStream data, long dataSize, byte[] key)
|
||||
throws IOException
|
||||
{
|
||||
URL uploadUrl = new URL(url);
|
||||
HttpsURLConnection connection = (HttpsURLConnection) uploadUrl.openConnection();
|
||||
connection.setDoOutput(true);
|
||||
|
||||
if (dataSize > 0) {
|
||||
connection.setFixedLengthStreamingMode((int) AttachmentCipherOutputStream.getCiphertextLength(dataSize));
|
||||
} else {
|
||||
connection.setChunkedStreamingMode(0);
|
||||
}
|
||||
|
||||
connection.setRequestMethod(method);
|
||||
connection.setRequestProperty("Content-Type", "application/octet-stream");
|
||||
connection.connect();
|
||||
|
||||
try {
|
||||
OutputStream stream = connection.getOutputStream();
|
||||
AttachmentCipherOutputStream out = new AttachmentCipherOutputStream(key, stream);
|
||||
|
||||
Util.copy(data, out);
|
||||
out.flush();
|
||||
|
||||
if (connection.getResponseCode() != 200) {
|
||||
throw new IOException("Bad response: " + connection.getResponseCode() + " " + connection.getResponseMessage());
|
||||
}
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private String makeRequest(String urlFragment, String method, String body)
|
||||
throws NonSuccessfulResponseCodeException, PushNetworkException
|
||||
{
|
||||
HttpURLConnection connection = makeBaseRequest(urlFragment, method, body);
|
||||
|
||||
try {
|
||||
String response = Util.readFully(connection.getInputStream());
|
||||
connection.disconnect();
|
||||
|
||||
return response;
|
||||
} catch (IOException ioe) {
|
||||
throw new PushNetworkException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
private HttpURLConnection makeBaseRequest(String urlFragment, String method, String body)
|
||||
throws NonSuccessfulResponseCodeException, PushNetworkException
|
||||
{
|
||||
HttpURLConnection connection = getConnection(urlFragment, method, body);
|
||||
int responseCode;
|
||||
String responseMessage;
|
||||
String response;
|
||||
|
||||
try {
|
||||
responseCode = connection.getResponseCode();
|
||||
responseMessage = connection.getResponseMessage();
|
||||
} catch (IOException ioe) {
|
||||
throw new PushNetworkException(ioe);
|
||||
}
|
||||
|
||||
switch (responseCode) {
|
||||
case 413:
|
||||
connection.disconnect();
|
||||
throw new RateLimitException("Rate limit exceeded: " + responseCode);
|
||||
case 401:
|
||||
case 403:
|
||||
connection.disconnect();
|
||||
throw new AuthorizationFailedException("Authorization failed!");
|
||||
case 404:
|
||||
connection.disconnect();
|
||||
throw new NotFoundException("Not found");
|
||||
case 409:
|
||||
try {
|
||||
response = Util.readFully(connection.getErrorStream());
|
||||
} catch (IOException e) {
|
||||
throw new PushNetworkException(e);
|
||||
}
|
||||
throw new MismatchedDevicesException(new Gson().fromJson(response, MismatchedDevices.class));
|
||||
case 410:
|
||||
try {
|
||||
response = Util.readFully(connection.getErrorStream());
|
||||
} catch (IOException e) {
|
||||
throw new PushNetworkException(e);
|
||||
}
|
||||
throw new StaleDevicesException(new Gson().fromJson(response, StaleDevices.class));
|
||||
case 417:
|
||||
throw new ExpectationFailedException();
|
||||
}
|
||||
|
||||
if (responseCode != 200 && responseCode != 204) {
|
||||
throw new NonSuccessfulResponseCodeException("Bad response: " + responseCode + " " +
|
||||
responseMessage);
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
private HttpURLConnection getConnection(String urlFragment, String method, String body)
|
||||
throws PushNetworkException
|
||||
{
|
||||
try {
|
||||
SSLContext context = SSLContext.getInstance("TLS");
|
||||
context.init(null, trustManagers, null);
|
||||
|
||||
URL url = new URL(String.format("%s%s", serviceUrl, urlFragment));
|
||||
Log.w("PushServiceSocket", "Push service URL: " + serviceUrl);
|
||||
Log.w("PushServiceSocket", "Opening URL: " + url);
|
||||
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
if (ENFORCE_SSL) {
|
||||
((HttpsURLConnection) connection).setSSLSocketFactory(context.getSocketFactory());
|
||||
((HttpsURLConnection) connection).setHostnameVerifier(new StrictHostnameVerifier());
|
||||
}
|
||||
|
||||
connection.setRequestMethod(method);
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
|
||||
if (password != null) {
|
||||
connection.setRequestProperty("Authorization", getAuthorizationHeader());
|
||||
}
|
||||
|
||||
if (body != null) {
|
||||
connection.setDoOutput(true);
|
||||
}
|
||||
|
||||
connection.connect();
|
||||
|
||||
if (body != null) {
|
||||
Log.w("PushServiceSocket", method + " -- " + body);
|
||||
OutputStream out = connection.getOutputStream();
|
||||
out.write(body.getBytes());
|
||||
out.close();
|
||||
}
|
||||
|
||||
return connection;
|
||||
} catch (IOException e) {
|
||||
throw new PushNetworkException(e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (KeyManagementException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getAuthorizationHeader() {
|
||||
try {
|
||||
return "Basic " + Base64.encodeBytes((localNumber + ":" + password).getBytes("UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private TrustManager[] initializeTrustManager(TrustStore trustStore) {
|
||||
try {
|
||||
InputStream keyStoreInputStream = trustStore.getKeyStoreInputStream();
|
||||
KeyStore keyStore = KeyStore.getInstance("BKS");
|
||||
|
||||
keyStore.load(keyStoreInputStream, trustStore.getKeyStorePassword().toCharArray());
|
||||
|
||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
|
||||
trustManagerFactory.init(keyStore);
|
||||
|
||||
return BlacklistingTrustManager.createFor(trustManagerFactory.getTrustManagers());
|
||||
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException kse) {
|
||||
throw new AssertionError(kse);
|
||||
}
|
||||
}
|
||||
|
||||
private static class GcmRegistrationId {
|
||||
private String gcmRegistrationId;
|
||||
|
||||
public GcmRegistrationId() {}
|
||||
|
||||
public GcmRegistrationId(String gcmRegistrationId) {
|
||||
this.gcmRegistrationId = gcmRegistrationId;
|
||||
}
|
||||
}
|
||||
|
||||
private static class AttachmentDescriptor {
|
||||
private long id;
|
||||
private String location;
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2013 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class PushTransportDetails {
|
||||
|
||||
private final int messageVersion;
|
||||
|
||||
public PushTransportDetails(int messageVersion) {
|
||||
this.messageVersion = messageVersion;
|
||||
}
|
||||
|
||||
public byte[] getStrippedPaddingMessageBody(byte[] messageWithPadding) {
|
||||
if (messageVersion < 2) throw new AssertionError("Unknown version: " + messageVersion);
|
||||
else if (messageVersion == 2) return messageWithPadding;
|
||||
|
||||
int paddingStart = 0;
|
||||
|
||||
for (int i=messageWithPadding.length-1;i>=0;i--) {
|
||||
if (messageWithPadding[i] == (byte)0x80) {
|
||||
paddingStart = i;
|
||||
break;
|
||||
} else if (messageWithPadding[i] != (byte)0x00) {
|
||||
Log.w("PushTransportDetails", "Padding byte is malformed, returning unstripped padding.");
|
||||
return messageWithPadding;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] strippedMessage = new byte[paddingStart];
|
||||
System.arraycopy(messageWithPadding, 0, strippedMessage, 0, strippedMessage.length);
|
||||
|
||||
return strippedMessage;
|
||||
}
|
||||
|
||||
public byte[] getPaddedMessageBody(byte[] messageBody) {
|
||||
if (messageVersion < 2) throw new AssertionError("Unknown version: " + messageVersion);
|
||||
else if (messageVersion == 2) return messageBody;
|
||||
|
||||
// NOTE: This is dumb. We have our own padding scheme, but so does the cipher.
|
||||
// The +1 -1 here is to make sure the Cipher has room to add one padding byte,
|
||||
// otherwise it'll add a full 16 extra bytes.
|
||||
byte[] paddedMessage = new byte[getPaddedMessageLength(messageBody.length + 1) - 1];
|
||||
System.arraycopy(messageBody, 0, paddedMessage, 0, messageBody.length);
|
||||
paddedMessage[messageBody.length] = (byte)0x80;
|
||||
|
||||
return paddedMessage;
|
||||
}
|
||||
|
||||
private int getPaddedMessageLength(int messageLength) {
|
||||
int messageLengthWithTerminator = messageLength + 1;
|
||||
int messagePartCount = messageLengthWithTerminator / 160;
|
||||
|
||||
if (messageLengthWithTerminator % 160 != 0) {
|
||||
messagePartCount++;
|
||||
}
|
||||
|
||||
return messagePartCount * 160;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class StaleDevices {
|
||||
|
||||
private List<Integer> staleDevices;
|
||||
|
||||
public List<Integer> getStaleDevices() {
|
||||
return staleDevices;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push.exceptions;
|
||||
|
||||
import org.whispersystems.textsecure.api.push.exceptions.NonSuccessfulResponseCodeException;
|
||||
import org.whispersystems.textsecure.internal.push.MismatchedDevices;
|
||||
|
||||
public class MismatchedDevicesException extends NonSuccessfulResponseCodeException {
|
||||
|
||||
private final MismatchedDevices mismatchedDevices;
|
||||
|
||||
public MismatchedDevicesException(MismatchedDevices mismatchedDevices) {
|
||||
this.mismatchedDevices = mismatchedDevices;
|
||||
}
|
||||
|
||||
public MismatchedDevices getMismatchedDevices() {
|
||||
return mismatchedDevices;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push.exceptions;
|
||||
|
||||
import org.whispersystems.textsecure.api.push.exceptions.NonSuccessfulResponseCodeException;
|
||||
import org.whispersystems.textsecure.internal.push.StaleDevices;
|
||||
|
||||
public class StaleDevicesException extends NonSuccessfulResponseCodeException {
|
||||
|
||||
private final StaleDevices staleDevices;
|
||||
|
||||
public StaleDevicesException(StaleDevices staleDevices) {
|
||||
this.staleDevices = staleDevices;
|
||||
}
|
||||
|
||||
public StaleDevices getStaleDevices() {
|
||||
return staleDevices;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.util;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
/**
|
||||
* Trust manager that defers to a system X509 trust manager, and
|
||||
* additionally rejects certificates if they have a blacklisted
|
||||
* serial.
|
||||
*
|
||||
* @author Moxie Marlinspike
|
||||
*/
|
||||
public class BlacklistingTrustManager implements X509TrustManager {
|
||||
|
||||
private static final List<BigInteger> BLACKLIST = new LinkedList<BigInteger>() {{
|
||||
add(new BigInteger("4098"));
|
||||
}};
|
||||
|
||||
public static TrustManager[] createFor(TrustManager[] trustManagers) {
|
||||
for (TrustManager trustManager : trustManagers) {
|
||||
if (trustManager instanceof X509TrustManager) {
|
||||
TrustManager[] results = new BlacklistingTrustManager[1];
|
||||
results[0] = new BlacklistingTrustManager((X509TrustManager)trustManager);
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
throw new AssertionError("No X509 Trust Managers!");
|
||||
}
|
||||
|
||||
private final X509TrustManager trustManager;
|
||||
|
||||
public BlacklistingTrustManager(X509TrustManager trustManager) {
|
||||
this.trustManager = trustManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType)
|
||||
throws CertificateException
|
||||
{
|
||||
trustManager.checkClientTrusted(chain, authType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType)
|
||||
throws CertificateException
|
||||
{
|
||||
trustManager.checkServerTrusted(chain, authType);
|
||||
|
||||
for (X509Certificate certificate : chain) {
|
||||
for (BigInteger blacklistedSerial : BLACKLIST) {
|
||||
if (certificate.getSerialNumber().equals(blacklistedSerial)) {
|
||||
throw new CertificateException("Blacklisted Serial: " + certificate.getSerialNumber());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return trustManager.getAcceptedIssuers();
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2011 Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Utility for generating hex dumps.
|
||||
*/
|
||||
public class Hex {
|
||||
|
||||
private final static int HEX_DIGITS_START = 10;
|
||||
private final static int ASCII_TEXT_START = HEX_DIGITS_START + (16*2 + (16/2));
|
||||
|
||||
final static String EOL = System.getProperty("line.separator");
|
||||
|
||||
private final static char[] HEX_DIGITS = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||
};
|
||||
|
||||
public static String toString(byte[] bytes) {
|
||||
return toString(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
public static String toString(byte[] bytes, int offset, int length) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i = 0; i < length; i++) {
|
||||
appendHexChar(buf, bytes[offset + i]);
|
||||
buf.append(' ');
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static String toStringCondensed(byte[] bytes) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i=0;i<bytes.length;i++) {
|
||||
appendHexChar(buf, bytes[i]);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static byte[] fromStringCondensed(String encoded) throws IOException {
|
||||
final char[] data = encoded.toCharArray();
|
||||
final int len = data.length;
|
||||
|
||||
if ((len & 0x01) != 0) {
|
||||
throw new IOException("Odd number of characters.");
|
||||
}
|
||||
|
||||
final byte[] out = new byte[len >> 1];
|
||||
|
||||
// two characters form the hex value.
|
||||
for (int i = 0, j = 0; j < len; i++) {
|
||||
int f = Character.digit(data[j], 16) << 4;
|
||||
j++;
|
||||
f = f | Character.digit(data[j], 16);
|
||||
j++;
|
||||
out[i] = (byte) (f & 0xFF);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
public static String dump(byte[] bytes) {
|
||||
return dump(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
public static String dump(byte[] bytes, int offset, int length) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
int lines = ((length - 1) / 16) + 1;
|
||||
int lineOffset;
|
||||
int lineLength;
|
||||
|
||||
for (int i = 0; i < lines; i++) {
|
||||
lineOffset = (i * 16) + offset;
|
||||
lineLength = Math.min(16, (length - (i * 16)));
|
||||
appendDumpLine(buf, i, bytes, lineOffset, lineLength);
|
||||
buf.append(EOL);
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static void appendDumpLine(StringBuffer buf, int line, byte[] bytes, int lineOffset, int lineLength) {
|
||||
buf.append(HEX_DIGITS[(line >> 28) & 0xf]);
|
||||
buf.append(HEX_DIGITS[(line >> 24) & 0xf]);
|
||||
buf.append(HEX_DIGITS[(line >> 20) & 0xf]);
|
||||
buf.append(HEX_DIGITS[(line >> 16) & 0xf]);
|
||||
buf.append(HEX_DIGITS[(line >> 12) & 0xf]);
|
||||
buf.append(HEX_DIGITS[(line >> 8) & 0xf]);
|
||||
buf.append(HEX_DIGITS[(line >> 4) & 0xf]);
|
||||
buf.append(HEX_DIGITS[(line ) & 0xf]);
|
||||
buf.append(": ");
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
int idx = i + lineOffset;
|
||||
if (i < lineLength) {
|
||||
int b = bytes[idx];
|
||||
appendHexChar(buf, b);
|
||||
} else {
|
||||
buf.append(" ");
|
||||
}
|
||||
if ((i % 2) == 1) {
|
||||
buf.append(' ');
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16 && i < lineLength; i++) {
|
||||
int idx = i + lineOffset;
|
||||
int b = bytes[idx];
|
||||
if (b >= 0x20 && b <= 0x7e) {
|
||||
buf.append((char)b);
|
||||
} else {
|
||||
buf.append('.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void appendHexChar(StringBuffer buf, int b) {
|
||||
buf.append(HEX_DIGITS[(b >> 4) & 0xf]);
|
||||
buf.append(HEX_DIGITS[b & 0xf]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.util;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class Util {
|
||||
|
||||
public static byte[][] split(byte[] input, int firstLength, int secondLength) {
|
||||
byte[][] parts = new byte[2][];
|
||||
|
||||
parts[0] = new byte[firstLength];
|
||||
System.arraycopy(input, 0, parts[0], 0, firstLength);
|
||||
|
||||
parts[1] = new byte[secondLength];
|
||||
System.arraycopy(input, firstLength, parts[1], 0, secondLength);
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
public static boolean isEmpty(String value) {
|
||||
return value == null || value.trim().length() == 0;
|
||||
}
|
||||
|
||||
public static byte[] getSecretBytes(int size) {
|
||||
try {
|
||||
byte[] secret = new byte[size];
|
||||
SecureRandom.getInstance("SHA1PRNG").nextBytes(secret);
|
||||
return secret;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String readFully(InputStream in) throws IOException {
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[4096];
|
||||
int read;
|
||||
|
||||
while ((read = in.read(buffer)) != -1) {
|
||||
bout.write(buffer, 0, read);
|
||||
}
|
||||
|
||||
in.close();
|
||||
|
||||
return new String(bout.toByteArray());
|
||||
}
|
||||
|
||||
public static void readFully(InputStream in, byte[] buffer) throws IOException {
|
||||
int offset = 0;
|
||||
|
||||
for (;;) {
|
||||
int read = in.read(buffer, offset, buffer.length - offset);
|
||||
|
||||
if (read + offset < buffer.length) offset += read;
|
||||
else return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void copy(InputStream in, OutputStream out) throws IOException {
|
||||
byte[] buffer = new byte[4096];
|
||||
int read;
|
||||
|
||||
while ((read = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, read);
|
||||
}
|
||||
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
|
||||
}
|
||||
9
proguard-appcompat-v7.pro
Normal file
9
proguard-appcompat-v7.pro
Normal file
@@ -0,0 +1,9 @@
|
||||
# https://code.google.com/p/android/issues/detail?id=78377
|
||||
-keepnames class !android.support.v7.internal.view.menu.**, ** { *; }
|
||||
|
||||
-keep public class android.support.v7.widget.** { *; }
|
||||
-keep public class android.support.v7.internal.widget.** { *; }
|
||||
|
||||
-keep public class * extends android.support.v4.view.ActionProvider {
|
||||
public <init>(android.content.Context);
|
||||
}
|
||||
20
proguard-dagger.pro
Normal file
20
proguard-dagger.pro
Normal file
@@ -0,0 +1,20 @@
|
||||
-keepattributes *Annotation*,EnclosingMethod
|
||||
-keep @interface dagger.*,javax.inject.*
|
||||
-keep @dagger.Module class *
|
||||
-keepclassmembers class * {
|
||||
@javax.inject.* *;
|
||||
@dagger.* *;
|
||||
<init>();
|
||||
}
|
||||
-keepclasseswithmembernames class * {
|
||||
@javax.inject.* <fields>;
|
||||
}
|
||||
-keep class javax.inject.** { *; }
|
||||
-keep class **$$ModuleAdapter
|
||||
-keep class **$$InjectAdapter
|
||||
-keep class **$$StaticInjection
|
||||
|
||||
-keep class dagger.** { *; }
|
||||
-keep class * extends dagger.** { *; }
|
||||
-keep interface dagger.** {*;}
|
||||
-dontwarn dagger.internal.codegen.**
|
||||
4
proguard-glide.pro
Normal file
4
proguard-glide.pro
Normal file
@@ -0,0 +1,4 @@
|
||||
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
|
||||
**[] $VALUES;
|
||||
public *;
|
||||
}
|
||||
19
proguard-google-play-services.pro
Normal file
19
proguard-google-play-services.pro
Normal file
@@ -0,0 +1,19 @@
|
||||
## Google Play Services 4.3.23 specific rules ##
|
||||
## https://developer.android.com/google/play-services/setup.html#Proguard ##
|
||||
|
||||
-keep class * extends java.util.ListResourceBundle {
|
||||
protected Object[][] getContents();
|
||||
}
|
||||
|
||||
-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
|
||||
public static final *** NULL;
|
||||
}
|
||||
|
||||
-keepnames @com.google.android.gms.common.annotation.KeepName class *
|
||||
-keepclassmembernames class * {
|
||||
@com.google.android.gms.common.annotation.KeepName *;
|
||||
}
|
||||
|
||||
-keepnames class * implements android.os.Parcelable {
|
||||
public static final ** CREATOR;
|
||||
}
|
||||
12
proguard-jackson.pro
Normal file
12
proguard-jackson.pro
Normal file
@@ -0,0 +1,12 @@
|
||||
# Proguard configuration for Jackson 2.x (fasterxml package instead of codehaus package)
|
||||
|
||||
-keepattributes *Annotation*,EnclosingMethod,Signature
|
||||
-keepnames class com.fasterxml.jackson.** {
|
||||
*;
|
||||
}
|
||||
-keepnames interface com.fasterxml.jackson.** {
|
||||
*;
|
||||
}
|
||||
-dontwarn com.fasterxml.jackson.databind.**
|
||||
-keep class org.codehaus.** { *; }
|
||||
|
||||
1
proguard-rounded-image-view.pro
Normal file
1
proguard-rounded-image-view.pro
Normal file
@@ -0,0 +1 @@
|
||||
-dontwarn com.squareup.picasso.**
|
||||
1
proguard-shortcutbadger.pro
Normal file
1
proguard-shortcutbadger.pro
Normal file
@@ -0,0 +1 @@
|
||||
-keep class me.leolin.shortcutbadger.** {*;}
|
||||
2
proguard-spongycastle.pro
Normal file
2
proguard-spongycastle.pro
Normal file
@@ -0,0 +1,2 @@
|
||||
-keep class org.spongycastle.** {*;}
|
||||
-dontwarn javax.naming.**
|
||||
2
proguard-sqlite.pro
Normal file
2
proguard-sqlite.pro
Normal file
@@ -0,0 +1,2 @@
|
||||
-keep class org.sqlite.** { *; }
|
||||
-keep class org.sqlite.database.** { *; }
|
||||
6
proguard-square-okhttp.pro
Normal file
6
proguard-square-okhttp.pro
Normal file
@@ -0,0 +1,6 @@
|
||||
# OkHttp
|
||||
-keepattributes Signature
|
||||
-keepattributes *Annotation*
|
||||
-keep class com.squareup.okhttp.** { *; }
|
||||
-keep interface com.squareup.okhttp.** { *; }
|
||||
-dontwarn com.squareup.okhttp.**
|
||||
5
proguard-square-okio.pro
Normal file
5
proguard-square-okio.pro
Normal file
@@ -0,0 +1,5 @@
|
||||
# Okio
|
||||
-keep class sun.misc.Unsafe { *; }
|
||||
-dontwarn java.nio.file.*
|
||||
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
|
||||
-dontwarn okio.**
|
||||
10
proguard-testing.pro
Normal file
10
proguard-testing.pro
Normal file
@@ -0,0 +1,10 @@
|
||||
-keepattributes Exceptions
|
||||
-dontskipnonpubliclibraryclassmembers
|
||||
|
||||
-dontwarn android.test.**
|
||||
-dontwarn com.android.support.test.**
|
||||
-dontwarn sun.reflect.**
|
||||
-dontwarn org.assertj.**
|
||||
-dontwarn org.hamcrest.**
|
||||
-dontwarn org.mockito.**
|
||||
-dontwarn com.squareup.**
|
||||
5
proguard.cfg
Normal file
5
proguard.cfg
Normal file
@@ -0,0 +1,5 @@
|
||||
-dontoptimize
|
||||
-keepattributes SourceFile,LineNumberTable
|
||||
-keep class org.whispersystems.** { *; }
|
||||
-keep class org.thoughtcrime.securesms.** { *; }
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:state_enabled="false" android:color="@color/gray27"/>
|
||||
<item android:color="@color/gray95"/>
|
||||
</selector>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user