safeguard 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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 files specified' or exit if ARGV.empty?
4
+ puts 'No command given' or exit if ARGV.empty?
5
5
 
6
- ARGV.each do |filename|
7
- puts "#{Safeguard.file filename} => #{filename}"
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'
@@ -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 filename
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
@@ -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
- PATCH = 1
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/digest'
1
+ require 'safeguard/command'
2
2
 
3
+ # Safeguard module.
3
4
  module Safeguard
4
5
 
5
- def self.file(filename)
6
- Digest.file filename
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.1
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-14 00:00:00.000000000 Z
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