scat 1.0.0.0 → 1.0.1.0
raw patch · 4 files changed
+102/−9 lines, 4 files
Files
- scat.cabal +6/−2
- src/Scat.hs +28/−5
- src/Scat/Options.hs +9/−1
- src/Scat/Schemas.hs +59/−1
scat.cabal view
@@ -10,13 +10,13 @@ -- PVP summary: +-+------- breaking API changes -- | | +----- non-breaking API additions -- | | | +--- code changes with no API change-version: 1.0.0.0+version: 1.0.1.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: +description: Flexible password generator. For each service, passwords are generated deterministically from a main password and a code. Internally, Scrypt is used to obtain the hash generating the passwords. -- The license under which the package is released. license: BSD3@@ -50,6 +50,10 @@ data-dir: lists data-files: *.txt ++source-repository head+ type: git+ location: https://github.com/redelmann/scat executable scat -- .hs or .lhs file containing the Main module.
src/Scat.hs view
@@ -4,8 +4,7 @@ module Main (main) where import Data.Monoid-import Data.ByteString (ByteString)-import Data.ByteString (unpack)+import Data.ByteString (ByteString, unpack) import qualified Data.ByteString.Char8 as C import System.IO import System.Exit@@ -41,7 +40,7 @@ shouldErase :: Visibility -> Bool shouldErase Shown = False shouldErase Hidden = False-shouldErase Erased = True +shouldErase Erased = True {- | Generates a password, given a input password, a service name (category, website, etc.),@@ -60,8 +59,20 @@ pw <- getPassword c <- getCode printVerbose "Generated password:\n"- liftIO $ putStrLn $ evalBuilder s $ scatter k pw c+ showGenerated $ evalBuilder s $ scatter k pw c +-- | Prints out the generated password.+showGenerated :: String -> Scat ()+showGenerated gen = do+ v <- fmap verbose ask+ a <- fmap ansi ask+ let ok = v && a+ liftIO $ do+ when ok $ setSGR [SetSwapForegroundBackground True]+ putStrLn gen+ when ok $ setSGR [SetSwapForegroundBackground False]++ -- | Prints, if the verbosity level allows it. printVerbose :: String -> Scat () printVerbose str = do@@ -105,7 +116,9 @@ (hSetEcho stdin $ shouldShow vis) (hSetEcho stdin old) C.getLine- when (shouldErase vis) $ liftIO $ do+ v <- fmap verbose ask+ a <- fmap ansi ask+ when (shouldErase vis && a && v) $ liftIO $ do cursorUpLine 1 cursorForward $ length str clearFromCursorToScreenEnd@@ -149,6 +162,16 @@ -- PIN. 'p' : 'i' : 'n' : xs | [(n, "")] <- reads xs -> return $ pin n++ -- PIN with default size.+ "pin" -> return $ pin 6++ -- Pattern lock+ 'l' : 'o' : 'c' : 'k' : xs | [(n, "")] <- reads xs -> return $+ androidPatternLock n++ -- Default size of pattern lock+ "lock" -> return $ androidPatternLock 9 -- Passphrase using Diceware's list. "diceware" -> liftIO diceware
src/Scat/Options.hs view
@@ -13,6 +13,7 @@ , schema , verbose , confirm+ , ansi -- * Execution , getOptions@@ -37,6 +38,8 @@ -- ^ Verbosity. If false, do not print anything but the generated password. , confirm :: Bool -- ^ Indicates if the password must be confirmed.+ , ansi :: Bool+ -- ^ Indicates if ANSI escape sequences can be used. } -- | Parses the arguments from the command line.@@ -45,7 +48,9 @@ where opts = info (helper <*> options) (fullDesc- <> progDesc "Safely generate passwords derived from a unique password and code."+ <> progDesc (unwords+ [ "Safely generate passwords derived "+ , "from a unique password and code." ]) <> header "scat - a password scatterer") -- | Option parser.@@ -83,3 +88,6 @@ (short 'c' <> long "confirmation" <> help "Asks for password confirmation")+ <*> flag True False+ (long "noansi"+ <> help "Do not use ANSI escape sequences to format output")
src/Scat/Schemas.hs view
@@ -18,9 +18,12 @@ -- * Pass phrases , pokemons , diceware++ -- * Pattern lock+ , androidPatternLock ) where -import Data.List (intercalate)+import Data.List (intercalate, (\\)) import Data.Vector (Vector) import qualified Data.Vector as V import Data.Monoid@@ -74,6 +77,61 @@ Entropy of about @3.32 * n@ bits. -} pin :: Int -> Schema pin n = replicateM n digit+++-- | Generates an Android lock pattern, of specified length.+androidPatternLock :: Int -> Schema+androidPatternLock number = do+ xs <- loop (min number (height * width)) []+ return $ intercalate " - " $ map showPosition xs+ where+ -- Gets `n` points.+ loop :: Int -> [(Int, Int)] -> Builder [(Int, Int)]+ loop n xs | n <= 0 = return $ reverse xs+ loop n xs = do+ x <- oneOf $ possibilities xs+ loop (n - 1) (x : xs)++ -- Grid dimensions.+ height = 3+ width = 3++ -- Text representation for a position.+ showPosition (1, 1) = "center"+ showPosition (i, j) = vshow i ++ hshow j+ where+ vshow 0 = "north"+ vshow 1 = ""+ vshow _ = "south"++ hshow 0 = "west"+ hshow 1 = ""+ hshow _ = "east"++ -- All positions.+ allPositions = [(i, j) | i <- [0 .. height - 1], j <- [0 .. width - 1]]++ {- Possible positions given a list of already used ones.+ The head of the list is the last used position. -}+ possibilities [] = allPositions+ possibilities pps@(p : ps) = filter isPossible candidates+ where+ candidates = allPositions \\ pps++ isPossible q = all (`elem` ps) $ interfere p q++ -- The list of positions that are on the way between two positions.+ interfere (i, j) (k, l) = do+ r <- [1 .. steps - 1]+ return (i + r * vstep, j + r * hstep)+ where+ vdiff = k - i+ hdiff = l - j++ steps = gcd vdiff hdiff++ vstep = vdiff `div` steps+ hstep = hdiff `div` steps {- | Generates a password with 4 of the original Pokemons and their level. Entropy of about 55.5 bits. -}