refactor a lot, add tests, add readme

This commit is contained in:
VetheonGames 2023-09-19 22:24:23 -06:00
parent 890402e424
commit ca5d108478
5 changed files with 204 additions and 31 deletions

View File

@ -1,5 +0,0 @@
## [Unreleased]
## [0.1.0] - 2023-09-19
- Initial release

View File

@ -1,39 +1,97 @@
# Actionhash
# ActionHash
TODO: Delete this and the text below, and describe your gem
## Overview
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/actionhash`. To experiment with that code, run `bin/console` for an interactive prompt.
ActionHash is a Ruby gem designed to validate a series of actions while obfuscating the associated data. It's particularly useful in scenarios where you want to ensure the integrity of a sequence of actions or data points, such as in gaming, financial transactions, IoT devices, and more.
> :warning: **Security Note**: While ActionHash does obfuscate data, it should not be considered a form of encryption. If someone gains access to the generated secret key, the hashes can be undone. Use this gem as a part of your security strategy, not as the sole mechanism for securing sensitive information.
## Installation
TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
```bash
gem install actionhash
```
Install the gem and add to the application's Gemfile by executing:
Or add it to your Gemfile:
$ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
```ruby
gem 'actionhash'
```
If bundler is not being used to manage dependencies, install the gem by executing:
Then run:
$ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
```bash
bundle install
```
## Usage
## Basic Usage
TODO: Write usage instructions here
Here's a simple example to get you started:
## Development
```ruby
require 'actionhash'
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
# Initialize
keys = [ActionHash.generate_new_key]
hashes = [] # Array to store finished hashes
action_count = 0
prev_hash = '0'
data = "some_data"
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
# Create a hash
new_hash = ActionHash.create(prev_hash, data, keys.last)
hashes << new_hash # Store the hash
```
## Contributing
### Validating a Hash
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/actionhash. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/actionhash/blob/master/CODE_OF_CONDUCT.md).
You can validate a hash using the `valid_hash?` method as follows:
## License
```ruby
# Validate the hash
is_valid = ActionHash.valid_hash?(hashes.last, keys.last, 20)
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
if is_valid
puts "Hash is valid."
else
puts "Hash is invalid."
end
```
## Code of Conduct
The `valid_hash?` method works by recursively decrypting the hash and checking if it reaches a base hash of '0'. It takes the hash, the key, and an optional level parameter to limit the depth of validation.
Here's the method definition for your reference:
```ruby
def self.valid_hash?(hash, key, level = 20)
current_level = 0
loop do
puts "Debug: Validating hash=#{hash} with key=#{key} at level=#{current_level}"
return false if current_level >= level
decrypted_data = down_layer(hash, key)
return true if decrypted_data[:prev_hash] == '0'
return false if decrypted_data[:prev_hash].nil? || decrypted_data[:prev_hash].empty?
hash = decrypted_data[:prev_hash]
current_level += 1
end
end
```
## Development Builds
For those interested in using development builds of ActionHash, you can install them directly from our Gem server hosted at PixelRidge Softworks.
Here's how you can install a development build:
```bash
gem install ActionHash --source "https://git.pixelridgesoftworks.com/api/packages/PixelRidge-Softworks/rubygems"
```
As an example, if you want to install a different gem from our Gem server, you can use the following command:
```bash
gem install Miniparser --source "https://git.pixelridgesoftworks.com/api/packages/PixelRidge-Softworks/rubygems"
```
Everyone interacting in the Actionhash project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/actionhash/blob/master/CODE_OF_CONDUCT.md).

View File

@ -9,7 +9,8 @@ Gem::Specification.new do |spec|
spec.email = ['ceo@pixelridgesoftworks.com']
spec.summary = 'A custom hash mechanism for action tracking and validation.'
spec.description = 'ActionHash provides a way to create and validate custom hashes for tracking user actions in a secure and efficient manner.'
spec.description = 'ActionHash provides a way to create and validate custom hashes for tracking user actions in a
secure and efficient manner.'
spec.homepage = 'https://git.pixelridgesoftworks.com/PixelRidge-Softworks/ActionHash'
spec.license = 'PixelRidge-BEGPULSE'
spec.required_ruby_version = '>= 3.2.2'
@ -27,7 +28,4 @@ Gem::Specification.new do |spec|
spec.bindir = 'exe'
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
spec.require_paths = ['lib']
# Uncomment to register a new dependency of your gem
spec.add_dependency "dotenv", "~> 2.7"
end

View File

@ -1,28 +1,68 @@
# frozen_string_literal: true
require_relative 'actionhash/version'
require 'securerandom'
# main module
module ActionHash
class Error < StandardError; end
@key_usage_count = {}
MAX_ACTIONS_PER_KEY = 10
# Generate a new key
def self.generate_new_key
SecureRandom.hex(8)
end
# Create a new Action Hash
def self.create(prev_hash, input_data, key)
# Check if the key has reached its limit
@key_usage_count[key] ||= 0
if @key_usage_count[key] >= MAX_ACTIONS_PER_KEY
raise Error, 'Key has reached its maximum usage. Please generate a new key.'
end
data = [prev_hash, input_data].join(',')
puts "Debug: Creating hash with prev_hash=#{prev_hash}, input_data=#{input_data}, key=#{key}"
puts "Concatenated data before encryption: #{data}"
encrypted_data = xor_encrypt(data, key)
encrypted_data.unpack1('H*') # Convert to hex
encrypted_hex = encrypted_data.unpack1('H*') # Convert to hex
puts "Encrypted hex: #{encrypted_hex}"
# Increment the usage count for the key
@key_usage_count[key] += 1
encrypted_hex
end
# Decrypt an Action Hash to its components
def self.down_layer(hash, key)
puts "Debug: Decrypting hash=#{hash} with key=#{key}"
hex_decoded = [hash].pack('H*') # Convert from hex
decrypted_data = xor_encrypt(hex_decoded, key)
puts "Decrypted data: #{decrypted_data}"
prev_hash, input_data = decrypted_data.split(',')
{ prev_hash: prev_hash.to_i, input_data: input_data.to_i }
{ prev_hash: prev_hash.to_s, input_data: input_data.to_s }
end
# XOR encrypt/decrypt (symmetric)
def self.xor_encrypt(data, key)
data.bytes.zip(key.bytes.cycle).map { |a, b| (a ^ b).chr }.join
end
# Validate if a hash can be traced back to '0'
def self.valid_hash?(hash, key, level = 20)
current_level = 0
loop do
puts "Debug: Validating hash=#{hash} with key=#{key} at level=#{current_level}"
return false if current_level >= level
decrypted_data = down_layer(hash, key)
return true if decrypted_data[:prev_hash] == '0'
return false if decrypted_data[:prev_hash].nil? || decrypted_data[:prev_hash].empty?
hash = decrypted_data[:prev_hash]
current_level += 1
end
end
end

82
tests/hash_generator.rb Normal file
View File

@ -0,0 +1,82 @@
# frozen_string_literal: true
require 'actionhash' # Update this path to where your ActionHash module is located
class ActionHashTest
def initialize
@keys = [ActionHash.generate_new_key] # Initialize an array to store keys
puts "Generated key: #{@keys.last}"
@hashes = []
@action_count = 0
end
def run_test(depth)
prev_hash = '0'
data = 30
depth.times do |i|
puts "Layer #{i + 1}:"
# Check if the key has reached its limit and generate a new one if necessary
if @action_count >= ActionHash::MAX_ACTIONS_PER_KEY
@keys << ActionHash.generate_new_key # Generate and store a new key
puts "Generated new key: #{@keys.last}"
@action_count = 0
prev_hash = '0' # Reset prev_hash for the new key
end
current_key = @keys.last # Use the last key in the array
new_hash = ActionHash.create(prev_hash, data.to_s, current_key)
puts "Generated hash: #{new_hash}"
@hashes << { hash: new_hash, key: current_key }
prev_hash = new_hash
data *= 2
@action_count += 1
end
validate_hashes
end
def validate_hashes
puts "\nValidating hashes..."
all_valid = true
prev_hash = '0' # Initialize prev_hash to '0' as in the run_test method
current_key_index = 0 # Initialize index to keep track of the current key
@hashes.each_with_index do |hash_data, index|
hash = hash_data[:hash]
key = hash_data[:key]
# Check if we need to switch to the next key
if current_key_index < @keys.length - 1 && key != @keys[current_key_index]
current_key_index += 1
prev_hash = '0' # Reset prev_hash for the new key
end
decrypted_data = ActionHash.down_layer(hash, key)
puts "Decrypted data: #{decrypted_data[:prev_hash]},#{decrypted_data[:input_data]}"
puts "Current level: #{index + 1}"
puts "Current hash: #{hash}"
if decrypted_data[:prev_hash] != prev_hash
puts "Hash at level #{index + 1} is invalid."
all_valid = false
break
end
prev_hash = hash # Update prev_hash for the next iteration
end
puts all_valid ? 'All hashes are valid.' : 'Hash validation failed.'
end
end
if ARGV.length != 1 || !ARGV[0].match?(/^\d+$/)
puts "Usage: ruby #{__FILE__} [depth]"
exit 1
end
depth = ARGV[0].to_i
test = ActionHashTest.new
test.run_test(depth)