🏡 index : ~doyle/1p.git

author Jordan Doyle <jordan@doyle.la> 2020-07-06 15:53:37.0 +00:00:00
committer Jordan Doyle <jordan@doyle.la> 2020-07-06 15:53:37.0 +00:00:00
commit
d9314afa138d7698c919308ed223ac9d2c325a39 [patch]
tree
f85d8e2db600b0e813142b642d2d3b1a4544054a
parent
c91b370741752da0929ada4978af1edec70885e6
download
d9314afa138d7698c919308ed223ac9d2c325a39.tar.gz

Clean up type conversion in API impl



Diff

 onep-api-op/src/lib.rs | 143 +++++++++++++++++++++++++++++---------------------
 onep-api/src/lib.rs    |   3 +-
 onep-cli/src/main.rs   |  18 +++---
 3 files changed, 99 insertions(+), 65 deletions(-)

diff --git a/onep-api-op/src/lib.rs b/onep-api-op/src/lib.rs
index 00bf2f6..c121b72 100644
--- a/onep-api-op/src/lib.rs
+++ b/onep-api-op/src/lib.rs
@@ -1,3 +1,5 @@
#![deny(clippy::pedantic)]

use serde::Deserialize;
use serde_json::Value;
use std::process::Command;
@@ -11,7 +13,7 @@ pub enum 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)
    Utf8(#[from] std::str::Utf8Error),
}

#[derive(Debug, Deserialize)]
@@ -20,12 +22,30 @@ struct GetAccount {
    domain: String,
}

impl Into<onep_api::AccountMetadata> for GetAccount {
    fn into(self) -> onep_api::AccountMetadata {
        onep_api::AccountMetadata {
            name: self.name,
            domain: self.domain,
        }
    }
}

#[derive(Debug, Deserialize)]
struct ListVault {
    uuid: String,
    name: String,
}

impl Into<onep_api::VaultMetadata> for ListVault {
    fn into(self) -> onep_api::VaultMetadata {
        onep_api::VaultMetadata {
            uuid: self.uuid,
            name: self.name,
        }
    }
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ListItem {
@@ -36,6 +56,17 @@ struct ListItem {
    overview: ItemOverview,
}

impl Into<onep_api::ItemMetadata> for ListItem {
    fn into(self) -> onep_api::ItemMetadata {
        onep_api::ItemMetadata {
            title: self.overview.title,
            account_info: self.overview.account_info,
            uuid: self.uuid,
            vault_uuid: self.vault_uuid,
        }
    }
}

#[derive(Debug, Deserialize)]
struct ItemOverview {
    #[serde(rename = "URLs", default)]
@@ -63,6 +94,35 @@ struct GetItem {
    overview: ItemOverview,
}

impl Into<onep_api::Item> for GetItem {
    fn into(self) -> onep_api::Item {
        onep_api::Item {
            title: self.overview.title,
            fields: self
                .details
                .fields
                .into_iter()
                .map(|f| f.into())
                .filter(|f: &onep_api::ItemField| !f.value.is_empty())
                .collect(),
            sections: self
                .details
                .sections
                .into_iter()
                .map(|v| onep_api::ItemSection {
                    name: v.title,
                    fields: v
                        .fields
                        .into_iter()
                        .map(|f| f.into())
                        .filter(|f: &onep_api::ItemField| !f.value.is_empty())
                        .collect(),
                })
                .collect(),
        }
    }
}

#[derive(Debug, Deserialize)]
struct GetItemDetails {
    #[serde(default)]
@@ -130,17 +190,18 @@ impl Into<onep_api::ItemField> for GetItemSectionField {

pub struct OnepasswordOp {}

impl OnepasswordOp {
    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(Error::Backend(
                std::str::from_utf8(&cmd.stderr)?.to_string()
            ))
        }
fn exec(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(Error::Backend(
            std::str::from_utf8(&cmd.stderr)?.to_string(),
        ))
    }
}

@@ -148,33 +209,27 @@ impl onep_api::OnePassword for OnepasswordOp {
    type Error = Error;

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

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

        Ok(onep_api::AccountMetadata {
            name: ret.name,
            domain: ret.domain,
        })
        Ok(ret.into())
    }

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

        Ok(ret.into_iter()
            .map(|v| onep_api::VaultMetadata {
                uuid: v.uuid,
                name: v.name,
            })
            .collect())
        Ok(ret.into_iter().map(|v| v.into()).collect())
    }

    #[allow(clippy::filter_map)]
    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"])?)?;
        let ret: Vec<ListItem> = serde_json::from_slice(&exec(&["list", "items"])?)?;

        Ok(ret.into_iter()
        Ok(ret
            .into_iter()
            .filter(|v| {
                if let Some(terms) = terms {
                    v.uuid == terms
@@ -187,41 +242,13 @@ impl onep_api::OnePassword for OnepasswordOp {
                    true
                }
            })
            .map(|v| onep_api::ItemMetadata {
                title: v.overview.title,
                account_info: v.overview.account_info,
                uuid: v.uuid,
                vault_uuid: v.vault_uuid,
            })
            .map(|v| v.into())
            .collect())
    }

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

        Ok(Some(onep_api::Item {
            title: ret.overview.title,
            fields: ret
                .details
                .fields
                .into_iter()
                .map(|f| f.into())
                .filter(|f: &onep_api::ItemField| !f.value.is_empty())
                .collect(),
            sections: ret
                .details
                .sections
                .into_iter()
                .map(|v| onep_api::ItemSection {
                    name: v.title,
                    fields: v
                        .fields
                        .into_iter()
                        .map(|f| f.into())
                        .filter(|f: &onep_api::ItemField| !f.value.is_empty())
                        .collect(),
                })
                .collect(),
        }))
        Ok(Some(ret.into()))
    }
}
diff --git a/onep-api/src/lib.rs b/onep-api/src/lib.rs
index ee203b5..55f78d0 100644
--- a/onep-api/src/lib.rs
+++ b/onep-api/src/lib.rs
@@ -1,3 +1,6 @@
#![deny(clippy::pedantic)]
#![allow(clippy::missing_errors_doc)]

#[derive(Debug)]
pub struct AccountMetadata {
    pub name: String,
diff --git a/onep-cli/src/main.rs b/onep-cli/src/main.rs
index 598e3bc..9840657 100644
--- a/onep-cli/src/main.rs
+++ b/onep-cli/src/main.rs
@@ -1,5 +1,7 @@
#![deny(clippy::pedantic)]

use clap::Clap;
use colored::*;
use colored::Colorize;
use itertools::Itertools;
use onep_api::OnePassword;
use term_table::{
@@ -36,15 +38,18 @@ enum Opt {
}

fn main() {
    if let Err(e) = run() {
    if let Err(e) = run(&onep_api_op::OnepasswordOp {}) {
        eprintln!("{}", e);
        std::process::exit(1);
    }
}

fn run() -> anyhow::Result<()> {
    let imp = onep_api_op::OnepasswordOp {};

#[warn(clippy::too_many_lines)]
#[allow(clippy::non_ascii_literal)]
fn run<T: OnePassword>(imp: &T) -> anyhow::Result<()>
where
    T::Error: 'static + std::error::Error + Send + Sync,
{
    match Opt::parse() {
        Opt::Ls {
            show_uuids,
@@ -67,8 +72,7 @@ fn run() -> anyhow::Result<()> {
                let vault = vaults
                    .iter()
                    .find(|v| v.uuid == vault)
                    .map(|v| v.name.clone())
                    .unwrap_or_else(|| format!("Unknown Vault ({})", vault));
                    .map_or_else(|| format!("Unknown Vault ({})", vault), |v| v.name.clone());

                println!(
                    "{} {}",