Random generation of xkcd-style passwords now functioning as expected, web interface now serves randomly generated xkcd-style passwords and provides a button to create a sharing link for them when a new generation is requested. Misc stylesheet updates. Generalized the hx-vals helper function in Core.Templates to be useful for arbitrary endpoints that will need to include specific JSON. Added configuration field for dbSalt which will be used as an encryption salt in the next commit when passwods are stored encrypted in the DB instead of in plaintext.
This commit is contained in:
parent
b1a4251d95
commit
bbe315c450
@ -24,9 +24,11 @@ library
|
|||||||
Core.SQLite
|
Core.SQLite
|
||||||
Core.Templates
|
Core.Templates
|
||||||
Core.Types
|
Core.Types
|
||||||
|
Feature.Generation.HTTP
|
||||||
Feature.Generation.Links
|
Feature.Generation.Links
|
||||||
Feature.Generation.Passwords
|
Feature.Generation.Passwords
|
||||||
Feature.Generation.Shared
|
Feature.Generation.Shared
|
||||||
|
Feature.Generation.Templates
|
||||||
Feature.Sharing.HTTP
|
Feature.Sharing.HTTP
|
||||||
Feature.Sharing.SQLite
|
Feature.Sharing.SQLite
|
||||||
Feature.Sharing.Templates
|
Feature.Sharing.Templates
|
||||||
|
@ -10,4 +10,6 @@
|
|||||||
, applicationHost = "REPLACEME"
|
, applicationHost = "REPLACEME"
|
||||||
, applicationPort = +3000
|
, applicationPort = +3000
|
||||||
, dbFile = "data/Purr.sqlite"
|
, dbFile = "data/Purr.sqlite"
|
||||||
|
, dbSalt = "REPLACEME!!!!!"
|
||||||
|
, linkLength = +24
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,9 @@ module Core.HTTP ( app ) where
|
|||||||
|
|
||||||
import Core.Types
|
import Core.Types
|
||||||
|
|
||||||
import Core.Templates (renderIndex, renderStyle)
|
import Core.Templates (renderIndex, renderStyle)
|
||||||
import Feature.Sharing.HTTP as Sharing
|
import Feature.Sharing.HTTP as Sharing
|
||||||
|
import Feature.Generation.HTTP as Generation
|
||||||
|
|
||||||
import Data.Maybe (Maybe (Nothing))
|
import Data.Maybe (Maybe (Nothing))
|
||||||
import Network.Wai.Middleware.RequestLogger (logStdoutDev)
|
import Network.Wai.Middleware.RequestLogger (logStdoutDev)
|
||||||
@ -26,3 +27,4 @@ app = do
|
|||||||
|
|
||||||
-- Feature Routes
|
-- Feature Routes
|
||||||
Sharing.routes
|
Sharing.routes
|
||||||
|
Generation.routes
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{-# LANGUAGE QuasiQuotes #-}
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
|
||||||
module Core.Templates ( renderIndex, renderStyle ) where
|
module Core.Templates ( renderIndex, renderStyle, hxVals ) where
|
||||||
|
|
||||||
import Text.Blaze.Html.Renderer.Text (renderHtml)
|
import Text.Blaze.Html.Renderer.Text (renderHtml)
|
||||||
import Text.Blaze.Html
|
import Text.Blaze.Html
|
||||||
@ -16,10 +16,10 @@ import Prelude
|
|||||||
renderIndex :: String -> LT.Text
|
renderIndex :: String -> LT.Text
|
||||||
renderIndex link = renderHtml ( $(shamletFile "./views/index.hamlet") )
|
renderIndex link = renderHtml ( $(shamletFile "./views/index.hamlet") )
|
||||||
where
|
where
|
||||||
hsUserLink = userLinkAttr link
|
hsUserLink = hxVals "userLink" link
|
||||||
|
|
||||||
renderStyle :: LT.Text
|
renderStyle :: LT.Text
|
||||||
renderStyle = renderCss ( $(cassiusFile "./views/cassius/style.cassius") "/style.css" )
|
renderStyle = renderCss ( $(cassiusFile "./views/cassius/style.cassius") "/style.css" )
|
||||||
|
|
||||||
userLinkAttr :: String -> (String, String)
|
hxVals :: String -> String -> (String, String)
|
||||||
userLinkAttr str = ("hx-vals", "{\"userLink\": \"" <> str <> "\"}")
|
hxVals attr str = ("hx-vals", "{\"" <> attr <> "\": \"" <> str <> "\"}")
|
||||||
|
@ -20,5 +20,6 @@ data DhallConfig = DhallConfig
|
|||||||
, applicationHost :: String
|
, applicationHost :: String
|
||||||
, applicationPort :: Int
|
, applicationPort :: Int
|
||||||
, dbFile :: String
|
, dbFile :: String
|
||||||
|
, dbSalt :: String
|
||||||
, linkLength :: Int
|
, linkLength :: Int
|
||||||
} deriving (Generic, Show)
|
} deriving (Generic, Show)
|
||||||
|
22
src/Feature/Generation/HTTP.hs
Normal file
22
src/Feature/Generation/HTTP.hs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
module Feature.Generation.HTTP ( routes ) where
|
||||||
|
|
||||||
|
import Core.Types
|
||||||
|
import Core.Templates (renderIndex)
|
||||||
|
|
||||||
|
import Feature.Generation.Passwords (suggestedScheme)
|
||||||
|
import Feature.Generation.Templates (renderGen)
|
||||||
|
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import qualified Data.Text.Lazy as LT
|
||||||
|
|
||||||
|
import Control.Monad.Reader (ask, lift, liftIO)
|
||||||
|
import Data.Maybe (listToMaybe)
|
||||||
|
import Web.Scotty.Trans
|
||||||
|
import Prelude
|
||||||
|
|
||||||
|
routes :: PurrApp ()
|
||||||
|
routes = do
|
||||||
|
|
||||||
|
get "/gen" $ do
|
||||||
|
genPw <- liftIO $ suggestedScheme 24
|
||||||
|
html $ renderGen genPw
|
@ -1,7 +1,7 @@
|
|||||||
module Feature.Generation.Links ( genLink ) where
|
module Feature.Generation.Links ( genLink ) where
|
||||||
|
|
||||||
import Core.Types
|
import Core.Types
|
||||||
import Feature.Generation.Shared (rIndex)
|
import Feature.Generation.Shared (rIndex, validChars)
|
||||||
|
|
||||||
import Control.Monad.Reader (ask, lift, liftIO)
|
import Control.Monad.Reader (ask, lift, liftIO)
|
||||||
import Data.Char (toLower, toUpper)
|
import Data.Char (toLower, toUpper)
|
||||||
@ -21,12 +21,6 @@ genLink = do
|
|||||||
fin <- liftIO $ randCapitalization res
|
fin <- liftIO $ randCapitalization res
|
||||||
genLink' (d - 1) (cs <> (fin:[]))
|
genLink' (d - 1) (cs <> (fin:[]))
|
||||||
|
|
||||||
-- Defines the valid range of characters to be used when generating links.
|
|
||||||
-- This consists of all lowercase Latin alphabet characters and the
|
|
||||||
-- numbers 1 through 9.
|
|
||||||
validChars :: [Char]
|
|
||||||
validChars = ['a'..'z'] <> ['1'..'9']
|
|
||||||
|
|
||||||
randChar :: IO Char
|
randChar :: IO Char
|
||||||
randChar = rIndex validChars
|
randChar = rIndex validChars
|
||||||
|
|
||||||
|
@ -1,25 +1,47 @@
|
|||||||
module Feature.Generation.Passwords where
|
module Feature.Generation.Passwords where
|
||||||
|
|
||||||
import Core.Types
|
import Core.Types
|
||||||
import Feature.Generation.Shared (rIndex)
|
import Feature.Generation.Shared (rIndex, validChars)
|
||||||
|
|
||||||
import Control.Monad.Reader (ask, lift, liftIO)
|
import Control.Monad.Reader (ask, lift, liftIO)
|
||||||
import Data.Char (toLower, toUpper)
|
import Data.Char (toLower, toUpper)
|
||||||
|
import Data.List (singleton)
|
||||||
import System.IO
|
import System.IO
|
||||||
import System.Random
|
import System.Random
|
||||||
|
|
||||||
|
camelCase :: [Char] -> [Char]
|
||||||
|
camelCase [] = []
|
||||||
|
camelCase x = toUpper (head x) : map toLower (tail x)
|
||||||
|
|
||||||
-- suggestedScheme and its helpers xkcd, oldschool, and gibberish are TODO.
|
-- suggestedScheme and its helpers xkcd, oldschool, and gibberish are TODO.
|
||||||
suggestedScheme :: Int -> String
|
suggestedScheme :: Int -> IO String
|
||||||
suggestedScheme i
|
suggestedScheme i
|
||||||
| i > 23 = xkcd i
|
| i > 23 = xkcd i
|
||||||
| i > 12 = oldschool i
|
| i > 12 = oldschool i
|
||||||
| otherwise = gibberish i
|
| otherwise = gibberish i
|
||||||
|
|
||||||
xkcd :: Int -> String
|
xkcd :: Int -> IO String
|
||||||
xkcd i = take i "correcthorsebatterystaple"
|
xkcd i = do
|
||||||
|
wOne <- randomCamel
|
||||||
|
wTwo <- randomCamel
|
||||||
|
wThree <- randomCamel
|
||||||
|
wFour <- randomCamel
|
||||||
|
return $ wOne <> wTwo <> wThree <> wFour
|
||||||
|
|
||||||
oldschool :: Int -> String
|
oldschool :: Int -> IO String
|
||||||
oldschool i = take i "PowerProlonger2974!"
|
oldschool i = do
|
||||||
|
wOne <- randomWord
|
||||||
|
wTwo <- randomWord
|
||||||
|
return $ wOne <> wTwo
|
||||||
|
|
||||||
gibberish :: Int -> String
|
gibberish :: Int -> IO String
|
||||||
gibberish i = take i "TCYx#@z5zlgw1o"
|
gibberish i = return "mf98sgs7bgg%#"
|
||||||
|
|
||||||
|
wordList :: IO [String]
|
||||||
|
wordList = fmap lines (readFile "./src/Feature/Generation/wordlist.txt")
|
||||||
|
|
||||||
|
randomWord :: IO String
|
||||||
|
randomWord = wordList >>= rIndex
|
||||||
|
|
||||||
|
randomCamel :: IO String
|
||||||
|
randomCamel = camelCase <$> randomWord
|
||||||
|
@ -6,3 +6,15 @@ rIndex :: [a] -> IO a
|
|||||||
rIndex arr = do
|
rIndex arr = do
|
||||||
i <- randomRIO (0, length arr - 1)
|
i <- randomRIO (0, length arr - 1)
|
||||||
return $ arr !! i
|
return $ arr !! i
|
||||||
|
|
||||||
|
-- Defines the valid range of characters to be used when generating.
|
||||||
|
-- This consists of all lowercase Latin alphabet characters and the
|
||||||
|
-- numbers 1 through 9.
|
||||||
|
validChars :: [Char]
|
||||||
|
validChars = validLetters <> validNumbers
|
||||||
|
|
||||||
|
validNumbers :: [Char]
|
||||||
|
validNumbers = ['1'..'9']
|
||||||
|
|
||||||
|
validLetters :: [Char]
|
||||||
|
validLetters = ['a'..'z']
|
||||||
|
20
src/Feature/Generation/Templates.hs
Normal file
20
src/Feature/Generation/Templates.hs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
|
||||||
|
module Feature.Generation.Templates ( renderGen ) where
|
||||||
|
|
||||||
|
import Core.Templates (hxVals)
|
||||||
|
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import qualified Data.Text.Lazy as LT
|
||||||
|
|
||||||
|
import Text.Blaze.Html.Renderer.Text (renderHtml)
|
||||||
|
import Text.Blaze.Html
|
||||||
|
import Text.Hamlet (shamletFile)
|
||||||
|
|
||||||
|
import Prelude
|
||||||
|
|
||||||
|
renderGen :: String -> LT.Text
|
||||||
|
renderGen genPw = renderHtml ( $(shamletFile "./views/gen.hamlet") )
|
||||||
|
where
|
||||||
|
hsGeneratedSharing = hxVals "newSec" genPw
|
@ -195,6 +195,7 @@ bury
|
|||||||
bush
|
bush
|
||||||
busy
|
busy
|
||||||
butter
|
butter
|
||||||
|
butterfly
|
||||||
button
|
button
|
||||||
buyer
|
buyer
|
||||||
cable
|
cable
|
||||||
@ -605,7 +606,6 @@ hall
|
|||||||
hammer
|
hammer
|
||||||
hand
|
hand
|
||||||
handle
|
handle
|
||||||
hang
|
|
||||||
happen
|
happen
|
||||||
happy
|
happy
|
||||||
hard
|
hard
|
||||||
@ -614,7 +614,6 @@ harm
|
|||||||
hate
|
hate
|
||||||
hatred
|
hatred
|
||||||
have
|
have
|
||||||
head
|
|
||||||
heal
|
heal
|
||||||
health
|
health
|
||||||
hear
|
hear
|
||||||
@ -628,7 +627,6 @@ help
|
|||||||
hence
|
hence
|
||||||
here
|
here
|
||||||
hero
|
hero
|
||||||
hers
|
|
||||||
hide
|
hide
|
||||||
high
|
high
|
||||||
highly
|
highly
|
@ -4,14 +4,18 @@
|
|||||||
@colorFour: #435F5D
|
@colorFour: #435F5D
|
||||||
|
|
||||||
html
|
html
|
||||||
|
font-family: Courier
|
||||||
background-color: #{colorTwo}
|
background-color: #{colorTwo}
|
||||||
color: #{colorOne}
|
color: #{colorOne}
|
||||||
|
|
||||||
body
|
body
|
||||||
font-family: Courier
|
|
||||||
font-size: 20px
|
font-size: 20px
|
||||||
text-align: left
|
text-align: left
|
||||||
|
|
||||||
|
h2
|
||||||
|
font-family: monaco, Consolas, monospace
|
||||||
|
text-transform: uppercase
|
||||||
|
|
||||||
p
|
p
|
||||||
margin: 0.4em 0 0.4em 0
|
margin: 0.4em 0 0.4em 0
|
||||||
|
|
||||||
@ -38,6 +42,7 @@ a
|
|||||||
height: 1%
|
height: 1%
|
||||||
|
|
||||||
.mainButton
|
.mainButton
|
||||||
|
margin: 0 0 0.25em 0
|
||||||
padding: 0.75em 1.75em
|
padding: 0.75em 1.75em
|
||||||
background-color: #{colorThree}
|
background-color: #{colorThree}
|
||||||
color: #{colorTwo}
|
color: #{colorTwo}
|
||||||
@ -51,8 +56,8 @@ a
|
|||||||
outline: none
|
outline: none
|
||||||
color: #{colorOne}
|
color: #{colorOne}
|
||||||
background: #{colorTwo}
|
background: #{colorTwo}
|
||||||
margin: 1em 0
|
margin: 0.5em 0
|
||||||
border-style: none none none none
|
border-style: none none solid none
|
||||||
padding: 0.4em 0
|
padding: 0.4em 0
|
||||||
box-sizing: border-box
|
box-sizing: border-box
|
||||||
-webkit-box-sizing: border-box
|
-webkit-box-sizing: border-box
|
||||||
@ -77,6 +82,9 @@ a
|
|||||||
.pwUtils
|
.pwUtils
|
||||||
width: 75%
|
width: 75%
|
||||||
|
|
||||||
|
.generators
|
||||||
|
margin: 5% 0 0 0
|
||||||
|
|
||||||
.shareNew
|
.shareNew
|
||||||
margin-bottom: 2em
|
margin-bottom: 2em
|
||||||
|
|
||||||
|
19
views/gen.hamlet
Normal file
19
views/gen.hamlet
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<div #generators .generators>
|
||||||
|
<h2>Generators
|
||||||
|
<p>Generated password:
|
||||||
|
<h3>#{genPw}
|
||||||
|
<button .mainButton
|
||||||
|
hx-get="/gen"
|
||||||
|
hx-target="#generators"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
/>
|
||||||
|
Generate New Password
|
||||||
|
<br />
|
||||||
|
<button .mainButton
|
||||||
|
hx-post="/new"
|
||||||
|
hx-target="#requestedPw"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
*{hsGeneratedSharing}
|
||||||
|
/>
|
||||||
|
Share Generated Password
|
||||||
|
<img class="htmx-indicator" src="/loading.svg" />
|
@ -18,6 +18,7 @@ $doctype 5
|
|||||||
<a #titleLink .titleLink href="/">Purr
|
<a #titleLink .titleLink href="/">Purr
|
||||||
|
|
||||||
<div #pwUtils .pwUtils>
|
<div #pwUtils .pwUtils>
|
||||||
|
<h2>Sharing Tools
|
||||||
$if (link == "/")
|
$if (link == "/")
|
||||||
<div #requestedPw .requestedPw>
|
<div #requestedPw .requestedPw>
|
||||||
<p .emptyReq>
|
<p .emptyReq>
|
||||||
@ -62,3 +63,12 @@ $doctype 5
|
|||||||
/>
|
/>
|
||||||
Get Secret
|
Get Secret
|
||||||
<img class="htmx-indicator" src="/loading.svg" />
|
<img class="htmx-indicator" src="/loading.svg" />
|
||||||
|
|
||||||
|
<div #generators .generators>
|
||||||
|
<h2>Generators
|
||||||
|
<button .mainButton
|
||||||
|
hx-get="/gen"
|
||||||
|
hx-target="#generators"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
/>
|
||||||
|
Generate Password
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<div #requestedPw .requestedPw>
|
<div #requestedPw .requestedPw>
|
||||||
$maybe pw <- password
|
$maybe pw <- password
|
||||||
<p>Here's the secret found at <a href="/pw/#{link}">/pw/#{link}</a>:
|
<p>Here's the secret found at <a href="/pw/#{link}">/pw/#{link}</a>:
|
||||||
<h2 .pwResult>#{pw}
|
<h3 .pwResult>#{pw}
|
||||||
|
<hr />
|
||||||
$nothing
|
$nothing
|
||||||
<p>No secret found at <a href="/pw/#{link}">/pw/#{link}</a>
|
<h3>No secret found at <a href="/pw/#{link}">/pw/#{link}</a>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user