Skip to content

Commit

Permalink
improved ssl check
Browse files Browse the repository at this point in the history
  • Loading branch information
lins05 committed Apr 1, 2014
1 parent 4c6b4b8 commit d9bd72b
Show file tree
Hide file tree
Showing 15 changed files with 812 additions and 279 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
*~
*#
bin
gen
local.properties
Expand Down
23 changes: 23 additions & 0 deletions res/layout/dialog_ssl_confirm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >

<TextView
android:id="@+id/message"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:textColor="@color/black"
android:textSize="18dp" />

<CheckBox
android:id="@+id/remember_choice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:text="@string/remember_my_choice" />

</LinearLayout>
6 changes: 6 additions & 0 deletions res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,10 @@
<string name="n_upload_files_selected">%d file(s) selected</string>
<string name="empty_folder">Empty folder</string>
<string name="choose_file">Choose a file</string>
<string name="ssl_error">SSL check failed</string>
<string name="ssl_confirm">The ssl certificate of %s is not trusted. Do you want to continue?</string>
<string name="ssl_confirm_title">Untrusted Connection</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="remember_my_choice">Remember my choice</string>
</resources>
35 changes: 30 additions & 5 deletions src/com/seafile/seadroid2/AccountDetailActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import com.seafile.seadroid2.account.Account;
import com.seafile.seadroid2.account.AccountManager;
import com.seafile.seadroid2.ui.SslConfirmDialog;


public class AccountDetailActivity extends FragmentActivity {
Expand Down Expand Up @@ -225,8 +226,32 @@ protected String doInBackground(Void... params) {
return doLogin();
}

private void resend() {
ConcurrentAsyncTask.execute(new LoginTask(loginAccount));
}

@Override
protected void onPostExecute(String result) {
protected void onPostExecute(final String result) {
if (err == SeafException.sslException) {
SslConfirmDialog dialog = new SslConfirmDialog(loginAccount,
new SslConfirmDialog.Listener() {
@Override
public void onAccepted(boolean rememberChoice) {
CertsManager.instance().saveCertForAccount(loginAccount, rememberChoice);
resend();
}

@Override
public void onRejected() {
Log.d("SeafileHTTPS", "the user rejectes the ssl certificate");
statusView.setText(result);
loginButton.setEnabled(true);
}
});
dialog.show(getSupportFragmentManager(), SslConfirmDialog.FRAGMENT_TAG);
return;
}

if (result != null && result.equals("Success")) {
if (isFromEdit) {
accountManager.updateAccount(account, loginAccount);
Expand All @@ -236,10 +261,7 @@ protected void onPostExecute(String result) {
}
startFilesActivity(loginAccount);
} else {
if (err != null && err == SeafException.sslException) {
statusView.setText("SSL Error or Certification Error. You may try again.");
} else
statusView.setText(result);
statusView.setText(result);
}
loginButton.setEnabled(true);
}
Expand All @@ -253,6 +275,9 @@ private String doLogin() {
return "Success";
} catch (SeafException e) {
err = e;
if (e == SeafException.sslException) {
return getString(R.string.ssl_error);
}
switch (e.getCode()) {
case 400:
return getString(R.string.err_wrong_user_or_passwd);
Expand Down
18 changes: 16 additions & 2 deletions src/com/seafile/seadroid2/BrowserActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@
import com.seafile.seadroid2.fileschooser.MultiFileChooserActivity;
import com.seafile.seadroid2.gallery.MultipleImageSelectionActivity;
import com.seafile.seadroid2.monitor.FileMonitorService;
import com.seafile.seadroid2.transfer.TransferService;
import com.seafile.seadroid2.transfer.TransferManager.DownloadTaskInfo;
import com.seafile.seadroid2.transfer.TransferManager.UploadTaskInfo;
import com.seafile.seadroid2.transfer.TransferService;
import com.seafile.seadroid2.transfer.TransferService.TransferBinder;
import com.seafile.seadroid2.ui.AppChoiceDialog;
import com.seafile.seadroid2.ui.AppChoiceDialog.CustomAction;
Expand All @@ -71,6 +71,7 @@
import com.seafile.seadroid2.ui.PasswordDialog;
import com.seafile.seadroid2.ui.RenameFileDialog;
import com.seafile.seadroid2.ui.ReposFragment;
import com.seafile.seadroid2.ui.SslConfirmDialog;
import com.seafile.seadroid2.ui.StarredFragment;
import com.seafile.seadroid2.ui.TabsFragment;
import com.seafile.seadroid2.ui.TaskDialog;
Expand Down Expand Up @@ -230,6 +231,7 @@ protected void onCreate(Bundle savedInstanceState) {
unsetRefreshing();

if (savedInstanceState != null) {
Log.d(DEBUG_TAG, "savedInstanceState is not null");
tabsFragment = (TabsFragment)
getSupportFragmentManager().findFragmentByTag(TABS_FRAGMENT_TAG);
uploadTasksFragment = (UploadTasksFragment)
Expand All @@ -247,6 +249,18 @@ protected void onCreate(Bundle savedInstanceState) {
ft.commit();
}

SslConfirmDialog sslConfirmDlg = (SslConfirmDialog)
getSupportFragmentManager().findFragmentByTag(SslConfirmDialog.FRAGMENT_TAG);

if (sslConfirmDlg != null) {
Log.d(DEBUG_TAG, "sslConfirmDlg is not null");
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.detach(sslConfirmDlg);
ft.commit();
} else {
Log.d(DEBUG_TAG, "sslConfirmDlg is null");
}

String repoID = savedInstanceState.getString("repoID");
String repoName = savedInstanceState.getString("repoName");
String path = savedInstanceState.getString("path");
Expand All @@ -257,6 +271,7 @@ protected void onCreate(Bundle savedInstanceState) {
navContext.setDir(path, dirID);
}
} else {
Log.d(DEBUG_TAG, "savedInstanceState is null");
tabsFragment = new TabsFragment();
uploadTasksFragment = new UploadTasksFragment();
getSupportFragmentManager().beginTransaction().add(R.id.content_frame, tabsFragment, TABS_FRAGMENT_TAG).commit();
Expand Down Expand Up @@ -371,7 +386,6 @@ public void onStart() {
mTransferReceiver = new TransferReceiver();
}


IntentFilter filter = new IntentFilter(TransferService.BROADCAST_ACTION);
LocalBroadcastManager.getInstance(this).registerReceiver(mTransferReceiver, filter);

Expand Down
199 changes: 199 additions & 0 deletions src/com/seafile/seadroid2/CertsManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
package com.seafile.seadroid2;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Map;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Base64;
import android.util.Log;

import com.google.common.collect.Maps;
import com.seafile.seadroid2.account.Account;

/**
* Save the ssl certificates the user has confirmed to trust
*/
public class CertsManager {

private static final String DEBUG_TAG = "CertsManager";

private DBHelper db = DBHelper.getDatabaseHelper();

private static CertsManager instance;

private static Map<Account, X509Certificate> cachedCerts = Maps.newHashMap();

public static synchronized CertsManager instance() {
if (instance == null) {
instance = new CertsManager();
}

return instance;
}

public void saveCertForAccount(Account account, boolean rememberChoice) {
List<X509Certificate> certs = SSLTrustManager.instance().getCertsChainForAccount(account);
if (certs == null || certs.size() == 0) {
return;
}

X509Certificate cert = certs.get(0);
cachedCerts.put(account, cert);

if (rememberChoice) {
db.saveCertificate(account.server, cert);
}

Log.d(DEBUG_TAG, "saved cert for account " + account);
}

X509Certificate getCertificate(Account account) {
X509Certificate cert = cachedCerts.get(account);
if (cert != null) {
return cert;
}
return db.getCertificate(account.server);
}

static class DBHelper extends SQLiteOpenHelper {
// If you change the database schema, you must increment the database version.
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "certs.db";

private static final String TABLE_NAME = "Certs";

private static final String COLUMN_URL = "url";
private static final String COLUMN_CERT = "cert";

private static final String CREATE_TABLE_SQL = "CREATE TABLE " + TABLE_NAME + " ("
+ COLUMN_URL + " VARCHAR(255) PRIMARY KEY, " + COLUMN_CERT + " TEXT " + ")";

private static DBHelper dbHelper = null;
private SQLiteDatabase database = null;

public static DBHelper getDatabaseHelper() {
if (dbHelper != null)
return dbHelper;
dbHelper = new DBHelper(SeadroidApplication.getAppContext());
dbHelper.database = dbHelper.getWritableDatabase();
return dbHelper;
}

public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_SQL);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}

@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {}

public X509Certificate getCertificate(String url) {
String[] projection = {COLUMN_CERT};

Cursor c = database.query(TABLE_NAME,
projection,
"url=?",
new String[] {url},
null, // don't group the rows
null, // don't filter by row groups
null); // The sort order

if (c.moveToFirst() == false) {
c.close();
return null;
}

X509Certificate cert = cursorToCert(c);

c.close();
return cert;
}

private X509Certificate cursorToCert(Cursor cursor) {
X509Certificate cert = null;
String text = cursor.getString(0);

ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
byte[] data = null;

data = Base64.decode(text, Base64.DEFAULT);

try {
bis = new ByteArrayInputStream(data);
ois = new ObjectInputStream(bis);
cert = (X509Certificate) ois.readObject();
return cert;
} catch (ClassNotFoundException e) {
return null;
} catch (IOException e) {
return null;
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
}
}

if (ois != null) {
try {
ois.close();
} catch (IOException e) {
}
}
}
}

public void saveCertificate(String url, X509Certificate cert) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = null;
String text = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(cert);
byte[] data = bos.toByteArray();
text = Base64.encodeToString(data, Base64.DEFAULT);
} catch (IOException e) {
return;
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException ex) {
// ignore close exception
}
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
}

ContentValues values = new ContentValues();
values.put(COLUMN_URL, url);
values.put(COLUMN_CERT, text);

database.replace(TABLE_NAME, null, values);
}
}
}
Loading

0 comments on commit d9bd72b

Please sign in to comment.