shredder 0.2.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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).
|