summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--store/src/backend.rs24
-rw-r--r--store/src/lib.rs124
-rw-r--r--store/src/store_protocol.capnp7
-rw-r--r--tool/src/main.rs22
4 files changed, 173 insertions, 4 deletions
diff --git a/store/src/backend.rs b/store/src/backend.rs
index 88b85177..6756b485 100644
--- a/store/src/backend.rs
+++ b/store/src/backend.rs
@@ -212,6 +212,16 @@ impl node::store::Server for StoreServer {
.from_server::<capnp_rpc::Server>()));
Promise::ok(())
}
+
+ fn delete(&mut self,
+ _: node::store::DeleteParams,
+ mut results: node::store::DeleteResults)
+ -> Promise<(), capnp::Error> {
+ bind_results!(results);
+ sry!(self.c.borrow().execute("DELETE FROM stores WHERE id = ?1",
+ &[&self.id]));
+ Promise::ok(())
+ }
}
struct BindingServer {
@@ -328,6 +338,16 @@ impl node::binding::Server for BindingServer {
Promise::ok(())
}
+ fn delete(&mut self,
+ _: node::binding::DeleteParams,
+ mut results: node::binding::DeleteResults)
+ -> Promise<(), capnp::Error> {
+ bind_results!(results);
+ sry!(self.c.borrow().execute("DELETE FROM bindings WHERE id = ?1",
+ &[&self.id]));
+ Promise::ok(())
+ }
+
fn register_encryption(&mut self,
_: node::binding::RegisterEncryptionParams,
mut results: node::binding::RegisterEncryptionResults)
@@ -531,8 +551,8 @@ CREATE TABLE bindings (
verification_last DEFAULT 0,
UNIQUE(store, label),
- FOREIGN KEY (store) REFERENCES stores(id),
- FOREIGN KEY (key) REFERENCES keys(id));
+ FOREIGN KEY (store) REFERENCES stores(id) ON DELETE CASCADE,
+ FOREIGN KEY (key) REFERENCES keys(id) ON DELETE CASCADE);
CREATE TABLE keys (
id INTEGER PRIMARY KEY,
diff --git a/store/src/lib.rs b/store/src/lib.rs
index 5d0dc357..e772476c 100644
--- a/store/src/lib.rs
+++ b/store/src/lib.rs
@@ -237,6 +237,37 @@ impl Store {
let binding = make_request!(self.core.borrow_mut(), request)?;
Ok(Binding::new(self, label, binding))
}
+
+ /// Deletes this store.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # extern crate openpgp;
+ /// # #[macro_use] extern crate sequoia_core;
+ /// # extern crate sequoia_store;
+ /// # use openpgp::Fingerprint;
+ /// # use sequoia_core::Context;
+ /// # use sequoia_store::{Store, Result, Error};
+ /// # fn main() { f().unwrap(); }
+ /// # fn f() -> Result<()> {
+ /// # let ctx = Context::configure("org.sequoia-pgp.demo.store")
+ /// # .ephemeral().build()?;
+ /// let store = Store::open(&ctx, "default")?;
+ /// let fp = Fingerprint::from_bytes(b"bbbbbbbbbbbbbbbbbbbb");
+ /// store.add("Mister B.", &fp)?;
+ /// store.delete()?;
+ /// // ...
+ /// let store = Store::open(&ctx, "default")?;
+ /// let binding = store.lookup("Mister B.");
+ /// assert_match!(Err(Error::NotFound) = binding);
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn delete(self) -> Result<()> {
+ let request = self.store.delete_request();
+ make_request_map!(self.core.borrow_mut(), request, |_| Ok(()))
+ }
}
/// Represents an entry in a Store.
@@ -424,6 +455,35 @@ impl<'a> Binding<'a> {
|data| TPK::from_bytes(data).map_err(|e| e.into()))
}
+ /// Deletes this binding.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # extern crate openpgp;
+ /// # #[macro_use] extern crate sequoia_core;
+ /// # extern crate sequoia_store;
+ /// # use openpgp::Fingerprint;
+ /// # use sequoia_core::Context;
+ /// # use sequoia_store::{Store, Result, Error};
+ /// # fn main() { f().unwrap(); }
+ /// # fn f() -> Result<()> {
+ /// # let ctx = Context::configure("org.sequoia-pgp.demo.store")
+ /// # .ephemeral().build()?;
+ /// let store = Store::open(&ctx, "default")?;
+ /// let fp = Fingerprint::from_bytes(b"bbbbbbbbbbbbbbbbbbbb");
+ /// let binding = store.add("Mister B.", &fp)?;
+ /// binding.delete()?;
+ /// let binding = store.lookup("Mister B.");
+ /// assert_match!(Err(Error::NotFound) = binding);
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn delete(self) -> Result<()> {
+ let request = self.binding.delete_request();
+ make_request_map!(self.store.core.borrow_mut(), request, |_| Ok(()))
+ }
+
fn register_encryption(&self) -> Result<Stats> {
#![allow(dead_code)] // XXX use
make_stats_request!(
@@ -448,6 +508,12 @@ pub struct Key<'a> {
key: node::key::Client,
}
+impl<'a> fmt::Debug for Key<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Key {{ }}")
+ }
+}
+
impl<'a> Key<'a> {
fn new(store: &'a Store, key: node::key::Client) -> Self {
Key{store: store, key: key}
@@ -700,5 +766,63 @@ mod store_test {
let r = binding.import(&tpk);
assert_match!(Err(Error::Conflict) = r);
}
+
+
+ #[test]
+ fn delete_store_twice() {
+ let ctx = core::Context::configure("org.sequoia-pgp.tests")
+ .ephemeral()
+ .network_policy(core::NetworkPolicy::Offline)
+ .build().unwrap();
+ let s0 = Store::open(&ctx, "default").unwrap();
+ let s1 = Store::open(&ctx, "default").unwrap();
+ s0.delete().unwrap();
+ s1.delete().unwrap();
+ }
+
+ #[test]
+ fn delete_store_then_use() {
+ let ctx = core::Context::configure("org.sequoia-pgp.tests")
+ .ephemeral()
+ .network_policy(core::NetworkPolicy::Offline)
+ .build().unwrap();
+ let s0 = Store::open(&ctx, "default").unwrap();
+ let s1 = Store::open(&ctx, "default").unwrap();
+ s0.delete().unwrap();
+ let binding = s1.lookup("Foobarbaz");
+ assert_match!(Err(Error::NotFound) = binding);
+ let fp = Fingerprint::from_bytes(b"bbbbbbbbbbbbbbbbbbbb");
+ let binding = s1.add("Mister B.", &fp);
+ assert_match!(Err(Error::NotFound) = binding);
+ }
+
+ #[test]
+ fn delete_binding_twice() {
+ let ctx = core::Context::configure("org.sequoia-pgp.tests")
+ .ephemeral()
+ .network_policy(core::NetworkPolicy::Offline)
+ .build().unwrap();
+ let store = Store::open(&ctx, "default").unwrap();
+ let fp = Fingerprint::from_bytes(b"bbbbbbbbbbbbbbbbbbbb");
+ let b0 = store.add("Mister B.", &fp).unwrap();
+ let b1 = store.lookup("Mister B.").unwrap();
+ b0.delete().unwrap();
+ b1.delete().unwrap();
+ }
+
+ #[test]
+ fn delete_binding_then_use() {
+ let ctx = core::Context::configure("org.sequoia-pgp.tests")
+ .ephemeral()
+ .network_policy(core::NetworkPolicy::Offline)
+ .build().unwrap();
+ let store = Store::open(&ctx, "default").unwrap();
+ let fp = Fingerprint::from_bytes(b"bbbbbbbbbbbbbbbbbbbb");
+ let b0 = store.add("Mister B.", &fp).unwrap();
+ let b1 = store.lookup("Mister B.").unwrap();
+ b0.delete().unwrap();
+ assert_match!(Err(Error::NotFound) = b1.stats());
+ assert_match!(Err(Error::NotFound) = b1.key());
+ }
}
diff --git a/store/src/store_protocol.capnp b/store/src/store_protocol.capnp
index 74f162cf..f29565da 100644
--- a/store/src/store_protocol.capnp
+++ b/store/src/store_protocol.capnp
@@ -7,7 +7,7 @@ interface Node {
interface Store {
add @0 (label: Text, fingerprint: Text) -> (result: Result(Binding));
lookup @1 (label: Text) -> (result: Result(Binding));
- delete @2 ();
+ delete @2 () -> (result: Result(Unit));
#iterate @3 (id: UInt32) -> (result: Result(Binding));
}
@@ -15,7 +15,7 @@ interface Node {
stats @0 () -> (result: Result(Stats));
key @1 () -> (result: Result(Key));
import @2 (key: Data, force: Bool) -> (result: Result(Data));
- delete @3 ();
+ delete @3 () -> (result: Result(Unit));
registerEncryption @4 () -> (result: Result(Stats));
registerVerification @5 () -> (result: Result(Stats));
}
@@ -26,6 +26,9 @@ interface Node {
import @2 (key: Data) -> (result: Result(Data));
}
+ # Unit struct. Useful with Result.
+ struct Unit {}
+
struct Stats {
created @0 :Int64;
updated @1 :Int64;
diff --git a/tool/src/main.rs b/tool/src/main.rs
index 0d06266c..dd791252 100644
--- a/tool/src/main.rs
+++ b/tool/src/main.rs
@@ -147,6 +147,14 @@ fn real_main() -> Result<()> {
.long("armor")
.short("A")
.help("Write armored data to file")))
+ .subcommand(SubCommand::with_name("delete")
+ .about("Deletes bindings or stores")
+ .arg(Arg::with_name("the-store")
+ .long("the-store")
+ .help("Delete the whole store"))
+ .arg(Arg::with_name("label")
+ .value_name("LABEL")
+ .help("Delete binding with this label")))
.subcommand(SubCommand::with_name("stats")
.about("Get stats for the given label")
.arg(Arg::with_name("label").value_name("LABEL")
@@ -298,6 +306,20 @@ fn real_main() -> Result<()> {
tpk.serialize(&mut output)
.expect("Failed to write the key");
},
+ ("delete", Some(m)) => {
+ if m.is_present("label") == m.is_present("the-store") {
+ eprintln!("Please specify either a label or --the-store.");
+ exit(1);
+ }
+
+ if m.is_present("the-store") {
+ store.delete().expect("Failed to delete the store");
+ } else {
+ let binding = store.lookup(m.value_of("label").unwrap())
+ .expect("Failed to get key");
+ binding.delete().expect("Failed to delete the binding");
+ }
+ },
("stats", Some(m)) => {
let binding = store.lookup(m.value_of("label").unwrap())
.expect("Failed to get key");