packages feed

password-persistent (empty) → 0.1.0.0

raw patch · 8 files changed

+281/−0 lines, 8 filesdep +basedep +base-compatdep +doctestbuild-type:Customsetup-changed

Dependencies added: base, base-compat, doctest, password, password-persistent, password-types, persistent, quickcheck-instances, tasty, tasty-quickcheck, text

Files

+ ChangeLog.md view
@@ -0,0 +1,5 @@+# Changelog for `password-persistent`++## 0.1.0.0++- Split from `password-instances`.
+ LICENSE view
@@ -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.
+ README.md view
@@ -0,0 +1,11 @@+# password-persistent++[![Build Status](https://github.com/cdepillabout/password/workflows/password/badge.svg)](http://github.com/cdepillabout/password)+[![Hackage](https://img.shields.io/hackage/v/password-persistent.svg)](https://hackage.haskell.org/package/password-persistent)+[![Stackage LTS](http://stackage.org/package/password-persistent/badge/lts)](http://stackage.org/lts/package/password-persistent)+[![Stackage Nightly](http://stackage.org/package/password-persistent/badge/nightly)](http://stackage.org/nightly/package/password-persistent)+[![BSD3 license](https://img.shields.io/badge/license-BSD3-blue.svg)](./LICENSE)++This package provides `persistent` typeclass instances for the plain-text password+and hashed password datatypes from the+[password](https://hackage.haskell.org/package/password) package.
+ Setup.hs view
@@ -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
+ password-persistent.cabal view
@@ -0,0 +1,83 @@+cabal-version: 1.12++name:           password-persistent+version:        0.1.0.0+category:       Security+synopsis:       persistent typeclass instances for password package+description:    A library providing typeclass instances for `persistent` for the types from the password package.+homepage:       https://github.com/cdepillabout/password/tree/master/password-persistent#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           >= 4.9   && < 5+    , Cabal                      < 4+    , cabal-doctest  >= 1.0.6 && < 1.1++library+  hs-source-dirs:+      src+  exposed-modules:+      Data.Password.Persistent+--   other-modules:+--       Paths_password_persistent+  build-depends:+      base          >= 4.9 && < 5+    , password-types          < 2+    , persistent    >= 1.2 && < 3+    , text                    < 3+  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+  default-language:+      Haskell2010++test-suite password-persistent-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-persistent+    , password-types+    , persistent+    , quickcheck-instances+    , tasty+    -- , tasty-hunit+    , tasty-quickcheck+  default-language:+      Haskell2010
+ src/Data/Password/Persistent.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++{-|+Module      : Data.Password.Persistent+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 `persistent` typeclass instances+for 'Password' and 'PasswordHash'.++See the "Data.Password.Types" module for more information.+-}++module Data.Password.Persistent () where++import Data.Password.Types+#if !MIN_VERSION_base(4,13,0)+import Data.Semigroup ((<>))+#endif+import Data.Text (pack)+import Data.Text.Encoding as TE (decodeUtf8')+import Database.Persist (PersistValue(..))+import Database.Persist.Class (PersistField(..))+import Database.Persist.Sql (PersistFieldSql(..))+import GHC.TypeLits (TypeError, ErrorMessage(..))++-- $setup+-- >>> :set -XOverloadedStrings+-- >>> :set -XDataKinds+--+-- Import needed functions.+--+-- >>> import Data.Password.Bcrypt (Salt(..), hashPasswordWithSalt, unsafeShowPassword)+-- >>> import Data.Password.Types (mkPassword)+-- >>> import Database.Persist.Class (PersistField(toPersistValue))++type ErrMsg = 'Text "Warning! Tried to convert plain-text Password to PersistValue!"+         :$$: '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 PersistValue."+         :$$: 'Text ""++-- | This instance allows a 'PasswordHash' to be stored as a field in a database using+-- "Database.Persist".+--+-- >>> let salt = Salt "abcdefghijklmnop"+-- >>> let pass = mkPassword "foobar"+-- >>> let hashedPassword = hashPasswordWithSalt 10 salt pass+-- >>> toPersistValue hashedPassword+-- PersistText "$2b$10$WUHhXETkX0fnYkrqZU3ta.N8Utt4U77kW4RVbchzgvBvBBEEdCD/u"+--+-- In the example above, the long 'PersistText' will be the value you store in+-- the database.+--+-- We don't provide an instance of 'PersistField' for 'Password', because we don't+-- want to make it easy to store a plain-text password in the database.+instance PersistField (PasswordHash a) where+  toPersistValue (PasswordHash hpw) = PersistText hpw+  fromPersistValue = \case+      PersistText txt -> Right $ PasswordHash txt+      PersistByteString bs ->+        either failed (Right . PasswordHash) $ TE.decodeUtf8' bs+      _ -> Left "could not parse PasswordHash from PersistValue"+    where+      failed e = Left $ "Failed decoding PasswordHash to UTF8: " <> pack (show e)++-- | This instance allows a 'PasswordHash' to be stored as a field in an SQL+-- database in "Database.Persist.Sql".+deriving newtype instance PersistFieldSql (PasswordHash a)++-- | Type error! Do not store plain-text 'Password's in your database!+instance TypeError ErrMsg => PersistField Password where+  toPersistValue = error "unreachable"+  fromPersistValue = error "unreachable"
+ test/doctest/doctest.hs view
@@ -0,0 +1,14 @@+module Main where++import Build_doctests (flags, pkgs, module_sources)+-- import Data.Foldable (traverse_)+import System.Environment.Compat (unsetEnv)+import Test.DocTest (doctest)++main :: IO ()+main = do+  -- traverse_ putStrLn args+  unsetEnv "GHC_ENVIRONMENT"+  doctest args+  where+    args = flags ++ pkgs ++ module_sources
+ test/tasty/Spec.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE OverloadedStrings #-}++import Database.Persist.Class (PersistField (..))+import Test.Tasty (TestTree, defaultMain, testGroup)+import Test.Tasty.QuickCheck (testProperty, (===))+import Test.QuickCheck.Instances.Text ()++import Data.Password.Types (PasswordHash (..))+import Data.Password.Persistent()+++main :: IO ()+main = defaultMain $ testGroup "Password Instances"+  [ persistTest+  ]++persistTest :: TestTree+persistTest = testProperty "PasswordHash (PersistField)" $ \pass ->+    let pwd = PasswordHash pass+    in fromPersistValue (toPersistValue pwd) === Right pwd