parent
5287fe671b
commit
0a273561f7
52
hledger/Hledger/Cli/Anon.hs
Normal file
52
hledger/Hledger/Cli/Anon.hs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
{-|
|
||||||
|
|
||||||
|
Instances for anonymizing sensitive data in various types.
|
||||||
|
|
||||||
|
Note that there is no clear way to anonymize numbers.
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
module Hledger.Cli.Anon
|
||||||
|
( Anon(..)
|
||||||
|
, anonAccount
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
|
import Control.Arrow (first)
|
||||||
|
import Data.Hashable (hash)
|
||||||
|
import Data.Word (Word32)
|
||||||
|
import Numeric (showHex)
|
||||||
|
import qualified Data.Text as T
|
||||||
|
|
||||||
|
import Hledger.Data
|
||||||
|
|
||||||
|
class Anon a where
|
||||||
|
-- | Consistent converter to structure with sensitive data anonymized
|
||||||
|
anon :: a -> a
|
||||||
|
|
||||||
|
instance Anon Journal where
|
||||||
|
-- Apply the anonymisation transformation on a journal after finalisation
|
||||||
|
anon j = j { jtxns = map anon . jtxns $ j
|
||||||
|
, jparseparentaccounts = map anonAccount $ jparseparentaccounts j
|
||||||
|
, jparsealiases = [] -- already applied
|
||||||
|
, jdeclaredaccounts = map (first anon) $ jdeclaredaccounts j
|
||||||
|
}
|
||||||
|
|
||||||
|
instance Anon Posting where
|
||||||
|
anon p = p { paccount = anonAccount . paccount $ p
|
||||||
|
, pcomment = T.empty
|
||||||
|
, ptransaction = fmap anon . ptransaction $ p -- Note that this will be overriden
|
||||||
|
, poriginal = anon <$> poriginal p
|
||||||
|
}
|
||||||
|
|
||||||
|
instance Anon Transaction where
|
||||||
|
anon txn = txnTieKnot $ txn { tpostings = map anon . tpostings $ txn
|
||||||
|
, tdescription = anon . tdescription $ txn
|
||||||
|
, tcomment = T.empty
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | Anonymize account name preserving hierarchy
|
||||||
|
anonAccount :: AccountName -> AccountName
|
||||||
|
anonAccount = T.intercalate (T.pack ":") . map anon . T.splitOn (T.pack ":")
|
||||||
|
|
||||||
|
instance Anon T.Text where anon = T.pack . flip showHex "" . (fromIntegral :: Int -> Word32) . hash
|
||||||
@ -31,14 +31,11 @@ where
|
|||||||
import Control.Exception as C
|
import Control.Exception as C
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
|
|
||||||
import Data.Hashable (hash)
|
|
||||||
import Data.List
|
import Data.List
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.IO as T
|
import qualified Data.Text.IO as T
|
||||||
import Data.Time (Day, addDays)
|
import Data.Time (Day, addDays)
|
||||||
import Data.Word
|
|
||||||
import Numeric
|
|
||||||
import Safe (readMay)
|
import Safe (readMay)
|
||||||
import System.Console.CmdArgs
|
import System.Console.CmdArgs
|
||||||
import System.Directory (getModificationTime, getDirectoryContents, copyFile)
|
import System.Directory (getModificationTime, getDirectoryContents, copyFile)
|
||||||
@ -54,6 +51,7 @@ import System.Time (ClockTime(TOD))
|
|||||||
import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds)
|
import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds)
|
||||||
|
|
||||||
import Hledger.Cli.CliOptions
|
import Hledger.Cli.CliOptions
|
||||||
|
import Hledger.Cli.Anon
|
||||||
import Hledger.Data
|
import Hledger.Data
|
||||||
import Hledger.Read
|
import Hledger.Read
|
||||||
import Hledger.Reports
|
import Hledger.Reports
|
||||||
@ -98,27 +96,9 @@ pivotByOpts opts =
|
|||||||
-- | Apply the anonymisation transformation on a journal, if option is present
|
-- | Apply the anonymisation transformation on a journal, if option is present
|
||||||
anonymiseByOpts :: CliOpts -> Journal -> Journal
|
anonymiseByOpts :: CliOpts -> Journal -> Journal
|
||||||
anonymiseByOpts opts =
|
anonymiseByOpts opts =
|
||||||
case maybestringopt "anon" . rawopts_ $ opts of
|
if anon_ . inputopts_ $ opts
|
||||||
Just _ -> anonymise
|
then anon
|
||||||
Nothing -> id
|
else id
|
||||||
|
|
||||||
-- | Apply the anonymisation transformation on a journal
|
|
||||||
anonymise :: Journal -> Journal
|
|
||||||
anonymise j
|
|
||||||
= let
|
|
||||||
pAnons p = p { paccount = T.intercalate (T.pack ":") . map anon . T.splitOn (T.pack ":") . paccount $ p
|
|
||||||
, pcomment = T.empty
|
|
||||||
, ptransaction = fmap tAnons . ptransaction $ p
|
|
||||||
, poriginal = pAnons <$> poriginal p
|
|
||||||
}
|
|
||||||
tAnons txn = txn { tpostings = map pAnons . tpostings $ txn
|
|
||||||
, tdescription = anon . tdescription $ txn
|
|
||||||
, tcomment = T.empty
|
|
||||||
}
|
|
||||||
in
|
|
||||||
j { jtxns = map tAnons . jtxns $ j }
|
|
||||||
where
|
|
||||||
anon = T.pack . flip showHex "" . (fromIntegral :: Int -> Word32) . hash
|
|
||||||
|
|
||||||
-- | Generate periodic transactions from all periodic transaction rules in the journal.
|
-- | Generate periodic transactions from all periodic transaction rules in the journal.
|
||||||
-- These transactions are added to the in-memory Journal (but not the on-disk file).
|
-- These transactions are added to the in-memory Journal (but not the on-disk file).
|
||||||
|
|||||||
@ -4,7 +4,7 @@ cabal-version: 1.12
|
|||||||
--
|
--
|
||||||
-- see: https://github.com/sol/hpack
|
-- see: https://github.com/sol/hpack
|
||||||
--
|
--
|
||||||
-- hash: cfbd7109f5527399580a07f847fc8f5d01951caffc3667948b6348f82183be52
|
-- hash: 8f2e354491d77c4334484836a2b1f0f95f6810abf49fffeaebeb19d37132a15a
|
||||||
|
|
||||||
name: hledger
|
name: hledger
|
||||||
version: 1.15.99
|
version: 1.15.99
|
||||||
@ -109,6 +109,7 @@ library
|
|||||||
Hledger.Cli.CliOptions
|
Hledger.Cli.CliOptions
|
||||||
Hledger.Cli.DocFiles
|
Hledger.Cli.DocFiles
|
||||||
Hledger.Cli.Utils
|
Hledger.Cli.Utils
|
||||||
|
Hledger.Cli.Anon
|
||||||
Hledger.Cli.Version
|
Hledger.Cli.Version
|
||||||
Hledger.Cli.Commands
|
Hledger.Cli.Commands
|
||||||
Hledger.Cli.Commands.Accounts
|
Hledger.Cli.Commands.Accounts
|
||||||
|
|||||||
@ -155,6 +155,7 @@ library:
|
|||||||
- Hledger.Cli.CliOptions
|
- Hledger.Cli.CliOptions
|
||||||
- Hledger.Cli.DocFiles
|
- Hledger.Cli.DocFiles
|
||||||
- Hledger.Cli.Utils
|
- Hledger.Cli.Utils
|
||||||
|
- Hledger.Cli.Anon
|
||||||
- Hledger.Cli.Version
|
- Hledger.Cli.Version
|
||||||
- Hledger.Cli.Commands
|
- Hledger.Cli.Commands
|
||||||
- Hledger.Cli.Commands.Accounts
|
- Hledger.Cli.Commands.Accounts
|
||||||
|
|||||||
35
tests/journal/anon.test
Normal file
35
tests/journal/anon.test
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
# Input for the following tests:
|
||||||
|
|
||||||
|
account assets
|
||||||
|
account expenses
|
||||||
|
alias tips=expenses:tips
|
||||||
|
|
||||||
|
2019-01-01 (receipt) ; signed
|
||||||
|
(assets) 2
|
||||||
|
|
||||||
|
2019-02-01 borrow
|
||||||
|
(liabilities) 1
|
||||||
|
(tips) 3
|
||||||
|
|
||||||
|
# Basic tests on accounts
|
||||||
|
|
||||||
|
$ hledger -f- print --anon
|
||||||
|
> !/assets|liabilities|expenses|tips/
|
||||||
|
|
||||||
|
$ hledger -f- reg --anon
|
||||||
|
> !/assets|liabilities|expenses|tips/
|
||||||
|
|
||||||
|
$ hledger -f- bal --anon
|
||||||
|
> !/assets|liabilities|expenses|tips/
|
||||||
|
|
||||||
|
$ hledger -f- accounts --anon
|
||||||
|
> !/assets|liabilities|expenses|tips/
|
||||||
|
|
||||||
|
# Basic tests on descriptions and comments
|
||||||
|
|
||||||
|
$ hledger -f- print --anon
|
||||||
|
> !/borrow|signed/
|
||||||
|
|
||||||
|
$ hledger -f- reg --anon
|
||||||
|
> !/borrow/
|
||||||
Loading…
Reference in New Issue
Block a user