alea 0.4.0.0 → 0.5.0.0
raw patch · 5 files changed
+107/−85 lines, 5 filesdep +optparse-applicativedep +randomdep +textdep −argparserdep −containersdep −threefish
Dependencies added: optparse-applicative, random, text
Dependencies removed: argparser, containers, threefish
Files
- alea.cabal +5/−5
- src/Alea/Diceware.hs +34/−20
- src/Alea/List.hs +0/−10
- src/Alea/Random.hs +0/−6
- src/Main.hs +68/−44
alea.cabal view
@@ -1,5 +1,5 @@ name: alea-version: 0.4.0.0+version: 0.5.0.0 synopsis: a diceware passphrase generator description: @@ -10,7 +10,7 @@ homepage: https://github.com/Rnhmjoj/alea license: MIT license-file: LICENSE-author: Rnhmjoj+author: rnhmjoj maintainer: micheleguerinirocco@me.com copyright: (C) Michele Guerini Rocco 2015 category: Utility@@ -27,8 +27,8 @@ main-is: Main.hs hs-source-dirs: src default-language: Haskell2010- other-modules: Alea.Diceware, Alea.List, Alea.Random+ other-modules: Alea.Diceware other-extensions: DeriveDataTypeable, RecordWildCards- build-depends: base >=4.8 && < 5.0, containers,- argparser, threefish+ build-depends: base >=4.8 && < 5.0, random, text,+ optparse-applicative ghc-options: -O2
src/Alea/Diceware.hs view
@@ -1,28 +1,42 @@+{-# LANGUAGE OverloadedStrings #-}+ module Alea.Diceware where -import Data.List (intersect, elemIndex)-import Alea.List+import Data.Monoid ((<>))+import Data.List (intersect, elemIndex)+import Data.Text (Text, pack)+import System.Random+import qualified Data.Text as T --- Diceware dictionary type-type Diceware = [String] --- Parse file content to a Diceware-parseDiceware :: String -> Diceware-parseDiceware x = map (last . split ' ') $ lines x+-- | Diceware dictionary alias+type Diceware = [Text] --- Lookup word with dice index-readDiceware :: Diceware -> Int -> String-readDiceware d n = show n ++ " -> " ++- case (undice n) of- Just x -> d !! x- Nothing -> "Does not exist" --- Lookup word with linear index-readDiceware' :: Diceware -> Int -> String+-- | Produces k random indices to be extracted+randIndices :: Int -> Int -> IO [Int]+randIndices n k = take k <$> randomRs (0, n-1) <$> newStdGen+++-- | Parse file content to a Diceware+parseDiceware :: Text -> Diceware+parseDiceware = map (last . T.splitOn " ") . T.lines+++-- | Lookup word with dice index+readDiceware :: Diceware -> Int -> Text+readDiceware d n =+ pack (show n) <> " -> " <>+ maybe "Does not exists" (d !!) (fromDice n)+++-- | Lookup word with linear index+readDiceware' :: Diceware -> Int -> Text readDiceware' d n = d !! n --- Dice numbers to numbers--- Ex. undice 11121 == Just 6-undice :: Int -> Maybe Int-undice n = elemIndex n . filter- (null . (intersect "0789") . show) $ [11111..66666]++-- | Dice numbers to numbers+-- > fromDice 11121 == Just 6+fromDice :: Int -> Maybe Int+fromDice n = elemIndex n (filter isDice [11111..66666])+ where isDice = null . (intersect "0789") . show
− src/Alea/List.hs
@@ -1,10 +0,0 @@-module Alea.List where---- Split a list into a list of lists--- ex. split ',' "ab,cd,ef" == ["ab","cd","ef"]-split :: (Eq a) => a -> [a] -> [[a]]-split _ [] = [[]]-split delim (c:cs)- | c == delim = [] : rest- | otherwise = (c : head rest) : tail rest- where rest = split delim cs
− src/Alea/Random.hs
@@ -1,6 +0,0 @@-module Alea.Random where--import Crypto.Threefish.Random--randWords :: Int -> Int -> IO [Int]-randWords n k = take k . randomRs (0, n-1) <$> newSkeinGen
src/Main.hs view
@@ -1,55 +1,79 @@ {-# LANGUAGE RecordWildCards #-} -import System.IO-import System.Console.ArgParser-import Control.Monad--import Paths_alea (getDataFileName)+import Control.Monad (when, forever)+import Data.Text (unpack)+import Options.Applicative import Alea.Diceware-import Alea.Random+import Paths_alea (getDataFileName) -data ProgArgs = ProgArgs- { interactive :: Bool- , dictionary :: FilePath- , phraseLength :: Int- , phrases :: Int- } deriving (Show)+import qualified Data.Text as T+import qualified Data.Text.IO as I -parser :: IO (ParserSpec ProgArgs)-parser = (\path -> ProgArgs- `parsedBy` boolFlag "interactive" `Descr` "Manually insert numbers"- `andBy` optFlag path "dictionary" `Descr` "Specify dictionary file path"- `andBy` optFlag 6 "lenght" `Descr` "Number of words in a passphrase"- `andBy` optFlag 1 "phrases" `Descr` "Number of passphrases to generate")- <$> path -interface :: IO (CmdLnInterface ProgArgs)-interface =- (`setAppDescr` "A diceware passphrase generator") <$>- (`setAppEpilog` "Alea iacta est.") <$>- (mkApp =<< parser)+-- * Command line interface description +-- | Program arguments record+data Options = Options+ { interactive :: Bool+ , dictionary :: Maybe FilePath+ , phraseLength :: Int+ , phrases :: Int+ }+++-- | Argument parser +options :: Parser Options+options = Options + <$> switch+ ( long "interactive"+ <> help "Manually insert numbers from a dice" )+ <*> optional (option auto+ ( long "dictionary"+ <> metavar "FILEPATH"+ <> help "Specify dictionary filepath" ))+ <*> option auto+ ( long "length"+ <> value 6+ <> metavar "N"+ <> help "Number of words in a passphrase")+ <*> option auto+ ( long "phrases"+ <> value 1+ <> metavar "M"+ <> help "Number of passphrases to generate" )+ ++-- | Program description+description :: ParserInfo Options+description = info (helper <*> options)+ ( fullDesc+ <> progDesc "A diceware passphrase generator"+ <> footer "Alea iacta est." )++++-- * Program++-- | Main function main :: IO ()-main = interface >>= flip runApp (readDict >=> exec)+main = execParser description >>= diceware --- Default path of the dictionary-path :: IO FilePath-path = getDataFileName "dict/diceware" --- Read dictionary file-readDict :: ProgArgs -> IO ProgArgs-readDict args@ProgArgs{..} =- (\x -> args {dictionary = x}) <$> readFile dictionary+-- | Actual application +diceware :: Options -> IO ()+diceware opts@Options{..} = do+ path <- case dictionary of+ Nothing -> getDataFileName "dict/diceware"+ Just x -> return x+ dict <- parseDiceware <$> I.readFile path+ let size = length dict-1+ dice = readDiceware dict . read . unpack+ dice' = readDiceware' dict --- Main function-exec :: ProgArgs -> IO ()-exec args@ProgArgs{..} =- if interactive- then interact (unlines . map dice . lines)- else do- randWords dictSize phraseLength >>= putStrLn . unwords . map dice'- when (phrases > 1) $ exec args {phrases = phrases - 1}- where- (dict, dictSize) = (parseDiceware dictionary, length dict)- dice n = readDiceware dict (read n :: Int)- dice' n = readDiceware' dict n+ if interactive+ then forever (dice <$> I.getLine >>= I.putStrLn)+ else do+ indices <- randIndices size phraseLength+ I.putStrLn $ T.unwords (map dice' indices)+ when (phrases > 1) $+ diceware opts {phrases = phrases - 1}