NETRAVE/lib/utils/utilities.rb
VetheonGames e4df29b0c1 Implementing Thread-Safe Alert System with Ring Buffer
This commit introduces a significant enhancement to our Ruby program by implementing a thread-safe alert system using a ring buffer data structure.

New Classes:
1. Alert: This class is responsible for creating and displaying alerts in the Curses Text User Interface (TUI). It takes a message and severity level as arguments and uses these to display color-coded alerts to the user.

2. AlertQueueManager: This class manages the queues for alerts using a ring buffer data structure. It continuously checks the queue and displays alerts as they arrive. It uses a mutex lock to ensure thread safety when accessing the ring buffer.

3. RingBuffer: This class is a custom implementation of a ring buffer, also known as a circular buffer. It's a fixed-size buffer that effectively overwrites old data when it is full. The buffer size has been optimized to 2MB to balance memory usage and performance.

Modifications to Existing Methods:
The DatabaseManager class has been updated to integrate the new alert system. The methods in this class now create Alert instances and enqueue them in the AlertQueueManager instead of directly displaying alerts to the user. This change ensures that alerts are displayed in a thread-safe manner and allows for better control over the timing and order of alert displays.

Thread Safety Measures:
Mutex locks and condition variables have been used to synchronize access to the ring buffer and prevent race conditions. This ensures that only one thread can access the buffer at a time, preventing data corruption and ensuring the correct operation of the alert system.

Testing:
Rigorous testing has been conducted to validate the correct functioning of the new system and to handle edge cases. This includes tests for the correct display of alerts, the correct operation of the ring buffer, and the correct synchronization of threads.

Documentation:
Detailed comments have been added to the code to explain the purpose and operation of the new classes and methods. This documentation will serve as a valuable reference for future development and maintenance of the codebase.

This commit represents a significant improvement in the functionality and robustness of our Ruby program's alert system.
2023-07-05 12:35:20 -06:00

117 lines
3.5 KiB
Ruby

# frozen_string_literal: true
require 'securerandom'
require 'digest'
require 'base64'
require 'openssl'
require 'sudo'
# Utiltiies Module
module Utilities
# Converts speed from Gbps to Mbps if necessary
def convert_speed_to_mbps(speed)
return nil unless speed.is_a?(String) && speed.downcase.match?(/\A\d+(gbps|mbps)\z/i)
# Extract the numeric part and the unit from the speed
numeric_speed, unit = speed.downcase.match(/(\d+)(gbps|mbps)/i).captures
# Convert the numeric part to an integer
numeric_speed = numeric_speed.to_i
# If the unit is 'gbps', multiply the numeric part by 1000
numeric_speed *= 1000 if unit == 'gbps'
numeric_speed
end
# Converts an array of services into a hash
def services_to_hash(services)
services_hash = {}
services.each { |service| services_hash[service] = true }
services_hash
end
# Calculates total bandwidth from uplink and downlink speeds
def calculate_total_bandwidth(uplink_speed, downlink_speed)
uplink_speed + downlink_speed
end
def generate_key
Base64.encode64(SecureRandom.bytes(32)).chomp
end
def encrypt_string_chacha20(data, key)
return nil if data.nil? || key.nil?
cipher = OpenSSL::Cipher.new('chacha20')
cipher.encrypt
cipher.key = Base64.decode64(key) # Decode the key from Base64
encrypted_data = cipher.update(data) + cipher.final
Base64.encode64(encrypted_data).chomp
rescue OpenSSL::Cipher::CipherError => e
@loggman.log_error("Failed to encrypt data: #{e.message}")
nil
end
def decrypt_string_chacha20(encrypted_data, key) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
return nil if encrypted_data.nil? || key.nil?
cipher = OpenSSL::Cipher.new('chacha20')
cipher.decrypt
cipher.key = Base64.decode64(key) # Decode the key from Base64
decrypted_data = cipher.update(Base64.decode64(encrypted_data)) + cipher.final
# Check if the decrypted data is valid ASCII
decrypted_data.force_encoding('UTF-8')
if decrypted_data.valid_encoding?
decrypted_data
else
@loggman.log_error("Decrypted data is not valid ASCII: #{decrypted_data.inspect}")
nil
end
rescue OpenSSL::Cipher::CipherError => e
@loggman.log_error("Failed to decrypt data: #{e.message}")
nil
end
def ask_for_sudo(logger)
@loggman = logger
@loggman.log_info('Asking for sudo password...')
Curses.addstr('Please enter your sudo password: ')
sudo_password = DCI.catch_input(true)
@loggman.log_info('Sudo password received.')
sudo_password
end
def test_and_deescalate_sudo(sudo_password)
# Run a simple command with sudo privileges
Sudo::Wrapper.run('ls', password: sudo_password)
# Invalidate the user's cached credentials
Sudo::Wrapper.run('sudo -k', password: sudo_password)
# Encrypt the sudo password and store it in an environment variable
encrypted_sudo_password = encrypt_string_chacha20(sudo_password, @secret_key)
ENV['SPW'] = encrypted_sudo_password
true
rescue Sudo::Wrapper::InvalidPassword
false
end
def clear_sudo_password
# Retrieve the encrypted sudo password from the environment variable
encrypted_sudo_password = ENV['SPW']
# Decrypt the sudo password
sudo_password = decrypt_string_chacha20(encrypted_sudo_password, @secret_key)
# Clear the sudo password from memory
sudo_password.replace(' ' * sudo_password.length)
# Remove the encrypted sudo password from the environment variables
ENV.delete('SPW')
end
end