From ee8686bc83be55d95d5e9e185ca8808600fa31b8 Mon Sep 17 00:00:00 2001 From: James Eversole Date: Tue, 27 Dec 2022 12:25:14 -0600 Subject: [PATCH] Bugfix on UI elements when no secret is found. Add copy secret button on successful retrieval. Include deployment information and updated example files. --- Purr.cabal | 43 ++----------------------------- README | 30 +++++++++++++++++----- build-docker | 12 +++++++++ examples/Dockerfile | 11 ++++---- examples/docker-stack.yml | 5 +--- package.yaml | 30 ++++++++++++++-------- stack.yaml | 50 +++++-------------------------------- views/cassius/style.cassius | 8 ++++++ views/index.hamlet | 1 + views/public/copySecret.js | 10 ++++++++ views/pw.hamlet | 4 ++- 11 files changed, 91 insertions(+), 113 deletions(-) create mode 100755 build-docker create mode 100644 views/public/copySecret.js diff --git a/Purr.cabal b/Purr.cabal index d778d68..fcdeabc 100644 --- a/Purr.cabal +++ b/Purr.cabal @@ -68,7 +68,7 @@ library , wai-middleware-static >=0.5 default-language: Haskell2010 -executable Purr-exe +executable Purr-musl main-is: Main.hs other-modules: Paths_Purr @@ -82,46 +82,7 @@ executable Purr-exe GeneralizedNewtypeDeriving OverloadedStrings ScopedTypeVariables - ghc-options: -threaded -rtsopts -with-rtsopts=-N - build-depends: - Purr - , base >=4.7 - , base64-bytestring >=1.2.0.0 - , blaze-html >=0.9.1.0 - , bytestring >=0.10.12.1 - , containers >=0.6.4.1 - , crypto-simple >=0.1.0.0 - , dhall >=1.40 && <1.41.2 - , http-types >=0.12.3 - , iso8601-time >=0.1.5 - , mtl >=2.2.2 - , random >=1.2 - , scotty ==0.12 - , shakespeare >=2.0.20 - , split >=0.2.3.4 - , sqlite-simple >=0.4.18.0 - , text >=1.2.5.0 - , time >=1.9 - , wai-extra >=3.1.12.1 - , wai-middleware-static >=0.5 - default-language: Haskell2010 - -test-suite Purr-test - type: exitcode-stdio-1.0 - main-is: Spec.hs - other-modules: - Paths_Purr - hs-source-dirs: - test - default-extensions: - ConstraintKinds - DeriveGeneric - FlexibleContexts - FlexibleInstances - GeneralizedNewtypeDeriving - OverloadedStrings - ScopedTypeVariables - ghc-options: -threaded -rtsopts -with-rtsopts=-N + ghc-options: -threaded -rtsopts -with-rtsopts=-N -static -optl-static -optl-pthread -fPIC build-depends: Purr , base >=4.7 diff --git a/README b/README index 9beb409..a46dd3a 100644 --- a/README +++ b/README @@ -4,6 +4,12 @@ purr https://purr.eversole.co a work-in-progress web application offering customizable password generation and time-limited sharing of secrets. +TECH STACK + +- Haskell and Scotty backend +- HTMX frontend +- SQLite database + GOALS - Generate sufficiently memorable but secure passwords for use with accounts that don't offer better authentication methods. @@ -14,16 +20,28 @@ GOALS WHY TRUST YOU? -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 which you can run on your own hardware. -TECH STACK +DEPLOYMENT -- Haskell and Scotty backend -- HTMX frontend -- SQLite database +purr is intended to run in a docker container. +This repo's Stack project is configured to use a musl-based docker container for builds. +Assuming your working directory is inside of this repository: + +1. Copy "examples/config.dhall" to ./config.dhall - configure this file appropriately. + - Use `openssl rand -hex 10` to generate an encryption key for "dbKey" +2. Copy "examples/Dockerfile" to ./Dockerfile +3. If using default database file location, run: `mkdir ./data; touch ./data/Purr.sqlite` +4. Run `chmod +x build-docker` +5. Run `./build-docker $IMAGE_NAME` to complete the initial Stack build and create the container +6. Orchestrate the container as desired + - docker run -d -v "$(pwd -P)/data/Purr.sqlite:/app/data/Purr.sqlite" \ + -v "$(pwd -P)/config.dhall:/app/config.dhall" \ + -p 5195:3000 purr + |- An example docker-stack.yml is provided: `docker stack deploy -c docker-stack.yml purr` DEVELOPMENT & SUPPORT -Please send me an email for support. +Please send me an email for support or to provide patches. Copyright 2022 James Eversole (james@eversole.co) diff --git a/build-docker b/build-docker new file mode 100755 index 0000000..abb882b --- /dev/null +++ b/build-docker @@ -0,0 +1,12 @@ +#!/bin/bash +set -e +# Date: 12/27/2022 +# Author: James Eversole +# ISC License +# This script completes a stack build and then builds a docker image +# containing Purr. The image name is the first argument to the script. + +IMAGE_NAME=${1:-"purr"} + +stack build --copy-bins +docker build . -t $IMAGE_NAME diff --git a/examples/Dockerfile b/examples/Dockerfile index 6b732cc..8288eb0 100644 --- a/examples/Dockerfile +++ b/examples/Dockerfile @@ -1,11 +1,10 @@ -FROM haskell:9.0.2 +FROM alpine:3.17.0 WORKDIR /app -ADD . /app - -RUN stack setup -RUN stack build --copy-bins --local-bin-path ./ +ADD ./views /app/views +ADD ./src /app/src +ADD ./bin/Purr-musl /app/Purr-musl EXPOSE 3000 -CMD ./Purr-exe +ENTRYPOINT ["/app/Purr-musl"] diff --git a/examples/docker-stack.yml b/examples/docker-stack.yml index 6551b08..22951e6 100644 --- a/examples/docker-stack.yml +++ b/examples/docker-stack.yml @@ -1,9 +1,5 @@ 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. - services: purr: image: purr @@ -13,6 +9,7 @@ services: - webnet volumes: - ./data/Purr.sqlite:/app/data/Purr.sqlite + - ./config.dhall:/app/config.dhall networks: webnet: diff --git a/package.yaml b/package.yaml index adf256f..1bf5a31 100644 --- a/package.yaml +++ b/package.yaml @@ -52,23 +52,31 @@ library: source-dirs: src executables: - Purr-exe: + Purr-musl: main: Main.hs source-dirs: app ghc-options: - -threaded - -rtsopts - -with-rtsopts=-N + - -static + - -optl-static + - -optl-pthread + - -fPIC dependencies: - Purr -tests: - Purr-test: - main: Spec.hs - source-dirs: test - ghc-options: - - -threaded - - -rtsopts - - -with-rtsopts=-N - dependencies: - - Purr + #tests: + # Purr-test: + # main: Spec.hs + # source-dirs: test + # ghc-options: + # - -threaded + # - -rtsopts + # - -with-rtsopts=-N + # - -static + # - -optl-static + # - -optl-pthread + # - -fPIC + # dependencies: + # - Purr diff --git a/stack.yaml b/stack.yaml index e58dfe7..7c12f6a 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,54 +1,23 @@ # This file was automatically generated by 'stack init' # -# Some commonly used options have been documented as comments in this file. -# For advanced use and comprehensive documentation of the format, please see: -# https://docs.haskellstack.org/en/stable/yaml_configuration/ - -# Resolver to choose a 'specific' stackage snapshot or a compiler version. -# A snapshot resolver dictates the compiler version and the set of packages -# to be used for project dependencies. For example: -# -# resolver: lts-3.5 -# resolver: nightly-2015-09-21 -# resolver: ghc-7.10.2 -# -# The location of a snapshot can be provided as a file or url. Stack assumes -# a snapshot provided as a file might change, whereas a url resource does not. -# -# resolver: ./custom-snapshot.yaml -# resolver: https://example.com/snapshots/2018-01-01.yaml resolver: url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/13.yaml # User packages to be built. -# Various formats can be used as shown in the example below. -# -# packages: -# - some-directory -# - https://example.com/foo/bar/baz-0.0.2.tar.gz -# subdirs: -# - auto-update -# - wai packages: - . -# Dependency packages to be pulled from upstream that are not in the resolver. -# These entries can reference officially published versions as well as -# forks / in-progress versions pinned to a git hash. For example: # extra-deps: - crypto-simple-0.1.0.0@sha256:5c0e1e04a814d903743d7543245951a91a46817230fdf478fadca57116805fc1,1502 +docker: + enable: true + image: "utdemir/ghc-musl:v24-ghc902" + +local-bin-path: + ./bin #ghc-options: -# Override default flag values for local packages and extra-deps -# flags: {} - -# Extra package databases containing global packages -# extra-package-dbs: [] - -# Control whether we use the GHC we find on the path -# system-ghc: true -# # Require a specific version of stack, using version ranges # require-stack-version: -any # Default # require-stack-version: ">=2.7" @@ -56,10 +25,3 @@ extra-deps: # Override the architecture used by stack, especially useful on Windows # arch: i386 # arch: x86_64 -# -# Extra directories used by stack for building -# extra-include-dirs: [/path/to/dir] -# extra-lib-dirs: [/path/to/dir] -# -# Allow a newer minor version of GHC than the snapshot specifies -# compiler-check: newer-minor diff --git a/views/cassius/style.cassius b/views/cassius/style.cassius index c9a4647..11e62c5 100644 --- a/views/cassius/style.cassius +++ b/views/cassius/style.cassius @@ -172,9 +172,17 @@ input[type=number] box-shadow: 8px 8px 12px #ccc .pwResult + margin: 0.25em 0 0.75em 0 font-size: 1.5em color: #f0f6f0 +.pwResultCopy + width: 1px + overflow: hidden + display: inline-block + height: 1px + color: rgba(255,255,255,0) + .shareNew padding: 0.5em 0.5em 0.5em 1.5em background-color: #{colorTwo} diff --git a/views/index.hamlet b/views/index.hamlet index 39cf387..6f229b2 100644 --- a/views/index.hamlet +++ b/views/index.hamlet @@ -5,6 +5,7 @@ $doctype 5 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"> + <script src="/copySecret.js" integrity="sha384-jB3mpB1WyAo8ToD7oWm/LjXBnEImM/8GB7tjExykwuNErwdPHa9mihHlVJRtV+bt"> <link rel="stylesheet" href="/style.css"> <body> diff --git a/views/public/copySecret.js b/views/public/copySecret.js new file mode 100644 index 0000000..909ed92 --- /dev/null +++ b/views/public/copySecret.js @@ -0,0 +1,10 @@ +function copySecret(secret) { + var tempText = document.createElement('input'); + tempText.style = 'position: absolute; left: -1000px; top: -1000px'; + tempText.value = secret; + document.body.appendChild(tempText); + tempText.select(); + document.execCommand('copy'); + document.body.removeChild(tempText); + document.getElementById('copyButton').innerHTML = "- secret copied -"; +} diff --git a/views/pw.hamlet b/views/pw.hamlet index c0264b6..fae6d33 100644 --- a/views/pw.hamlet +++ b/views/pw.hamlet @@ -2,5 +2,7 @@ $maybe pw <- password <p .resLink>secret found at <a href="/pw/#{link}">/pw/#{link}</a>: <h3 .pwResult>#{pw} + <button #copyButton .mainButton onclick="copySecret('#{pw}')">copy secret</button> $nothing - <h3 .pwResult>no secret found at <a href="/pw/#{link}">/pw/#{link}</a> + <p .resLink>no secret found at + <br /><a href="/pw/#{link}">/pw/#{link}</a>