aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/mygram/droid/Prefs.java
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-22 12:04:10 +0200
committerDanilo M. <danix@danix.xyz>2026-10-22 12:04:10 +0200
commit48b44a6e27b87ee8bf5340a8d7ff37afaf04b7f9 (patch)
tree1eb779b880a78bda3af7bed4eb93a43dafd288bc /app/src/main/java/mygram/droid/Prefs.java
parenta605449390de7737e718e6d10574e5581cf757e3 (diff)
downloadmygram-droid-48b44a6e27b87ee8bf5340a8d7ff37afaf04b7f9.tar.gz
mygram-droid-48b44a6e27b87ee8bf5340a8d7ff37afaf04b7f9.zip
Optional app PIN, settings header, pink selection ring
- A PIN (4 to 8 digits, salted SHA-256 in prefs) set in Settings shows a logo splash with a PIN prompt at start and whenever the app returns after leaving the screen; Back there leaves the app. - Settings gets the back-arrow header shared with the folder grid (Ui.header) and scrolls, since the PIN fields overflow the screen. - Tile and list focus rings use the icon pink. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'app/src/main/java/mygram/droid/Prefs.java')
-rw-r--r--app/src/main/java/mygram/droid/Prefs.java47
1 files changed, 47 insertions, 0 deletions
diff --git a/app/src/main/java/mygram/droid/Prefs.java b/app/src/main/java/mygram/droid/Prefs.java
index 33ce878..0ff295d 100644
--- a/app/src/main/java/mygram/droid/Prefs.java
+++ b/app/src/main/java/mygram/droid/Prefs.java
@@ -17,6 +17,11 @@ package mygram.droid;
import android.content.Context;
import android.content.SharedPreferences;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
/** Settings stored on the device. */
final class Prefs {
private static SharedPreferences prefs;
@@ -57,4 +62,46 @@ final class Prefs {
static void setTimes(int photo, int background) {
prefs.edit().putInt("photo", photo).putInt("background", background).apply();
}
+
+ static boolean validPin(String pin) {
+ return pin.matches("[0-9]{4,8}");
+ }
+
+ static boolean hasPin() {
+ return !prefs.getString("pin", "").isEmpty();
+ }
+
+ /** Stores "salt:sha256(salt + pin)", never the PIN; null removes it. */
+ static void setPin(String pin) {
+ if (pin == null) {
+ prefs.edit().remove("pin").apply();
+ return;
+ }
+ byte[] b = new byte[16];
+ new SecureRandom().nextBytes(b);
+ String salt = hex(b);
+ prefs.edit().putString("pin", salt + ":" + hash(salt, pin)).apply();
+ }
+
+ static boolean checkPin(String pin) {
+ String[] stored = prefs.getString("pin", "").split(":");
+ return stored.length == 2 && MessageDigest.isEqual(stored[1].getBytes(StandardCharsets.UTF_8),
+ hash(stored[0], pin).getBytes(StandardCharsets.UTF_8));
+ }
+
+ // ponytail: one SHA-256 round; a 4-8 digit PIN is a privacy screen, not a secret against someone with the device storage.
+ static String hash(String salt, String pin) {
+ try {
+ return hex(MessageDigest.getInstance("SHA-256").digest((salt + pin).getBytes(StandardCharsets.UTF_8)));
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException(e); // every Java platform ships SHA-256
+ }
+ }
+
+ private static String hex(byte[] b) {
+ StringBuilder s = new StringBuilder();
+ for (byte x : b)
+ s.append(String.format("%02x", x));
+ return s.toString();
+ }
}