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.Monad
|
||||
|
||||
import Data.Hashable (hash)
|
||||
import Data.List
|
||||
import Data.Maybe
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.IO as T
|
||||
import Data.Time (Day, addDays)
|
||||
import Data.Word
|
||||
import Numeric
|
||||
import Safe (readMay)
|
||||
import System.Console.CmdArgs
|
||||
import System.Directory (getModificationTime, getDirectoryContents, copyFile)
|
||||
@ -54,6 +51,7 @@ import System.Time (ClockTime(TOD))
|
||||
import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds)
|
||||
|
||||
import Hledger.Cli.CliOptions
|
||||
import Hledger.Cli.Anon
|
||||
import Hledger.Data
|
||||
import Hledger.Read
|
||||
import Hledger.Reports
|
||||
@ -98,27 +96,9 @@ pivotByOpts opts =
|
||||
-- | Apply the anonymisation transformation on a journal, if option is present
|
||||
anonymiseByOpts :: CliOpts -> Journal -> Journal
|
||||
anonymiseByOpts opts =
|
||||
case maybestringopt "anon" . rawopts_ $ opts of
|
||||
Just _ -> anonymise
|
||||
Nothing -> 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
|
||||
if anon_ . inputopts_ $ opts
|
||||
then anon
|
||||
else id
|
||||
|
||||
-- | 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).
|
||||
|
||||
@ -4,7 +4,7 @@ cabal-version: 1.12
|
||||
--
|
||||
-- see: https://github.com/sol/hpack
|
||||
--
|
||||
-- hash: cfbd7109f5527399580a07f847fc8f5d01951caffc3667948b6348f82183be52
|
||||
-- hash: 8f2e354491d77c4334484836a2b1f0f95f6810abf49fffeaebeb19d37132a15a
|
||||
|
||||
name: hledger
|
||||
version: 1.15.99
|
||||
@ -109,6 +109,7 @@ library
|
||||
Hledger.Cli.CliOptions
|
||||
Hledger.Cli.DocFiles
|
||||
Hledger.Cli.Utils
|
||||
Hledger.Cli.Anon
|
||||
Hledger.Cli.Version
|
||||
Hledger.Cli.Commands
|
||||
Hledger.Cli.Commands.Accounts
|
||||
|
||||
@ -155,6 +155,7 @@ library:
|
||||
- Hledger.Cli.CliOptions
|
||||
- Hledger.Cli.DocFiles
|
||||
- Hledger.Cli.Utils
|
||||
- Hledger.Cli.Anon
|
||||
- Hledger.Cli.Version
|
||||
- Hledger.Cli.Commands
|
||||
- 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