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 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