That fuck shit the fascists are using
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}