Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions cursive/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ use cursive::{
};
use lazy_static::lazy_static;
use pass::Result;
use ripasso::pass::Recipient;
use ripasso::{crypto::CryptoImpl, pass};
use ripasso::{crypto::CryptoImpl, pass, pass::Recipient};

lazy_static! {
static ref CLIPBOARD: Arc<Mutex<Clipboard>> = Arc::new(Mutex::new(Clipboard::new().unwrap()));
Expand Down
126 changes: 120 additions & 6 deletions cursive/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ use ripasso::{
pass::{
OwnerTrustLevel, PasswordStore, Recipient, SignatureStatus, all_recipients_from_stores,
},
passphrase_generator::passphrase_generator,
password_generator::password_generator,
};
use unic_langid::LanguageIdentifier;

Expand Down Expand Up @@ -442,8 +444,23 @@ fn open(ui: &mut Cursive, store: PasswordStoreType) -> Result<()> {
new_secret.zeroize();

})
.button(CATALOG.gettext("Generate"), move |s| {
let mut new_password = ripasso::words::generate_password(6);
.button(CATALOG.gettext("Generate Password"), move |s| {
let mut new_password = password_generator(20, 0);
s.call_on_name("editbox", |e: &mut TextArea| {
e.set_content(&new_password);
});
new_password.zeroize()
})


.button(CATALOG.gettext("Generate Passphrase"), move |s| {
let mut new_password = match passphrase_generator(6) {
Ok(words) => words.join(" "),
Err(err) => {
helpers::errorbox(s, &ripasso::pass::Error::from(err));
return;
}
};
s.call_on_name("editbox", |e: &mut TextArea| {
e.set_content(&new_password);
});
Expand Down Expand Up @@ -653,12 +670,12 @@ fn create_save(s: &mut Cursive, store: PasswordStoreType) {
do_new_password_save(s, path.as_ref(), password.as_ref(), store, false);
}
}

fn create(ui: &mut Cursive, store: PasswordStoreType) {
let mut fields = LinearLayout::vertical();
let mut path_fields = LinearLayout::horizontal();
let mut password_fields = LinearLayout::horizontal();
let mut note_fields = LinearLayout::horizontal();

path_fields.add_child(
TextView::new(CATALOG.gettext("Path: "))
.with_name("path_name")
Expand All @@ -669,6 +686,7 @@ fn create(ui: &mut Cursive, store: PasswordStoreType) {
.with_name("new_path_input")
.fixed_size((50_usize, 1_usize)),
);

password_fields.add_child(
TextView::new(CATALOG.gettext("Password: "))
.with_name("password_name")
Expand All @@ -680,22 +698,116 @@ fn create(ui: &mut Cursive, store: PasswordStoreType) {
.with_name("new_password_input")
.fixed_size((50_usize, 1_usize)),
);

note_fields.add_child(
TextView::new(CATALOG.gettext("Note: "))
.with_name("note_name")
.fixed_size((10_usize, 1_usize)),
);
note_fields.add_child(TextArea::new().with_name("note_input").min_size((50, 1)));

fields.add_child(path_fields);
fields.add_child(password_fields);
fields.add_child(note_fields);

let store2 = store.clone();

let category_value = Arc::new(Mutex::new(0));
let reveal_flag = Arc::new(Mutex::new(false));
let password_length = Arc::new(Mutex::new(20_usize));

let d = Dialog::around(fields)
.title(CATALOG.gettext("Add new password"))
.button(CATALOG.gettext("Generate"), move |s| {
let new_password = ripasso::words::generate_password(6);
.button(CATALOG.gettext("Password Options"), {
let category_value = category_value.clone();
let reveal_flag = reveal_flag.clone();
let password_length = password_length.clone();
move |s| {
let mut select = SelectView::<usize>::new();
select.add_item("Category 0 (ASCII 33–126)", 0);
select.add_item("Category 1 (ASCII 33–255)", 1);
select.set_selection(*category_value.lock().unwrap());
let select = select.with_name("password_category");

let length_input = EditView::new()
.content(password_length.lock().unwrap().to_string())
.with_name("password_length")
.fixed_width(5);

let reveal_checkbox = LinearLayout::horizontal()
.child(cursive::views::Checkbox::new().on_change({
let reveal_flag = reveal_flag.clone();
move |siv, checked| {
siv.call_on_name("new_password_input", |e: &mut EditView| {
e.set_secret(!checked);
});
*reveal_flag.lock().unwrap() = checked;
}
}))
.child(TextView::new("Reveal password"));

let dialog_content = LinearLayout::vertical()
.child(select.scrollable().fixed_size((30, 5)))
.child(
LinearLayout::horizontal()
.child(TextView::new("Length: "))
.child(length_input),
)
.child(reveal_checkbox);

let save_selection = {
let category_value = category_value.clone();
let password_length = password_length.clone();
move |s: &mut Cursive| {
s.call_on_name("password_category", |view: &mut SelectView<usize>| {
if let Some(sel) = view.selection() {
*category_value.lock().unwrap() = *sel;
}
});

s.call_on_name("password_length", |view: &mut EditView| {
if let Ok(len) = view.get_content().parse::<usize>() {
*password_length.lock().unwrap() = len;
}
});

s.pop_layer();
}
};

let popup = OnEventView::new(
Dialog::around(dialog_content)
.title("Password Options")
.button("OK", save_selection.clone())
.dismiss_button("Cancel"),
)
.on_event(Key::Enter, save_selection);

s.add_layer(popup);
}
})
.button(CATALOG.gettext("Generate Password"), {
let category_value = category_value.clone();
let password_length = password_length.clone();
move |s| {
let category = *category_value.lock().unwrap();
let length = *password_length.lock().unwrap();
let new_password =
ripasso::password_generator::password_generator(length, category);

s.call_on_name("new_password_input", |e: &mut EditView| {
e.set_content(new_password);
});
}
})
.button(CATALOG.gettext("Generate Passphrase"), move |s| {
let new_password = match ripasso::passphrase_generator::passphrase_generator(6) {
Ok(words) => words.join(" "),
Err(err) => {
helpers::errorbox(s, &ripasso::pass::Error::from(err));
return;
}
};
s.call_on_name("new_password_input", |e: &mut EditView| {
e.set_content(new_password);
});
Expand All @@ -710,7 +822,9 @@ fn create(ui: &mut Cursive, store: PasswordStoreType) {
s.pop_layer();
})
.on_event(Key::Enter, move |ui: &mut Cursive| {
create_save(ui, store2.clone())
if ui.screen_mut().len() == 1 {
create_save(ui, store2.clone());
}
});

ui.add_layer(ev);
Expand Down
13 changes: 8 additions & 5 deletions cursive/src/tests/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
use std::sync::Arc;

use crate::helpers::{
get_value_from_input, is_checkbox_checked, is_radio_button_selected, recipients_widths,
};
use cursive::{
view::Nameable,
views::{Checkbox, EditView, LinearLayout, RadioButton, RadioGroup},
};
use hex::FromHex;
use ripasso::crypto::CryptoImpl;
use ripasso::pass::{Comment, KeyRingStatus, OwnerTrustLevel, Recipient};
use ripasso::{
crypto::CryptoImpl,
pass::{Comment, KeyRingStatus, OwnerTrustLevel, Recipient},
};

use crate::helpers::{
get_value_from_input, is_checkbox_checked, is_radio_button_selected, recipients_widths,
};

#[test]
fn test_get_value_from_input() {
Expand Down
27 changes: 27 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ pub mod git;
/// This is the library part of ripasso, it implements the functions needed to manipulate a pass
/// directory.
pub mod pass;
/// Generates passphrases
pub mod passphrase_generator;
/// Generates ASCII and non ASCII passwords
pub mod password_generator;
/// All functions and structs related to handling the identity and signing of things
pub(crate) mod signature;
/// This is the library that handles password generation, based on the long word list from EFF
/// <https://www.eff.org/sv/deeplinks/2016/07/new-wordlists-random-passphrases>
pub mod words;

#[cfg(test)]
#[path = "tests/test_helpers.rs"]
pub mod test_helpers;
32 changes: 32 additions & 0 deletions src/passphrase_generator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use std::io;

use rand::seq::SliceRandom;

static WORDLIST: &str = include_str!("wordlists/eff_large.wordlist");

pub fn passphrase_generator(wordcount: i32) -> io::Result<Vec<String>> {
let words: Vec<String> = WORDLIST
.lines()
.map(|line| line.trim())
.filter(|line| !line.is_empty())
.map(String::from)
.collect();

if words.is_empty() {
eprintln!("The word list is empty!");
return Ok(Vec::new());
}

let mut rng = rand::thread_rng();

let selected = if words.len() <= wordcount as usize {
words.clone()
} else {
words
.choose_multiple(&mut rng, wordcount as usize)
.cloned()
.collect()
};

Ok(selected)
}
25 changes: 25 additions & 0 deletions src/password_generator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use rand::Rng;

pub fn password_generator(length: usize, category: usize) -> String {
let mut rng = rand::thread_rng();

if category == 0 {
(0..length)
.map(|_| {
let ascii_val = rng.gen_range(33..=126);
ascii_val as u8 as char
})
.collect()
} else {
(0..length)
.map(|_| {
let ascii_val = rng.gen_range(33..=255);
ascii_val as u8 as char
})
.collect()
}
}

#[cfg(test)]
#[path = "tests/password_generator.rs"]
mod password_generator;
3 changes: 2 additions & 1 deletion src/tests/pass.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::{env, fs::File, path::PathBuf};

use config::ConfigBuilder;
use git2::Repository;
use hex::FromHex;
Expand All @@ -8,7 +10,6 @@ use sequoia_openpgp::{
stream::{Armorer, Message, Signer},
},
};
use std::{env, fs::File, path::PathBuf};
use tempfile::tempdir;

use super::*;
Expand Down
15 changes: 15 additions & 0 deletions src/tests/password_generator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use crate::password_generator::password_generator;

#[test]
fn password_length_varies_correctly() {
for len in [8, 12, 20] {
let pass = password_generator(len, 0);
assert_eq!(
pass.len(),
len,
"Expected {} chars, got {}",
len,
pass.len()
);
}
}
6 changes: 3 additions & 3 deletions src/tests/test_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ use std::{

use flate2::read::GzDecoder;
use hex::FromHex;
use sequoia_openpgp::crypto::SessionKey;
use sequoia_openpgp::packet::UserID;
use sequoia_openpgp::types::SymmetricAlgorithm;
use sequoia_openpgp::{
Cert, KeyHandle, KeyID,
cert::CertBuilder,
crypto::SessionKey,
packet::UserID,
parse::{
Parse,
stream::{DecryptionHelper, DecryptorBuilder, MessageStructure, VerificationHelper},
},
policy::StandardPolicy,
types::SymmetricAlgorithm,
};
use tar::Archive;

Expand Down
15 changes: 0 additions & 15 deletions src/tests/words.rs

This file was deleted.

Loading
Loading