That fuck shit the fascists are using
at master 211 lines 7.7 kB view raw
1package org.tm.archive.lock; 2 3import android.content.Context; 4import android.content.Intent; 5import android.text.Editable; 6import android.text.InputType; 7import android.text.SpannableString; 8import android.text.SpannableStringBuilder; 9import android.text.Spanned; 10import android.text.TextUtils; 11import android.text.method.LinkMovementMethod; 12import android.text.style.ClickableSpan; 13import android.util.DisplayMetrics; 14import android.view.Display; 15import android.view.View; 16import android.view.ViewGroup; 17import android.view.WindowManager; 18import android.widget.EditText; 19import android.widget.TextView; 20 21import androidx.annotation.NonNull; 22import androidx.annotation.Nullable; 23import androidx.appcompat.app.AlertDialog; 24import androidx.autofill.HintConstants; 25import androidx.core.app.DialogCompat; 26import androidx.core.view.ViewCompat; 27 28import com.google.android.material.dialog.MaterialAlertDialogBuilder; 29 30import org.signal.core.util.logging.Log; 31import org.tm.archive.R; 32import org.tm.archive.contactshare.SimpleTextWatcher; 33import org.tm.archive.keyvalue.SignalStore; 34import org.tm.archive.lock.v2.CreateSvrPinActivity; 35import org.tm.archive.lock.v2.SvrConstants; 36import org.tm.archive.util.ServiceUtil; 37import org.tm.archive.util.ViewUtil; 38import org.whispersystems.signalservice.api.kbs.PinHashUtil; 39 40import java.util.Objects; 41 42public final class SignalPinReminderDialog { 43 44 private static final String TAG = Log.tag(SignalPinReminderDialog.class); 45 46 public static void show(@NonNull Context context, @NonNull Launcher launcher, @NonNull Callback mainCallback) { 47 if (!SignalStore.svr().hasPin()) { 48 throw new AssertionError("Must have a PIN!"); 49 } 50 51 Log.i(TAG, "Showing PIN reminder dialog."); 52 53 AlertDialog dialog = new MaterialAlertDialogBuilder(context, R.style.ThemeOverlay_Signal_MaterialAlertDialog_Wide) 54 .setView(R.layout.kbs_pin_reminder_view) 55 .setCancelable(false) 56 .setOnCancelListener(d -> RegistrationLockReminders.scheduleReminder(context, false)) 57 .create(); 58 59 WindowManager windowManager = ServiceUtil.getWindowManager(context); 60 Display display = windowManager.getDefaultDisplay(); 61 DisplayMetrics metrics = new DisplayMetrics(); 62 display.getMetrics(metrics); 63 64 dialog.show(); 65 dialog.getWindow().setLayout((int)(metrics.widthPixels * .80), ViewGroup.LayoutParams.WRAP_CONTENT); 66 67 EditText pinEditText = (EditText) DialogCompat.requireViewById(dialog, R.id.pin); 68 TextView pinStatus = (TextView) DialogCompat.requireViewById(dialog, R.id.pin_status); 69 TextView reminder = (TextView) DialogCompat.requireViewById(dialog, R.id.reminder); 70 View skip = DialogCompat.requireViewById(dialog, R.id.skip); 71 View submit = DialogCompat.requireViewById(dialog, R.id.submit); 72 73 SpannableString reminderText = new SpannableString(context.getString(R.string.KbsReminderDialog__to_help_you_memorize_your_pin)); 74 SpannableString forgotText = new SpannableString(context.getString(R.string.KbsReminderDialog__forgot_pin)); 75 76 ViewUtil.focusAndShowKeyboard(pinEditText); 77 ViewCompat.setAutofillHints(pinEditText, HintConstants.AUTOFILL_HINT_PASSWORD); 78 79 switch (SignalStore.pinValues().getKeyboardType()) { 80 case NUMERIC: 81 pinEditText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD); 82 break; 83 case ALPHA_NUMERIC: 84 pinEditText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); 85 break; 86 } 87 88 ClickableSpan clickableSpan = new ClickableSpan() { 89 @Override 90 public void onClick(@NonNull View widget) { 91 dialog.dismiss(); 92 launcher.launch(CreateSvrPinActivity.getIntentForPinChangeFromForgotPin(context), CreateSvrPinActivity.REQUEST_NEW_PIN); 93 } 94 }; 95 96 forgotText.setSpan(clickableSpan, 0, forgotText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 97 98 reminder.setText(new SpannableStringBuilder(reminderText).append(" ").append(forgotText)); 99 reminder.setMovementMethod(LinkMovementMethod.getInstance()); 100 101 PinVerifier.Callback callback = getPinWatcherCallback(context, dialog, pinEditText, pinStatus, mainCallback); 102 PinVerifier verifier = new V2PinVerifier(); 103 104 skip.setOnClickListener(v -> { 105 dialog.dismiss(); 106 mainCallback.onReminderDismissed(callback.hadWrongGuess()); 107 }); 108 109 submit.setEnabled(false); 110 submit.setOnClickListener(v -> { 111 Editable pinEditable = pinEditText.getText(); 112 113 verifier.verifyPin(pinEditable == null ? null : pinEditable.toString(), callback); 114 }); 115 116 pinEditText.addTextChangedListener(new SimpleTextWatcher() { 117 118 private final String localHash = Objects.requireNonNull(SignalStore.svr().getLocalPinHash()); 119 120 @Override 121 public void onTextChanged(String text) { 122 if (text.length() >= SvrConstants.MINIMUM_PIN_LENGTH) { 123 submit.setEnabled(true); 124 125 if (PinHashUtil.verifyLocalPinHash(localHash, text)) { 126 dialog.dismiss(); 127 mainCallback.onReminderCompleted(text, callback.hadWrongGuess()); 128 } 129 } else { 130 submit.setEnabled(false); 131 } 132 } 133 }); 134 } 135 136 private static PinVerifier.Callback getPinWatcherCallback(@NonNull Context context, 137 @NonNull AlertDialog dialog, 138 @NonNull EditText inputText, 139 @NonNull TextView statusText, 140 @NonNull Callback mainCallback) 141 { 142 return new PinVerifier.Callback() { 143 boolean hadWrongGuess = false; 144 145 @Override 146 public void onPinCorrect(@NonNull String pin) { 147 Log.i(TAG, "Correct PIN entry."); 148 dialog.dismiss(); 149 mainCallback.onReminderCompleted(pin, hadWrongGuess); 150 } 151 152 @Override 153 public void onPinWrong() { 154 Log.i(TAG, "Incorrect PIN entry."); 155 hadWrongGuess = true; 156 inputText.getText().clear(); 157 statusText.setText(context.getString(R.string.KbsReminderDialog__incorrect_pin_try_again)); 158 } 159 160 @Override 161 public boolean hadWrongGuess() { 162 return hadWrongGuess; 163 } 164 }; 165 } 166 167 private static final class V2PinVerifier implements PinVerifier { 168 169 private final String localPinHash; 170 171 V2PinVerifier() { 172 localPinHash = SignalStore.svr().getLocalPinHash(); 173 174 if (localPinHash == null) throw new AssertionError("No local pin hash set at time of reminder"); 175 } 176 177 @Override 178 public void verifyPin(@Nullable String pin, @NonNull Callback callback) { 179 if (pin == null) return; 180 if (TextUtils.isEmpty(pin)) return; 181 182 if (pin.length() < SvrConstants.MINIMUM_PIN_LENGTH) return; 183 184 if (PinHashUtil.verifyLocalPinHash(localPinHash, pin)) { 185 callback.onPinCorrect(pin); 186 } else { 187 callback.onPinWrong(); 188 } 189 } 190 } 191 192 private interface PinVerifier { 193 194 void verifyPin(@Nullable String pin, @NonNull PinVerifier.Callback callback); 195 196 interface Callback { 197 void onPinCorrect(@NonNull String pin); 198 void onPinWrong(); 199 boolean hadWrongGuess(); 200 } 201 } 202 203 public interface Launcher { 204 void launch(@NonNull Intent intent, int requestCode); 205 } 206 207 public interface Callback { 208 void onReminderDismissed(boolean includedFailure); 209 void onReminderCompleted(@NonNull String pin, boolean includedFailure); 210 } 211}