diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 17ddaa1..c2207f2 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,9 +1,9 @@ + android:versionCode="12" + android:versionName="1.11" + android:installLocation="internalOnly"> diff --git a/README.md b/README.md index 5367dbb..2cdb897 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A tiny Audiobookshelf **podcast** client for the Samsung Galaxy Mini (GT-S5570) 1. Copy `Podlite.apk` to the phone (USB to the SD card, or download it in the browser). 2. On the phone: **Settings → Applications → Unknown sources** → tick it. -3. Open the APK from a file manager and install. It can be moved to the SD card (Settings → Applications → Manage applications → Podlite → Move to SD card). +3. Open the APK from a file manager and install. Podlite installs to internal storage (about 1 MB): an app on the SD card is killed whenever the phone shares its SD card over USB, which stopped playback and broke HTTPS until a restart. ## Connecting diff --git a/src/com/miniabs/Api.java b/src/com/miniabs/Api.java index 87bda38..7ba50c0 100644 --- a/src/com/miniabs/Api.java +++ b/src/com/miniabs/Api.java @@ -26,7 +26,7 @@ import android.os.Build; /** Audiobookshelf REST client (API as of server 2.x, including the 2.26+ token system). */ final class Api { - static final String VERSION = "1.10"; + static final String VERSION = "1.11"; static class ApiException extends IOException { final int code; diff --git a/src/com/miniabs/net/AssetRoots.java b/src/com/miniabs/net/AssetRoots.java index 6ed9198..61a8a4b 100644 --- a/src/com/miniabs/net/AssetRoots.java +++ b/src/com/miniabs/net/AssetRoots.java @@ -4,35 +4,47 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import android.content.Context; -/** Mozilla roots shipped as assets/roots/-.der */ +/** + * Mozilla roots shipped as assets/roots/-.der + * + * Roots are read from the APK once and kept: an app installed on the SD card loses its APK while the + * card is shared over USB, and a failed read must not leave every server "untrusted" until a restart. + */ public final class AssetRoots implements CertVerifier.RootStore { private final Context ctx; - private Set names; + private Set names; // asset file names, once listed + private final Map> found = new HashMap>(); // by subject hash; null = none public AssetRoots(Context c) { ctx = c.getApplicationContext(); } public synchronized List find(byte[] subjectDer) { + String h = CertVerifier.sha1Hex(subjectDer); + if (found.containsKey(h)) return found.get(h); try { if (names == null) { - names = new HashSet(); String[] l = ctx.getAssets().list("roots"); - if (l != null) for (int i = 0; i < l.length; i++) names.add(l[i]); + if (l == null || l.length == 0) return null; // APK unreadable right now: try again next time + Set n = new HashSet(); + for (int i = 0; i < l.length; i++) n.add(l[i]); + names = n; } - String h = CertVerifier.sha1Hex(subjectDer); List out = null; for (int i = 0; names.contains(h + "-" + i + ".der"); i++) { if (out == null) out = new ArrayList(); out.add(readAll(ctx.getAssets().open("roots/" + h + "-" + i + ".der"))); } + found.put(h, out); return out; } catch (IOException e) { - return null; + return null; // not cached: the next handshake reads again } }