|
|
(One intermediate revision by one other user not shown) |
Line 5: |
Line 5: |
| The solution is to obfuscate the data in your data file. For the GnuCash xml data files, you can use the script by Adam Buchbinder below for that purpose. | | The solution is to obfuscate the data in your data file. For the GnuCash xml data files, you can use the script by Adam Buchbinder below for that purpose. |
| | | |
− | ; Warning : Only use this script on a copy of your data !
| + | The script has been moved here: https://github.com/Gnucash/gnucash/blob/maint/util/obfuscate.pl |
| | | |
− | <pre>#!/usr/bin/perl
| + | The script will read in the file, process the data, and write the output on "stdout". |
− | | |
− | # gnucash-obfuscate.pl
| |
− | # Adam Buchbinder
| |
− | | |
− | use strict;
| |
− | use warnings;
| |
− | | |
− | use Digest::MD5 qw(md5_hex);
| |
− | use XML::DOM;
| |
− | | |
− | my $dictionary = '/usr/share/dict/american-english';
| |
− | my $hex_digits = 4;
| |
− | | |
− | unless (-f $dictionary) {
| |
− | print STDERR "Default dictionary $dictionary not found.\n";
| |
− | $dictionary = '/usr/share/dict/words';
| |
− | unless (-f $dictionary) {
| |
− | die("Cannot open dictionary $dictionary");
| |
− | }
| |
− | }
| |
− | | |
− | $ARGV[0] || die("Usage: $0 filename");
| |
− | (-f $ARGV[0]) || die("Unable to open $ARGV[0]");
| |
− | (-f $dictionary) || die("Dictionary file $dictionary does not exist");
| |
− | open DICT, $dictionary || die("Unable to open $dictionary");
| |
− | | |
− | my @dict = <DICT>;
| |
− | close DICT;
| |
− | | |
− | sub get_a_name {
| |
− | my $scalar = shift;
| |
− | return '' if !$scalar;
| |
− | my $index = hex substr(md5_hex($scalar),-$hex_digits);
| |
− | my $result = $dict[$index];
| |
− | chop $result;
| |
− | return $result;
| |
− | }
| |
− | | |
− | sub replace_text_element {
| |
− | my $doc = shift;
| |
− | my $tag = shift;
| |
− | my $elements = $doc->getElementsByTagName($tag);
| |
− | | |
− | my $i; my $n = $elements->getLength;
| |
− | for ($i=0; $i<$n; $i++) {
| |
− | my $text = $elements->item($i)->getFirstChild;
| |
− | $text->setData(get_a_name($text->getData));
| |
− | }
| |
− | }
| |
− | | |
− | my $parser = new XML::DOM::Parser;
| |
− | print STDERR "Parsing XML document.\n";
| |
− | my $doc = $parser->parsefile($ARGV[0]);
| |
− | | |
− | # first, clean up strings in account names and transaction names
| |
− | print STDERR "Obfuscating account names.\n";
| |
− | replace_text_element($doc,'act:name');
| |
− | print STDERR "Obfuscating account descriptions.\n";
| |
− | replace_text_element($doc,'act:description');
| |
− | print STDERR "Obfuscating transaction descriptions.\n";
| |
− | replace_text_element($doc,'trn:description');
| |
− | print STDERR "Obfuscating check numbers.\n";
| |
− | replace_text_element($doc,'trn:num');
| |
− | print STDERR "Obfuscating split memos.\n";
| |
− | replace_text_element($doc,'split:memo');
| |
− | print STDERR "Obfuscating transaction notes.\n";
| |
− | my $transactions = $doc->getElementsByTagName('trn:slots');
| |
− | for (my $i=0; $i<$transactions->getLength; $i++) {
| |
− | replace_text_element($transactions->item($i),'slot:value');
| |
− | }
| |
− | | |
− | sub get_child_value {
| |
− | my $parent = shift;
| |
− | my $childname = shift;
| |
− | my $index = shift;
| |
− |
| |
− | my $return;
| |
− | my $elements = $parent->getElementsByTagName($childname);
| |
− | my $child;
| |
− | | |
− | unless (defined($index)) {
| |
− | $child = $elements->item(0)->getFirstChild;
| |
− | } else {
| |
− | $child = $elements->item($index)->getFirstChild;
| |
− | }
| |
− | $return = $child->getData;
| |
− | return $return;
| |
− | }
| |
− | | |
− | sub set_child_value {
| |
− | my $parent = shift;
| |
− | my $childname = shift;
| |
− | my $value = shift;
| |
− |
| |
− | my $return;
| |
− | my $elements = $parent->getElementsByTagName($childname);
| |
− | my $child;
| |
− | | |
− | $child = $elements->item(0)->getFirstChild;
| |
− | | |
− | $return = $child->setData($value);
| |
− | return $return;
| |
− | }
| |
− | | |
− | # replace transaction values
| |
− | print STDERR "Obfuscating money amounts.\n";
| |
− | my $elements = $doc->getElementsByTagName('trn:splits');
| |
− | my $i; my $n = $elements->getLength;
| |
− | for ($i=0; $i<$n; $i++) {
| |
− | my $parent = $elements->item($i);
| |
− | my $splits = $parent->getElementsByTagName('trn:split');
| |
− | my $count = $splits->getLength;
| |
− | | |
− | foreach my $j (0..$count-1) {
| |
− | my $split = $splits->item($j);
| |
− | my $valuestring;
| |
− | my $sum = 0;
| |
− | my ($num,$denom);
| |
− | if (get_child_value($split,'split:value') eq
| |
− | get_child_value($split,'split:quantity')) {
| |
− | $valuestring = get_child_value($split,'split:value');
| |
− | ($num,$denom) = $valuestring =~ /(\-?\d+)\/(\d+)/;
| |
− | $num = int rand 10*$denom; $sum += $num;
| |
− | set_child_value($split,'split:value',"$num/$denom");
| |
− | set_child_value($split,'split:quantity',"$num/$denom");
| |
− | } else {
| |
− | $valuestring = get_child_value($split,'split:value');
| |
− | ($num,$denom) = $valuestring =~ /(\-?\d+)\/(\d+)/;
| |
− | $num = int rand 10*$denom; $sum = $num;
| |
− | set_child_value($split,'split:value',"$num/$denom");
| |
− | | |
− | $valuestring = get_child_value($split,'split:quantity');
| |
− | ($num,$denom) = $valuestring =~ /(\-?\d+)\/(\d+)/;
| |
− | $num = int rand 10*$denom;
| |
− | set_child_value($split,'split:quantity',"$num/$denom");
| |
− | }
| |
− | # if we're on the last split, balance split:value's to 0
| |
− | if ($j == $count-1) {
| |
− | $valuestring = get_child_value($split,'split:value');
| |
− | ($num,$denom) = $valuestring =~ /(\d+)\/(\d+)/;
| |
− | $num = $sum;
| |
− | set_child_value($split,'split:value',"$num/$denom");
| |
− | }
| |
− | }
| |
− | }
| |
− | | |
− | print STDERR "Writing output.\n";
| |
− | print $doc->toString;
| |
− | | |
− | $doc->dispose;
| |
− | </pre>
| |