shredder 0.2.0 → 1.0.0
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 +7 -0
- data/History.txt +0 -0
- data/README.rdoc +58 -0
- data/TODO.txt +7 -0
- data/bin/shredder +34 -75
- data/features/main.feature +72 -0
- data/features/step_definitions/main_steps.rb +77 -0
- data/lib/shredder.rb +7 -34
- data/lib/shredder/files.rb +15 -10
- data/lib/shredder/functions.rb +36 -0
- data/lib/shredder/shredder.rb +46 -0
- data/lib/shredder/streams.rb +11 -6
- data/lib/shredder/version.rb +5 -0
- data/shredder.gemspec +55 -0
- data/test/test_shredder.rb +140 -0
- metadata +113 -55
- data/README.txt +0 -28
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 86de11dca31147b96703885615c3727a7256bda2
|
4
|
+
data.tar.gz: 10147305bd2892e76a56b5ad8378f52470c4be5d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5f19a35eb7ba38592f328f0d87e93401ae528b470c6046d81ace2d4b0dfbaf1db2e8a07df8d41a2a2e86091d7969d52e51889d78988037cc53c71b3d7aeb83a4
|
7
|
+
data.tar.gz: cfb6ccd2fcecd29df7a02c24caba969a06e7025ea8b82c2af782d1aa5a2c994c1eb2dff806e0e31169c426ae904ef07af6bb90c1f9c015c17e759fbd010f7ac0
|
data/History.txt
ADDED
File without changes
|
data/README.rdoc
ADDED
@@ -0,0 +1,58 @@
|
|
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
ADDED
data/bin/shredder
CHANGED
@@ -1,84 +1,43 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
require 'shredder'
|
3
|
-
raise "Need Shredder version ~> 0.1" if Shredder::VERSION < '0.1'
|
4
2
|
|
5
|
-
#
|
6
|
-
|
7
|
-
def self.version
|
8
|
-
puts Shredder::VERSION
|
9
|
-
exit(0)
|
10
|
-
end
|
3
|
+
# Gems:
|
4
|
+
require 'help_parser'
|
11
5
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
shredder --io --shred shred_file1 shred_file2... # shred stdin to shreds
|
16
|
-
shredder --sew sewed_file shred_file1 shred_file2... # sew shreds back to file
|
17
|
-
shredder --io --sew shred_file1 shred_file2... # sew shreds out to stdout
|
18
|
-
# --relay in sew mode will relay the first gets from stdin (used to pass on a passphrase to gpg, for example).
|
19
|
-
EOT
|
20
|
-
print "# VERSION: "
|
21
|
-
CommandLine.version
|
22
|
-
end
|
6
|
+
# This Gem:
|
7
|
+
require 'shredder'
|
8
|
+
include SHREDDER
|
23
9
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
# validate
|
33
|
-
raise "--sew or --shred ?" if !(options=~/--sew\b/) && !(options=~/--shred\b/)
|
34
|
-
length = ARGV.length
|
35
|
-
raise "Expected sew shred1 shred2 ..." if length < 2 && !(options=~/--io\b/)
|
36
|
-
raise "Expected shred1 shred2..." if length < 1
|
37
|
-
return options
|
38
|
-
end
|
10
|
+
NAME = File.basename $0 # Program Name
|
11
|
+
HELP = <<HELP
|
12
|
+
Usage: #{NAME} [options] [file] shred1 shred2...
|
13
|
+
Options:
|
14
|
+
-r --shred Shred a file to shreds.
|
15
|
+
-w --sew Sew shreds back to file.
|
16
|
+
-s --io Shreds/sews from/to stdin/stdout respectively.
|
17
|
+
--relay Relay first stdin gets to stdout puts.
|
39
18
|
|
40
|
-
|
41
|
-
|
42
|
-
@shredding = (options=~/--shred\b/)? true : false
|
43
|
-
@relay = (options=~/--relay\b/)? true : false
|
44
|
-
if options=~/--io/ then
|
45
|
-
if @shredding then
|
46
|
-
@sew = $stdin
|
47
|
-
@shreds = ARGV.map{|filename| File.open(filename,'w')} # WRITE SHREDS
|
48
|
-
else
|
49
|
-
@sew = $stdout
|
50
|
-
@shreds = ARGV.map{|filename| File.open(filename,'r')} # READ SHREDS
|
51
|
-
end
|
52
|
-
else
|
53
|
-
@sew = ARGV.shift
|
54
|
-
@shreds = ARGV
|
55
|
-
end
|
56
|
-
end
|
19
|
+
-h --help Puts this help and exits.
|
20
|
+
-v --version Puts version and exits.
|
57
21
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
# In a typical situation, we may be asked to relay a passphrase
|
66
|
-
$stdout.puts passphrase
|
67
|
-
end
|
68
|
-
shredder.sew
|
69
|
-
end
|
70
|
-
rescue StandardError
|
71
|
-
$stderr.puts $!
|
72
|
-
$stderr.puts $!.backtrace if $verbose
|
73
|
-
ensure
|
74
|
-
@shreds.each{|filehandle| filehandle.close} if !(@sew.class == String)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
22
|
+
-f --force These are not implemented yet,
|
23
|
+
--yes but are defined to provide
|
24
|
+
--no a symmetry with commands like gpg.
|
25
|
+
Note:
|
26
|
+
Typical use of relay is for passphrase.
|
27
|
+
Version: #{VERSION}
|
28
|
+
HELP
|
78
29
|
|
79
30
|
begin
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
31
|
+
OPTIONS = HELP_PARSER::HelpParser.new(VERSION, HELP)
|
32
|
+
OPTIONS.defaults!(:shred, false, true)
|
33
|
+
OPTIONS.defaults!(:sew, false, true)
|
34
|
+
OPTIONS.usage_error "Need choice: sew or shred?" unless OPTIONS[:sew] ^ OPTIONS[:shred] # xor
|
35
|
+
MIN = (OPTIONS[:io])? 2 : 3
|
36
|
+
OPTIONS.usage_error "Need at least 2 shreds" unless ARGV.length >= MIN
|
37
|
+
Shredder.new(OPTIONS, ARGV).execute
|
38
|
+
rescue HELP_PARSER::UsageException
|
39
|
+
puts $!.message
|
40
|
+
rescue HELP_PARSER::UsageError
|
41
|
+
STDERR.puts $!.message
|
42
|
+
exit 64
|
84
43
|
end
|
@@ -0,0 +1,72 @@
|
|
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)
|
@@ -0,0 +1,77 @@
|
|
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.rb
CHANGED
@@ -1,35 +1,8 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'shredder/version'
|
2
|
+
require 'shredder/functions'
|
3
|
+
require 'shredder/files'
|
4
|
+
require 'shredder/streams'
|
5
|
+
require 'shredder/shredder'
|
3
6
|
|
4
|
-
|
5
|
-
|
6
|
-
shreds = writers.length
|
7
|
-
xor = count = 0
|
8
|
-
while byte = reader.getbyte do
|
9
|
-
writers[ count % shreds ].putc byte^xor
|
10
|
-
xor = byte
|
11
|
-
count += 1
|
12
|
-
# note: will not break if limit is zero
|
13
|
-
break if count == limit
|
14
|
-
end
|
15
|
-
return count
|
16
|
-
end
|
17
|
-
|
18
|
-
# note that these are streams
|
19
|
-
def self.sew(writer,readers,limit=0)
|
20
|
-
shreds = readers.length
|
21
|
-
xor = count = 0
|
22
|
-
while byte = readers[ count % shreds ].getbyte do
|
23
|
-
chr = byte^xor
|
24
|
-
xor = chr
|
25
|
-
writer.putc chr
|
26
|
-
count += 1
|
27
|
-
# note: will not break if limit is zero
|
28
|
-
break if count == limit
|
29
|
-
end
|
30
|
-
return count
|
31
|
-
end
|
32
|
-
|
33
|
-
autoload :Files, 'shredder/files'
|
34
|
-
autoload :Streams, 'shredder/streams'
|
35
|
-
end
|
7
|
+
# Requires:
|
8
|
+
#`ruby`
|
data/lib/shredder/files.rb
CHANGED
@@ -1,20 +1,23 @@
|
|
1
|
-
module
|
1
|
+
module SHREDDER
|
2
|
+
|
2
3
|
class Files
|
4
|
+
extend Functions
|
5
|
+
|
3
6
|
# this one takes filenames
|
4
|
-
def initialize(sew,shreds,limit=0)
|
5
|
-
@sew
|
7
|
+
def initialize(sew, shreds, limit=0)
|
8
|
+
@sew = sew
|
6
9
|
@shreds = shreds
|
7
|
-
@limit
|
10
|
+
@limit = limit
|
8
11
|
end
|
9
12
|
|
10
13
|
def shred(limit=@limit)
|
11
|
-
reader
|
14
|
+
reader = File.open(@sew, 'r')
|
12
15
|
writers = []
|
13
|
-
@shreds.each{|shred| writers.push(
|
16
|
+
@shreds.each{|shred| writers.push(File.open(shred, 'wb'))}
|
14
17
|
|
15
18
|
count = nil
|
16
19
|
begin
|
17
|
-
count =
|
20
|
+
count = Files.shred(reader, writers, limit)
|
18
21
|
rescue Exception
|
19
22
|
raise $!
|
20
23
|
ensure
|
@@ -26,13 +29,13 @@ module Shredder
|
|
26
29
|
end
|
27
30
|
|
28
31
|
def sew(limit=@limit)
|
29
|
-
writer
|
32
|
+
writer = File.open(@sew, 'wb')
|
30
33
|
readers = []
|
31
|
-
@shreds.each{|shred| readers.push(
|
34
|
+
@shreds.each{|shred| readers.push(File.open(shred, 'r'))}
|
32
35
|
|
33
36
|
count = nil
|
34
37
|
begin
|
35
|
-
count =
|
38
|
+
count = Files.sew(writer, readers, limit)
|
36
39
|
rescue Exception
|
37
40
|
raise $!
|
38
41
|
ensure
|
@@ -42,5 +45,7 @@ module Shredder
|
|
42
45
|
|
43
46
|
return count
|
44
47
|
end
|
48
|
+
|
45
49
|
end
|
50
|
+
|
46
51
|
end
|
@@ -0,0 +1,36 @@
|
|
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
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module SHREDDER
|
2
|
+
|
3
|
+
class Shredder
|
4
|
+
|
5
|
+
attr_reader :shreds, :sewed
|
6
|
+
def initialize(options={}, shreds=[], sewed=nil)
|
7
|
+
@shreds, @sewed = shreds, sewed
|
8
|
+
@shred = options[:shred]
|
9
|
+
@relay = options[:relay]
|
10
|
+
if @sewed.nil?
|
11
|
+
if options[:io]
|
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
|
34
|
+
end
|
35
|
+
|
36
|
+
def shred(sewed, *shreds)
|
37
|
+
execute(sewed, shreds, true)
|
38
|
+
end
|
39
|
+
|
40
|
+
def sew(sewed, *shreds)
|
41
|
+
execute(sewed, shreds, false)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
data/lib/shredder/streams.rb
CHANGED
@@ -1,18 +1,23 @@
|
|
1
|
-
module
|
1
|
+
module SHREDDER
|
2
|
+
|
2
3
|
class Streams
|
4
|
+
extend Functions
|
5
|
+
|
3
6
|
# this one takes streams
|
4
|
-
def initialize(sew,shreds,limit=0)
|
5
|
-
@sew
|
7
|
+
def initialize(sew, shreds, limit=0)
|
8
|
+
@sew = sew
|
6
9
|
@shreds = shreds
|
7
|
-
@limit
|
10
|
+
@limit = limit
|
8
11
|
end
|
9
12
|
|
10
13
|
def shred(limit=@limit)
|
11
|
-
|
14
|
+
Streams.shred(@sew,@shreds,limit)
|
12
15
|
end
|
13
16
|
|
14
17
|
def sew(limit=@limit)
|
15
|
-
|
18
|
+
Streams.sew(@sew,@shreds,limit)
|
16
19
|
end
|
20
|
+
|
17
21
|
end
|
22
|
+
|
18
23
|
end
|
data/shredder.gemspec
ADDED
@@ -0,0 +1,55 @@
|
|
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
|
@@ -0,0 +1,140 @@
|
|
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
|
metadata
CHANGED
@@ -1,73 +1,131 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: shredder
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 2
|
9
|
-
- 0
|
10
|
-
version: 0.2.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
11
5
|
platform: ruby
|
12
|
-
authors:
|
13
|
-
-
|
6
|
+
authors:
|
7
|
+
- CarlosJHR64
|
14
8
|
autorequire:
|
15
9
|
bindir: bin
|
16
10
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
date: 2014-01-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: help_parser
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.1'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.1.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.1'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.1.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: test-unit
|
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
|
21
73
|
description: |
|
22
|
-
|
23
|
-
such that no one depository has the entire file.
|
24
|
-
Note: These are not file segments, they're shreds.
|
74
|
+
Shred a file into file fragments, and join fragments back into a restored file.
|
25
75
|
|
76
|
+
Disperse file shreds in separate depositories
|
77
|
+
so that no one depository has the entire file.
|
26
78
|
email: carlosjhr64@gmail.com
|
27
|
-
executables:
|
79
|
+
executables:
|
28
80
|
- shredder
|
29
81
|
extensions: []
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
-
|
35
|
-
-
|
36
|
-
- ./lib/shredder.rb
|
37
|
-
- ./README.txt
|
82
|
+
extra_rdoc_files:
|
83
|
+
- README.rdoc
|
84
|
+
files:
|
85
|
+
- History.txt
|
86
|
+
- README.rdoc
|
87
|
+
- TODO.txt
|
38
88
|
- bin/shredder
|
39
|
-
|
40
|
-
|
41
|
-
|
89
|
+
- features/main.feature
|
90
|
+
- features/step_definitions/main_steps.rb
|
91
|
+
- lib/shredder.rb
|
92
|
+
- lib/shredder/files.rb
|
93
|
+
- lib/shredder/functions.rb
|
94
|
+
- lib/shredder/shredder.rb
|
95
|
+
- lib/shredder/streams.rb
|
96
|
+
- lib/shredder/version.rb
|
97
|
+
- shredder.gemspec
|
98
|
+
- test/test_shredder.rb
|
99
|
+
homepage: https://github.com/carlosjhr64/shredder
|
100
|
+
licenses:
|
101
|
+
- MIT
|
102
|
+
metadata: {}
|
42
103
|
post_install_message:
|
43
|
-
rdoc_options:
|
44
|
-
|
45
|
-
|
104
|
+
rdoc_options:
|
105
|
+
- "--main"
|
106
|
+
- README.rdoc
|
107
|
+
require_paths:
|
46
108
|
- lib
|
47
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
-
|
49
|
-
requirements:
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
50
111
|
- - ">="
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
version: "0"
|
56
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
|
-
requirements:
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
59
116
|
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
requirements:
|
120
|
+
- 'ruby: ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-linux]'
|
121
|
+
- 'bash in development: GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu)'
|
122
|
+
- 'system in development: linux/bash'
|
123
|
+
- 'rm in development: rm (GNU coreutils) 8.13'
|
124
|
+
- 'diff in development: diff (GNU diffutils) 3.2'
|
67
125
|
rubyforge_project:
|
68
|
-
rubygems_version:
|
126
|
+
rubygems_version: 2.2.0
|
69
127
|
signing_key:
|
70
|
-
specification_version:
|
71
|
-
summary: Shred a file into file fragments, and join fragments back into a restored
|
128
|
+
specification_version: 4
|
129
|
+
summary: Shred a file into file fragments, and join fragments back into a restored
|
130
|
+
file.
|
72
131
|
test_files: []
|
73
|
-
|
data/README.txt
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
### SYNOPSIS ###
|
2
|
-
|
3
|
-
require 'shredder'
|
4
|
-
|
5
|
-
# Shreds text.txt into test.f.1, test.f.2, test.f.3
|
6
|
-
Shredder::Files.new('README.txt', ['test.f.1','test.f.2','test.f.3'] ).shred
|
7
|
-
|
8
|
-
# Sews test.f.1, test.f.2, test.f.3 into restored.f.txt
|
9
|
-
Shredder::Files.new('restored.f.txt', ['test.f.1','test.f.2','test.f.3'] ).sew
|
10
|
-
|
11
|
-
# or #
|
12
|
-
|
13
|
-
# shred streams #
|
14
|
-
reader = File.open('README.txt','r')
|
15
|
-
writers = []; ['test.s.1','test.s.2','test.s.3'].each{|writer| writers.push(File.open(writer,'wb'))}
|
16
|
-
Shredder::Streams.new(reader,writers).shred
|
17
|
-
reader.close
|
18
|
-
writers.each{|writer| writer.close}
|
19
|
-
|
20
|
-
# sew streams
|
21
|
-
writer = File.open('restored.s.txt','wb')
|
22
|
-
readers = []; ['test.s.1','test.s.2','test.s.3'].each{|writer| readers.push(File.open(writer,'r'))}
|
23
|
-
Shredder::Streams.new(writer,readers).sew
|
24
|
-
writer.close
|
25
|
-
readers.each{|reader| reader.close}
|
26
|
-
|
27
|
-
# Also available, Shredder.shred( writer, readers) and Shredder.sew( reader, writers )
|
28
|
-
# and a command line utility, shredder (run shredder --help for more info).
|