diff --git a/fdroidserver/install.py b/fdroidserver/install.py index c3a64ae8..9645f89d 100644 --- a/fdroidserver/install.py +++ b/fdroidserver/install.py @@ -106,6 +106,17 @@ def download_fdroid_apk(privacy_mode=False): # pylint: disable=unused-argument return net.download_using_mirrors([mirror]) +def download_fdroid_apk_from_ipns(privacy_mode=False): + """Download the F-Droid APK from an IPNS repo.""" + cid = 'k51qzi5uqu5dl4hbcksbdmplanu9n4hivnqsupqe6vzve1pdbeh418ssptldd3' + mirrors = [ + {"url": f"https://ipfs.io/ipns/{cid}/F-Droid.apk"}, + ] + if not privacy_mode: + mirrors.append({"url": f"https://{cid}.ipns.dweb.link/F-Droid.apk"}) + return net.download_using_mirrors(mirrors) + + def download_fdroid_apk_from_maven(privacy_mode=False): """Download F-Droid.apk from Maven Central and official mirrors.""" path = 'org/fdroid/fdroid/F-Droid' @@ -149,11 +160,13 @@ def install_fdroid_apk(privacy_mode=False): if privacy_mode or not (common.config and common.config.get('jarsigner')): download_methods = [ download_fdroid_apk_from_maven, + download_fdroid_apk_from_ipns, ] else: download_methods = [ download_apk, download_fdroid_apk_from_maven, + download_fdroid_apk_from_ipns, download_fdroid_apk, ] for method in download_methods: diff --git a/tests/install.TestCase b/tests/install.TestCase index c09b05d8..535832d2 100755 --- a/tests/install.TestCase +++ b/tests/install.TestCase @@ -177,48 +177,57 @@ class InstallTest(unittest.TestCase): @patch('fdroidserver.install.download_apk') @patch('fdroidserver.install.download_fdroid_apk') + @patch('fdroidserver.install.download_fdroid_apk_from_ipns') @patch('fdroidserver.install.download_fdroid_apk_from_maven') def test_install_fdroid_apk_privacy_mode_true( - self, maven, download_fdroid_apk, download_apk + self, maven, ipns, download_fdroid_apk, download_apk ): download_apk.side_effect = self._download_raise download_fdroid_apk.side_effect = self._download_raise + ipns.side_effect = self._download_raise maven.side_effect = self._download_raise fdroidserver.common.config = {'jarsigner': 'fakepath'} install.install_fdroid_apk(privacy_mode=True) download_apk.assert_not_called() download_fdroid_apk.assert_not_called() + ipns.assert_called_once() maven.assert_called_once() @patch('fdroidserver.install.download_apk') @patch('fdroidserver.install.download_fdroid_apk') + @patch('fdroidserver.install.download_fdroid_apk_from_ipns') @patch('fdroidserver.install.download_fdroid_apk_from_maven') def test_install_fdroid_apk_privacy_mode_false( - self, maven, download_fdroid_apk, download_apk + self, maven, ipns, download_fdroid_apk, download_apk ): download_apk.side_effect = self._download_raise download_fdroid_apk.side_effect = self._download_raise + ipns.side_effect = self._download_raise maven.side_effect = self._download_raise fdroidserver.common.config = {'jarsigner': 'fakepath'} install.install_fdroid_apk(privacy_mode=False) download_apk.assert_called_once() download_fdroid_apk.assert_called_once() + ipns.assert_called_once() maven.assert_called_once() @patch('fdroidserver.install.download_apk') @patch('fdroidserver.install.download_fdroid_apk') + @patch('fdroidserver.install.download_fdroid_apk_from_ipns') @patch('fdroidserver.install.download_fdroid_apk_from_maven') @patch('locale.getlocale', lambda: ('zh_CN', 'UTF-8')) def test_install_fdroid_apk_privacy_mode_locale_auto( - self, maven, download_fdroid_apk, download_apk + self, maven, ipns, download_fdroid_apk, download_apk ): download_apk.side_effect = self._download_raise download_fdroid_apk.side_effect = self._download_raise + ipns.side_effect = self._download_raise maven.side_effect = self._download_raise fdroidserver.common.config = {'jarsigner': 'fakepath'} install.install_fdroid_apk(privacy_mode=None) download_apk.assert_not_called() download_fdroid_apk.assert_not_called() + ipns.assert_called_once() maven.assert_called_once() @patch('fdroidserver.net.download_using_mirrors', lambda m: 'testvalue') @@ -235,6 +244,11 @@ class InstallTest(unittest.TestCase): f = install.download_fdroid_apk_from_maven() self.assertTrue(Path(f).exists()) + @unittest.skipUnless(os.getenv('test_download_fdroid_apk'), 'requires net access') + def test_download_fdroid_apk_from_ipns(self): + f = install.download_fdroid_apk_from_ipns() + self.assertTrue(Path(f).exists()) + if __name__ == "__main__": os.chdir(os.path.dirname(__file__))