🏡 index : ~doyle/1p.git

author Jordan Doyle <jordan@doyle.la> 2020-07-13 18:20:55.0 +00:00:00
committer Jordan Doyle <jordan@doyle.la> 2020-07-13 18:29:25.0 +00:00:00
commit
b0d4705d8ed3facea778e72a3b882db73f9623e2 [patch]
tree
95daae85ccbf0cae00ebbbf5071894e8bd095f0e
parent
13084b27f290443321bf56f9ec739b657bb36ff8
download
b0d4705d8ed3facea778e72a3b882db73f9623e2.tar.gz

Grab 2fa codes on 'get' rather than a separate totp call to backend



Diff

 Cargo.lock                  | 353 +++++++++++++++++++++++++++++++++++++++++++++-
 onep-backend-api/src/lib.rs |   8 +-
 onep-backend-op/src/lib.rs  |  18 +-
 onep-cli/Cargo.toml         |   3 +-
 onep-cli/src/main.rs        |  18 +-
 onep-cli/src/otp.rs         |  81 ++++++++++-
 6 files changed, 469 insertions(+), 12 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index bf59fd1..3a69e94 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -19,6 +19,16 @@ version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "arrayref"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "arrayvec"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "async-trait"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -44,11 +54,65 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "base32"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "base64"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "base64"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "blake2b_simd"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
 "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "block-buffer"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
 "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
 "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "block-padding"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "byteorder"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "bytes"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -107,6 +171,30 @@ dependencies = [
]

[[package]]
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "crossbeam-utils"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "crypto-mac"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
 "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "darling"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -139,11 +227,24 @@ dependencies = [
]

[[package]]
name = "digest"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "either"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "fake-simd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -180,6 +281,24 @@ dependencies = [
]

[[package]]
name = "generic-array"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "getrandom"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
 "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "heck"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -196,11 +315,35 @@ dependencies = [
]

[[package]]
name = "hex"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "hmac"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "idna"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
 "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
 "unicode-normalization 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "indexmap"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -230,6 +373,11 @@ version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "keccak"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -244,11 +392,44 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "lexical-core"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
 "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
 "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "libc"
version = "0.2.71"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "libreauth"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "base32 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
 "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "nom 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "rust-argon2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "sha2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "unicode-normalization 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
 "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "log"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -267,6 +448,11 @@ dependencies = [
]

[[package]]
name = "matches"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "memchr"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -341,6 +527,16 @@ dependencies = [
]

[[package]]
name = "nom"
version = "5.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "lexical-core 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
 "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
 "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "num_cpus"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -377,19 +573,40 @@ dependencies = [
 "clap 3.0.0-beta.1 (git+https://github.com/clap-rs/clap)",
 "colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
 "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "libreauth 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "onep-backend-api 0.1.0",
 "onep-backend-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)",
 "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
 "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "os_str_bytes"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "pbkdf2"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
 "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "pin-project-lite"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -456,6 +673,17 @@ version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "rust-argon2"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
 "blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
 "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -535,6 +763,40 @@ dependencies = [
]

[[package]]
name = "sha-1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
 "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "sha2"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
 "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "sha3"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
 "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "signal-hook-registry"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -560,6 +822,11 @@ dependencies = [
]

[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "strsim"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -570,6 +837,11 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "subtle"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "syn"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -642,6 +914,11 @@ dependencies = [
]

[[package]]
name = "tinyvec"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "tokio"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -675,6 +952,27 @@ dependencies = [
]

[[package]]
name = "typenum"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "unicode-bidi"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "unicode-normalization"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "tinyvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "unicode-segmentation"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -690,6 +988,16 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "url"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
 "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -700,6 +1008,11 @@ version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -749,37 +1062,61 @@ dependencies = [
"checksum aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)" = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
"checksum anyhow 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f"
"checksum arc-swap 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034"
"checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
"checksum async-trait 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a265e3abeffdce30b2e26b7a11b222fe37c6067404001b434101457d0385eb92"
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
"checksum base32 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa"
"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
"checksum base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
"checksum bytes 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "118cf036fbb97d0816e3c34b2d7a1e8cfc60f68fcf63d550ddbe9bd5f59c213b"
"checksum cc 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)" = "0fde55d2a2bfaa4c9668bbc63f531fbdeee3ffe188f4662511ce2c22b3eedebe"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum clap 3.0.0-beta.1 (git+https://github.com/clap-rs/clap)" = "<none>"
"checksum clap_derive 3.0.0-beta.1 (git+https://github.com/clap-rs/clap)" = "<none>"
"checksum colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59"
"checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
"checksum darling 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
"checksum darling_core 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
"checksum darling_macro 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
"checksum fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399"
"checksum generator 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "add72f17bb81521258fcc8a7a3245b1e184e916bfbe34f0ea89558f440df5c68"
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
"checksum hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909"
"checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
"checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695"
"checksum ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
"checksum indexmap 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c398b2b113b55809ceb9ee3e753fcbac793f1956663f3c36549c1346015c2afe"
"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
"checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
"checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum lexical-core 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616"
"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
"checksum libreauth 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81757fdedce2ef66fe96424f18c1f2d6f9a07b8afc90e1bd3e6f31f5768bd4f3"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum loom 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecc775857611e1df29abba5c41355cdf540e7e9d4acfdf0f355eefee82330b7"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
"checksum mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)" = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
"checksum mio-named-pipes 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656"
@@ -787,8 +1124,12 @@ dependencies = [
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum miow 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e"
"checksum net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7"
"checksum nom 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
"checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
"checksum os_str_bytes 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "06de47b848347d8c4c94219ad8ecd35eb90231704b067e67e6ae2e36ee023510"
"checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9"
"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
"checksum pin-project-lite 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715"
"checksum proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fc175e9777c3116627248584e8f8b3e2987405cabe1c0adf7d1dd28f09dc7880"
"checksum proc-macro-error-attr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3cc9795ca17eb581285ec44936da7fc2335a3f34f2ddd13118b6f4d515435c50"
@@ -797,6 +1138,7 @@ dependencies = [
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
"checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
"checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
"checksum rust-argon2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
"checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28"
@@ -807,11 +1149,16 @@ dependencies = [
"checksum serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)" = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3"
"checksum serde_with 1.5.0-alpha.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14922cc3f5279e98d5790b4607854a129749aecccfffc75dc794fbfaba85209e"
"checksum serde_with_macros 1.2.0-alpha.1 (registry+https://github.com/rust-lang/crates.io-index)" = "460c3cc47cbbfdf107ae7c1e68022ad57b3f3f63d998255c155a54514a3e3f2e"
"checksum sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
"checksum sha2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69"
"checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf"
"checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918"
"checksum static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
"checksum strsim 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
"checksum strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
"checksum syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd"
"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
"checksum term-table 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dea05ef801340799f4c96296e9e8cf79cdfa66ef66fe991522591fde77405105"
@@ -820,13 +1167,19 @@ dependencies = [
"checksum thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08"
"checksum thiserror-impl 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
"checksum tinyvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed"
"checksum tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d099fa27b9702bed751524694adbe393e18b36b204da91eb1cbbbbb4a5ee2d58"
"checksum tokio-macros 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389"
"checksum typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977"
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
"checksum url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
diff --git a/onep-backend-api/src/lib.rs b/onep-backend-api/src/lib.rs
index b29ce7b..620a4bc 100644
--- a/onep-backend-api/src/lib.rs
+++ b/onep-backend-api/src/lib.rs
@@ -33,9 +33,16 @@ pub struct Item {
#[derive(Debug)]
pub struct ItemField {
    pub name: String,
    pub field_type: ItemFieldType,
    pub value: String,
}

#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
pub enum ItemFieldType {
    Totp,
    Unknown,
}

#[derive(Debug)]
pub struct ItemSection {
    pub name: String,
@@ -46,7 +53,6 @@ pub struct ItemSection {
pub trait Backend {
    type Error;

    async fn totp(&self, uuid: &str) -> Result<String, Self::Error>;
    async fn account(&self) -> Result<AccountMetadata, Self::Error>;
    async fn vaults(&self) -> Result<Vec<VaultMetadata>, Self::Error>;
    async fn search(&self, terms: Option<&str>) -> Result<Vec<ItemMetadata>, Self::Error>;
diff --git a/onep-backend-op/src/lib.rs b/onep-backend-op/src/lib.rs
index 7ca1eed..43d4141 100644
--- a/onep-backend-op/src/lib.rs
+++ b/onep-backend-op/src/lib.rs
@@ -5,6 +5,7 @@
//! [op]: https://1password.com/downloads/command-line/

#![deny(clippy::pedantic)]
#![allow(clippy::used_underscore_binding)]

use async_trait::async_trait;
use onep_backend_api as api;
@@ -151,7 +152,11 @@ struct GetItemDetailsField {
impl Into<api::ItemField> for GetItemDetailsField {
    fn into(self) -> api::ItemField {
        api::ItemField {
            name: self.field_type,
            name: if self.field_type.is_empty() {
                self.name.clone()
            } else {
                self.field_type
            },
            value: match self.value {
                Value::Null => String::new(),
                Value::String(v) => v,
@@ -159,6 +164,7 @@ impl Into<api::ItemField> for GetItemDetailsField {
                Value::Bool(v) => if v { "true" } else { "false" }.to_string(),
                _ => panic!("unknown item field type for {}", self.name),
            },
            field_type: api::ItemFieldType::Unknown,
        }
    }
}
@@ -193,6 +199,11 @@ impl Into<api::ItemField> for GetItemSectionField {
                Value::Bool(v) => if v { "true" } else { "false" }.to_string(),
                _ => panic!("unknown item field type for {}", self.name),
            },
            field_type: if self.name.starts_with("TOTP_") {
                api::ItemFieldType::Totp
            } else {
                api::ItemFieldType::Unknown
            },
        }
    }
}
@@ -230,10 +241,6 @@ where
impl api::Backend for OpBackend {
    type Error = Error;

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

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

@@ -280,7 +287,6 @@ impl api::Backend for OpBackend {

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

        Ok(Some(ret.into()))
    }

diff --git a/onep-cli/Cargo.toml b/onep-cli/Cargo.toml
index 87afece..1e71f59 100644
--- a/onep-cli/Cargo.toml
+++ b/onep-cli/Cargo.toml
@@ -23,3 +23,6 @@ colored = "1.9"

thiserror = "1.0"
anyhow = "1.0"

libreauth = "0.13"
url = "2.1"
\ No newline at end of file
diff --git a/onep-cli/src/main.rs b/onep-cli/src/main.rs
index 248de33..85e3c2a 100644
--- a/onep-cli/src/main.rs
+++ b/onep-cli/src/main.rs
@@ -1,11 +1,14 @@
#![deny(clippy::pedantic)]
#![allow(clippy::used_underscore_binding)]

mod otp;

use clap::Clap;
use colored::Colorize;
use itertools::Itertools;
use onep_backend_api as api;
use onep_backend_op as backend;
use std::collections::BTreeMap;
use std::{collections::BTreeMap, convert::TryFrom};
use term_table::{
    row::Row,
    table_cell::{Alignment, TableCell},
@@ -38,8 +41,6 @@ enum Opt {
        show_account_names: bool,
        terms: String,
    },
    /// Grab a two-factor authentication code for the given item
    Totp { uuid: String },
    /// Show existing password and optionally put it on the clipboard
    #[clap(alias = "get")]
    Show { uuid: String },
@@ -82,7 +83,6 @@ where
            show_uuids,
            show_account_names,
        } => search(backend, Some(terms), show_uuids, show_account_names).await?,
        Opt::Totp { uuid } => println!("{}", backend.totp(&uuid).await?.trim()),
        Opt::Show { uuid } => {
            let result = backend.get(&uuid).await?.ok_or(Error::NotFound)?;
            show(result);
@@ -234,9 +234,17 @@ fn show(item: api::Item) {
        }

        for field in section.fields {
            let mut value = field.value;

            if field.field_type == api::ItemFieldType::Totp {
                if let Ok(tfa) = otp::TwoFactorAuth::try_from(value.as_ref()) {
                    value = tfa.generate().value;
                }
            }

            table.add_row(Row::new(vec![
                TableCell::new(field.name),
                TableCell::new_with_alignment(field.value, 1, Alignment::Right),
                TableCell::new_with_alignment(value, 1, Alignment::Right),
            ]));
        }

diff --git a/onep-cli/src/otp.rs b/onep-cli/src/otp.rs
new file mode 100644
index 0000000..e5899dc
--- /dev/null
+++ b/onep-cli/src/otp.rs
@@ -0,0 +1,81 @@
//! Handles OTP code generation
use std::convert::TryFrom;
use url::Url;

pub enum TwoFactorAuth {
    Totp(libreauth::oath::TOTP),
}

pub struct TwoFactorAuthResponse {
    pub value: String,
}

impl TwoFactorAuth {
    pub fn generate(&self) -> TwoFactorAuthResponse {
        match &self {
            TwoFactorAuth::Totp(inner) => TwoFactorAuthResponse {
                value: inner.generate(),
            },
        }
    }
}

impl TryFrom<&str> for TwoFactorAuth {
    type Error = ();

    fn try_from(key: &str) -> Result<TwoFactorAuth, ()> {
        if let Ok(uri) = url::Url::parse(&key) {
            if let Ok(tfa) = Self::try_from(uri) {
                return Ok(tfa);
            }
        }

        Ok(TwoFactorAuth::Totp(
            libreauth::oath::TOTPBuilder::new()
                .base32_key(&key.replace(" ", ""))
                .finalize()
                .unwrap(),
        ))
    }
}

impl TryFrom<Url> for TwoFactorAuth {
    type Error = ();

    fn try_from(url: Url) -> Result<TwoFactorAuth, ()> {
        if url.scheme() != "otpauth" {
            return Err(());
        }

        if url.host_str() != Some("totp") {
            return Err(());
        }

        let mut query = url.query_pairs();

        let mut builder = &mut libreauth::oath::TOTPBuilder::new();

        if let Some(secret) = query.find(|v| v.0 == "secret") {
            builder = builder.base32_key(&secret.1);
        }

        if let Some(digits) = query.find(|v| v.0 == "digits") {
            builder = builder.output_len(digits.1.parse().map_err(|_| ())?);
        }

        if let Some(algorithm) = query.find(|v| v.0 == "algorithm") {
            builder = builder.hash_function(match algorithm.1.as_ref() {
                "sha1" => libreauth::hash::HashFunction::Sha1,
                "sha256" => libreauth::hash::HashFunction::Sha256,
                "sha512" => libreauth::hash::HashFunction::Sha512,
                _ => return Err(()),
            });
        }

        if let Some(period) = query.find(|v| v.0 == "period") {
            builder = builder.period(period.1.parse().map_err(|_| ())?);
        }

        Ok(TwoFactorAuth::Totp(builder.finalize().unwrap()))
    }
}