public void TestReadOnlyDb() { CreateDocuments(database, 10); database.Close(); var options = new ManagerOptions(); options.ReadOnly = true; var readOnlyManager = new Manager(new DirectoryInfo(manager.Directory), options); database = readOnlyManager.GetExistingDatabase(database.Name); Assert.IsNotNull(database); var e = Assert.Throws <CouchbaseLiteException>(() => CreateDocuments(database, 1)); Assert.AreEqual(StatusCode.Forbidden, e.Code); database.Close(); var dbOptions = new DatabaseOptions(); dbOptions.ReadOnly = true; database = manager.OpenDatabase(database.Name, dbOptions); Assert.IsNotNull(database); e = Assert.Throws <CouchbaseLiteException>(() => CreateDocuments(database, 1)); Assert.AreEqual(StatusCode.Forbidden, e.Code); database.Close(); dbOptions.ReadOnly = false; database = manager.OpenDatabase(database.Name, dbOptions); Assert.DoesNotThrow(() => CreateDocuments(database, 1)); }
public void TestUnencryptedDB() { // Create unencrypted DB: var options = new DatabaseOptions(); options.Create = true; var seekrit = manager.OpenDatabase("seekrit", options); Assert.IsNotNull(seekrit, "Failed to create db"); CreateDocumentWithProperties(seekrit, new Dictionary<string, object> { { "answer", 42 } }); Assert.DoesNotThrow(() => seekrit.Close().Wait(15000)); var key = new SymmetricKey(_wrong.KeyData); options.EncryptionKey = key; var e = Assert.Throws<CouchbaseLiteException>(() => seekrit = manager.OpenDatabase("seekrit", options), "Shouldn't have been able to reopen encrypted db with wrong password"); Assert.AreEqual(StatusCode.Unauthorized, e.Code); seekrit.ChangeEncryptionKey(null); options.EncryptionKey = null; seekrit = manager.OpenDatabase("seekrit", options); Assert.IsNotNull(seekrit, "Failed to reopen db"); Assert.AreEqual(1, seekrit.GetDocumentCount()); }
internal DatabaseOptions DefaultOptionsFor(string dbName) { var options = new DatabaseOptions(); var encryptionKey = default(SymmetricKey); if (Shared.TryGetValue("encryptionKey", "", dbName, out encryptionKey)) { options.EncryptionKey = encryptionKey; } return(options); }
public void TestUpgradeDatabase() { // Install a canned database: using (var dbStream = GetAsset("ios120.zip")) { Assert.DoesNotThrow(() => manager.ReplaceDatabase("replacedb", dbStream, true)); } // Open installed db with storageType set to this test's storage type: var options = new DatabaseOptions(); options.StorageType = _storageType; var replacedb = default(Database); Assert.DoesNotThrow(() => replacedb = manager.OpenDatabase("replacedb", options)); Assert.IsNotNull(replacedb); // Verify storage type matches what we requested: Assert.IsInstanceOf(database.Storage.GetType(), replacedb.Storage); // Test db contents: CheckRowsOfReplacedDB("replacedb", rows => { Assert.AreEqual(1, rows.Count); var doc = rows.ElementAt(0).Document; Assert.AreEqual("doc1", doc.Id); Assert.AreEqual(2, doc.CurrentRevision.Attachments.Count()); var att1 = doc.CurrentRevision.GetAttachment("attach1"); Assert.IsNotNull(att1); Assert.AreEqual(att1.Length, att1.Content.Count()); var att2 = doc.CurrentRevision.GetAttachment("attach2"); Assert.IsNotNull(att2); Assert.AreEqual(att2.Length, att2.Content.Count()); }); // Close and re-open the db using SQLite storage type. Should fail if it used to be ForestDB: Assert.DoesNotThrow(() => replacedb.Close().Wait(15000)); options.StorageType = StorageEngineTypes.SQLite; if (_storageType == StorageEngineTypes.SQLite) { Assert.DoesNotThrow(() => replacedb = manager.OpenDatabase("replacedb", options)); Assert.IsNotNull(replacedb); } else { var e = Assert.Throws <CouchbaseLiteException>(() => replacedb = manager.OpenDatabase("replacedb", options)); Assert.AreEqual(StatusCode.InvalidStorageType, e.Code); } }
public void TestEncryptedDB() { var options = new DatabaseOptions(); options.Create = true; options.EncryptionKey = _letmein; var seekrit = default(Database); Assert.DoesNotThrow(() => seekrit = manager.OpenDatabase("seekrit", options), "Failed to create encrypted DB"); CreateDocumentWithProperties(seekrit, new Dictionary <string, object> { { "answer", 42 } }); Assert.DoesNotThrow(() => seekrit.Close().Wait(15000)); // Try to reopen without the password (fails): options.EncryptionKey = null; var e = Assert.Throws <CouchbaseLiteException>(() => seekrit = manager.OpenDatabase("seekrit", options), "Shouldn't have been able to reopen encrypted db with wrong password"); Assert.AreEqual(StatusCode.Unauthorized, e.Code); // Try to reopen with wrong password (fails): options.EncryptionKey = _wrong; e = Assert.Throws <CouchbaseLiteException>(() => seekrit = manager.OpenDatabase("seekrit", options), "Shouldn't have been able to reopen encrypted db with wrong password"); Assert.AreEqual(StatusCode.Unauthorized, e.Code); // Reopen with correct password: options.EncryptionKey = _letmein; seekrit = manager.OpenDatabase("seekrit", options); Assert.IsNotNull(seekrit, "Failed to reopen encrypted db"); Assert.AreEqual(1, seekrit.GetDocumentCount()); seekrit.ChangeEncryptionKey(null); var dbName = seekrit.Name; Assert.DoesNotThrow(() => seekrit.Close().Wait(15000), "Couldn't close seekrit"); seekrit = null; options.EncryptionKey = null; seekrit = manager.OpenDatabase("seekrit", options); Assert.IsNotNull(seekrit, "Failed to reopen encrypted db"); Assert.AreEqual(1, seekrit.GetDocumentCount()); seekrit.Dispose(); }
public void TestCompactEncryptedDatabase() { var options = new DatabaseOptions(); options.Create = true; options.EncryptionKey = _letmein; var seekrit = default(Database); Assert.DoesNotThrow(() => seekrit = manager.OpenDatabase("seekrit", options), "Failed to create encrypted DB"); // Create a doc and then update it: var doc = CreateDocumentWithProperties(seekrit, new Dictionary <string, object> { { "answer", 42 } }); doc.Update(rev => { var props = rev.UserProperties; props["foo"] = 84; rev.SetUserProperties(props); return(true); }); // Compact: Assert.IsTrue(seekrit.Compact()); doc.Update(rev => { var props = rev.UserProperties; props["foo"] = 85; rev.SetUserProperties(props); return(true); }); // Close and re-open: Assert.DoesNotThrow(() => seekrit.Close().Wait(15000), "Close failed"); Assert.DoesNotThrow(() => seekrit = manager.OpenDatabase("seekrit", options), "Failed to reopen encrypted db"); Assert.AreEqual(1, seekrit.GetDocumentCount()); }
/// <summary> /// Returns the database with the given name. If the database is not yet open, the options given /// will be applied; if it's already open, the options are ignored. /// Multiple calls with the same name will return the same CBLDatabase instance. /// </summary> /// <param name="name">The name of the database. May NOT contain capital letters!</param> /// <param name="options">ptions to use when opening, such as the encryption key; if nil, a default /// set of options will be used.</param> /// <returns>The opened database, or null if it doesn't exist and options.Create is false</returns> /// <exception cref="Couchbase.Lite.CouchbaseLiteException">Thrown if an error occurs opening /// the database</exception> public Database OpenDatabase(string name, DatabaseOptions options) { if (name == null) { throw new ArgumentNullException("name"); } if (options == null) { options = new DatabaseOptions(); } var db = GetDatabase(name, !options.Create); if (db != null && !db.IsOpen) { db.OpenWithOptions(options); Shared.SetValue("encryptionKey", "", name, options.EncryptionKey); } return(db); }
public void TestDeleteEncryptedDatabase() { var options = new DatabaseOptions(); options.Create = true; options.EncryptionKey = _letmein; var seekrit = default(Database); Assert.DoesNotThrow(() => seekrit = manager.OpenDatabase("seekrit", options), "Failed to create encrypted DB"); CreateDocumentWithProperties(seekrit, new Dictionary <string, object> { { "answer", 42 } }); // Delete db; this also unregisters its password: Assert.DoesNotThrow(seekrit.Delete); // Re-create database: options.EncryptionKey = null; Assert.DoesNotThrow(() => seekrit = manager.OpenDatabase("seekrit", options), "Failed to re-create formerly encrypted db"); Assert.AreEqual(0, seekrit.GetDocumentCount()); Assert.DoesNotThrow(() => seekrit.Close().Wait(15000)); // Make sure it doesn't need a password now: Assert.DoesNotThrow(() => seekrit = manager.OpenDatabase("seekrit", options), "Failed to re-create formerly encrypted db"); Assert.AreEqual(0, seekrit.GetDocumentCount()); Assert.DoesNotThrow(() => seekrit.Close().Wait(15000)); // Make sure old password doesn't work: options.EncryptionKey = _letmein; var e = Assert.Throws <CouchbaseLiteException>(() => seekrit = manager.OpenDatabase("seekrit", options), "Password opened unencrypted db or unexpected exception occurred!"); Assert.AreEqual(StatusCode.Unauthorized, e.Code); }
public void TestEncryptedAttachments() { var options = new DatabaseOptions(); options.Create = true; options.EncryptionKey = _letmein; var seekrit = default(Database); Assert.DoesNotThrow(() => seekrit = manager.OpenDatabase("seekrit", options), "Failed to create encrypted DB"); // Save a doc with an attachment: var doc = seekrit.GetDocument("att"); var body = Encoding.UTF8.GetBytes("This is a test attachment!"); var rev = doc.CreateRevision(); rev.SetAttachment("att.txt", "text/plain; charset=utf-8", body); var savedRev = rev.Save(); Assert.IsNotNull(savedRev, "Saving doc failed"); // Read the raw attachment file and make sure it's not cleartext: var digest = savedRev.GetProperty("_attachments").AsDictionary <string, object>().Get("att.txt") .AsDictionary <string, object>().GetCast <string>("digest"); Assert.IsNotNull(digest); var attKey = default(BlobKey); Assert.DoesNotThrow(() => attKey = new BlobKey(digest)); var path = seekrit.Attachments.PathForKey(attKey); var raw = File.ReadAllBytes(path); Assert.IsNotNull(raw); Assert.AreNotEqual(raw, body, "Oops, attachment was not encrypted"); seekrit.Dispose(); }
public void TestRekey() { // First run the encrypted-attachments test to populate the db: TestEncryptedAttachments(); var options = new DatabaseOptions(); options.Create = true; options.EncryptionKey = _letmein; var seekrit = default(Database); Assert.DoesNotThrow(() => seekrit = manager.OpenDatabase("seekrit", options), "Failed to create encrypted DB"); CreateDocuments(seekrit, 100); var view = seekrit.GetView("vu"); view.SetMap((doc, emit) => { if (doc.ContainsKey("sequence")) { emit(doc["sequence"], null); } }, "1"); var query = view.CreateQuery(); Assert.AreEqual(100, query.Run().Count); Assert.DoesNotThrow(() => seekrit.ChangeEncryptionKey(_letmeout), "Error changing encryption key"); // Close & reopen seekrit: var dbName = seekrit.Name; Assert.DoesNotThrow(() => seekrit.Close().Wait(15000), "Couldn't close seekrit"); seekrit = null; options.EncryptionKey = _letmeout; var seekrit2 = default(Database); Assert.DoesNotThrow(() => seekrit2 = manager.OpenDatabase(dbName, options)); seekrit = seekrit2; // Check the document and its attachment: var savedRev = seekrit.GetDocument("att").CurrentRevision; Assert.IsNotNull(savedRev); var att = savedRev.GetAttachment("att.txt"); Assert.IsNotNull(att); var body = Encoding.UTF8.GetBytes("This is a test attachment!"); Assert.AreEqual(body, att.Content); view = seekrit.GetExistingView("vu"); Assert.IsNotNull(view); view.SetMap((doc, emit) => { if (doc.ContainsKey("sequence")) { emit(doc["sequence"], null); } }, "1"); query = view.CreateQuery(); query.IndexUpdateMode = IndexUpdateMode.Never; // Ensure that the previous results survived // Check that the view survived: Assert.AreEqual(100, query.Run().Count); seekrit.Dispose(); }
public void TestUpgradeDatabase() { // Install a canned database: using (var dbStream = GetAsset("ios120.zip")) { Assert.DoesNotThrow(() => manager.ReplaceDatabase("replacedb", dbStream, true)); } // Open installed db with storageType set to this test's storage type: var options = new DatabaseOptions(); options.StorageType = _storageType; var replacedb = default(Database); Assert.DoesNotThrow(() => replacedb = manager.OpenDatabase("replacedb", options)); Assert.IsNotNull(replacedb); // Verify storage type matches what we requested: Assert.IsInstanceOf(database.Storage.GetType(), replacedb.Storage); // Test db contents: CheckRowsOfReplacedDB("replacedb", rows => { Assert.AreEqual(1, rows.Count); var doc = rows.ElementAt(0).Document; Assert.AreEqual("doc1", doc.Id); Assert.AreEqual(2, doc.CurrentRevision.Attachments.Count()); var att1 = doc.CurrentRevision.GetAttachment("attach1"); Assert.IsNotNull(att1); Assert.AreEqual(att1.Length, att1.Content.Count()); var att2 = doc.CurrentRevision.GetAttachment("attach2"); Assert.IsNotNull(att2); Assert.AreEqual(att2.Length, att2.Content.Count()); }); // Close and re-open the db using SQLite storage type. Should fail if it used to be ForestDB: Assert.DoesNotThrow(() => replacedb.Close().Wait(15000)); options.StorageType = StorageEngineTypes.SQLite; if (_storageType == StorageEngineTypes.SQLite) { Assert.DoesNotThrow(() => replacedb = manager.OpenDatabase("replacedb", options)); Assert.IsNotNull(replacedb); } else { var e = Assert.Throws<CouchbaseLiteException>(() => replacedb = manager.OpenDatabase("replacedb", options)); Assert.AreEqual(StatusCode.InvalidStorageType, e.Code); } }
protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); RequestWindowFeature(WindowFeatures.IndeterminateProgress); var opts = new DatabaseOptions(); opts.Create = true; // To use this feature, add the Couchbase.Lite.Storage.ForestDB nuget package //opts.StorageType = StorageEngineTypes.ForestDB; // To use this feature add the Couchbase.Lite.Storage.SQLCipher nuget package, // or uncomment the above line and add the Couchbase.Lite.Storage.ForestDB package //opts.EncryptionKey = new SymmetricKey("foo"); Database = Manager.SharedInstance.OpenDatabase(Tag.ToLower(), opts); Query = List.GetQuery(Database); Query.Completed += (sender, e) => Log.Verbose("MainActivity", e.ErrorInfo.ToString() ?? e.Rows.ToString()); LiveQuery = Query.ToLiveQuery(); var layout = new LinearLayout(this); layout.LayoutParameters = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent); layout.Orientation = Orientation.Vertical; // Allow user to add Items. var newItemText = new EditText(this) { // Ensure we get a 'done' key instead of carriage return. InputType = Android.Text.InputTypes.ClassText }; newItemText.LayoutParameters = new LinearLayout.LayoutParams( ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent); newItemText.KeyPress += (sender, e) => { e.Handled = false; if (e.KeyCode == Keycode.Enter) { if (e.Event.Action == KeyEventActions.Down && newItemText.Text.Length > 0) { AddItem(newItemText.Text); } newItemText.Text = ""; } e.Handled = false; }; layout.AddView(newItemText); // Create our table listView = new ListView(this); listView.LayoutParameters = new LinearLayout.LayoutParams( ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent); listView.Adapter = new ListLiveQueryAdapter(this, LiveQuery); layout.AddView(listView); SetContentView (layout); }
internal void OpenWithOptions(DatabaseOptions options) { if(IsOpen) { return; } Log.To.Database.I(TAG, "Opening {0}", this); _readonly = _readonly || options.ReadOnly; // Instantiate storage: string storageType = options.StorageType ?? Manager.StorageType ?? StorageEngineTypes.SQLite; var primaryStorage = GetStorageClass(storageType); if(primaryStorage == null) { if(storageType == StorageEngineTypes.SQLite) { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.InvalidStorageType, TAG, "No implementation found for SQLite storage. For more information, see " + "https://github.com/couchbase/couchbase-lite-net/wiki/Error-Dictionary#cblcs0001"); } else { throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.InvalidStorageType, TAG, "No implementation found for ForestDB storage. For more information, see " + "https://github.com/couchbase/couchbase-lite-net/wiki/Error-Dictionary#cblcs0002"); } } var upgrade = false; var primarySQLite = storageType == StorageEngineTypes.SQLite; var otherStorage = primarySQLite ? GetStorageClass(StorageEngineTypes.ForestDB) : GetStorageClass(StorageEngineTypes.SQLite); var primaryStorageInstance = (ICouchStore)Activator.CreateInstance(primaryStorage); var otherStorageInstance = otherStorage != null ? (ICouchStore)Activator.CreateInstance(otherStorage) : null; if(options.StorageType != null) { // If explicit storage type given in options, always use primary storage type, // and if secondary db exists, try to upgrade from it: upgrade = otherStorageInstance != null && otherStorageInstance.DatabaseExistsIn(DbDirectory) && !primaryStorageInstance.DatabaseExistsIn(DbDirectory); if(upgrade && primarySQLite) { throw Misc.CreateExceptionAndLog(Log.To.Upgrade, StatusCode.InvalidStorageType, TAG, "Upgrades from ForestDB to SQLite are not supported. For more information see " + "https://github.com/couchbase/couchbase-lite-net/wiki/Error-Dictionary#cbldb0001"); } } else { // If options don't specify, use primary unless secondary db already exists in dir: if(otherStorageInstance != null && otherStorageInstance.DatabaseExistsIn(DbDirectory)) { primaryStorageInstance = otherStorageInstance; } } Log.To.Database.I(TAG, "Using {0} for db at {1}; upgrade={2}", primaryStorage.FullName, DbDirectory, upgrade); Storage = primaryStorageInstance; Storage.Delegate = this; Storage.AutoCompact = AUTO_COMPACT; // Encryption: var encryptionKey = options.EncryptionKey; if(encryptionKey != null) { Storage.SetEncryptionKey(encryptionKey); } // Open the storage! try { Storage.Open(DbDirectory, Manager, _readonly); } catch(CouchbaseLiteException) { Storage.Close(); Log.To.Database.E(TAG, "Failed to open storage for database, rethrowing..."); throw; } catch(Exception e) { Storage.Close(); throw Misc.CreateExceptionAndLog(Log.To.Database, e, TAG, "Got exception while opening storage for database"); } // First-time setup: if(PrivateUUID() == null) { Storage.SetInfo("privateUUID", Misc.CreateGUID()); Storage.SetInfo("publicUUID", Misc.CreateGUID()); } var savedMaxRevDepth = _maxRevTreeDepth != 0 ? _maxRevTreeDepth.ToString() : Storage.GetInfo("max_revs"); int maxRevTreeDepth = 0; if(savedMaxRevDepth != null && int.TryParse(savedMaxRevDepth, out maxRevTreeDepth)) { SetMaxRevTreeDepth(maxRevTreeDepth); } else { SetMaxRevTreeDepth(Manager.DefaultMaxRevTreeDepth); } // Open attachment store: string attachmentsPath = AttachmentStorePath; try { Attachments = new BlobStore(attachmentsPath, encryptionKey); } catch(CouchbaseLiteException) { Log.To.Database.E(TAG, "Error creating blob store at {0}, rethrowing...", attachmentsPath); Storage.Close(); Storage = null; throw; } catch(Exception e) { Storage.Close(); Storage = null; throw Misc.CreateExceptionAndLog(Log.To.Database, e, TAG, "Got exception creating blob store at {0}", attachmentsPath); } IsOpen = true; if(upgrade) { var upgrader = primarySQLite ? Storage.CreateUpgrader(this, DbDirectory) : otherStorageInstance.CreateUpgrader(this, DbDirectory); try { upgrader.Import(); } catch(CouchbaseLiteException e) { Log.To.Database.E(TAG, "Upgrade failed for {0} (Status {1}), rethrowing...", DbDirectory, e.CBLStatus); upgrader.Backout(); Close(); throw; } } _expirePurgeTimer = new Timer(PurgeExpired, null, HousekeepingDelayAfterOpen, TimeSpan.FromMilliseconds(-1)); }
public void TestRekey() { // First run the encrypted-attachments test to populate the db: TestEncryptedAttachments(); var options = new DatabaseOptions(); options.Create = true; options.EncryptionKey = _letmein; var seekrit = default(Database); Assert.DoesNotThrow(() => seekrit = manager.OpenDatabase("seekrit", options), "Failed to create encrypted DB"); CreateDocuments(seekrit, 100); var view = seekrit.GetView("vu"); view.SetMap((doc, emit) => { if(doc.ContainsKey("sequence")) { emit(doc["sequence"], null); }}, "1"); var query = view.CreateQuery(); Assert.AreEqual(100, query.Run().Count); Assert.DoesNotThrow(() => seekrit.ChangeEncryptionKey(_letmeout), "Error changing encryption key"); // Close & reopen seekrit: var dbName = seekrit.Name; Assert.DoesNotThrow(() => seekrit.Close().Wait(15000), "Couldn't close seekrit"); seekrit = null; options.EncryptionKey = _letmeout; var seekrit2 = default(Database); Assert.DoesNotThrow(() => seekrit2 = manager.OpenDatabase(dbName, options)); seekrit = seekrit2; // Check the document and its attachment: var savedRev = seekrit.GetDocument("att").CurrentRevision; Assert.IsNotNull(savedRev); var att = savedRev.GetAttachment("att.txt"); Assert.IsNotNull(att); var body = Encoding.UTF8.GetBytes("This is a test attachment!"); Assert.AreEqual(body, att.Content); view = seekrit.GetExistingView("vu"); Assert.IsNotNull(view); view.SetMap((doc, emit) => { if(doc.ContainsKey("sequence")) { emit(doc["sequence"], null); }}, "1"); query = view.CreateQuery(); query.IndexUpdateMode = IndexUpdateMode.Never; // Ensure that the previous results survived // Check that the view survived: Assert.AreEqual(100, query.Run().Count); seekrit.Dispose(); } }
public void TestEncryptedAttachments() { var options = new DatabaseOptions(); options.Create = true; options.EncryptionKey = _letmein; var seekrit = default(Database); Assert.DoesNotThrow(() => seekrit = manager.OpenDatabase("seekrit", options), "Failed to create encrypted DB"); // Save a doc with an attachment: var doc = seekrit.GetDocument("att"); var body = Encoding.UTF8.GetBytes("This is a test attachment!"); var rev = doc.CreateRevision(); rev.SetAttachment("att.txt", "text/plain; charset=utf-8", body); var savedRev = rev.Save(); Assert.IsNotNull(savedRev, "Saving doc failed"); // Read the raw attachment file and make sure it's not cleartext: var digest = savedRev.GetProperty("_attachments").AsDictionary<string, object>().Get("att.txt") .AsDictionary<string, object>().GetCast<string>("digest"); Assert.IsNotNull(digest); var attKey = default(BlobKey); Assert.DoesNotThrow(() => attKey = new BlobKey(digest)); var path = seekrit.Attachments.PathForKey(attKey); var raw = File.ReadAllBytes(path); Assert.IsNotNull(raw); Assert.AreNotEqual(raw, body, "Oops, attachment was not encrypted"); seekrit.Dispose(); }
public void TestCompactEncryptedDatabase() { var options = new DatabaseOptions(); options.Create = true; options.EncryptionKey = _letmein; var seekrit = default(Database); Assert.DoesNotThrow(() => seekrit = manager.OpenDatabase("seekrit", options), "Failed to create encrypted DB"); // Create a doc and then update it: var doc = CreateDocumentWithProperties(seekrit, new Dictionary<string, object> { { "answer", 42 } }); doc.Update(rev => { var props = rev.UserProperties; props["foo"] = 84; rev.SetUserProperties(props); return true; }); // Compact: Assert.IsTrue(seekrit.Compact()); doc.Update(rev => { var props = rev.UserProperties; props["foo"] = 85; rev.SetUserProperties(props); return true; }); // Close and re-open: Assert.DoesNotThrow(() => seekrit.Close().Wait(15000), "Close failed"); Assert.DoesNotThrow(() => seekrit = manager.OpenDatabase("seekrit", options), "Failed to reopen encrypted db"); Assert.AreEqual(1, seekrit.GetDocumentCount()); }
public void TestDeleteEncryptedDatabase() { var options = new DatabaseOptions(); options.Create = true; options.EncryptionKey = _letmein; var seekrit = default(Database); Assert.DoesNotThrow(() => seekrit = manager.OpenDatabase("seekrit", options), "Failed to create encrypted DB"); CreateDocumentWithProperties(seekrit, new Dictionary<string, object> { { "answer", 42 } }); // Delete db; this also unregisters its password: Assert.DoesNotThrow(seekrit.Delete); // Re-create database: options.EncryptionKey = null; Assert.DoesNotThrow(() => seekrit = manager.OpenDatabase("seekrit", options), "Failed to re-create formerly encrypted db"); Assert.AreEqual(0, seekrit.GetDocumentCount()); Assert.DoesNotThrow(() => seekrit.Close().Wait(15000)); // Make sure it doesn't need a password now: Assert.DoesNotThrow(() => seekrit = manager.OpenDatabase("seekrit", options), "Failed to re-create formerly encrypted db"); Assert.AreEqual(0, seekrit.GetDocumentCount()); Assert.DoesNotThrow(() => seekrit.Close().Wait(15000)); // Make sure old password doesn't work: options.EncryptionKey = _letmein; var e = Assert.Throws<CouchbaseLiteException>(() => seekrit = manager.OpenDatabase("seekrit", options), "Password opened unencrypted db or unexpected exception occurred!"); Assert.AreEqual(StatusCode.Unauthorized, e.Code); }
internal void OpenWithOptions(DatabaseOptions options) { if (IsOpen) { return; } Log.D(TAG, "Opening {0}", Name); _readonly = _readonly || options.ReadOnly; // Instantiate storage: string storageType = options.StorageType ?? Manager.StorageType ?? DatabaseOptions.SQLITE_STORAGE; var className = String.Format("Couchbase.Lite.Store.{0}CouchStore", storageType); var primaryStorage = Type.GetType(className, false, true); var errorMessage = default(string); if (primaryStorage == null) { #if !FORESTDB if (storageType == DatabaseOptions.FORESTDB_STORAGE) { errorMessage = "ForestDB storage option selected but not compiled into library"; } #endif #if NOSQLITE if (storageType == DatabaseOptions.SQLITE_STORAGE) { errorMessage = "SQLite storage option selected but not compiled into library"; } #endif } else if (primaryStorage.GetInterface("Couchbase.Lite.Store.ICouchStore") == null) { errorMessage = String.Format("{0} does not implement ICouchStore", className); primaryStorage = null; } if (primaryStorage == null) { throw new CouchbaseLiteException(errorMessage, StatusCode.InvalidStorageType); } var upgrade = false; var primarySQLite = storageType == DatabaseOptions.SQLITE_STORAGE; var otherStorage = primarySQLite ? Type.GetType("Couchbase.Lite.Store.ForestDBCouchStore") : Type.GetType("Couchbase.Lite.Store.SqliteCouchStore"); var primaryStorageInstance = (ICouchStore)Activator.CreateInstance(primaryStorage); var otherStorageInstance = otherStorage != null ? (ICouchStore)Activator.CreateInstance(otherStorage) : null; if(options.StorageType != null) { // If explicit storage type given in options, always use primary storage type, // and if secondary db exists, try to upgrade from it: upgrade = otherStorageInstance != null && otherStorageInstance.DatabaseExistsIn(DbDirectory) && !primaryStorageInstance.DatabaseExistsIn(DbDirectory); if (upgrade && primarySQLite) { throw new CouchbaseLiteException("Cannot upgrade to SQLite", StatusCode.InvalidStorageType); } } else { // If options don't specify, use primary unless secondary db already exists in dir: if (otherStorageInstance != null && otherStorageInstance.DatabaseExistsIn(DbDirectory)) { primaryStorageInstance = otherStorageInstance; } } Log.I(TAG, "Using {0} for db at {1}; upgrade={2}", primaryStorage, DbDirectory, upgrade); Storage = primaryStorageInstance; Storage.Delegate = this; Storage.AutoCompact = AUTO_COMPACT; // Encryption: var encryptionKey = options.EncryptionKey; if (encryptionKey != null) { Storage.SetEncryptionKey(encryptionKey); } // Open the storage! try { Storage.Open(DbDirectory, Manager, _readonly); } catch(CouchbaseLiteException) { Storage.Close(); Log.E(TAG, "Failed to open storage for database"); throw; } catch(Exception e) { Storage.Close(); throw new CouchbaseLiteException("Error opening storage for database", e); } // First-time setup: if (PrivateUUID() == null) { Storage.SetInfo("privateUUID", Misc.CreateGUID()); Storage.SetInfo("publicUUID", Misc.CreateGUID()); } var savedMaxRevDepth = _maxRevTreeDepth != 0 ? _maxRevTreeDepth.ToString() : Storage.GetInfo("max_revs"); int maxRevTreeDepth = 0; if (savedMaxRevDepth != null && int.TryParse(savedMaxRevDepth, out maxRevTreeDepth)) { SetMaxRevTreeDepth(maxRevTreeDepth); } else { SetMaxRevTreeDepth(DEFAULT_MAX_REVS); } // Open attachment store: string attachmentsPath = AttachmentStorePath; try { Attachments = new BlobStore(attachmentsPath, encryptionKey); } catch(CouchbaseLiteException) { Log.E(TAG, "Error creating blob store at {0}", attachmentsPath); Storage.Close(); Storage = null; throw; } catch(Exception e) { Storage.Close(); Storage = null; throw new CouchbaseLiteException(String.Format("Unknown error creating blob store at {0}", attachmentsPath), e) { Code = StatusCode.Exception }; } IsOpen = true; if (upgrade) { var upgrader = DatabaseUpgraderFactory.CreateUpgrader(this, DbDirectory); try { upgrader.Import(); } catch(CouchbaseLiteException e) { Log.W(TAG, "Upgrade failed for {0} (Status {1})", DbDirectory, e.CBLStatus); upgrader.Backout(); Close(); throw; } } }
public void TestEncryptedDB() { var options = new DatabaseOptions(); options.Create = true; options.EncryptionKey = _letmein; var seekrit = default(Database); Assert.DoesNotThrow(() => seekrit = manager.OpenDatabase("seekrit", options), "Failed to create encrypted DB"); CreateDocumentWithProperties(seekrit, new Dictionary<string, object> { { "answer", 42 } }); Assert.DoesNotThrow(() => seekrit.Close().Wait(15000)); // Try to reopen without the password (fails): options.EncryptionKey = null; var e = Assert.Throws<CouchbaseLiteException>(() => seekrit = manager.OpenDatabase("seekrit", options), "Shouldn't have been able to reopen encrypted db with wrong password"); Assert.AreEqual(StatusCode.Unauthorized, e.Code); // Try to reopen with wrong password (fails): options.EncryptionKey = _wrong; e = Assert.Throws<CouchbaseLiteException>(() => seekrit = manager.OpenDatabase("seekrit", options), "Shouldn't have been able to reopen encrypted db with wrong password"); Assert.AreEqual(StatusCode.Unauthorized, e.Code); // Reopen with correct password: options.EncryptionKey = _letmein; seekrit = manager.OpenDatabase("seekrit", options); Assert.IsNotNull(seekrit, "Failed to reopen encrypted db"); Assert.AreEqual(1, seekrit.GetDocumentCount()); seekrit.Dispose(); }
public void TestReadOnlyDb() { CreateDocuments(database, 10); database.Close(); var options = new ManagerOptions(); options.ReadOnly = true; var readOnlyManager = new Manager(new DirectoryInfo(manager.Directory), options); database = readOnlyManager.GetExistingDatabase(database.Name); Assert.IsNotNull(database); var e = Assert.Throws<CouchbaseLiteException>(() => CreateDocuments(database, 1)); Assert.AreEqual(StatusCode.Forbidden, e.Code); database.Close(); var dbOptions = new DatabaseOptions(); dbOptions.ReadOnly = true; database = manager.OpenDatabase(database.Name, dbOptions); Assert.IsNotNull(database); e = Assert.Throws<CouchbaseLiteException>(() => CreateDocuments(database, 1)); Assert.AreEqual(StatusCode.Forbidden, e.Code); database.Close(); dbOptions.ReadOnly = false; database = manager.OpenDatabase(database.Name, dbOptions); Assert.DoesNotThrow(() => CreateDocuments(database, 1)); }