diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-22 12:04:10 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-22 12:04:10 +0200 |
| commit | 48b44a6e27b87ee8bf5340a8d7ff37afaf04b7f9 (patch) | |
| tree | 1eb779b880a78bda3af7bed4eb93a43dafd288bc /app/src/main/java/mygram/droid/Prefs.java | |
| parent | a605449390de7737e718e6d10574e5581cf757e3 (diff) | |
| download | mygram-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.java | 47 |
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(); + } } |
