UI and backend refactoring to support both database versions.

This commit is contained in:
Brian Pellin
2010-05-20 23:19:48 -05:00
parent a363dd677b
commit d78f900fcd
52 changed files with 1382 additions and 339 deletions

View File

@@ -29,7 +29,7 @@
<data android:pathPattern=".*\\.kdb" />
</intent-filter>
</activity>
<activity android:name="com.keepassdroid.GroupActivity" android:configChanges="orientation|keyboardHidden">
<activity android:name="com.keepassdroid.GroupActivityV3" android:configChanges="orientation|keyboardHidden">
<!-- This metadata entry causes .app.SearchQueryResults to be the default context -->
<!-- whenever the user invokes search while in this Activity. -->
<meta-data android:name="android.app.default_searchable"

Binary file not shown.

View File

@@ -68,7 +68,8 @@ jint Java_com_keepassdroid_crypto_NativeAESCipherSpi_nativeUpdate(JNIEnv *env,
jint inputLen, jbyteArray output, jint outputOffset, jint outputSize) {
LOGD("InputSize: %d; OutputSize: %d", inputLen, outputSize);
LOGD("InputSize: %d; InputOffset: %d, OutputOffset: %d, OutputSize: %d", inputLen, inputOffset,
outputOffset, outputSize);
if ( inputLen == 0 ) {
return 0;
}
@@ -98,7 +99,7 @@ jint Java_com_keepassdroid_crypto_NativeAESCipherSpi_nativeUpdate(JNIEnv *env,
}
*/
LOGD("PreOut: OutLen=%d", outLen);
LOGD("PreOut: outputSize=%d, outputOffset=%d, OutLen=%d", outputSize, outputOffset, outLen);
(*env)->SetByteArrayRegion(env, output, outputOffset, outLen, c_output);
free(c_output);

View File

@@ -73,6 +73,7 @@
<string name="error_nopass">A password or a keyfile is required.</string>
<string name="error_pass_match">Passwords do not match.</string>
<string name="error_rounds_not_number">Rounds must be a number.</string>
<string name="error_rounds_too_large">Rounds too big. Setting to 2147483648.</string>
<string name="error_title_required">A title is required.</string>
<string name="FileNotFound">File not found.</string>
<string name="group">Group</string>

View File

@@ -34,8 +34,10 @@ import java.util.Vector;
import android.content.Context;
import android.os.Debug;
import com.keepassdroid.database.PwDatabaseV3;
import com.keepassdroid.database.PwEntryV3;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.PwGroupId;
import com.keepassdroid.database.PwGroupV3;
import com.keepassdroid.database.exception.InvalidDBSignatureException;
import com.keepassdroid.database.exception.InvalidDBVersionException;
@@ -46,7 +48,7 @@ import com.keepassdroid.database.exception.PwDbOutputException;
import com.keepassdroid.database.load.Importer;
import com.keepassdroid.database.load.ImporterFactory;
import com.keepassdroid.database.load.ImporterV3;
import com.keepassdroid.database.save.PwDbV3Output;
import com.keepassdroid.database.save.PwDbOutput;
import com.keepassdroid.search.SearchDbHelper;
import com.keepassdroid.utils.Types;
@@ -54,11 +56,11 @@ import com.keepassdroid.utils.Types;
* @author bpellin
*/
public class Database {
public HashMap<Integer, WeakReference<PwGroupV3>> groups = new HashMap<Integer, WeakReference<PwGroupV3>>();
public HashMap<UUID, WeakReference<PwEntryV3>> entries = new HashMap<UUID, WeakReference<PwEntryV3>>();
public HashMap<PwGroupV3, WeakReference<PwGroupV3>> dirty = new HashMap<PwGroupV3, WeakReference<PwGroupV3>>();
public PwGroupV3 root;
public PwDatabaseV3 pm;
public HashMap<PwGroupId, WeakReference<PwGroup>> groups = new HashMap<PwGroupId, WeakReference<PwGroup>>();
public HashMap<UUID, WeakReference<PwEntry>> entries = new HashMap<UUID, WeakReference<PwEntry>>();
public HashMap<PwGroup, WeakReference<PwGroup>> dirty = new HashMap<PwGroup, WeakReference<PwGroup>>();
public PwGroup root;
public PwDatabase pm;
public String mFilename;
public SearchDbHelper searchHelper;
public boolean indexBuilt = false;
@@ -119,7 +121,6 @@ public class Database {
pm = Importer.openDatabase(bis, password, keyfile, status);
if ( pm != null ) {
pm.constructTree(null);
populateGlobals(null);
}
@@ -138,7 +139,7 @@ public class Database {
initSearch();
searchHelper.open();
searchHelper.insertEntry(pm.entries);
searchHelper.insertEntry(pm.getEntries());
/*for ( int i = 0; i < pm.entries.size(); i++) {
PwEntryV3 entry = pm.entries.get(i);
if ( ! entry.isMetaStream() ) {
@@ -170,7 +171,7 @@ public class Database {
//BufferedOutputStream bos = new BufferedOutputStream(fos);
//PwDbV3Output pmo = new PwDbV3Output(pm, bos, App.getCalendar());
PwDbV3Output pmo = new PwDbV3Output(pm, fos);
PwDbOutput pmo = PwDbOutput.getInstance(pm, fos);
pmo.output();
//bos.flush();
//bos.close();
@@ -187,30 +188,30 @@ public class Database {
}
private void populateGlobals(PwGroupV3 currentGroup) {
private void populateGlobals(PwGroup currentGroup) {
if (currentGroup == null) {
Vector<PwGroupV3> rootChildGroups = pm.getGrpRoots();
Vector<? extends PwGroup> rootChildGroups = pm.getGrpRoots();
for (int i = 0; i < rootChildGroups.size(); i++ ){
PwGroupV3 cur = rootChildGroups.elementAt(i);
root = cur.parent;
groups.put(cur.groupId, new WeakReference<PwGroupV3>(cur));
PwGroup cur = rootChildGroups.elementAt(i);
root = cur.getParent();
groups.put(cur.getId(), new WeakReference<PwGroup>(cur));
populateGlobals(cur);
}
return;
}
Vector<PwGroupV3> childGroups = currentGroup.childGroups;
Vector<PwEntryV3> childEntries = currentGroup.childEntries;
Vector<PwGroup> childGroups = currentGroup.childGroups;
Vector<PwEntry> childEntries = currentGroup.childEntries;
for (int i = 0; i < childEntries.size(); i++ ) {
PwEntryV3 cur = childEntries.elementAt(i);
entries.put(Types.bytestoUUID(cur.uuid), new WeakReference<PwEntryV3>(cur));
PwEntry cur = childEntries.elementAt(i);
entries.put(Types.bytestoUUID(cur.uuid), new WeakReference<PwEntry>(cur));
}
for (int i = 0; i < childGroups.size(); i++ ) {
PwGroupV3 cur = childGroups.elementAt(i);
groups.put(cur.groupId, new WeakReference<PwGroupV3>(cur));
PwGroup cur = childGroups.elementAt(i);
groups.put(cur.getId(), new WeakReference<PwGroup>(cur));
populateGlobals(cur);
}
}

View File

@@ -20,12 +20,11 @@
package com.keepassdroid;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
@@ -51,7 +50,7 @@ import android.widget.Toast;
import com.android.keepass.KeePass;
import com.android.keepass.R;
import com.keepassdroid.app.App;
import com.keepassdroid.database.PwDate;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.PwEntryV3;
import com.keepassdroid.intents.Intents;
import com.keepassdroid.utils.Types;
@@ -75,7 +74,7 @@ public class EntryActivity extends LockCloseActivity {
private static final int COL_LABEL = 0;
private static final int COL_DATA = 1;
public static void Launch(Activity act, PwEntryV3 pw, int pos) {
public static void Launch(Activity act, PwEntry pw, int pos) {
Intent i = new Intent(act, EntryActivity.class);
i.putExtra(KEY_ENTRY, pw.uuid);
@@ -84,7 +83,7 @@ public class EntryActivity extends LockCloseActivity {
act.startActivityForResult(i,0);
}
private PwEntryV3 mEntry;
private PwEntry mEntry;
private Timer mTimer = new Timer();
private boolean mShowPassword;
private int mPos;
@@ -113,8 +112,7 @@ public class EntryActivity extends LockCloseActivity {
mEntry = db.entries.get(uuid).get();
// Update last access time.
Calendar cal = Calendar.getInstance();
mEntry.tLastAccess = new PwDate(cal.getTime());
mEntry.stampLastAccess();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
mShowPassword = ! prefs.getBoolean(getString(R.string.maskpass_key), getResources().getBoolean(R.bool.maskpass_default));
@@ -152,9 +150,9 @@ public class EntryActivity extends LockCloseActivity {
String action = intent.getAction();
if ( action.equals(Intents.COPY_USERNAME) ) {
String username = mEntry.username;
String username = mEntry.getUsername();
if ( username.length() > 0 ) {
timeoutCopyToClipboard(mEntry.username);
timeoutCopyToClipboard(username);
}
} else if ( action.equals(Intents.COPY_PASSWORD) ) {
String password = new String(mEntry.getPassword());
@@ -199,20 +197,21 @@ public class EntryActivity extends LockCloseActivity {
private void fillData() {
populateText(R.id.entry_title, mEntry.title);
populateText(R.id.entry_user_name, mEntry.username);
populateText(R.id.entry_user_name, mEntry.getUsername());
populateText(R.id.entry_url, mEntry.url);
populateText(R.id.entry_password, new String(mEntry.getPassword()));
populateText(R.id.entry_password, mEntry.getPassword());
setPasswordStyle();
DateFormat df = DateFormat.getInstance();
populateText(R.id.entry_created, df.format(mEntry.tCreation.getJDate()));
populateText(R.id.entry_modified, df.format(mEntry.tLastMod.getJDate()));
populateText(R.id.entry_accessed, df.format(mEntry.tLastAccess.getJDate()));
populateText(R.id.entry_created, df.format(mEntry.getCreate()));
populateText(R.id.entry_modified, df.format(mEntry.getMod()));
populateText(R.id.entry_accessed, df.format(mEntry.getAccess()));
if ( PwEntryV3.IsNever(mEntry.tExpire.getJDate()) ) {
Date expires = mEntry.getExpire();
if ( PwEntryV3.IsNever(expires) ) {
populateText(R.id.entry_expires, R.string.never);
} else {
populateText(R.id.entry_expires, df.format(mEntry.tExpire.getJDate()));
populateText(R.id.entry_expires, df.format(expires));
}
populateText(R.id.entry_comment, mEntry.additional);
@@ -317,7 +316,7 @@ public class EntryActivity extends LockCloseActivity {
return true;
case MENU_COPY_USER:
timeoutCopyToClipboard(mEntry.username);
timeoutCopyToClipboard(mEntry.getUsername());
return true;
case MENU_COPY_PASS:

View File

@@ -24,7 +24,6 @@ import java.util.Calendar;
import java.util.Date;
import java.util.UUID;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
@@ -42,7 +41,9 @@ import com.android.keepass.KeePass;
import com.android.keepass.R;
import com.keepassdroid.app.App;
import com.keepassdroid.database.PwDate;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.PwEntryV3;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.PwGroupV3;
import com.keepassdroid.database.edit.AddEntry;
import com.keepassdroid.database.edit.OnFinish;
@@ -62,7 +63,11 @@ public class EntryEditActivity extends LockCloseActivity {
private boolean mShowPassword = false;
private boolean mIsNew;
public static void Launch(Activity act, PwEntryV3 pw) {
public static void Launch(Activity act, PwEntry pw) {
if ( !(pw instanceof PwEntryV3) ) {
throw new RuntimeException("Not yet implemented.");
}
Intent i = new Intent(act, EntryEditActivity.class);
i.putExtra(KEY_ENTRY, pw.uuid);
@@ -70,9 +75,14 @@ public class EntryEditActivity extends LockCloseActivity {
act.startActivityForResult(i, 0);
}
public static void Launch(Activity act, PwGroupV3 parent) {
public static void Launch(Activity act, PwGroup pw) {
if ( !(pw instanceof PwGroupV3) ) {
throw new RuntimeException("Not yet implemented.");
}
Intent i = new Intent(act, EntryEditActivity.class);
PwGroupV3 parent = (PwGroupV3) pw;
i.putExtra(KEY_PARENT, parent.groupId);
act.startActivityForResult(i, 0);
@@ -105,7 +115,7 @@ public class EntryEditActivity extends LockCloseActivity {
UUID uuid = Types.bytestoUUID(uuidBytes);
assert(uuid != null);
mEntry = db.entries.get(uuid).get();
mEntry = (PwEntryV3) db.entries.get(uuid).get();
mIsNew = false;
fillData();
@@ -179,7 +189,7 @@ public class EntryEditActivity extends LockCloseActivity {
OnFinish onFinish = act.new AfterSave(new Handler());
if ( mIsNew ) {
task = new AddEntry(App.getDB(), newEntry, onFinish);
task = AddEntry.getInstance(App.getDB(), newEntry, onFinish);
} else {
task = new UpdateEntry(App.getDB(), mEntry, newEntry, onFinish);
}
@@ -259,7 +269,7 @@ public class EntryEditActivity extends LockCloseActivity {
private void fillData() {
populateText(R.id.entry_title, mEntry.title);
populateText(R.id.entry_user_name, mEntry.username);
populateText(R.id.entry_user_name, mEntry.getUsername());
populateText(R.id.entry_url, mEntry.url);
String password = new String(mEntry.getPassword());

View File

@@ -21,7 +21,6 @@ package com.keepassdroid;
import java.lang.ref.WeakReference;
import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
@@ -39,10 +38,15 @@ import android.widget.AdapterView.AdapterContextMenuInfo;
import com.android.keepass.KeePass;
import com.android.keepass.R;
import com.keepassdroid.app.App;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.PwDatabaseV3;
import com.keepassdroid.database.PwDatabaseV4;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.PwGroupId;
import com.keepassdroid.database.PwGroupV3;
import com.keepassdroid.database.edit.AddGroup;
public class GroupActivity extends GroupBaseActivity {
public abstract class GroupActivity extends GroupBaseActivity {
public static final int UNINIT = -1;
public static final int VIEW_ONLY = 0;
@@ -50,11 +54,22 @@ public class GroupActivity extends GroupBaseActivity {
public static final int FULL = 2;
private static final String TAG = "Group Activity:";
public static void Launch(Activity act, PwGroupV3 group, int mode) {
Intent i = new Intent(act, GroupActivity.class);
public static void Launch(Activity act, PwGroup group, int mode) {
Intent i;
PwDatabase pm = App.getDB().pm;
if ( pm instanceof PwDatabaseV3 ) {
i = new Intent(act, GroupActivityV3.class);
if ( group != null ) {
i.putExtra(KEY_ENTRY, group.groupId);
PwGroupV3 g = (PwGroupV3) group;
i.putExtra(KEY_ENTRY, g.groupId);
}
} else if ( pm instanceof PwDatabaseV4 ) {
throw new RuntimeException("Not yet implemented.");
} else {
assert(true); // Should never be reached
throw new RuntimeException("Should never be reached.");
}
i.putExtra(KEY_MODE, mode);
@@ -62,6 +77,9 @@ public class GroupActivity extends GroupBaseActivity {
act.startActivityForResult(i,0);
}
protected abstract PwGroupId retrieveGroupId(Intent i);
protected abstract PwGroup getGroup();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -89,13 +107,13 @@ public class GroupActivity extends GroupBaseActivity {
}
Log.w(TAG, "Set view");
int id = intent.getIntExtra(KEY_ENTRY, -1);
PwGroupId id = retrieveGroupId(intent);
Database db = App.getDB();
if ( id == -1 ) {
if ( id == null ) {
mGroup = db.root;
} else {
WeakReference<PwGroupV3> wPw = db.groups.get(id);
WeakReference<PwGroup> wPw = db.groups.get(id);
mGroup = wPw.get();
}
Log.w(TAG, "Retrieved group");
@@ -105,7 +123,6 @@ public class GroupActivity extends GroupBaseActivity {
}
if ( mode == FULL || mode == ADD_GROUP_ONLY ) {
// Add Group button
Button addGroup = (Button) findViewById(R.id.add_group);
@@ -155,10 +172,10 @@ public class GroupActivity extends GroupBaseActivity {
private class GroupAddHandler implements View.OnClickListener {
private GroupBaseActivity mAct;
private PwGroupV3 mGroup;
private PwGroup mGroup;
private GroupCreateDialog mDialog;
GroupAddHandler(GroupBaseActivity act, PwGroupV3 group) {
GroupAddHandler(GroupBaseActivity act, PwGroup group) {
mAct = act;
mGroup = group;
}
@@ -178,7 +195,7 @@ public class GroupActivity extends GroupBaseActivity {
if ( ! mDialog.canceled() && res.length() > 0 ) {
GroupActivity act = GroupActivity.this;
Handler handler = new Handler();
AddGroup task = new AddGroup(App.getDB(), res, mGroup, act.new RefreshTask(handler), false);
AddGroup task = AddGroup.getInstance(App.getDB(), res, mGroup, act.new RefreshTask(handler), false);
ProgressTask pt = new ProgressTask(act, task, R.string.saving_database);
pt.run();
}

View File

@@ -0,0 +1,28 @@
package com.keepassdroid;
import android.content.Intent;
import com.keepassdroid.database.PwGroupIdV3;
import com.keepassdroid.database.PwGroupV3;
public class GroupActivityV3 extends GroupActivity {
@Override
protected PwGroupV3 getGroup() {
return (PwGroupV3) mGroup;
}
@Override
protected PwGroupIdV3 retrieveGroupId(Intent i) {
int id = i.getIntExtra(KEY_ENTRY, -1);
if ( id == -1 ) {
return null;
}
return new PwGroupIdV3(id);
}
}

View File

@@ -20,9 +20,7 @@
package com.keepassdroid;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
@@ -37,7 +35,7 @@ import android.widget.Toast;
import com.android.keepass.KeePass;
import com.android.keepass.R;
import com.keepassdroid.app.App;
import com.keepassdroid.database.PwGroupV3;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.edit.OnFinish;
import com.keepassdroid.settings.AppSettingsActivity;
import com.keepassdroid.utils.Util;
@@ -52,9 +50,10 @@ public abstract class GroupBaseActivity extends LockCloseListActivity {
protected static final int MENU_CHANGE_MASTER_KEY = Menu.FIRST + 3;
protected static final int MENU_APP_SETTINGS = Menu.FIRST + 4;
protected PwGroupV3 mGroup;
protected PwGroup mGroup;
public static void Launch(Activity act, PwGroupV3 group) {
/*
public static void Launch(Activity act, PwGroup group) {
Intent i = new Intent(act, GroupActivity.class);
if ( group != null ) {
@@ -63,6 +62,7 @@ public abstract class GroupBaseActivity extends LockCloseListActivity {
act.startActivityForResult(i,0);
}
*/
@Override
protected void onResume() {
@@ -117,7 +117,7 @@ public abstract class GroupBaseActivity extends LockCloseListActivity {
protected void setGroupTitle() {
if ( mGroup != null ) {
String name = mGroup.name;
String name = mGroup.getName();
if ( name != null && name.length() > 0 ) {
TextView tv = (TextView) findViewById(R.id.group_name);
if ( tv != null ) {

View File

@@ -30,21 +30,21 @@ import android.widget.TextView;
import com.android.keepass.R;
import com.keepassdroid.app.App;
import com.keepassdroid.database.PwEntryV3;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.edit.DeleteEntry;
import com.keepassdroid.settings.PrefsUtil;
public class PwEntryView extends ClickView {
private GroupBaseActivity mAct;
private PwEntryV3 mPw;
private PwEntry mPw;
private TextView mTv;
private int mPos;
private static final int MENU_OPEN = Menu.FIRST;
private static final int MENU_DELETE = Menu.FIRST + 1;
public PwEntryView(GroupBaseActivity act, PwEntryV3 pw, int pos) {
public PwEntryView(GroupBaseActivity act, PwEntry pw, int pos) {
super(act);
mAct = act;
mPw = pw;

View File

@@ -21,14 +21,15 @@ package com.keepassdroid;
import java.util.Vector;
import com.keepassdroid.database.PwEntryV3;
import com.keepassdroid.database.PwGroupV3;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.PwEntryV3;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.PwGroupV3;
public class PwListAdapter extends BaseAdapter {
@Override
@@ -46,10 +47,10 @@ public class PwListAdapter extends BaseAdapter {
}
private GroupBaseActivity mAct;
private PwGroupV3 mGroup;
private Vector<PwEntryV3> filteredEntries;
private PwGroup mGroup;
private Vector<PwEntry> filteredEntries;
public PwListAdapter(GroupBaseActivity act, PwGroupV3 group) {
public PwListAdapter(GroupBaseActivity act, PwGroup group) {
mAct = act;
mGroup = group;
@@ -58,7 +59,7 @@ public class PwListAdapter extends BaseAdapter {
}
private void filter() {
filteredEntries = new Vector<PwEntryV3>();
filteredEntries = new Vector<PwEntry>();
for (int i = 0; i < mGroup.childEntries.size(); i++) {
PwEntryV3 entry = (PwEntryV3) mGroup.childEntries.elementAt(i);

View File

@@ -137,7 +137,6 @@ public class NativeAESCipherSpi extends CipherSpi {
}
private int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) {
mBuffered = 0;
int outputSize = engineGetOutputSize(inputLen);
@@ -145,7 +144,11 @@ public class NativeAESCipherSpi extends CipherSpi {
int finalAmt = nativeDoFinal(mCtxPtr, output, outputOffset + updateAmt, outputSize - updateAmt);
return updateAmt + finalAmt;
int out = updateAmt + finalAmt;
mBuffered = 0;
return out;
}
private native int nativeDoFinal(long ctxPtr, byte[] output, int outputOffest, int outputSize);
@@ -164,9 +167,11 @@ public class NativeAESCipherSpi extends CipherSpi {
protected int engineGetOutputSize(int inputLen) {
int totalLen = mBuffered + inputLen;
/*
if ( ! mPadding || ! mEncrypting ) {
return totalLen;
}
*/
int padLen = AES_BLOCK_SIZE - (totalLen % AES_BLOCK_SIZE);
@@ -299,8 +304,15 @@ public class NativeAESCipherSpi extends CipherSpi {
}
int update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) {
mBuffered = (mBuffered + inputLen) % AES_BLOCK_SIZE;
return nativeUpdate(mCtxPtr, input, inputOffset, inputLen, output, outputOffset, engineGetOutputSize(inputLen));
int outputSize = engineGetOutputSize(inputLen);
int out = nativeUpdate(mCtxPtr, input, inputOffset, inputLen, output, outputOffset, outputSize);
mBuffered = (mBuffered + ((inputLen - out))) % AES_BLOCK_SIZE;
return out;
}
private native int nativeUpdate(long ctxPtr, byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset, int outputSize);

View File

@@ -27,6 +27,7 @@ import java.io.UnsupportedEncodingException;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Vector;
import com.keepassdroid.crypto.finalkey.FinalKey;
import com.keepassdroid.crypto.finalkey.FinalKeyFactory;
@@ -203,4 +204,14 @@ public abstract class PwDatabase {
public abstract byte[] getPasswordKey(String key) throws IOException;
public abstract Vector<PwGroup> getGrpRoots();
public abstract Vector<PwGroup> getGroups();
public abstract Vector<PwEntry> getEntries();
public abstract long getNumRounds();
public abstract void setNumRonuds(long rounds) throws NumberFormatException;
}

View File

@@ -52,12 +52,12 @@ public class PwDatabaseV3 extends PwDatabase {
public String name = "KeePass database";
// Special entry for settings
public PwEntryV3 metaInfo;
public PwEntry metaInfo;
// all entries
public Vector<PwEntryV3> entries = new Vector<PwEntryV3>();
public Vector<PwEntry> entries = new Vector<PwEntry>();
// all groups
public Vector<PwGroupV3> groups = new Vector<PwGroupV3>();
private Vector<PwGroup> groups = new Vector<PwGroup>();
// Algorithm used to encrypt the database
public int algorithm;
public int numKeyEncRounds;
@@ -75,11 +75,27 @@ public class PwDatabaseV3 extends PwDatabase {
return numKeyEncRounds;
}
public Vector<PwGroupV3> getGrpRoots() {
@Override
public Vector<PwGroup> getGroups() {
return groups;
}
@Override
public Vector<PwEntry> getEntries() {
return entries;
}
public void setGroups(Vector<PwGroup> grp) {
groups = grp;
}
@Override
public Vector<PwGroup> getGrpRoots() {
int target = 0;
Vector<PwGroupV3> kids = new Vector<PwGroupV3>();
Vector<PwGroup> kids = new Vector<PwGroup>();
for( int i=0; i < groups.size(); i++ ) {
PwGroupV3 grp = groups.elementAt( i );
PwGroupV3 grp = (PwGroupV3) groups.elementAt( i );
if( grp.level == target )
kids.addElement( grp );
}
@@ -88,7 +104,7 @@ public class PwDatabaseV3 extends PwDatabase {
public int getRootGroupId() {
for ( int i = 0; i < groups.size(); i++ ) {
PwGroupV3 grp = groups.elementAt(i);
PwGroupV3 grp = (PwGroupV3) groups.elementAt(i);
if ( grp.level == 0 ) {
return grp.groupId;
}
@@ -97,30 +113,29 @@ public class PwDatabaseV3 extends PwDatabase {
return -1;
}
public Vector<PwGroupV3> getGrpChildren( PwGroupV3 parent ) {
public Vector<PwGroup> getGrpChildren(PwGroupV3 parent) {
int idx = groups.indexOf(parent);
int target = parent.level + 1;
Vector<PwGroupV3> kids = new Vector<PwGroupV3>();
Vector<PwGroup> kids = new Vector<PwGroup>();
while (++idx < groups.size()) {
PwGroupV3 grp = groups.elementAt( idx );
PwGroupV3 grp = (PwGroupV3) groups.elementAt(idx);
if (grp.level < target)
break;
else
if( grp.level == target )
else if (grp.level == target)
kids.addElement(grp);
}
return kids;
}
public Vector<PwEntryV3> getEntries( PwGroupV3 parent ) {
Vector<PwEntryV3> kids = new Vector<PwEntryV3>();
/*for( Iterator i = entries.iterator(); i.hasNext(); ) {
PwEntryV3 ent = (PwEntryV3)i.next();
if( ent.groupId == parent.groupId )
kids.add( ent );
}*/
public Vector<PwEntry> getEntries(PwGroupV3 parent) {
Vector<PwEntry> kids = new Vector<PwEntry>();
/*
* for( Iterator i = entries.iterator(); i.hasNext(); ) { PwEntryV3 ent
* = (PwEntryV3)i.next(); if( ent.groupId == parent.groupId ) kids.add(
* ent ); }
*/
for (int i = 0; i < entries.size(); i++) {
PwEntryV3 ent = entries.elementAt(i);
PwEntryV3 ent = (PwEntryV3) entries.elementAt(i);
if (ent.groupId == parent.groupId)
kids.addElement(ent);
}
@@ -149,30 +164,33 @@ public class PwDatabaseV3 extends PwDatabase {
if (currentGroup == null) {
rootGroup = new PwGroupV3();
Vector<PwGroupV3> rootChildGroups = getGrpRoots();
rootGroup.childGroups = rootChildGroups;
rootGroup.childEntries = new Vector<PwEntryV3>();
Vector<PwGroup> rootChildGroups = getGrpRoots();
rootGroup.setGroups(rootChildGroups);
rootGroup.childEntries = new Vector<PwEntry>();
rootGroup.level = -1;
for (int i=0; i<rootChildGroups.size(); i++) {
rootChildGroups.elementAt(i).parent = rootGroup;
constructTree(rootChildGroups.elementAt(i));
PwGroupV3 grp = (PwGroupV3) rootChildGroups.elementAt(i);
grp.parent = rootGroup;
constructTree(grp);
}
return;
}
// I'm in non-root
// get child groups
currentGroup.childGroups = getGrpChildren(currentGroup);
currentGroup.setGroups(getGrpChildren(currentGroup));
currentGroup.childEntries = getEntries(currentGroup);
// set parent in child entries
for (int i=0; i<currentGroup.childEntries.size(); i++) {
currentGroup.childEntries.elementAt(i).parent = currentGroup;
PwEntryV3 entry = (PwEntryV3) currentGroup.childEntries.elementAt(i);
entry.parent = currentGroup;
}
// recursively construct child groups
for (int i=0; i<currentGroup.childGroups.size(); i++) {
currentGroup.childGroups.elementAt(i).parent = currentGroup;
constructTree(currentGroup.childGroups.elementAt(i));
PwGroupV3 grp = (PwGroupV3) currentGroup.childGroups.elementAt(i);
grp.parent = currentGroup;
constructTree((PwGroupV3) currentGroup.childGroups.elementAt(i));
}
return;
}
@@ -194,8 +212,8 @@ public class PwDatabaseV3 extends PwDatabase {
group.level = parent.level + 1;
group.childEntries = new Vector<PwEntryV3>();
group.childGroups = new Vector<PwGroupV3>();
group.childEntries = new Vector<PwEntry>();
group.setGroups(new Vector<PwGroup>());
// Add group PwDatabaseV3 and Parent
parent.childGroups.add(group);
@@ -235,7 +253,8 @@ public class PwDatabaseV3 extends PwDatabase {
*/
private boolean isGroupIdUsed(int id) {
for ( int i = 0; i < groups.size(); i++ ) {
if ( groups.get(i).groupId == id ) {
PwGroupV3 group = (PwGroupV3) groups.get(i);
if ( group.groupId == id ) {
return true;
}
}
@@ -263,4 +282,19 @@ public class PwDatabaseV3 extends PwDatabase {
return getPasswordKey(key, "ISO-8859-1");
}
@Override
public long getNumRounds() {
return numKeyEncRounds;
}
@Override
public void setNumRonuds(long rounds) throws NumberFormatException {
if ( rounds > Integer.MAX_VALUE || rounds < Integer.MIN_VALUE ) {
throw new NumberFormatException();
}
numKeyEncRounds = (int) rounds;
}
}

View File

@@ -23,7 +23,13 @@ import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
import java.util.Vector;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.keepassdroid.database.exception.InconsistentDBException;
import com.keepassdroid.database.exception.InvalidKeyFileException;
@@ -32,6 +38,10 @@ public class PwDatabaseV4 extends PwDatabase {
public UUID dataCipher;
public PwCompressionAlgorithm compressionAlgorithm;
public long numKeyEncRounds;
private Document doc;
//private Vector<PwGroupV4> groups = new Vector<PwGroupV4>();
private PwGroupV4 rootGroup;
@Override
public byte[] getMasterKey(String key, String keyFileName)
@@ -65,4 +75,51 @@ public class PwDatabaseV4 extends PwDatabase {
return getPasswordKey(key, "UTF-8");
}
@Override
public Vector<PwGroup> getGroups() {
Vector<PwGroup> list = new Vector<PwGroup>();
rootGroup.buildChildGroupsRecursive(list);
return list;
}
public void parseDB(Document d) throws InconsistentDBException {
doc = d;
NodeList list = doc.getElementsByTagName("Root");
int len = list.getLength();
if ( len < 0 || len > 1 ) {
throw new InconsistentDBException("Missing root node");
}
Node root = list.item(1);
rootGroup = new PwGroupV4(root);
}
@Override
public Vector<PwGroup> getGrpRoots() {
return rootGroup.childGroups;
}
@Override
public Vector<PwEntry> getEntries() {
Vector<PwEntry> list = new Vector<PwEntry>();
rootGroup.buildChildEntriesRecursive(list);
return list;
}
@Override
public long getNumRounds() {
return numKeyEncRounds;
}
@Override
public void setNumRonuds(long rounds) throws NumberFormatException {
numKeyEncRounds = rounds;
}
}

View File

@@ -19,6 +19,54 @@
*/
package com.keepassdroid.database;
public abstract class PwEntry {
import java.util.Date;
public abstract class PwEntry implements Cloneable {
public byte uuid[] = new byte[16];
public String title;
public String url;
public String additional;
public PwEntry() {
}
@Override
public Object clone() {
PwEntry newEntry;
try {
newEntry = (PwEntry) super.clone();
} catch (CloneNotSupportedException e) {
assert(false);
throw new RuntimeException("Clone should be supported");
}
System.arraycopy(uuid, 0, newEntry.uuid, 0, uuid.length);
newEntry.title = title;
newEntry.url = url;
newEntry.additional = additional;
return newEntry;
}
public void assign(PwEntry source) {
System.arraycopy(source.uuid, 0, uuid, 0, source.uuid.length);
title = source.title;
url = source.url;
additional = source.additional;
}
public abstract void stampLastAccess();
public abstract String getUsername();
public abstract String getPassword();
public abstract Date getCreate();
public abstract Date getMod();
public abstract Date getAccess();
public abstract Date getExpire();
public abstract PwGroup getParent();
public abstract String getDisplayTitle();
}

View File

@@ -70,18 +70,13 @@ public class PwEntryV3 extends PwEntry {
public byte uuid[] = new byte[16];
public int groupId;
public int imageId;
public String title;
public String url;
public String username;
private byte[] password;
public String additional;
public PwDate tCreation;
public PwDate tLastMod;
public PwDate tLastAccess;
@@ -132,17 +127,20 @@ public class PwEntryV3 extends PwEntry {
public PwGroupV3 parent = null;
public PwEntryV3() {
super();
}
/*
public PwEntryV3(PwEntryV3 source) {
assign(source);
}
*/
public PwEntryV3(Database db, int parentId) {
WeakReference<PwGroupV3> wPw = db.groups.get(parentId);
WeakReference<PwGroup> wPw = db.groups.get(parentId);
parent = wPw.get();
parent = (PwGroupV3) wPw.get();
groupId = parentId;
Random random = new Random();
@@ -162,6 +160,7 @@ public class PwEntryV3 extends PwEntry {
return title.equals(PMS_TAN_ENTRY);
}
@Override
public String getDisplayTitle() {
if ( isTan() ) {
return PMS_TAN_ENTRY + " " + username;
@@ -173,7 +172,12 @@ public class PwEntryV3 extends PwEntry {
/**
* @return the actual password byte array.
*/
public byte[] getPassword() {
@Override
public String getPassword() {
return new String(password);
}
public byte[] getPasswordBytes() {
return password;
}
@@ -235,19 +239,31 @@ public class PwEntryV3 extends PwEntry {
return true;
}
public void assign(PwEntryV3 source) {
System.arraycopy(source.uuid, 0, uuid, 0, source.uuid.length);
@Override
public void assign(PwEntry source) {
if ( ! (source instanceof PwEntryV3) ) {
throw new RuntimeException("DB version mix");
}
super.assign(source);
PwEntryV3 src = (PwEntryV3) source;
assign(src);
}
private void assign(PwEntryV3 source) {
groupId = source.groupId;
imageId = source.imageId;
title = source.title;
url = source.url;
username = source.username;
int passLen = source.password.length;
password = new byte[passLen];
System.arraycopy(source.password, 0, password, 0, passLen);
additional = source.additional;
tCreation = (PwDate) source.tCreation.clone();
tLastMod = (PwDate) source.tLastMod.clone();
tLastAccess = (PwDate) source.tLastAccess.clone();
@@ -265,4 +281,68 @@ public class PwEntryV3 extends PwEntry {
}
@Override
public Object clone() {
PwEntryV3 newEntry = (PwEntryV3) super.clone();
int passLen = password.length;
password = new byte[passLen];
System.arraycopy(password, 0, newEntry.password, 0, passLen);
newEntry.tCreation = (PwDate) tCreation.clone();
newEntry.tLastMod = (PwDate) tLastMod.clone();
newEntry.tLastAccess = (PwDate) tLastAccess.clone();
newEntry.tExpire = (PwDate) tExpire.clone();
newEntry.binaryDesc = binaryDesc;
if ( binaryData != null ) {
int descLen = binaryData.length;
newEntry.binaryData = new byte[descLen];
System.arraycopy(binaryData, 0, newEntry.binaryData, 0, descLen);
}
newEntry.parent = parent;
return newEntry;
}
@Override
public void stampLastAccess() {
Calendar cal = Calendar.getInstance();
tLastAccess = new PwDate(cal.getTime());
}
@Override
public String getUsername() {
return username;
}
@Override
public Date getAccess() {
return tLastAccess.getJDate();
}
@Override
public Date getCreate() {
return tCreation.getJDate();
}
@Override
public Date getExpire() {
return tExpire.getJDate();
}
@Override
public Date getMod() {
return tLastMod.getJDate();
}
@Override
public PwGroupV3 getParent() {
return parent;
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright 2010 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 java.util.Date;
import org.w3c.dom.Node;
public class PwEntryV4 extends PwEntry {
private Node node;
public PwEntryV4(Node n) {
node = n;
}
@Override
public void assign(PwEntry source) {
super.assign(source);
if ( ! (source instanceof PwEntryV4) ) {
throw new RuntimeException("DB version mix.");
}
PwEntryV4 src = (PwEntryV4) source;
assign(src);
}
private void assign(PwEntryV4 source) {
node = source.node;
}
@Override
public Object clone() {
PwEntryV4 newEntry = (PwEntryV4) super.clone();
return newEntry;
}
@Override
public void stampLastAccess() {
// TODO Implement me
}
@Override
public String getUsername() {
// TODO Implement me
return null;
}
@Override
public String getPassword() {
// TODO Implement me
return null;
}
@Override
public Date getAccess() {
// TODO Auto-generated method stub
return null;
}
@Override
public Date getCreate() {
// TODO Auto-generated method stub
return null;
}
@Override
public Date getExpire() {
// TODO Auto-generated method stub
return null;
}
@Override
public Date getMod() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getDisplayTitle() {
// TOOD: Add special TAN handling for V4?
return title;
}
@Override
public PwGroupV4 getParent() {
// TODO Auto-generated method stub
return null;
}
}

View File

@@ -19,6 +19,16 @@
*/
package com.keepassdroid.database;
public class PwGroup {
import java.util.Vector;
public abstract class PwGroup {
public Vector<PwGroup> childGroups = new Vector<PwGroup>();
public Vector<PwEntry> childEntries = new Vector<PwEntry>();
public abstract PwGroup getParent();
public abstract PwGroupId getId();
public abstract String getName();
}

View File

@@ -0,0 +1,5 @@
package com.keepassdroid.database;
public abstract class PwGroupId {
}

View File

@@ -0,0 +1,29 @@
package com.keepassdroid.database;
public class PwGroupIdV3 extends PwGroupId {
private int id;
public PwGroupIdV3(int i) {
id = i;
}
@Override
public boolean equals(Object compare) {
if ( ! (compare instanceof PwGroupIdV3) ) {
return false;
}
PwGroupIdV3 cmp = (PwGroupIdV3) compare;
return id == cmp.id;
}
@Override
public int hashCode() {
Integer i = new Integer(id);
return i.hashCode();
}
}

View File

@@ -0,0 +1,28 @@
package com.keepassdroid.database;
import java.util.UUID;
public class PwGroupIdV4 extends PwGroupId {
private UUID uuid;
public PwGroupIdV4(UUID u) {
uuid = u;
}
@Override
public boolean equals(Object id) {
if ( ! (id instanceof PwGroupIdV4) ) {
return false;
}
PwGroupIdV4 v4 = (PwGroupIdV4) id;
return uuid.equals(v4.uuid);
}
@Override
public int hashCode() {
return uuid.hashCode();
}
}

View File

@@ -57,8 +57,6 @@ public class PwGroupV3 extends PwGroup {
public static final int BUF_SIZE = 124;
// for tree traversing
public Vector<PwGroupV3> childGroups = null;
public Vector<PwEntryV3> childEntries = null;
public PwGroupV3 parent = null;
public int groupId;
@@ -75,29 +73,49 @@ public class PwGroupV3 extends PwGroup {
/** Used by KeePass internally, don't use */
public int flags;
public void setGroups(Vector<PwGroup> groups) {
childGroups = groups;
}
public void sortGroupsByName() {
Collections.sort(childGroups, new GroupNameComparator());
}
@Override
public PwGroup getParent() {
return parent;
}
public void sortEntriesByName() {
Collections.sort(childEntries, new EntryNameComparator());
}
private class GroupNameComparator implements Comparator<PwGroupV3> {
private class GroupNameComparator implements Comparator<PwGroup> {
@Override
public int compare(PwGroupV3 object1, PwGroupV3 object2) {
return object1.name.compareToIgnoreCase(object2.name);
public int compare(PwGroup object1, PwGroup object2) {
return object1.getName().compareToIgnoreCase(object2.getName());
}
}
private class EntryNameComparator implements Comparator<PwEntryV3> {
private class EntryNameComparator implements Comparator<PwEntry> {
@Override
public int compare(PwEntryV3 object1, PwEntryV3 object2) {
public int compare(PwEntry object1, PwEntry object2) {
return object1.title.compareToIgnoreCase(object2.title);
}
}
@Override
public PwGroupId getId() {
return new PwGroupIdV3(groupId);
}
@Override
public String getName() {
return name;
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright 2010 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 java.util.UUID;
import java.util.Vector;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.keepassdroid.database.exception.InconsistentDBException;
public class PwGroupV4 extends PwGroup {
private Node node;
private PwGroup parent;
public PwGroupV4(Node n) throws InconsistentDBException {
this(n, null);
}
public PwGroupV4(Node n, PwGroup p) throws InconsistentDBException {
node = n;
parent = p;
buildTree();
}
private void buildTree() throws InconsistentDBException {
NodeList children = node.getChildNodes();
for ( int i = 0; i < children.getLength(); i++ ) {
Node child = children.item(i);
String name = child.getNodeName();
if ( name.equalsIgnoreCase("Group") ) {
PwGroupV4 group = new PwGroupV4(child, this);
childGroups.add(group);
} else if ( name.equalsIgnoreCase("Entry") ) {
PwEntryV4 entry = new PwEntryV4(child);
childEntries.add(entry);
}
}
}
@Override
public PwGroup getParent() {
return parent;
}
public void buildChildGroupsRecursive(Vector<PwGroup> list) {
list.add(this);
for ( int i = 0; i < childGroups.size(); i++) {
PwGroupV4 child = (PwGroupV4) childGroups.get(i);
child.buildChildGroupsRecursive(list);
}
}
public void buildChildEntriesRecursive(Vector<PwEntry> list) {
for ( int i = 0; i < childEntries.size(); i++ ) {
list.add(childEntries.get(i));
}
for ( int i = 0; i < childGroups.size(); i++ ) {
PwGroupV4 child = (PwGroupV4) childGroups.get(i);
child.buildChildEntriesRecursive(list);
}
}
@Override
public PwGroupId getId() {
return new PwGroupIdV4(getUUID());
}
public UUID getUUID() {
// TODO: Get UUID from document
return null;
}
@Override
public String getName() {
// TODO Auto-generated method stub
return null;
}
}

View File

@@ -21,18 +21,27 @@ package com.keepassdroid.database.edit;
import java.lang.ref.WeakReference;
import com.keepassdroid.Database;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.PwEntryV3;
import com.keepassdroid.database.PwGroupV3;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.search.SearchDbHelper;
import com.keepassdroid.utils.Types;
public class AddEntry extends RunnableOnFinish {
private Database mDb;
private PwEntryV3 mEntry;
public abstract class AddEntry extends RunnableOnFinish {
protected Database mDb;
private PwEntry mEntry;
public AddEntry(Database db, PwEntryV3 entry, OnFinish finish) {
public static AddEntry getInstance(Database db, PwEntry entry, OnFinish finish) {
if ( entry instanceof PwEntryV3 ) {
return new AddEntryV3(db, (PwEntryV3) entry, finish);
} else {
// TODO: Implement me
throw new RuntimeException("Not implemented yet.");
}
}
protected AddEntry(Database db, PwEntry entry, OnFinish finish) {
super(finish);
mDb = db;
@@ -41,18 +50,11 @@ public class AddEntry extends RunnableOnFinish {
mFinish = new AfterAdd(mFinish);
}
public abstract void addEntry();
@Override
public void run() {
PwGroupV3 parent = mEntry.parent;
// Add entry to group
parent.childEntries.add(mEntry);
// Add entry to PwDatabaseV3
mDb.pm.entries.add(mEntry);
// Sort entries
parent.sortEntriesByName();
addEntry();
// Commit to disk
SaveDB save = new SaveDB(mDb, mFinish);
@@ -68,13 +70,13 @@ public class AddEntry extends RunnableOnFinish {
@Override
public void run() {
if ( mSuccess ) {
PwGroupV3 parent = mEntry.parent;
PwGroup parent = mEntry.getParent();
// Mark parent group dirty
mDb.dirty.put(parent, new WeakReference<PwGroupV3>(parent));
mDb.dirty.put(parent, new WeakReference<PwGroup>(parent));
// Add entry to global
mDb.entries.put(Types.bytestoUUID(mEntry.uuid), new WeakReference<PwEntryV3>(mEntry));
mDb.entries.put(Types.bytestoUUID(mEntry.uuid), new WeakReference<PwEntry>(mEntry));
if ( mDb.indexBuilt ) {
// Add entry to search index
@@ -85,10 +87,10 @@ public class AddEntry extends RunnableOnFinish {
}
} else {
// Remove from group
mEntry.parent.childEntries.removeElement(mEntry);
mEntry.getParent().childEntries.removeElement(mEntry);
// Remove from manager
mDb.pm.entries.removeElement(mEntry);
mDb.pm.getEntries().removeElement(mEntry);
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2010 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.edit;
import com.keepassdroid.Database;
import com.keepassdroid.database.PwDatabaseV3;
import com.keepassdroid.database.PwEntryV3;
import com.keepassdroid.database.PwGroupV3;
public class AddEntryV3 extends AddEntry {
private PwEntryV3 mEntry;
protected AddEntryV3(Database db, PwEntryV3 entry, OnFinish finish) {
super(db, entry, finish);
mEntry = entry;
}
public void addEntry() {
PwGroupV3 parent = mEntry.getParent();
// Add entry to group
parent.childEntries.add(mEntry);
// Add entry to PwDatabaseV3
PwDatabaseV3 pm = (PwDatabaseV3) mDb.pm;
pm.getEntries().add(mEntry);
// Sort entries
parent.sortEntriesByName();
}
}

View File

@@ -19,67 +19,31 @@
*/
package com.keepassdroid.database.edit;
import java.lang.ref.WeakReference;
import com.keepassdroid.Database;
import com.keepassdroid.database.PwDatabaseV3;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.PwGroupV3;
public class AddGroup extends RunnableOnFinish {
private Database mDb;
private String mName;
private PwGroupV3 mParent;
private PwGroupV3 mGroup;
private boolean mDontSave;
public abstract class AddGroup extends RunnableOnFinish {
protected Database mDb;
protected boolean mDontSave;
public AddGroup(Database db, String name, PwGroupV3 parent, OnFinish finish, boolean dontSave) {
public static AddGroup getInstance(Database db, String name, PwGroup parent, OnFinish finish, boolean dontSave) {
if ( parent instanceof PwGroupV3 ) {
return new AddGroupV3(db, name, (PwGroupV3) parent, finish, dontSave);
} else {
throw new RuntimeException("Not yet implemented");
}
}
protected AddGroup(Database db, OnFinish finish, boolean dontSave) {
super(finish);
mDb = db;
mName = name;
mParent = parent;
mDontSave = dontSave;
mFinish = new AfterAdd(mFinish);
}
@Override
public void run() {
PwDatabaseV3 pm = mDb.pm;
public abstract void run();
// Generate new group
mGroup = pm.newGroup(mName, mParent);
mParent.sortGroupsByName();
// Commit to disk
SaveDB save = new SaveDB(mDb, mFinish, mDontSave);
save.run();
}
private class AfterAdd extends OnFinish {
public AfterAdd(OnFinish finish) {
super(finish);
}
@Override
public void run() {
if ( mSuccess ) {
// Mark parent group dirty
mDb.dirty.put(mParent, new WeakReference<PwGroupV3>(mParent));
// Add group to global list
mDb.groups.put(mGroup.groupId, new WeakReference<PwGroupV3>(mGroup));
} else {
mDb.pm.removeGroup(mGroup);
}
super.run();
}
}
}

View File

@@ -0,0 +1,67 @@
package com.keepassdroid.database.edit;
import java.lang.ref.WeakReference;
import com.keepassdroid.Database;
import com.keepassdroid.database.PwDatabaseV3;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.PwGroupV3;
public class AddGroupV3 extends AddGroup {
private Database mDb;
private String mName;
private PwGroupV3 mParent;
private PwGroupV3 mGroup;
private boolean mDontSave;
protected AddGroupV3(Database db, String name, PwGroupV3 parent, OnFinish finish, boolean dontSave) {
super(db, finish, dontSave);
mDb = db;
mName = name;
mParent = parent;
mDontSave = dontSave;
mFinish = new AfterAdd(mFinish);
}
@Override
public void run() {
PwDatabaseV3 pm = (PwDatabaseV3) mDb.pm;
// Generate new group
mGroup = pm.newGroup(mName, mParent);
mParent.sortGroupsByName();
// Commit to disk
SaveDB save = new SaveDB(mDb, mFinish, mDontSave);
save.run();
}
private class AfterAdd extends OnFinish {
public AfterAdd(OnFinish finish) {
super(finish);
}
@Override
public void run() {
if ( mSuccess ) {
// Mark parent group dirty
mDb.dirty.put(mParent, new WeakReference<PwGroup>(mParent));
// Add group to global list
mDb.groups.put(mGroup.getId(), new WeakReference<PwGroup>(mGroup));
} else {
PwDatabaseV3 pm = (PwDatabaseV3) mDb.pm;
pm.removeGroup(mGroup);
}
super.run();
}
}
}

View File

@@ -60,9 +60,9 @@ public class CreateDB extends RunnableOnFinish {
db.setLoaded();
// Add a couple default groups
AddGroup internet = new AddGroup(db, "Internet", pm.rootGroup, null, true);
AddGroup internet = AddGroup.getInstance(db, "Internet", pm.rootGroup, null, true);
internet.run();
AddGroup email = new AddGroup(db, "eMail", pm.rootGroup, null, true);
AddGroup email = AddGroup.getInstance(db, "eMail", pm.rootGroup, null, true);
email.run();
// Commit changes

View File

@@ -21,10 +21,9 @@ package com.keepassdroid.database.edit;
import java.lang.ref.WeakReference;
import com.keepassdroid.Database;
import com.keepassdroid.database.PwEntryV3;
import com.keepassdroid.database.PwGroupV3;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.search.SearchDbHelper;
/** Task to delete entries
@@ -34,10 +33,10 @@ import com.keepassdroid.search.SearchDbHelper;
public class DeleteEntry extends RunnableOnFinish {
private Database mDb;
private PwEntryV3 mEntry;
private PwEntry mEntry;
private boolean mDontSave;
public DeleteEntry(Database db, PwEntryV3 entry, OnFinish finish) {
public DeleteEntry(Database db, PwEntry entry, OnFinish finish) {
super(finish);
mDb = db;
@@ -46,7 +45,7 @@ public class DeleteEntry extends RunnableOnFinish {
}
public DeleteEntry(Database db, PwEntryV3 entry, OnFinish finish, boolean dontSave) {
public DeleteEntry(Database db, PwEntry entry, OnFinish finish, boolean dontSave) {
super(finish);
mDb = db;
@@ -59,11 +58,11 @@ public class DeleteEntry extends RunnableOnFinish {
public void run() {
// Remove Entry from parent
PwGroupV3 parent = mEntry.parent;
PwGroup parent = mEntry.getParent();
parent.childEntries.remove(mEntry);
// Remove Entry from PwDatabaseV3
mDb.pm.entries.remove(mEntry);
// Remove Entry from PwDatabase
mDb.pm.getEntries().remove(mEntry);
// Save
mFinish = new AfterDelete(mFinish, parent, mEntry);
@@ -75,13 +74,12 @@ public class DeleteEntry extends RunnableOnFinish {
}
private class AfterDelete extends OnFinish {
private PwGroupV3 mParent;
private PwEntryV3 mEntry;
private PwGroup mParent;
private PwEntry mEntry;
public AfterDelete(OnFinish finish, PwGroupV3 parent, PwEntryV3 entry) {
public AfterDelete(OnFinish finish, PwGroup parent, PwEntry entry) {
super(finish);
mParent = parent;
@@ -105,22 +103,21 @@ public class DeleteEntry extends RunnableOnFinish {
// Mark parent dirty
if ( mParent != null ) {
mDb.dirty.put(mParent, new WeakReference<PwGroupV3>(mParent));
mDb.dirty.put(mParent, new WeakReference<PwGroup>(mParent));
}
} else {
// Undo remove entry
mDb.pm.entries.add(mEntry);
mDb.pm.getEntries().add(mEntry);
PwGroupV3 parent = mEntry.parent;
PwGroup parent = mEntry.getParent();
if ( parent != null ) {
parent.childEntries.add(mEntry);
}
}
super.run();
}
}
}

View File

@@ -22,36 +22,36 @@ package com.keepassdroid.database.edit;
import java.lang.ref.WeakReference;
import java.util.Vector;
import com.keepassdroid.Database;
import com.keepassdroid.GroupBaseActivity;
import com.keepassdroid.database.PwEntryV3;
import com.keepassdroid.database.PwGroupV3;
import com.keepassdroid.app.App;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.PwGroup;
public class DeleteGroup extends RunnableOnFinish {
private Database mDb;
private PwGroupV3 mGroup;
private PwGroup mGroup;
private GroupBaseActivity mAct;
private boolean mDontSave;
public DeleteGroup(Database db, PwGroupV3 group, GroupBaseActivity act, OnFinish finish) {
public DeleteGroup(Database db, PwGroup group, GroupBaseActivity act, OnFinish finish) {
super(finish);
setMembers(db, group, act, false);
}
public DeleteGroup(Database db, PwGroupV3 group, GroupBaseActivity act, OnFinish finish, boolean dontSave) {
public DeleteGroup(Database db, PwGroup group, GroupBaseActivity act, OnFinish finish, boolean dontSave) {
super(finish);
setMembers(db, group, act, dontSave);
}
public DeleteGroup(Database db, PwGroupV3 group, OnFinish finish, boolean dontSave) {
public DeleteGroup(Database db, PwGroup group, OnFinish finish, boolean dontSave) {
super(finish);
setMembers(db, group, null, dontSave);
}
private void setMembers(Database db, PwGroupV3 group, GroupBaseActivity act, boolean dontSave) {
private void setMembers(Database db, PwGroup group, GroupBaseActivity act, boolean dontSave) {
mDb = db;
mGroup = group;
mAct = act;
@@ -67,14 +67,14 @@ public class DeleteGroup extends RunnableOnFinish {
public void run() {
// Remove child entries
Vector<PwEntryV3> childEnt = (Vector<PwEntryV3>) mGroup.childEntries.clone();
Vector<PwEntry> childEnt = (Vector<PwEntry>) mGroup.childEntries.clone();
for ( int i = 0; i < childEnt.size(); i++ ) {
DeleteEntry task = new DeleteEntry(mDb, childEnt.get(i), null, true);
task.run();
}
// Remove child groups
Vector<PwGroupV3> childGrp = (Vector<PwGroupV3>) mGroup.childGroups.clone();
Vector<PwGroup> childGrp = (Vector<PwGroup>) mGroup.childGroups.clone();
for ( int i = 0; i < childGrp.size(); i++ ) {
DeleteGroup task = new DeleteGroup(mDb, childGrp.get(i), mAct, null, true);
task.run();
@@ -82,13 +82,13 @@ public class DeleteGroup extends RunnableOnFinish {
// Remove from parent
PwGroupV3 parent = mGroup.parent;
PwGroup parent = mGroup.getParent();
if ( parent != null ) {
parent.childGroups.remove(mGroup);
}
// Remove from PwDatabaseV3
mDb.pm.groups.remove(mGroup);
mDb.pm.getGroups().remove(mGroup);
// Save
SaveDB save = new SaveDB(mDb, mFinish, mDontSave);
@@ -104,7 +104,7 @@ public class DeleteGroup extends RunnableOnFinish {
public void run() {
if ( mSuccess ) {
// Remove from group global
mDb.groups.remove(mGroup.groupId);
mDb.groups.remove(mGroup.getId());
// Remove group from the dirty global (if it is present), not a big deal if this fails
try {
@@ -114,12 +114,13 @@ public class DeleteGroup extends RunnableOnFinish {
}
// Mark parent dirty
PwGroupV3 parent = mGroup.parent;
PwGroup parent = mGroup.getParent();
if ( parent != null ) {
mDb.dirty.put(parent, new WeakReference<PwGroupV3>(parent));
mDb.dirty.put(parent, new WeakReference<PwGroup>(parent));
}
} else {
// Let's not bother recovering from a failure to save a deleted group. It is too much work.
App.setShutdown();
}
super.run();

View File

@@ -21,18 +21,19 @@ package com.keepassdroid.database.edit;
import java.lang.ref.WeakReference;
import com.keepassdroid.Database;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.PwEntryV3;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.PwGroupV3;
import com.keepassdroid.search.SearchDbHelper;
public class UpdateEntry extends RunnableOnFinish {
private Database mDb;
private PwEntryV3 mOldE;
private PwEntryV3 mNewE;
private PwEntry mOldE;
private PwEntry mNewE;
public UpdateEntry(Database db, PwEntryV3 oldE, PwEntryV3 newE, OnFinish finish) {
public UpdateEntry(Database db, PwEntry oldE, PwEntry newE, OnFinish finish) {
super(finish);
mDb = db;
@@ -40,7 +41,9 @@ public class UpdateEntry extends RunnableOnFinish {
mNewE = newE;
// Keep backup of original values in case save fails
PwEntryV3 backup = new PwEntryV3(mOldE);
PwEntryV3 backup;
backup = (PwEntryV3) mOldE.clone();
mFinish = new AfterUpdate(backup, finish);
}
@@ -74,7 +77,7 @@ public class UpdateEntry extends RunnableOnFinish {
parent.sortEntriesByName();
// Mark parent group dirty
mDb.dirty.put(parent, new WeakReference<PwGroupV3>(parent));
mDb.dirty.put(parent, new WeakReference<PwGroup>(parent));
}

View File

@@ -0,0 +1,11 @@
package com.keepassdroid.database.exception;
public class InconsistentDBException extends Exception {
public InconsistentDBException(String msg) {
super(msg);
}
private static final long serialVersionUID = 4879502365625912291L;
}

View File

@@ -270,6 +270,8 @@ public class ImporterV3 extends Importer {
pos += 2 + 4 + fieldSize;
}
newManager.constructTree(null);
return newManager;
}

View File

@@ -19,7 +19,7 @@
*/
package com.keepassdroid.database.load;
import java.io.FileOutputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidAlgorithmParameterException;
@@ -29,20 +29,27 @@ import java.util.Arrays;
import java.util.zip.GZIPInputStream;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.NoSuchPaddingException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import com.keepassdroid.UpdateStatus;
import com.keepassdroid.crypto.CipherFactory;
import com.keepassdroid.database.PwCompressionAlgorithm;
import com.keepassdroid.database.PwDatabaseV4;
import com.keepassdroid.database.PwDbHeaderV4;
import com.keepassdroid.database.exception.InconsistentDBException;
import com.keepassdroid.database.exception.InvalidDBSignatureException;
import com.keepassdroid.database.exception.InvalidDBVersionException;
import com.keepassdroid.database.exception.InvalidKeyFileException;
import com.keepassdroid.database.exception.InvalidPasswordException;
import com.keepassdroid.stream.LEDataInputStream;
import com.keepassdroid.stream.BetterCipherInputStream;
import com.keepassdroid.stream.HashedBlockInputStream;
import com.keepassdroid.stream.LEDataInputStream;
public class ImporterV4 extends Importer {
@@ -60,12 +67,14 @@ public class ImporterV4 extends Importer {
InvalidKeyFileException, InvalidPasswordException,
InvalidDBSignatureException, InvalidDBVersionException {
// TODO: Measure whether this buffer is better or worse for performance
BufferedInputStream bis = new BufferedInputStream(inStream);
PwDatabaseV4 db = new PwDatabaseV4();
PwDbHeaderV4 header = new PwDbHeaderV4(db);
header.loadFromFile(inStream);
header.loadFromFile(bis);
db.setMasterKey(password, keyfile);
db.makeFinalKey(header.masterSeed, header.transformSeed, (int)db.numKeyEncRounds);
@@ -84,7 +93,7 @@ public class ImporterV4 extends Importer {
throw new IOException("Invalid algorithm.");
}
InputStream decrypted = new CipherInputStream(inStream, cipher);
InputStream decrypted = new BetterCipherInputStream(bis, cipher, 50 * 1024);
LEDataInputStream dataDecrypted = new LEDataInputStream(decrypted);
byte[] storedStartBytes = dataDecrypted.readBytes(32);
if ( storedStartBytes == null || storedStartBytes.length != 32 ) {
@@ -97,7 +106,7 @@ public class ImporterV4 extends Importer {
throw new IOException("Bad database key");
}
HashedBlockInputStream hashed = new HashedBlockInputStream(decrypted);
HashedBlockInputStream hashed = new HashedBlockInputStream(dataDecrypted);
InputStream decompressed;
if ( db.compressionAlgorithm == PwCompressionAlgorithm.Gzip ) {
@@ -106,18 +115,44 @@ public class ImporterV4 extends Importer {
decompressed = hashed;
}
// TODO: output into database instead of file
FileOutputStream fos = new FileOutputStream("/sdcard/output.xml");
// TODO: Measure whether this buffer is better or worse for performance
BufferedInputStream bis2 = new BufferedInputStream(decompressed);
// Parse the xml document
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder docB;
try {
docB = dbf.newDocumentBuilder();
} catch (ParserConfigurationException e) {
throw new IOException("Couldn't create document builder.");
}
Document doc;
try {
doc = docB.parse(bis2);
} catch (SAXException e) {
throw new IOException("Failed to parse db xml: " + e.getLocalizedMessage());
}
try {
db.parseDB(doc);
} catch (InconsistentDBException e) {
throw new IOException(e.getLocalizedMessage());
}
/*
FileOutputStream fos = new FileOutputStream("/sdcard/outputx.xml");
byte[] buf = new byte[1024];
int bytesRead;
while ( (bytesRead = decompressed.read(buf)) != -1 ) {
fos.write(buf, 0, bytesRead);
}
fos.close();
*/
return db;
}

View File

@@ -26,11 +26,11 @@ import java.io.OutputStream;
import com.keepassdroid.database.PwDbHeaderV3;
import com.keepassdroid.utils.Types;
public class PwDbHeaderOutput {
public class PwDbHeaderOutputV3 {
private PwDbHeaderV3 mHeader;
private OutputStream mOS;
public PwDbHeaderOutput(PwDbHeaderV3 header, OutputStream os) {
public PwDbHeaderOutputV3(PwDbHeaderV3 header, OutputStream os) {
mHeader = header;
mOS = os;
}

View File

@@ -0,0 +1,46 @@
/*
` * Copyright 2010 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.save;
import java.io.OutputStream;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.PwDatabaseV3;
import com.keepassdroid.database.PwDatabaseV4;
import com.keepassdroid.database.exception.PwDbOutputException;
public abstract class PwDbOutput {
public abstract void output() throws PwDbOutputException;
public static PwDbOutput getInstance(PwDatabase pm, OutputStream os) {
return getInstance(pm, os, false);
}
public static PwDbOutput getInstance(PwDatabase pm, OutputStream os, boolean debug) {
if ( pm instanceof PwDatabaseV3 ) {
return new PwDbV3Output((PwDatabaseV3)pm, os, debug);
} else if ( pm instanceof PwDatabaseV4 ) {
// TODO: Implement me
throw new RuntimeException(".kdbx output not yet supported.");
}
return null;
}
}

View File

@@ -40,11 +40,12 @@ import com.keepassdroid.database.PwDatabaseV3;
import com.keepassdroid.database.PwDbHeader;
import com.keepassdroid.database.PwDbHeaderV3;
import com.keepassdroid.database.PwEntryV3;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.PwGroupV3;
import com.keepassdroid.database.exception.PwDbOutputException;
import com.keepassdroid.stream.NullOutputStream;
public class PwDbV3Output {
public class PwDbV3Output extends PwDbOutput {
private PwDatabaseV3 mPM;
private OutputStream mOS;
private final boolean mDebug;
@@ -121,7 +122,7 @@ public class PwDbV3Output {
}
header.version = PwDbHeaderV3.DBVER_DW;
header.numGroups = mPM.groups.size();
header.numGroups = mPM.getGroups().size();
header.numEntries = mPM.entries.size();
header.numKeyEncRounds = mPM.getNumKeyEncRecords();
@@ -165,7 +166,7 @@ public class PwDbV3Output {
header.contentsHash = md.digest();
// Output header
PwDbHeaderOutput pho = new PwDbHeaderOutput(header, os);
PwDbHeaderOutputV3 pho = new PwDbHeaderOutputV3(header, os);
try {
pho.output();
} catch (IOException e) {
@@ -179,9 +180,10 @@ public class PwDbV3Output {
//long size = 0;
// Groups
for ( int i = 0; i < mPM.groups.size(); i++ ) {
PwGroupV3 pg = mPM.groups.get(i);
PwGroupOutput pgo = new PwGroupOutput(pg, os);
Vector<PwGroup> groups = mPM.getGroups();
for ( int i = 0; i < groups.size(); i++ ) {
PwGroupV3 pg = (PwGroupV3) groups.get(i);
PwGroupOutputV3 pgo = new PwGroupOutputV3(pg, os);
try {
pgo.output();
} catch (IOException e) {
@@ -191,8 +193,8 @@ public class PwDbV3Output {
// Entries
for (int i = 0; i < mPM.entries.size(); i++ ) {
PwEntryV3 pe = mPM.entries.get(i);
PwEntryOutput peo = new PwEntryOutput(pe, os);
PwEntryV3 pe = (PwEntryV3) mPM.entries.get(i);
PwEntryOutputV3 peo = new PwEntryOutputV3(pe, os);
try {
peo.output();
} catch (IOException e) {
@@ -202,24 +204,24 @@ public class PwDbV3Output {
}
private void sortGroupsForOutput() {
Vector<PwGroupV3> groupList = new Vector<PwGroupV3>();
Vector<PwGroup> groupList = new Vector<PwGroup>();
// Rebuild list according to coalation sorting order removing any orphaned groups
Vector<PwGroupV3> roots = mPM.getGrpRoots();
Vector<PwGroup> roots = mPM.getGrpRoots();
for ( int i = 0; i < roots.size(); i++ ) {
sortGroup(roots.get(i), groupList);
sortGroup((PwGroupV3) roots.get(i), groupList);
}
mPM.groups = groupList;
mPM.setGroups(groupList);
}
private void sortGroup(PwGroupV3 group, Vector<PwGroupV3> groupList) {
private void sortGroup(PwGroupV3 group, Vector<PwGroup> groupList) {
// Add current group
groupList.add(group);
// Recurse over children
for ( int i = 0; i < group.childGroups.size(); i++ ) {
sortGroup(group.childGroups.get(i), groupList);
sortGroup((PwGroupV3) group.childGroups.get(i), groupList);
}
}
}

View File

@@ -26,7 +26,7 @@ import java.io.OutputStream;
import com.keepassdroid.database.PwEntryV3;
import com.keepassdroid.utils.Types;
public class PwEntryOutput {
public class PwEntryOutputV3 {
// Constants
public static final byte[] UUID_FIELD_TYPE = Types.writeShort(1);
public static final byte[] GROUPID_FIELD_TYPE = Types.writeShort(2);
@@ -61,7 +61,7 @@ public class PwEntryOutput {
* @param pe
* @param os
*/
public PwEntryOutput(PwEntryV3 pe, OutputStream os) {
public PwEntryOutputV3(PwEntryV3 pe, OutputStream os) {
mPE = pe;
mOS = os;
}
@@ -103,7 +103,7 @@ public class PwEntryOutput {
outputBytes += userLen;
// Password
byte[] password = mPE.getPassword();
byte[] password = mPE.getPasswordBytes();
mOS.write(PASSWORD_FIELD_TYPE);
mOS.write(Types.writeInt(password.length+1));
mOS.write(password);

View File

@@ -26,7 +26,7 @@ import java.io.OutputStream;
import com.keepassdroid.database.PwGroupV3;
import com.keepassdroid.utils.Types;
public class PwGroupOutput {
public class PwGroupOutputV3 {
// Constants
public static final byte[] GROUPID_FIELD_TYPE = Types.writeShort(1);
public static final byte[] NAME_FIELD_TYPE = Types.writeShort(2);
@@ -53,7 +53,7 @@ public class PwGroupOutput {
* @param pg
* @param os
*/
public PwGroupOutput(PwGroupV3 pg, OutputStream os) {
public PwGroupOutputV3(PwGroupV3 pg, OutputStream os) {
mPG = pg;
mOS = os;
}

View File

@@ -22,7 +22,6 @@ package com.keepassdroid.search;
import java.util.UUID;
import java.util.Vector;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
@@ -32,7 +31,9 @@ import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.keepassdroid.Database;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.PwEntryV3;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.PwGroupV3;
import com.keepassdroid.utils.Types;
@@ -96,7 +97,7 @@ public class SearchDbHelper {
mDb.delete(SEARCH_TABLE, null, null);
}
private ContentValues buildNewEntryContent(PwEntryV3 entry) {
private ContentValues buildNewEntryContent(PwEntry entry) {
ContentValues cv = new ContentValues();
UUID uuid = Types.bytestoUUID(entry.uuid);
@@ -110,12 +111,12 @@ public class SearchDbHelper {
return cv;
}
public void insertEntry(PwEntryV3 entry) {
public void insertEntry(PwEntry entry) {
ContentValues cv = buildNewEntryContent(entry);
mDb.insert(SEARCH_TABLE, null, cv);
}
public void insertEntry(Vector<PwEntryV3> entries) {
public void insertEntry(Vector<? extends PwEntry> entries) {
mDb.beginTransaction();
try {
@@ -128,14 +129,14 @@ public class SearchDbHelper {
}
}
public void updateEntry(PwEntryV3 entry) {
public void updateEntry(PwEntry entry) {
ContentValues cv = buildNewEntryContent(entry);
String uuidStr = cv.getAsString(KEY_UUID);
mDb.update(SEARCH_TABLE, cv, KEY_UUID + " = ?", new String[] {uuidStr});
}
public void deleteEntry(PwEntryV3 entry) {
public void deleteEntry(PwEntry entry) {
UUID uuid = Types.bytestoUUID(entry.uuid);
String uuidStr = uuid.toString();
@@ -148,15 +149,15 @@ public class SearchDbHelper {
PwGroupV3 group = new PwGroupV3();
group.name = "Search results";
group.childEntries = new Vector<PwEntryV3>();
group.childGroups = new Vector<PwGroupV3>();
group.childEntries = new Vector<PwEntry>();
group.setGroups(new Vector<PwGroup>());
cursor.moveToFirst();
while ( ! cursor.isAfterLast() ) {
String sUUID = cursor.getString(0);
UUID uuid = UUID.fromString(sUUID);
Log.d("TAG", uuid.toString());
PwEntryV3 entry = db.entries.get(uuid).get();
PwEntryV3 entry = (PwEntryV3) db.entries.get(uuid).get();
group.childEntries.add(entry);
cursor.moveToNext();

View File

@@ -84,7 +84,7 @@ public class AppSettingsActivity extends LockingClosePreferenceActivity {
}
private void setRounds(Database db, Preference rounds) {
rounds.setSummary(Integer.toString(db.pm.numKeyEncRounds));
rounds.setSummary(Long.toString(db.pm.getNumRounds()));
}

View File

@@ -32,13 +32,13 @@ import com.android.keepass.R;
import com.keepassdroid.Database;
import com.keepassdroid.ProgressTask;
import com.keepassdroid.app.App;
import com.keepassdroid.database.PwDatabaseV3;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.edit.OnFinish;
import com.keepassdroid.database.edit.SaveDB;
public class RoundsPreference extends DialogPreference {
private PwDatabaseV3 mPM;
private PwDatabase mPM;
private TextView mRoundsView;
@Override
@@ -49,8 +49,8 @@ public class RoundsPreference extends DialogPreference {
Database db = App.getDB();
mPM = db.pm;
int numRounds = mPM.numKeyEncRounds;
mRoundsView.setText(Integer.toString(numRounds));
long numRounds = mPM.getNumRounds();
mRoundsView.setText(Long.toString(numRounds));
return view;
}
@@ -82,8 +82,13 @@ public class RoundsPreference extends DialogPreference {
rounds = 1;
}
int oldRounds = mPM.numKeyEncRounds;
mPM.numKeyEncRounds = rounds;
long oldRounds = mPM.getNumRounds();
try {
mPM.setNumRonuds(rounds);
} catch (NumberFormatException e) {
Toast.makeText(getContext(), R.string.error_rounds_too_large, Toast.LENGTH_LONG).show();
mPM.setNumRonuds(Integer.MAX_VALUE);
}
Handler handler = new Handler();
SaveDB save = new SaveDB(App.getDB(), new AfterSave(getContext(), handler, oldRounds));
@@ -95,10 +100,10 @@ public class RoundsPreference extends DialogPreference {
}
private class AfterSave extends OnFinish {
private int mOldRounds;
private long mOldRounds;
private Context mCtx;
public AfterSave(Context ctx, Handler handler, int oldRounds) {
public AfterSave(Context ctx, Handler handler, long oldRounds) {
super(handler);
mCtx = ctx;
@@ -114,7 +119,7 @@ public class RoundsPreference extends DialogPreference {
}
} else {
displayMessage(mCtx);
mPM.numKeyEncRounds = mOldRounds;
mPM.setNumRonuds(mOldRounds);
}
super.run();

View File

@@ -0,0 +1,247 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.keepassdroid.stream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import javax.crypto.Cipher;
import javax.crypto.NullCipher;
/**
* This class wraps an {@code InputStream} and a cipher so that {@code read()}
* methods return data that are read from the underlying {@code InputStream} and
* processed by the cipher.
* <p>
* The cipher must be initialized for the requested operation before being used
* by a {@code BetterCipherInputStream}. For example, if a cipher initialized for
* decryption is used with a {@code BetterCipherInputStream}, the {@code
* BetterCipherInputStream} tries to read the data an decrypt them before returning.
*/
public class BetterCipherInputStream extends FilterInputStream {
private final Cipher cipher;
private static final int I_DEFAULT_BUFFER_SIZE = 8 * 1024;
private final byte[] i_buffer;
private int index; // index of the bytes to return from o_buffer
private byte[] o_buffer;
private boolean finished;
/**
* Creates a new {@code BetterCipherInputStream} instance for an {@code
* InputStream} and a cipher.
*
* @param is
* the input stream to read data from.
* @param c
* the cipher to process the data with.
*/
public BetterCipherInputStream(InputStream is, Cipher c) {
this(is, c, I_DEFAULT_BUFFER_SIZE);
}
/**
* Creates a new {@code BetterCipherInputStream} instance for an {@code
* InputStream} and a cipher.
*
* @param is
* the input stream to read data from.
* @param c
* the cipher to process the data with.
* @param bufferSize
* size to buffer output from the cipher
*/
public BetterCipherInputStream(InputStream is, Cipher c, int bufferSize) {
super(is);
this.cipher = c;
i_buffer = new byte[bufferSize];
}
/**
* Creates a new {@code BetterCipherInputStream} instance for an {@code
* InputStream} without a cipher.
* <p>
* A {@code NullCipher} is created and used to process the data.
*
* @param is
* the input stream to read data from.
*/
protected BetterCipherInputStream(InputStream is) {
this(is, new NullCipher());
}
/**
* Reads the next byte from this cipher input stream.
*
* @return the next byte, or {@code -1} if the end of the stream is reached.
* @throws IOException
* if an error occurs.
*/
@Override
public int read() throws IOException {
if (finished) {
return ((o_buffer == null) || (index == o_buffer.length))
? -1
: o_buffer[index++] & 0xFF;
}
if ((o_buffer != null) && (index < o_buffer.length)) {
return o_buffer[index++] & 0xFF;
}
index = 0;
o_buffer = null;
int num_read;
while (o_buffer == null) {
if ((num_read = in.read(i_buffer)) == -1) {
try {
o_buffer = cipher.doFinal();
} catch (Exception e) {
throw new IOException(e.getMessage());
}
finished = true;
break;
}
o_buffer = cipher.update(i_buffer, 0, num_read);
}
return read();
}
/**
* Reads the next {@code b.length} bytes from this input stream into buffer
* {@code b}.
*
* @param b
* the buffer to be filled with data.
* @return the number of bytes filled into buffer {@code b}, or {@code -1}
* if the end of the stream is reached.
* @throws IOException
* if an error occurs.
*/
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
/**
* Reads the next {@code len} bytes from this input stream into buffer
* {@code b} starting at offset {@code off}.
* <p>
* if {@code b} is {@code null}, the next {@code len} bytes are read and
* discarded.
*
* @param b
* the buffer to be filled with data.
* @param off
* the offset to start in the buffer.
* @param len
* the maximum number of bytes to read.
* @return the number of bytes filled into buffer {@code b}, or {@code -1}
* of the of the stream is reached.
* @throws IOException
* if an error occurs.
* @throws NullPointerException
* if the underlying input stream is {@code null}.
*/
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (in == null) {
throw new NullPointerException("Underlying input stream is null");
}
int read_b;
int i;
for (i=0; i<len; i++) {
if ((read_b = read()) == -1) {
return (i == 0) ? -1 : i;
}
if (b != null) {
b[off+i] = (byte) read_b;
}
}
return i;
}
/**
* Skips up to n bytes from this input stream.
* <p>
* The number of bytes skipped depends on the result of a call to
* {@link BetterCipherInputStream#available() available}. The smaller of n and the
* result are the number of bytes being skipped.
*
* @param n
* the number of bytes that should be skipped.
* @return the number of bytes actually skipped.
* @throws IOException
* if an error occurs
*/
@Override
public long skip(long n) throws IOException {
long i = 0;
int available = available();
if (available < n) {
n = available;
}
while ((i < n) && (read() != -1)) {
i++;
}
return i;
}
/**
* Returns the number of bytes available without blocking.
*
* @return the number of bytes available, currently zero.
* @throws IOException
* if an error occurs
*/
@Override
public int available() throws IOException {
return 0;
}
/**
* Closes this {@code BetterCipherInputStream}, also closes the underlying input
* stream and call {@code doFinal} on the cipher object.
*
* @throws IOException
* if an error occurs.
*/
@Override
public void close() throws IOException {
in.close();
try {
cipher.doFinal();
} catch (GeneralSecurityException ignore) {
//do like RI does
}
}
/**
* Returns whether this input stream supports {@code mark} and
* {@code reset}, which it does not.
*
* @return false, since this input stream does not support {@code mark} and
* {@code reset}.
*/
@Override
public boolean markSupported() {
return false;
}
}

View File

@@ -37,7 +37,7 @@ public class PwEntryTest extends AndroidTestCase {
protected void setUp() throws Exception {
super.setUp();
mPE = TestData.GetTest1(getContext()).entries.get(0);
mPE = (PwEntryV3) TestData.GetTest1(getContext()).entries.get(0);
}
@@ -49,7 +49,7 @@ public class PwEntryTest extends AndroidTestCase {
String sPass = "12345";
byte[] password = sPass.getBytes("UTF-8");
assertArrayEquals(password, mPE.getPassword());
assertArrayEquals(password, mPE.getPasswordBytes());
}
public void testCreation() {

View File

@@ -33,7 +33,7 @@ public class PwGroupTest extends AndroidTestCase {
protected void setUp() throws Exception {
super.setUp();
mPG = TestData.GetTest1(getContext()).groups.get(0);
mPG = (PwGroupV3) TestData.GetTest1(getContext()).getGroups().get(0);
}

View File

@@ -21,13 +21,13 @@ package com.keepassdroid.tests.database;
import java.util.Vector;
import android.content.Context;
import android.test.AndroidTestCase;
import com.keepassdroid.Database;
import com.keepassdroid.database.PwDatabaseV3;
import com.keepassdroid.database.PwEntryV3;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.PwGroupV3;
import com.keepassdroid.database.edit.DeleteGroup;
import com.keepassdroid.search.SearchDbHelper;
@@ -54,8 +54,8 @@ public class DeleteEntry extends AndroidTestCase {
return;
}
PwGroupV3 group1 = getGroup(db.pm, GROUP1_NAME);
PwDatabaseV3 pm = (PwDatabaseV3) db.pm;
PwGroup group1 = getGroup(pm, GROUP1_NAME);
assertNotNull("Could not find group1", group1);
// Delete the group
@@ -63,10 +63,10 @@ public class DeleteEntry extends AndroidTestCase {
task.run();
// Verify the entries were deleted
PwEntryV3 entry1 = getEntry(db.pm, ENTRY1_NAME);
PwEntry entry1 = getEntry(pm, ENTRY1_NAME);
assertNull("Entry 1 was not removed", entry1);
PwEntryV3 entry2 = getEntry(db.pm, ENTRY2_NAME);
PwEntry entry2 = getEntry(pm, ENTRY2_NAME);
assertNull("Entry 2 was not removed", entry2);
// Verify the entries were removed from the search index
@@ -80,17 +80,17 @@ public class DeleteEntry extends AndroidTestCase {
assertEquals("Entry2 was not removed from the search results", 0, results2.childEntries.size());
// Verify the group was deleted
group1 = getGroup(db.pm, GROUP1_NAME);
group1 = getGroup(pm, GROUP1_NAME);
assertNull("Group 1 was not removed.", group1);
}
private PwEntryV3 getEntry(PwDatabaseV3 pm, String name) {
Vector<PwEntryV3> entries = pm.entries;
private PwEntry getEntry(PwDatabaseV3 pm, String name) {
Vector<PwEntry> entries = pm.entries;
for ( int i = 0; i < entries.size(); i++ ) {
PwEntryV3 entry = entries.get(i);
PwEntry entry = entries.get(i);
if ( entry.title.equals(name) ) {
return entry;
}
@@ -100,11 +100,11 @@ public class DeleteEntry extends AndroidTestCase {
}
private PwGroupV3 getGroup(PwDatabaseV3 pm, String name) {
Vector<PwGroupV3> groups = pm.groups;
private PwGroup getGroup(PwDatabaseV3 pm, String name) {
Vector<PwGroup> groups = pm.getGroups();
for ( int i = 0; i < groups.size(); i++ ) {
PwGroupV3 group = groups.get(i);
if ( group.name.equals(name) ) {
PwGroup group = groups.get(i);
if ( group.getName().equals(name) ) {
return group;
}
}

View File

@@ -44,6 +44,9 @@ public class Kdb4 extends AndroidTestCase {
return;
}
is.close();
assertTrue(false);
}

View File

@@ -44,7 +44,7 @@ public class Kdb4Header extends AndroidTestCase {
assertTrue(db.dataCipher.equals(CipherFactory.AES_CIPHER));
am.close();
is.close();
}
}

View File

@@ -65,6 +65,6 @@ public class TestData {
GetDb1(ctx);
}
return mDb1.pm;
return (PwDatabaseV3) mDb1.pm;
}
}

View File

@@ -37,7 +37,7 @@ import com.keepassdroid.database.PwDatabaseV3;
import com.keepassdroid.database.PwDbHeader;
import com.keepassdroid.database.PwDbHeaderV3;
import com.keepassdroid.database.exception.PwDbOutputException;
import com.keepassdroid.database.save.PwDbHeaderOutput;
import com.keepassdroid.database.save.PwDbHeaderOutputV3;
import com.keepassdroid.database.save.PwDbV3Output;
import com.keepassdroid.stream.NullOutputStream;
import com.keepassdroid.tests.database.TestData;
@@ -99,7 +99,7 @@ public class PwManagerOutputTest extends AndroidTestCase {
PwDbHeaderV3 header = pActual.outputHeader(bActual);
ByteArrayOutputStream bExpected = new ByteArrayOutputStream();
PwDbHeaderOutput outExpected = new PwDbHeaderOutput(mPM.dbHeader, bExpected);
PwDbHeaderOutputV3 outExpected = new PwDbHeaderOutputV3(mPM.dbHeader, bExpected);
outExpected.output();
assertHeadersEquals(mPM.dbHeader, header);