1
0
mirror of https://github.com/redelmann/scat synced 2025-04-20 12:38:38 +02:00

Modifies options so that the use of code is strongly encouraged.

This commit is contained in:
Romain Edelmann 2013-08-12 18:10:36 +02:00
parent 83288f00d7
commit b14cf29657
3 changed files with 68 additions and 54 deletions

View File

@ -10,7 +10,7 @@ name: scat
-- PVP summary: +-+------- breaking API changes
-- | | +----- non-breaking API additions
-- | | | +--- code changes with no API change
version: 0.2.1.0
version: 1.0.0.0
-- A short (one-line) description of the package.
synopsis: Generates unique passwords for various websites from a single password.
@ -63,5 +63,5 @@ executable scat
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.*, scrypt ==0.3.*, bytestring ==0.9.*, optparse-applicative ==0.5.*, mtl ==2.1.*, vector ==0.10.*
build-depends: base ==4.5.*, scrypt ==0.3.*, bytestring ==0.9.*, optparse-applicative ==0.5.*, mtl ==2.1.*, vector ==0.10.*, ansi-terminal ==0.6.*

View File

@ -9,6 +9,7 @@ import Data.ByteString (unpack)
import qualified Data.ByteString.Char8 as C
import System.IO
import System.Exit
import System.Console.ANSI
import Control.Exception
import Control.Monad.Reader
import Crypto.Scrypt
@ -17,19 +18,34 @@ import Scat.Schemas
import Scat.Builder
import Scat.Options
-- | Generates the seed integer given a key and a password.
-- | Generates the seed integer given a service, a password and a code.
scatter :: ByteString -> ByteString -> ByteString -> Integer
scatter k pw c = foldr (\ n s -> fromIntegral n + 256 * s) 0 $
unpack $ unHash $ scrypt params (Salt k) (Pass $ pw <> c)
where
Just params = scryptParams 14 8 50
unpack $ unHash $ scrypt params (Salt k) (Pass $ pw <> c)
where
Just params = scryptParams 14 8 50
-- | Main type of the program.
type Scat a = ReaderT Options IO a
-- | Input visibility.
data Visibility = Shown | Hidden | Erased
-- | Should the input be echoed?
shouldShow :: Visibility -> Bool
shouldShow Shown = True
shouldShow Hidden = False
shouldShow Erased = True
-- | Should the input be erased afterwards?
shouldErase :: Visibility -> Bool
shouldErase Shown = False
shouldErase Hidden = False
shouldErase Erased = True
{- | Generates a password, given a input password,
a key (category, website, etc.),
and a password `Schema`.
a service name (category, website, etc.),
a code, and a password `Schema`.
The parameters are specified as command line arguments.
The password can be read from @stdin@ if not already provided. -}
@ -39,7 +55,7 @@ main = getOptions >>= runReaderT scat
-- | Main program.
scat :: Scat ()
scat = do
k <- getKey
k <- getService
s <- getSchema
pw <- getPassword
c <- getCode
@ -69,32 +85,41 @@ getPassword = do
-- Retrieve the password from the arguments.
Just st -> return $ C.pack st
where
getPass = askPassword False "Password: "
getPass = prompt Hidden "Password: "
getPassConfirm = do
a <- askPassword False "Password: "
b <- askPassword False "Confirm: "
a <- prompt Hidden "Password: "
b <- prompt Hidden "Confirm: "
if a == b
then return a
else do
printVerbose "Passwords do not match, please retry.\n"
getPassConfirm
-- | Ask a password on the command line, with the specified prompt.
askPassword :: Bool -> String -> Scat ByteString
askPassword echo str = do
-- | Ask a for input on the command line, with the specified prompt.
prompt :: Visibility -> String -> Scat ByteString
prompt vis str = do
printVerbose str
old <- liftIO $ hGetEcho stdin
pw <- liftIO $ bracket_
(hSetEcho stdin echo)
(hSetEcho stdin $ shouldShow vis)
(hSetEcho stdin old)
C.getLine
unless echo $ printVerbose "\n"
when (shouldErase vis) $ liftIO $ do
cursorUpLine 1
cursorForward $ length str
clearFromCursorToScreenEnd
cursorDownLine 1
unless (shouldShow vis) $ printVerbose "\n"
return pw
-- | Gets the key.
getKey :: Scat ByteString
getKey = fmap (C.pack . key) ask
-- | Gets the service.
getService :: Scat ByteString
getService = do
mk <- fmap service ask
case mk of
Just k -> return $ C.pack k
Nothing -> prompt Shown "Service: "
-- | Gets the code.
getCode :: Scat ByteString
@ -105,7 +130,7 @@ getCode = do
mc <- fmap code ask
case mc of
Just st -> return $ C.pack st
Nothing -> askPassword True "Code: "
Nothing -> prompt Erased "Code: "
else return ""
-- | Gets the schema to generate the new password.

View File

@ -7,7 +7,7 @@ module Scat.Options
-- * Accessors
, password
, key
, service
, useCode
, code
, schema
@ -19,43 +19,33 @@ module Scat.Options
) where
import Data.Monoid
import Data.Maybe (isJust)
import Options.Applicative
-- | All program options.
data Options = Options
{ password :: Maybe String
-- ^ Password, optionally provided.
, key :: String
-- ^ Key or category for the password.
, useCode_ :: Bool
, service :: Maybe String
-- ^ Service for which to generate the password.
, useCode :: Bool
-- ^ Indicates if extra code should be used.
, code :: Maybe String
-- ^ Extra code. Activates code usage.
-- ^ Extra code.
, schema :: String
-- ^ Name of the schema to use.
, verbose_ :: Bool
, verbose :: Bool
-- ^ Verbosity. If false, do not print anything but the generated password.
, confirm :: Bool
-- ^ Indicates if the password must be confirmed. Activates verbosity.
-- ^ Indicates if the password must be confirmed.
}
-- | Indicates if extra code should be used.
useCode :: Options -> Bool
useCode opts = useCode_ opts || isJust (code opts)
{- | Verbosity. If false, do not print anything but the generated password.
True when @--verbose@ or @--confirmation@ are specified. -}
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."
<> progDesc "Safely generate passwords derived from a unique password and code."
<> header "scat - a password scatterer")
-- | Option parser.
@ -66,18 +56,18 @@ options = Options
<> long "password"
<> help "The password"
<> metavar "PASSWORD"))
<*> strOption
(short 'k'
<> long "key"
<> help "Key associated (website, email address, ...) (mandatory)"
<> metavar "KEY")
<*> switch
(short 'x'
<> long "extra"
<> help "Indicates extra code should be used.")
<*> optional (strOption
(short 'S'
<> long "service"
<> help "Service associated (website, email address, ...)"
<> metavar "SERVICE"))
<*> flag True False
(long "nocode"
<> help "Indicates that extra code should be not be used")
<*> optional
(strOption (long "code"
<> help "Extra code."
(strOption (short 'x'
<> long "code"
<> help "The extra code to use"
<> metavar "CODE"))
<*> strOption
(short 's'
@ -86,10 +76,9 @@ options = Options
<> metavar "SCHEMA"
<> value "safe"
<> showDefault)
<*> switch
(short 'v'
<> long "verbose"
<> help "Prints instructions and information")
<*> flag True False
(long "silent"
<> help "Do not print anything but the generated password")
<*> switch
(short 'c'
<> long "confirmation"