1
0
Fork 0
mirror of https://github.com/syncthing/syncthing-android.git synced 2024-11-23 04:41:16 +00:00

More refactoring

This commit is contained in:
Felix Ableitner 2017-10-02 15:40:10 +09:00
parent be1be9746e
commit e6c9960d0b
12 changed files with 98 additions and 73 deletions

View file

@ -334,7 +334,7 @@ public class SettingsActivity extends SyncthingActivity {
mUseRoot.setChecked(false); mUseRoot.setChecked(false);
new TestRootTask().execute(); new TestRootTask().execute();
} else { } else {
new Thread(new ChownFilesRunnable()).start(); new Thread(() -> Util.fixAppDataPermissions(getActivity())).start();
mSyncthingService.getApi().showRestartDialog(getActivity()); mSyncthingService.getApi().showRestartDialog(getActivity());
} }
return true; return true;
@ -409,16 +409,5 @@ public class SettingsActivity extends SyncthingActivity {
} }
} }
} }
/**
* Changes the owner of syncthing files so they can be accessed without root.
*/
private class ChownFilesRunnable implements Runnable {
@Override
public void run() {
Util.fixAppDataPermissions(getActivity());
}
}
} }
} }

View file

@ -24,6 +24,7 @@ import com.nutomic.syncthingandroid.service.RestApi;
import com.nutomic.syncthingandroid.service.SyncthingService; import com.nutomic.syncthingandroid.service.SyncthingService;
import com.nutomic.syncthingandroid.util.Util; import com.nutomic.syncthingandroid.util.Util;
import java.io.File;
import java.net.URL; import java.net.URL;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.Locale; import java.util.Locale;
@ -196,7 +197,7 @@ public class DrawerFragment extends Fragment implements View.OnClickListener {
private void showQrCode() { private void showQrCode() {
//The QRCode request takes one paramteer called "text", which is the text to be converted to a QRCode. //The QRCode request takes one paramteer called "text", which is the text to be converted to a QRCode.
String httpsCertPath = mActivity.getFilesDir() + "/" + SyncthingService.HTTPS_CERT_FILE; File httpsCertPath = new File(mActivity.getFilesDir(), SyncthingService.HTTPS_CERT_FILE);
String apiKey = mActivity.getApi().getGui().apiKey; String apiKey = mActivity.getApi().getGui().apiKey;
String deviceId = mActivity.getApi().getLocalDevice().deviceID; String deviceId = mActivity.getApi().getLocalDevice().deviceID;
URL url = mActivity.getApi().getUrl(); URL url = mActivity.getApi().getUrl();

View file

@ -19,6 +19,7 @@ import com.android.volley.toolbox.Volley;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
@ -78,10 +79,10 @@ public abstract class ApiRequest {
private final Context mContext; private final Context mContext;
private final URL mUrl; private final URL mUrl;
private final String mPath; private final String mPath;
private final String mHttpsCertPath; private final File mHttpsCertPath;
private final String mApiKey; private final String mApiKey;
public ApiRequest(Context context, URL url, String path, String httpsCertPath, String apiKey) { public ApiRequest(Context context, URL url, String path, File httpsCertPath, String apiKey) {
mContext = context; mContext = context;
mUrl = url; mUrl = url;
mPath = path; mPath = path;
@ -176,7 +177,7 @@ public abstract class ApiRequest {
private SSLSocketFactory getSslSocketFactory() { private SSLSocketFactory getSslSocketFactory() {
try { try {
SSLContext sslContext = SSLContext.getInstance("TLS"); SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{new SyncthingTrustManager()}, sslContext.init(null, new TrustManager[]{new SyncthingTrustManager(mHttpsCertPath)},
new SecureRandom()); new SecureRandom());
return sslContext.getSocketFactory(); return sslContext.getSocketFactory();
} catch (NoSuchAlgorithmException | KeyManagementException e) { } catch (NoSuchAlgorithmException | KeyManagementException e) {
@ -184,51 +185,4 @@ public abstract class ApiRequest {
return null; return null;
} }
} }
/*
* TrustManager checking against the local Syncthing instance's https public key.
*
* Based on http://stackoverflow.com/questions/16719959#16759793
*/
private class SyncthingTrustManager implements X509TrustManager {
private static final String TAG = "SyncthingTrustManager";
@Override
@SuppressLint("TrustAllX509TrustManager")
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
/**
* Verifies certs against public key of the local syncthing instance
*/
@Override
public void checkServerTrusted(X509Certificate[] certs,
String authType) throws CertificateException {
InputStream is = null;
try {
is = new FileInputStream(mHttpsCertPath);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate ca = (X509Certificate) cf.generateCertificate(is);
for (X509Certificate cert : certs) {
cert.verify(ca.getPublicKey());
}
} catch (FileNotFoundException | NoSuchAlgorithmException | InvalidKeyException |
NoSuchProviderException | SignatureException e) {
throw new CertificateException("Untrusted Certificate!", e);
} finally {
try {
if (is != null)
is.close();
} catch (IOException e) {
Log.w(TAG, e);
}
}
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
} }

View file

@ -7,6 +7,7 @@ import android.support.annotation.Nullable;
import com.android.volley.Request; import com.android.volley.Request;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import java.io.File;
import java.net.URL; import java.net.URL;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
@ -25,7 +26,7 @@ public class GetRequest extends ApiRequest {
public static final String URI_REPORT = "/rest/svc/report"; public static final String URI_REPORT = "/rest/svc/report";
public static final String URI_EVENTS = "/rest/events"; public static final String URI_EVENTS = "/rest/events";
public GetRequest(Context context, URL url, String path, String httpsCertPath, String apiKey, public GetRequest(Context context, URL url, String path, File httpsCertPath, String apiKey,
@Nullable Map<String, String> params, OnSuccessListener listener) { @Nullable Map<String, String> params, OnSuccessListener listener) {
super(context, url, path, httpsCertPath, apiKey); super(context, url, path, httpsCertPath, apiKey);
Map<String, String> safeParams = Optional.fromNullable(params).or(Collections.emptyMap()); Map<String, String> safeParams = Optional.fromNullable(params).or(Collections.emptyMap());

View file

@ -6,6 +6,7 @@ import android.support.annotation.Nullable;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import java.io.File;
import java.net.URL; import java.net.URL;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
@ -14,7 +15,7 @@ public class ImageGetRequest extends ApiRequest {
public static final String QR_CODE_GENERATOR = "/qr/"; public static final String QR_CODE_GENERATOR = "/qr/";
public ImageGetRequest(Context context, URL url, String path, String httpsCertPath, String apiKey, public ImageGetRequest(Context context, URL url, String path, File httpsCertPath, String apiKey,
@Nullable Map<String, String> params, OnImageSuccessListener onSuccessListener, OnErrorListener onErrorListener) { @Nullable Map<String, String> params, OnImageSuccessListener onSuccessListener, OnErrorListener onErrorListener) {
super(context, url, path, httpsCertPath, apiKey); super(context, url, path, httpsCertPath, apiKey);
Map<String, String> safeParams = Optional.fromNullable(params).or(Collections.emptyMap()); Map<String, String> safeParams = Optional.fromNullable(params).or(Collections.emptyMap());

View file

@ -8,6 +8,7 @@ import android.os.Handler;
import com.android.volley.Request; import com.android.volley.Request;
import com.android.volley.VolleyError; import com.android.volley.VolleyError;
import java.io.File;
import java.net.URL; import java.net.URL;
import java.util.Collections; import java.util.Collections;
@ -25,7 +26,7 @@ public class PollWebGuiAvailableTask extends ApiRequest {
private final OnSuccessListener mListener; private final OnSuccessListener mListener;
private final Handler mHandler = new Handler(); private final Handler mHandler = new Handler();
public PollWebGuiAvailableTask(Context context, URL url, String httpsCertPath, String apiKey, public PollWebGuiAvailableTask(Context context, URL url, File httpsCertPath, String apiKey,
OnSuccessListener listener) { OnSuccessListener listener) {
super(context, url, "", httpsCertPath, apiKey); super(context, url, "", httpsCertPath, apiKey);
mListener = listener; mListener = listener;

View file

@ -5,6 +5,7 @@ import android.net.Uri;
import com.android.volley.Request; import com.android.volley.Request;
import java.io.File;
import java.net.URL; import java.net.URL;
import java.util.Collections; import java.util.Collections;
@ -12,7 +13,7 @@ public class PostConfigRequest extends ApiRequest {
private static final String URI_CONFIG = "/rest/system/config"; private static final String URI_CONFIG = "/rest/system/config";
public PostConfigRequest(Context context, URL url, String httpsCertPath, String apiKey, String config, public PostConfigRequest(Context context, URL url, File httpsCertPath, String apiKey, String config,
OnSuccessListener listener) { OnSuccessListener listener) {
super(context, url, URI_CONFIG, httpsCertPath, apiKey); super(context, url, URI_CONFIG, httpsCertPath, apiKey);
Uri uri = buildUri(Collections.emptyMap()); Uri uri = buildUri(Collections.emptyMap());

View file

@ -6,13 +6,14 @@ import android.net.Uri;
import com.android.volley.Request; import com.android.volley.Request;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.io.File;
import java.net.URL; import java.net.URL;
public class PostScanRequest extends ApiRequest { public class PostScanRequest extends ApiRequest {
private static final String URI_SCAN = "/rest/db/scan"; private static final String URI_SCAN = "/rest/db/scan";
public PostScanRequest(Context context, URL url, String httpsCertPath, String apiKey, public PostScanRequest(Context context, URL url, File httpsCertPath, String apiKey,
String folder, String sub) { String folder, String sub) {
super(context, url, URI_SCAN, httpsCertPath, apiKey); super(context, url, URI_SCAN, httpsCertPath, apiKey);
Uri uri = buildUri(ImmutableMap.of("folder", folder, "sub", sub)); Uri uri = buildUri(ImmutableMap.of("folder", folder, "sub", sub));

View file

@ -0,0 +1,71 @@
package com.nutomic.syncthingandroid.http;
import android.annotation.SuppressLint;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
/*
* TrustManager checking against the local Syncthing instance's https public key.
*
* Based on http://stackoverflow.com/questions/16719959#16759793
*/
class SyncthingTrustManager implements X509TrustManager {
private static final String TAG = "SyncthingTrustManager";
private final File mHttpsCertPath;
SyncthingTrustManager(File httpsCertPath) {
mHttpsCertPath = httpsCertPath;
}
@Override
@SuppressLint("TrustAllX509TrustManager")
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
/**
* Verifies certs against public key of the local syncthing instance
*/
@Override
public void checkServerTrusted(X509Certificate[] certs,
String authType) throws CertificateException {
InputStream is = null;
try {
is = new FileInputStream(mHttpsCertPath);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate ca = (X509Certificate) cf.generateCertificate(is);
for (X509Certificate cert : certs) {
cert.verify(ca.getPublicKey());
}
} catch (FileNotFoundException | NoSuchAlgorithmException | InvalidKeyException |
NoSuchProviderException | SignatureException e) {
throw new CertificateException("Untrusted Certificate!", e);
} finally {
try {
if (is != null)
is.close();
} catch (IOException e) {
Log.w(TAG, e);
}
}
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}

View file

@ -32,6 +32,7 @@ import com.nutomic.syncthingandroid.model.SystemInfo;
import com.nutomic.syncthingandroid.model.SystemVersion; import com.nutomic.syncthingandroid.model.SystemVersion;
import com.nutomic.syncthingandroid.util.FolderObserver; import com.nutomic.syncthingandroid.util.FolderObserver;
import java.io.File;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.net.URL; import java.net.URL;
import java.util.Collections; import java.util.Collections;
@ -75,7 +76,7 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
private final Context mContext; private final Context mContext;
private final URL mUrl; private final URL mUrl;
private final String mApiKey; private final String mApiKey;
private final String mHttpsCertPath; private final File mHttpsCertPath;
private String mVersion; private String mVersion;
private Config mConfig; private Config mConfig;
@ -104,7 +105,7 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
mContext = context; mContext = context;
mUrl = url; mUrl = url;
mApiKey = apiKey; mApiKey = apiKey;
mHttpsCertPath = mContext.getFilesDir() + "/" + SyncthingService.HTTPS_CERT_FILE; mHttpsCertPath = new File(mContext.getFilesDir(), SyncthingService.HTTPS_CERT_FILE);
mOnApiAvailableListener = apiListener; mOnApiAvailableListener = apiListener;
mOnConfigChangedListener = configListener; mOnConfigChangedListener = configListener;
} }
@ -151,7 +152,7 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
/** /**
* Increments mAvailableCount by one, and, if it reached TOTAL_STARTUP_CALLS, * Increments mAvailableCount by one, and, if it reached TOTAL_STARTUP_CALLS,
* calls {@link SyncthingService#onApiChange()}. * calls {@link SyncthingService#onApiChange}.
*/ */
private void tryIsAvailable() { private void tryIsAvailable() {
int value = mAvailableCount.incrementAndGet(); int value = mAvailableCount.incrementAndGet();

View file

@ -28,6 +28,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.LineNumberReader; import java.io.LineNumberReader;
import java.security.InvalidParameterException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
@ -85,7 +86,7 @@ public class SyncthingRunnable implements Runnable {
mCommand = new String[]{ mSyncthingBinary, "-home", mContext.getFilesDir().toString(), "-reset" }; mCommand = new String[]{ mSyncthingBinary, "-home", mContext.getFilesDir().toString(), "-reset" };
break; break;
default: default:
Log.w(TAG, "Unknown command option"); throw new InvalidParameterException("Unknown command option");
} }
} }
@ -342,6 +343,9 @@ public class SyncthingRunnable implements Runnable {
* Only keep last {@link #LOG_FILE_MAX_LINES} lines in log file, to avoid bloat. * Only keep last {@link #LOG_FILE_MAX_LINES} lines in log file, to avoid bloat.
*/ */
private void trimLogFile() { private void trimLogFile() {
if (!mLogFile.exists())
return;
try { try {
LineNumberReader lnr = new LineNumberReader(new FileReader(mLogFile)); LineNumberReader lnr = new LineNumberReader(new FileReader(mLogFile));
lnr.skip(Long.MAX_VALUE); lnr.skip(Long.MAX_VALUE);

View file

@ -471,7 +471,7 @@ public class SyncthingService extends Service implements
* for SyncthingService.onDestroy for details. * for SyncthingService.onDestroy for details.
*/ */
private void pollWebGui() { private void pollWebGui() {
new PollWebGuiAvailableTask(this, getWebGuiUrl(), getFilesDir() + "/" + HTTPS_CERT_FILE, new PollWebGuiAvailableTask(this, getWebGuiUrl(), new File(getFilesDir(), HTTPS_CERT_FILE),
mConfig.getApiKey(), result -> { mConfig.getApiKey(), result -> {
synchronized (stateLock) { synchronized (stateLock) {
if (mStopScheduled) { if (mStopScheduled) {