shredder 1.0.0 → 2.0.200126
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 +5 -5
- data/README.md +113 -0
- data/bin/shredder +47 -35
- data/lib/shredder.rb +6 -5
- data/lib/shredder/files.rb +22 -36
- data/lib/shredder/shredder.rb +33 -39
- data/lib/shredder/stdio.rb +31 -0
- data/lib/shredder/streams.rb +4 -17
- metadata +16 -72
- data/History.txt +0 -0
- data/README.rdoc +0 -58
- data/TODO.txt +0 -7
- data/features/main.feature +0 -72
- data/features/step_definitions/main_steps.rb +0 -77
- data/lib/shredder/functions.rb +0 -36
- data/lib/shredder/version.rb +0 -5
- data/shredder.gemspec +0 -55
- data/test/test_shredder.rb +0 -140
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 498eeb86b0aea1ba926ec9c2dd168d41ef4467dd64ff79e7e712f3141aec4e02
|
4
|
+
data.tar.gz: 654802da4b46624cc48f87ca2d6aa949ba451fade334c6ce77a5c7836465938d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52830fd82dd9711003bd78e039df4467e66b95b013ca622c28103e65265dbe8b02841f886008db00b66508e2e34a47eb8f586c398b11fecf41e2ed5bcc6274c2
|
7
|
+
data.tar.gz: 766b712345d5efa6783a730d4f9afb4a00fe48e40a7f805a65252c7075edf1bad5f6cb750ab388f842e4accd2e58bb26612d6ed1b6d43eb85f57dbcdb9f5d929
|
data/README.md
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
# shredder
|
2
|
+
|
3
|
+
* [VERSION 2.0.200126](https://github.com/carlosjhr64/shredder/releases)
|
4
|
+
* [github](https://github.com/carlosjhr64/shredder)
|
5
|
+
* [rubygems](https://rubygems.org/gems/shredder)
|
6
|
+
|
7
|
+
## DESCRIPTION:
|
8
|
+
|
9
|
+
Shred a file into file fragments, and join fragments back into a restored file.
|
10
|
+
|
11
|
+
## HELP:
|
12
|
+
|
13
|
+
$ Usage:
|
14
|
+
$ shredder shred [:options+] <shreds=FILENAME>+
|
15
|
+
$ shredder sew [:options+] <shreds=FILENAME>+
|
16
|
+
$ Options:
|
17
|
+
$ --n=INTEGER Number of shreds
|
18
|
+
$ --passphrase Relay passphrase from stding to stdout
|
19
|
+
$ Types:
|
20
|
+
$ FILENAME /^[[:print:]]+$/
|
21
|
+
$ INTEGER /^[2-9]d*$/
|
22
|
+
$ # Examples:
|
23
|
+
$ # shredder shred file.1 file.2 < file.txt
|
24
|
+
$ # shredder shred --n=2 file < file.txt
|
25
|
+
$ # shredder sew file.1 file.2 > file.txt
|
26
|
+
$ # shredder shred --n=2 file > file.txt
|
27
|
+
|
28
|
+
## SYNOPSIS
|
29
|
+
|
30
|
+
### Library:
|
31
|
+
|
32
|
+
require 'shredder'
|
33
|
+
|
34
|
+
#### Shredder::Streams
|
35
|
+
|
36
|
+
require 'stringio'
|
37
|
+
|
38
|
+
sewn = StringIO.new("This is a test String: 1, 2, 3.")
|
39
|
+
sewn.string.length #=> 31
|
40
|
+
shreds = [StringIO.new, StringIO.new]
|
41
|
+
|
42
|
+
shredder = Shredder::Streams.new(sewn, shreds)
|
43
|
+
shredder.shred #=> 31
|
44
|
+
|
45
|
+
shreds[0].string
|
46
|
+
#=> "T\u0001S\u001AAT\u0016T'\e\t\u001A\u001D\u0012\f\u001D"
|
47
|
+
shreds[0].string.length #=> 16
|
48
|
+
|
49
|
+
shreds[1].string
|
50
|
+
#=> "<\u001AISA\u0011\as\u0006\a]\u0011\f\u001E\u0013"
|
51
|
+
shreds[1].string.length #=> 15
|
52
|
+
|
53
|
+
restored = StringIO.new
|
54
|
+
shreds.each{|_|_.rewind}
|
55
|
+
|
56
|
+
shredder = Shredder::Streams.new(restored, shreds)
|
57
|
+
shredder.sew #=> 31
|
58
|
+
|
59
|
+
restored.string #=> "This is a test String: 1, 2, 3."
|
60
|
+
|
61
|
+
#### Shredder::Files
|
62
|
+
|
63
|
+
sewn = './tmp/sewn.txt'
|
64
|
+
shreds = './tmp/shreds'
|
65
|
+
restored = './tmp/restored.txt'
|
66
|
+
|
67
|
+
File.read(sewn).chomp #=> "This is a test file: 1, 2, 3."
|
68
|
+
File.size(sewn) #=> 30
|
69
|
+
|
70
|
+
shredder = Shredder::Files.new(sewn, shreds, 3)
|
71
|
+
shredder.shreds
|
72
|
+
#=> ["./tmp/shreds.1", "./tmp/shreds.2", "./tmp/shreds.3"]
|
73
|
+
shredder.shred #=> 30
|
74
|
+
|
75
|
+
File.read(shreds+'.1') #=> "T\u001A\u001AA\u0016F\t\u0011\u0012\u0013"
|
76
|
+
File.read(shreds+'.2') #=> "<SST\a\u000F_\u001D\u001E\u001D"
|
77
|
+
File.read(shreds+'.3') #=> "\u0001IA\u0011T\u0005\u001A\f\f$"
|
78
|
+
File.size(shreds+'.3') #=> 10
|
79
|
+
|
80
|
+
shredder = Shredder::Files.new(restored, shreds, 3)
|
81
|
+
shredder.sewn #=> "./tmp/restored.txt"
|
82
|
+
shredder.sew #=> 30
|
83
|
+
File.read(restored).chomp #=> "This is a test file: 1, 2, 3."
|
84
|
+
|
85
|
+
## INSTALL:
|
86
|
+
|
87
|
+
$ gem install shredder
|
88
|
+
|
89
|
+
## LICENSE:
|
90
|
+
|
91
|
+
(The MIT License)
|
92
|
+
|
93
|
+
Copyright (c) 2020 CarlosJHR64
|
94
|
+
|
95
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
96
|
+
a copy of this software and associated documentation files (the
|
97
|
+
'Software'), to deal in the Software without restriction, including
|
98
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
99
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
100
|
+
permit persons to whom the Software is furnished to do so, subject to
|
101
|
+
the following conditions:
|
102
|
+
|
103
|
+
The above copyright notice and this permission notice shall be
|
104
|
+
included in all copies or substantial portions of the Software.
|
105
|
+
|
106
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
107
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
108
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
109
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
110
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
111
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
112
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
113
|
+
|
data/bin/shredder
CHANGED
@@ -1,43 +1,55 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
# Gems:
|
4
2
|
require 'help_parser'
|
5
3
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
NAME = File.basename $0 # Program Name
|
11
|
-
HELP = <<HELP
|
12
|
-
Usage: #{NAME} [options] [file] shred1 shred2...
|
4
|
+
OPTIONS = HelpParser['2.0.200126', <<HELP]
|
5
|
+
Usage:
|
6
|
+
shredder shred [:options+] <shreds=FILENAME>+
|
7
|
+
shredder sew [:options+] <shreds=FILENAME>+
|
13
8
|
Options:
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
--no a symmetry with commands like gpg.
|
25
|
-
Note:
|
26
|
-
Typical use of relay is for passphrase.
|
27
|
-
Version: #{VERSION}
|
9
|
+
--n=INTEGER \tNumber of shreds
|
10
|
+
--passphrase\tRelay passphrase from stding to stdout
|
11
|
+
Types:
|
12
|
+
FILENAME /^[[:print:]]+$/
|
13
|
+
INTEGER /^[2-9]\d*$/
|
14
|
+
# Examples:
|
15
|
+
# shredder shred file.1 file.2 < file.txt
|
16
|
+
# shredder shred --n=2 file < file.txt
|
17
|
+
# shredder sew file.1 file.2 > file.txt
|
18
|
+
# shredder shred --n=2 file > file.txt
|
28
19
|
HELP
|
20
|
+
HelpParser.int?(:n)
|
29
21
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
22
|
+
shreds = OPTIONS.shreds
|
23
|
+
count = shreds.length
|
24
|
+
if n = OPTIONS.n?
|
25
|
+
if count == 1
|
26
|
+
count = n
|
27
|
+
shreds = shreds.first
|
28
|
+
elsif count != n
|
29
|
+
$stderr.puts "shred count(#{count}) not equal to n(#{n})."
|
30
|
+
exit 64
|
31
|
+
end
|
32
|
+
end
|
33
|
+
unless count > 1
|
34
|
+
$stderr.puts "shred count must be at least 2"
|
42
35
|
exit 64
|
43
36
|
end
|
37
|
+
|
38
|
+
require 'shredder/shredder'
|
39
|
+
require 'shredder/streams'
|
40
|
+
require 'shredder/stdio'
|
41
|
+
|
42
|
+
shredder = Shredder::StdIO.new(shreds, count)
|
43
|
+
case OPTIONS[1]
|
44
|
+
when 'shred'
|
45
|
+
shredder.shred
|
46
|
+
when 'sew'
|
47
|
+
begin
|
48
|
+
shredder.sew
|
49
|
+
rescue Errno::ENOENT
|
50
|
+
# Common expected type of error,
|
51
|
+
# user tries to sew non-existing shreds.
|
52
|
+
$stderr.puts $!.message
|
53
|
+
exit 65
|
54
|
+
end
|
55
|
+
end
|
data/lib/shredder.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
require 'shredder/streams'
|
1
|
+
module Shredder
|
2
|
+
VERSION = '2.0.200126'
|
3
|
+
end
|
5
4
|
require 'shredder/shredder'
|
6
|
-
|
5
|
+
require 'shredder/streams'
|
6
|
+
require 'shredder/stdio'
|
7
|
+
require 'shredder/files'
|
7
8
|
# Requires:
|
8
9
|
#`ruby`
|
data/lib/shredder/files.rb
CHANGED
@@ -1,51 +1,37 @@
|
|
1
|
-
module
|
2
|
-
|
1
|
+
module Shredder
|
3
2
|
class Files
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
@
|
9
|
-
@shreds
|
10
|
-
@limit = limit
|
3
|
+
include Shredder
|
4
|
+
# this one takes filenames
|
5
|
+
def initialize(sewn, shreds=sewn, m=2, n: m)
|
6
|
+
@sewn = sewn
|
7
|
+
@shreds = shred_files(shreds, n)
|
8
|
+
raise "Need at least 2 shreds" unless @shreds.length > 1
|
11
9
|
end
|
12
10
|
|
13
|
-
def shred(limit
|
14
|
-
reader
|
15
|
-
writers = []
|
16
|
-
@shreds.each{|shred| writers.push(File.open(shred, 'wb'))}
|
17
|
-
|
18
|
-
count = nil
|
11
|
+
def shred(limit=0)
|
12
|
+
reader = writers = count = nil
|
19
13
|
begin
|
20
|
-
|
21
|
-
|
22
|
-
|
14
|
+
reader = File.open(@sewn, 'r')
|
15
|
+
writers = @shreds.map{|shred| File.open(shred, 'wb')}
|
16
|
+
count = Streams.new(reader, writers).shred(limit: limit)
|
23
17
|
ensure
|
24
|
-
writers.each{|writer| writer.close}
|
25
|
-
reader.close
|
26
|
-
|
27
|
-
|
18
|
+
writers.each{|writer| writer.close} if writers
|
19
|
+
reader.close if reader
|
20
|
+
end
|
28
21
|
return count
|
29
22
|
end
|
30
23
|
|
31
|
-
def sew(limit
|
32
|
-
writer
|
33
|
-
readers = []
|
34
|
-
@shreds.each{|shred| readers.push(File.open(shred, 'r'))}
|
35
|
-
|
36
|
-
count = nil
|
24
|
+
def sew(limit=0)
|
25
|
+
writer = readers = count = nil
|
37
26
|
begin
|
38
|
-
|
39
|
-
|
40
|
-
|
27
|
+
writer = File.open(@sewn, 'wb')
|
28
|
+
readers = @shreds.map{|shred| File.open(shred, 'r')}
|
29
|
+
count = Streams.new(writer, readers).sew(limit: limit)
|
41
30
|
ensure
|
42
|
-
writer.close
|
43
|
-
readers.each{|reader| reader.close}
|
31
|
+
writer.close if writer
|
32
|
+
readers.each{|reader| reader.close} if readers
|
44
33
|
end
|
45
|
-
|
46
34
|
return count
|
47
35
|
end
|
48
|
-
|
49
36
|
end
|
50
|
-
|
51
37
|
end
|
data/lib/shredder/shredder.rb
CHANGED
@@ -1,46 +1,40 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
@sewed = (@shred)? STDIN : STDOUT
|
13
|
-
else
|
14
|
-
@sewed = @shreds.shift
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def execute(sewed=@sewed, shreds=@shreds, shred=@shred)
|
20
|
-
stream = false
|
21
|
-
if sewed.kind_of?(IO)
|
22
|
-
stream = true
|
23
|
-
rw = (shred)? 'w' : 'r'
|
24
|
-
shreds = shreds.map{|filename| File.open(filename, rw)}
|
25
|
-
end
|
26
|
-
|
27
|
-
shredder = (stream)? Shredder::Streams.new(sewed, shreds) : Shredder::Files.new(sewed, shreds)
|
28
|
-
STDOUT.puts STDIN.gets if @relay
|
29
|
-
begin
|
30
|
-
(shred)? shredder.shred : shredder.sew
|
31
|
-
ensure
|
32
|
-
shreds.each{|filehandle| filehandle.close} if stream
|
33
|
-
end
|
1
|
+
module Shredder
|
2
|
+
attr_accessor :sewn, :shreds
|
3
|
+
|
4
|
+
# note that these are streams
|
5
|
+
def shred(sewn=(@sewn or $stdin), shreds=@shreds,
|
6
|
+
writers: shreds, reader: sewn, limit: 0)
|
7
|
+
shreds,xor,count = writers.length,0,0
|
8
|
+
while byte = reader.getbyte do
|
9
|
+
writers[count%shreds].putc(xor^(xor=byte))
|
10
|
+
count += 1 # not that 0 is skipped
|
11
|
+
break if count == limit
|
34
12
|
end
|
13
|
+
return count
|
14
|
+
end
|
35
15
|
|
36
|
-
|
37
|
-
|
16
|
+
# note that these are streams
|
17
|
+
def sew(shreds=@shreds, sewn=(@sewn or $stdout),
|
18
|
+
readers: shreds, writer: sewn, limit: 0)
|
19
|
+
shreds,xor,count = readers.length,0,0
|
20
|
+
while byte = readers[count%shreds].getbyte do
|
21
|
+
writer.putc(xor=(byte^xor))
|
22
|
+
count += 1 # note that 0 is skipped
|
23
|
+
break if count == limit
|
38
24
|
end
|
25
|
+
return count
|
26
|
+
end
|
39
27
|
|
40
|
-
|
41
|
-
|
28
|
+
def shred_files(b, m=2, basename: b, n: m)
|
29
|
+
case basename
|
30
|
+
when Array
|
31
|
+
basename
|
32
|
+
when String
|
33
|
+
(1..n).map{|i| "#{basename}.#{i}"}
|
34
|
+
when Integer
|
35
|
+
(1..basename).map{|i| "#{@sewn or 'shred'}.#{i}"}
|
36
|
+
else
|
37
|
+
raise "Expected basename Array|String|Integer"
|
42
38
|
end
|
43
|
-
|
44
39
|
end
|
45
|
-
|
46
40
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Shredder
|
2
|
+
class StdIO
|
3
|
+
include Shredder
|
4
|
+
# this one takes shred filenames and uses $stdin or $stdout appropriately.
|
5
|
+
def initialize(*args)
|
6
|
+
@shreds = shred_files(*args)
|
7
|
+
end
|
8
|
+
|
9
|
+
def shred(limit=0)
|
10
|
+
writers = count = nil
|
11
|
+
begin
|
12
|
+
writers = @shreds.map{|shred| File.open(shred, 'wb')}
|
13
|
+
count = Streams.new($stdin, writers).shred(limit: limit)
|
14
|
+
ensure
|
15
|
+
writers.each{|writer| writer.close} if writers
|
16
|
+
end
|
17
|
+
return count
|
18
|
+
end
|
19
|
+
|
20
|
+
def sew(limit=0)
|
21
|
+
readers = count = nil
|
22
|
+
begin
|
23
|
+
readers = @shreds.map{|shred| File.open(shred, 'r')}
|
24
|
+
count = Streams.new($stdout, readers).sew(limit: limit)
|
25
|
+
ensure
|
26
|
+
readers.each{|reader| reader.close} if readers
|
27
|
+
end
|
28
|
+
return count
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/shredder/streams.rb
CHANGED
@@ -1,23 +1,10 @@
|
|
1
|
-
module
|
2
|
-
|
1
|
+
module Shredder
|
3
2
|
class Streams
|
4
|
-
|
5
|
-
|
3
|
+
include Shredder
|
6
4
|
# this one takes streams
|
7
|
-
def initialize(
|
8
|
-
@
|
5
|
+
def initialize(sewn, shreds)
|
6
|
+
@sewn = sewn
|
9
7
|
@shreds = shreds
|
10
|
-
@limit = limit
|
11
8
|
end
|
12
|
-
|
13
|
-
def shred(limit=@limit)
|
14
|
-
Streams.shred(@sew,@shreds,limit)
|
15
|
-
end
|
16
|
-
|
17
|
-
def sew(limit=@limit)
|
18
|
-
Streams.sew(@sew,@shreds,limit)
|
19
|
-
end
|
20
|
-
|
21
9
|
end
|
22
|
-
|
23
10
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shredder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.200126
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- carlosjhr64
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: help_parser
|
@@ -16,94 +16,43 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '6.5'
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
22
|
+
version: 6.5.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
29
|
+
version: '6.5'
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
33
|
-
|
34
|
-
|
35
|
-
requirement: !ruby/object:Gem::Requirement
|
36
|
-
requirements:
|
37
|
-
- - "~>"
|
38
|
-
- !ruby/object:Gem::Version
|
39
|
-
version: '2.5'
|
40
|
-
- - ">="
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
version: 2.5.5
|
43
|
-
type: :development
|
44
|
-
prerelease: false
|
45
|
-
version_requirements: !ruby/object:Gem::Requirement
|
46
|
-
requirements:
|
47
|
-
- - "~>"
|
48
|
-
- !ruby/object:Gem::Version
|
49
|
-
version: '2.5'
|
50
|
-
- - ">="
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
version: 2.5.5
|
53
|
-
- !ruby/object:Gem::Dependency
|
54
|
-
name: symmetric_gpg
|
55
|
-
requirement: !ruby/object:Gem::Requirement
|
56
|
-
requirements:
|
57
|
-
- - "~>"
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
version: '2.0'
|
60
|
-
- - ">="
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
version: 2.0.1
|
63
|
-
type: :development
|
64
|
-
prerelease: false
|
65
|
-
version_requirements: !ruby/object:Gem::Requirement
|
66
|
-
requirements:
|
67
|
-
- - "~>"
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '2.0'
|
70
|
-
- - ">="
|
71
|
-
- !ruby/object:Gem::Version
|
72
|
-
version: 2.0.1
|
73
|
-
description: |
|
74
|
-
Shred a file into file fragments, and join fragments back into a restored file.
|
32
|
+
version: 6.5.0
|
33
|
+
description: 'Shred a file into file fragments, and join fragments back into a restored
|
34
|
+
file.
|
75
35
|
|
76
|
-
|
77
|
-
so that no one depository has the entire file.
|
36
|
+
'
|
78
37
|
email: carlosjhr64@gmail.com
|
79
38
|
executables:
|
80
39
|
- shredder
|
81
40
|
extensions: []
|
82
|
-
extra_rdoc_files:
|
83
|
-
- README.rdoc
|
41
|
+
extra_rdoc_files: []
|
84
42
|
files:
|
85
|
-
-
|
86
|
-
- README.rdoc
|
87
|
-
- TODO.txt
|
43
|
+
- README.md
|
88
44
|
- bin/shredder
|
89
|
-
- features/main.feature
|
90
|
-
- features/step_definitions/main_steps.rb
|
91
45
|
- lib/shredder.rb
|
92
46
|
- lib/shredder/files.rb
|
93
|
-
- lib/shredder/functions.rb
|
94
47
|
- lib/shredder/shredder.rb
|
48
|
+
- lib/shredder/stdio.rb
|
95
49
|
- lib/shredder/streams.rb
|
96
|
-
- lib/shredder/version.rb
|
97
|
-
- shredder.gemspec
|
98
|
-
- test/test_shredder.rb
|
99
50
|
homepage: https://github.com/carlosjhr64/shredder
|
100
51
|
licenses:
|
101
52
|
- MIT
|
102
53
|
metadata: {}
|
103
54
|
post_install_message:
|
104
|
-
rdoc_options:
|
105
|
-
- "--main"
|
106
|
-
- README.rdoc
|
55
|
+
rdoc_options: []
|
107
56
|
require_paths:
|
108
57
|
- lib
|
109
58
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -117,13 +66,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
117
66
|
- !ruby/object:Gem::Version
|
118
67
|
version: '0'
|
119
68
|
requirements:
|
120
|
-
- 'ruby: ruby 2.
|
121
|
-
|
122
|
-
- 'system in development: linux/bash'
|
123
|
-
- 'rm in development: rm (GNU coreutils) 8.13'
|
124
|
-
- 'diff in development: diff (GNU diffutils) 3.2'
|
125
|
-
rubyforge_project:
|
126
|
-
rubygems_version: 2.2.0
|
69
|
+
- 'ruby: ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-linux]'
|
70
|
+
rubygems_version: 3.1.2
|
127
71
|
signing_key:
|
128
72
|
specification_version: 4
|
129
73
|
summary: Shred a file into file fragments, and join fragments back into a restored
|
data/History.txt
DELETED
File without changes
|
data/README.rdoc
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
= shredder
|
2
|
-
|
3
|
-
github :: https://www.github.com/carlosjhr64/shredder
|
4
|
-
rubygems :: https://rubygems.org/gems/shredder
|
5
|
-
|
6
|
-
== DESCRIPTION:
|
7
|
-
|
8
|
-
Shred a file into file fragments, and join fragments back into a restored file.
|
9
|
-
|
10
|
-
Disperse file shreds in separate depositories
|
11
|
-
so that no one depository has the entire file.
|
12
|
-
|
13
|
-
== SYNOPSIS
|
14
|
-
|
15
|
-
Command line:
|
16
|
-
|
17
|
-
$ shredder --help
|
18
|
-
$ shredder --shred file.orig file.1 file.2
|
19
|
-
$ shredder --sew file.sewed file.1 file.2
|
20
|
-
$ cat file.orig | shredder --shred --io file.1 file.2
|
21
|
-
$ shredder --sew --io file.1 file.2 > file.sewed
|
22
|
-
|
23
|
-
Library:
|
24
|
-
|
25
|
-
require 'shredder'
|
26
|
-
# ...
|
27
|
-
shredder = SHREDDER:Shredder.new
|
28
|
-
shredder.shred('orinal.txt', 'shred.1', 'shred.2')
|
29
|
-
shredder.sew( 'sewed.txt', 'shred.1', 'shred.2')
|
30
|
-
|
31
|
-
== INSTALL:
|
32
|
-
|
33
|
-
$ sudo gem install shredder
|
34
|
-
|
35
|
-
== LICENSE:
|
36
|
-
|
37
|
-
(The MIT License)
|
38
|
-
|
39
|
-
Copyright (c) 2014 CarlosJHR64
|
40
|
-
|
41
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
42
|
-
a copy of this software and associated documentation files (the
|
43
|
-
'Software'), to deal in the Software without restriction, including
|
44
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
45
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
46
|
-
permit persons to whom the Software is furnished to do so, subject to
|
47
|
-
the following conditions:
|
48
|
-
|
49
|
-
The above copyright notice and this permission notice shall be
|
50
|
-
included in all copies or substantial portions of the Software.
|
51
|
-
|
52
|
-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
53
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
54
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
55
|
-
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
56
|
-
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
57
|
-
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
58
|
-
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/TODO.txt
DELETED
data/features/main.feature
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
@main
|
2
|
-
Feature: Main Features
|
3
|
-
|
4
|
-
Background:
|
5
|
-
* Given command "ruby -I ./lib ./bin/shredder"
|
6
|
-
|
7
|
-
Scenario: Long opt version.
|
8
|
-
* Given arguments "--version"
|
9
|
-
* When run
|
10
|
-
* Then status is "0"
|
11
|
-
* Then stderr is ""
|
12
|
-
* Then stdout is "1.0.0"
|
13
|
-
|
14
|
-
Scenario: Long opt help.
|
15
|
-
* Given arguments "--help"
|
16
|
-
* When run
|
17
|
-
* Then status is "0"
|
18
|
-
* Then stderr is ""
|
19
|
-
* Then stdout matches "^Usage: shredder"
|
20
|
-
|
21
|
-
Scenario: Can't be both sew and shred.
|
22
|
-
* Given system(rm ./temp.* 2> /dev/null)
|
23
|
-
* Given system(openssl rand -base64 32 > ./temp.txt)
|
24
|
-
* Given arguments "--sew --shred ./temp.txt ./temp.1 ./temp.2"
|
25
|
-
* When run
|
26
|
-
* Then status is "64"
|
27
|
-
* Then stderr is not ""
|
28
|
-
* Then stdout is ""
|
29
|
-
* Then stderr is "Need choice: sew or shred?"
|
30
|
-
|
31
|
-
Scenario: Needs to be either sew or shred.
|
32
|
-
* Given system(rm ./temp.* 2> /dev/null)
|
33
|
-
* Given system(openssl rand -base64 32 > ./temp.txt)
|
34
|
-
* Given arguments "./temp.txt ./temp.1 ./temp.2"
|
35
|
-
* When run
|
36
|
-
* Then status is "64"
|
37
|
-
* Then stderr is not ""
|
38
|
-
* Then stdout is ""
|
39
|
-
* Then stderr is "Need choice: sew or shred?"
|
40
|
-
|
41
|
-
Scenario: What we shred, we can sew.
|
42
|
-
* Given system(rm ./temp.* 2> /dev/null)
|
43
|
-
* Given system(openssl rand -base64 32 > ./temp.txt)
|
44
|
-
* Given arguments "--shred ./temp.txt ./temp.1 ./temp.2"
|
45
|
-
* When run
|
46
|
-
* Then status is "0"
|
47
|
-
* Then stderr is ""
|
48
|
-
* Then stdout is ""
|
49
|
-
* Then system(test -e ./temp.1)
|
50
|
-
* Then system(test -e ./temp.2)
|
51
|
-
* Given arguments "--sew ./temp.sewed ./temp.1 ./temp.2"
|
52
|
-
* When run
|
53
|
-
* Then status is "0"
|
54
|
-
* Then stderr is ""
|
55
|
-
* Then stdout is ""
|
56
|
-
* Then system(test -e ./temp.sewed)
|
57
|
-
# temp.txt and temp.sewed are equal
|
58
|
-
* Then system(diff temp.txt temp.sewed > /dev/null)
|
59
|
-
# Just a sanity check temp.1 and temp.2 are not equal
|
60
|
-
* Then not system(diff temp.1 temp.2 > /dev/null)
|
61
|
-
|
62
|
-
Scenario: What we shred from stdin, we can sew to stdout. And using 3 shreds to boot!
|
63
|
-
* Given system(rm ./temp.* 2> /dev/null)
|
64
|
-
* Given system(openssl rand -base64 32 > ./temp.txt)
|
65
|
-
* Given system(cat ./temp.txt | ruby -I ./lib ./bin/shredder --shred --io ./temp.1 ./temp.2 ./temp.3)
|
66
|
-
* Then system(test -e ./temp.3)
|
67
|
-
* Given system(ruby -I ./lib ./bin/shredder --sew --io ./temp.1 ./temp.2 ./temp.3 > ./temp.sewed)
|
68
|
-
* Then system(test -e ./temp.sewed)
|
69
|
-
* Then system(diff temp.txt temp.sewed > /dev/null)
|
70
|
-
|
71
|
-
# Let's clean up after ourselves...
|
72
|
-
* Given system(rm ./temp.* 2> /dev/null)
|
@@ -1,77 +0,0 @@
|
|
1
|
-
require 'open3'
|
2
|
-
|
3
|
-
# Requires:
|
4
|
-
#`bash`
|
5
|
-
|
6
|
-
H = {}
|
7
|
-
|
8
|
-
def _capture3(command)
|
9
|
-
stdout, stderr, status = Open3.capture3(command)
|
10
|
-
H['status'] = status.exitstatus
|
11
|
-
H['stdout'] = stdout.chomp
|
12
|
-
H['stderr'] = stderr.chomp
|
13
|
-
end
|
14
|
-
|
15
|
-
def _given(condition)
|
16
|
-
case condition
|
17
|
-
when /^(\w+) "([^"]*)"$/
|
18
|
-
H[$1] = $2
|
19
|
-
when /^system\(([^\(\)]*)\)$/
|
20
|
-
system($1)
|
21
|
-
else
|
22
|
-
raise "Unrecognized Given-Statement"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def _when(condition)
|
27
|
-
case condition
|
28
|
-
when 'run'
|
29
|
-
command, arguments = H['command'], H['arguments']
|
30
|
-
raise 'Need command and argurments to run' unless command and arguments
|
31
|
-
_capture3("#{command} #{arguments}")
|
32
|
-
when /^run\(([^\(\)]*)\)$/
|
33
|
-
_capture3($1)
|
34
|
-
else
|
35
|
-
raise "Unrecognized When-Statement"
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def _then(condition)
|
40
|
-
case condition
|
41
|
-
when /^(not )?system\(([^\(\)]*)\)$/
|
42
|
-
neg, cmd = $1, $2
|
43
|
-
ok = system(cmd)
|
44
|
-
ok = !ok if neg
|
45
|
-
raise "System Call Error" unless ok
|
46
|
-
when /^(\w+) (\w+)( not)? "([^"]*)"$/
|
47
|
-
key, cmp, negate, expected = $1, $2, $3, $4
|
48
|
-
actual = H[key].to_s
|
49
|
-
ok = case cmp
|
50
|
-
when 'is'
|
51
|
-
actual == expected
|
52
|
-
when 'matches'
|
53
|
-
expected = Regexp.new(expected)
|
54
|
-
actual =~ expected
|
55
|
-
else
|
56
|
-
raise "Unrecognized Comparison Operator"
|
57
|
-
end
|
58
|
-
ok = !ok if negate
|
59
|
-
raise "Got #{actual} for #{key}" unless ok
|
60
|
-
else
|
61
|
-
raise "Unrecognized Then-Statement"
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
Given /^(\w+) (.*)$/ do |given, condition|
|
66
|
-
condition.strip!
|
67
|
-
case given
|
68
|
-
when 'Given'
|
69
|
-
_given(condition)
|
70
|
-
when 'When'
|
71
|
-
_when(condition)
|
72
|
-
when 'Then'
|
73
|
-
_then(condition)
|
74
|
-
else
|
75
|
-
raise "'#{given}' form not defined."
|
76
|
-
end
|
77
|
-
end
|
data/lib/shredder/functions.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
module SHREDDER
|
2
|
-
|
3
|
-
module Functions
|
4
|
-
|
5
|
-
# note that these are streams
|
6
|
-
def shred(reader, writers, limit=0)
|
7
|
-
shreds = writers.length
|
8
|
-
xor = count = 0
|
9
|
-
while byte = reader.getbyte do
|
10
|
-
writers[ count % shreds ].putc byte^xor
|
11
|
-
xor = byte
|
12
|
-
count += 1
|
13
|
-
# note: will not break if limit is zero
|
14
|
-
break if count == limit
|
15
|
-
end
|
16
|
-
return count
|
17
|
-
end
|
18
|
-
|
19
|
-
# note that these are streams
|
20
|
-
def sew(writer, readers, limit=0)
|
21
|
-
shreds = readers.length
|
22
|
-
xor = count = 0
|
23
|
-
while byte = readers[ count % shreds ].getbyte do
|
24
|
-
chr = byte^xor
|
25
|
-
xor = chr
|
26
|
-
writer.putc chr
|
27
|
-
count += 1
|
28
|
-
# note: will not break if limit is zero
|
29
|
-
break if count == limit
|
30
|
-
end
|
31
|
-
return count
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
data/lib/shredder/version.rb
DELETED
data/shredder.gemspec
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
Gem::Specification.new do |s|
|
2
|
-
|
3
|
-
s.name = 'shredder'
|
4
|
-
s.version = '1.0.0'
|
5
|
-
|
6
|
-
s.homepage = 'https://github.com/carlosjhr64/shredder'
|
7
|
-
|
8
|
-
s.author = 'CarlosJHR64'
|
9
|
-
s.email = 'carlosjhr64@gmail.com'
|
10
|
-
|
11
|
-
s.date = '2014-01-11'
|
12
|
-
s.licenses = ['MIT']
|
13
|
-
|
14
|
-
s.description = <<DESCRIPTION
|
15
|
-
Shred a file into file fragments, and join fragments back into a restored file.
|
16
|
-
|
17
|
-
Disperse file shreds in separate depositories
|
18
|
-
so that no one depository has the entire file.
|
19
|
-
DESCRIPTION
|
20
|
-
|
21
|
-
s.summary = <<SUMMARY
|
22
|
-
Shred a file into file fragments, and join fragments back into a restored file.
|
23
|
-
SUMMARY
|
24
|
-
|
25
|
-
s.extra_rdoc_files = ['README.rdoc']
|
26
|
-
s.rdoc_options = ["--main", "README.rdoc"]
|
27
|
-
|
28
|
-
s.require_paths = ["lib"]
|
29
|
-
s.files = %w(
|
30
|
-
History.txt
|
31
|
-
README.rdoc
|
32
|
-
TODO.txt
|
33
|
-
bin/shredder
|
34
|
-
features/main.feature
|
35
|
-
features/step_definitions/main_steps.rb
|
36
|
-
lib/shredder.rb
|
37
|
-
lib/shredder/files.rb
|
38
|
-
lib/shredder/functions.rb
|
39
|
-
lib/shredder/shredder.rb
|
40
|
-
lib/shredder/streams.rb
|
41
|
-
lib/shredder/version.rb
|
42
|
-
shredder.gemspec
|
43
|
-
test/test_shredder.rb
|
44
|
-
)
|
45
|
-
s.executables << 'shredder'
|
46
|
-
s.add_runtime_dependency 'help_parser', '~> 1.1', '>= 1.1.0'
|
47
|
-
s.add_development_dependency 'test-unit', '~> 2.5', '>= 2.5.5'
|
48
|
-
s.add_development_dependency 'symmetric_gpg', '~> 2.0', '>= 2.0.1'
|
49
|
-
s.requirements << 'ruby: ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-linux]'
|
50
|
-
s.requirements << 'bash in development: GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu)'
|
51
|
-
s.requirements << 'system in development: linux/bash'
|
52
|
-
s.requirements << 'rm in development: rm (GNU coreutils) 8.13'
|
53
|
-
s.requirements << 'diff in development: diff (GNU diffutils) 3.2'
|
54
|
-
|
55
|
-
end
|
data/test/test_shredder.rb
DELETED
@@ -1,140 +0,0 @@
|
|
1
|
-
# Standard Libraries
|
2
|
-
require 'stringio'
|
3
|
-
|
4
|
-
# Gems
|
5
|
-
require 'test/unit'
|
6
|
-
begin
|
7
|
-
require 'symmetric_gpg'
|
8
|
-
GPG = true
|
9
|
-
rescue
|
10
|
-
STDERR.puts "Warning: symmetric_gpg not available for testing"
|
11
|
-
GPG = false
|
12
|
-
end
|
13
|
-
|
14
|
-
# This Gem
|
15
|
-
require 'shredder'
|
16
|
-
include SHREDDER
|
17
|
-
|
18
|
-
module TestFunction
|
19
|
-
extend Functions
|
20
|
-
end
|
21
|
-
|
22
|
-
class TestShredder < Test::Unit::TestCase
|
23
|
-
|
24
|
-
def test_version
|
25
|
-
assert_equal '1.0.0', VERSION
|
26
|
-
assert_equal '1.0.0', SHREDDER::VERSION
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_functions_even
|
30
|
-
abc = "abcdefghijklmnopqrstuvwxyz"
|
31
|
-
string = StringIO.new(abc)
|
32
|
-
shred1 = StringIO.new
|
33
|
-
shred2 = StringIO.new
|
34
|
-
TestFunction.shred(string, [shred1, shred2])
|
35
|
-
string.rewind
|
36
|
-
shred1.rewind
|
37
|
-
shred2.rewind
|
38
|
-
l0, l1, l2 = string.length, shred1.length, shred2.length
|
39
|
-
assert_equal(l0, l1 + l2)
|
40
|
-
assert_equal(l1, l2)
|
41
|
-
sewed = StringIO.new
|
42
|
-
TestFunction.sew(sewed, [shred1, shred2])
|
43
|
-
sewed.rewind
|
44
|
-
assert_equal(sewed.read, abc)
|
45
|
-
|
46
|
-
# Note that the xor starts it's seed with the first letter,
|
47
|
-
# so that 'a' in the abc string remains unchanged.
|
48
|
-
# Anyways, the point of the following is to show that the shreds
|
49
|
-
# are no longer easily recognizable as part of the original string.
|
50
|
-
|
51
|
-
shred1.rewind
|
52
|
-
shred = shred1.read
|
53
|
-
assert_nil(shred=~/[b-z]/)
|
54
|
-
|
55
|
-
shred2.rewind
|
56
|
-
shred = shred2.read
|
57
|
-
assert_nil(shred=~/[b-z]/)
|
58
|
-
end
|
59
|
-
|
60
|
-
def test_functions_odd
|
61
|
-
abc = "abcdefghijklmnopqrstuvwxyz+"
|
62
|
-
string = StringIO.new(abc)
|
63
|
-
shred1 = StringIO.new
|
64
|
-
shred2 = StringIO.new
|
65
|
-
TestFunction.shred(string, [shred1, shred2])
|
66
|
-
string.rewind
|
67
|
-
shred1.rewind
|
68
|
-
shred2.rewind
|
69
|
-
l0, l1, l2 = string.length, shred1.length, shred2.length
|
70
|
-
assert_equal(l0, l1 + l2)
|
71
|
-
assert_equal(l1, l2+1)
|
72
|
-
sewed = StringIO.new
|
73
|
-
TestFunction.sew(sewed, [shred1, shred2])
|
74
|
-
sewed.rewind
|
75
|
-
assert_equal(sewed.read, abc)
|
76
|
-
end
|
77
|
-
|
78
|
-
def test_functions_three
|
79
|
-
abc = "abcdefghijklmnopqrstuvwxyz"
|
80
|
-
string = StringIO.new(abc)
|
81
|
-
shred1 = StringIO.new
|
82
|
-
shred2 = StringIO.new
|
83
|
-
shred3 = StringIO.new
|
84
|
-
TestFunction.shred(string, [shred1, shred2, shred3])
|
85
|
-
string.rewind
|
86
|
-
shred1.rewind
|
87
|
-
shred2.rewind
|
88
|
-
shred3.rewind
|
89
|
-
l0, l1, l2, l3 = string.length, shred1.length, shred2.length, shred3.length
|
90
|
-
assert_equal(l0, l1 + l2 + l3)
|
91
|
-
assert(l1>7)
|
92
|
-
assert(l2>7)
|
93
|
-
assert(l3>7)
|
94
|
-
sewed = StringIO.new
|
95
|
-
TestFunction.sew(sewed, [shred1, shred2, shred3])
|
96
|
-
sewed.rewind
|
97
|
-
assert_equal(sewed.read, abc)
|
98
|
-
end
|
99
|
-
|
100
|
-
# Most of the code is tested under cucumber.
|
101
|
-
# Just going to test an untested path.
|
102
|
-
# Shredder.new(...).execute is well tested.
|
103
|
-
# Now test Shredder.new.shred and #sew
|
104
|
-
def test_shredder
|
105
|
-
system('rm ./temp.* 2> /dev/null')
|
106
|
-
refute File.exist? './temp.sewed' # just a quick sanity check
|
107
|
-
system('openssl rand -base64 32 > ./temp.txt')
|
108
|
-
shredder = Shredder.new
|
109
|
-
# ...and just for something a bit different, 4 shreds.
|
110
|
-
shredder.shred('./temp.txt', './temp.1', './temp.2', './temp.3', './temp.4')
|
111
|
-
assert File.exist? './temp.1'
|
112
|
-
assert File.exist? './temp.2'
|
113
|
-
assert File.exist? './temp.3'
|
114
|
-
assert File.exist? './temp.4'
|
115
|
-
shredder.sew('./temp.sewed', './temp.1', './temp.2', './temp.3', './temp.4')
|
116
|
-
assert File.exist? './temp.sewed'
|
117
|
-
# The following will show the two files to be equal
|
118
|
-
assert system 'diff ./temp.txt ./temp.sewed 2> /dev/null'
|
119
|
-
|
120
|
-
system('rm ./temp.*') # cleanup after ourselves
|
121
|
-
end
|
122
|
-
|
123
|
-
def test_symmetric_gpg
|
124
|
-
if GPG
|
125
|
-
system('rm ./temp.* 2> /dev/null')
|
126
|
-
string = "A is for Apple."
|
127
|
-
shreds = SymmetricGPG::Shreds.new("Shreddelicious!", string, ['./temp.1','./temp.2'])
|
128
|
-
shreds.shredder = '/usr/local/bin/ruby -I ./lib ./bin/shredder'
|
129
|
-
shreds.shred # Should encrypt and then shred the string into shred.1 and shred.2.
|
130
|
-
assert File.exist? './temp.1'
|
131
|
-
assert File.exist? './temp.2'
|
132
|
-
shreds.plain = nil # no cheat!
|
133
|
-
plain = shreds.sew # should get the shredded string back.
|
134
|
-
assert_equal string, plain
|
135
|
-
# Cleanup after ourselves
|
136
|
-
system('rm ./temp.* 2> /dev/null')
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
end
|