That fuck shit the fascists are using
at master 265 lines 11 kB view raw
1package org.tm.archive; 2 3import android.Manifest; 4import android.annotation.SuppressLint; 5import android.content.Context; 6import android.content.Intent; 7import android.net.Uri; 8import android.os.AsyncTask; 9import android.os.Bundle; 10import android.os.Vibrator; 11import android.text.TextUtils; 12import android.transition.TransitionInflater; 13import android.view.Menu; 14import android.view.MenuItem; 15import android.view.View; 16import android.widget.Button; 17import android.widget.Toast; 18 19import androidx.annotation.NonNull; 20import androidx.appcompat.widget.Toolbar; 21 22import org.signal.core.util.ThreadUtil; 23import org.signal.core.util.logging.Log; 24import org.signal.libsignal.protocol.IdentityKeyPair; 25import org.signal.libsignal.protocol.InvalidKeyException; 26import org.signal.libsignal.protocol.ecc.Curve; 27import org.signal.libsignal.protocol.ecc.ECPublicKey; 28import org.signal.libsignal.zkgroup.profiles.ProfileKey; 29import org.signal.qr.kitkat.ScanListener; 30import org.tm.archive.crypto.ProfileKeyUtil; 31import org.tm.archive.dependencies.ApplicationDependencies; 32import org.tm.archive.jobs.LinkedDeviceInactiveCheckJob; 33import org.tm.archive.keyvalue.SignalStore; 34import org.tm.archive.permissions.Permissions; 35import org.signal.core.util.Base64; 36import org.tm.archive.util.DynamicLanguage; 37import org.tm.archive.util.DynamicNoActionBarTheme; 38import org.tm.archive.util.DynamicTheme; 39import org.tm.archive.util.TextSecurePreferences; 40import org.tm.archive.util.task.ProgressDialogAsyncTask; 41import org.whispersystems.signalservice.api.SignalServiceAccountManager; 42import org.whispersystems.signalservice.api.push.exceptions.NotFoundException; 43import org.whispersystems.signalservice.internal.push.DeviceLimitExceededException; 44 45import java.io.IOException; 46 47public class DeviceActivity extends PassphraseRequiredActivity 48 implements Button.OnClickListener, ScanListener, DeviceLinkFragment.LinkClickedListener 49{ 50 51 private static final String TAG = Log.tag(DeviceActivity.class); 52 53 private static final String EXTRA_DIRECT_TO_SCANNER = "add"; 54 55 private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme(); 56 private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); 57 58 private DeviceAddFragment deviceAddFragment; 59 private DeviceListFragment deviceListFragment; 60 private DeviceLinkFragment deviceLinkFragment; 61 private MenuItem cameraSwitchItem = null; 62 63 64 public static Intent getIntentForScanner(Context context) { 65 Intent intent = new Intent(context, DeviceActivity.class); 66 intent.putExtra(EXTRA_DIRECT_TO_SCANNER, true); 67 return intent; 68 } 69 70 @Override 71 public void onPreCreate() { 72 dynamicTheme.onCreate(this); 73 dynamicLanguage.onCreate(this); 74 } 75 76 @Override 77 public void onCreate(Bundle bundle, boolean ready) { 78 setContentView(R.layout.device_activity); 79 80 Toolbar toolbar = findViewById(R.id.toolbar); 81 82 setSupportActionBar(toolbar); 83 requireSupportActionBar().setDisplayHomeAsUpEnabled(true); 84 requireSupportActionBar().setTitle(R.string.AndroidManifest__linked_devices); 85 86 this.deviceAddFragment = new DeviceAddFragment(); 87 this.deviceListFragment = new DeviceListFragment(); 88 this.deviceLinkFragment = new DeviceLinkFragment(); 89 90 this.deviceListFragment.setAddDeviceButtonListener(this); 91 this.deviceAddFragment.setScanListener(this); 92 93 if (getIntent().getBooleanExtra(EXTRA_DIRECT_TO_SCANNER, false)) { 94 initFragment(R.id.fragment_container, deviceAddFragment, dynamicLanguage.getCurrentLocale()); 95 } else { 96 initFragment(R.id.fragment_container, deviceListFragment, dynamicLanguage.getCurrentLocale()); 97 } 98 } 99 100 @Override 101 public void onResume() { 102 super.onResume(); 103 dynamicTheme.onResume(this); 104 dynamicLanguage.onResume(this); 105 } 106 107 @Override 108 public boolean onOptionsItemSelected(MenuItem item) { 109 if (item.getItemId() == android.R.id.home) { 110 finish(); 111 return true; 112 } 113 114 return false; 115 } 116 117 @Override 118 public boolean onCreateOptionsMenu(Menu menu) { 119 getMenuInflater().inflate(R.menu.device_add, menu); 120 cameraSwitchItem = menu.findItem(R.id.device_add_camera_switch); 121 cameraSwitchItem.setVisible(false); 122 return super.onCreateOptionsMenu(menu); 123 } 124 125 public MenuItem getCameraSwitchItem() { 126 return cameraSwitchItem; 127 } 128 129 @Override 130 public void onClick(View v) { 131 Permissions.with(this) 132 .request(Manifest.permission.CAMERA) 133 .ifNecessary() 134 .withPermanentDenialDialog(getString(R.string.DeviceActivity_signal_needs_the_camera_permission_in_order_to_scan_a_qr_code)) 135 .onAllGranted(() -> { 136 getSupportFragmentManager().beginTransaction() 137 .replace(R.id.fragment_container, deviceAddFragment) 138 .addToBackStack(null) 139 .commitAllowingStateLoss(); 140 }) 141 .onAnyDenied(() -> Toast.makeText(this, R.string.DeviceActivity_unable_to_scan_a_qr_code_without_the_camera_permission, Toast.LENGTH_LONG).show()) 142 .execute(); 143 } 144 145 @Override 146 public void onQrDataFound(@NonNull final String data) { 147 ThreadUtil.runOnMain(() -> { 148 ((Vibrator)getSystemService(Context.VIBRATOR_SERVICE)).vibrate(50); 149 Uri uri = Uri.parse(data); 150 deviceLinkFragment.setLinkClickedListener(uri, DeviceActivity.this); 151 152 deviceAddFragment.setSharedElementReturnTransition(TransitionInflater.from(DeviceActivity.this).inflateTransition(R.transition.fragment_shared)); 153 deviceAddFragment.setExitTransition(TransitionInflater.from(DeviceActivity.this).inflateTransition(android.R.transition.fade)); 154 155 deviceLinkFragment.setSharedElementEnterTransition(TransitionInflater.from(DeviceActivity.this).inflateTransition(R.transition.fragment_shared)); 156 deviceLinkFragment.setEnterTransition(TransitionInflater.from(DeviceActivity.this).inflateTransition(android.R.transition.fade)); 157 158 getSupportFragmentManager().beginTransaction() 159 .addToBackStack(null) 160 .addSharedElement(deviceAddFragment.getDevicesImage(), "devices") 161 .replace(R.id.fragment_container, deviceLinkFragment) 162 .commit(); 163 164 }); 165 } 166 167 @SuppressLint("MissingSuperCall") 168 @Override 169 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 170 Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults); 171 } 172 173 @SuppressLint("StaticFieldLeak") 174 @Override 175 public void onLink(final Uri uri) { 176 new ProgressDialogAsyncTask<Void, Void, Integer>(this, 177 R.string.DeviceProvisioningActivity_content_progress_title, 178 R.string.DeviceProvisioningActivity_content_progress_content) 179 { 180 private static final int SUCCESS = 0; 181 private static final int NO_DEVICE = 1; 182 private static final int NETWORK_ERROR = 2; 183 private static final int KEY_ERROR = 3; 184 private static final int LIMIT_EXCEEDED = 4; 185 private static final int BAD_CODE = 5; 186 187 @Override 188 protected Integer doInBackground(Void... params) { 189 boolean isMultiDevice = TextSecurePreferences.isMultiDevice(DeviceActivity.this); 190 191 try { 192 Context context = DeviceActivity.this; 193 SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager(); 194 String verificationCode = accountManager.getNewDeviceVerificationCode(); 195 String ephemeralId = uri.getQueryParameter("uuid"); 196 String publicKeyEncoded = uri.getQueryParameter("pub_key"); 197 198 if (TextUtils.isEmpty(ephemeralId) || TextUtils.isEmpty(publicKeyEncoded)) { 199 Log.w(TAG, "UUID or Key is empty!"); 200 return BAD_CODE; 201 } 202 203 ECPublicKey publicKey = Curve.decodePoint(Base64.decode(publicKeyEncoded), 0); 204 IdentityKeyPair aciIdentityKeyPair = SignalStore.account().getAciIdentityKey(); 205 IdentityKeyPair pniIdentityKeyPair = SignalStore.account().getPniIdentityKey(); 206 ProfileKey profileKey = ProfileKeyUtil.getSelfProfileKey(); 207 208 TextSecurePreferences.setMultiDevice(DeviceActivity.this, true); 209 accountManager.addDevice(ephemeralId, publicKey, aciIdentityKeyPair, pniIdentityKeyPair, profileKey, SignalStore.svr().getOrCreateMasterKey(), verificationCode); 210 211 return SUCCESS; 212 } catch (NotFoundException e) { 213 Log.w(TAG, e); 214 TextSecurePreferences.setMultiDevice(DeviceActivity.this, isMultiDevice); 215 return NO_DEVICE; 216 } catch (DeviceLimitExceededException e) { 217 Log.w(TAG, e); 218 TextSecurePreferences.setMultiDevice(DeviceActivity.this, isMultiDevice); 219 return LIMIT_EXCEEDED; 220 } catch (IOException e) { 221 Log.w(TAG, e); 222 TextSecurePreferences.setMultiDevice(DeviceActivity.this, isMultiDevice); 223 return NETWORK_ERROR; 224 } catch (InvalidKeyException e) { 225 Log.w(TAG, e); 226 TextSecurePreferences.setMultiDevice(DeviceActivity.this, isMultiDevice); 227 return KEY_ERROR; 228 } 229 } 230 231 @Override 232 protected void onPostExecute(Integer result) { 233 super.onPostExecute(result); 234 235 LinkedDeviceInactiveCheckJob.enqueue(); 236 237 Context context = DeviceActivity.this; 238 239 switch (result) { 240 case SUCCESS: 241 Toast.makeText(context, R.string.DeviceProvisioningActivity_content_progress_success, Toast.LENGTH_SHORT).show(); 242 finish(); 243 return; 244 case NO_DEVICE: 245 Toast.makeText(context, R.string.DeviceProvisioningActivity_content_progress_no_device, Toast.LENGTH_LONG).show(); 246 break; 247 case NETWORK_ERROR: 248 Toast.makeText(context, R.string.DeviceProvisioningActivity_content_progress_network_error, Toast.LENGTH_LONG).show(); 249 break; 250 case KEY_ERROR: 251 Toast.makeText(context, R.string.DeviceProvisioningActivity_content_progress_key_error, Toast.LENGTH_LONG).show(); 252 break; 253 case LIMIT_EXCEEDED: 254 Toast.makeText(context, R.string.DeviceProvisioningActivity_sorry_you_have_too_many_devices_linked_already, Toast.LENGTH_LONG).show(); 255 break; 256 case BAD_CODE: 257 Toast.makeText(context, R.string.DeviceActivity_sorry_this_is_not_a_valid_device_link_qr_code, Toast.LENGTH_LONG).show(); 258 break; 259 } 260 261 getSupportFragmentManager().popBackStackImmediate(); 262 } 263 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 264 } 265}