|
|
(2 intermediate revisions by one other user not shown) |
Line 1: |
Line 1: |
− | Sometimes users hit a bug in GnuCash that a developer can't reproduce. This bug may be triggered <span class="plainlinks">[http://www.thepiggybackrider.com/ <span style="color:black;font-weight:normal; text-decoration:none!important; background:none!important; text-decoration:none;/*CITATION*/">child carrier</span>]</span> by something in the user's data file, but if the developer doesn't have access to the user's data file it can be very hard to figure out what the problem is exactly. | + | Sometimes users hit a bug in GnuCash that a developer can't reproduce. This bug may be triggered by something in the user's data file, but if the developer doesn't have access to the user's data file it can be very hard to figure out what the problem is exactly. |
| | | |
| Of course, a user's data file contains private information that he probably likes to keep private. | | Of course, a user's data file contains private information that he probably likes to keep private. |
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>
| |
Sometimes users hit a bug in GnuCash that a developer can't reproduce. This bug may be triggered by something in the user's data file, but if the developer doesn't have access to the user's data file it can be very hard to figure out what the problem is exactly.
Of course, a user's data file contains private information that he probably likes to keep private.
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 script will read in the file, process the data, and write the output on "stdout".