Read encrypted secret entries from the database and decode/unencrypt appropriately, add max duration/view count entries for the database and frontend interface, update README to remove graceful JS degradation goal, remove a few wordlist entries

This commit is contained in:
James Eversole 2022-07-31 17:41:54 -05:00
parent 478384aae9
commit ca73ed7982
8 changed files with 96 additions and 29 deletions

View File

@ -18,7 +18,6 @@ You shouldn't! This is [free and open-source software](https://git.eversole.co/J
## Project Goals ## Project Goals
1. Provide a minimal and clean interface for generating and sharing passwords. 1. Provide a minimal and clean interface for generating and sharing passwords.
2. Maintain a clean and organized codebase that can be extended to include more utilities than originally anticipated. 2. Maintain a clean and organized codebase that can be extended to include more utilities than originally anticipated.
3. Aim for graceful degradation when JavaScript isn't enabled.
## Development & Support ## Development & Support
Please send me an [email](mailto:james@eversole.co) or join the [Support Chat](openpgp4fpr://FEB27223219E8DB3203225350462EA0901FE08F7#a=james%40eversole.co&g=Purr%20Support&x=RbVs8iQCVnf&i=-FuzUDK_RM1&s=KgeGtFFJtkq) in [DeltaChat](https://delta.chat)! Please send me an [email](mailto:james@eversole.co) or join the [Support Chat](openpgp4fpr://FEB27223219E8DB3203225350462EA0901FE08F7#a=james%40eversole.co&g=Purr%20Support&x=RbVs8iQCVnf&i=-FuzUDK_RM1&s=KgeGtFFJtkq) in [DeltaChat](https://delta.chat)!

View File

@ -15,7 +15,10 @@ main db = do
"CREATE TABLE IF NOT EXISTS pws\ "CREATE TABLE IF NOT EXISTS pws\
\ (link TEXT PRIMARY KEY,\ \ (link TEXT PRIMARY KEY,\
\ secret TEXT,\ \ secret TEXT,\
\ date DATETIME DEFAULT CURRENT_TIMESTAMP)" \ date DATETIME DEFAULT CURRENT_TIMESTAMP,\
\ life INT,\
\ views INT,\
\ maxViews INT)"
close conn close conn
dbPath :: PurrAction String dbPath :: PurrAction String

View File

@ -175,7 +175,6 @@ bread
break break
breast breast
breath breath
breed
brick brick
bridge bridge
brief brief
@ -820,9 +819,7 @@ media
medium medium
meet meet
melt melt
member
memory memory
mental
menu menu
mere mere
merely merely
@ -1035,7 +1032,6 @@ profit
prompt prompt
proof proof
proper proper
proud
prove prove
public public
pull pull

View File

@ -26,10 +26,12 @@ routes = do
post "/pw" $ do post "/pw" $ do
reqId <- param "userLink" reqId <- param "userLink"
res <- findByLink reqId res <- findByLink reqId
html $ renderPw reqId (secret <$> res) html $ renderPw reqId res
post "/new" $ do post "/new" $ do
reqSecret <- param "newSec" reqSecret <- param "newSec"
reqDur <- param "newSecDuration"
reqViews <- param "newSecViews"
link <- genLink link <- genLink
insertNewSecret reqSecret (T.pack link) insertNewSecret reqSecret reqDur (T.pack link) reqViews
html $ renderPw link (Just reqSecret) html $ renderPw link (Just reqSecret)

View File

@ -9,7 +9,6 @@ import Crypto.Simple.CBC (encrypt, decrypt)
import Data.Maybe (listToMaybe) import Data.Maybe (listToMaybe)
import Data.Time.Clock.POSIX (getPOSIXTime) import Data.Time.Clock.POSIX (getPOSIXTime)
import Database.SQLite.Simple import Database.SQLite.Simple
import Database.SQLite.Simple.FromRow
import qualified Data.ByteString.Base64 as B64 import qualified Data.ByteString.Base64 as B64
import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Char8 as B
@ -17,28 +16,44 @@ import qualified Data.Text as T
import qualified Data.Text.Encoding as ET import qualified Data.Text.Encoding as ET
import qualified Data.Text.Lazy as LT import qualified Data.Text.Lazy as LT
findByLink :: String -> PurrAction (Maybe SecretEntry) findByLink :: String -> PurrAction (Maybe T.Text)
findByLink link = do findByLink link = do
db <- dbPath db <- dbPath
conn <- liftIO $ open db key <- encKey
res <- liftIO $ query conn "SELECT * from pws WHERE link = ?" (Only link) conn <- liftIO $ open db
res <- liftIO $ query conn "SELECT * from pws WHERE link = ?" (Only link)
liftIO $ close conn liftIO $ close conn
return $ listToMaybe res readEncryptedSecret key res
insertNewSecret :: T.Text -> T.Text -> PurrAction () insertNewSecret :: T.Text -> Integer -> T.Text -> Integer -> PurrAction ()
insertNewSecret sec link = do insertNewSecret sec life link maxViews = do
db <- dbPath db <- dbPath
key <- encKey key <- encKey
encSec <- liftIO $ encrypt (B.pack key) (ET.encodeUtf8 sec) encSec <- liftIO $ encryptSecret key sec
conn <- liftIO $ open db conn <- liftIO $ open db
time <- liftIO $ epochTime time <- liftIO $ epochTime
liftIO $ execute conn liftIO $ execute conn
"INSERT INTO pws (link, secret, date) VALUES (?, ?, ?)" "INSERT INTO pws (link, secret, date, life, views, maxViews) VALUES (?, ?, ?, ?, ?, ?)"
(SecretEntry link (encodeSecret encSec) time) (SecretEntry link (encodeSecret encSec) time life 0 maxViews)
liftIO $ close conn liftIO $ close conn
epochTime :: IO Integer readEncryptedSecret :: String -> [SecretEntry] -> PurrAction (Maybe T.Text)
epochTime = fmap round getPOSIXTime readEncryptedSecret key sec = do
decKey <- liftIO
(sequence $ decryptSecret key <$> decodeSecret <$> listToMaybe sec)
return (ET.decodeLatin1 <$> decKey)
encodeSecret :: B.ByteString -> T.Text encodeSecret :: B.ByteString -> T.Text
encodeSecret b = ET.decodeUtf8 $ B64.encode b encodeSecret b = ET.decodeUtf8 $ B64.encode b
decodeSecret :: SecretEntry -> B.ByteString
decodeSecret s = B64.decodeLenient $ ET.encodeUtf8 (secret s)
encryptSecret :: String -> T.Text -> IO B.ByteString
encryptSecret k s = encrypt (B.pack k) (ET.encodeUtf8 s)
decryptSecret :: String -> B.ByteString -> IO B.ByteString
decryptSecret k b = decrypt (B.pack k) b
epochTime :: IO Integer
epochTime = fmap round getPOSIXTime

View File

@ -10,9 +10,12 @@ import Database.SQLite.Simple.FromRow
import qualified Data.Text as T import qualified Data.Text as T
data SecretEntry = SecretEntry data SecretEntry = SecretEntry
{ link :: T.Text { link :: T.Text
, secret :: T.Text , secret :: T.Text
, date :: Integer , date :: Integer
, life :: Integer
, views :: Integer
, maxViews :: Integer
} deriving (Show, Generic) } deriving (Show, Generic)
instance FromRow SecretEntry where instance FromRow SecretEntry where

View File

@ -56,7 +56,7 @@ a
outline: none outline: none
color: #{colorOne} color: #{colorOne}
background: #{colorTwo} background: #{colorTwo}
margin: 0.5em 0 margin: 0.5em 0 1em 0
border-style: none none solid none border-style: none none solid none
padding: 0.4em 0 padding: 0.4em 0
box-sizing: border-box box-sizing: border-box
@ -75,6 +75,33 @@ a
color: #{colorThree} color: #{colorThree}
opacity: 0.5 opacity: 0.5
.numberInput
text-align: center
font-weight: 400
font-size: 1em
width: 10%
outline: none
color: #{colorOne}
background: #{colorTwo}
margin: 0.5em 0
border-style: none none solid none
padding: 0.4em 0
box-sizing: border-box
-webkit-box-sizing: border-box
-moz-box-sizing: border-box
-webkit-transition: all 0.1s ease-in-out
-moz-transition: all 0.1s ease-in-out
-ms-transition: all 0.1s ease-in-out
-o-transition: all 0.1s ease-in-out
transition: all 0.1s ease-in-out
.numberInput:focus
border-bottom: 0.2em solid #{colorThree};
.numberInput:focus::placeholder
color: #{colorThree}
opacity: 0.5
.pwResult .pwResult
font-size: 1.5em font-size: 1.5em
color: #{colorFour} color: #{colorFour}
@ -109,6 +136,9 @@ a
width: 95% width: 95%
text-align: center text-align: center
.numberInput
width: 25%
.title .title
margin: 8% auto 2% auto margin: 8% auto 2% auto
font-size: 3em font-size: 3em

View File

@ -39,11 +39,30 @@ $doctype 5
type="text" type="text"
placeholder="Enter a Secret to Share" placeholder="Enter a Secret to Share"
/> />
<br />
Valid for:
<br />
<input .numberInput
name="newSecDuration"
type="number"
min="1"
max="90"
value="20"
onkeyup="if (value < 1 || value > 90) { value = 0 }"
/> days
<input .numberInput
name="newSecViews"
type="number"
min="1"
max="60"
value="20"
onkeyup="if (value < 1 || value > 60) { value = 0 }"
/> views
<button .mainButton <button .mainButton
hx-post="/new" hx-post="/new"
hx-target="#requestedPw" hx-target="#requestedPw"
hx-swap="outerHTML" hx-swap="outerHTML"
hx-include="[name='newSec']" hx-include="[id='shareNew']"
/> />
Share Secret Share Secret
<img class="htmx-indicator" src="/loading.svg" /> <img class="htmx-indicator" src="/loading.svg" />