Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions hie.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,27 @@ cradle:

- path: "./password-instances/src"
component: "password-instances:lib"
- path: "./password-instances/test/doctest"
component: "password-instances:test:doctests"
- path: "./password-instances/test/tasty"
component: "password-instances:test:password-instances-tasty"

- path: "./password-aeson/src"
component: "password-aeson:lib"
- path: "./password-aeson/test/doctest"
component: "password-aeson:test:doctests"
- path: "./password-aeson/test/tasty"
component: "password-aeson:test:password-aeson-tasty"

- path: "./password-http-api-data/src"
component: "password-http-api-data:lib"
- path: "./password-http-api-data/test/doctest"
component: "password-http-api-data:test:doctests"
- path: "./password-http-api-data/test/tasty"
component: "password-http-api-data:test:password-http-api-data-tasty"

- path: "./password-persistent/src"
component: "password-persistent:lib"
- path: "./password-persistent/test/doctest"
component: "password-persistent:test:doctests"
- path: "./password-persistent/test/tasty"
component: "password-persistent:test:password-persistent-tasty"

- path: "./password-cli/app"
component: "password-cli:exe:password-cli"
5 changes: 5 additions & 0 deletions password-aeson/ChangeLog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Changelog for `password-aeson`

## 0.1.0.0

- Split from `password-instances`.
30 changes: 30 additions & 0 deletions password-aeson/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Copyright (c) Dennis Gosnell, 2019; Felix Paulusma, 2020

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.

* Neither the name of Dennis Gosnell, Felix Paulusma nor the names
of other contributors may be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11 changes: 11 additions & 0 deletions password-aeson/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# password-aeson

[![Build Status](https://github.com/cdepillabout/password/workflows/password/badge.svg)](http://github.com/cdepillabout/password)
[![Hackage](https://img.shields.io/hackage/v/password-aeson.svg)](https://hackage.haskell.org/package/password-aeson)
[![Stackage LTS](http://stackage.org/package/password-aeson/badge/lts)](http://stackage.org/lts/package/password-aeson)
[![Stackage Nightly](http://stackage.org/package/password-aeson/badge/nightly)](http://stackage.org/nightly/package/password-aeson)
[![BSD3 license](https://img.shields.io/badge/license-BSD3-blue.svg)](./LICENSE)

This package provides `aeson` typeclass instances for the plain-text password
and hashed password datatypes from the
[password](https://hackage.haskell.org/package/password) package.
33 changes: 33 additions & 0 deletions password-aeson/Setup.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{-# LANGUAGE CPP #-}
{-# OPTIONS_GHC -Wall #-}
module Main (main) where

#ifndef MIN_VERSION_cabal_doctest
#define MIN_VERSION_cabal_doctest(x,y,z) 0
#endif

#if MIN_VERSION_cabal_doctest(1,0,0)

import Distribution.Extra.Doctest ( defaultMainWithDoctests )
main :: IO ()
main = defaultMainWithDoctests "doctests"

#else

#ifdef MIN_VERSION_Cabal
-- If the macro is defined, we have new cabal-install,
-- but for some reason we don't have cabal-doctest in package-db
--
-- Probably we are running cabal sdist, when otherwise using new-build
-- workflow
#warning You are configuring this package without cabal-doctest installed. \
The doctests test-suite will not work as a result. \
To fix this, install cabal-doctest before configuring.
#endif

import Distribution.Simple

main :: IO ()
main = defaultMain

#endif
88 changes: 88 additions & 0 deletions password-aeson/password-aeson.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
cabal-version: 1.12

name: password-aeson
version: 0.1.0.0
category: Security
synopsis: aeson typeclass instances for password package
description: A library providing typeclass instances for aeson for the types from the password package.
homepage: https://github.com/cdepillabout/password/tree/master/password-aeson#readme
bug-reports: https://github.com/cdepillabout/password/issues
author: Dennis Gosnell, Felix Paulusma
maintainer: cdep.illabout@gmail.com, felix.paulusma@gmail.com
copyright: Copyright (c) Dennis Gosnell, 2019; Felix Paulusma, 2020
license: BSD3
license-file: LICENSE
build-type: Custom
extra-source-files:
README.md
ChangeLog.md

source-repository head
type: git
location: https://github.com/cdepillabout/password

custom-setup
setup-depends:
base
, Cabal
, cabal-doctest >=1.0.6 && <1.1

library
hs-source-dirs:
src
exposed-modules:
Data.Password.Aeson
other-modules:
Paths_password_aeson
build-depends:
base >= 4.9 && < 5
, aeson >= 0.2
, password-types < 2
, text
ghc-options:
-Wall
default-language:
Haskell2010

test-suite doctests
type:
exitcode-stdio-1.0
hs-source-dirs:
test/doctest
main-is:
doctest.hs
ghc-options:
-threaded -rtsopts -with-rtsopts=-N
build-depends:
base >=4.9 && <5
, base-compat
, doctest
, password
, password-aeson
, QuickCheck
, quickcheck-instances
, template-haskell
default-language:
Haskell2010

test-suite password-aeson-tasty
type:
exitcode-stdio-1.0
hs-source-dirs:
test/tasty
main-is:
Spec.hs
ghc-options:
-threaded -rtsopts -with-rtsopts=-N
build-depends:
base >=4.9 && <5
, password-aeson
, password-types
, aeson
, quickcheck-instances
, tasty
, tasty-hunit
, tasty-quickcheck
, text
default-language:
Haskell2010
83 changes: 83 additions & 0 deletions password-aeson/src/Data/Password/Aeson.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

{-|
Module : Data.Password.Aeson
Copyright : (c) Dennis Gosnell, 2019; Felix Paulusma, 2020
License : BSD-style (see LICENSE file)
Maintainer : cdep.illabout@gmail.com
Stability : experimental
Portability : POSIX

This module provides additional typeclass instances
for 'Password' and 'PasswordHash'.

See the "Data.Password.Types" module for more information.
-}

module Data.Password.Aeson
( FromJSON (..),
ToJSON (..),
ExposedPassword (..),
) where

import Data.Aeson (FromJSON(..), ToJSON(..))
import Data.Password.Types
import GHC.TypeLits (TypeError, ErrorMessage(..))

-- $setup
-- >>> :set -XOverloadedStrings
-- >>> :set -XDataKinds
--
-- Import needed functions.
--
-- >>> import Data.Aeson (decode)
-- >>> import Data.Password.Bcrypt (Salt(..), hashPasswordWithSalt, unsafeShowPassword)

-- | This instance allows a 'Password' to be created from a JSON blob.
--
-- >>> let maybePassword = decode "\"foobar\"" :: Maybe Password
-- >>> fmap unsafeShowPassword maybePassword
-- Just "foobar"
--
-- There is no instance for 'ToJSON' for 'Password' because we don't want to
-- accidentally encode a plain-text 'Password' to JSON and send it to the end-user.
--
-- Similarly, there is no 'ToJSON' and 'FromJSON' instance for 'PasswordHash'
-- because we don't want to accidentally send the password hash to the end
-- user.
instance FromJSON Password where
parseJSON = fmap mkPassword . parseJSON

type ErrMsg = 'Text "Warning! Tried to convert plain-text Password to JSON!"
':$$: 'Text " This is likely a security leak. Please make sure whether this was intended."
':$$: 'Text " If this is intended, please use 'unsafeShowPassword' before converting to JSON"
':$$: 'Text ""

-- | Type error! Do not use 'toJSON' on a 'Password'!
instance TypeError ErrMsg => ToJSON Password where
toJSON = error "unreachable"

-- | WARNING: DO NOT USE UNLESS ABSOLUTELY NECESSARY!
--
-- Using this newtype will allow your plain text password to be turned into
-- JSON. Keep this type tightly bound to only the section where you want to
-- expose the `Password`, since it's easy for a bigger type that contains
-- this `ExposedPassword` to be logged or printed as JSON, and now you've
-- accidentally leaked passwords in your logs or database.
newtype ExposedPassword = ExposedPassword Password
deriving newtype (FromJSON)

instance ToJSON ExposedPassword where
toJSON (ExposedPassword p) = toJSON $ unsafeShowPassword p

deriving newtype instance FromJSON (PasswordHash a)

deriving newtype instance ToJSON (PasswordHash a)
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,18 @@
import Data.Aeson
import Data.Aeson.Types (parseMaybe)
import Data.Text (Text)
import Database.Persist.Class (PersistField(..))
import Test.Tasty
import Test.Tasty.HUnit
import Test.Tasty.QuickCheck
import Test.QuickCheck.Instances.Text ()
import Web.HttpApiData (FromHttpApiData(..))

import Data.Password.Types (Password, PasswordHash(..), unsafeShowPassword)
import Data.Password.Instances()
import Data.Password.Aeson()


main :: IO ()
main = defaultMain $ testGroup "Password Instances"
[ aesonTest
, fromHttpApiDataTest
, persistTest
]

data TestUser = TestUser {
Expand All @@ -41,15 +37,3 @@ aesonTest = testCase "Password (Aeson)" $
[ "name" .= String "testname"
, "password" .= String testPassword
]

fromHttpApiDataTest :: TestTree
fromHttpApiDataTest = testCase "Password (FromHttpApiData)" $
assertEqual "password doesn't match" (Right testPassword) $
unsafeShowPassword <$> parseUrlPiece testPassword
where
testPassword = "passtest"

persistTest :: TestTree
persistTest = testProperty "PasswordHash (PersistField)" $ \pass ->
let pwd = PasswordHash pass
in fromPersistValue (toPersistValue pwd) === Right pwd
5 changes: 5 additions & 0 deletions password-http-api-data/ChangeLog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Changelog for `password-http-api-data`

## 0.1.0.0

- Split from `password-instances`.
30 changes: 30 additions & 0 deletions password-http-api-data/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Copyright (c) Dennis Gosnell, 2019; Felix Paulusma, 2020

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.

* Neither the name of Dennis Gosnell, Felix Paulusma nor the names
of other contributors may be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11 changes: 11 additions & 0 deletions password-http-api-data/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# password-http-api-data

[![Build Status](https://github.com/cdepillabout/password/workflows/password/badge.svg)](http://github.com/cdepillabout/password)
[![Hackage](https://img.shields.io/hackage/v/password-http-api-data.svg)](https://hackage.haskell.org/package/password-http-api-data)
[![Stackage LTS](http://stackage.org/package/password-http-api-data/badge/lts)](http://stackage.org/lts/package/password-http-api-data)
[![Stackage Nightly](http://stackage.org/package/password-http-api-data/badge/nightly)](http://stackage.org/nightly/package/password-http-api-data)
[![BSD3 license](https://img.shields.io/badge/license-BSD3-blue.svg)](./LICENSE)

This package provides `http-api-data` typeclass instances for the plain-text password
and hashed password datatypes from the
[password](https://hackage.haskell.org/package/password) package.
Loading