diff --git a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java
index 8b9bb743e..b6a290916 100644
--- a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java
+++ b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java
@@ -387,9 +387,6 @@ public class FDroidApp extends Application implements androidx.work.Configuratio
grantUriPermission(packageName, InstallHistoryService.LOG_URI, modeFlags);
}
- // find and process provisions if any.
- Provisioner.scanAndProcess(getApplicationContext());
-
// if the underlying OS version has changed, then fully rebuild the database
SharedPreferences atStartTime = getAtStartTimeSharedPreferences();
if (Build.VERSION.SDK_INT != atStartTime.getInt("build-version", Build.VERSION.SDK_INT)) {
diff --git a/app/src/main/java/org/fdroid/fdroid/Provisioner.java b/app/src/main/java/org/fdroid/fdroid/Provisioner.java
deleted file mode 100644
index 809b3a298..000000000
--- a/app/src/main/java/org/fdroid/fdroid/Provisioner.java
+++ /dev/null
@@ -1,320 +0,0 @@
-package org.fdroid.fdroid;
-
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.util.Base64;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import org.apache.commons.io.IOUtils;
-import org.fdroid.fdroid.data.Repo;
-import org.fdroid.fdroid.data.RepoProvider;
-import org.fdroid.fdroid.views.ManageReposActivity;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-/**
- * @author Michael Pöhn (michael.poehn@fsfe.org)
- */
-@SuppressWarnings("LineLength")
-public class Provisioner {
-
- public static final String TAG = "Provisioner";
-
- /**
- * This is the name of the subfolder in the file directory of this app
- * where {@link Provisioner} looks for new provisions.
- *
- * eg. in the Emulator (API level 24): /data/user/0/org.fdroid.fdroid.debug/files/provisions
- */
- private static final String NEW_PROVISIONS_DIR = "provisions";
-
- protected Provisioner() {
- }
-
- /**
- * search for provision files and process them
- */
- static void scanAndProcess(Context context) {
- File externalFilesDir = context.getExternalFilesDir(null);
- if (externalFilesDir == null) {
- return;
- }
- File provisionDir = new File(externalFilesDir.getAbsolutePath(), NEW_PROVISIONS_DIR);
-
- if (!provisionDir.isDirectory()) {
- Utils.debugLog(TAG, "Provisions dir does not exists: '" + provisionDir.getAbsolutePath() + "' moving on ...");
- } else if (provisionDir.list().length == 0) {
- Utils.debugLog(TAG, "Provisions dir is empty: '" + provisionDir.getAbsolutePath() + "' moving on ...");
- } else {
-
- Provisioner p = new Provisioner();
- List files = p.findProvisionFiles(context);
- List plaintexts = p.extractProvisionsPlaintext(files);
- List provisions = p.parseProvisions(plaintexts);
-
- if (provisions == null || provisions.isEmpty()) {
- Utils.debugLog(TAG, "Provision dir is empty: '" + provisionDir.getAbsolutePath() + "' moving on ...");
- } else {
- int cleanupCounter = 0;
- for (Provision provision : provisions) {
- if (provision.getRepositoryProvision() != null) {
- RepositoryProvision repo = provision.getRepositoryProvision();
-
- Repo storedRepo = RepoProvider.Helper.findByAddress(context, repo.getUrl());
- if (storedRepo != null) {
- Utils.debugLog(TAG, "Provision contains a repo which is already added: '" + provision.getProvisonPath() + "' ignoring ...");
- } else {
- // Note: only the last started activity will visible to users.
- // All other prompting attempts will be lost.
- Uri origUrl = Uri.parse(repo.getUrl());
- Uri.Builder data = new Uri.Builder();
- data.scheme(origUrl.getScheme());
- data.encodedAuthority(Uri.encode(repo.getUsername()) + ':'
- + Uri.encode(repo.getPassword()) + '@' + Uri.encode(origUrl.getAuthority()));
- data.path(origUrl.getPath());
- data.appendQueryParameter("fingerprint", repo.getSigfp());
- Intent i = new Intent(context, ManageReposActivity.class);
- i.setData(data.build());
- context.startActivity(i);
- Utils.debugLog(TAG, "Provision processed: '"
- + provision.getProvisonPath() + "' prompted user ...");
- }
-
- }
-
- // remove provision file
- try {
- if (new File(provision.getProvisonPath()).delete()) {
- cleanupCounter++;
- }
- } catch (SecurityException e) {
- // ignore this exception
- Utils.debugLog(TAG, "Removing provision not possible: " + e.getMessage() + " ()");
- }
- }
- Utils.debugLog(TAG, "Provisions done, removed " + cleanupCounter + " provision(s).");
- }
- }
- }
-
- private List findProvisionFiles(Context context) {
- File externalFilesDir = context.getExternalFilesDir(null);
- if (externalFilesDir == null) {
- return Collections.emptyList();
- }
- File provisionDir = new File(externalFilesDir.getAbsolutePath(), NEW_PROVISIONS_DIR);
- return findProvisionFilesInDir(provisionDir);
- }
-
- List findProvisionFilesInDir(File file) {
- if (file == null || !file.isDirectory()) {
- return Collections.emptyList();
- }
- try {
- File[] files = file.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- if (name != null && name.endsWith(".fdrp")) {
- return true;
- }
- return false;
- }
- });
- return files != null ? Arrays.asList(files) : null;
- } catch (Exception e) {
- Utils.debugLog(TAG, "can not search for provisions, can not access: " + file.getAbsolutePath(), e);
- return new ArrayList<>();
- }
- }
-
- String rot13(String text) {
- StringBuilder sb = new StringBuilder(text.length());
- for (int i = 0; i < text.length(); i++) {
- char c = text.charAt(i);
- if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M')) {
- sb.append((char) (c + 13));
- } else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z')) {
- sb.append((char) (c - 13));
- } else {
- sb.append(c);
- }
- }
- return sb.toString();
- }
-
- String deobfuscate(String obfuscated) {
- try {
- return new String(Base64.decode(rot13(obfuscated), Base64.DEFAULT), "UTF-8");
- } catch (UnsupportedEncodingException e) {
- // encoding is defined to be utf8, continue gracefully if this magically fails.
- return "";
- }
- }
-
- List extractProvisionsPlaintext(List files) {
- List result = new ArrayList<>();
- if (files != null) {
- for (File file : files) {
- ProvisionPlaintext plain = new ProvisionPlaintext();
- plain.setProvisionPath(file.getAbsolutePath());
- ZipInputStream in = null;
- try {
- in = new ZipInputStream(new FileInputStream(file));
- ZipEntry zipEntry;
- while ((zipEntry = in.getNextEntry()) != null) { // NOPMD Avoid assignments in operands
- String name = zipEntry.getName();
- if ("repo_provision.json".equals(name)) {
- if (plain.getRepositoryProvision() != null) {
- throw new IOException("provision malformed: contains more than one repo provision file.");
- }
- plain.setRepositoryProvision(IOUtils.toString(in, Charset.forName("UTF-8")));
- } else if ("repo_provision.ojson".equals(name)) {
- if (plain.getRepositoryProvision() != null) {
- throw new IOException("provision malformed: contains more than one repo provision file.");
- }
- plain.setRepositoryProvision(deobfuscate(IOUtils.toString(in, Charset.forName("UTF-8"))));
- }
- }
- } catch (FileNotFoundException e) {
- Utils.debugLog(TAG, String.format("finding provision '%s' failed", file.getPath()), e);
- continue;
- } catch (IOException e) {
- Utils.debugLog(TAG, String.format("reading provision '%s' failed", file.getPath()), e);
- continue;
- } finally {
- IOUtils.closeQuietly(in);
- }
-
- result.add(plain);
- }
- }
- return result;
- }
-
- List parseProvisions(List provisionPlaintexts) {
-
- List provisions = new ArrayList<>();
- ObjectMapper mapper = new ObjectMapper();
-
- if (provisionPlaintexts != null) {
- for (ProvisionPlaintext provisionPlaintext : provisionPlaintexts) {
- Provision provision = new Provision();
- provision.setProvisonPath(provisionPlaintext.getProvisionPath());
- try {
- provision.setRepositoryProvision(
- mapper.readValue(provisionPlaintext.getRepositoryProvision(), RepositoryProvision.class));
- provisions.add(provision);
- } catch (IOException e) {
- Utils.debugLog(TAG, "could not parse repository provision", e);
- }
- }
- }
-
- return provisions;
- }
-
- static class ProvisionPlaintext {
- private String provisionPath;
- private String repositoryProvision;
-
- String getProvisionPath() {
- return provisionPath;
- }
-
- void setProvisionPath(String provisionPath) {
- this.provisionPath = provisionPath;
- }
-
- String getRepositoryProvision() {
- return repositoryProvision;
- }
-
- void setRepositoryProvision(String repositoryProvision) {
- this.repositoryProvision = repositoryProvision;
- }
- }
-
- static class Provision {
- private String provisonPath;
- private RepositoryProvision repositoryProvision;
-
- String getProvisonPath() {
- return provisonPath;
- }
-
- void setProvisonPath(String provisonPath) {
- this.provisonPath = provisonPath;
- }
-
- RepositoryProvision getRepositoryProvision() {
- return repositoryProvision;
- }
-
- void setRepositoryProvision(RepositoryProvision repositoryProvision) {
- this.repositoryProvision = repositoryProvision;
- }
- }
-
- public static class RepositoryProvision {
-
- private String name;
- private String url;
- private String sigfp;
- private String username;
- private String password;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getUrl() {
- return url;
- }
-
- public void setUrl(String url) {
- this.url = url;
- }
-
- public String getSigfp() {
- return sigfp;
- }
-
- public void setSigfp(String sigfp) {
- this.sigfp = sigfp;
- }
-
- public String getUsername() {
- return username;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
- }
-}
diff --git a/app/src/test/java/org/fdroid/fdroid/ProvisionerTest.java b/app/src/test/java/org/fdroid/fdroid/ProvisionerTest.java
deleted file mode 100644
index 3fd318007..000000000
--- a/app/src/test/java/org/fdroid/fdroid/ProvisionerTest.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package org.fdroid.fdroid;
-
-import org.fdroid.fdroid.shadows.ShadowLog;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * @author Michael Poehn (michael.poehn@fsfe.org)
- */
-@RunWith(RobolectricTestRunner.class)
-@SuppressWarnings("LineLength")
-public class ProvisionerTest {
-
- @Before
- public void setUp() {
- ShadowLog.stream = System.out;
- }
-
- @Test
- public void provisionLookup() throws IOException {
- // wired hack for getting resource dir path ...
- String resourceDir = getResourceFile(
- "demo_credentials_user1.fdrp").getParent();
-
- Provisioner p = new Provisioner();
- List files = p.findProvisionFilesInDir(new File(resourceDir));
-
- List expectedFilenames = Arrays.asList(
- "demo_credentials_user1.fdrp",
- "demo_credentials_user2.fdrp");
-
- Assert.assertEquals(2, files.size());
- for (File f : files) {
- Assert.assertTrue("unexpected file name " + f.getName(), expectedFilenames.contains(f.getName()));
- }
- }
-
- @Test
- public void rot13() {
- Provisioner p = new Provisioner();
- String result = p.rot13("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890{}\"':=");
- Assert.assertEquals("nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM1234567890{}\"':=", result);
- }
-
- @Test
- public void deobfuscate() {
- Provisioner p = new Provisioner();
- String result = p.deobfuscate("rlWVMKWuL2kcqUImVwbaGz90nTyhMlOyozE1pzImVTW1qPOwnTShM2HhWljXVPNtVPq3nTIhWmbtJlWuLz91qPN1ZQNtDv5QYvWqsD==");
- Assert.assertEquals("{\"Heraclitus\":'Nothing endures but change.',\n 'when': [\"about 500 B.C.\"]}", result);
- }
-
- @Test
- public void extractProvisionsPlaintextUnobfuscated() throws IOException {
- Provisioner p = new Provisioner();
- List files = Arrays.asList(getResourceFile("demo_credentials_user2.fdrp"));
- List result = p.extractProvisionsPlaintext(files);
-
- Assert.assertEquals(result.size(), 1);
- Assert.assertEquals("{\"username\": \"user2\", \"password\": \"other secret\", \"name\": \"Example Repo\", \"url\": \"https://example.com/fdroid/repo\", \"sigfp\": \"1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff\"}", result.get(0).getRepositoryProvision());
- Assert.assertTrue(String.valueOf(result.get(0).getProvisionPath()).endsWith("demo_credentials_user2.fdrp"));
- }
-
- @Test
- public void extractProvisionsPlaintextObfuscated() throws IOException {
- Provisioner p = new Provisioner();
- List files = Arrays.asList(getResourceFile("demo_credentials_user1.fdrp"));
- List result = p.extractProvisionsPlaintext(files);
-
- Assert.assertEquals(result.size(), 1);
- Assert.assertEquals("{\"sigfp\": \"1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff\", \"name\": \"Example Repo\", \"password\": \"secret1\", \"url\": \"https://example.com/fdroid/repo\", \"username\": \"user1\"}", result.get(0).getRepositoryProvision());
- Assert.assertTrue(String.valueOf(result.get(0).getProvisionPath()).endsWith("demo_credentials_user1.fdrp"));
- }
-
- @Test
- public void parseProvisions() {
-
- List plaintexts = Arrays.asList(new Provisioner.ProvisionPlaintext(), new Provisioner.ProvisionPlaintext());
- plaintexts.get(0).setProvisionPath("/some/dir/abc.fdrp");
- plaintexts.get(0).setRepositoryProvision("{\"username\": \"user1\", \"password\": \"secret1\", \"name\": \"test repo a\", \"url\": \"https://example.com/fdroid/repo\", \"sigfp\": \"1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff\"}");
- plaintexts.get(1).setProvisionPath("/some/dir/def.fdrp");
- plaintexts.get(1).setRepositoryProvision("{\"username\": \"user2\", \"name\": \"test repo a\", \"password\": \"other secret\", \"url\": \"https://example.com/fdroid/repo\", \"sigfp\": \"1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff\"}");
-
- Provisioner p = new Provisioner();
- List result = p.parseProvisions(plaintexts);
-
- Assert.assertEquals("/some/dir/abc.fdrp", result.get(0).getProvisonPath());
- Assert.assertEquals("test repo a", result.get(0).getRepositoryProvision().getName());
- Assert.assertEquals("https://example.com/fdroid/repo", result.get(0).getRepositoryProvision().getUrl());
- Assert.assertEquals("1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff", result.get(0).getRepositoryProvision().getSigfp());
- Assert.assertEquals("user1", result.get(0).getRepositoryProvision().getUsername());
- Assert.assertEquals("secret1", result.get(0).getRepositoryProvision().getPassword());
-
- Assert.assertEquals("/some/dir/def.fdrp", result.get(1).getProvisonPath());
- Assert.assertEquals("test repo a", result.get(1).getRepositoryProvision().getName());
- Assert.assertEquals("https://example.com/fdroid/repo", result.get(1).getRepositoryProvision().getUrl());
- Assert.assertEquals("1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff", result.get(1).getRepositoryProvision().getSigfp());
- Assert.assertEquals("user2", result.get(1).getRepositoryProvision().getUsername());
- Assert.assertEquals("other secret", result.get(1).getRepositoryProvision().getPassword());
- }
-
- private File getResourceFile(String resourceFileName) {
- return new File(getClass().getClassLoader().getResource(resourceFileName).getPath());
- }
-}