🏡 index : ~doyle/1p.git

author Jordan Doyle <jordan@doyle.la> 2020-07-06 15:36:39.0 +00:00:00
committer Jordan Doyle <jordan@doyle.la> 2020-07-06 15:36:39.0 +00:00:00
commit
c91b370741752da0929ada4978af1edec70885e6 [patch]
tree
f735c12e2e3319ed631e1e1a4a4844238a29f76c
parent
887a2efe4f9534593c87682e2e869a816309ef8e
download
c91b370741752da0929ada4978af1edec70885e6.tar.gz

Generate errors, allow API impls to define their own errors



Diff

 Cargo.lock             |  5 ++---
 onep-api-op/Cargo.toml |  3 ++-
 onep-api-op/src/lib.rs | 43 ++++++++++++++++++++++++++++---------------
 onep-api/Cargo.toml    |  3 +--
 onep-api/src/lib.rs    | 22 +++++++---------------
 onep-cli/Cargo.toml    |  1 +
 onep-cli/src/main.rs   |  8 +++++++-
 7 files changed, 48 insertions(+), 37 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 5a20de1..cce23b2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -175,9 +175,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "onep-api"
version = "0.1.0"
dependencies = [
 "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "onep-api-op"
@@ -187,6 +184,7 @@ dependencies = [
 "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
 "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)",
 "serde_with 1.5.0-alpha.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -200,6 +198,7 @@ dependencies = [
 "onep-api 0.1.0",
 "onep-api-op 0.1.0",
 "term-table 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
diff --git a/onep-api-op/Cargo.toml b/onep-api-op/Cargo.toml
index 19b3e3a..f7a4e12 100644
--- a/onep-api-op/Cargo.toml
+++ b/onep-api-op/Cargo.toml
@@ -10,4 +10,5 @@ edition = "2018"
onep-api = { path = "../onep-api" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_with = "1.5.0-alpha.1"
\ No newline at end of file
serde_with = "1.5.0-alpha.1"
thiserror = "1.0"
\ No newline at end of file
diff --git a/onep-api-op/src/lib.rs b/onep-api-op/src/lib.rs
index 1e2e7fa..00bf2f6 100644
--- a/onep-api-op/src/lib.rs
+++ b/onep-api-op/src/lib.rs
@@ -1,8 +1,19 @@
use serde::Deserialize;
use serde_json::Value;
use onep_api::OnePasswordApiError;
use std::process::Command;

#[derive(thiserror::Error, Debug)]
pub enum Error {
    #[error("op backend returned an error:\n{0}")]
    Backend(String),
    #[error("failed to exec backend:\n{0}")]
    Exec(std::io::Error),
    #[error("failed to parse json from op:\n{0}")]
    Json(#[from] serde_json::error::Error),
    #[error("failed to convert op response to utf-8:\n{0}")]
    Utf8(#[from] std::str::Utf8Error)
}

#[derive(Debug, Deserialize)]
struct GetAccount {
    name: String,
@@ -120,26 +131,28 @@ impl Into<onep_api::ItemField> for GetItemSectionField {
pub struct OnepasswordOp {}

impl OnepasswordOp {
    fn exec(&self, args: &[&str]) -> Result<Vec<u8>, OnePasswordApiError> {
        let cmd = Command::new("op").args(args).output().map_err(OnePasswordApiError::Exec)?;
    fn exec(&self, args: &[&str]) -> Result<Vec<u8>, Error> {
        let cmd = Command::new("op").args(args).output().map_err(Error::Exec)?;

        if cmd.status.success() {
            Ok(cmd.stdout)
        } else {
            Err(OnePasswordApiError::Backend(
                std::str::from_utf8(&cmd.stderr).unwrap().to_string()
            Err(Error::Backend(
                std::str::from_utf8(&cmd.stderr)?.to_string()
            ))
        }
    }
}

impl onep_api::OnePassword for OnepasswordOp {
    fn totp(&self, uuid: &str) -> Result<String, OnePasswordApiError> {
        Ok(std::str::from_utf8(&self.exec(&["get", "totp", uuid])?).unwrap().to_string())
    type Error = Error;

    fn totp(&self, uuid: &str) -> Result<String, Self::Error> {
        Ok(std::str::from_utf8(&self.exec(&["get", "totp", uuid])?)?.to_string())
    }

    fn account(&self) -> Result<onep_api::AccountMetadata, OnePasswordApiError> {
        let ret: GetAccount = serde_json::from_slice(&self.exec(&["get", "account"])?).unwrap();
    fn account(&self) -> Result<onep_api::AccountMetadata, Self::Error> {
        let ret: GetAccount = serde_json::from_slice(&self.exec(&["get", "account"])?)?;

        Ok(onep_api::AccountMetadata {
            name: ret.name,
@@ -147,8 +160,8 @@ impl onep_api::OnePassword for OnepasswordOp {
        })
    }

    fn vaults(&self) -> Result<Vec<onep_api::VaultMetadata>, OnePasswordApiError> {
        let ret: Vec<ListVault> = serde_json::from_slice(&self.exec(&["list", "vaults"])?).unwrap();
    fn vaults(&self) -> Result<Vec<onep_api::VaultMetadata>, Self::Error> {
        let ret: Vec<ListVault> = serde_json::from_slice(&self.exec(&["list", "vaults"])?)?;

        Ok(ret.into_iter()
            .map(|v| onep_api::VaultMetadata {
@@ -158,8 +171,8 @@ impl onep_api::OnePassword for OnepasswordOp {
            .collect())
    }

    fn search(&self, terms: Option<&str>) -> Result<Vec<onep_api::ItemMetadata>, OnePasswordApiError> {
        let ret: Vec<ListItem> = serde_json::from_slice(&self.exec(&["list", "items"])?).unwrap();
    fn search(&self, terms: Option<&str>) -> Result<Vec<onep_api::ItemMetadata>, Self::Error> {
        let ret: Vec<ListItem> = serde_json::from_slice(&self.exec(&["list", "items"])?)?;

        Ok(ret.into_iter()
            .filter(|v| {
@@ -183,8 +196,8 @@ impl onep_api::OnePassword for OnepasswordOp {
            .collect())
    }

    fn get(&self, uuid: &str) -> Result<Option<onep_api::Item>, OnePasswordApiError> {
        let ret: GetItem = serde_json::from_slice(&self.exec(&["get", "item", uuid])?).unwrap();
    fn get(&self, uuid: &str) -> Result<Option<onep_api::Item>, Self::Error> {
        let ret: GetItem = serde_json::from_slice(&self.exec(&["get", "item", uuid])?)?;

        Ok(Some(onep_api::Item {
            title: ret.overview.title,
diff --git a/onep-api/Cargo.toml b/onep-api/Cargo.toml
index 57b5b99..09bee57 100644
--- a/onep-api/Cargo.toml
+++ b/onep-api/Cargo.toml
@@ -6,5 +6,4 @@ edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
thiserror = "1.0"
\ No newline at end of file
[dependencies]
\ No newline at end of file
diff --git a/onep-api/src/lib.rs b/onep-api/src/lib.rs
index fd6523c..ee203b5 100644
--- a/onep-api/src/lib.rs
+++ b/onep-api/src/lib.rs
@@ -1,13 +1,3 @@
use thiserror::Error;

#[derive(Error, Debug)]
pub enum OnePasswordApiError {
    #[error("1password backend returned an error:\n{0}")]
    Backend(String),
    #[error("failed to exec backend:\n{0}")]
    Exec(std::io::Error),
}

#[derive(Debug)]
pub struct AccountMetadata {
    pub name: String,
@@ -48,9 +38,11 @@ pub struct ItemSection {
}

pub trait OnePassword {
    fn totp(&self, uuid: &str) -> Result<String, OnePasswordApiError>;
    fn account(&self) -> Result<AccountMetadata, OnePasswordApiError>;
    fn vaults(&self) -> Result<Vec<VaultMetadata>, OnePasswordApiError>;
    fn search(&self, terms: Option<&str>) -> Result<Vec<ItemMetadata>, OnePasswordApiError>;
    fn get(&self, uuid: &str) -> Result<Option<Item>, OnePasswordApiError>;
    type Error;

    fn totp(&self, uuid: &str) -> Result<String, Self::Error>;
    fn account(&self) -> Result<AccountMetadata, Self::Error>;
    fn vaults(&self) -> Result<Vec<VaultMetadata>, Self::Error>;
    fn search(&self, terms: Option<&str>) -> Result<Vec<ItemMetadata>, Self::Error>;
    fn get(&self, uuid: &str) -> Result<Option<Item>, Self::Error>;
}
diff --git a/onep-cli/Cargo.toml b/onep-cli/Cargo.toml
index 581178b..d1d5e68 100644
--- a/onep-cli/Cargo.toml
+++ b/onep-cli/Cargo.toml
@@ -15,4 +15,5 @@ term-table = "1.3"
itertools = "0.9"
colored = "1.9"

thiserror = "1.0"
anyhow = "1.0"
\ No newline at end of file
diff --git a/onep-cli/src/main.rs b/onep-cli/src/main.rs
index 51ff0b0..598e3bc 100644
--- a/onep-cli/src/main.rs
+++ b/onep-cli/src/main.rs
@@ -8,6 +8,12 @@ use term_table::{
    Table, TableStyle,
};

#[derive(thiserror::Error, Debug)]
enum Error {
    #[error("Couldn't find the requested item.")]
    NotFound,
}

#[derive(Clap, Debug)]
#[clap(author, version)]
/// 1password cli for humans
@@ -125,7 +131,7 @@ fn run() -> anyhow::Result<()> {
            }
        }
        Opt::Show { uuid } => {
            let result = imp.get(&uuid)?.unwrap();
            let result = imp.get(&uuid)?.ok_or(Error::NotFound)?;

            let mut table = Table::new();
            table.style = TableStyle::extended();