mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 21:29:54 +01:00
UI for setting and entering the password that encrypts the database key.
This commit is contained in:
@@ -30,7 +30,7 @@
|
|||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.SetupActivity"
|
android:name=".android.SetupActivity"
|
||||||
android:label="@string/app_name" >
|
android:label="@string/setup_title" >
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.SplashScreenActivity"
|
android:name=".android.SplashScreenActivity"
|
||||||
|
|||||||
@@ -3,6 +3,13 @@
|
|||||||
<string name="app_name">Briar</string>
|
<string name="app_name">Briar</string>
|
||||||
<string name="notification_title">Briar is running</string>
|
<string name="notification_title">Briar is running</string>
|
||||||
<string name="notification_text">Touch to quit.</string>
|
<string name="notification_text">Touch to quit.</string>
|
||||||
|
<string name="setup_title">Briar Setup</string>
|
||||||
|
<string name="choose_nickname">Choose your nickname:</string>
|
||||||
|
<string name="choose_password">Choose your password:</string>
|
||||||
|
<string name="confirm_password">Confirm your password:</string>
|
||||||
|
<string name="format_min_password">Password must be at least %1$d characters long.</string>
|
||||||
|
<string name="enter_password">Enter your password:</string>
|
||||||
|
<string name="try_again">Wrong password, try again</string>
|
||||||
<string name="contact_list_button">Contacts</string>
|
<string name="contact_list_button">Contacts</string>
|
||||||
<string name="messages_button">Messages</string>
|
<string name="messages_button">Messages</string>
|
||||||
<string name="groups_button">Groups</string>
|
<string name="groups_button">Groups</string>
|
||||||
@@ -29,14 +36,14 @@
|
|||||||
<string name="format_connecting_wifi">Connecting via %1$s\u2026</string>
|
<string name="format_connecting_wifi">Connecting via %1$s\u2026</string>
|
||||||
<string name="connecting_bluetooth">Connecting via Bluetooth\u2026</string>
|
<string name="connecting_bluetooth">Connecting via Bluetooth\u2026</string>
|
||||||
<string name="connection_failed">Connection failed</string>
|
<string name="connection_failed">Connection failed</string>
|
||||||
<string name="check_same_network">Please check that you are both using the same network.</string>
|
<string name="check_same_network">Please check that you are both using the same network</string>
|
||||||
<string name="try_again_button">Try again</string>
|
<string name="try_again_button">Try again</string>
|
||||||
<string name="connected_to_contact">Connected to contact</string>
|
<string name="connected_to_contact">Connected to contact</string>
|
||||||
<string name="your_confirmation_code">Your confirmation code is</string>
|
<string name="your_confirmation_code">Your confirmation code is</string>
|
||||||
<string name="enter_confirmation_code">Please enter your contact\'s confirmation code:</string>
|
<string name="enter_confirmation_code">Please enter your contact\'s confirmation code:</string>
|
||||||
<string name="waiting_for_contact">Waiting for contact\u2026</string>
|
<string name="waiting_for_contact">Waiting for contact\u2026</string>
|
||||||
<string name="codes_do_not_match">Codes do not match</string>
|
<string name="codes_do_not_match">Codes do not match</string>
|
||||||
<string name="interfering">This could mean that someone is trying to interfere with your connection.</string>
|
<string name="interfering">This could mean that someone is trying to interfere with your connection</string>
|
||||||
<string name="contact_added">Contact added</string>
|
<string name="contact_added">Contact added</string>
|
||||||
<string name="done_button">Done</string>
|
<string name="done_button">Done</string>
|
||||||
<string name="messages_title">Messages</string>
|
<string name="messages_title">Messages</string>
|
||||||
@@ -67,7 +74,6 @@
|
|||||||
<string name="new_blog_item">New blog\u2026</string>
|
<string name="new_blog_item">New blog\u2026</string>
|
||||||
<string name="create_nickname_item">New nickname\u2026</string>
|
<string name="create_nickname_item">New nickname\u2026</string>
|
||||||
<string name="create_identity_title">Create an Identity</string>
|
<string name="create_identity_title">Create an Identity</string>
|
||||||
<string name="choose_nickname">Choose your nickname:</string>
|
|
||||||
<string name="create_button">Create</string>
|
<string name="create_button">Create</string>
|
||||||
<string name="no_contacts">You don\'t have any contacts. Add a contact now?</string>
|
<string name="no_contacts">You don\'t have any contacts. Add a contact now?</string>
|
||||||
<string name="add_button">Add</string>
|
<string name="add_button">Add</string>
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
package net.sf.briar.android;
|
package net.sf.briar.android;
|
||||||
|
|
||||||
|
import static android.text.InputType.TYPE_CLASS_TEXT;
|
||||||
|
import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
|
||||||
import static android.view.Gravity.CENTER;
|
import static android.view.Gravity.CENTER;
|
||||||
|
import static android.view.Gravity.CENTER_HORIZONTAL;
|
||||||
|
import static android.view.View.GONE;
|
||||||
|
import static android.view.View.VISIBLE;
|
||||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
import static android.view.inputmethod.InputMethodManager.HIDE_IMPLICIT_ONLY;
|
||||||
|
import static android.widget.LinearLayout.VERTICAL;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
|
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
|
||||||
|
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP;
|
||||||
import static net.sf.briar.api.messaging.Rating.GOOD;
|
import static net.sf.briar.api.messaging.Rating.GOOD;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -22,20 +30,31 @@ import net.sf.briar.android.messages.ConversationListActivity;
|
|||||||
import net.sf.briar.api.LocalAuthor;
|
import net.sf.briar.api.LocalAuthor;
|
||||||
import net.sf.briar.api.android.DatabaseUiExecutor;
|
import net.sf.briar.api.android.DatabaseUiExecutor;
|
||||||
import net.sf.briar.api.android.ReferenceManager;
|
import net.sf.briar.api.android.ReferenceManager;
|
||||||
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
|
import net.sf.briar.api.crypto.CryptoExecutor;
|
||||||
import net.sf.briar.api.db.DatabaseComponent;
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
|
import net.sf.briar.api.db.DatabaseConfig;
|
||||||
import net.sf.briar.api.db.DbException;
|
import net.sf.briar.api.db.DbException;
|
||||||
|
import net.sf.briar.util.StringUtils;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.view.KeyEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.BaseAdapter;
|
import android.widget.BaseAdapter;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
import android.widget.GridView;
|
import android.widget.GridView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.TextView.OnEditorActionListener;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
@@ -48,10 +67,17 @@ public class HomeScreenActivity extends BriarActivity {
|
|||||||
new BriarServiceConnection();
|
new BriarServiceConnection();
|
||||||
|
|
||||||
@Inject private ReferenceManager referenceManager = null;
|
@Inject private ReferenceManager referenceManager = null;
|
||||||
|
@Inject private DatabaseConfig databaseConfig = null;
|
||||||
@Inject @DatabaseUiExecutor private Executor dbUiExecutor = null;
|
@Inject @DatabaseUiExecutor private Executor dbUiExecutor = null;
|
||||||
|
@Inject @CryptoExecutor private Executor cryptoExecutor = null;
|
||||||
|
private boolean bound = false;
|
||||||
|
private TextView tryAgain = null;
|
||||||
|
private Button continueButton = null;
|
||||||
|
private ProgressBar progress = null;
|
||||||
|
|
||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
@Inject private volatile DatabaseComponent db = null;
|
@Inject private volatile DatabaseComponent db = null;
|
||||||
|
@Inject private volatile CryptoComponent crypto = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
@@ -62,20 +88,23 @@ public class HomeScreenActivity extends BriarActivity {
|
|||||||
if(quit) {
|
if(quit) {
|
||||||
// The activity was launched from the notification bar
|
// The activity was launched from the notification bar
|
||||||
showSpinner();
|
showSpinner();
|
||||||
|
bindService();
|
||||||
quit();
|
quit();
|
||||||
} else if(handle != -1) {
|
} else if(handle != -1) {
|
||||||
// The activity was launched from the setup wizard
|
// The activity was launched from the setup wizard
|
||||||
showSpinner();
|
showSpinner();
|
||||||
|
startService(new Intent(BriarService.class.getName()));
|
||||||
|
bindService();
|
||||||
storeLocalAuthor(referenceManager.removeReference(handle,
|
storeLocalAuthor(referenceManager.removeReference(handle,
|
||||||
LocalAuthor.class));
|
LocalAuthor.class));
|
||||||
} else {
|
} else if(databaseConfig.getEncryptionKey() == null) {
|
||||||
// The activity was launched from the splash screen
|
// The activity was launched from the splash screen
|
||||||
|
showPasswordPrompt();
|
||||||
|
} else {
|
||||||
|
// The activity has been launched before
|
||||||
showButtons();
|
showButtons();
|
||||||
|
bindService();
|
||||||
}
|
}
|
||||||
// Start the service and bind to it
|
|
||||||
startService(new Intent(BriarService.class.getName()));
|
|
||||||
bindService(new Intent(BriarService.class.getName()),
|
|
||||||
serviceConnection, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showSpinner() {
|
private void showSpinner() {
|
||||||
@@ -88,6 +117,11 @@ public class HomeScreenActivity extends BriarActivity {
|
|||||||
setContentView(layout);
|
setContentView(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void bindService() {
|
||||||
|
bound = bindService(new Intent(BriarService.class.getName()),
|
||||||
|
serviceConnection, 0);
|
||||||
|
}
|
||||||
|
|
||||||
private void quit() {
|
private void quit() {
|
||||||
new Thread() {
|
new Thread() {
|
||||||
@Override
|
@Override
|
||||||
@@ -145,6 +179,110 @@ public class HomeScreenActivity extends BriarActivity {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showPasswordPrompt() {
|
||||||
|
SharedPreferences prefs = getSharedPreferences("db", MODE_PRIVATE);
|
||||||
|
String hex = prefs.getString("key", null);
|
||||||
|
if(hex == null) throw new IllegalStateException();
|
||||||
|
final byte[] encrypted = StringUtils.fromHexString(hex);
|
||||||
|
|
||||||
|
LinearLayout layout = new LinearLayout(this);
|
||||||
|
layout.setLayoutParams(MATCH_MATCH);
|
||||||
|
layout.setOrientation(VERTICAL);
|
||||||
|
layout.setGravity(CENTER_HORIZONTAL);
|
||||||
|
|
||||||
|
TextView enterPassword = new TextView(this);
|
||||||
|
enterPassword.setGravity(CENTER);
|
||||||
|
enterPassword.setTextSize(18);
|
||||||
|
enterPassword.setPadding(10, 10, 10, 10);
|
||||||
|
enterPassword.setText(R.string.enter_password);
|
||||||
|
layout.addView(enterPassword);
|
||||||
|
|
||||||
|
final EditText passwordEntry = new EditText(this);
|
||||||
|
passwordEntry.setMaxLines(1);
|
||||||
|
passwordEntry.setPadding(10, 0, 10, 10);
|
||||||
|
int inputType = TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD;
|
||||||
|
passwordEntry.setInputType(inputType);
|
||||||
|
passwordEntry.setOnEditorActionListener(new OnEditorActionListener() {
|
||||||
|
public boolean onEditorAction(TextView v, int action, KeyEvent e) {
|
||||||
|
validatePassword(encrypted, passwordEntry.getText());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
layout.addView(passwordEntry);
|
||||||
|
|
||||||
|
tryAgain = new TextView(this);
|
||||||
|
tryAgain.setGravity(CENTER);
|
||||||
|
tryAgain.setTextSize(14);
|
||||||
|
tryAgain.setPadding(10, 10, 10, 10);
|
||||||
|
tryAgain.setText(R.string.try_again);
|
||||||
|
tryAgain.setVisibility(GONE);
|
||||||
|
layout.addView(tryAgain);
|
||||||
|
|
||||||
|
continueButton = new Button(this);
|
||||||
|
continueButton.setLayoutParams(WRAP_WRAP);
|
||||||
|
continueButton.setText(R.string.continue_button);
|
||||||
|
continueButton.setOnClickListener(new OnClickListener() {
|
||||||
|
public void onClick(View v) {
|
||||||
|
validatePassword(encrypted, passwordEntry.getText());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
layout.addView(continueButton);
|
||||||
|
|
||||||
|
progress = new ProgressBar(this);
|
||||||
|
progress.setLayoutParams(WRAP_WRAP);
|
||||||
|
progress.setIndeterminate(true);
|
||||||
|
progress.setVisibility(GONE);
|
||||||
|
layout.addView(progress);
|
||||||
|
setContentView(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validatePassword(final byte[] encrypted, Editable e) {
|
||||||
|
if(tryAgain == null || continueButton == null || progress == null)
|
||||||
|
return;
|
||||||
|
// Hide the soft keyboard
|
||||||
|
Object o = getSystemService(INPUT_METHOD_SERVICE);
|
||||||
|
((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0);
|
||||||
|
// Replace the button with a progress bar
|
||||||
|
continueButton.setVisibility(GONE);
|
||||||
|
progress.setVisibility(VISIBLE);
|
||||||
|
// Decrypt the database key in a background thread
|
||||||
|
int length = e.length();
|
||||||
|
final char[] password = new char[length];
|
||||||
|
e.getChars(0, length, password, 0);
|
||||||
|
e.delete(0, length);
|
||||||
|
cryptoExecutor.execute(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
byte[] key = crypto.decryptWithPassword(encrypted, password);
|
||||||
|
if(key == null) {
|
||||||
|
tryAgain();
|
||||||
|
} else {
|
||||||
|
databaseConfig.setEncryptionKey(key);
|
||||||
|
showButtonsAndStartService();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryAgain() {
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
tryAgain.setVisibility(VISIBLE);
|
||||||
|
continueButton.setVisibility(VISIBLE);
|
||||||
|
progress.setVisibility(GONE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showButtonsAndStartService() {
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
showButtons();
|
||||||
|
startService(new Intent(BriarService.class.getName()));
|
||||||
|
bindService();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void showButtons() {
|
private void showButtons() {
|
||||||
ListView.LayoutParams matchMatch =
|
ListView.LayoutParams matchMatch =
|
||||||
new ListView.LayoutParams(MATCH_PARENT, MATCH_PARENT);
|
new ListView.LayoutParams(MATCH_PARENT, MATCH_PARENT);
|
||||||
@@ -227,6 +365,7 @@ public class HomeScreenActivity extends BriarActivity {
|
|||||||
quitButton.setText(R.string.quit_button);
|
quitButton.setText(R.string.quit_button);
|
||||||
quitButton.setOnClickListener(new OnClickListener() {
|
quitButton.setOnClickListener(new OnClickListener() {
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
|
showSpinner();
|
||||||
quit();
|
quit();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -264,6 +403,6 @@ public class HomeScreenActivity extends BriarActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
unbindService(serviceConnection);
|
if(bound) unbindService(serviceConnection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,18 @@ package net.sf.briar.android;
|
|||||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||||
import static android.text.InputType.TYPE_CLASS_TEXT;
|
import static android.text.InputType.TYPE_CLASS_TEXT;
|
||||||
import static android.text.InputType.TYPE_TEXT_FLAG_CAP_WORDS;
|
import static android.text.InputType.TYPE_TEXT_FLAG_CAP_WORDS;
|
||||||
|
import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
|
||||||
import static android.view.Gravity.CENTER;
|
import static android.view.Gravity.CENTER;
|
||||||
import static android.view.Gravity.CENTER_HORIZONTAL;
|
import static android.view.Gravity.CENTER_HORIZONTAL;
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static android.view.inputmethod.InputMethodManager.HIDE_IMPLICIT_ONLY;
|
|
||||||
import static android.widget.LinearLayout.VERTICAL;
|
import static android.widget.LinearLayout.VERTICAL;
|
||||||
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
|
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
|
||||||
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP;
|
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import net.sf.briar.R;
|
import net.sf.briar.R;
|
||||||
@@ -22,31 +23,36 @@ import net.sf.briar.api.LocalAuthor;
|
|||||||
import net.sf.briar.api.android.ReferenceManager;
|
import net.sf.briar.api.android.ReferenceManager;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.CryptoExecutor;
|
import net.sf.briar.api.crypto.CryptoExecutor;
|
||||||
|
import net.sf.briar.api.db.DatabaseConfig;
|
||||||
|
import net.sf.briar.util.StringUtils;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.SharedPreferences.Editor;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.KeyEvent;
|
import android.text.Editable;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.TextView.OnEditorActionListener;
|
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
public class SetupActivity extends BriarActivity
|
public class SetupActivity extends BriarActivity implements OnClickListener {
|
||||||
implements OnEditorActionListener, OnClickListener {
|
|
||||||
|
private static final int MIN_PASSWORD_LENGTH = 8;
|
||||||
|
|
||||||
@Inject @CryptoExecutor private Executor cryptoExecutor;
|
@Inject @CryptoExecutor private Executor cryptoExecutor;
|
||||||
private EditText nicknameEntry = null;
|
private EditText nicknameEntry = null;
|
||||||
private Button createButton = null;
|
private EditText passwordEntry = null, passwordConfirmation = null;
|
||||||
|
private Button continueButton = null;
|
||||||
private ProgressBar progress = null;
|
private ProgressBar progress = null;
|
||||||
|
|
||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
@Inject private volatile CryptoComponent crypto;
|
@Inject private volatile CryptoComponent crypto;
|
||||||
|
@Inject private volatile DatabaseConfig databaseConfig;
|
||||||
@Inject private volatile AuthorFactory authorFactory;
|
@Inject private volatile AuthorFactory authorFactory;
|
||||||
@Inject private volatile ReferenceManager referenceManager;
|
@Inject private volatile ReferenceManager referenceManager;
|
||||||
|
|
||||||
@@ -69,24 +75,66 @@ implements OnEditorActionListener, OnClickListener {
|
|||||||
@Override
|
@Override
|
||||||
protected void onTextChanged(CharSequence text, int start,
|
protected void onTextChanged(CharSequence text, int start,
|
||||||
int lengthBefore, int lengthAfter) {
|
int lengthBefore, int lengthAfter) {
|
||||||
if(createButton != null)
|
enableOrDisableContinueButton();
|
||||||
createButton.setEnabled(lengthAfter > 0);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
nicknameEntry.setTextSize(18);
|
|
||||||
nicknameEntry.setMaxLines(1);
|
nicknameEntry.setMaxLines(1);
|
||||||
nicknameEntry.setPadding(10, 10, 10, 10);
|
|
||||||
int inputType = TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_WORDS;
|
int inputType = TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_WORDS;
|
||||||
nicknameEntry.setInputType(inputType);
|
nicknameEntry.setInputType(inputType);
|
||||||
nicknameEntry.setOnEditorActionListener(this);
|
|
||||||
layout.addView(nicknameEntry);
|
layout.addView(nicknameEntry);
|
||||||
|
|
||||||
createButton = new Button(this);
|
TextView choosePassword = new TextView(this);
|
||||||
createButton.setLayoutParams(WRAP_WRAP);
|
choosePassword.setGravity(CENTER);
|
||||||
createButton.setText(R.string.create_button);
|
choosePassword.setTextSize(18);
|
||||||
createButton.setEnabled(false);
|
choosePassword.setPadding(10, 10, 10, 10);
|
||||||
createButton.setOnClickListener(this);
|
choosePassword.setText(R.string.choose_password);
|
||||||
layout.addView(createButton);
|
layout.addView(choosePassword);
|
||||||
|
|
||||||
|
passwordEntry = new EditText(this) {
|
||||||
|
@Override
|
||||||
|
protected void onTextChanged(CharSequence text, int start,
|
||||||
|
int lengthBefore, int lengthAfter) {
|
||||||
|
enableOrDisableContinueButton();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
passwordEntry.setMaxLines(1);
|
||||||
|
inputType = TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD;
|
||||||
|
passwordEntry.setInputType(inputType);
|
||||||
|
layout.addView(passwordEntry);
|
||||||
|
|
||||||
|
TextView confirmPassword = new TextView(this);
|
||||||
|
confirmPassword.setGravity(CENTER);
|
||||||
|
confirmPassword.setTextSize(18);
|
||||||
|
confirmPassword.setPadding(10, 10, 10, 10);
|
||||||
|
confirmPassword.setText(R.string.confirm_password);
|
||||||
|
layout.addView(confirmPassword);
|
||||||
|
|
||||||
|
passwordConfirmation = new EditText(this) {
|
||||||
|
@Override
|
||||||
|
protected void onTextChanged(CharSequence text, int start,
|
||||||
|
int lengthBefore, int lengthAfter) {
|
||||||
|
enableOrDisableContinueButton();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
passwordConfirmation.setMaxLines(1);
|
||||||
|
inputType = TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD;
|
||||||
|
passwordConfirmation.setInputType(inputType);
|
||||||
|
layout.addView(passwordConfirmation);
|
||||||
|
|
||||||
|
TextView minPasswordLength = new TextView(this);
|
||||||
|
minPasswordLength.setGravity(CENTER);
|
||||||
|
minPasswordLength.setTextSize(14);
|
||||||
|
minPasswordLength.setPadding(10, 10, 10, 10);
|
||||||
|
String format = getResources().getString(R.string.format_min_password);
|
||||||
|
minPasswordLength.setText(String.format(format, MIN_PASSWORD_LENGTH));
|
||||||
|
layout.addView(minPasswordLength);
|
||||||
|
|
||||||
|
continueButton = new Button(this);
|
||||||
|
continueButton.setLayoutParams(WRAP_WRAP);
|
||||||
|
continueButton.setText(R.string.continue_button);
|
||||||
|
continueButton.setEnabled(false);
|
||||||
|
continueButton.setOnClickListener(this);
|
||||||
|
layout.addView(continueButton);
|
||||||
|
|
||||||
progress = new ProgressBar(this);
|
progress = new ProgressBar(this);
|
||||||
progress.setLayoutParams(WRAP_WRAP);
|
progress.setLayoutParams(WRAP_WRAP);
|
||||||
@@ -97,20 +145,42 @@ implements OnEditorActionListener, OnClickListener {
|
|||||||
setContentView(layout);
|
setContentView(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) {
|
private void enableOrDisableContinueButton() {
|
||||||
validateNickname();
|
if(nicknameEntry == null || passwordEntry == null ||
|
||||||
return true;
|
passwordConfirmation == null || continueButton == null) return;
|
||||||
|
boolean nicknameNotEmpty = nicknameEntry.getText().length() > 0;
|
||||||
|
char[] firstPassword = getChars(passwordEntry.getText());
|
||||||
|
char[] secondPassword = getChars(passwordConfirmation.getText());
|
||||||
|
boolean passwordLength = firstPassword.length >= MIN_PASSWORD_LENGTH;
|
||||||
|
boolean passwordsMatch = Arrays.equals(firstPassword, secondPassword);
|
||||||
|
for(int i = 0; i < firstPassword.length; i++) firstPassword[i] = 0;
|
||||||
|
for(int i = 0; i < secondPassword.length; i++) secondPassword[i] = 0;
|
||||||
|
boolean valid = nicknameNotEmpty && passwordLength && passwordsMatch;
|
||||||
|
continueButton.setEnabled(valid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private char[] getChars(Editable e) {
|
||||||
|
int length = e.length();
|
||||||
|
char[] c = new char[length];
|
||||||
|
e.getChars(0, length, c, 0);
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if(!validateNickname()) return;
|
|
||||||
final String nickname = nicknameEntry.getText().toString();
|
final String nickname = nicknameEntry.getText().toString();
|
||||||
|
final char[] password = getChars(passwordEntry.getText());
|
||||||
|
delete(passwordEntry.getText());
|
||||||
|
delete(passwordConfirmation.getText());
|
||||||
// Replace the button with a progress bar
|
// Replace the button with a progress bar
|
||||||
createButton.setVisibility(GONE);
|
continueButton.setVisibility(GONE);
|
||||||
progress.setVisibility(VISIBLE);
|
progress.setVisibility(VISIBLE);
|
||||||
// Create the identity in a background thread
|
// Store the DB key and create the identity in a background thread
|
||||||
cryptoExecutor.execute(new Runnable() {
|
cryptoExecutor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
|
byte[] key = crypto.generateSecretKey().getEncoded();
|
||||||
|
byte[] encrypted = crypto.encryptWithPassword(key, password);
|
||||||
|
storeEncryptedDatabaseKey(encrypted);
|
||||||
|
databaseConfig.setEncryptionKey(key);
|
||||||
KeyPair keyPair = crypto.generateSignatureKeyPair();
|
KeyPair keyPair = crypto.generateSignatureKeyPair();
|
||||||
final byte[] publicKey = keyPair.getPublic().getEncoded();
|
final byte[] publicKey = keyPair.getPublic().getEncoded();
|
||||||
final byte[] privateKey = keyPair.getPrivate().getEncoded();
|
final byte[] privateKey = keyPair.getPrivate().getEncoded();
|
||||||
@@ -127,6 +197,17 @@ implements OnEditorActionListener, OnClickListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void delete(Editable e) {
|
||||||
|
e.delete(0, e.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void storeEncryptedDatabaseKey(byte[] encrypted) {
|
||||||
|
SharedPreferences prefs = getSharedPreferences("db", MODE_PRIVATE);
|
||||||
|
Editor editor = prefs.edit();
|
||||||
|
editor.putString("key", StringUtils.toHexString(encrypted));
|
||||||
|
editor.commit();
|
||||||
|
}
|
||||||
|
|
||||||
private void showHomeScreen(final long handle) {
|
private void showHomeScreen(final long handle) {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -139,12 +220,4 @@ implements OnEditorActionListener, OnClickListener {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean validateNickname() {
|
|
||||||
if(nicknameEntry.getText().toString().equals("")) return false;
|
|
||||||
// Hide the soft keyboard
|
|
||||||
Object o = getSystemService(INPUT_METHOD_SERVICE);
|
|
||||||
((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package net.sf.briar.android;
|
|||||||
|
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||||
import static android.view.Gravity.CENTER;
|
import static android.view.Gravity.CENTER;
|
||||||
import net.sf.briar.android.widgets.CommonLayoutParams;
|
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
|
||||||
import net.sf.briar.api.db.DatabaseConfig;
|
import net.sf.briar.api.db.DatabaseConfig;
|
||||||
import roboguice.RoboGuice;
|
import roboguice.RoboGuice;
|
||||||
import roboguice.activity.RoboSplashActivity;
|
import roboguice.activity.RoboSplashActivity;
|
||||||
@@ -24,7 +24,7 @@ public class SplashScreenActivity extends RoboSplashActivity {
|
|||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
super.onCreate(null);
|
super.onCreate(null);
|
||||||
LinearLayout layout = new LinearLayout(this);
|
LinearLayout layout = new LinearLayout(this);
|
||||||
layout.setLayoutParams(CommonLayoutParams.MATCH_MATCH);
|
layout.setLayoutParams(MATCH_MATCH);
|
||||||
layout.setGravity(CENTER);
|
layout.setGravity(CENTER);
|
||||||
ProgressBar spinner = new ProgressBar(this);
|
ProgressBar spinner = new ProgressBar(this);
|
||||||
spinner.setIndeterminate(true);
|
spinner.setIndeterminate(true);
|
||||||
|
|||||||
@@ -99,9 +99,8 @@ SelectContactsDialog.Listener {
|
|||||||
enableOrDisableCreateButton();
|
enableOrDisableCreateButton();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
nameEntry.setTextSize(18);
|
|
||||||
nameEntry.setMaxLines(1);
|
nameEntry.setMaxLines(1);
|
||||||
nameEntry.setPadding(10, 10, 10, 10);
|
nameEntry.setPadding(10, 0, 10, 10);
|
||||||
nameEntry.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_SENTENCES);
|
nameEntry.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_SENTENCES);
|
||||||
nameEntry.setOnEditorActionListener(this);
|
nameEntry.setOnEditorActionListener(this);
|
||||||
layout.addView(nameEntry);
|
layout.addView(nameEntry);
|
||||||
|
|||||||
@@ -94,9 +94,8 @@ SelectContactsDialog.Listener {
|
|||||||
enableOrDisableCreateButton();
|
enableOrDisableCreateButton();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
nameEntry.setTextSize(18);
|
|
||||||
nameEntry.setMaxLines(1);
|
nameEntry.setMaxLines(1);
|
||||||
nameEntry.setPadding(10, 10, 10, 10);
|
nameEntry.setPadding(10, 0, 10, 10);
|
||||||
nameEntry.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_SENTENCES);
|
nameEntry.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_SENTENCES);
|
||||||
nameEntry.setOnEditorActionListener(this);
|
nameEntry.setOnEditorActionListener(this);
|
||||||
layout.addView(nameEntry);
|
layout.addView(nameEntry);
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ public class HelloWorldModule extends AbstractModule {
|
|||||||
final File dir = app.getApplicationContext().getDir("db", MODE_PRIVATE);
|
final File dir = app.getApplicationContext().getDir("db", MODE_PRIVATE);
|
||||||
return new DatabaseConfig() {
|
return new DatabaseConfig() {
|
||||||
|
|
||||||
|
private volatile byte[] key = null;
|
||||||
|
|
||||||
public boolean databaseExists() {
|
public boolean databaseExists() {
|
||||||
return dir.isDirectory() && dir.listFiles().length > 0;
|
return dir.isDirectory() && dir.listFiles().length > 0;
|
||||||
}
|
}
|
||||||
@@ -43,8 +45,12 @@ public class HelloWorldModule extends AbstractModule {
|
|||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
public char[] getPassword() {
|
public void setEncryptionKey(byte[] key) {
|
||||||
return "foo bar".toCharArray();
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getEncryptionKey() {
|
||||||
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getMaxSize() {
|
public long getMaxSize() {
|
||||||
|
|||||||
@@ -85,12 +85,11 @@ implements OnEditorActionListener, OnClickListener {
|
|||||||
protected void onTextChanged(CharSequence text, int start,
|
protected void onTextChanged(CharSequence text, int start,
|
||||||
int lengthBefore, int lengthAfter) {
|
int lengthBefore, int lengthAfter) {
|
||||||
if(createButton != null)
|
if(createButton != null)
|
||||||
createButton.setEnabled(lengthAfter > 0);
|
createButton.setEnabled(getText().length() > 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
nicknameEntry.setTextSize(18);
|
|
||||||
nicknameEntry.setMaxLines(1);
|
nicknameEntry.setMaxLines(1);
|
||||||
nicknameEntry.setPadding(10, 10, 10, 10);
|
nicknameEntry.setPadding(10, 0, 10, 10);
|
||||||
int inputType = TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_WORDS;
|
int inputType = TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_WORDS;
|
||||||
nicknameEntry.setInputType(inputType);
|
nicknameEntry.setInputType(inputType);
|
||||||
nicknameEntry.setOnEditorActionListener(this);
|
nicknameEntry.setOnEditorActionListener(this);
|
||||||
|
|||||||
@@ -96,7 +96,6 @@ implements OnItemSelectedListener, OnClickListener {
|
|||||||
|
|
||||||
from = new TextView(this);
|
from = new TextView(this);
|
||||||
from.setTextSize(18);
|
from.setTextSize(18);
|
||||||
from.setMaxLines(1);
|
|
||||||
from.setPadding(10, 10, 10, 10);
|
from.setPadding(10, 10, 10, 10);
|
||||||
from.setText(R.string.from);
|
from.setText(R.string.from);
|
||||||
header.addView(from);
|
header.addView(from);
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ public interface DatabaseConfig {
|
|||||||
|
|
||||||
File getDatabaseDirectory();
|
File getDatabaseDirectory();
|
||||||
|
|
||||||
char[] getPassword();
|
void setEncryptionKey(byte[] key);
|
||||||
|
|
||||||
|
byte[] getEncryptionKey();
|
||||||
|
|
||||||
long getMaxSize();
|
long getMaxSize();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
private static final String STORAGE_CIPHER_ALGO = "AES/GCM/NoPadding";
|
private static final String STORAGE_CIPHER_ALGO = "AES/GCM/NoPadding";
|
||||||
private static final int STORAGE_IV_BYTES = 16; // 128 bits
|
private static final int STORAGE_IV_BYTES = 16; // 128 bits
|
||||||
private static final int PBKDF_SALT_BYTES = 16; // 128 bits
|
private static final int PBKDF_SALT_BYTES = 16; // 128 bits
|
||||||
private static final int PBKDF_ITERATIONS = 10 * 1000; // FIXME: How many?
|
private static final int PBKDF_ITERATIONS = 1000;
|
||||||
private static final String KEY_DERIVATION_ALGO = "AES/CTR/NoPadding";
|
private static final String KEY_DERIVATION_ALGO = "AES/CTR/NoPadding";
|
||||||
private static final int KEY_DERIVATION_IV_BYTES = 16; // 128 bits
|
private static final int KEY_DERIVATION_IV_BYTES = 16; // 128 bits
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import java.io.IOException;
|
|||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import net.sf.briar.api.clock.Clock;
|
import net.sf.briar.api.clock.Clock;
|
||||||
import net.sf.briar.api.db.DatabaseConfig;
|
import net.sf.briar.api.db.DatabaseConfig;
|
||||||
import net.sf.briar.api.db.DbException;
|
import net.sf.briar.api.db.DbException;
|
||||||
import net.sf.briar.util.FileUtils;
|
import net.sf.briar.util.FileUtils;
|
||||||
|
import net.sf.briar.util.StringUtils;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
@@ -23,23 +23,23 @@ class H2Database extends JdbcDatabase {
|
|||||||
private static final String COUNTER_TYPE = "INT NOT NULL AUTO_INCREMENT";
|
private static final String COUNTER_TYPE = "INT NOT NULL AUTO_INCREMENT";
|
||||||
private static final String SECRET_TYPE = "BINARY(32)";
|
private static final String SECRET_TYPE = "BINARY(32)";
|
||||||
|
|
||||||
private final File dir;
|
private final DatabaseConfig config;
|
||||||
private final String url;
|
private final String url;
|
||||||
private final char[] password;
|
|
||||||
private final long maxSize;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
H2Database(DatabaseConfig config, Clock clock) {
|
H2Database(DatabaseConfig config, Clock clock) {
|
||||||
super(HASH_TYPE, BINARY_TYPE, COUNTER_TYPE, SECRET_TYPE, config, clock);
|
super(HASH_TYPE, BINARY_TYPE, COUNTER_TYPE, SECRET_TYPE, clock);
|
||||||
dir = config.getDatabaseDirectory();
|
this.config = config;
|
||||||
url = "jdbc:h2:split:" + new File(dir, "db").getPath()
|
String path = new File(config.getDatabaseDirectory(), "db").getPath();
|
||||||
|
url = "jdbc:h2:split:" + path
|
||||||
+ ";CIPHER=AES;MULTI_THREADED=1;DB_CLOSE_ON_EXIT=false";
|
+ ";CIPHER=AES;MULTI_THREADED=1;DB_CLOSE_ON_EXIT=false";
|
||||||
password = config.getPassword();
|
|
||||||
maxSize = config.getMaxSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean open() throws DbException, IOException {
|
public boolean open() throws DbException, IOException {
|
||||||
return super.open("org.h2.Driver");
|
boolean reopen = config.databaseExists();
|
||||||
|
if(!reopen) config.getDatabaseDirectory().mkdirs();
|
||||||
|
super.open("org.h2.Driver", reopen);
|
||||||
|
return reopen;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() throws DbException {
|
public void close() throws DbException {
|
||||||
@@ -52,6 +52,8 @@ class H2Database extends JdbcDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getFreeSpace() throws DbException {
|
public long getFreeSpace() throws DbException {
|
||||||
|
File dir = config.getDatabaseDirectory();
|
||||||
|
long maxSize = config.getMaxSize();
|
||||||
try {
|
try {
|
||||||
long free = FileUtils.getFreeSpace(dir);
|
long free = FileUtils.getFreeSpace(dir);
|
||||||
long used = getDiskSpace(dir);
|
long used = getDiskSpace(dir);
|
||||||
@@ -73,14 +75,28 @@ class H2Database extends JdbcDatabase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Connection createConnection() throws SQLException {
|
protected Connection createConnection() throws SQLException {
|
||||||
char[] passwordCopy = password.clone();
|
char[] password = encodePassword(config.getEncryptionKey());
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.setProperty("user", "user");
|
props.setProperty("user", "user");
|
||||||
props.put("password", passwordCopy);
|
props.put("password", password);
|
||||||
try {
|
try {
|
||||||
return DriverManager.getConnection(url, props);
|
return DriverManager.getConnection(url, props);
|
||||||
} finally {
|
} finally {
|
||||||
Arrays.fill(passwordCopy, (char) 0);
|
for(int i = 0; i < password.length; i++) password[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private char[] encodePassword(byte[] key) {
|
||||||
|
// The database password is the hex-encoded key
|
||||||
|
char[] hex = StringUtils.toHexChars(key);
|
||||||
|
// Separate the database password from the user password with a space
|
||||||
|
char[] user = "password".toCharArray();
|
||||||
|
char[] combined = new char[hex.length + 1 + user.length];
|
||||||
|
System.arraycopy(hex, 0, combined, 0, hex.length);
|
||||||
|
combined[hex.length] = ' ';
|
||||||
|
System.arraycopy(user, 0, combined, hex.length + 1, user.length);
|
||||||
|
// Erase the hex-encoded key
|
||||||
|
for(int i = 0; i < hex.length; i++) hex[i] = 0;
|
||||||
|
return combined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import net.sf.briar.api.TransportConfig;
|
|||||||
import net.sf.briar.api.TransportId;
|
import net.sf.briar.api.TransportId;
|
||||||
import net.sf.briar.api.TransportProperties;
|
import net.sf.briar.api.TransportProperties;
|
||||||
import net.sf.briar.api.clock.Clock;
|
import net.sf.briar.api.clock.Clock;
|
||||||
import net.sf.briar.api.db.DatabaseConfig;
|
|
||||||
import net.sf.briar.api.db.DbClosedException;
|
import net.sf.briar.api.db.DbClosedException;
|
||||||
import net.sf.briar.api.db.DbException;
|
import net.sf.briar.api.db.DbException;
|
||||||
import net.sf.briar.api.db.GroupMessageHeader;
|
import net.sf.briar.api.db.GroupMessageHeader;
|
||||||
@@ -360,7 +359,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
// Different database libraries use different names for certain types
|
// Different database libraries use different names for certain types
|
||||||
private final String hashType, binaryType, counterType, secretType;
|
private final String hashType, binaryType, counterType, secretType;
|
||||||
private final DatabaseConfig config;
|
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
|
|
||||||
private final LinkedList<Connection> connections =
|
private final LinkedList<Connection> connections =
|
||||||
@@ -372,18 +370,16 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
protected abstract Connection createConnection() throws SQLException;
|
protected abstract Connection createConnection() throws SQLException;
|
||||||
|
|
||||||
JdbcDatabase(String hashType, String binaryType, String counterType,
|
JdbcDatabase(String hashType, String binaryType, String counterType,
|
||||||
String secretType, DatabaseConfig config, Clock clock) {
|
String secretType, Clock clock) {
|
||||||
this.hashType = hashType;
|
this.hashType = hashType;
|
||||||
this.binaryType = binaryType;
|
this.binaryType = binaryType;
|
||||||
this.counterType = counterType;
|
this.counterType = counterType;
|
||||||
this.secretType = secretType;
|
this.secretType = secretType;
|
||||||
this.config = config;
|
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean open(String driverClass) throws DbException, IOException {
|
protected void open(String driverClass, boolean reopen) throws DbException,
|
||||||
boolean reopen = config.databaseExists();
|
IOException {
|
||||||
if(!reopen) config.getDatabaseDirectory().mkdirs();
|
|
||||||
// Load the JDBC driver
|
// Load the JDBC driver
|
||||||
try {
|
try {
|
||||||
Class.forName(driverClass);
|
Class.forName(driverClass);
|
||||||
@@ -399,7 +395,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
abortTransaction(txn);
|
abortTransaction(txn);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
return reopen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createTables(Connection txn) throws DbException {
|
private void createTables(Connection txn) throws DbException {
|
||||||
|
|||||||
@@ -29,16 +29,19 @@ public class StringUtils {
|
|||||||
else return s;
|
else return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Converts the given byte array to a hex character array. */
|
||||||
|
public static char[] toHexChars(byte[] bytes) {
|
||||||
|
char[] hex = new char[bytes.length * 2];
|
||||||
|
for(int i = 0, j = 0; i < bytes.length; i++) {
|
||||||
|
hex[j++] = HEX[(bytes[i] >> 4) & 0xF];
|
||||||
|
hex[j++] = HEX[bytes[i] & 0xF];
|
||||||
|
}
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
/** Converts the given byte array to a hex string. */
|
/** Converts the given byte array to a hex string. */
|
||||||
public static String toHexString(byte[] bytes) {
|
public static String toHexString(byte[] bytes) {
|
||||||
StringBuilder s = new StringBuilder(bytes.length * 2);
|
return new String(toHexChars(bytes));
|
||||||
for(byte b : bytes) {
|
|
||||||
int high = (b >> 4) & 0xF;
|
|
||||||
s.append(HEX[high]);
|
|
||||||
int low = b & 0xF;
|
|
||||||
s.append(HEX[low]);
|
|
||||||
}
|
|
||||||
return s.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts the given hex string to a byte array. */
|
/** Converts the given hex string to a byte array. */
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ public class TestDatabaseConfig implements DatabaseConfig {
|
|||||||
|
|
||||||
private final File dir;
|
private final File dir;
|
||||||
private final long maxSize;
|
private final long maxSize;
|
||||||
|
private volatile byte[] key = new byte[] { 'f', 'o', 'o' };
|
||||||
|
|
||||||
public TestDatabaseConfig(File dir, long maxSize) {
|
public TestDatabaseConfig(File dir, long maxSize) {
|
||||||
this.dir = dir;
|
this.dir = dir;
|
||||||
@@ -22,8 +23,12 @@ public class TestDatabaseConfig implements DatabaseConfig {
|
|||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
public char[] getPassword() {
|
public void setEncryptionKey(byte[] key) {
|
||||||
return "foo bar".toCharArray();
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getEncryptionKey() {
|
||||||
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getMaxSize() {
|
public long getMaxSize() {
|
||||||
|
|||||||
Reference in New Issue
Block a user