From 72214b9d3617a66a70727819dbf7fe59ea037264 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Sat, 25 Jul 2026 01:30:21 +0000 Subject: Migrate http:// feeds to https:// where it actually works; add feeds as https-only going forward Android blocks cleartext by default (targetSdk 28+), so every http:// feed was failing every single fetch ("CLEARTEXT communication ... not permitted"). Checked each of this user's 9 http feeds live via curl: - 6 work fine over https (5 are a plain scheme swap; divingforpearlsblog.com's own https endpoint redirects through an insecure feedburner hop, so that one points straight at feedburner's https endpoint instead) -- migrated via a new Room migration (v6->v7), rewriting both the feed row and its articles' feedId so read history isn't orphaned. Confirmed live: all 6 now fetch clean with no lastError. - 3 have no usable https at all (bit-player.org: connection refused, no TLS listener; blog.securitymouse.com: broken TLS handshake; webpolicy.org: a certificate that doesn't match the hostname) and are deliberately left alone. Going forward, adding a feed (manually or via OPML import) upgrades a given http:// URL to https:// before using it -- most sites serve identical content either way, and a site with no real https support just fails its very next fetch attempt the normal way instead of silently subscribing to a feed that can never actually update. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL --- .../java/org/terst/feedreader/data/AppDatabase.kt | 40 ++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) (limited to 'app/src/main/java/org/terst/feedreader/data') diff --git a/app/src/main/java/org/terst/feedreader/data/AppDatabase.kt b/app/src/main/java/org/terst/feedreader/data/AppDatabase.kt index 3367a71..da68d3d 100644 --- a/app/src/main/java/org/terst/feedreader/data/AppDatabase.kt +++ b/app/src/main/java/org/terst/feedreader/data/AppDatabase.kt @@ -9,7 +9,7 @@ import androidx.room.migration.Migration @Database( entities = [FeedEntity::class, ArticleEntity::class, FilterRuleEntity::class], - version = 6, + version = 7, exportSchema = false ) abstract class AppDatabase : RoomDatabase() { @@ -99,12 +99,48 @@ abstract class AppDatabase : RoomDatabase() { } } + // v7: this app now upgrades http:// feed URLs to https:// at add/import time (see + // AddFeedScreen.preferHttps), but that only ever runs on the way IN -- feeds already + // subscribed to before this change stay http:// forever otherwise. Android blocks + // cleartext by default (targetSdk 28+), so every one of these was failing every fetch + // ("CLEARTEXT communication ... not permitted"). Checked live (curl) which of this + // user's http feeds actually serve valid content over https and rewrite just those -- + // three hosts genuinely have no usable HTTPS (no TLS listener at all, a broken TLS + // handshake, or a certificate that doesn't match the hostname) and are deliberately + // left alone, since switching them would just trade one permanent failure for another. + private val MIGRATION_6_7 = object : Migration(6, 7) { + override fun migrate(db: SupportSQLiteDatabase) { + val httpToHttps = mapOf( + "http://blog.cryptographyengineering.com/feeds/posts/default" to + "https://blog.cryptographyengineering.com/feeds/posts/default", + "http://mybiasedcoin.blogspot.com/feeds/posts/default?alt=rss" to + "https://mybiasedcoin.blogspot.com/feeds/posts/default?alt=rss", + "http://processalgebra.blogspot.com/feeds/posts/default?alt=rss" to + "https://processalgebra.blogspot.com/feeds/posts/default?alt=rss", + "http://www.rowetel.com/blog/?feed=rss2" to + "https://www.rowetel.com/blog/?feed=rss2", + "http://www.thecodelesscode.com/rss" to + "https://www.thecodelesscode.com/rss", + // This one's own https endpoint redirects through an insecure (http) + // feedburner hop before landing on real content -- point straight at + // feedburner's own https endpoint instead of a URL that would still fail + // cleartext-blocked partway through the redirect chain. + "http://www.divingforpearlsblog.com/feeds/posts/default" to + "https://feeds.feedburner.com/blogspot/sjomU" + ) + for ((oldUrl, newUrl) in httpToHttps) { + db.execSQL("UPDATE articles SET feedId = ? WHERE feedId = ?", arrayOf(newUrl, oldUrl)) + db.execSQL("UPDATE feeds SET id = ? WHERE id = ?", arrayOf(newUrl, oldUrl)) + } + } + } + fun get(context: Context): AppDatabase = instance ?: synchronized(this) { instance ?: Room.databaseBuilder( context.applicationContext, AppDatabase::class.java, "feedreader.db" - ).addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6).build().also { instance = it } + ).addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6, MIGRATION_6_7).build().also { instance = it } } } } -- cgit v1.2.3