mirror of
https://github.com/moparisthebest/keepass2android
synced 2024-11-11 20:15:04 -05:00
a671c4f241
-> + Tests First, very simple implementation of ChangingFileStorage in KP2A App (preliminary)
370 lines
12 KiB
C#
370 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using Android.App;
|
|
using Android.OS;
|
|
using KeePassLib;
|
|
using KeePassLib.Keys;
|
|
using KeePassLib.Serialization;
|
|
using KeePassLib.Utility;
|
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
using keepass2android;
|
|
|
|
namespace Kp2aUnitTests
|
|
{
|
|
[TestClass]
|
|
class TestSaveDb: TestBase
|
|
{
|
|
private string newFilename;
|
|
|
|
[TestMethod]
|
|
public void TestLoadEditSave()
|
|
{
|
|
//create the default database:
|
|
IKp2aApp app = SetupAppWithDefaultDatabase();
|
|
IOConnection.DeleteFile(new IOConnectionInfo { Path = DefaultFilename });
|
|
//save it and reload it so we have a base version
|
|
SaveDatabase(app);
|
|
app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
|
//modify the database by adding a group:
|
|
app.GetDb().KpDatabase.RootGroup.AddGroup(new PwGroup(true, true, "TestGroup", PwIcon.Apple), true);
|
|
//save the database again:
|
|
SaveDatabase(app);
|
|
|
|
//load database to a new app instance:
|
|
IKp2aApp resultApp = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
|
|
|
//ensure the change was saved:
|
|
AssertDatabasesAreEqual(app.GetDb().KpDatabase, resultApp.GetDb().KpDatabase);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestLoadEditSaveWithSync()
|
|
{
|
|
TestSync(DefaultFilename);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestLoadEditSaveWithSyncKdbp()
|
|
{
|
|
TestSync(DefaultDirectory+"savetest.kdbp");
|
|
}
|
|
|
|
|
|
private void TestSync(string filename)
|
|
{
|
|
//create the default database:
|
|
IKp2aApp app = SetupAppWithDatabase(filename);
|
|
//save it and reload it so we have a base version
|
|
SaveDatabase(app);
|
|
app = LoadDatabase(filename, DefaultPassword, DefaultKeyfile);
|
|
//load it once again:
|
|
IKp2aApp app2 = LoadDatabase(filename, DefaultPassword, DefaultKeyfile);
|
|
|
|
//modify the database by adding a group in both databases:
|
|
app.GetDb().KpDatabase.RootGroup.AddGroup(new PwGroup(true, true, "TestGroup", PwIcon.Apple), true);
|
|
var group2 = new PwGroup(true, true, "TestGroup2", PwIcon.Energy);
|
|
app2.GetDb().KpDatabase.RootGroup.AddGroup(group2, true);
|
|
//save the database from app 1:
|
|
SaveDatabase(app);
|
|
|
|
((TestKp2aApp) app2).SetYesNoCancelResult(TestKp2aApp.YesNoCancelResult.Yes);
|
|
|
|
//save the database from app 2: This save operation must detect the changes made from app 1 and ask if it should sync:
|
|
SaveDatabase(app2);
|
|
|
|
//make sure the right question was asked
|
|
Assert.AreEqual(UiStringKey.TitleSyncQuestion, ((TestKp2aApp) app2).LastYesNoCancelQuestionTitle);
|
|
|
|
//add group 2 to app 1:
|
|
app.GetDb().KpDatabase.RootGroup.AddGroup(group2, true);
|
|
|
|
//load database to a new app instance:
|
|
IKp2aApp resultApp = LoadDatabase(filename, DefaultPassword, DefaultKeyfile);
|
|
|
|
//ensure the sync was successful:
|
|
AssertDatabasesAreEqual(app.GetDb().KpDatabase, resultApp.GetDb().KpDatabase);
|
|
}
|
|
|
|
|
|
[TestMethod]
|
|
public void TestLoadEditSaveWithSyncOverwrite()
|
|
{
|
|
//create the default database:
|
|
IKp2aApp app = SetupAppWithDefaultDatabase();
|
|
//save it and reload it so we have a base version
|
|
SaveDatabase(app);
|
|
app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
|
//load it once again:
|
|
IKp2aApp app2 = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
|
|
|
//modify the database by adding a group in both databases:
|
|
app.GetDb().KpDatabase.RootGroup.AddGroup(new PwGroup(true, true, "TestGroup", PwIcon.Apple), true);
|
|
var group2 = new PwGroup(true, true, "TestGroup2", PwIcon.Energy);
|
|
app2.GetDb().KpDatabase.RootGroup.AddGroup(group2, true);
|
|
//save the database from app 1:
|
|
SaveDatabase(app);
|
|
|
|
//the user clicks the "no" button when asked if the sync should be performed -> overwrite expected!
|
|
((TestKp2aApp)app2).SetYesNoCancelResult(TestKp2aApp.YesNoCancelResult.No);
|
|
|
|
//save the database from app 2: This save operation must detect the changes made from app 1 and ask if it should sync:
|
|
SaveDatabase(app2);
|
|
|
|
//make sure the right question was asked
|
|
Assert.AreEqual(UiStringKey.TitleSyncQuestion, ((TestKp2aApp)app2).LastYesNoCancelQuestionTitle);
|
|
|
|
//load database to a new app instance:
|
|
IKp2aApp resultApp = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
|
|
|
//ensure the sync was NOT performed (overwrite expected!):
|
|
AssertDatabasesAreEqual(app2.GetDb().KpDatabase, resultApp.GetDb().KpDatabase);
|
|
|
|
}
|
|
|
|
|
|
[TestMethod]
|
|
public void TestLoadEditSaveWithWriteBecauseTargetNotExists()
|
|
{
|
|
//create the default database:
|
|
IKp2aApp app = SetupAppWithDefaultDatabase();
|
|
//save it and reload it so we have a base version
|
|
SaveDatabase(app);
|
|
app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
|
|
|
//modify the database by adding a group:
|
|
app.GetDb().KpDatabase.RootGroup.AddGroup(new PwGroup(true, true, "TestGroup", PwIcon.Apple), true);
|
|
|
|
//delete the file:
|
|
File.Delete(DefaultFilename);
|
|
|
|
//save the database:
|
|
SaveDatabase(app);
|
|
|
|
//make sure no question was asked
|
|
Assert.AreEqual(null, ((TestKp2aApp)app).LastYesNoCancelQuestionTitle);
|
|
|
|
//load database to a new app instance:
|
|
IKp2aApp resultApp = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
|
|
|
//ensure the file was saved:
|
|
AssertDatabasesAreEqual(app.GetDb().KpDatabase, resultApp.GetDb().KpDatabase);
|
|
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestLoadEditSaveWithSyncOverwriteBecauseOfNoCheck()
|
|
{
|
|
//create the default database:
|
|
IKp2aApp app = SetupAppWithDefaultDatabase();
|
|
//save it and reload it so we have a base version
|
|
SaveDatabase(app);
|
|
app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
|
//load it once again:
|
|
IKp2aApp app2 = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
|
|
|
//modify the database by adding a group in both databases:
|
|
app.GetDb().KpDatabase.RootGroup.AddGroup(new PwGroup(true, true, "TestGroup", PwIcon.Apple), true);
|
|
var group2 = new PwGroup(true, true, "TestGroup2", PwIcon.Energy);
|
|
app2.GetDb().KpDatabase.RootGroup.AddGroup(group2, true);
|
|
//save the database from app 1:
|
|
SaveDatabase(app);
|
|
|
|
//the user doesn't want to perform check for file change:
|
|
((TestKp2aApp) app2).SetPreference(PreferenceKey.CheckForFileChangesOnSave, false);
|
|
|
|
//save the database from app 2: This save operation must detect the changes made from app 1 and ask if it should sync:
|
|
SaveDatabase(app2);
|
|
|
|
//make sure no question was asked
|
|
Assert.AreEqual(null, ((TestKp2aApp)app2).LastYesNoCancelQuestionTitle);
|
|
|
|
//load database to a new app instance:
|
|
IKp2aApp resultApp = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
|
|
|
//ensure the sync was NOT performed (overwrite expected!):
|
|
AssertDatabasesAreEqual(app2.GetDb().KpDatabase, resultApp.GetDb().KpDatabase);
|
|
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestLoadEditSaveWithSyncCancel()
|
|
{
|
|
//create the default database:
|
|
IKp2aApp app = SetupAppWithDefaultDatabase();
|
|
//save it and reload it so we have a base version
|
|
SaveDatabase(app);
|
|
app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
|
//load it once again:
|
|
IKp2aApp app2 = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
|
|
|
//modify the database by adding a group in both databases:
|
|
app.GetDb().KpDatabase.RootGroup.AddGroup(new PwGroup(true, true, "TestGroup", PwIcon.Apple), true);
|
|
var group2 = new PwGroup(true, true, "TestGroup2", PwIcon.Energy);
|
|
app2.GetDb().KpDatabase.RootGroup.AddGroup(group2, true);
|
|
//save the database from app 1:
|
|
SaveDatabase(app);
|
|
|
|
//the user clicks the "cancel" button when asked if the sync should be performed
|
|
((TestKp2aApp)app2).SetYesNoCancelResult(TestKp2aApp.YesNoCancelResult.Cancel);
|
|
|
|
//save the database from app 2: This save operation must detect the changes made from app 1 and ask if it should sync:
|
|
Assert.AreEqual(false, TrySaveDatabase(app2));
|
|
|
|
//make sure the right question was asked
|
|
Assert.AreEqual(UiStringKey.TitleSyncQuestion, ((TestKp2aApp)app2).LastYesNoCancelQuestionTitle);
|
|
|
|
//load database to a new app instance:
|
|
IKp2aApp resultApp = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
|
|
|
//ensure the sync was NOT performed (cancel expected!):
|
|
AssertDatabasesAreEqual(app.GetDb().KpDatabase, resultApp.GetDb().KpDatabase);
|
|
|
|
}
|
|
|
|
|
|
[TestMethod]
|
|
public void TestLoadEditSaveWithSyncConflict()
|
|
{
|
|
|
|
//create the default database:
|
|
IKp2aApp app = SetupAppWithDefaultDatabase();
|
|
//save it and reload it so we have a base version
|
|
SaveDatabase(app);
|
|
app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
|
//load it once again:
|
|
IKp2aApp app2 = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
|
|
|
|
//modify the database by renaming the same group in both databases:
|
|
app.GetDb().KpDatabase.RootGroup.Groups.Single(g => g.Name == "Internet").Name += "abc";
|
|
app2.GetDb().KpDatabase.RootGroup.Groups.Single(g => g.Name == "Internet").Name += "abcde";
|
|
//app1 also changes the master password:
|
|
var compositeKey = app.GetDb().KpDatabase.MasterKey;
|
|
compositeKey.RemoveUserKey(compositeKey.GetUserKey(typeof (KcpPassword)));
|
|
compositeKey.AddUserKey(new KcpPassword("abc"));
|
|
|
|
//save the database from app 1:
|
|
SaveDatabase(app);
|
|
|
|
|
|
((TestKp2aApp)app2).SetYesNoCancelResult(TestKp2aApp.YesNoCancelResult.Yes);
|
|
|
|
//save the database from app 2: This save operation must fail because the target file cannot be loaded:
|
|
Assert.IsFalse(TrySaveDatabase(app2));
|
|
|
|
//make sure the right question was asked
|
|
Assert.AreEqual(UiStringKey.TitleSyncQuestion, ((TestKp2aApp)app2).LastYesNoCancelQuestionTitle);
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
[TestMethod]
|
|
public void TestSaveAsWhenReadOnly()
|
|
{
|
|
Assert.Fail("TODO: Test ");
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestSaveAsWhenSyncError()
|
|
{
|
|
Assert.Fail("TODO: Test ");
|
|
}*/
|
|
|
|
[TestMethod]
|
|
public void TestLoadAndSave_TestIdenticalFiles()
|
|
{
|
|
IKp2aApp app = LoadDatabase(DefaultDirectory + "complexDb.kdbx", "test", null);
|
|
var kdbxXml = DatabaseToXml(app);
|
|
|
|
newFilename = TestDbDirectory + "tmp_complexDb.kdbx";
|
|
if (File.Exists(newFilename))
|
|
File.Delete(newFilename);
|
|
app.GetDb().KpDatabase.IOConnectionInfo.Path = newFilename;
|
|
app.GetDb().SaveData(Application.Context);
|
|
|
|
|
|
IKp2aApp appReloaded = LoadDatabase(newFilename, "test", null);
|
|
|
|
var kdbxReloadedXml = DatabaseToXml(appReloaded);
|
|
|
|
Assert.AreEqual(kdbxXml,kdbxReloadedXml);
|
|
|
|
|
|
|
|
}
|
|
|
|
[TestMethod]
|
|
public void TestLoadKdbxAndSaveKdbp_TestIdenticalFiles()
|
|
{
|
|
IKp2aApp app = LoadDatabase(DefaultDirectory + "complexDb.kdbx", "test", null);
|
|
//string kdbxXml = DatabaseToXml(app);
|
|
|
|
newFilename = TestDbDirectory + "tmp_complexDb.kdbp";
|
|
if (File.Exists(newFilename))
|
|
File.Delete(newFilename);
|
|
app.GetDb().KpDatabase.IOConnectionInfo.Path = newFilename;
|
|
app.GetDb().SaveData(Application.Context);
|
|
|
|
|
|
IKp2aApp appReloaded = LoadDatabase(newFilename, "test", null);
|
|
/*
|
|
* Unfortunately we cannot compare the xml because there are slight differences:
|
|
* - the order of ProtectedStrings in the xml is different (which is ok)
|
|
* - the CustomIconUuids are serialized as Zeros instead of not being serialized (which is ok as well)
|
|
string kdbxReloadedXml = DatabaseToXml(appReloaded);
|
|
|
|
bool areEqual = kdbxXml.Equals(kdbxReloadedXml);
|
|
|
|
if (!areEqual)
|
|
{
|
|
using (StreamWriter w1 = File.CreateText(TestDbDirectory + "FromOriginalKdbx.xml"))
|
|
{
|
|
w1.Write(kdbxXml);
|
|
}
|
|
using (StreamWriter w2 = File.CreateText(TestDbDirectory + "FromKdbp.xml"))
|
|
{
|
|
w2.Write(kdbxReloadedXml);
|
|
}
|
|
|
|
}
|
|
Assert.IsTrue(areEqual, "reloaded->xml differs from loaded->xml");
|
|
*/
|
|
AssertDatabasesAreEqual(app.GetDb().KpDatabase, appReloaded.GetDb().KpDatabase);
|
|
|
|
|
|
|
|
}
|
|
|
|
private class OnCloseToStringMemoryStream : MemoryStream
|
|
{
|
|
public string Text { get; private set; }
|
|
private bool _closed;
|
|
public override void Close()
|
|
{
|
|
if (!_closed)
|
|
{
|
|
Position = 0;
|
|
Text = new StreamReader(this).ReadToEnd();
|
|
}
|
|
base.Close();
|
|
_closed = true;
|
|
|
|
}
|
|
}
|
|
|
|
private static string DatabaseToXml(IKp2aApp app)
|
|
{
|
|
KdbxFile kdb = new KdbxFile(app.GetDb().KpDatabase);
|
|
var sOutput = new OnCloseToStringMemoryStream();
|
|
kdb.Save(sOutput, app.GetDb().KpDatabase.RootGroup, KdbxFormat.PlainXml, null);
|
|
return sOutput.Text;
|
|
}
|
|
}
|
|
|
|
|
|
}
|