Skip to content

Instantly share code, notes, and snippets.

@Naddiseo
Last active December 14, 2015 17:59
Show Gist options
  • Save Naddiseo/5126508 to your computer and use it in GitHub Desktop.
Save Naddiseo/5126508 to your computer and use it in GitHub Desktop.
A script for encrypting part of a file before committing to git. Useful for storing passwords encrypted on places like github, but having the plaintext available locally. Requirements: gpg, perl >=5.14
#!/usr/bin/perl
#A script for encrypting part of a file before committing to git.
#Useful for storing passwords encrypted on places like github, but having the plaintext available locally.
#
#Requirements: gpg, perl >=5.14
#
#Usage:
#- Create a gpg key for encrypting, passwordless.
#- Make sure crypt_pub.pl is executable and in $PATH
#- In your .git/config place:
#[filter "crypt_pub"]
# clean = crypt_pub.pl encrypt <KEY>
# smudge = crypt_pub.pl decrypt <KEY>
#[diff "crypt_pub"]
# command crypt_pub.pl diff <KEY>
#
#- In your source file that needs encrypting, in a comment at the end of the line place
# "$$ ENCRYPT N $$" where "N" is the number of non-whitespace tokens in the line where the password is, for example:
# "PASSWORD" : "THIS IS MY PASSWORD" # $$ ENCRYPT 3 $$
# The above line can be tokenised into 3 tokens: (STRING COLON STRING),
# the "3" indicates that the 3rd token is a string that needs encrypting.
use 5.14.0;
use warnings;
use Data::Dumper;
my $cmd = shift;
my $key_r = shift;
my $op = $cmd eq 'encrypt' ? \&encrypt : ($cmd eq 'decrypt' ? \&decrypt : undef);
if (not defined $op) {
# call diff instead
my $file1 = $ARGV[0];
my $file2 = $ARGV[3];
open my $fh, ">out.txt" or die $!;
print $fh "$file1\n\n$file2";
close $fh;
print STDERR "diff -u \"$file1\" \"$file2\" | cat";
print `diff -u "$file1" "$file2" | cat`;
exit(0);
}
sub encrypt {
my $what = shift;
return `echo "$what" | gpg -ea -q --batch --no-tty -r $key_r`;
}
sub decrypt {
my $what = shift;
return `echo "$what" | gpg -d -q --batch --no-tty`;
}
sub tokenize_line {
my $line = shift;
my @tokens = ();
my $in_string = 0;
my $escape = 0;
my $is_white = 0;
my $q = '';
my $buf = '';
CHAR: for my $c (split //, $line) {
if ($in_string) {
if ($escape) {
$escape = 0;
}
elsif ($c eq '\\') {
$escape = 1;
}
elsif ($c eq $q) {
$in_string = 0;
$buf .= $q;
push @tokens, $buf;
$buf = '';
next CHAR;
}
}
elsif ($is_white) {
if ($c !~ /\s/) {
push @tokens, $buf if length $buf;
$buf = '';
$is_white = 0;
}
}
elsif ($c =~ /\s/) {
push @tokens, $buf if length $buf;
$buf = '';
$is_white = 1;
}
if ($c eq '"' or $c eq "'") {
push @tokens, $buf if length $buf;
$buf = '';
$in_string = 1;
$q = $c;
}
$buf .= $c;
}
push @tokens, $buf if length $buf;
return @tokens
}
LINE: for my $line (<>) {
unless ($line =~ /\$\$\s+ENCRYPT\s+(\d+)\s+\$\$/) {
print $line;
next LINE;
}
my $token_number = int $1;
my @tokens = tokenize_line $line;
my $i = 0;
TOK: for my $tok (@tokens) {
if ($tok !~ /^\s*$/) {
if (++$i == $token_number) {
if ($cmd eq 'decrypt') {
# we want to remove quotes surrounding the text
if ($tok =~ /^(["'])(.*?)\1(.*)$/) {
my ($q, $txt, $post) = ($1, $2, $3);
my $decrypted = $op->($txt);
$decrypted =~ s/\n$//;
print $decrypted;
print $post;
}
else {
print $tok;
}
}
else {
print "'";
$tok =~ s/\n$//gm;
my $encrypted = $op->($tok);
$encrypted =~ s/\n$//;
$encrypted =~ s/\n/\\n/gm;
print $encrypted;
print "'";
}
next TOK;
}
}
print $tok;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment