Ошибка при сохранении базы данных Couchbase Lite в пользовательском каталоге при реализации SQLCipher

So,

Что я хочу:

Чтобы иметь возможность указать Couchbase Lite (CB Lite), где хранить данные и внедрить на них шифрование SQLCipher.

В чем моя проблема:

Несмотря на то, что шифрование работает в каталоге по умолчанию, как только я говорю менеджеру использовать пользовательский каталог, он выдает исключение при попытке создать базу данных: Сообщение:

«Ошибка 8, 1032 (попытка записи базы данных только для чтения) при выполнении sql «CREATE INDEX docs_docid ON docs (docid)»»

Источник:

"Couchbase.Lite.Storage.SQLCipher"

Трассировки стека:

«в Couchbase.Lite.Storage.SQLCipher.SqlitePCLRawStorageEngine.ExecSQL (System.String sql, SQLitePCL.sqlite3 db, System.Object [] paramArgs) [0x00079] в /Users/jenkins/jenkins/workspace/couchbase-lite-net- build@2/1.4/Android/couchbase-lite-net/src/StorageEngines/SQLiteCommon/storage.sqlite.common/src/DatabaseUpgraderFactory_Upgraders.cs:249 \n в Couchbase.Lite.Storage.SQLCipher.SqlitePCLRawStorageEngine.ExecSQL (System. String sql, System.Object[] paramArgs) ‹0xd70821f8 + 0x0005f> in ‹223c4357c0d44faaaa01c387793a30cc>:0 \n at Couchbase.Lite.Storage.SQLCipher.SqlitePCLRawStorageEngine.Open (путь System.String, схема System.String только для чтения, System.String , Couchbase.Lite.Store.SymmetricKey EncryptionKey) [0x00065] в /Users/jenkins/jenkins/workspace/couchbase-lite-net-build@2/1.4/Android/couchbase-lite-net/src/StorageEngines/SQLiteCommon/storage .sqlite.common/src/DatabaseUpgraderFactory.cs:87 "

Теперь странно то, что при запуске моего кода на эмуляторе он не выдает никаких исключений. Проблема возникает только при запуске моего кода на реальном устройстве (Lenovo TAB 2A Series, Android 5.0.1).

Примечание. Несмотря на то, что создается исключение, пользовательская папка создается, а также папка для дивана lite, но внутри нее находится только файл с именем db.sqlite3. Обычно создаются три файла и папка: введите здесь описание изображения

Примечание 2. я добавил разрешение WRITE_EXTERNAL_STORAGE в манифест Android.

Код, который работает без проблем:

public async Task<Database> OpenDatabaseOnEncryptedWayAsync(string encryptionPassword)
    {
        Database encryptedDatabase = null;

        try
        {
            SymmetricKey Key;
            DatabaseOptions options = new DatabaseOptions();
            await Task.Run(() =>
            {
                Key = new SymmetricKey(encryptionPassword);
                options.EncryptionKey = Key;
                options.Create = true;
                options.StorageType = StorageEngineTypes.SQLite;
            });

            // Database stored in default directory
            encryptedDatabase = Manager.SharedInstance.OpenDatabase(database, options);
        }
        catch (CouchbaseLiteException e)
        {
            LogWriterMethod.TryWriteLog(String.Format("Error while creating encrypted database: {0}", e)); 
            Console.WriteLine("Encryption Message: {0}", e);
        }
        catch (Exception e)
        {
            LogWriterMethod.TryWriteLog(String.Format("Unhandled Exception on OpenDatabaseOnEncryptedWayAsync method: {0}", e));
            Console.WriteLine("Unhandled Exception Message: {0}", e);
        }

        App.SettingsViewModel.isDatabaseOpen = encryptedDatabase != null;

        return encryptedDatabase;
    }

Код, вызывающий исключение (CouchbaseLite):

    public async Task<Database> OpenDatabaseOnEncryptedWayAsync(string encryptionPassword)
    {            
        Database encryptedDatabase = null;

        try
        {
            SymmetricKey Key;
            DatabaseOptions options = new DatabaseOptions();
            await Task.Run(() =>
            {
                Key = new SymmetricKey(encryptionPassword);
                options.EncryptionKey = Key;
                options.Create = true;
                options.StorageType = StorageEngineTypes.SQLite;
            });

            // Custom directory
            var path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).Path;
            var dir = Directory.CreateDirectory(path);
            Manager manager = new Manager(dir, Manager.DefaultOptions);
            encryptedDatabase = manager.GetDatabase(database);
        }
        catch (CouchbaseLiteException e)
        {
            LogWriterMethod.TryWriteLog(String.Format("Error while creating encrypted database: {0}", e)); 
            Console.WriteLine("Encryption Message: {0}", e);
        }
        catch (Exception e)
        {
            LogWriterMethod.TryWriteLog(String.Format("Unhandled Exception on OpenDatabaseOnEncryptedWayAsync method: {0}", e));
            Console.WriteLine("Unhandled Exception Message: {0}", e);
        }

        App.SettingsViewModel.isDatabaseOpen = encryptedDatabase != null;

        return encryptedDatabase;
    }

Итак, кто-нибудь знает, как справиться с этой проблемой? Заранее спасибо :)


person Deczaloth    schedule 25.08.2017    source источник


Ответы (1)


Возвращаясь к теме, я обнаружил очень простую ошибку в коде, который вызывает исключение (CouchbaseLite). Я делюсь им на случай, если кто-то, кто читает это, попадет в ту же ошибку:

Я создаю каталог, а затем менеджер, используя новый путь, но я никогда не назначаю DatabaseOptions вновь созданному менеджеру.

SymmetricKey Key;
DatabaseOptions options = new DatabaseOptions();
await Task.Run(() =>
{
    Key = new SymmetricKey(encryptionPassword);
    options.EncryptionKey = Key;
    options.Create = true;
    options.StorageType = StorageEngineTypes.SQLite;
});
var path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).Path;
var dir = Directory.CreateDirectory(path);
Manager manager = new Manager(dir, Manager.DefaultOptions);
encryptedDatabase = manager.GetDatabase(database);

Итак, все, что нам нужно сделать, это изменить код для чтения

encryptedDatabase = manager.OpenDatabase(database, options);

Вот и все!

person Deczaloth    schedule 17.11.2017