safeguard 0.0.1 → 0.0.2
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.
- data/.gitignore +1 -0
- data/LICENSE.GPLv3 +14 -0
- data/bin/safeguard +3 -4
- data/lib/safeguard/command/add.rb +32 -0
- data/lib/safeguard/command/hash.rb +22 -0
- data/lib/safeguard/command/init.rb +26 -0
- data/lib/safeguard/command/verify.rb +34 -0
- data/lib/safeguard/command.rb +45 -0
- data/lib/safeguard/digest.rb +4 -1
- data/lib/safeguard/hash_table.rb +71 -0
- data/lib/safeguard/repository.rb +73 -0
- data/lib/safeguard/version.rb +20 -1
- data/lib/safeguard.rb +5 -3
- metadata +11 -2
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
.safeguard/
|
data/LICENSE.GPLv3
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Copyright © 2011 Matheus Afonso Martins Moreira
|
2
|
+
|
3
|
+
This program is free software: you can redistribute it and/or modify
|
4
|
+
it under the terms of the GNU General Public License as published by
|
5
|
+
the Free Software Foundation, either version 3 of the License, or
|
6
|
+
(at your option) any later version.
|
7
|
+
|
8
|
+
This program is distributed in the hope that it will be useful,
|
9
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
GNU General Public License for more details.
|
12
|
+
|
13
|
+
You should have received a copy of the GNU General Public License
|
14
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
data/bin/safeguard
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'safeguard'
|
3
3
|
|
4
|
-
puts 'No
|
4
|
+
puts 'No command given' or exit if ARGV.empty?
|
5
5
|
|
6
|
-
ARGV.
|
7
|
-
|
8
|
-
end
|
6
|
+
command = ARGV.shift
|
7
|
+
Safeguard.run(command, *ARGV)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'safeguard/command'
|
2
|
+
|
3
|
+
module Safeguard
|
4
|
+
module Command
|
5
|
+
|
6
|
+
# Adds files to a Repository.
|
7
|
+
module Add
|
8
|
+
|
9
|
+
Command.register self
|
10
|
+
|
11
|
+
# For every argument, try to add it to the Repository in the current
|
12
|
+
# directory.
|
13
|
+
def self.execute(*args)
|
14
|
+
repo = Repository.new Dir.pwd
|
15
|
+
count = 0
|
16
|
+
args.each do |filename|
|
17
|
+
begin
|
18
|
+
puts "Adding #{filename}..."
|
19
|
+
repo.track filename
|
20
|
+
# If an exception is raised, count will not be incremented.
|
21
|
+
count += 1
|
22
|
+
rescue => e
|
23
|
+
puts e.message
|
24
|
+
end
|
25
|
+
end
|
26
|
+
puts "Added #{count} files to repository."
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'safeguard/command'
|
2
|
+
require 'safeguard/digest'
|
3
|
+
|
4
|
+
module Safeguard
|
5
|
+
module Command
|
6
|
+
|
7
|
+
# Outputs the SHA1 hash of files.
|
8
|
+
module Hash
|
9
|
+
|
10
|
+
Command.register self
|
11
|
+
|
12
|
+
# For every argument, outputs its SHA1 sum if it exists as a file.
|
13
|
+
def self.execute(*args)
|
14
|
+
args.each do |filename|
|
15
|
+
puts "#{Digest.file filename} => #{filename}" if File.file? filename
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'safeguard/command'
|
2
|
+
require 'safeguard/repository'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module Safeguard
|
6
|
+
module Command
|
7
|
+
|
8
|
+
# Initializes a Repository in a given directory.
|
9
|
+
module Init
|
10
|
+
|
11
|
+
Command.register self
|
12
|
+
|
13
|
+
# Initializes a Safeguard Repository in a directory, which is either the
|
14
|
+
# current directory, if +args+ is empty, or the directory designated by
|
15
|
+
# the last element in +args+.
|
16
|
+
def self.execute(*args)
|
17
|
+
args << Dir.pwd if args.empty?
|
18
|
+
dir = File.expand_path args.pop
|
19
|
+
repo = Repository.new(dir)
|
20
|
+
puts "Initialized safeguard repository in #{repo.dir}"
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'safeguard/command'
|
2
|
+
|
3
|
+
module Safeguard
|
4
|
+
module Command
|
5
|
+
|
6
|
+
# Verifies the files present in a Repository.
|
7
|
+
module Verify
|
8
|
+
|
9
|
+
Command.register self
|
10
|
+
|
11
|
+
# Verify the files passed as arguments using information from the
|
12
|
+
# Repository in the current directory.
|
13
|
+
def self.execute(*args)
|
14
|
+
repo = Repository.new Dir.pwd
|
15
|
+
if args.empty?
|
16
|
+
repo.verify_all do |filename, result|
|
17
|
+
display_result filename, result
|
18
|
+
end
|
19
|
+
else
|
20
|
+
args.each do |filename|
|
21
|
+
result = repo.verify filename
|
22
|
+
display_result filename, result
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.display_result(filename, result)
|
28
|
+
puts "#{filename} => #{result ? 'OK' : 'Mismatch'}"
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Safeguard
|
2
|
+
|
3
|
+
# Manages the commands that may be given to Safeguard.
|
4
|
+
module Command
|
5
|
+
|
6
|
+
instance_eval do
|
7
|
+
|
8
|
+
# Returns a hash that associates command modules by name.
|
9
|
+
def commands
|
10
|
+
@commands ||= {}
|
11
|
+
end
|
12
|
+
|
13
|
+
alias :all :commands
|
14
|
+
|
15
|
+
# Computes a name for the command and associates it with the command's
|
16
|
+
# module.
|
17
|
+
def register(command_module)
|
18
|
+
name = command_module.name.gsub(/^.*::/, '').downcase
|
19
|
+
commands[name] = command_module
|
20
|
+
end
|
21
|
+
|
22
|
+
# Looks up a command by name and returns its module, raising an exception
|
23
|
+
# if there is no match.
|
24
|
+
def find(command_name)
|
25
|
+
name = command_name.to_s.strip.downcase
|
26
|
+
commands[name].tap do |command|
|
27
|
+
raise "unsupported command: #{name}" if command.nil?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Attempts to find a command by name, and, if successful, invokes it with
|
32
|
+
# the given arguments.
|
33
|
+
def invoke(command_name, *args)
|
34
|
+
find(command_name).execute(*args)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
require 'safeguard/command/add'
|
43
|
+
require 'safeguard/command/hash'
|
44
|
+
require 'safeguard/command/init'
|
45
|
+
require 'safeguard/command/verify'
|
data/lib/safeguard/digest.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
require 'openssl'
|
2
2
|
|
3
3
|
module Safeguard
|
4
|
+
|
5
|
+
# Encapsulates checksum computation for files using a set of hash functions.
|
4
6
|
module Digest
|
5
7
|
|
8
|
+
# Compute the SHA1 sum of a file.
|
6
9
|
def self.file(filename)
|
7
|
-
OpenSSL::Digest::SHA1.file
|
10
|
+
OpenSSL::Digest::SHA1.file(filename).hexdigest
|
8
11
|
end
|
9
12
|
|
10
13
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'safeguard/digest'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Safeguard
|
5
|
+
|
6
|
+
# Holds filename => checksum pairs.
|
7
|
+
class HashTable
|
8
|
+
|
9
|
+
# Initializes an empty HashTable.
|
10
|
+
def initialize
|
11
|
+
@table = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
# Saves the HashTable to a YAML file.
|
15
|
+
def save(filename)
|
16
|
+
File.open("#{filename}.yaml", 'w') do |file|
|
17
|
+
file.puts to_yaml
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Loads the HashTable from a YAML file.
|
22
|
+
def self.load(filename)
|
23
|
+
YAML::load_file "#{filename}.yaml"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Associates the given +filename+ to the computed checksum of the file it
|
27
|
+
# refers to.
|
28
|
+
def <<(filename)
|
29
|
+
@table[filename] = Digest.file filename
|
30
|
+
end
|
31
|
+
|
32
|
+
alias :add :<<
|
33
|
+
|
34
|
+
# Looks up the checksum for the given +filename+.
|
35
|
+
def [](filename)
|
36
|
+
@table[filename]
|
37
|
+
end
|
38
|
+
|
39
|
+
# Recalculates the hash and compares it to the original hash associated with
|
40
|
+
# the given filename.
|
41
|
+
#
|
42
|
+
# If a hash for the given file isn't stored in this table, an exception will
|
43
|
+
# be raised.
|
44
|
+
def verify(filename)
|
45
|
+
hash = @table[filename]
|
46
|
+
raise "File not in repository: #{filename}" unless hash
|
47
|
+
Digest.file(filename) == hash
|
48
|
+
end
|
49
|
+
|
50
|
+
# Verifies all files stored in this table and returns a hash of results
|
51
|
+
# associating a filename with either +true+, when the file's recalculated
|
52
|
+
# hash is equal to the hash stored in this table, or +false+, when
|
53
|
+
# otherwise.
|
54
|
+
#
|
55
|
+
# If a block is given, the filename and the result will be yielded instead.
|
56
|
+
def verify_all
|
57
|
+
files = @table.keys
|
58
|
+
if block_given?
|
59
|
+
files.each { |file| yield file, verify(file) }
|
60
|
+
else
|
61
|
+
{}.tap do |results|
|
62
|
+
files.each do |file|
|
63
|
+
results[file] = verify file
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'safeguard/hash_table'
|
2
|
+
|
3
|
+
module Safeguard
|
4
|
+
|
5
|
+
# Directory which holds file-related data.
|
6
|
+
class Repository
|
7
|
+
|
8
|
+
# Name of the directory in which the Safeguard repository resides.
|
9
|
+
DIRECTORY_NAME = '.safeguard'.freeze
|
10
|
+
|
11
|
+
# Name of the file to which the HashTable is saved.
|
12
|
+
HASH_TABLE_FILE_NAME = 'hash_table'.freeze
|
13
|
+
|
14
|
+
attr_accessor :directory
|
15
|
+
alias :dir :directory
|
16
|
+
|
17
|
+
# Initializes a Safeguard repository in or from the given directory.
|
18
|
+
#
|
19
|
+
# If the given directory does not contain a repository directory, whose name
|
20
|
+
# is defined by the DIRECTORY_NAME constant, it will be created.
|
21
|
+
def initialize(dir)
|
22
|
+
self.directory = Repository.directory_in(dir)
|
23
|
+
FileUtils.mkdir_p directory
|
24
|
+
end
|
25
|
+
|
26
|
+
# Loads this repository's HashTable. Creates a new one if unable to do so.
|
27
|
+
def hash_table
|
28
|
+
HashTable.load hash_table_file_name rescue HashTable.new
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the name of the HashTable file relative to this repository.
|
32
|
+
def hash_table_file_name
|
33
|
+
File.join directory, HASH_TABLE_FILE_NAME
|
34
|
+
end
|
35
|
+
|
36
|
+
# Adds a file to this repository's HashTable, and saves it.
|
37
|
+
def track(filename)
|
38
|
+
table = hash_table_file_name
|
39
|
+
file = File.expand_path filename
|
40
|
+
hash_table.instance_eval do
|
41
|
+
add file
|
42
|
+
save table
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Verifies whether or not the file still matches the original version.
|
47
|
+
#
|
48
|
+
# An exception will be raised if the given file isn't in the repository.
|
49
|
+
def verify(filename)
|
50
|
+
hash_table.verify File.expand_path(filename)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Verifies all files present in this repository, and returns a hash of
|
54
|
+
# results associating a filename with either +true+, when the file is the
|
55
|
+
# same as the original version, or +false+, when otherwise.
|
56
|
+
#
|
57
|
+
# If a block is given, the filename and the result will be yielded instead.
|
58
|
+
def verify_all(&block)
|
59
|
+
hash_table.verify_all &block
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns the path to the repository relative to the given +dir+.
|
63
|
+
def self.directory_in(dir)
|
64
|
+
File.join File.expand_path(dir), DIRECTORY_NAME
|
65
|
+
end
|
66
|
+
|
67
|
+
# Checks whether or not a repository has been created in the given +dir+.
|
68
|
+
def self.initialized?(dir)
|
69
|
+
File.directory? directory_in(dir)
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
data/lib/safeguard/version.rb
CHANGED
@@ -1,11 +1,30 @@
|
|
1
1
|
module Safeguard
|
2
|
+
|
3
|
+
# Contains the current version of Safeguard.
|
2
4
|
module Version
|
3
5
|
|
6
|
+
# Major version.
|
7
|
+
#
|
8
|
+
# Increments denote backward-incompatible changes and additions.
|
4
9
|
MAJOR = 0
|
10
|
+
|
11
|
+
# Minor version.
|
12
|
+
#
|
13
|
+
# Increments denote backward-compatible changes and additions.
|
5
14
|
MINOR = 0
|
6
|
-
|
15
|
+
|
16
|
+
# Patch version.
|
17
|
+
#
|
18
|
+
# Increments denote changes in implementation.
|
19
|
+
PATCH = 2
|
20
|
+
|
21
|
+
# Build version.
|
22
|
+
#
|
23
|
+
# Used for pre-release versions.
|
7
24
|
BUILD = nil
|
8
25
|
|
26
|
+
# Complete version string, which is every individual version number joined
|
27
|
+
# by a dot ('.'), in descending order of prescedence.
|
9
28
|
STRING = [ MAJOR, MINOR, PATCH, BUILD ].compact.join '.'
|
10
29
|
|
11
30
|
end
|
data/lib/safeguard.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
require 'safeguard/
|
1
|
+
require 'safeguard/command'
|
2
2
|
|
3
|
+
# Safeguard module.
|
3
4
|
module Safeguard
|
4
5
|
|
5
|
-
|
6
|
-
|
6
|
+
# Run a command by name with the given arguments.
|
7
|
+
def self.run(command, *args)
|
8
|
+
Command.invoke(command, *args)
|
7
9
|
end
|
8
10
|
|
9
11
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: safeguard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-12-
|
12
|
+
date: 2011-12-15 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Hash-based file integrity verification utility
|
15
15
|
email: matheus.a.m.moreira@gmail.com
|
@@ -18,12 +18,21 @@ executables:
|
|
18
18
|
extensions: []
|
19
19
|
extra_rdoc_files: []
|
20
20
|
files:
|
21
|
+
- .gitignore
|
21
22
|
- .rvmrc
|
23
|
+
- LICENSE.GPLv3
|
22
24
|
- README.markdown
|
23
25
|
- Rakefile
|
24
26
|
- bin/safeguard
|
25
27
|
- lib/safeguard.rb
|
28
|
+
- lib/safeguard/command.rb
|
29
|
+
- lib/safeguard/command/add.rb
|
30
|
+
- lib/safeguard/command/hash.rb
|
31
|
+
- lib/safeguard/command/init.rb
|
32
|
+
- lib/safeguard/command/verify.rb
|
26
33
|
- lib/safeguard/digest.rb
|
34
|
+
- lib/safeguard/hash_table.rb
|
35
|
+
- lib/safeguard/repository.rb
|
27
36
|
- lib/safeguard/version.rb
|
28
37
|
- safeguard.gemspec
|
29
38
|
homepage: https://github.com/matheusmoreira/safeguard
|