mirror of
https://github.com/redelmann/scat
synced 2025-01-09 22:24:19 +01:00
Initial import.
This commit is contained in:
commit
3edbc3421d
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
dist
|
||||||
|
cabal-dev
|
30
LICENSE
Normal file
30
LICENSE
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
Copyright (c) 2013, Romain Edelmann
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following
|
||||||
|
disclaimer in the documentation and/or other materials provided
|
||||||
|
with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of Romain Edelmann nor the names of other
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
7776
lists/diceware.txt
Normal file
7776
lists/diceware.txt
Normal file
File diff suppressed because it is too large
Load Diff
151
lists/pokemons.txt
Normal file
151
lists/pokemons.txt
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
Abra
|
||||||
|
Aerodactyl
|
||||||
|
Alakazam
|
||||||
|
Arbok
|
||||||
|
Arcanine
|
||||||
|
Articuno
|
||||||
|
Beedrill
|
||||||
|
Bellsprout
|
||||||
|
Blastoise
|
||||||
|
Bulbasaur
|
||||||
|
Butterfree
|
||||||
|
Caterpie
|
||||||
|
Chansey
|
||||||
|
Charizard
|
||||||
|
Charmander
|
||||||
|
Charmeleon
|
||||||
|
Clefable
|
||||||
|
Clefairy
|
||||||
|
Cloyster
|
||||||
|
Cubone
|
||||||
|
Dewgong
|
||||||
|
Diglett
|
||||||
|
Ditto
|
||||||
|
Dodrio
|
||||||
|
Doduo
|
||||||
|
Dragonair
|
||||||
|
Dragonite
|
||||||
|
Dratini
|
||||||
|
Drowzee
|
||||||
|
Dugtrio
|
||||||
|
Eevee
|
||||||
|
Ekans
|
||||||
|
Electabuzz
|
||||||
|
Electrode
|
||||||
|
Exeggcute
|
||||||
|
Exeggutor
|
||||||
|
Farfetch'd
|
||||||
|
Fearow
|
||||||
|
Flareon
|
||||||
|
Gastly
|
||||||
|
Gengar
|
||||||
|
Geodude
|
||||||
|
Gloom
|
||||||
|
Golbat
|
||||||
|
Goldeen
|
||||||
|
Golduck
|
||||||
|
Golem
|
||||||
|
Graveler
|
||||||
|
Grimer
|
||||||
|
Growlithe
|
||||||
|
Gyarados
|
||||||
|
Haunter
|
||||||
|
Hitmonchan
|
||||||
|
Hitmonlee
|
||||||
|
Horsea
|
||||||
|
Hypno
|
||||||
|
Ivysaur
|
||||||
|
Jigglypuff
|
||||||
|
Jolteon
|
||||||
|
Jynx
|
||||||
|
Kabuto
|
||||||
|
Kabutops
|
||||||
|
Kadabra
|
||||||
|
Kakuna
|
||||||
|
Kangaskhan
|
||||||
|
Kingler
|
||||||
|
Koffing
|
||||||
|
Krabby
|
||||||
|
Lapras
|
||||||
|
Lickitung
|
||||||
|
Machamp
|
||||||
|
Machoke
|
||||||
|
Machop
|
||||||
|
Magikarp
|
||||||
|
Magmar
|
||||||
|
Magnemite
|
||||||
|
Magneton
|
||||||
|
Mankey
|
||||||
|
Marowak
|
||||||
|
Meowth
|
||||||
|
Metapod
|
||||||
|
Mew
|
||||||
|
Mewtwo
|
||||||
|
Moltres
|
||||||
|
Mr. Mime
|
||||||
|
Muk
|
||||||
|
Nidoking
|
||||||
|
Nidoqueen
|
||||||
|
Nidoran Male
|
||||||
|
Nidoran Female
|
||||||
|
Nidorina
|
||||||
|
Nidorino
|
||||||
|
Ninetales
|
||||||
|
Oddish
|
||||||
|
Omanyte
|
||||||
|
Omastar
|
||||||
|
Onix
|
||||||
|
Paras
|
||||||
|
Parasect
|
||||||
|
Persian
|
||||||
|
Pidgeot
|
||||||
|
Pidgeotto
|
||||||
|
Pidgey
|
||||||
|
Pikachu
|
||||||
|
Pinsir
|
||||||
|
Poliwag
|
||||||
|
Poliwhirl
|
||||||
|
Poliwrath
|
||||||
|
Ponyta
|
||||||
|
Porygon
|
||||||
|
Primeape
|
||||||
|
Psyduck
|
||||||
|
Raichu
|
||||||
|
Rapidash
|
||||||
|
Raticate
|
||||||
|
Rattata
|
||||||
|
Rhydon
|
||||||
|
Rhyhorn
|
||||||
|
Sandshrew
|
||||||
|
Sandslash
|
||||||
|
Scyther
|
||||||
|
Seadra
|
||||||
|
Seaking
|
||||||
|
Seel
|
||||||
|
Shellder
|
||||||
|
Slowbro
|
||||||
|
Slowpoke
|
||||||
|
Snorlax
|
||||||
|
Spearow
|
||||||
|
Squirtle
|
||||||
|
Starmie
|
||||||
|
Staryu
|
||||||
|
Tangela
|
||||||
|
Tauros
|
||||||
|
Tentacool
|
||||||
|
Tentacruel
|
||||||
|
Vaporeon
|
||||||
|
Venomoth
|
||||||
|
Venonat
|
||||||
|
Venusaur
|
||||||
|
Victreebel
|
||||||
|
Vileplume
|
||||||
|
Voltorb
|
||||||
|
Vulpix
|
||||||
|
Wartortle
|
||||||
|
Weedle
|
||||||
|
Weepinbell
|
||||||
|
Weezing
|
||||||
|
Wigglytuff
|
||||||
|
Zapdos
|
||||||
|
Zubat
|
61
scat.cabal
Normal file
61
scat.cabal
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
-- Initial scat.cabal generated by cabal init. For further documentation,
|
||||||
|
-- see http://haskell.org/cabal/users-guide/
|
||||||
|
|
||||||
|
-- The name of the package.
|
||||||
|
name: scat
|
||||||
|
|
||||||
|
-- The package version. See the Haskell package versioning policy (PVP)
|
||||||
|
-- for standards guiding when and how versions should be incremented.
|
||||||
|
-- http://www.haskell.org/haskellwiki/Package_versioning_policy
|
||||||
|
-- PVP summary: +-+------- breaking API changes
|
||||||
|
-- | | +----- non-breaking API additions
|
||||||
|
-- | | | +--- code changes with no API change
|
||||||
|
version: 0.1.0.0
|
||||||
|
|
||||||
|
-- A short (one-line) description of the package.
|
||||||
|
synopsis: Generates unique passwords for various websites from a single password.
|
||||||
|
|
||||||
|
-- A longer description of the package.
|
||||||
|
-- description:
|
||||||
|
|
||||||
|
-- The license under which the package is released.
|
||||||
|
license: BSD3
|
||||||
|
|
||||||
|
-- The file containing the license text.
|
||||||
|
license-file: LICENSE
|
||||||
|
|
||||||
|
-- The package author(s).
|
||||||
|
author: Romain Edelmann
|
||||||
|
|
||||||
|
-- An email address to which users can send suggestions, bug reports, and
|
||||||
|
-- patches.
|
||||||
|
maintainer: romain.edelmann@gmail.com
|
||||||
|
|
||||||
|
-- A copyright notice.
|
||||||
|
-- copyright:
|
||||||
|
|
||||||
|
category: Password
|
||||||
|
|
||||||
|
build-type: Simple
|
||||||
|
|
||||||
|
-- Constraint on the version of Cabal needed to build this package.
|
||||||
|
cabal-version: >=1.8
|
||||||
|
|
||||||
|
data-dir: lists
|
||||||
|
|
||||||
|
data-files: *.txt
|
||||||
|
|
||||||
|
executable scat
|
||||||
|
-- .hs or .lhs file containing the Main module.
|
||||||
|
main-is: Scat.hs
|
||||||
|
|
||||||
|
ghc-options: -Wall -O3
|
||||||
|
|
||||||
|
hs-source-dirs: src
|
||||||
|
|
||||||
|
-- Modules included in this executable, other than Main.
|
||||||
|
other-modules: Scat.Builder, Scat.Schemas, Scat.Options, Scat.Utils.Permutation, Paths_scat
|
||||||
|
|
||||||
|
-- Other library packages from which modules are imported.
|
||||||
|
build-depends: base ==4.5.*, SHA ==1.6.*, bytestring ==0.9.*, optparse-applicative ==0.5.*, mtl ==2.1.*, vector ==0.10.*
|
||||||
|
|
118
src/Scat.hs
Normal file
118
src/Scat.hs
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
{-# LANGUAGE OverloadedStrings, PatternGuards #-}
|
||||||
|
|
||||||
|
-- | Password scatterer.
|
||||||
|
module Main (main) where
|
||||||
|
|
||||||
|
import Data.Monoid
|
||||||
|
import Data.Digest.Pure.SHA
|
||||||
|
import Data.ByteString.Lazy (ByteString)
|
||||||
|
import qualified Data.ByteString.Char8 as C
|
||||||
|
import qualified Data.ByteString.Lazy.Char8 as LC
|
||||||
|
import qualified Data.ByteString.Lazy as BS
|
||||||
|
import System.IO
|
||||||
|
import System.Exit
|
||||||
|
import Control.Exception
|
||||||
|
import Control.Monad.Reader
|
||||||
|
|
||||||
|
import Scat.Schemas
|
||||||
|
import Scat.Builder
|
||||||
|
import Scat.Options
|
||||||
|
|
||||||
|
-- | Generates the seed integer given a key and a password.
|
||||||
|
scatter :: ByteString -> ByteString -> Integer
|
||||||
|
scatter k pw = integerDigest $ sha512 (k <> pw)
|
||||||
|
|
||||||
|
-- | Main type of the program.
|
||||||
|
type Scat a = ReaderT Options IO a
|
||||||
|
|
||||||
|
{- | Generates a password, given a input password,
|
||||||
|
a key (category, website, etc.),
|
||||||
|
and a password `Schema`.
|
||||||
|
|
||||||
|
The parameters are specified as command line arguments.
|
||||||
|
The password can be read from @stdin@ if not already provided. -}
|
||||||
|
main :: IO ()
|
||||||
|
main = getOptions >>= runReaderT scat
|
||||||
|
|
||||||
|
-- | Main program.
|
||||||
|
scat :: Scat ()
|
||||||
|
scat = do
|
||||||
|
k <- getKey
|
||||||
|
s <- getSchema
|
||||||
|
pw <- getPassword
|
||||||
|
printVerbose "Generated password:\n"
|
||||||
|
liftIO $ putStrLn $ evalBuilder s $ scatter k pw
|
||||||
|
|
||||||
|
printVerbose :: String -> Scat ()
|
||||||
|
printVerbose str = do
|
||||||
|
v <- fmap verbose ask
|
||||||
|
when v $ liftIO $ do
|
||||||
|
putStr str
|
||||||
|
hFlush stdout
|
||||||
|
|
||||||
|
-- | Gets the password.
|
||||||
|
getPassword :: Scat ByteString
|
||||||
|
getPassword = do
|
||||||
|
mpw <- fmap password ask
|
||||||
|
pw <- case mpw of
|
||||||
|
-- Ask for the password on stdin.
|
||||||
|
Nothing -> do
|
||||||
|
c <- fmap confirm ask
|
||||||
|
if c
|
||||||
|
then getPassConfirm
|
||||||
|
else getPass
|
||||||
|
|
||||||
|
-- Retrieve the password from the arguments.
|
||||||
|
Just st -> return $ C.pack st
|
||||||
|
return $ BS.fromChunks [pw]
|
||||||
|
where
|
||||||
|
getPass = askPassword "Password: "
|
||||||
|
|
||||||
|
getPassConfirm = do
|
||||||
|
a <- askPassword "Password: "
|
||||||
|
b <- askPassword "Confirm: "
|
||||||
|
if (a == b)
|
||||||
|
then return a
|
||||||
|
else do
|
||||||
|
printVerbose "Passwords do not match, please retry.\n"
|
||||||
|
getPassConfirm
|
||||||
|
|
||||||
|
askPassword :: String -> Scat C.ByteString
|
||||||
|
askPassword str = do
|
||||||
|
printVerbose str
|
||||||
|
old <- liftIO $ hGetEcho stdin
|
||||||
|
pw <- liftIO $ bracket_
|
||||||
|
(hSetEcho stdin False)
|
||||||
|
(hSetEcho stdin old)
|
||||||
|
C.getLine
|
||||||
|
printVerbose "\n"
|
||||||
|
return pw
|
||||||
|
|
||||||
|
-- | Gets the key.
|
||||||
|
getKey :: Scat ByteString
|
||||||
|
getKey = fmap (LC.pack . key) ask
|
||||||
|
|
||||||
|
-- | Gets the schema to generate the new password.
|
||||||
|
getSchema :: Scat Schema
|
||||||
|
getSchema = do
|
||||||
|
name <- fmap schema ask
|
||||||
|
case name of
|
||||||
|
-- Safe, the default.
|
||||||
|
"safe" -> return safe
|
||||||
|
|
||||||
|
-- Alphanumeric.
|
||||||
|
"alpha" -> return alphanumeric
|
||||||
|
|
||||||
|
-- PIN.
|
||||||
|
'p' : 'i' : 'n' : xs | [(n, "")] <- reads xs -> return $ pin n
|
||||||
|
|
||||||
|
-- Passphrase using Diceware's list.
|
||||||
|
"diceware" -> liftIO diceware
|
||||||
|
|
||||||
|
-- Passphrase using Pokemons.
|
||||||
|
"pokemons" -> liftIO pokemons
|
||||||
|
|
||||||
|
-- Unkown.
|
||||||
|
_ -> liftIO $ do
|
||||||
|
hPutStrLn stderr "Error: Unknown schema"
|
||||||
|
exitFailure
|
131
src/Scat/Builder.hs
Normal file
131
src/Scat/Builder.hs
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
|
||||||
|
{- | This modules defines `Builder`s,
|
||||||
|
which are simple parsers on `Integer`. -}
|
||||||
|
module Scat.Builder
|
||||||
|
(
|
||||||
|
-- * Type
|
||||||
|
Builder
|
||||||
|
|
||||||
|
-- * Execution
|
||||||
|
, runBuilder
|
||||||
|
, evalBuilder
|
||||||
|
, execBuilder
|
||||||
|
|
||||||
|
-- * Primitives
|
||||||
|
|
||||||
|
-- ** Numbers
|
||||||
|
, lessThan
|
||||||
|
, inRange
|
||||||
|
|
||||||
|
-- ** Char
|
||||||
|
, digit
|
||||||
|
, letter
|
||||||
|
, lower
|
||||||
|
, upper
|
||||||
|
, ascii
|
||||||
|
, special
|
||||||
|
|
||||||
|
-- * Combinators
|
||||||
|
, useup
|
||||||
|
, shuffle
|
||||||
|
, oneOf
|
||||||
|
, oneOfV
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.Char (ord, chr)
|
||||||
|
import Data.Monoid
|
||||||
|
import Control.Applicative
|
||||||
|
import Control.Monad
|
||||||
|
import Control.Arrow (second)
|
||||||
|
import Data.Vector (Vector)
|
||||||
|
import qualified Data.Vector as V
|
||||||
|
|
||||||
|
import Scat.Utils.Permutation
|
||||||
|
|
||||||
|
-- | Parser acting on an `Integer`.
|
||||||
|
newtype Builder a = Builder
|
||||||
|
{ runBuilder :: Integer -> (Integer, a)
|
||||||
|
-- ^ Runs the builder.
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | Evaluates the builder.
|
||||||
|
evalBuilder :: Builder a -> Integer -> a
|
||||||
|
evalBuilder b n = snd $ runBuilder b n
|
||||||
|
|
||||||
|
-- | Executes the builder.
|
||||||
|
execBuilder :: Builder a -> Integer -> Integer
|
||||||
|
execBuilder b n = fst $ runBuilder b n
|
||||||
|
|
||||||
|
instance Functor Builder where
|
||||||
|
fmap f (Builder g) = Builder $ second f . g
|
||||||
|
|
||||||
|
instance Applicative Builder where
|
||||||
|
pure x = Builder (\ n -> (n, x))
|
||||||
|
f <*> x = Builder $ \ n ->
|
||||||
|
let (n', g) = runBuilder f n
|
||||||
|
in fmap g $ runBuilder x n'
|
||||||
|
|
||||||
|
instance Monad Builder where
|
||||||
|
return = pure
|
||||||
|
x >>= f = Builder $ \ n ->
|
||||||
|
let (n', v) = runBuilder x n
|
||||||
|
in runBuilder (f v) n'
|
||||||
|
|
||||||
|
instance Monoid a => Monoid (Builder a) where
|
||||||
|
mempty = return mempty
|
||||||
|
mappend a b = mappend <$> a <*> b
|
||||||
|
|
||||||
|
-- | Returns a positive integer less than `i`.
|
||||||
|
lessThan :: Integral a => a -> Builder a
|
||||||
|
lessThan i = Builder $ \ n -> second fromIntegral $ quotRem n $ fromIntegral i
|
||||||
|
|
||||||
|
-- | Returns an integer between `a` and `b`, both inclusive.
|
||||||
|
inRange :: Integral a => (a, a) -> Builder a
|
||||||
|
inRange (a, b) = fmap (+ a) $ lessThan $ b + 1 - a
|
||||||
|
|
||||||
|
-- | Returns a lower case letter.
|
||||||
|
lower :: Builder Char
|
||||||
|
lower = fmap (chr . (+ ord 'a')) $ lessThan 26
|
||||||
|
|
||||||
|
-- | Returns an upper case letter.
|
||||||
|
upper :: Builder Char
|
||||||
|
upper = fmap (chr . (+ ord 'A')) $ lessThan 26
|
||||||
|
|
||||||
|
-- | Returns an printable ascii char.
|
||||||
|
ascii :: Builder Char
|
||||||
|
ascii = fmap chr $ inRange (32, 126)
|
||||||
|
|
||||||
|
-- | Returns a digit.
|
||||||
|
digit :: Builder Char
|
||||||
|
digit = fmap chr $ inRange (48, 57)
|
||||||
|
|
||||||
|
-- | Returns a letter.
|
||||||
|
letter :: Builder Char
|
||||||
|
letter = join $ oneOf [upper, lower]
|
||||||
|
|
||||||
|
-- | Returns a special character.
|
||||||
|
special :: Builder Char
|
||||||
|
special = oneOf "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
|
||||||
|
|
||||||
|
-- | Returns one element of the list.
|
||||||
|
oneOf :: [a] -> Builder a
|
||||||
|
oneOf [] = error "oneOf on empty list"
|
||||||
|
oneOf xs = fmap (xs !!) $ lessThan $ length xs
|
||||||
|
|
||||||
|
-- | Returns on element of the vector.
|
||||||
|
oneOfV :: Vector a -> Builder a
|
||||||
|
oneOfV vect = fmap (vect V.!) $ lessThan $ V.length vect
|
||||||
|
|
||||||
|
{- | Returns the results of the input builder
|
||||||
|
until the consummed integer is 0. -}
|
||||||
|
useup :: Builder a -> Builder [a]
|
||||||
|
useup b = Builder $ \ n ->
|
||||||
|
if n == 0 then (0, []) else runBuilder
|
||||||
|
((:) <$> b <*> useup b) n
|
||||||
|
|
||||||
|
-- | Shuffles the input list.
|
||||||
|
shuffle :: [a] -> Builder [a]
|
||||||
|
shuffle xs = fmap (perm xs) $ lessThan $ fact $ length xs
|
||||||
|
where
|
||||||
|
fact :: Int -> Int
|
||||||
|
fact n = product [1 .. n]
|
75
src/Scat/Options.hs
Normal file
75
src/Scat/Options.hs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
-- | Parses command-line arguments.
|
||||||
|
module Scat.Options
|
||||||
|
(
|
||||||
|
-- * Type
|
||||||
|
Options
|
||||||
|
|
||||||
|
-- * Accessors
|
||||||
|
, password
|
||||||
|
, key
|
||||||
|
, schema
|
||||||
|
, verbose
|
||||||
|
, confirm
|
||||||
|
|
||||||
|
-- * Execution
|
||||||
|
, getOptions
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.Monoid
|
||||||
|
import Options.Applicative
|
||||||
|
|
||||||
|
-- | All program options.
|
||||||
|
data Options = Options
|
||||||
|
{ password :: Maybe String
|
||||||
|
-- ^ Password, optionally provided.
|
||||||
|
, key :: String
|
||||||
|
-- ^ Key or category for the password.
|
||||||
|
, schema :: String
|
||||||
|
-- ^ Name of the schema to use.
|
||||||
|
, verbose_ :: Bool
|
||||||
|
-- ^ Verbosity. If false, do not print anything but the generated password.
|
||||||
|
, confirm :: Bool
|
||||||
|
-- ^ Indicates if the password must be confirmed. Activates verbosity.
|
||||||
|
}
|
||||||
|
|
||||||
|
verbose :: Options -> Bool
|
||||||
|
verbose opts = verbose_ opts || confirm opts
|
||||||
|
|
||||||
|
-- | Parses the arguments from the command line.
|
||||||
|
getOptions :: IO Options
|
||||||
|
getOptions = execParser opts
|
||||||
|
where
|
||||||
|
opts = info (helper <*> options)
|
||||||
|
(fullDesc
|
||||||
|
<> progDesc "Safely generate passwords derived from a unique password."
|
||||||
|
<> header "scat - a password scatterer")
|
||||||
|
|
||||||
|
-- | Option parser.
|
||||||
|
options :: Parser Options
|
||||||
|
options = Options
|
||||||
|
<$> optional
|
||||||
|
(strOption (short 'p'
|
||||||
|
<> long "password"
|
||||||
|
<> help "The password"
|
||||||
|
<> metavar "PASSWORD"))
|
||||||
|
<*> strOption
|
||||||
|
(short 'k'
|
||||||
|
<> long "key"
|
||||||
|
<> help "Key associated (website, email address, ...) (mandatory)"
|
||||||
|
<> metavar "KEY")
|
||||||
|
<*> strOption
|
||||||
|
(short 's'
|
||||||
|
<> long "schema"
|
||||||
|
<> help "Schema for the generated password"
|
||||||
|
<> metavar "SCHEMA"
|
||||||
|
<> value "safe"
|
||||||
|
<> showDefault)
|
||||||
|
<*> switch
|
||||||
|
(short 'v'
|
||||||
|
<> long "verbose"
|
||||||
|
<> help "Prints instructions and information")
|
||||||
|
<*> switch
|
||||||
|
(short 'c'
|
||||||
|
<> long "confirmation"
|
||||||
|
<> help "Asks for password confirmation")
|
96
src/Scat/Schemas.hs
Normal file
96
src/Scat/Schemas.hs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
{-# LANGUAGE BangPatterns #-}
|
||||||
|
|
||||||
|
{- | This module defines `Schema`s,
|
||||||
|
which can generate passwords. -}
|
||||||
|
module Scat.Schemas
|
||||||
|
(
|
||||||
|
-- * Type
|
||||||
|
Schema
|
||||||
|
|
||||||
|
-- * Passwords
|
||||||
|
, safe
|
||||||
|
, alphanumeric
|
||||||
|
|
||||||
|
-- * PIN
|
||||||
|
, pin
|
||||||
|
|
||||||
|
-- * Pass phrases
|
||||||
|
, pokemons
|
||||||
|
, diceware
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.List (intercalate)
|
||||||
|
import Data.Vector (Vector)
|
||||||
|
import qualified Data.Vector as V
|
||||||
|
import Data.Monoid
|
||||||
|
import Control.Monad (replicateM)
|
||||||
|
import System.IO
|
||||||
|
|
||||||
|
import Scat.Builder
|
||||||
|
|
||||||
|
import Paths_scat
|
||||||
|
|
||||||
|
-- | Password builder.
|
||||||
|
type Schema = Builder String
|
||||||
|
|
||||||
|
{- | Generates a password of length 18,
|
||||||
|
containing upper case letters,
|
||||||
|
lower case letters,
|
||||||
|
digits and symbols.
|
||||||
|
Entropy of about 115 bits. -}
|
||||||
|
safe :: Schema
|
||||||
|
safe = do
|
||||||
|
nUpper <- inRange (2, 5)
|
||||||
|
nDigit <- inRange (2, 5)
|
||||||
|
nSpecial <- inRange (2, 5)
|
||||||
|
let nLower = 18 - nUpper - nSpecial - nDigit
|
||||||
|
uppers <- replicateM nUpper upper
|
||||||
|
digits <- replicateM nDigit digit
|
||||||
|
specials <- replicateM nSpecial special
|
||||||
|
lowers <- replicateM nLower lower
|
||||||
|
shuffle (uppers <> digits <> specials <> lowers)
|
||||||
|
|
||||||
|
{- | Generates a password of length 18,
|
||||||
|
containing upper case letters,
|
||||||
|
lower case letters and
|
||||||
|
digits, but no symbols.
|
||||||
|
Entropy of about 104.2 bits. -}
|
||||||
|
alphanumeric :: Schema
|
||||||
|
alphanumeric = do
|
||||||
|
nUpper <- inRange (2, 5)
|
||||||
|
nDigit <- inRange (2, 5)
|
||||||
|
let nLower = 18 - nUpper - nDigit
|
||||||
|
uppers <- replicateM nUpper upper
|
||||||
|
digits <- replicateM nDigit digit
|
||||||
|
lowers <- replicateM nLower lower
|
||||||
|
shuffle (uppers <> digits <> lowers)
|
||||||
|
|
||||||
|
{- | Generates a PIN number, of length `n`.
|
||||||
|
Entropy of about @3.32 * n@ bits. -}
|
||||||
|
pin :: Int -> Schema
|
||||||
|
pin n = replicateM n digit
|
||||||
|
|
||||||
|
{- | Generates a password with 4 of the original Pokemons and their level.
|
||||||
|
Entropy of about 55.5 bits. -}
|
||||||
|
pokemons :: IO Schema
|
||||||
|
pokemons = fromFile "pokemons.txt" $ \ vect -> do
|
||||||
|
ps <- replicateM 4 $ oneOfV vect
|
||||||
|
ls <- replicateM 4 $ inRange (1, 100 :: Int)
|
||||||
|
let ss = zipWith (\ p l -> p ++ " " ++ show l) ps ls
|
||||||
|
return $ intercalate ", " ss
|
||||||
|
|
||||||
|
{- | Generates a password with 5 words
|
||||||
|
from the Diceware list.
|
||||||
|
Entropy of about 64.6 bits. -}
|
||||||
|
diceware :: IO Schema
|
||||||
|
diceware = fromFile "diceware.txt" $ \ vect -> do
|
||||||
|
ws <- replicateM 5 $ oneOfV vect
|
||||||
|
return $ unwords ws
|
||||||
|
|
||||||
|
-- | Feeds all lines of a file to a builder.
|
||||||
|
fromFile :: FilePath -> (Vector String -> Builder a) -> IO (Builder a)
|
||||||
|
fromFile fp bs = do
|
||||||
|
fp' <- getDataFileName fp
|
||||||
|
withFile fp' ReadMode $ \ h -> do
|
||||||
|
!vect <- fmap (V.fromList . lines) $ hGetContents h
|
||||||
|
return $ bs vect
|
41
src/Scat/Utils/Permutation.hs
Normal file
41
src/Scat/Utils/Permutation.hs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
{- Copyright (c) 2013 the authors listed at the following URL, and/or
|
||||||
|
the authors of referenced articles or incorporated external code:
|
||||||
|
http://en.literateprograms.org/Kth_permutation_(Haskell)?action=history&offset=20090329064426
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
Retrieved from: http://en.literateprograms.org/Kth_permutation_(Haskell)?oldid=16316
|
||||||
|
-}
|
||||||
|
|
||||||
|
{- | Permutations, taken from the
|
||||||
|
http://en.literateprograms.org/Kth_permutation_(Haskell) webpage. -}
|
||||||
|
module Scat.Utils.Permutation (perm) where
|
||||||
|
|
||||||
|
rr :: Int -> Int -> [Int]
|
||||||
|
rr 0 _ = []
|
||||||
|
rr n k = k `mod` n : rr (n - 1) (k `div` n)
|
||||||
|
|
||||||
|
dfr :: [Int] -> [Int]
|
||||||
|
dfr = foldr (\ x rs -> x : [r + (if x <= r then 1 else 0) | r <- rs]) []
|
||||||
|
|
||||||
|
-- | List permutation.
|
||||||
|
perm :: [a] -> Int -> [a]
|
||||||
|
perm xs k = [xs !! i | i <- dfr (rr (length xs) k)]
|
Loading…
Reference in New Issue
Block a user