Updated README with project goals, started prototyping frontend and added route for primary css dist, added reasonable functionality for requesting a password directly via link as well as patching index DOM when requesting HTML stub from /pw

This commit is contained in:
James Eversole 2022-07-03 21:48:40 -05:00
parent 7274560398
commit f1b18f3b47
10 changed files with 211 additions and 43 deletions

View File

@ -1,19 +1,24 @@
# Purr - Password Generation and Sharing
# Purr - Password Generation and Secret Sharing
![Big Purr and Sploot](https://eversole.co/Purr-Small.png "Purr!")
Purr is a work-in-progress web application offering customizable password generation and time-limited link sharing features.
Purr is a work-in-progress web application offering customizable password generation and time-limited sharing of secrets.
## What problems does Purr solve?
1. Generating sufficiently memorable but secure passwords for use with accounts that don't offer better authentication methods.
2. Sharing passwords or other text secrets with others via email/chat/etc., without disclosing the password itself. As passwords expire after a predefined period, the email/chat history where the information was shared don't become a purr-manent (sorry, **permanent**) vulnerability.
2. Sharing text secrets with others without disclosing the secret in the message itself. As secrets expire after a predefined period, the email/chat history where the information was shared don't become a purr-manent (sorry, **permanent**) vulnerability.
3. Being really cute compared to the competition.
## Why should I trust you with my secrets?
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.
## Tech Stack?
1. [Haskell](https://www.haskell.org) and [Scotty](https://github.com/scotty-web/scotty) backend.
2. [HTMX](https://github.com/bigskysoftware/htmx) and [Alpine.js](https://github.com/alpinejs/alpine) for the frontend.
2. [HTMX](https://github.com/bigskysoftware/htmx) for the frontend.
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](https://git.eversole.co/James/Purr/src/branch/main/LICENSE) which you can run on your own hardware. Instructions for deployment are coming soon.
## Project Goals
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.
3. Aim for graceful degradation when JavaScript isn't enabled.
## 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)!

View File

@ -2,9 +2,10 @@ module Core.HTTP ( app ) where
import Core.Types
import Core.Templates (renderIndex)
import Core.Templates (renderIndex, renderStyle)
import Feature.Sharing.HTTP as Sharing
import Data.Maybe (Maybe (Nothing))
import Network.Wai.Middleware.RequestLogger (logStdoutDev)
import Web.Scotty.Trans
@ -15,7 +16,11 @@ app = do
-- Core Routes
get "/" $ do
html $ renderIndex
html $ renderIndex "/" Nothing
get "/style.css" $ do
setHeader "Content-Type" "text/css"
text renderStyle
-- Feature Routes
Sharing.routes

View File

@ -1,16 +1,19 @@
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
module Core.Templates ( renderIndex ) where
import qualified Data.Text.Lazy as LT
module Core.Templates ( renderIndex, renderStyle ) where
import Data.Text.Lazy (Text)
import Database.MongoDB (Document)
import Text.Blaze.Html.Renderer.Text (renderHtml)
import Text.Blaze.Html
import Text.Cassius (cassiusFile, renderCss)
import Text.Hamlet (shamletFile)
import Prelude
renderIndex :: LT.Text
renderIndex = renderHtml ( $(shamletFile "./views/index.hamlet") )
renderIndex :: String -> Maybe String -> Text
renderIndex link password = renderHtml ( $(shamletFile "./views/index.hamlet") )
renderStyle :: Text
renderStyle = renderCss ( $(cassiusFile "./views/cassius/style.cassius") "/style.css" )

View File

@ -1,9 +1,10 @@
module Feature.Sharing.HTTP ( routes ) where
import Core.Types
import Core.Types
import Core.Templates (renderIndex)
import Feature.Sharing.Templates
import qualified Feature.Sharing.Mongo as DB
import Feature.Sharing.Templates (renderPw)
import qualified Feature.Sharing.Mongo as DB
import qualified Data.Text as T
import qualified Data.Text.Lazy as LT
@ -12,21 +13,21 @@ 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)
import Prelude hiding (lookup)
routes :: PurrApp ()
routes = do
get "/pw/:id" $ do
id <- param "id"
doc <- DB.findByLink id
html $ renderPw id (pwLookup doc)
reqId <- param "id"
doc <- DB.findByLink reqId
html $ renderIndex reqId (pwLookup doc)
post "/pw" $ do
id <- param "userLink"
doc <- DB.findByLink id
html $ renderPw id (pwLookup doc)
reqId <- param "userLink"
doc <- DB.findByLink reqId
html $ renderPw reqId (pwLookup doc)
pwLookup :: Maybe Document -> Maybe String
pwLookup (Just x) = (lookup "password" x)
pwLookup _ = Nothing
pwLookup (Just x) = lookup "password" x
pwLookup _ = Nothing

View File

@ -1,15 +1,15 @@
module Lib ( main ) where
import Core.Types
import qualified Core.Configuration as Configuration
import qualified Core.HTTP as HTTP
import qualified Core.Mongo as DB
import Core.Types
import Control.Monad.Reader (liftIO, runReaderT)
import Database.MongoDB (MongoContext)
import GHC.Natural (popCountNatural)
import Web.Scotty.Trans (scottyT)
import Prelude hiding (id)
import Web.Scotty.Trans (scottyT)
main :: IO ()
main = do
@ -20,4 +20,4 @@ main = do
}
scottyT (port dhallConf) (flip runApp config) HTTP.app where
runApp :: ConfigM a -> AppConfig -> IO a
runApp m c = runReaderT (runConfigM m) c
runApp m = runReaderT (runConfigM m)

View File

@ -39,6 +39,9 @@ extra-deps:
- AesonBson-0.4.1@sha256:30a4ecb39e8da94dc1e1e8945eb0d4e33a833ae4342841b3c87c56b5918a90a1,1398
- bson-generic-0.0.9@sha256:ea6685daa618b2bbe6e189c33e195e812501baf42f53183eedc16f011690895a,817
ghc-options:
'$everything': -haddock
# Override default flag values for local packages and extra-deps
# flags: {}

106
views/cassius/style.cassius Normal file
View File

@ -0,0 +1,106 @@
@colorOne: #222323
@colorTwo: #f0f6f0
@colorThree: #6D92AD
@colorFour: #435F5D
html
background-color: #{colorTwo}
color: #{colorOne}
body
font-family: Courier
font-size: 20px
text-align: left
p
margin: 0.4em 0 0.4em 0
::placeholder
color: #{colorOne}
opacity: 1
.asciiCat
margin: 2% 3% 0 0
font-size: 1.2vw
color: #{colorFour}
text-align: center
.content
margin: 0 15% 0 15%
.emptyReq
height: 1%
.mainButton
padding: 0.75em 1.75em
background-color: #{colorThree}
color: #{colorTwo}
border-style: none
text-decoration: none
.mainInput
font-weight: 400
font-size: 1em
width: 50%
outline: none
color: #{colorOne}
background: #{colorTwo}
margin: 1em 0
border-style: none none none 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
.mainInput:focus
border-bottom: 0.2em solid #{colorThree};
.mainInput:focus::placeholder
color: #{colorThree}
opacity: 0.5
.pwResult
font-size: 1.5em
color: #{colorFour}
.pwUtils
width: 75%
.shareNew
margin-bottom: 2em
.title
font-size: 2em
color: #{colorOne}
text-decoration: none
.titleLink
all: unset
cursor: pointer
.title h1
margin: 0.1em 0 0.3em 0
@media only screen and (max-width : 768px)
body
text-align: center
font-size: 16px
.asciiCat
display: none
.mainInput
width: 95%
text-align: center
.title
margin: 8% auto
font-size: 3em
.pwUtils
width: 100%

View File

@ -1,14 +1,58 @@
$doctype 5
<html>
<head>
<title>Purr
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://unpkg.com/htmx.org@1.7.0" integrity="sha384-EzBXYPt0/T6gxNp0nuPtLkmRpmDBbjg6WmCUZRLXBBwYYmwAUxzlSGej0ARHX0Bo" crossorigin="anonymous">
<link rel="stylesheet" href="/style.css">
<body>
<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!
<pre #asciiCat .asciiCat>
_._ _,-'""`-._
\ (,-.`._,'( |\`-/|
\ `-.-' \ )-`( , o o)
\ `- \`_`"'-
<div #content .content>
<div #title .title>
<h1>
<a #titleLink .titleLink href="/">Purr
<div #pwUtils .pwUtils>
<div #requestedPw .requestedPw>
$maybe pw <- password
<p>Here's the secret for /pw/#{link}:
<h2 .pwResult>#{pw}
$nothing
$if (link == "/")
<p .emptyReq>
$else
<p>No secret available at /pw/#{link}
<div #shareNew .shareNew>
<p>
<input .mainInput
name="newPw"
type="text"
placeholder="Enter a Secret to Share"
/>
<button .mainButton
hx-post="/newpw"
hx-target="#requestedPw"
hx-swap="outerHTML"
hx-include="[name='newPw']"
/>
Share Secret
<div #requestNew .requestNew>
<p>
<input .mainInput
name="userLink"
type="text"
placeholder="Enter a Link to View Secret"
/>
<button .mainButton
hx-post="/pw"
hx-target="#requestedPw"
hx-swap="outerHTML"
hx-include="[name='userLink']"
/>
Get Secret

View File

@ -1,5 +1,6 @@
<div #requestedPw>
<div #requestedPw .requestedPw>
$maybe pw <- password
<p>Here's the password for https://purr.eversole.co/pw/#{link}: #{pw}
<p>Here's the secret for /pw/#{link}:
<h2 .pwResult>#{pw}
$nothing
<p>No password available at https://purr.eversole.co/pw/#{link}
<p>No secret available at /pw/#{link}