package org.fdroid.fdroid.data;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.text.TextUtils;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.localrepo.peers.WifiPeer;
import org.fdroid.fdroid.views.swap.SwapWorkflowActivity;
import java.util.Arrays;
import java.util.Locale;
public class NewRepoConfig {
private static final String TAG = "NewRepoConfig";
private String errorMessage;
private boolean isValidRepo;
private String uriString;
private String host;
private int port = -1;
private String fingerprint;
private String bssid;
private String ssid;
private boolean fromSwap;
private boolean preventFurtherSwaps;
public NewRepoConfig(Context context, String uri) {
init(context, uri != null ? Uri.parse(uri) : null);
}
public NewRepoConfig(Context context, Intent intent) {
init(context, intent.getData());
preventFurtherSwaps = intent.getBooleanExtra(SwapWorkflowActivity.EXTRA_PREVENT_FURTHER_SWAP_REQUESTS, false);
}
private void init(Context context, Uri incomingUri) {
/* an URL from a click, NFC, QRCode scan, etc */
Uri uri = incomingUri;
if (uri == null) {
isValidRepo = false;
return;
}
Utils.debugLog(TAG, "Parsing incoming intent looking for repo: " + incomingUri);
// scheme and host should only ever be pure ASCII aka Locale.ENGLISH
String scheme = uri.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));
}
String path = uri.getPath();
if (path == null || !(path.contains("/fdroid/archive") || path.contains("/fdroid/repo"))) {
isValidRepo = false;
return;
}
// 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");
fromSwap = uri.getQueryParameter("swap") != null;
if (!Arrays.asList("fdroidrepos", "fdroidrepo", "https", "http").contains(scheme)) {
isValidRepo = false;
return;
}
uriString = sanitizeRepoUri(uri);
isValidRepo = true;
}
public String getBssid() {
return bssid;
}
public String getSsid() {
return ssid;
}
public int getPort() {
return port;
}
public String getRepoUriString() {
return uriString;
}
public Uri getRepoUri() {
if (uriString == null) {
return null;
}
return Uri.parse(uriString);
}
public String getHost() {
return host;
}
public String getFingerprint() {
return fingerprint;
}
public boolean isValidRepo() {
return isValidRepo;
}
public boolean isFromSwap() {
return fromSwap;
}
public boolean preventFurtherSwaps() {
return preventFurtherSwaps;
}
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
}
public WifiPeer toPeer() {
return new WifiPeer(this);
}
}