lenc 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.txt +9 -0
- data/README.txt +6 -2
- data/lib/lenc/aes.rb +0 -4
- data/lib/lenc/lencrypt.rb +17 -20
- data/lib/lenc/repo.rb +55 -41
- data/lib/lenc/tools.rb +5 -2
- data/test/test.rb +2 -14
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f09c6e3e0d5b6ce0ebb95fe5a2b7f24a672601d
|
4
|
+
data.tar.gz: a5e5dd2ac1ea3c34f2a96fb5568381d4a1368803
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a54fe2806c2703d53770abfcf3eedfd66ef0c7d714683de2e15644c6053ead25a83da08ea272a84c059de5208bccd65161aa0618e68e605326e5fe449992b389
|
7
|
+
data.tar.gz: eb0aec9260ed9fd7d5f771cc11cb48845746dc58ec9d68399d2912f1e428fdef1a8e2c94e1a80c50a6285237891083114127a103951867e568a682eeda13611e
|
data/CHANGELOG.txt
CHANGED
@@ -2,6 +2,15 @@
|
|
2
2
|
* Version 1.0.0 released
|
3
3
|
|
4
4
|
2013-03-22
|
5
|
+
* 1.1.0 released
|
5
6
|
* For added safety, unless the --storekey option is given when the repository is
|
6
7
|
initialized, the key is no longer stored in repository configuration file, and
|
7
8
|
the user is prompted at every update to enter the password.
|
9
|
+
|
10
|
+
2013-04-08
|
11
|
+
* 1.1.1 released
|
12
|
+
* Fixed problem with README that was omitting a word
|
13
|
+
* Now allows passwords as short as 8 characters, to agree with documentation
|
14
|
+
* Now omitting symlink'd files (it used to fail upon encountering these)
|
15
|
+
* Added ability to provide update password as command line argument (i.e. lencrypt <pwd>)
|
16
|
+
|
data/README.txt
CHANGED
@@ -33,7 +33,7 @@ Running the program
|
|
33
33
|
|
34
34
|
The program can be asked to perform one of the following tasks:
|
35
35
|
|
36
|
-
1) Setting up a repository. Select a directory you wish to be the
|
36
|
+
1) Setting up a repository. Select a directory you wish to be the \<source\>
|
37
37
|
directory, and make it the current directory. Type:
|
38
38
|
|
39
39
|
lencrypt -i KEY ENCDIR
|
@@ -50,7 +50,8 @@ it cannot lie within the current directory's tree).
|
|
50
50
|
You will be prompted for the encryption key, and then the program will examine
|
51
51
|
which files within the \<source\> directory have been changed (since the repository
|
52
52
|
was created or last updated), and re-encrypt these into the \<encrypted\> directory.
|
53
|
-
|
53
|
+
|
54
|
+
|
54
55
|
3) Recovering encrypted files. Type:
|
55
56
|
|
56
57
|
lencrypt -r KEY ENCDIR RECDIR
|
@@ -97,4 +98,7 @@ The format of ignore files is similar to that of .gitignore files. Details:
|
|
97
98
|
* If the pattern contains any path separators, then the wildcards '*', '?' will not
|
98
99
|
match the path separator.
|
99
100
|
|
101
|
+
Miscellaneous Issues
|
102
|
+
-------
|
103
|
+
At present, the program will ignore any files (or directories) that are symbolic links.
|
100
104
|
|
data/lib/lenc/aes.rb
CHANGED
data/lib/lenc/lencrypt.rb
CHANGED
@@ -13,7 +13,8 @@ class LEncApp
|
|
13
13
|
opt :orignames, "(with --init) leave filenames unencrypted"
|
14
14
|
opt :storekey, "(with --init) store the key within the repository configuration file so it" \
|
15
15
|
" need not be entered with every update"
|
16
|
-
opt :update, "update encrypted repository (default operation)"
|
16
|
+
opt :update, "update encrypted repository (default operation): KEY", :default => ""
|
17
|
+
#opt :updatepwd, "specify key for update: KEY", :type => :string
|
17
18
|
opt :recover, "recover files from an encrypted repository: KEY ENCDIR RECDIR", :type => :strings
|
18
19
|
opt :where, "specify source directory (default = current directory)", :type => :string
|
19
20
|
opt :verbose,"verbose operation"
|
@@ -25,16 +26,25 @@ class LEncApp
|
|
25
26
|
p.parse argv
|
26
27
|
end
|
27
28
|
|
29
|
+
# Not sure how to determine if there were leftover arguments;
|
30
|
+
# trollop seems to include path information ('.')
|
31
|
+
#p.die("Unrecognized argument: #{p.leftovers[0]}",nil) if p.leftovers.size
|
32
|
+
|
28
33
|
v = 0
|
29
34
|
v = -1 if options[:quiet]
|
30
35
|
v = 1 if options[:verbose]
|
31
36
|
|
37
|
+
update_pwd = options[:update]
|
38
|
+
update_pwd = nil if update_pwd.size == 0
|
39
|
+
|
32
40
|
nOpt = 0
|
33
41
|
nOpt += 1 if options[:init]
|
34
|
-
nOpt += 1 if
|
42
|
+
nOpt += 1 if update_pwd
|
35
43
|
nOpt += 1 if options[:recover]
|
36
|
-
|
37
|
-
|
44
|
+
|
45
|
+
#pr("trollop opts = %s\n",d2(options))
|
46
|
+
|
47
|
+
p.die("Only one operation can be performed at a time.",nil) if nOpt > 1
|
38
48
|
|
39
49
|
r = Repo.new(:dryrun => options[:dryrun],
|
40
50
|
:verbosity => v)
|
@@ -42,14 +52,14 @@ class LEncApp
|
|
42
52
|
begin
|
43
53
|
|
44
54
|
if (a = options[:init])
|
45
|
-
|
55
|
+
p.die("Expecting: KEY ENCDIR",nil) if a.size != 2
|
46
56
|
pwd,encDir = a
|
47
57
|
r.create(options[:where], pwd, encDir, options[:orignames], options[:storekey])
|
48
58
|
elsif (a = options[:recover])
|
49
|
-
Trollop::die("Expecting: KEY ENCDIR RECDIR") if a.size != 3
|
59
|
+
p.Trollop::die("Expecting: KEY ENCDIR RECDIR",nil) if a.size != 3
|
50
60
|
r.perform_recovery(a[0],a[1],a[2])
|
51
61
|
else
|
52
|
-
r.open(options[:where])
|
62
|
+
r.open(options[:where],update_pwd)
|
53
63
|
r.perform_update(options[:verifyenc])
|
54
64
|
end
|
55
65
|
|
@@ -64,19 +74,6 @@ end
|
|
64
74
|
if __FILE__ == $0
|
65
75
|
args = ARGV
|
66
76
|
|
67
|
-
# if true && Dir.home.end_with?("/jeff")
|
68
|
-
# warn("trying special")
|
69
|
-
# bs = File.join(Dir.home,"Desktop/_testdirs_")
|
70
|
-
#
|
71
|
-
# if !File.file? "#{bs}/src/.lenc"
|
72
|
-
# s = "-w #{bs}/src -i onefishtwofishredfishbluefish #{bs}/encr"
|
73
|
-
# else
|
74
|
-
# s = "-w #{bs}/src"
|
75
|
-
# end
|
76
|
-
## s = "-h"
|
77
|
-
# args = s.split
|
78
|
-
# # args = "-h".split
|
79
|
-
# end
|
80
77
|
|
81
78
|
LEncApp.new().run(args)
|
82
79
|
end
|
data/lib/lenc/repo.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'base64'
|
2
2
|
require 'pathname'
|
3
3
|
require 'fileutils'
|
4
|
+
require 'tempfile'
|
4
5
|
|
5
6
|
require_relative 'tools'
|
6
7
|
req('aes config_file')
|
@@ -28,6 +29,9 @@ end
|
|
28
29
|
|
29
30
|
module LEnc
|
30
31
|
|
32
|
+
class DecryptionError < Exception
|
33
|
+
end
|
34
|
+
|
31
35
|
class RepoNotFoundException < Exception
|
32
36
|
end
|
33
37
|
|
@@ -66,16 +70,14 @@ module LEnc
|
|
66
70
|
|
67
71
|
if windows?
|
68
72
|
IGNOREFILENAME = "__lencignore__.txt"
|
69
|
-
TEMPFILENAME = "__tmp_file__.bin"
|
70
73
|
else
|
71
74
|
IGNOREFILENAME = ".lencignore"
|
72
|
-
TEMPFILENAME = ".lenc__temp__file"
|
73
75
|
end
|
74
76
|
|
75
77
|
|
76
78
|
DEFAULTIGNORE = \
|
77
|
-
"#{LENC_REPO_FILENAME}\n
|
78
|
-
|
79
|
+
"#{LENC_REPO_FILENAME}\n " \
|
80
|
+
".DS_Store\n" + \
|
79
81
|
".recoverdefaults\n"
|
80
82
|
|
81
83
|
STATE_CLOSED = 0
|
@@ -115,7 +117,7 @@ module LEnc
|
|
115
117
|
# Create a new encryption repository, and open it.
|
116
118
|
#
|
117
119
|
# @param repo_dir directory of new repository (nil for current directory)
|
118
|
-
# @param key encryption key, a string from
|
120
|
+
# @param key encryption key, a string from 8 to 56 characters in length
|
119
121
|
# @param enc_dir directory to store encrypted files; must not yet exist, and must
|
120
122
|
# not represent a directory lying within the repo_dir tree
|
121
123
|
# @param original_names if true, the filenames are not encrypted, only the file contents
|
@@ -161,7 +163,7 @@ module LEnc
|
|
161
163
|
" is a subdirectory of " + pp[1]
|
162
164
|
end
|
163
165
|
|
164
|
-
if (key.size <
|
166
|
+
if (key.size < 8 || key.size > 56)
|
165
167
|
raise ArgumentError, "Password length " + key.size.to_s \
|
166
168
|
+ " is illegal"
|
167
169
|
end
|
@@ -272,7 +274,6 @@ module LEnc
|
|
272
274
|
|
273
275
|
raise IllegalStateException if @state != STATE_OPEN
|
274
276
|
|
275
|
-
removeTempFile()
|
276
277
|
reset_state()
|
277
278
|
end
|
278
279
|
|
@@ -363,13 +364,6 @@ module LEnc
|
|
363
364
|
nil
|
364
365
|
end
|
365
366
|
|
366
|
-
def renameTempFile(newFilename)
|
367
|
-
if !File.exists?(TEMPFILENAME)
|
368
|
-
raise IOError, "Temporary file missing or of wrong type"
|
369
|
-
end
|
370
|
-
|
371
|
-
File.rename(TEMPFILENAME, newFilename)
|
372
|
-
end
|
373
367
|
|
374
368
|
# Starting in a particular directory, attempt to find the nearest
|
375
369
|
# parent repository.
|
@@ -451,7 +445,6 @@ module LEnc
|
|
451
445
|
# [...] => [...]
|
452
446
|
# [!..] => [^...]
|
453
447
|
|
454
|
-
|
455
448
|
pat = ''
|
456
449
|
|
457
450
|
inBrace = false
|
@@ -557,12 +550,6 @@ module LEnc
|
|
557
550
|
@ignoreStack.pop()
|
558
551
|
end
|
559
552
|
|
560
|
-
def removeTempFile()
|
561
|
-
if not @dryrun and File.file?(TEMPFILENAME)
|
562
|
-
remove_file_or_dir(TEMPFILENAME)
|
563
|
-
end
|
564
|
-
end
|
565
|
-
|
566
553
|
# Determine the secondary key, which is used for the filenames (not their contents)
|
567
554
|
# This is found by encrypting the primary key.
|
568
555
|
def prepareKeys()
|
@@ -642,8 +629,7 @@ module LEnc
|
|
642
629
|
!db || hex_dump(s,"after cvt to string (#{s})")
|
643
630
|
|
644
631
|
rescue ArgumentError => e
|
645
|
-
|
646
|
-
raise DecryptionError(e)
|
632
|
+
raise DecryptionError.new(e)
|
647
633
|
end
|
648
634
|
|
649
635
|
set_recovery_pwd_verified()
|
@@ -688,7 +674,7 @@ module LEnc
|
|
688
674
|
|
689
675
|
|
690
676
|
# Update a single source file if necessary (not a directory)
|
691
|
-
def
|
677
|
+
def encrypt_file(sourceFile, encryptFile)
|
692
678
|
|
693
679
|
# If encrypted file is a directory, delete it
|
694
680
|
if File.directory?(encryptFile)
|
@@ -716,19 +702,25 @@ module LEnc
|
|
716
702
|
pr("%s", srcDisp)
|
717
703
|
end
|
718
704
|
|
719
|
-
convertFile(sourceFile,
|
705
|
+
encPath = convertFile(sourceFile, true, showProgress, false)
|
706
|
+
FileUtils.mv(encPath, encryptFile)
|
707
|
+
|
720
708
|
|
721
709
|
if @verifyEncryption
|
722
710
|
# Verify that the original and decoded files are identical
|
723
|
-
convertFile(encryptFile,
|
724
|
-
|
711
|
+
decoded_file = convertFile(encryptFile, false, showProgress, true)
|
712
|
+
files_match = FileUtils.compare_file(sourceFile, decoded_file.path)
|
713
|
+
decoded_file.unlink
|
714
|
+
|
715
|
+
if !files_match
|
716
|
+
delete_file_or_dir(encryptFile)
|
725
717
|
raise EncryptionVerificationException, \
|
726
718
|
"File '#{srcDisp}' did not encrypt/decrypt correctly"
|
719
|
+
|
727
720
|
end
|
728
721
|
if @verbosity >= 0
|
729
722
|
pr(" (file #{srcDisp} encrypted correctly)\n")
|
730
723
|
end
|
731
|
-
removeTempFile()
|
732
724
|
end
|
733
725
|
end
|
734
726
|
end
|
@@ -736,13 +728,16 @@ module LEnc
|
|
736
728
|
# Determine if a file matches one of the expressions in the ignore stack.
|
737
729
|
# Searches the stack from top to bottom (i.e., the outermost elements are examined last)
|
738
730
|
def shouldFileBeIgnored(f)
|
731
|
+
db = false
|
732
|
+
!db || pr("shouldFileBeIgnored? #{f}\n")
|
739
733
|
f2 = f
|
740
734
|
@ignoreStack.reverse.each do |dir,ients|
|
741
735
|
ients.each do |ient|
|
742
736
|
fArg = ient.pathMode ? f2 : f
|
743
737
|
|
744
738
|
matches = ient.rexp.match(fArg)
|
745
|
-
|
739
|
+
!db || pr(" ent path=#{ient.pathMode} rexp=#{ient.rexp} neg=#{ient.negated} matches=#{matches}\n")
|
740
|
+
|
746
741
|
if matches
|
747
742
|
return !ient.negated
|
748
743
|
end
|
@@ -810,10 +805,18 @@ module LEnc
|
|
810
805
|
# Convert string to ASCII-8BIT encoding.
|
811
806
|
f = to_ascii8(f2)
|
812
807
|
|
808
|
+
!db || pr(" testing if file should be ignored: #{f}\n")
|
813
809
|
ignore = shouldFileBeIgnored(f)
|
814
810
|
|
815
811
|
filePath = File.join(sourceDir,f)
|
816
812
|
|
813
|
+
if File.symlink?(filePath)
|
814
|
+
if @verbosity >= 0
|
815
|
+
pr("Omitting symlink file '#{rel_path(filePath,@inputDir)}'\n")
|
816
|
+
end
|
817
|
+
next
|
818
|
+
end
|
819
|
+
|
817
820
|
if ignore
|
818
821
|
!db || pr("(ignoring %s)\n", rel_path(filePath, @inputDir)) if @verbosity >= 1
|
819
822
|
next
|
@@ -821,8 +824,7 @@ module LEnc
|
|
821
824
|
|
822
825
|
if f.start_with?(ENCRFILENAMEPREFIX)
|
823
826
|
if @verbosity >= 0
|
824
|
-
|
825
|
-
pr("(%s)\n", f)
|
827
|
+
pr("(Omitting source file / dir with name that looks encrypted: #{d(f)})\n")
|
826
828
|
end
|
827
829
|
end
|
828
830
|
|
@@ -848,7 +850,8 @@ module LEnc
|
|
848
850
|
if File.directory?(filePath)
|
849
851
|
encryptDir(filePath, encrPath)
|
850
852
|
else
|
851
|
-
|
853
|
+
!db || pr("...attempting to encrypt file #{filePath} to #{encrPath}...\n")
|
854
|
+
encrypt_file(filePath, encrPath)
|
852
855
|
end
|
853
856
|
end
|
854
857
|
|
@@ -859,6 +862,7 @@ module LEnc
|
|
859
862
|
|
860
863
|
# (if doing dry run, encrypt dir may not exist)
|
861
864
|
|
865
|
+
!db || pr("examining files in encrypted dir #{encryptDir} to delete ones that don't belong\n")
|
862
866
|
if File.directory?(encryptDir)
|
863
867
|
dire = dir_entries(encryptDir)
|
864
868
|
else
|
@@ -872,10 +876,10 @@ module LEnc
|
|
872
876
|
begin
|
873
877
|
orphanOrigName = decryptFilename(f)
|
874
878
|
next if !orphanOrigName
|
875
|
-
orphanPath =
|
879
|
+
orphanPath = File.join(encryptDir, f)
|
876
880
|
if @verbosity >= 1
|
877
881
|
printf("Removing encrypted version of missing (or ignored) file " \
|
878
|
-
+ rel_path(
|
882
|
+
+ rel_path(File.join(sourceDir, orphanOrigName), @inputDir) + ": " + orphanPath)
|
879
883
|
end
|
880
884
|
if !@dryrun
|
881
885
|
remove_file_or_dir(orphanPath)
|
@@ -962,14 +966,19 @@ module LEnc
|
|
962
966
|
pr("%s", pth)
|
963
967
|
end
|
964
968
|
begin
|
965
|
-
convertFile(encrFullPath,
|
969
|
+
tmp_file = convertFile(encrFullPath,false, showProgress)
|
970
|
+
|
966
971
|
set_recovery_pwd_verified()
|
972
|
+
|
967
973
|
if not @dryrun
|
968
974
|
if File.file?(origPath)
|
969
975
|
remove_file_or_dir(origPath)
|
970
976
|
end
|
971
|
-
|
977
|
+
FileUtils.mv(tmp_file.path, origPath)
|
978
|
+
else
|
979
|
+
tmp_file.unlink
|
972
980
|
end
|
981
|
+
|
973
982
|
rescue DecryptionError => e
|
974
983
|
|
975
984
|
if !@recovery_pwd_verified
|
@@ -986,18 +995,23 @@ module LEnc
|
|
986
995
|
end
|
987
996
|
|
988
997
|
# Encrypt or decrypt a file (not a directory)
|
989
|
-
|
998
|
+
# @param srcPath source path
|
999
|
+
# @param encrypt true if encrypting
|
1000
|
+
# @return temporary file containing modified file
|
1001
|
+
#
|
1002
|
+
def convertFile(srcPath,encrypt, showProgress=false, verifying=false)
|
990
1003
|
|
991
1004
|
db = warndb 0
|
992
|
-
!db||pr("\n\n\n\nconvertFile\n %s
|
1005
|
+
!db||pr("\n\n\n\nconvertFile\n %s\n",d(srcPath))
|
993
1006
|
|
1007
|
+
fw = nil
|
994
1008
|
showDots = false
|
995
1009
|
if not @dryrun
|
996
1010
|
|
997
1011
|
fSize = File.size(srcPath)
|
998
1012
|
|
999
1013
|
fr = File.open(srcPath, 'rb')
|
1000
|
-
fw =
|
1014
|
+
fw = Tempfile.new("repo")
|
1001
1015
|
|
1002
1016
|
cSize = 100000
|
1003
1017
|
|
@@ -1054,8 +1068,6 @@ module LEnc
|
|
1054
1068
|
fr.close()
|
1055
1069
|
fw.close()
|
1056
1070
|
|
1057
|
-
renameTempFile(destPath)
|
1058
|
-
|
1059
1071
|
pr("]") if showDots
|
1060
1072
|
|
1061
1073
|
end
|
@@ -1063,6 +1075,8 @@ module LEnc
|
|
1063
1075
|
if showProgress and (showDots or not verifying)
|
1064
1076
|
pr("\n")
|
1065
1077
|
end
|
1078
|
+
|
1079
|
+
fw
|
1066
1080
|
end
|
1067
1081
|
|
1068
1082
|
end # class Repo
|
data/lib/lenc/tools.rb
CHANGED
@@ -506,7 +506,7 @@ end
|
|
506
506
|
# Convenience method to detect if a script is being run
|
507
507
|
# e.g. as a 'main' method (for debug purposes only).
|
508
508
|
# If so, it changes the current directory to the
|
509
|
-
# directory containing the script.
|
509
|
+
# directory containing the script (if such a directory exists).
|
510
510
|
#
|
511
511
|
# @param file pass __FILE__ in here
|
512
512
|
# @return true if so
|
@@ -523,7 +523,10 @@ def main?(file)
|
|
523
523
|
end
|
524
524
|
|
525
525
|
if (ret = (file == scr))
|
526
|
-
|
526
|
+
dr = File.dirname(file)
|
527
|
+
if File.directory?(dr)
|
528
|
+
Dir.chdir(dr)
|
529
|
+
end
|
527
530
|
end
|
528
531
|
ret
|
529
532
|
end
|
data/test/test.rb
CHANGED
@@ -4,7 +4,7 @@ require_relative '../lib/lenc/tools.rb'
|
|
4
4
|
req('repo lencrypt')
|
5
5
|
|
6
6
|
|
7
|
-
#SINGLETEST = "
|
7
|
+
#SINGLETEST = "test_101_update_repo_with_verify"
|
8
8
|
if defined? SINGLETEST
|
9
9
|
if main?(__FILE__)
|
10
10
|
ARGV.concat("-n #{SINGLETEST}".split)
|
@@ -350,6 +350,7 @@ end
|
|
350
350
|
end
|
351
351
|
end
|
352
352
|
|
353
|
+
|
353
354
|
def test_200_recover_with_incorrect_password
|
354
355
|
create_repo
|
355
356
|
ex("") # updates repo
|
@@ -361,17 +362,4 @@ end
|
|
361
362
|
end
|
362
363
|
end
|
363
364
|
|
364
|
-
# def test_300_source_contains_encrypted_filename
|
365
|
-
# create_repo
|
366
|
-
# update_repo
|
367
|
-
#
|
368
|
-
# makeFile(bogusSourceFile())
|
369
|
-
# assert_raise(UpdateException) do
|
370
|
-
# update_repo
|
371
|
-
# end
|
372
|
-
# remove_file_or_dir(bogusSourceFile())
|
373
|
-
# end
|
374
|
-
|
375
|
-
|
376
|
-
|
377
365
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lenc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Sember
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-04-08 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: "Encrypts a set of local files, and copies the encrypted versions to
|
14
14
|
a repository, \nwhich may be located within a free cloud service (Dropbox, Google
|