Support creating databases.

This commit is contained in:
Brian Pellin
2009-10-02 23:25:20 -05:00
parent 589d16cdaa
commit 739fd2beb9
12 changed files with 350 additions and 82 deletions

View File

@@ -17,57 +17,42 @@
You should have received a copy of the GNU General Public License
along with KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="@+id/file_listtop"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="?android:attr/listSeparatorTextViewStyle"
android:text="Open recent database (click to open):"/>
<Button android:id="@+id/open"
android:text="Open"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_alignParentBottom="true"
android:width="100sp"/>
<Button android:id="@+id/create"
android:text="Create"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@id/open"
android:width="100sp"/>
<EditText android:id="@+id/file_filename"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:layout_above="@id/open"
android:text="/sdcard/keepass/keepass.kdb"/>
<TextView android:id="@+id/label_open_by_filename"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:orientation="vertical">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pass_filename"/>
<EditText android:id="@+id/file_filename"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="/sdcard/keepass/keepass.kdb"/>
<Button android:id="@+id/file_button"
android:text="Open"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:width="100sp"/>
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:tint="@color/blue_highlight"
android:src="@android:drawable/divider_horizontal_dark"/>
<TextView android:id="@+id/file_listtop"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Recently opened files:"/>
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="@android:drawable/divider_horizontal_dark"/>
</LinearLayout>
android:layout_above="@id/file_filename"
style="?android:attr/listSeparatorTextViewStyle"
android:text="Enter database filename:"/>
<ListView android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<TextView android:id="@android:id/empty"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="No files in history"
android:textSize="10sp"
android:textStyle="italic"/>
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="@android:drawable/divider_horizontal_dark"
android:layout_weight="0"/>
</LinearLayout>
android:layout_below="@id/file_listtop"
android:layout_above="@id/label_open_by_filename"/>
</RelativeLayout>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2009 Brian Pellin.
This file is part of KeePassDroid.
KeePassDroid is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
KeePassDroid is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="@+id/label_open_by_filename"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="?android:attr/listSeparatorTextViewStyle"
android:text="Enter database filename:"/>
<EditText android:id="@+id/file_filename"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:layout_below="@id/label_open_by_filename"
android:text="/sdcard/keepass/keepass.kdb"/>
<Button android:id="@+id/open"
android:text="Open"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_below="@id/file_filename"
android:width="100sp"/>
<Button android:id="@+id/create"
android:text="Create"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_below="@id/file_filename"
android:layout_toRightOf="@id/open"
android:width="100sp"/>
</RelativeLayout>

View File

@@ -72,6 +72,8 @@
<string name="add_entry">Add entry</string>
<string name="error_pass_match">Passwords do not match.</string>
<string name="error_title_required">A title is required.</string>
<string name="error_filename_required">A filename is required.</string>
<string name="error_file_not_create">Could not create file:</string>
<string name="menu_search">Search</string>
<string name="search_label">Search</string>
<string name="search_hint">Entry title/description</string>
@@ -98,4 +100,7 @@
<string name="saving_database">Saving database...</string>
<string name="loading_database">Loading database...</string>
<string name="progress_title">Working...</string>
<string name="progress_create">Creating new database...</string>
<string name="error_database_exists">This file already exists.</string>
<string name="password_title">Enter database password</string>
</resources>

View File

@@ -190,6 +190,10 @@ public class PasswordActivity extends Activity {
String fileName = getEditText(R.id.pass_filename);
// Clear before we load
KeePass.db.clear();
Handler handler = new Handler();
LoadDB task = new LoadDB(KeePass.db, PasswordActivity.this, fileName, pass, key, new AfterLoad(handler));
ProgressTask pt = new ProgressTask(PasswordActivity.this, task, R.string.loading_database);

View File

@@ -29,26 +29,41 @@ import android.widget.Toast;
import com.android.keepass.KeePass;
import com.android.keepass.R;
import com.keepassdroid.database.FileOnFinish;
import com.keepassdroid.database.OnFinish;
import com.keepassdroid.database.SetPassword;
public class SetPasswordDialog extends CancelDialog {
private byte[] masterKey;
private String mKeyfile;
private FileOnFinish mFinish;
public SetPasswordDialog(Context context) {
super(context);
}
public SetPasswordDialog(Context context, FileOnFinish finish) {
super(context);
mFinish = finish;
}
public byte[] getKey() {
return masterKey;
}
public String keyfile() {
return mKeyfile;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.set_password);
setTitle(R.string.password_title);
// Ok button
Button okButton = (Button) findViewById(R.id.ok);
okButton.setOnClickListener(new View.OnClickListener() {
@@ -69,6 +84,7 @@ public class SetPasswordDialog extends CancelDialog {
TextView keyfileView = (TextView) findViewById(R.id.pass_keyfile);
String keyfile = keyfileView.getText().toString();
mKeyfile = keyfile;
// Verify that a password or keyfile is set
if ( pass.length() == 0 && keyfile.length() == 0 ) {
@@ -77,7 +93,7 @@ public class SetPasswordDialog extends CancelDialog {
}
SetPassword sp = new SetPassword(KeePass.db, pass, keyfile, new AfterSave(new Handler()));
SetPassword sp = new SetPassword(KeePass.db, pass, keyfile, new AfterSave(mFinish, new Handler()));
ProgressTask pt = new ProgressTask(getContext(), sp, R.string.saving_database);
pt.run();
}
@@ -91,18 +107,27 @@ public class SetPasswordDialog extends CancelDialog {
@Override
public void onClick(View v) {
cancel();
if ( mFinish != null ) {
mFinish.run();
}
}
});
}
private class AfterSave extends OnFinish {
public AfterSave(Handler handler) {
super(handler);
private FileOnFinish mFinish;
public AfterSave(FileOnFinish finish, Handler handler) {
super(finish, handler);
mFinish = finish;
}
@Override
public void run() {
if ( mSuccess ) {
if ( mFinish != null ) {
mFinish.setFilename(mKeyfile);
}
dismiss();
} else {
displayMessage(getContext());

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2009 Brian Pellin.
*
* This file is part of KeePassDroid.
*
* KeePassDroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* KeePassDroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.database;
import org.phoneid.keepassj2me.PwDbHeader;
import org.phoneid.keepassj2me.PwManager;
import com.android.keepass.KeePass;
import com.keepassdroid.Database;
public class CreateDB extends RunnableOnFinish {
private final int DEFAULT_ENCRYPTION_ROUNDS = 300;
private String mFilename;
private boolean mDontSave;
public CreateDB(String filename, OnFinish finish, boolean dontSave) {
super(finish);
mFilename = filename;
mDontSave = dontSave;
}
@Override
public void run() {
// Create new database record
Database db = new Database();
KeePass.db = db;
// Create the PwManager
PwManager pm = new PwManager();
pm.algorithm = PwDbHeader.ALGO_AES;
pm.numKeyEncRounds = DEFAULT_ENCRYPTION_ROUNDS;
pm.name = "KeePass Password Manager";
// Build the root group
pm.constructTree(null);
// Set Database state
db.gRoot = pm.rootGroup;
db.mPM = pm;
db.mFilename = mFilename;
// Add a couple default groups
AddGroup internet = new AddGroup(db, "Internet", pm.rootGroup, null, true);
internet.run();
AddGroup email = new AddGroup(db, "eMail", pm.rootGroup, null, true);
email.run();
// Commit changes
SaveDB save = new SaveDB(db, mFinish, mDontSave);
mFinish = null;
save.run();
}
}

View File

@@ -0,0 +1,21 @@
package com.keepassdroid.database;
public class FileOnFinish extends OnFinish {
private String mFilename = "";
protected FileOnFinish mOnFinish;
public FileOnFinish(FileOnFinish finish) {
super(finish);
mOnFinish = finish;
}
public void setFilename(String filename) {
mFilename = filename;
}
public String getFilename() {
return mFilename;
}
}

View File

@@ -35,7 +35,9 @@ public class OnFinish implements Runnable {
protected OnFinish mOnFinish;
protected Handler mHandler;
public OnFinish() {
}
public OnFinish(Handler handler) {
mOnFinish = null;

View File

@@ -31,6 +31,7 @@ public class SetPassword extends RunnableOnFinish {
private String mPassword;
private String mKeyfile;
private Database mDb;
private boolean mDontSave;
public SetPassword(Database db, String password, String keyfile, OnFinish finish) {
super(finish);
@@ -38,6 +39,16 @@ public class SetPassword extends RunnableOnFinish {
mDb = db;
mPassword = password;
mKeyfile = keyfile;
mDontSave = false;
}
public SetPassword(Database db, String password, String keyfile, OnFinish finish, boolean dontSave) {
super(finish);
mDb = db;
mPassword = password;
mKeyfile = keyfile;
mDontSave = dontSave;
}
@Override
@@ -62,7 +73,7 @@ public class SetPassword extends RunnableOnFinish {
// Save Database
mFinish = new AfterSave(backupKey, mFinish);
SaveDB save = new SaveDB(mDb, mFinish);
SaveDB save = new SaveDB(mDb, mFinish, mDontSave);
save.run();
}

View File

@@ -206,4 +206,9 @@ public class FileDbHelper {
return cursor.getString(0);
}
public boolean hasRecentFiles() {
Cursor cursor = fetchAllFiles();
return cursor.getCount() > 0;
}
}

View File

@@ -19,9 +19,10 @@
*/
package com.keepassdroid.fileselect;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import android.app.Activity;
import android.app.ListActivity;
import android.content.Intent;
import android.database.Cursor;
@@ -36,8 +37,14 @@ import android.widget.Toast;
import com.android.keepass.R;
import com.keepassdroid.AboutDialog;
import com.keepassdroid.GroupActivity;
import com.keepassdroid.PasswordActivity;
import com.keepassdroid.ProgressTask;
import com.keepassdroid.SetPasswordDialog;
import com.keepassdroid.Util;
import com.keepassdroid.database.CreateDB;
import com.keepassdroid.database.FileOnFinish;
import com.keepassdroid.database.OnFinish;
import com.keepassdroid.intents.TimeoutIntents;
public class FileSelectActivity extends ListActivity {
@@ -49,18 +56,119 @@ public class FileSelectActivity extends ListActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.file_selection);
Button openButton = (Button) findViewById(R.id.file_button);
openButton.setOnClickListener(new ClickHandler(this));
mDbHelper = new FileDbHelper(this);
mDbHelper.open();
if ( mDbHelper.hasRecentFiles() ) {
setContentView(R.layout.file_selection);
} else {
setContentView(R.layout.file_selection_no_recent);
}
// Open button
Button openButton = (Button) findViewById(R.id.open);
openButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String fileName = Util.getEditText(FileSelectActivity.this, R.id.file_filename);
try {
PasswordActivity.Launch(FileSelectActivity.this, fileName);
} catch (FileNotFoundException e) {
Toast.makeText(FileSelectActivity.this, R.string.FileNotFound, Toast.LENGTH_LONG).show();
}
}
});
// Create button
Button createButton = (Button) findViewById(R.id.create);
createButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String filename = Util.getEditText(FileSelectActivity.this, R.id.file_filename);
// Make sure file name exists
if ( filename.length() == 0 ) {
Toast.makeText(FileSelectActivity.this, R.string.error_filename_required, Toast.LENGTH_LONG).show();
return;
}
// Try to create the file
File file = new File(filename);
try {
if ( file.exists() ) {
Toast.makeText(FileSelectActivity.this, R.string.error_database_exists, Toast.LENGTH_LONG).show();
return;
}
file.createNewFile();
} catch (IOException e) {
Toast.makeText(FileSelectActivity.this, getText(R.string.error_file_not_create) + " " + e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
return;
}
// Prep an object to collect a password once the database has been created
CollectPassword password = new CollectPassword(new LaunchGroupActivity(filename));
// Create the new database
CreateDB create = new CreateDB(filename, password, true);
ProgressTask createTask = new ProgressTask(FileSelectActivity.this, create, R.string.progress_create);
createTask.run();
}
});
fillData();
}
private class LaunchGroupActivity extends FileOnFinish {
private String mFilename;
public LaunchGroupActivity(String filename) {
super(null);
mFilename = filename;
}
@Override
public void run() {
if ( mSuccess ) {
// Add to recent files
FileDbHelper dbHelper = new FileDbHelper(FileSelectActivity.this);
dbHelper.open();
dbHelper.createFile(mFilename, getFilename());
dbHelper.close();
GroupActivity.Launch(FileSelectActivity.this, null, GroupActivity.ADD_GROUP_ONLY);
} else {
File file = new File(mFilename);
file.delete();
}
}
}
private class CollectPassword extends FileOnFinish {
public CollectPassword(FileOnFinish finish) {
super(finish);
}
@Override
public void run() {
SetPasswordDialog password = new SetPasswordDialog(FileSelectActivity.this, mOnFinish);
password.show();
}
}
private void fillData() {
// Get all of the rows from the database and create the item list
Cursor filesCursor = mDbHelper.fetchAllFiles();
@@ -118,26 +226,6 @@ public class FileSelectActivity extends ListActivity {
sendBroadcast(new Intent(TimeoutIntents.CANCEL));
}
private class ClickHandler implements View.OnClickListener {
Activity mAct;
ClickHandler(Activity act) {
mAct = act;
}
@Override
public void onClick(View v) {
String fileName = Util.getEditText(mAct, R.id.file_filename);
try {
PasswordActivity.Launch(mAct, fileName);
} catch (FileNotFoundException e) {
Toast.makeText(mAct, R.string.FileNotFound, Toast.LENGTH_LONG).show();
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {

View File

@@ -71,7 +71,7 @@ public class PwManager {
// Master key used to encrypt the whole database
public byte masterKey[] = new byte[32];
// Algorithm used to encrypt the database
int algorithm;
public int algorithm;
public int numKeyEncRounds;
// Debugging entries
@@ -80,7 +80,7 @@ public class PwManager {
public byte[] finalKey;
// root group
PwGroup rootGroup;
public PwGroup rootGroup;
public int getAlgorithm() {
return algorithm;