stainless-steel / sqlite3-sys

Bindings to SQLite
Other
19 stars 6 forks source link

Support SQLCipher #1

Closed IvanUkhov closed 8 years ago

IvanUkhov commented 8 years ago

Hello Ivan,

I've been looking to interface SQLCipher (https://www.zetetic.net/sqlcipher/) from Rust and I'm thinking of using your crates as a starting point. However, I'm not sure what would be the best approach here.

Namely, SQLCipher basically comes as SQLite + the encryption support, i.e. you get a libsqlcipher.so library with the same SQLite interface as vanilla libsqlite.so. Encryption is handled completely transparently and you can use everything you use normally when working with SQLite (though, one has to note that each SQLCipher version is based on top off a specific SQLite version, and SQLCipher uses private SQLite API internally).

Currently I think there are two options:

1) copy sqlite and sqlite3-sys and modify them to link against SQLCipher

2) make sqlite3-sys look up the symbols dynamically instead of linking directly, configurable at runtime

Option 1) seems pretty bad and wasteful because we would end up with practically identical code in two different crates. The only thing that would change is the linking part.

Option 2) would avoid code duplication and allow the user to decide at runtime what to use, but it would complicate the implementation somewhat.

What do you think?

IvanUkhov commented 8 years ago

The linking is handled by the build script. If the API of SQLCipher is indeed the same as the one of SQLite3, one could implement a Cargo feature changing the name of the library the build script links to. What do you think about this approach?

istankovic commented 8 years ago

Hm, that could work, yes. As far as I know, the interface should really be the same (depending on the SQLite version, of course).

IvanUkhov commented 8 years ago

Have a look at this. I’ve not tried, but it sounds promising. Could you please give it a shot?

IvanUkhov commented 8 years ago

Theoretically, if this functionality works, you could have your own crate, say sqlcipher (the name is still available), which would depend on sqlite3-sys and sqlite and just swap the library that is used under the hood. You could also compile SQLCipher; I suppose it’s not as widespread as SQLite.

istankovic commented 8 years ago

I'll try, thanks for the helpful hints!

istankovic commented 8 years ago

Heh, it seems it's not as easy as one would first think. Cargo let's you override metadata, but only if your crate directly depends on the crate you're modifying. In this particular case, the dependency would be sqlcipher -> sqlite -> sqlite3-sys, so override doesn't work.

IvanUkhov commented 8 years ago

@istankovic, but your crate can directly depend on both sqlite and sqlite3-sys, can’t it?

istankovic commented 8 years ago

Probably, but I'm not sure that would be best.

IvanUkhov commented 8 years ago

@istankovic, push your crate to GitHub so that one could have a look.

istankovic commented 8 years ago

Doesn't work, cargo complains: native librarysqlite3is being linked to by more than one package, and can only be linked to by one package

Which is as expected, because of the Cargo rule that there needs to be a single crate linking to a native lib.

istankovic commented 8 years ago

I'm thinking of just adding a feature to sqlite that would override the lib in sqlite3 and be done with it. What do you think?

istankovic commented 8 years ago

Ok, adding the feature was straightforward and works nicely. Would you find this approach acceptable?

IvanUkhov commented 8 years ago

Please open a pull request. I’d like to have a look how it plays out.

istankovic commented 8 years ago

Please open a pull request. I’d like to have a look how it plays out.

Done. There are two actually, one for sqlite3-sys and one for sqlite.

IvanUkhov commented 8 years ago

Thanks for the pull requests! What was bothering me about a name switch in the build script is that the links key would be lying. To prevent this, I delegated the linking to separate crates, sqlite3-provider and sqlcipher-provider. The first is a default feature in both sqlite3-sys and sqlite, and the second is an optional feature. Please try the following in your project and tell me if it works for you:

[dependencies.sqlite]
version = "0.21"
default-features = false
features = ["sqlcipher"]
istankovic commented 8 years ago

The approach with provider crates is definitely better and, I've just checked, works perfectly. Thanks!

IvanUkhov commented 8 years ago

@istankovic, if some day you have the time and desire, sqlcipher-provider would definitely benefit from the ability to compile SQLCipher in case pkg-config fails to find it installed.

istankovic commented 8 years ago

Yes, that would be nice to have. Right now I'm actually focused on using this.