diff --git a/src/org/fdroid/fdroid/data/NewRepoConfig.java b/src/org/fdroid/fdroid/data/NewRepoConfig.java new file mode 100644 index 000000000..080c97b4a --- /dev/null +++ b/src/org/fdroid/fdroid/data/NewRepoConfig.java @@ -0,0 +1,137 @@ + +package org.fdroid.fdroid.data; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.text.TextUtils; +import android.util.Log; + +import org.fdroid.fdroid.R; + +import java.util.Arrays; +import java.util.Locale; + +public class NewRepoConfig { + + private String errorMessage; + private boolean isValidRepo; + + private String uriString; + private Uri uri; + private String host; + private int port = -1; + private String scheme; + private String fingerprint; + private String bssid; + private String ssid; + + public NewRepoConfig(Context context, Intent intent) { + /* an URL from a click, NFC, QRCode scan, etc */ + uri = intent.getData(); + if (uri == null) { + isValidRepo = false; + return; + } + + // scheme and host should only ever be pure ASCII aka Locale.ENGLISH + scheme = intent.getScheme(); + host = uri.getHost(); + port = uri.getPort(); + if (TextUtils.isEmpty(scheme) || TextUtils.isEmpty(host)) { + errorMessage = String.format(context.getString(R.string.malformed_repo_uri), + uri); + isValidRepo = false; + return; + } + + if (Arrays.asList("FDROIDREPO", "FDROIDREPOS").contains(scheme)) { + /* + * QRCodes are more efficient in all upper case, so QR URIs are + * encoded in all upper case, then forced to lower case. Checking if + * the special F-Droid scheme being all is upper case means it + * should be downcased. + */ + uri = Uri.parse(uri.toString().toLowerCase(Locale.ENGLISH)); + } else if (uri.getPath().endsWith("/FDROID/REPO")) { + /* + * some QR scanners chop off the fdroidrepo:// and just try http://, + * then the incoming URI does not get downcased properly, and the + * query string is stripped off. So just downcase the path, and + * carry on to get something working. + */ + uri = Uri.parse(uri.toString().toLowerCase(Locale.ENGLISH)); + } + + // make scheme and host lowercase so they're readable in dialogs + scheme = scheme.toLowerCase(Locale.ENGLISH); + host = host.toLowerCase(Locale.ENGLISH); + fingerprint = uri.getQueryParameter("fingerprint"); + bssid = uri.getQueryParameter("bssid"); + ssid = uri.getQueryParameter("ssid"); + + Log.i("RepoListFragment", "onCreate " + fingerprint); + if (Arrays.asList("fdroidrepos", "fdroidrepo", "https", "http").contains(scheme)) { + uriString = sanitizeRepoUri(uri); + } + + this.isValidRepo = true; + } + + public String getBssid() { + return bssid; + } + + public String getSsid() { + return ssid; + } + + public int getPort() { + return port; + } + + public String getUriString() { + return uriString; + } + + public String getHost() { + return host; + } + + public String getScheme() { + return scheme; + } + + public String getFingerprint() { + return fingerprint; + } + + public boolean isValidRepo() { + return isValidRepo; + } + + /* + * The port starts out as 8888, but if there is a conflict, it will be + * incremented until there is a free port found. + */ + public boolean looksLikeLocalRepo() { + return (port >= 8888 && host.matches("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+")); + } + + public String getErrorMessage() { + return errorMessage; + } + + /** Sanitize and format an incoming repo URI for function and readability */ + public static String sanitizeRepoUri(Uri uri) { + String scheme = uri.getScheme(); + String host = uri.getHost(); + return uri.toString() + .replaceAll("\\?.*$", "") // remove the whole query + .replaceAll("/*$", "") // remove all trailing slashes + .replace(host, host.toLowerCase(Locale.ENGLISH)) + .replace(scheme, scheme.toLowerCase(Locale.ENGLISH)) + .replace("fdroidrepo", "http") // proper repo address + .replace("/FDROID/REPO", "/fdroid/repo"); // for QR FDroid path + } +} diff --git a/src/org/fdroid/fdroid/views/ManageReposActivity.java b/src/org/fdroid/fdroid/views/ManageReposActivity.java index 1473e7ef7..00b3463c7 100644 --- a/src/org/fdroid/fdroid/views/ManageReposActivity.java +++ b/src/org/fdroid/fdroid/views/ManageReposActivity.java @@ -60,6 +60,7 @@ import org.fdroid.fdroid.ProgressListener; import org.fdroid.fdroid.R; import org.fdroid.fdroid.UpdateService; import org.fdroid.fdroid.compat.ClipboardCompat; +import org.fdroid.fdroid.data.NewRepoConfig; import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.RepoProvider; import org.fdroid.fdroid.net.MDnsHelper; @@ -443,71 +444,28 @@ public class ManageReposActivity extends ActionBarActivity { private void addRepoFromIntent(Intent intent) { /* an URL from a click, NFC, QRCode scan, etc */ - Uri uri = intent.getData(); - if (uri != null) { - // scheme and host should only ever be pure ASCII aka Locale.ENGLISH - String scheme = intent.getScheme(); - String host = uri.getHost(); - if (scheme == null || host == null) { - String msg = String.format(getString(R.string.malformed_repo_uri), uri); + NewRepoConfig newRepoConfig = new NewRepoConfig(this, intent); + if (newRepoConfig.isValidRepo()) { + importRepo(newRepoConfig.getUriString(), newRepoConfig.getFingerprint()); + checkIfNewRepoOnSameWifi(newRepoConfig); + } else if (newRepoConfig.getErrorMessage() != null) { + Toast.makeText(this, newRepoConfig.getErrorMessage(), Toast.LENGTH_LONG).show(); + } + } + + private void checkIfNewRepoOnSameWifi(NewRepoConfig newRepo) { + // if this is a local repo, check we're on the same wifi + if (!TextUtils.isEmpty(newRepo.getBssid())) { + WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + String bssid = wifiInfo.getBSSID().toLowerCase(Locale.ENGLISH); + String newRepoBssid = Uri.decode(newRepo.getBssid()).toLowerCase(Locale.ENGLISH); + if (!bssid.equals(newRepoBssid)) { + String msg = String.format(getString(R.string.not_on_same_wifi), newRepo.getSsid()); Toast.makeText(this, msg, Toast.LENGTH_LONG).show(); - return; - } - if (scheme.equals("FDROIDREPO") || scheme.equals("FDROIDREPOS")) { - /* - * QRCodes are more efficient in all upper case, so QR URIs are - * encoded in all upper case, then forced to lower case. - * Checking if the special F-Droid scheme being all is upper - * case means it should be downcased. - */ - uri = Uri.parse(uri.toString().toLowerCase(Locale.ENGLISH)); - } else if (uri.getPath().startsWith("/FDROID/REPO")) { - /* - * some QR scanners chop off the fdroidrepo:// and just try - * http://, then the incoming URI does not get downcased - * properly, and the query string is stripped off. So just - * downcase the path, and carry on to get something working. - */ - uri = Uri.parse(uri.toString().toLowerCase(Locale.ENGLISH)); - } - // make scheme and host lowercase so they're readable in dialogs - scheme = scheme.toLowerCase(Locale.ENGLISH); - host = host.toLowerCase(Locale.ENGLISH); - String fingerprint = uri.getQueryParameter("fingerprint"); - Log.i("RepoListFragment", "onCreate " + fingerprint); - if (scheme.equals("fdroidrepos") || scheme.equals("fdroidrepo") - || scheme.equals("https") || scheme.equals("http")) { - - /* sanitize and format for function and readability */ - String uriString = uri.toString() - .replaceAll("\\?.*$", "") // remove the whole query - .replaceAll("/*$", "") // remove all trailing slashes - .replace(uri.getHost(), host) // downcase host name - .replace(intent.getScheme(), scheme) // downcase scheme - .replace("fdroidrepo", "http"); // proper repo address - importRepo(uriString, fingerprint); - - // if this is a local repo, check we're on the same wifi - String uriBssid = uri.getQueryParameter("bssid"); - if (!TextUtils.isEmpty(uriBssid)) { - if (uri.getPort() != 8888 - && !host.matches("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+")) { - Log.i("ManageRepo", "URI is not local repo: " + uri); - return; - } - WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); - WifiInfo wifiInfo = wifiManager.getConnectionInfo(); - String bssid = wifiInfo.getBSSID().toLowerCase(Locale.ENGLISH); - uriBssid = Uri.decode(uriBssid).toLowerCase(Locale.ENGLISH); - if (!bssid.equals(uriBssid)) { - String msg = String.format(getString(R.string.not_on_same_wifi), - uri.getQueryParameter("ssid")); - Toast.makeText(this, msg, Toast.LENGTH_LONG).show(); - } - // TODO we should help the user to the right thing here, - // instead of just showing a message! - } } + // TODO we should help the user to the right thing here, + // instead of just showing a message! } }