purr

password generation and secret sharing
Log | Files | Refs | README | LICENSE

commit f088ff3690c8959f2b69fa726c8fe88d2171589a
parent d15b40a33900533c35d65334db11678246d4458a
Author: James Eversole <james@eversole.co>
Date:   Sat,  2 Jul 2022 18:37:30 -0500

Beginnings of HTMX frontend interaction, able to request particular PWs by link names and patch the DOM appropriately

Diffstat:
MPurr.cabal | 4+++-
Msrc/Core/HTTP.hs | 11+++++++++--
Msrc/Core/Mongo.hs | 30++----------------------------
Msrc/Core/Templates.hs | 12+++++++-----
Msrc/Core/Types.hs | 1-
Dsrc/Feature/Handlers.hs | 23-----------------------
Asrc/Feature/Sharing/HTTP.hs | 32++++++++++++++++++++++++++++++++
Asrc/Feature/Sharing/Mongo.hs | 35+++++++++++++++++++++++++++++++++++
Asrc/Feature/Sharing/Templates.hs | 16++++++++++++++++
Msrc/Lib.hs | 2+-
Mviews/index.hamlet | 14++++++++++----
Aviews/pw.hamlet | 5+++++
12 files changed, 120 insertions(+), 65 deletions(-)

diff --git a/Purr.cabal b/Purr.cabal @@ -24,7 +24,9 @@ library Core.Mongo Core.Templates Core.Types - Feature.Handlers + Feature.Sharing.HTTP + Feature.Sharing.Mongo + Feature.Sharing.Templates Lib other-modules: Paths_Purr diff --git a/src/Core/HTTP.hs b/src/Core/HTTP.hs @@ -2,13 +2,20 @@ module Core.HTTP ( app ) where import Core.Types -import Feature.Handlers as HD +import Core.Templates (renderIndex) +import Feature.Sharing.HTTP as Sharing import Network.Wai.Middleware.RequestLogger (logStdoutDev) import Web.Scotty.Trans app :: PurrApp () app = do + -- Middleware definition middleware logStdoutDev - get "/:id" HD.pwLookup + -- Core Routes + get "/" $ do + html $ renderIndex + + -- Feature Routes + Sharing.routes diff --git a/src/Core/Mongo.hs b/src/Core/Mongo.hs @@ -1,39 +1,13 @@ - module Core.Mongo ( mongoSetup, getAllDocs, findByLink ) where +module Core.Mongo ( mongoSetup ) where import Core.Types import Control.Monad.Reader (MonadIO, lift, ask) import Data.Maybe -import Data.Text (Text) +import Data.Text (Text) import Database.MongoDB import Prelude -findByLink :: String -> PurrAction (Maybe Document) -findByLink link = do - col <- confCollection - dataConn <- dataAccess - dataConn $ findOne (select ["link" =: link] col) - -getAllDocs :: PurrAction [Document] -getAllDocs = do - col <- confCollection - dataConn <- dataAccess - dataConn $ find (select [] col) - >>= rest - -dataAccess :: MonadIO m => PurrAction (Action m a -> m a) -dataAccess = do - appConfig <- lift ask - return $ access - (mongoPipe $ dbconn appConfig) - (mongoAccessMode $ dbconn appConfig) - (mongoDatabase $ dbconn appConfig) - -confCollection :: PurrAction Text -confCollection = do - appConfig <- lift ask - return $ collection $ res appConfig - -- Authenticates to Mongo and returns the MongoContext for the dataDB mongoSetup :: DhallConfig -> IO MongoContext mongoSetup conf = do diff --git a/src/Core/Templates.hs b/src/Core/Templates.hs @@ -3,12 +3,14 @@ module Core.Templates ( renderIndex ) where -import Database.MongoDB (Document) -import Text.Blaze.Html.Renderer.String (renderHtml) +import qualified Data.Text.Lazy as LT + +import Database.MongoDB (Document) +import Text.Blaze.Html.Renderer.Text (renderHtml) import Text.Blaze.Html -import Text.Hamlet (shamletFile) +import Text.Hamlet (shamletFile) import Prelude -renderIndex :: String -> Maybe String -> String -renderIndex link password = renderHtml ( $(shamletFile "./views/index.hamlet") ) +renderIndex :: LT.Text +renderIndex = renderHtml ( $(shamletFile "./views/index.hamlet") ) diff --git a/src/Core/Types.hs b/src/Core/Types.hs @@ -31,4 +31,3 @@ data DhallConfig = DhallConfig , mongoUsername :: Text , mongoPassword :: Text } deriving (Generic, Show) - diff --git a/src/Feature/Handlers.hs b/src/Feature/Handlers.hs @@ -1,23 +0,0 @@ -module Feature.Handlers ( pwLookup ) where - -import Core.Types -import Core.Templates -import qualified Core.Mongo as DB - -import Control.Monad.Reader (ask, lift) -import Data.AesonBson (aesonify) -import Data.Bson (Document, Field (..), Value (Array, Doc), lookup) -import qualified Data.Text as T -import qualified Data.Text.Lazy as LT -import Web.Scotty.Trans (html, param) -import Prelude hiding (id, lookup) - -pwLookup :: PurrAction () -pwLookup = do - id <- param "id" - doc <- DB.findByLink id - html $ LT.pack $ renderIndex id (pwLook doc) - where - pwLook :: Maybe Document -> Maybe String - pwLook (Just x) = (lookup "password" x) :: Maybe String - pwLook _ = Nothing diff --git a/src/Feature/Sharing/HTTP.hs b/src/Feature/Sharing/HTTP.hs @@ -0,0 +1,32 @@ +module Feature.Sharing.HTTP ( routes ) where + +import Core.Types + +import Feature.Sharing.Templates +import qualified Feature.Sharing.Mongo as DB + +import qualified Data.Text as T +import qualified Data.Text.Lazy as LT + +import Control.Monad.Reader (ask, lift) +import Data.AesonBson (aesonify) +import Data.Bson (Document, Field (..), Value (..), lookup) +import Web.Scotty.Trans +import Prelude hiding (id, lookup) + +routes :: PurrApp () +routes = do + + get "/pw/:id" $ do + id <- param "id" + doc <- DB.findByLink id + html $ renderPw id (pwLookup doc) + + post "/pw" $ do + id <- param "userLink" + doc <- DB.findByLink id + html $ renderPw id (pwLookup doc) + +pwLookup :: Maybe Document -> Maybe String +pwLookup (Just x) = (lookup "password" x) +pwLookup _ = Nothing diff --git a/src/Feature/Sharing/Mongo.hs b/src/Feature/Sharing/Mongo.hs @@ -0,0 +1,35 @@ +module Feature.Sharing.Mongo ( getAllDocs, findByLink ) where + +import Core.Types + +import Control.Monad.Reader (MonadIO, lift, ask) +import Data.Maybe +import Data.Text (Text) +import Database.MongoDB +import Prelude + +findByLink :: String -> PurrAction (Maybe Document) +findByLink link = do + col <- confCollection + dataConn <- dataAccess + dataConn $ findOne (select ["link" =: link] col) + +getAllDocs :: PurrAction [Document] +getAllDocs = do + col <- confCollection + dataConn <- dataAccess + dataConn $ find (select [] col) + >>= rest + +dataAccess :: MonadIO m => PurrAction (Action m a -> m a) +dataAccess = do + appConfig <- lift ask + return $ access + (mongoPipe $ dbconn appConfig) + (mongoAccessMode $ dbconn appConfig) + (mongoDatabase $ dbconn appConfig) + +confCollection :: PurrAction Text +confCollection = do + appConfig <- lift ask + return $ collection $ res appConfig diff --git a/src/Feature/Sharing/Templates.hs b/src/Feature/Sharing/Templates.hs @@ -0,0 +1,16 @@ +{-# LANGUAGE QuasiQuotes #-} +{-# LANGUAGE TemplateHaskell #-} + +module Feature.Sharing.Templates ( renderPw ) where + +import qualified Data.Text.Lazy as LT + +import Database.MongoDB (Document) +import Text.Blaze.Html.Renderer.Text (renderHtml) +import Text.Blaze.Html +import Text.Hamlet (shamletFile) + +import Prelude + +renderPw :: String -> Maybe String -> LT.Text +renderPw link password = renderHtml ( $(shamletFile "./views/pw.hamlet") ) diff --git a/src/Lib.hs b/src/Lib.hs @@ -1,6 +1,6 @@ module Lib ( main ) where -import Core.Types +import Core.Types import qualified Core.Configuration as Configuration import qualified Core.HTTP as HTTP import qualified Core.Mongo as DB diff --git a/views/index.hamlet b/views/index.hamlet @@ -1,8 +1,14 @@ <html> <head> <title>Purr + <script src="https://unpkg.com/htmx.org@1.7.0" integrity="sha384-EzBXYPt0/T6gxNp0nuPtLkmRpmDBbjg6WmCUZRLXBBwYYmwAUxzlSGej0ARHX0Bo" crossorigin="anonymous"> <body> - $maybe pw <- password - <p>Here's the password for #{link}: #{pw} - $nothing - <p>No password available at https://purr.eversole.co/#{link} + <h1>Welcome to Purr! + <p #requestedPw>No password currently requested. + <p>Ask for the <input name="userLink" type="text"/> password + <button hx-post="/pw" + hx-target="#requestedPw" + hx-swap="outerHTML" + hx-include="[name='userLink']" + /> + Get Password! diff --git a/views/pw.hamlet b/views/pw.hamlet @@ -0,0 +1,5 @@ + <div #requestedPw> + $maybe pw <- password + <p>Here's the password for #{link}: #{pw} + $nothing + <p>No password available at https://purr.eversole.co/#{link}