1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
extern crate rand;

use std::env;
use std::io::{self, BufReader};
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use rand::{thread_rng, Rng};

#[derive(Debug)]
pub enum DiceError {
    Io(io::Error),
    Var(env::VarError),
}

impl From<io::Error> for DiceError {
    fn from(err: io::Error) -> DiceError {
        DiceError::Io(err)
    }
}

impl From<env::VarError> for DiceError {
    fn from(err: env::VarError) -> DiceError {
        DiceError::Var(err)
    }
}

pub struct DicewareGen {
    words: Vec<String>,
    rng: rand::ThreadRng,
}

impl DicewareGen {
    pub fn new() -> Result<DicewareGen, DiceError> {
        let dirs = vec!(
            // if env var doesn't exist, then try reading from current directory.
            match env::var("DICEWARE_GEN_WORDLISTS") {
                Ok(p) => p,
                Err(_) => String::from(""),
            },
            String::from("/usr/share/diceware-gen/"),
        );
        let f = read_order(dirs, "eff_large_wordlist.txt")?;

        Ok(DicewareGen {
            words: {
                BufReader::new(f).lines().map(|line| {
                    line
                }).collect::<Result<Vec<String>, io::Error>>()?
            },
            rng: thread_rng(),
        })
    }

    pub fn gen(mut self, rounds: u8) -> Vec<String> {
        (0..rounds).map(|_| {
            let x: usize = self.rng.gen_range(0, 7775);
            self.words[x].clone()
        }).collect::<Vec<String>>()
    }
}

fn read_order(dirs: Vec<String>, f: &str) -> Result<File, DiceError> {
    for d in dirs {
        let p = Path::new(&d).join(f);

        match File::open(p) {
            Ok(f) => return Ok(f),
            Err(_) => {},
        }
    }

    Err(DiceError::Io(io::Error::new(io::ErrorKind::Other, "could not read wordlist")))
}