upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/cli_interactor.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2023-09-01 00:00:00 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2023-09-01 00:00:00 +0000
commit96660a90e4cd296a2922d7a547de4cd9d0b1928b (patch)
treee5216e22ee1a3e1653d8d1ecd856f4f03615d6a1 /src/cli_interactor.rs
parent6423baebd92e45c9be85157c443dff42e65d8d14 (diff)
feat(login) password login using encrypted nsec
Enables the user to only handle the nsec upon first use of the tool by encrypting it with a password and storing it on disk in an application cache. The approach to encryption draws heavily from that used by the gossip nostr client. - unencrypted nsec is zeroed from memory - a salt is used to defend against rainbow tables - computationally expensive key stretching defends against brute-force attacks of passwords with low entropy. There is UX trade-off between decryption speed and key-stretching computation. This UX challenge is exacerbated in a cli tool as decryption must take place more regularly. Thought was put into the selected n_log and a heavily reduced value is provided for long passwords where security benefits are smaller. A more granular reducing in computation was also considered by rejected to avoided to revealing just how weak a password is as most weak passwords are reused.
Diffstat (limited to 'src/cli_interactor.rs')
-rw-r--r--src/cli_interactor.rs31
1 files changed, 29 insertions, 2 deletions
diff --git a/src/cli_interactor.rs b/src/cli_interactor.rs
index 2f28aee..d7de087 100644
--- a/src/cli_interactor.rs
+++ b/src/cli_interactor.rs
@@ -1,5 +1,5 @@
1use anyhow::{bail, Result}; 1use anyhow::Result;
2use dialoguer::{theme::ColorfulTheme, Input}; 2use dialoguer::{theme::ColorfulTheme, Input, Password};
3#[cfg(test)] 3#[cfg(test)]
4use mockall::*; 4use mockall::*;
5 5
@@ -11,6 +11,7 @@ pub struct Interactor {
11#[cfg_attr(test, automock)] 11#[cfg_attr(test, automock)]
12pub trait InteractorPrompt { 12pub trait InteractorPrompt {
13 fn input(&self, parms: PromptInputParms) -> Result<String>; 13 fn input(&self, parms: PromptInputParms) -> Result<String>;
14 fn password(&self, parms: PromptPasswordParms) -> Result<String>;
14} 15}
15impl InteractorPrompt for Interactor { 16impl InteractorPrompt for Interactor {
16 fn input(&self, parms: PromptInputParms) -> Result<String> { 17 fn input(&self, parms: PromptInputParms) -> Result<String> {
@@ -19,6 +20,15 @@ impl InteractorPrompt for Interactor {
19 .interact_text()?; 20 .interact_text()?;
20 Ok(input) 21 Ok(input)
21 } 22 }
23 fn password(&self, parms: PromptPasswordParms) -> Result<String> {
24 let mut p = Password::with_theme(&self.theme);
25 p.with_prompt(parms.prompt);
26 if parms.confirm {
27 p.with_confirmation("confirm password", "passwords didnt match...");
28 }
29 let pass: String = p.interact()?;
30 Ok(pass)
31 }
22} 32}
23 33
24#[derive(Default)] 34#[derive(Default)]
@@ -32,3 +42,20 @@ impl PromptInputParms {
32 self 42 self
33 } 43 }
34} 44}
45
46#[derive(Default)]
47pub struct PromptPasswordParms {
48 pub prompt: String,
49 pub confirm: bool,
50}
51
52impl PromptPasswordParms {
53 pub fn with_prompt<S: Into<String>>(mut self, prompt: S) -> Self {
54 self.prompt = prompt.into();
55 self
56 }
57 pub const fn with_confirm(mut self) -> Self {
58 self.confirm = true;
59 self
60 }
61}