Listing & adding entries now works
This commit is contained in:
parent
d34a957780
commit
7d4c37debe
@ -41,6 +41,7 @@ library
|
|||||||
, ansi-terminal
|
, ansi-terminal
|
||||||
, base >=4.7 && <5
|
, base >=4.7 && <5
|
||||||
, bytestring
|
, bytestring
|
||||||
|
, cipher-aes
|
||||||
, hashable
|
, hashable
|
||||||
, sqlite-simple
|
, sqlite-simple
|
||||||
, text
|
, text
|
||||||
@ -62,6 +63,7 @@ executable HasswordManager-exe
|
|||||||
, ansi-terminal
|
, ansi-terminal
|
||||||
, base >=4.7 && <5
|
, base >=4.7 && <5
|
||||||
, bytestring
|
, bytestring
|
||||||
|
, cipher-aes
|
||||||
, hashable
|
, hashable
|
||||||
, sqlite-simple
|
, sqlite-simple
|
||||||
, text
|
, text
|
||||||
@ -84,6 +86,7 @@ test-suite HasswordManager-test
|
|||||||
, ansi-terminal
|
, ansi-terminal
|
||||||
, base >=4.7 && <5
|
, base >=4.7 && <5
|
||||||
, bytestring
|
, bytestring
|
||||||
|
, cipher-aes
|
||||||
, hashable
|
, hashable
|
||||||
, sqlite-simple
|
, sqlite-simple
|
||||||
, text
|
, text
|
||||||
|
95
app/Main.hs
95
app/Main.hs
@ -1,9 +1,10 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
module Main (main) where
|
module Main (main) where
|
||||||
|
|
||||||
import Data.ByteString.UTF8 (fromString)
|
import Data.ByteString.UTF8 (fromString, toString)
|
||||||
import Database.SQLite.Simple
|
import Database.SQLite.Simple
|
||||||
import System.Hclip
|
import System.Hclip
|
||||||
|
import qualified Data.Text as T
|
||||||
|
|
||||||
import qualified UserInterface as Ui
|
import qualified UserInterface as Ui
|
||||||
import qualified Database as Db
|
import qualified Database as Db
|
||||||
@ -13,18 +14,19 @@ import qualified Utils as Ut
|
|||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
conn <- Db.init_connection
|
conn <- Db.init_connection
|
||||||
|
|
||||||
Ut.clear_screen
|
Ut.clear_screen
|
||||||
putStrLn "Welcome to Hassword Manager!!!"
|
putStrLn "Welcome to Hassword Manager!!!"
|
||||||
welcome_screen conn
|
|
||||||
|
setup_application conn
|
||||||
mpass <- open_hassword_book conn
|
mpass <- open_hassword_book conn
|
||||||
putStrLn mpass
|
application_loop conn mpass
|
||||||
setClipboard mpass
|
|
||||||
-- application_loop conn
|
|
||||||
|
|
||||||
Db.close_connection conn
|
Db.close_connection conn
|
||||||
|
|
||||||
welcome_screen :: Connection -> IO ()
|
|
||||||
welcome_screen conn = do
|
setup_application :: Connection -> IO ()
|
||||||
|
setup_application conn = do
|
||||||
first <- Db.is_it_first_app_usage conn
|
first <- Db.is_it_first_app_usage conn
|
||||||
if first
|
if first
|
||||||
then do
|
then do
|
||||||
@ -66,8 +68,8 @@ open_hassword_book :: Connection -> IO (String)
|
|||||||
open_hassword_book conn = do
|
open_hassword_book conn = do
|
||||||
putStrLn "Please Enter your MASTER PASSWORD:"
|
putStrLn "Please Enter your MASTER PASSWORD:"
|
||||||
mpass <- Ut.get_password
|
mpass <- Ut.get_password
|
||||||
res <- Db.check_if_mpass_valid conn (Cr.hash' $ fromString mpass)
|
mpass_valid <- Db.check_if_mpass_valid conn (Cr.hash' $ fromString mpass)
|
||||||
if res
|
if mpass_valid
|
||||||
then
|
then
|
||||||
return mpass
|
return mpass
|
||||||
else do
|
else do
|
||||||
@ -76,7 +78,74 @@ open_hassword_book conn = do
|
|||||||
Ut.reset_color
|
Ut.reset_color
|
||||||
open_hassword_book conn
|
open_hassword_book conn
|
||||||
|
|
||||||
application_loop :: Connection -> IO ()
|
get_action_choice :: IO (Ut.ActionChoice)
|
||||||
application_loop conn = do
|
get_action_choice = do
|
||||||
putStrLn "What would you like to do?"
|
putStrLn "\nWhat would you like to do?"
|
||||||
application_loop conn
|
putStrLn "1. List all entries"
|
||||||
|
putStrLn "2. Copy entry password"
|
||||||
|
putStrLn "3. Add a new entry"
|
||||||
|
putStrLn "4. Delete an entry"
|
||||||
|
putStrLn "5. Update an entry"
|
||||||
|
putStrLn "6. Change Master Password"
|
||||||
|
putStrLn "7. Close the application"
|
||||||
|
choice <- getLine
|
||||||
|
case choice of
|
||||||
|
"1" -> return Ut.ListAllEntries
|
||||||
|
"2" -> return Ut.CopyEntryPassword
|
||||||
|
"3" -> return Ut.AddNewEntry
|
||||||
|
"4" -> return Ut.DeleteEntry
|
||||||
|
"5" -> return Ut.UpdateEntry
|
||||||
|
"6" -> return Ut.ChangeMasterPassword
|
||||||
|
"7" -> return Ut.Exit
|
||||||
|
_ -> return Ut.InvalidAction
|
||||||
|
|
||||||
|
application_loop :: Connection -> String -> IO ()
|
||||||
|
application_loop conn mpass = do
|
||||||
|
choice <- get_action_choice
|
||||||
|
case choice of
|
||||||
|
Ut.ListAllEntries -> do
|
||||||
|
list_all_entries conn
|
||||||
|
application_loop conn mpass
|
||||||
|
Ut.CopyEntryPassword -> do
|
||||||
|
return ()
|
||||||
|
application_loop conn mpass
|
||||||
|
Ut.AddNewEntry -> do
|
||||||
|
add_entry conn mpass
|
||||||
|
application_loop conn mpass
|
||||||
|
Ut.DeleteEntry -> do
|
||||||
|
return ()
|
||||||
|
application_loop conn mpass
|
||||||
|
Ut.UpdateEntry -> do
|
||||||
|
return ()
|
||||||
|
application_loop conn mpass
|
||||||
|
Ut.ChangeMasterPassword -> do
|
||||||
|
return ()
|
||||||
|
application_loop conn mpass
|
||||||
|
Ut.InvalidAction -> do
|
||||||
|
putStrLn "Invalid choice!!!"
|
||||||
|
application_loop conn mpass
|
||||||
|
Ut.Exit -> do
|
||||||
|
return ()
|
||||||
|
|
||||||
|
list_all_entries :: Connection -> IO ()
|
||||||
|
list_all_entries conn = do
|
||||||
|
entries <- Db.get_all_entries conn
|
||||||
|
Ui.print_entries entries
|
||||||
|
|
||||||
|
add_entry :: Connection -> String -> IO ()
|
||||||
|
add_entry conn mpass = do
|
||||||
|
putStrLn "Please Enter the service name:"
|
||||||
|
service <- getLine
|
||||||
|
putStrLn "Please Enter the login:"
|
||||||
|
login <- getLine
|
||||||
|
entry_exists <- Db.entry_already_exists conn (T.pack service) (T.pack login)
|
||||||
|
if entry_exists
|
||||||
|
then do
|
||||||
|
Ut.set_red
|
||||||
|
putStrLn "Entry already exists!!!"
|
||||||
|
Ut.reset_color
|
||||||
|
return ()
|
||||||
|
else do
|
||||||
|
putStrLn "Please Enter the password:"
|
||||||
|
password <- Ut.get_password
|
||||||
|
Db.add_entry conn (T.pack service) (T.pack login) (T.pack (toString (Cr.encrypt' (fromString mpass) (fromString password))))
|
||||||
|
@ -27,6 +27,7 @@ dependencies:
|
|||||||
- utf8-string
|
- utf8-string
|
||||||
- ansi-terminal
|
- ansi-terminal
|
||||||
- Hclip
|
- Hclip
|
||||||
|
- cipher-aes
|
||||||
- base >= 4.7 && < 5
|
- base >= 4.7 && < 5
|
||||||
|
|
||||||
ghc-options:
|
ghc-options:
|
||||||
|
@ -1,15 +1,28 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
module Crypto (
|
module Crypto (
|
||||||
-- encode,
|
encrypt',
|
||||||
-- decode,
|
decrypt',
|
||||||
hash'
|
hash'
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
import Data.Hashable
|
import Data.Hashable
|
||||||
|
import Crypto.Cipher.AES
|
||||||
|
|
||||||
pepper :: ByteString
|
pepper :: ByteString
|
||||||
pepper = "pepper"
|
pepper = "pepper"
|
||||||
|
|
||||||
hash' :: ByteString -> Int
|
hash' :: ByteString -> Int
|
||||||
hash' = hashWithSalt 0 . mappend pepper
|
hash' = hashWithSalt 0 . mappend pepper
|
||||||
|
|
||||||
|
encrypt' :: ByteString -> ByteString -> ByteString
|
||||||
|
encrypt' key plain_text = plain_text
|
||||||
|
|
||||||
|
decrypt' :: ByteString -> ByteString -> ByteString
|
||||||
|
decrypt' key cypher_text = cypher_text
|
||||||
|
|
||||||
|
-- encrypt' :: ByteString -> ByteString -> ByteString
|
||||||
|
-- encrypt' = encryptECB . initAES
|
||||||
|
|
||||||
|
-- decrypt' :: ByteString -> ByteString -> ByteString
|
||||||
|
-- decrypt' = decryptECB . initAES
|
||||||
|
@ -1,29 +1,22 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
module Database (
|
module Database where
|
||||||
Entry(..),
|
|
||||||
init_connection,
|
|
||||||
close_connection,
|
|
||||||
check_if_mpass_valid,
|
|
||||||
insert_new_mpass,
|
|
||||||
is_it_first_app_usage
|
|
||||||
) where
|
|
||||||
|
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Database.SQLite.Simple
|
import Database.SQLite.Simple
|
||||||
|
|
||||||
data Entry = Entry { entryId :: Int, entryLogin :: T.Text, entryPassword :: T.Text } deriving (Show)
|
data Entry = Entry { entryId :: Int, entryService :: T.Text, entryLogin :: T.Text, entryPassword :: T.Text } deriving (Show)
|
||||||
data Mpass = Mpass { mpassId :: Int, hash :: Int } deriving (Show)
|
data Mpass = Mpass { mpassId :: Int, hash :: Int } deriving (Show)
|
||||||
|
|
||||||
|
|
||||||
instance FromRow Entry where
|
instance FromRow Entry where
|
||||||
fromRow = Entry <$> field <*> field <*> field
|
fromRow = Entry <$> field <*> field <*> field <*> field
|
||||||
|
|
||||||
instance FromRow Mpass where
|
instance FromRow Mpass where
|
||||||
fromRow = Mpass <$> field <*> field
|
fromRow = Mpass <$> field <*> field
|
||||||
|
|
||||||
instance ToRow Entry where
|
instance ToRow Entry where
|
||||||
toRow (Entry id_ login password) = toRow (id_, login, password)
|
toRow (Entry id_ service login password) = toRow (id_, service, login, password)
|
||||||
|
|
||||||
instance ToRow Mpass where
|
instance ToRow Mpass where
|
||||||
toRow (Mpass id_ hash) = toRow (id_, hash)
|
toRow (Mpass id_ hash) = toRow (id_, hash)
|
||||||
@ -41,9 +34,9 @@ close_connection conn = close conn
|
|||||||
|
|
||||||
create_db :: Connection -> IO ()
|
create_db :: Connection -> IO ()
|
||||||
create_db conn = do
|
create_db conn = do
|
||||||
execute_ conn "CREATE TABLE IF NOT EXISTS hasswords (entryId INTEGER PRIMARY KEY, entryLogin TEXT, entryPassword TEXT)"
|
execute_ conn "CREATE TABLE IF NOT EXISTS entries (entryId INTEGER PRIMARY KEY AUTOINCREMENT, entryService TEXT, entryLogin TEXT, entryPassword TEXT)"
|
||||||
execute_ conn "CREATE TABLE IF NOT EXISTS mpass (mpassId INTEGER PRIMARY KEY, hash INTEGER)"
|
execute_ conn "CREATE TABLE IF NOT EXISTS mpass (mpassId INTEGER PRIMARY KEY AUTOINCREMENT, hash INTEGER)"
|
||||||
-- execute conn "INSERT INTO hassword (entryId, entryLogin, entryPassword) VALUES (?,?,?)" (Entry 1 "admin" "admin")
|
-- execute conn "INSERT INTO entries (entryId, entryLogin, entryPassword) VALUES (?,?,?)" (Entry 1 "admin" "admin")
|
||||||
-- rowId <- lastInsertRowId conn
|
-- rowId <- lastInsertRowId conn
|
||||||
-- r <- query_ conn "SELECT * from hassword" :: IO [Entry]
|
-- r <- query_ conn "SELECT * from hassword" :: IO [Entry]
|
||||||
-- mapM_ print r
|
-- mapM_ print r
|
||||||
@ -56,9 +49,36 @@ is_it_first_app_usage conn = do
|
|||||||
insert_new_mpass :: Connection -> Int -> IO ()
|
insert_new_mpass :: Connection -> Int -> IO ()
|
||||||
insert_new_mpass conn hash = do
|
insert_new_mpass conn hash = do
|
||||||
execute_ conn "DELETE FROM mpass"
|
execute_ conn "DELETE FROM mpass"
|
||||||
execute conn "INSERT INTO mpass (mpassId, hash) VALUES (?,?)" (Mpass 1 hash)
|
execute conn "INSERT INTO mpass (hash) VALUES (?)" (Only hash)
|
||||||
|
|
||||||
check_if_mpass_valid :: Connection -> Int -> IO Bool
|
check_if_mpass_valid :: Connection -> Int -> IO Bool
|
||||||
check_if_mpass_valid conn hash = do
|
check_if_mpass_valid conn hash = do
|
||||||
r <- query conn "SELECT * from mpass WHERE hash = ?" (Only hash) :: IO [Mpass]
|
r <- query conn "SELECT * from mpass WHERE hash = ?" (Only hash) :: IO [Mpass]
|
||||||
return $ length r == 1
|
return $ length r == 1
|
||||||
|
|
||||||
|
add_entry :: Connection -> T.Text -> T.Text -> T.Text -> IO ()
|
||||||
|
add_entry conn service login password = do
|
||||||
|
execute conn "INSERT INTO entries (entryService, entryLogin, entryPassword) VALUES (?,?,?)" (service, login, password)
|
||||||
|
|
||||||
|
update_entry :: Connection -> Int -> T.Text -> IO ()
|
||||||
|
update_entry conn id new_password = do
|
||||||
|
execute conn "UPDATE entries SET entryPassword = ? WHERE entryId = ?" (new_password, id)
|
||||||
|
|
||||||
|
get_entry :: Connection -> Int -> IO (Maybe Entry)
|
||||||
|
get_entry conn id = do
|
||||||
|
r <- query conn "SELECT * from entries WHERE entryId = ?" (Only id) :: IO [Entry]
|
||||||
|
return $ case r of
|
||||||
|
[] -> Nothing
|
||||||
|
[entry] -> Just entry
|
||||||
|
|
||||||
|
get_all_entries :: Connection -> IO [Entry]
|
||||||
|
get_all_entries conn = query_ conn "SELECT * from entries"
|
||||||
|
|
||||||
|
delete_entry :: Connection -> Int -> IO ()
|
||||||
|
delete_entry conn id = do
|
||||||
|
execute conn "DELETE FROM entries WHERE entryId = ?" (Only id)
|
||||||
|
|
||||||
|
entry_already_exists :: Connection -> T.Text -> T.Text -> IO Bool
|
||||||
|
entry_already_exists conn service login = do
|
||||||
|
r <- query conn "SELECT * from entries WHERE entryService = ? AND entryLogin = ?" (service, login) :: IO [Entry]
|
||||||
|
return $ length r == 1
|
||||||
|
@ -1,6 +1,18 @@
|
|||||||
module UserInterface
|
module UserInterface
|
||||||
( someFunc
|
( print_entries
|
||||||
) where
|
) where
|
||||||
|
|
||||||
someFunc :: IO ()
|
import qualified Database as Db
|
||||||
someFunc = putStrLn "someFunc"
|
|
||||||
|
print_entries :: [Db.Entry] -> IO ()
|
||||||
|
print_entries entries = do
|
||||||
|
putStrLn "Entries:"
|
||||||
|
mapM_ print_entry entries
|
||||||
|
|
||||||
|
print_entry :: Db.Entry -> IO ()
|
||||||
|
print_entry entry = do
|
||||||
|
putStrLn $ "ID: " ++ show (Db.entryId entry)
|
||||||
|
putStrLn $ "Service: " ++ show (Db.entryService entry)
|
||||||
|
putStrLn $ "Login: " ++ show (Db.entryLogin entry)
|
||||||
|
putStrLn $ "Password: *****"
|
||||||
|
putStrLn ""
|
||||||
|
@ -6,6 +6,8 @@ import Control.Exception
|
|||||||
|
|
||||||
data MasterPasswordValidationCases = Empty | TooShort | DoNotMatch | NotValid | Valid String deriving (Show)
|
data MasterPasswordValidationCases = Empty | TooShort | DoNotMatch | NotValid | Valid String deriving (Show)
|
||||||
|
|
||||||
|
data ActionChoice = ListAllEntries | CopyEntryPassword | AddNewEntry | DeleteEntry | UpdateEntry | ChangeMasterPassword | Exit | InvalidAction deriving (Show)
|
||||||
|
|
||||||
validate_password :: String -> String -> MasterPasswordValidationCases
|
validate_password :: String -> String -> MasterPasswordValidationCases
|
||||||
validate_password p1 p2
|
validate_password p1 p2
|
||||||
| p1 /= p2 = DoNotMatch
|
| p1 /= p2 = DoNotMatch
|
||||||
|
Loading…
Reference in New Issue
Block a user