Added Shakespeare templating and setup basic Maybe-bound lookup for conditional rendering of the page or an appropriate notice that the password doesn't exist.

This commit is contained in:
James Eversole 2022-07-02 13:23:53 -05:00
parent f7a61dcddc
commit d15b40a339
10 changed files with 144 additions and 37 deletions

2
.gitignore vendored
View File

@ -2,6 +2,6 @@ data/
bin/
/config.dhall
/Dockerfile
docker-stack.yml
/docker-stack.yml
.stack-work/
*~

View File

@ -22,6 +22,7 @@ library
Core.Configuration
Core.HTTP
Core.Mongo
Core.Templates
Core.Types
Feature.Handlers
Lib
@ -30,17 +31,18 @@ library
hs-source-dirs:
src
default-extensions:
OverloadedStrings
GeneralizedNewtypeDeriving
DeriveGeneric
ConstraintKinds
DeriveGeneric
FlexibleContexts
FlexibleInstances
GeneralizedNewtypeDeriving
OverloadedStrings
ScopedTypeVariables
build-depends:
AesonBson ==0.4.1
, aeson >=2.0.0.0
, base >=4.7
, blaze-html >=0.9.1.0
, bson >=0.3
, dhall >=1.40 && <1.41.2
, http-types >=0.12.3
@ -48,6 +50,7 @@ library
, mongoDB >=2.7.1.1
, mtl >=2.2.2
, scotty ==0.12
, shakespeare >=2.0.20
, text >=1.2
, time >=1.9
, wai-extra >=3.1.12.1
@ -60,12 +63,12 @@ executable Purr-exe
hs-source-dirs:
app
default-extensions:
OverloadedStrings
GeneralizedNewtypeDeriving
DeriveGeneric
ConstraintKinds
DeriveGeneric
FlexibleContexts
FlexibleInstances
GeneralizedNewtypeDeriving
OverloadedStrings
ScopedTypeVariables
ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends:
@ -73,6 +76,7 @@ executable Purr-exe
, Purr
, aeson >=2.0.0.0
, base >=4.7
, blaze-html >=0.9.1.0
, bson >=0.3
, dhall >=1.40 && <1.41.2
, http-types >=0.12.3
@ -80,6 +84,7 @@ executable Purr-exe
, mongoDB >=2.7.1.1
, mtl >=2.2.2
, scotty ==0.12
, shakespeare >=2.0.20
, text >=1.2
, time >=1.9
, wai-extra >=3.1.12.1
@ -93,12 +98,12 @@ test-suite Purr-test
hs-source-dirs:
test
default-extensions:
OverloadedStrings
GeneralizedNewtypeDeriving
DeriveGeneric
ConstraintKinds
DeriveGeneric
FlexibleContexts
FlexibleInstances
GeneralizedNewtypeDeriving
OverloadedStrings
ScopedTypeVariables
ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends:
@ -106,6 +111,7 @@ test-suite Purr-test
, Purr
, aeson >=2.0.0.0
, base >=4.7
, blaze-html >=0.9.1.0
, bson >=0.3
, dhall >=1.40 && <1.41.2
, http-types >=0.12.3
@ -113,6 +119,7 @@ test-suite Purr-test
, mongoDB >=2.7.1.1
, mtl >=2.2.2
, scotty ==0.12
, shakespeare >=2.0.20
, text >=1.2
, time >=1.9
, wai-extra >=3.1.12.1

View File

@ -13,7 +13,7 @@ Purr is a work-in-progress web application offering customizable password genera
3. [MongoDB](https://github.com/mongodb/mongo) database.
## Why should I trust you with my passwords?
You shouldn't! This is free and open-source software which you can run on your own hardware. Instructions for deployment are coming soon.
You shouldn't! This is [free and open-source software](https://git.eversole.co/James/Purr/src/branch/main/LICENSE) which you can run on your own hardware. Instructions for deployment are coming soon.
## 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)!

44
examples/docker-stack.yml Normal file
View File

@ -0,0 +1,44 @@
version: '3.1'
# Default Docker Stack/Compose configuration for Purr.
# You will need to change all instances of "REPLACEME" with the appropriate details.
# Additionally, you may want to update the host port definitions for each service and
# remove the Mongo Express service entirely for production.
services:
mongodb:
image: mongo:4.4.6
ports:
- 27017:27017
volumes:
- ./data:/opt/purr/data
networks:
- webnet
environment:
MONGO_INITDB_ROOT_USERNAME: REPLACEME
MONGO_INITDB_ROOT_PASSWORD: REPLACEME
mexpress:
image: mongo-express
ports:
- 8081:8081
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: REPLACEME
ME_CONFIG_MONGODB_ADMINPASSWORD: REPLACEME
ME_CONFIG_MONGODB_SERVER: mongodb
networks:
- webnet
depends_on:
- mongodb
purr:
image: purr
ports:
- 3000:3000
networks:
- webnet
depends_on:
- mongodb
networks:
webnet:

View File

@ -10,12 +10,12 @@ extra-source-files:
- ChangeLog.md
default-extensions:
- OverloadedStrings
- GeneralizedNewtypeDeriving
- DeriveGeneric
- ConstraintKinds
- DeriveGeneric
- FlexibleContexts
- FlexibleInstances
- GeneralizedNewtypeDeriving
- OverloadedStrings
- ScopedTypeVariables
# Metadata used when publishing your package
@ -30,14 +30,16 @@ description: https://git.eversole.co/James/Purr
dependencies:
- aeson >= 2.0.0.0
- AesonBson == 0.4.1
- bson >= 0.3
- base >= 4.7
- blaze-html >= 0.9.1.0
- bson >= 0.3
- dhall >= 1.40 && < 1.41.2
- http-types >= 0.12.3
- iso8601-time >= 0.1.5
- mongoDB >= 2.7.1.1
- mtl >= 2.2.2
- scotty == 0.12
- shakespeare >= 2.0.20
- time >= 1.9
- text >= 1.2
- wai-extra >= 3.1.12.1

View File

@ -2,7 +2,7 @@ module Core.HTTP ( app ) where
import Core.Types
import Feature.Handlers as RES
import Feature.Handlers as HD
import Network.Wai.Middleware.RequestLogger (logStdoutDev)
import Web.Scotty.Trans
@ -11,4 +11,4 @@ app :: PurrApp ()
app = do
middleware logStdoutDev
get "/" RES.root
get "/:id" HD.pwLookup

View File

@ -1,20 +1,47 @@
module Core.Mongo ( mongoSetup, tempGetDocs ) where
module Core.Mongo ( mongoSetup, getAllDocs, findByLink ) where
import Core.Types
import Control.Monad.Reader (MonadIO)
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
-- Authenticates to Mongo and returns the MongoContext for the dataDB
mongoSetup :: DhallConfig -> IO MongoContext
mongoSetup conf = do
mongoCon <- connect $ host (hostname conf)
let adminCon = MongoContext mongoCon master (adminDB conf)
access (mongoPipe adminCon) (mongoAccessMode adminCon) (mongoDatabase adminCon) (auth (mongoUsername conf) (mongoPassword conf))
access
(mongoPipe adminCon)
(mongoAccessMode adminCon)
(mongoDatabase adminCon)
(auth (mongoUsername conf) (mongoPassword conf))
return $ MongoContext mongoCon master (dataDB conf)
tempGetDocs :: MonadIO m => AppConfig -> m [Document]
tempGetDocs appConfig = access (mongoPipe db) (mongoAccessMode db) (mongoDatabase db) $ find (select [] (collection conf)) >>= rest
where
db = dbconn appConfig
conf = res appConfig

14
src/Core/Templates.hs Normal file
View File

@ -0,0 +1,14 @@
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
module Core.Templates ( renderIndex ) where
import Database.MongoDB (Document)
import Text.Blaze.Html.Renderer.String (renderHtml)
import Text.Blaze.Html
import Text.Hamlet (shamletFile)
import Prelude
renderIndex :: String -> Maybe String -> String
renderIndex link password = renderHtml ( $(shamletFile "./views/index.hamlet") )

View File

@ -1,18 +1,23 @@
module Feature.Handlers ( root ) where
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))
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 (json)
import Prelude hiding (id)
import Web.Scotty.Trans (html, param)
import Prelude hiding (id, lookup)
root :: PurrAction ()
root = do
config <- lift $ ask
docs <- DB.tempGetDocs config
json $ aesonify ["allDocs" := Array (map Doc docs)]
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

8
views/index.hamlet Normal file
View File

@ -0,0 +1,8 @@
<html>
<head>
<title>Purr
<body>
$maybe pw <- password
<p>Here's the password for #{link}: #{pw}
$nothing
<p>No password available at https://purr.eversole.co/#{link}