public void TestDeleteBlobs() { RunTestVariants(() => { var blobToStore = Encoding.ASCII.GetBytes("This is a blob to store in the store!"); var key = new C4BlobKey(); LiteCoreBridge.Check(err => { C4BlobKey tmp; var retVal = Native.c4blob_create(_store, blobToStore, null, &tmp, err); key = tmp; return(retVal); }); var str = Native.c4blob_keyToString(key); str.Should().Be("sha1-QneWo5IYIQ0ZrbCG0hXPGC6jy7E="); LiteCoreBridge.Check(err => Native.c4blob_delete(_store, key, err)); var blobSize = Native.c4blob_getSize(_store, key); blobSize.Should().Be(-1L, "because the blob was deleted"); var gotBlob = Native.c4blob_getContents(_store, key, null); gotBlob.Should().BeNull("because the blob was deleted"); C4Error error; var p = Native.c4blob_getFilePath(_store, key, &error); p.Should().BeNull("because the blob was deleted"); error.domain.Should().Be(C4ErrorDomain.LiteCoreDomain); error.code.Should().Be((int)C4ErrorCode.NotFound); }); }
public void TestCreateBlobKeyMismatch() { RunTestVariants(() => { var blobToStore = C4Slice.Constant("This is a blob to store in the store!"); C4BlobKey key, expectedKey = new C4BlobKey(); var i = 0; foreach (var b in Enumerable.Repeat <byte>(0x55, sizeof(C4BlobKey))) { expectedKey.bytes[i++] = b; } C4Error error; NativePrivate.c4log_warnOnErrors(false); try { NativeRaw.c4blob_create(_store, blobToStore, &expectedKey, &key, &error).Should().BeFalse(); error.domain.Should().Be(C4ErrorDomain.LiteCoreDomain); error.code.Should().Be((int)C4ErrorCode.CorruptData); } finally { NativePrivate.c4log_warnOnErrors(true); } Native.c4blob_keyFromString("sha1-QneWo5IYIQ0ZrbCG0hXPGC6jy7E=", &expectedKey); NativeRaw.c4blob_create(_store, blobToStore, &expectedKey, &key, &error).Should().BeTrue(); }); }
public void TestCreateBlobs() { RunTestVariants(() => { var blobToStore = Encoding.UTF8.GetBytes("This is a blob to store in the store!"); // Add the blob to the store: var key = new C4BlobKey(); var localKey = &key; LiteCoreBridge.Check(err => { return(Native.c4blob_create(_store, blobToStore, null, localKey, err)); }); var str = Native.c4blob_keyToString(key); str.Should().Be("sha1-QneWo5IYIQ0ZrbCG0hXPGC6jy7E=", "because the blob key should hash correctly"); // Read it back and compare var blobSize = Native.c4blob_getSize(_store, key); blobSize.Should().BeGreaterOrEqualTo(blobToStore.Length, "because the size should be a conservative estimate, never lower"); if (_encrypted) { blobSize.Should().BeLessOrEqualTo(blobToStore.Length + 16, "because the estimate should never be more than 16 bytes off"); } else { blobSize.Should().Be(blobToStore.Length, "because unecrypted blobs should have the exact size"); } C4Error error; var gotBlob = Native.c4blob_getContents(_store, key, &error); gotBlob.Should().NotBeNull("because the attachment should be readable"); blobToStore.Should().Equal(gotBlob, "because the attachment shouldn't change"); var p = Native.c4blob_getFilePath(_store, key, &error); if (_encrypted) { p.Should().BeNull("because an encrypted store will not return a file path"); error.code.Should().Be((int)C4ErrorCode.WrongFormat, "because otherwise an unexpected error occurred"); } else { p.Should().NotBeNull("because otherwise the DB failed to return its blob store"); var filename = "QneWo5IYIQ0ZrbCG0hXPGC6jy7E=.blob"; Path.GetFileName(p).Should().Be(filename, "because otherwise the store returned an invalid filename"); } // Try storing it again var key2 = new C4BlobKey(); localKey = &key2; LiteCoreBridge.Check(err => { return(Native.c4blob_create(_store, blobToStore, null, localKey, err)); }); for (int i = 0; i < C4BlobKey.Size; i++) { key.bytes[i].Should().Be(key2.bytes[i]); } }); }
public void TestDatabaseRekey() { RunTestVariants(() => { CreateNumberedDocs(99); // Add blob to the store: var blobToStore = C4Slice.Constant("This is a blob to store in the store!"); var blobKey = new C4BlobKey(); var blobStore = (C4BlobStore *)LiteCoreBridge.Check(err => Native.c4db_getBlobStore(Db, err)); LiteCoreBridge.Check(err => { C4BlobKey local; var retVal = NativeRaw.c4blob_create(blobStore, blobToStore, null, &local, err); blobKey = local; return(retVal); }); C4Error error; var blobResult = NativeRaw.c4blob_getContents(blobStore, blobKey, &error); ((C4Slice)blobResult).Should().Equal(blobToStore); Native.c4slice_free(blobResult); // If we're on the unexcrypted pass, encrypt the db. Otherwise, decrypt it: var newKey = new C4EncryptionKey(); if (Native.c4db_getConfig(Db)->encryptionKey.algorithm == C4EncryptionAlgorithm.None) { newKey.algorithm = C4EncryptionAlgorithm.AES256; var keyBytes = Encoding.ASCII.GetBytes("a different key than default...."); Marshal.Copy(keyBytes, 0, (IntPtr)newKey.bytes, 32); } var tmp = newKey; LiteCoreBridge.Check(err => { var local = tmp; return(Native.c4db_rekey(Db, &local, err)); }); // Verify the db works: Native.c4db_getDocumentCount(Db).Should().Be(99); ((IntPtr)blobStore).Should().NotBe(IntPtr.Zero); blobResult = NativeRaw.c4blob_getContents(blobStore, blobKey, &error); ((C4Slice)blobResult).Should().Equal(blobToStore); Native.c4slice_free(blobResult); // Check thqat db can be reopened with the new key: Native.c4db_getConfig(Db)->encryptionKey.algorithm.Should().Be(newKey.algorithm); for (int i = 0; i < 32; i++) { Native.c4db_getConfig(Db)->encryptionKey.bytes[i].Should().Be(newKey.bytes[i]); } ReopenDB(); }); }
internal C4BlobKey[] AddDocWithAttachments(C4Slice docID, List <string> atts, string contentType) { var keys = new List <C4BlobKey>(); var json = new StringBuilder(); json.Append("{attached: ["); foreach (var att in atts) { var key = new C4BlobKey(); LiteCoreBridge.Check(err => { var localKey = key; var retVal = Native.c4blob_create(Native.c4db_getBlobStore(Db, null), Encoding.UTF8.GetBytes(att), null, &localKey, err); key = localKey; return(retVal); }); keys.Add(key); var keyStr = Native.c4blob_keyToString(key); json.Append( $"{{'{Constants.ObjectTypeProperty}': '{Constants.ObjectTypeBlob}', 'digest': '{keyStr}', length: {att.Length}, 'content_type': '{contentType}'}},"); } json.Append("]}"); var jsonStr = Native.FLJSON5_ToJSON(json.ToString(), null); using (var jsonStr_ = new C4String(jsonStr)) { C4Error error; var body = NativeRaw.c4db_encodeJSON(Db, jsonStr_.AsC4Slice(), &error); ((long)body.buf).Should().NotBe(0, "because otherwise the encode failed"); var rq = new C4DocPutRequest(); rq.docID = docID; rq.revFlags = C4RevisionFlags.HasAttachments; rq.body = (C4Slice)body; rq.save = true; var doc = Native.c4doc_put(Db, &rq, null, &error); Native.c4slice_free(body); ((long)doc).Should().NotBe(0, "because otherwise the put failed"); Native.c4doc_free(doc); return(keys.ToArray()); } }
public void TestReadBlobWithStream() { RunTestVariants(() => { var blob = Encoding.UTF8.GetBytes("This is a blob to store in the store!"); // Add blob to the store: var key = new C4BlobKey(); LiteCoreBridge.Check(err => { var localKey = key; var retVal = Native.c4blob_create(_store, blob, null, &localKey, err); key = localKey; return(retVal); }); C4Error error; ((long)Native.c4blob_openReadStream(_store, _bogusKey, &error)).Should().Be(0, "because an invalid key should not have a stream"); var stream = (C4ReadStream *)LiteCoreBridge.Check(err => Native.c4blob_openReadStream(_store, key, err)); Native.c4stream_getLength(stream, &error).Should().Be(blob.Length, "because the stream should know its own length"); // Read it back, 6 bytes at a time: var buffer = new byte[6]; var readBack = new List <byte>(); ulong bytesRead = 0; do { bytesRead = Native.c4stream_read(stream, buffer, &error); bytesRead.Should().BeGreaterThan(0, "because there should be new bytes"); readBack.AddRange(buffer.Take((int)bytesRead)); } while(bytesRead == (ulong)buffer.Length); error.code.Should().Be(0, "because otherwise an error occurred"); readBack.Should().Equal(blob, "because the data should persist correctly"); // Try seeking: LiteCoreBridge.Check(err => Native.c4stream_seek(stream, 10, err)); Native.c4stream_read(stream, buffer, 4, &error).Should().Be(4, "because reading should succeed after seeking"); Native.c4stream_close(stream); Native.c4stream_close(null); // This should be a no-op, not a crash }); }
public void TestCreateBlobs() { RunTestVariants(() => { var blobToStore = Encoding.UTF8.GetBytes("This is a blob to store in the store!"); // Add the blob to the store: var key = new C4BlobKey(); var localKey = &key; LiteCoreBridge.Check(err => { return(Native.c4blob_create(_store, blobToStore, localKey, err)); }); var str = Native.c4blob_keyToString(key); str.Should().Be("sha1-QneWo5IYIQ0ZrbCG0hXPGC6jy7E=", "because the blob key should hash correctly"); // Read it back and compare var blobSize = Native.c4blob_getSize(_store, key); blobSize.Should().BeGreaterOrEqualTo(blobToStore.Length, "because the size should be a conservative estimate, never lower"); if (_encrypted) { blobSize.Should().BeLessOrEqualTo(blobToStore.Length + 16, "because the estimate should never be more than 16 bytes off"); } else { blobSize.Should().Be(blobToStore.Length, "because unecrypted blobs should have the exact size"); } C4Error error; var gotBlob = Native.c4blob_getContents(_store, key, &error); gotBlob.Should().NotBeNull("because the attachment should be readable"); blobToStore.Should().Equal(gotBlob, "because the attachment shouldn't change"); // Try storing it again var key2 = new C4BlobKey(); localKey = &key2; LiteCoreBridge.Check(err => { return(Native.c4blob_create(_store, blobToStore, localKey, err)); }); key.Equals(key2).Should().BeTrue("because the two keys are for the same attachment"); }); }
public void TestParseBlobKeys() { var key1 = new C4BlobKey(); for (int i = 0; i < C4BlobKey.Size; i++) { key1.bytes[i] = 0x55; } var str = Native.c4blob_keyToString(key1); str.Should().Be("sha1-VVVVVVVVVVVVVVVVVVVVVVVVVVU=", "because otherwise the parse failed"); var key2 = new C4BlobKey(); Native.c4blob_keyFromString(str, &key2).Should().BeTrue("because the key should survive a round trip"); for (int i = 0; i < C4BlobKey.Size; i++) { key1.bytes[i].Should().Be(key2.bytes[i], "because the two keys should have equal bytes"); } }
public static C4ReadStream *c4blob_openReadStream(C4BlobStore *store, C4BlobKey key, C4Error *outError) => Impl.c4blob_openReadStream(store, key, outError);
public static bool c4blob_delete(C4BlobStore *store, C4BlobKey key, C4Error *outError) => Impl.c4blob_delete(store, key, outError);
public static string c4blob_getFilePath(C4BlobStore *store, C4BlobKey key, C4Error *outError) => Impl.c4blob_getFilePath(store, key, outError);
public static byte[] c4blob_getContents(C4BlobStore *store, C4BlobKey key, C4Error *outError) => Impl.c4blob_getContents(store, key, outError);
public static long c4blob_getSize(C4BlobStore *store, C4BlobKey key) => Impl.c4blob_getSize(store, key);
public static string c4blob_keyToString(C4BlobKey key) => Impl.c4blob_keyToString(key);
public static FLSliceResult c4blob_getContents(C4BlobStore *store, C4BlobKey key, C4Error *outError) => Impl.c4blob_getContents(store, key, outError);
public static FLSliceResult c4blob_keyToString(C4BlobKey key) => Impl.c4blob_keyToString(key);