示例#1
0
        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());
        }
示例#3
0
        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);
            }
        }
示例#5
0
        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());
        }
示例#7
0
        /// <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);
        }
示例#18
0
        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));
        }