-- Copyright (C) 2017 Matthew Harm Bekkema -- -- This file is part of passman-core -- -- passman-core is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- passman-core is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . ----------------------------------------------------------------------------- -- | -- Module : Passman.Core.Config -- Copyright : Matthew Harm Bekkema 2017 -- License : GPL-3 -- Maintainer : mbekkema97@gmail.com ----------------------------------------------------------------------------- {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} module Passman.Core.Config ( -- * Data Structures Config(..) -- * File IO , loadConfig , saveConfig ) where import Control.Exception (throwIO) import Data.Text (Text) import Data.Yaml (encodeFile, decodeFileEither) import Data.Aeson.TH (deriveJSON, defaultOptions) import System.FilePath (()) import System.Directory (XdgDirectory(XdgConfig), getXdgDirectory, createDirectoryIfMissing) import System.PosixCompat.Files (fileMode, getFileStatus, setFileMode, intersectFileModes, ownerModes) -- | The persistent configuration of the password manager. -- -- Intended to be saved to file in YAML format. This example config file: -- -- >masterPasswordHash: "$2y$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy" -- >passlistPath: "/path/to/passlist.txt" -- -- Would be parsed as: -- -- >Config { masterPasswordHash = "$2y$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy" -- > , passlistPath = "/path/to/passlist.txt" -- > } data Config = Config { -- | Hash of the master password generated by -- `Passman.Core.Hash.hashMasterPassword` masterPasswordHash :: Text -- | Path to the passlist file , passlistPath :: FilePath } deriving (Show, Eq) $(deriveJSON defaultOptions ''Config) -- | Load a `Config` from file. loadConfig :: IO Config loadConfig = configFile >>= decodeFileEither >>= either throwIO pure -- | Save the specified `Config` to file, overwriting an existing config file. saveConfig :: Config -> IO () saveConfig config = configFile >>= flip encodeFile config -- | Create the path leading up to the config file with the correct permissions -- and return the config filepath. configFile :: IO FilePath configFile = do fp <- getXdgDirectory XdgConfig "passman" createDirectoryIfMissing False fp correctPermissions fp pure $ fp "config.yaml" -- | Remove all but the owner's permissions on the specified path. correctPermissions :: FilePath -> IO () correctPermissions fp = do currentMode <- fileMode <$> getFileStatus fp let newMode = intersectFileModes currentMode ownerModes setFileMode fp newMode