diff --git a/.rubocop.yml b/.rubocop.yml index f913acd..cc4712a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,14 +1,10 @@ -# This is an example Rubocop configuration file with all cops enabled. - -# AllCops section defines global settings. -AllCops: - Exclude: - - 'vendor/**/*' # Exclude vendor directory - - 'db/schema.rb' # Exclude database schema file - - 'db/migrate/**/*' # Exclude database migration files - -# Enables all cops. -# Set the value to `true` or `false` to enable/disable all cops. -# You can also enable/disable specific cops individually. -# By default, all cops are enabled. -inherit_from: .rubocop_todo.yml +# The behavior of RuboCop can be controlled via the .rubocop.yml +# configuration file. It makes it possible to enable/disable +# certain cops (checks) and to alter their behavior if they accept +# any parameters. The file can be placed either in your home +# directory or in some project directory. +# +# RuboCop will start looking for the configuration file in the directory +# where the inspected file is and continue its way up to the root directory. +# +# See https://docs.rubocop.org/rubocop/configuration diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml deleted file mode 100644 index 22d74a5..0000000 --- a/.rubocop_todo.yml +++ /dev/null @@ -1,217 +0,0 @@ -# This configuration was generated by -# `rubocop --auto-gen-config --exclude-limit 1000` -# on 2023-06-07 19:34:17 UTC using RuboCop version 1.52.0. -# The point is for the user to remove these configuration records -# one by one as the offenses are removed from the code base. -# Note that changes in the inspected code, or installation of new -# versions of RuboCop, may require this file to be generated again. - -# Offense count: 1 -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: TreatCommentsAsGroupSeparators, ConsiderPunctuation, Include. -# Include: **/*.gemfile, **/Gemfile, **/gems.rb -Bundler/OrderedGems: - Exclude: - - 'lib/Gemfile' - -# Offense count: 1 -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyleAlignWith, Severity. -# SupportedStylesAlignWith: keyword, variable, start_of_line -Layout/EndAlignment: - Exclude: - - 'lib/utils/utilities.rb' - -# Offense count: 3 -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: Width, AllowedPatterns. -Layout/IndentationWidth: - Exclude: - - 'lib/utils/utilities.rb' - -# Offense count: 8 -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: final_newline, final_blank_line -Layout/TrailingEmptyLines: - Exclude: - - 'Modules/advanced_logger.rb' - - 'Modules/firewall_manager.rb' - - 'Modules/nftables_interface.rb' - - 'Modules/packet_manager.rb' - - 'Modules/protection_engine.rb' - - 'lib/utils/database_manager.rb' - - 'lib/utils/system_information_gather.rb' - - 'lib/utils/utilities.rb' - -# Offense count: 9 -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: AllowInHeredoc. -Layout/TrailingWhitespace: - Exclude: - - 'lib/utils/database_manager.rb' - - 'lib/utils/first_run_init.rb' - - 'lib/utils/system_information_gather.rb' - - 'lib/utils/utilities.rb' - -# Offense count: 1 -# Configuration parameters: AllowComments. -Lint/EmptyFile: - Exclude: - - 'TUI/main_tui.rb' - -# Offense count: 1 -# This cop supports safe autocorrection (--autocorrect). -Lint/ScriptPermission: - Exclude: - - 'bin/NETRAVE' - -# Offense count: 1 -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods. -Lint/UnusedMethodArgument: - Exclude: - - 'lib/utils/system_information_gather.rb' - -# Offense count: 5 -# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. -Metrics/AbcSize: - Max: 20 - -# Offense count: 8 -# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. -Metrics/MethodLength: - Max: 19 - -# Offense count: 1 -# Configuration parameters: AllowedNames. -# AllowedNames: module_parent -Naming/ClassAndModuleCamelCase: - Exclude: - - 'lib/utils/GUI_launcher.rb' - -# Offense count: 1 -# Configuration parameters: ExpectMatchingDefinition, CheckDefinitionPathHierarchy, CheckDefinitionPathHierarchyRoots, Regex, IgnoreExecutableScripts, AllowedAcronyms. -# CheckDefinitionPathHierarchyRoots: lib, spec, test, src -# AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS -Naming/FileName: - Exclude: - - 'lib/utils/GUI_launcher.rb' - -# Offense count: 2 -# This cop supports unsafe autocorrection (--autocorrect-all). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: always, conditionals -Style/AndOr: - Exclude: - - 'lib/utils/GUI_launcher.rb' - -# Offense count: 5 -# Configuration parameters: AllowedConstants. -Style/Documentation: - Exclude: - - 'spec/**/*' - - 'test/**/*' - - 'lib/utils/GUI_launcher.rb' - - 'lib/utils/database_manager.rb' - - 'lib/utils/first_run_init.rb' - - 'lib/utils/system_information_gather.rb' - - 'lib/utils/utilities.rb' - -# Offense count: 11 -# This cop supports unsafe autocorrection (--autocorrect-all). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: always, always_true, never -Style/FrozenStringLiteralComment: - Exclude: - - 'Modules/advanced_logger.rb' - - 'Modules/firewall_manager.rb' - - 'Modules/nftables_interface.rb' - - 'Modules/packet_manager.rb' - - 'Modules/protection_engine.rb' - - 'bin/NETRAVE' - - 'lib/utils/GUI_launcher.rb' - - 'lib/utils/database_manager.rb' - - 'lib/utils/first_run_init.rb' - - 'lib/utils/system_information_gather.rb' - - 'lib/utils/utilities.rb' - -# Offense count: 4 -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: MinBodyLength, AllowConsecutiveConditionals. -Style/GuardClause: - Exclude: - - 'lib/utils/first_run_init.rb' - - 'lib/utils/system_information_gather.rb' - -# Offense count: 4 -# This cop supports unsafe autocorrection (--autocorrect-all). -Style/InfiniteLoop: - Exclude: - - 'lib/utils/first_run_init.rb' - - 'lib/utils/system_information_gather.rb' - -# Offense count: 1 -# This cop supports safe autocorrection (--autocorrect). -Style/NegatedWhile: - Exclude: - - 'lib/utils/first_run_init.rb' - -# Offense count: 1 -# This cop supports unsafe autocorrection (--autocorrect-all). -# Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns. -# SupportedStyles: predicate, comparison -Style/NumericPredicate: - Exclude: - - 'spec/**/*' - - 'lib/utils/system_information_gather.rb' - -# Offense count: 1 -# This cop supports safe autocorrection (--autocorrect). -Style/RedundantBegin: - Exclude: - - 'lib/utils/database_manager.rb' - -# Offense count: 9 -# This cop supports safe autocorrection (--autocorrect). -Style/RedundantFileExtensionInRequire: - Exclude: - - 'bin/NETRAVE' - - 'lib/utils/database_manager.rb' - - 'lib/utils/first_run_init.rb' - - 'lib/utils/system_information_gather.rb' - -# Offense count: 1 -# This cop supports unsafe autocorrection (--autocorrect-all). -# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength. -# AllowedMethods: present?, blank?, presence, try, try! -Style/SafeNavigation: - Exclude: - - 'lib/utils/database_manager.rb' - -# Offense count: 40 -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline. -# SupportedStyles: single_quotes, double_quotes -Style/StringLiterals: - Exclude: - - 'bin/NETRAVE' - - 'lib/Gemfile' - - 'lib/utils/GUI_launcher.rb' - - 'lib/utils/database_manager.rb' - - 'lib/utils/first_run_init.rb' - - 'lib/utils/system_information_gather.rb' - -# Offense count: 1 -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: MinSize, WordRegex. -# SupportedStyles: percent, brackets -Style/WordArray: - EnforcedStyle: brackets - -# Offense count: 6 -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. -# URISchemes: http, https -Layout/LineLength: - Max: 239 diff --git a/.ruby-version b/.ruby-version index eca690e..be94e6f 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.0.5 +3.2.2 diff --git a/.vscode/settings.json b/.vscode/settings.json index a8f763c..10d8d5a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,5 @@ { - "ruby.rubocop.autocorrectOnSave": true + "ruby.rubocop.autocorrectOnSave": true, + "ruby.rubocop.configFilePath": "/home/vetheon/VSCode/NETRAVE/.rubocop.yml", + "ruby.rubocop.executePath": "/home/vetheon/.rbenv/shims/" } diff --git a/bin/NETRAVE b/bin/NETRAVE index 3597643..d8d26cd 100644 --- a/bin/NETRAVE +++ b/bin/NETRAVE @@ -1,31 +1,63 @@ #!/usr/bin/env ruby +# frozen_string_literal: true -require 'yaml' -require_relative '../lib/utils/system_information_gather.rb' -require_relative '../lib/utils/database_manager.rb' -require_relative '../lib/utils/first_run_init.rb' +require 'dotenv' +require_relative '../lib/utils/system_information_gather' +require_relative '../lib/utils/database_manager' +require_relative '../lib/utils/first_run_init' +require_relative '../lib/utils/utilities' -# Check if config.yml exists, if not, create it -unless File.exist?('config.yml') - first_run_init = FirstRunInit.new - db_details = first_run_init.ask_for_db_details - first_run_init.write_db_details_to_config_file(db_details) +include Utilities # rubocop:disable Style/MixinUsage + +# Create .env file if it doesn't exist +File.new('.env', 'w') unless File.exist?('.env') + +# Load environment variables from .env file +Dotenv.load + +# Initialize DatabaseManager +db_manager = DatabaseManager.new + +# Get database details from environment variables +db_details = { + username: ENV['DB_USERNAME'], + password: ENV['DB_PASSWORD'], + key: ENV['DB_SECRET_KEY'], + database: ENV['DB_DATABASE'] +} + +# If any of the necessary details are missing, run the first run setup +if db_details.values.any?(&:nil?) + puts 'Missing or incomplete configuration. Running first run setup.' + first_run_init = FirstRunInit.new(db_manager) + first_run_init.run + # Reload environment variables after first run setup + Dotenv.load + db_details = { + username: ENV['DB_USERNAME'], + password: ENV['DB_PASSWORD'], + key: ENV['DB_SECRET_KEY'], + database: ENV['DB_DATABASE'] + } end -# Load database configuration -db_details = YAML.load_file('config.yml') +# Decrypt the password +db_details[:password] = decrypt_string_chacha20(db_details[:password], db_details[:key]) -# Initialize DatabaseManager and test connection -db_manager = DatabaseManager.new +# Test connection +unless db_manager.test_db_connection(db_details) + puts 'Failed to connect to the database with existing configuration. Please re-enter your details.' + first_run_init = FirstRunInit.new(db_manager) + first_run_init.run +end + +# Test connection again after potentially updating config if db_manager.test_db_connection(db_details) - puts "Successfully connected to the database." + puts 'Successfully connected to the database.' else - puts "Failed to connect to the database. Please check your configuration." + puts 'Failed to connect to the database. Please check your configuration.' exit 1 end -# Initialize the first run setup -first_run_setup = FirstRunInit.new(db_manager) -first_run_setup.run - +puts 'Program successfully ran with no errors' # TODO: Add the rest of your application logic here diff --git a/lib/.env b/lib/.env new file mode 100644 index 0000000..e69de29 diff --git a/lib/Gemfile b/lib/Gemfile index d2a097b..153ef0e 100644 --- a/lib/Gemfile +++ b/lib/Gemfile @@ -1,22 +1,32 @@ # frozen_string_literal: true -source "https://rubygems.org" +source 'https://rubygems.org' # gem "rails" -gem "curses", "~> 1.4" gem 'console' +gem 'curses', '~> 1.4' -gem "rubocop", "~> 1.52" +gem 'rubocop', '~> 1.52' -gem "solargraph", "~> 0.49.0" +gem 'solargraph', '~> 0.49.0' -gem "sequel", "~> 5.69" +gem 'sequel', '~> 5.69' -gem "mysql2", "~> 0.5.5" +gem 'mysql2', '~> 0.5.5' -gem "yaml", "~> 0.2.1" +gem 'yaml', '~> 0.2.1' -gem "gtk3", "~> 4.1" +gem 'gtk3', '~> 4.1' -gem "reek", "~> 6.1" +gem 'reek', '~> 6.1' + +gem 'dynamic_curses_input', '~> 1.0' + +gem 'openssl', '~> 3.1' + +gem 'base64', '~> 0.1.1' + +gem 'securerandom', '~> 0.2.2' + +gem 'dotenv', '~> 2.8' diff --git a/lib/Gemfile.lock b/lib/Gemfile.lock index f332d34..7f7e786 100644 --- a/lib/Gemfile.lock +++ b/lib/Gemfile.lock @@ -5,6 +5,7 @@ GEM atk (4.1.7) glib2 (= 4.1.7) backport (1.2.0) + base64 (0.1.1) benchmark (0.2.1) cairo (1.17.8) native-package-installer (>= 1.0.3) @@ -13,11 +14,16 @@ GEM cairo-gobject (4.1.7) cairo (>= 1.16.2) glib2 (= 4.1.7) - console (1.16.2) + console (1.17.2) + fiber-annotation fiber-local curses (1.4.4) diff-lcs (1.5.0) + dotenv (2.8.1) + dynamic_curses_input (1.0.0) + curses e2mmap (0.1.0) + fiber-annotation (0.2.0) fiber-local (1.0.0) fiddle (1.1.1) gdk3 (4.1.7) @@ -49,14 +55,16 @@ GEM native-package-installer (1.1.5) nokogiri (1.15.2-x86_64-linux) racc (~> 1.4) + openssl (3.1.0) pango (4.1.7) cairo-gobject (= 4.1.7) gobject-introspection (= 4.1.7) parallel (1.23.0) - parser (3.2.2.1) + parser (3.2.2.3) ast (~> 2.4.1) + racc pkg-config (1.5.1) - racc (1.6.2) + racc (1.7.0) rainbow (3.1.1) rbs (2.8.4) red-colors (0.3.0) @@ -82,6 +90,7 @@ GEM rubocop-ast (1.29.0) parser (>= 3.2.1.0) ruby-progressbar (1.13.0) + securerandom (0.2.2) sequel (5.69.0) solargraph (0.49.0) backport (~> 1.2) @@ -100,7 +109,7 @@ GEM tilt (~> 2.0) yard (~> 0.9, >= 0.9.24) thor (1.2.2) - tilt (2.1.0) + tilt (2.2.0) unicode-display_width (2.4.2) yaml (0.2.1) yard (0.9.34) @@ -109,12 +118,17 @@ PLATFORMS x86_64-linux DEPENDENCIES + base64 (~> 0.1.1) console curses (~> 1.4) + dotenv (~> 2.8) + dynamic_curses_input (~> 1.0) gtk3 (~> 4.1) mysql2 (~> 0.5.5) + openssl (~> 3.1) reek (~> 6.1) rubocop (~> 1.52) + securerandom (~> 0.2.2) sequel (~> 5.69) solargraph (~> 0.49.0) yaml (~> 0.2.1) diff --git a/lib/utils/GUI_launcher.rb b/lib/utils/GUI_launcher.rb index d3e1ea7..40bfe13 100644 --- a/lib/utils/GUI_launcher.rb +++ b/lib/utils/GUI_launcher.rb @@ -1,14 +1,15 @@ require 'gtk3' -class GUI_Launcher - def initialize - @app = Gtk::Application.new("com.netrave.gui", :flags_none) +# GUI launcher +class GUILauncher + def initialize # rubocop:disable Metrics/MethodLength, Metrics/AbcSize + @app = Gtk::Application.new('com.netrave.gui', :flags_none) - @app.signal_connect "activate" do |application| + @app.signal_connect 'activate' do |application| builder = Gtk::Builder.new - builder.add_from_file("./Glade/NETRAVE.glade") + builder.add_from_file('./Glade/NETRAVE.glade') - window = builder.get_object("main_window") + window = builder.get_object('main_window') window.application = application screen = Gdk::Screen.default @@ -31,7 +32,7 @@ class GUI_Launcher end def run - puts "Launching GUI..." + puts 'Launching GUI...' @app.run end end diff --git a/lib/utils/database_manager.rb b/lib/utils/database_manager.rb index c99562f..3c35f32 100644 --- a/lib/utils/database_manager.rb +++ b/lib/utils/database_manager.rb @@ -1,25 +1,30 @@ +# frozen_string_literal: true + require 'sequel' require 'mysql2' -require_relative 'system_information_gather.rb' +require_relative 'system_information_gather' require_relative '../utils/utilities' +# database manager class DatabaseManager + include Utilities + def initialize @db = nil end def test_db_connection(db_details) - begin - connection_string = "mysql2://#{db_details[:username]}:#{db_details[:password]}@localhost/#{db_details[:database]}" - @db = Sequel.connect(connection_string) - # Try a simple query to test the connection - @db.run "SELECT 1" - true - rescue Sequel::DatabaseConnectionError - false - ensure - @db.disconnect if @db - end + # Decrypt the password before using it + decrypted_password = decrypt_string_chacha20(db_details[:password], db_details[:key]) + connection_string = "mysql2://#{db_details[:username]}:#{decrypted_password}@localhost/#{db_details[:database]}" + @db = Sequel.connect(connection_string) + # Try a simple query to test the connection + @db.run 'SELECT 1' + true + rescue Sequel::DatabaseConnectionError + false + ensure + @db&.disconnect end def create_system_info_table @@ -27,25 +32,25 @@ class DatabaseManager primary_key :id Integer :uplink_speed Integer :downlink_speed - String :services, text: true + Integer :total_bandwidth end end def store_system_info(system_info) @db[:system_info].insert(system_info) - end + end def create_services_table - @db.create_table :services do + @db.create_table? :services do primary_key :id String :service_name - Boolean :status + TrueClass :status, default: true end end def store_services(services) - services.each do |service, status| - @db[:services].insert(service_name: service, status: status) + services.each do |service| + @db[:services].insert(service_name: service, status: true) end end -end \ No newline at end of file +end diff --git a/lib/utils/first_run_init.rb b/lib/utils/first_run_init.rb index f8e6970..76258d7 100644 --- a/lib/utils/first_run_init.rb +++ b/lib/utils/first_run_init.rb @@ -1,13 +1,19 @@ -require 'curses' -require_relative 'database_manager.rb' -require_relative 'system_information_gather.rb' -require_relative 'utilities.rb' +# frozen_string_literal: true +require 'curses' +require 'dynamic_curses_input' +require 'dotenv' +require_relative 'database_manager' +require_relative 'system_information_gather' +require_relative 'utilities' + +# first run class class FirstRunInit include Utilities + include Curses - def initialize(db_manager) - @db_manager = db_manager + def initialize(db_manager = nil) + @db_manager = db_manager || DatabaseManager.new @info_gatherer = SystemInformationGather.new(@db_manager) end @@ -15,70 +21,88 @@ class FirstRunInit first_run_setup end - def first_run_setup + def first_run_setup # rubocop:disable Metrics/MethodLength db_details = ask_for_db_details - while !@db_manager.test_db_connection(db_details) + + until @db_manager.test_db_connection(db_details) Curses.setpos(4, 0) Curses.addstr("Whoops! We couldn't connect to the database with the details you provided. Please try again!") Curses.refresh db_details = ask_for_db_details end + @db_manager.create_system_info_table + @db_manager.create_services_table + uplink_speed = @info_gatherer.ask_for_uplink_speed - @db_manager.store_system_info(uplink_speed) downlink_speed = @info_gatherer.ask_for_downlink_speed - @db_manager.store_system_info(downlink_speed) total_bandwidth = calculate_total_bandwidth(uplink_speed, downlink_speed) - @db_manager.store_system_info(total_bandwidth) services = @info_gatherer.ask_for_services - @db_manager.store_system_info(services) + + system_info = { + uplink_speed:, + downlink_speed:, + total_bandwidth: + } + + @db_manager.store_system_info(system_info) + @db_manager.store_services(services) end - def ask_for_db_details + def ask_for_db_details # rubocop:disable Metrics/MethodLength, Metrics/AbcSize Curses.clear + Curses.setpos(1, 0) - Curses.addstr("Please enter your database username: ") + Curses.addstr('Please enter your database username: ') Curses.refresh - username = Curses.getstr.strip + username = DCI.catch_input(true) Curses.setpos(2, 0) - Curses.addstr("Please enter your database password: ") + Curses.addstr('Please enter your database password: ') Curses.refresh Curses.noecho - password = Curses.getstr.strip + password = DCI.catch_input(false) Curses.echo Curses.setpos(3, 0) - Curses.addstr("Please enter your database name: ") + Curses.addstr('Please enter your database name: ') Curses.refresh - database = Curses.getstr.strip + database = DCI.catch_input(true) - { username: username, password: password, database: database } + # Generate a secret key + key = generate_key + + # Encrypt the password + encrypted_password = encrypt_string_chacha20(password, key) + + { username:, password: encrypted_password, key:, database: } end def write_db_details_to_config_file(db_details) - File.open("config.yml", "w") do |file| - file.write(db_details.to_yaml) + # Write the database details to the .env file + File.open('.env', 'w') do |file| + file.puts "DB_USERNAME=#{db_details[:username]}" + file.puts "DB_PASSWORD=#{db_details[:password]}" + file.puts "DB_SECRET_KEY=#{db_details[:key]}" + file.puts "DB_DATABASE=#{db_details[:database]}" end end def ask_for_default_mode - while true + loop do Curses.setpos(8, 0) - Curses.addstr("Please enter the default mode (TUI, GUI, or WebApp): ") + Curses.addstr('Please enter the default mode (TUI, GUI, or WebApp): ') Curses.refresh mode = Curses.getstr.strip.downcase - if valid_mode?(mode) - return mode - else - Curses.setpos(9, 0) - Curses.addstr("Whoops! That didn't appear to be a valid mode. Please try again!") - Curses.refresh - end + return mode if valid_mode?(mode) + + Curses.setpos(9, 0) + Curses.addstr("Whoops! That didn't appear to be a valid mode. Please try again!") + Curses.refresh end end def valid_mode?(mode) - ['tui', 'gui', 'webapp'].include?(mode) + %w[tui gui webapp].include?(mode) end end diff --git a/lib/utils/system_information_gather.rb b/lib/utils/system_information_gather.rb index c24cc56..e522ccc 100644 --- a/lib/utils/system_information_gather.rb +++ b/lib/utils/system_information_gather.rb @@ -1,8 +1,10 @@ require 'curses' require 'yaml' -require_relative 'utilities.rb' -require_relative 'database_manager.rb' +require_relative 'utilities' +require_relative 'database_manager' +require 'dynamic_curses_input' +# gather system info class SystemInformationGather include Utilities @@ -10,7 +12,7 @@ class SystemInformationGather @db_manager = db_manager end - def gather_system_info + def gather_system_info # rubocop:disable Metrics/MethodLength uplink_speed = ask_for_uplink_speed downlink_speed = ask_for_downlink_speed services = ask_for_services @@ -18,9 +20,9 @@ class SystemInformationGather total_bandwidth = uplink_speed + downlink_speed system_info = { - uplink_speed: uplink_speed, - downlink_speed: downlink_speed, - total_bandwidth: total_bandwidth + uplink_speed:, + downlink_speed:, + total_bandwidth: } # Check if the system_info table exists, if not, create it @@ -36,79 +38,67 @@ class SystemInformationGather @db_manager.store_services(services) end - def ask_for_uplink_speed - while true - Curses.clear - Curses.setpos(2, 0) - Curses.addstr("Please enter your uplink speed (upload speed, e.g., 1000Mbps or 1Gbps). ") - Curses.addstr("This is typically the maximum upload speed provided by your ISP. ") - Curses.addstr("You can check your ISP bill, use an online speed test, or contact your ISP if you're unsure. ") - Curses.addstr(" ") + def ask_for_uplink_speed # rubocop:disable Metrics/MethodLength + Curses.clear + Curses.addstr("Please enter your uplink speed (upload speed, e.g., 1000Mbps or 1Gbps).\n" \ + "This is typically the maximum upload speed provided by your ISP.\n" \ + "You can check your ISP bill, use an online speed test, or contact your ISP if you're unsure.\n\n") + Curses.refresh + Curses.addstr('Uplink Speed: ') + speed = DCI.catch_input(true) + if valid_speed?(speed) + speed.end_with?('gbps') ? convert_speed_to_mbps(speed) : speed.to_i + else Curses.setpos(5, 0) - Curses.addstr("Uplink Speed: ") + Curses.addstr("Whoops! That didn't appear to be a valid speed. Please try again!") Curses.refresh - speed = Curses.getstr.strip.downcase - if valid_speed?(speed) - return speed.end_with?('gbps') ? convert_speed_to_mbps(speed) : speed.to_i - else - Curses.setpos(5, 0) - Curses.addstr("Whoops! That didn't appear to be a valid speed. Please try again!") - Curses.refresh - end + ask_for_uplink_speed end end - - def ask_for_downlink_speed - while true - Curses.clear - Curses.setpos(2, 0) - Curses.addstr("Please enter your downlink speed (download speed, e.g., 1000Mbps or 1Gbps). ") - Curses.addstr("This is typically the maximum download speed provided by your ISP. ") - Curses.addstr("You can check your ISP bill, use an online speed test, or contact your ISP if you're unsure. ") + + def ask_for_downlink_speed # rubocop:disable Metrics/MethodLength + Curses.clear + Curses.addstr("Please enter your downlink speed (download speed, e.g., 1000Mbps or 1Gbps).\n" \ + "This is typically the maximum download speed provided by your ISP.\n"\ + "You can check your ISP bill, use an online speed test, or contact your ISP if you're unsure.\n\n") + Curses.refresh + Curses.addstr('Downlink Speed: ') + speed = DCI.catch_input(true) + if valid_speed?(speed) + speed.end_with?('gbps') ? convert_speed_to_mbps(speed) : speed.to_i + else Curses.setpos(5, 0) - Curses.addstr("Downlink Speed: ") + Curses.addstr("Whoops! That didn't appear to be a valid speed. Please try again!") Curses.refresh - speed = Curses.getstr.strip.downcase - if valid_speed?(speed) - return speed.end_with?('gbps') ? convert_speed_to_mbps(speed) : speed.to_i - else - Curses.setpos(5, 0) - Curses.addstr("Whoops! That didn't appear to be a valid speed. Please try again!") - Curses.refresh - end + ask_for_downlink_speed end - end + end def valid_speed?(speed) - speed.to_i > 0 + speed.to_i.positive? end - def ask_for_services - while true - Curses.clear - Curses.setpos(6, 0) - Curses.addstr("Please enter the services the system should be aware of (e.g., webserver, database). ") - Curses.addstr("Enter the services as a comma-separated list (e.g., webserver,database). ") + def ask_for_services # rubocop:disable Metrics/MethodLength + Curses.clear + Curses.addstr("Please enter the services the system should be aware of (e.g., webserver or database).\n" \ + "Enter the services as a comma-separated list (e.g., webserver,database).\n\n") + Curses.refresh + Curses.addstr('Services: ') + services = DCI.catch_input(true) + services_arr = services.strip.downcase.split(',').map(&:strip) + + if valid_services?(services_arr) + services_arr # return the array of services directly + else + Curses.setpos(7, 0) + Curses.addstr("Whoops! That didn't appear to be a valid list of services. Please try again!") Curses.refresh - services = Curses.getstr.strip.downcase.split(',').map(&:strip) - if valid_services?(services) - return services_to_hash(services) - else - Curses.setpos(7, 0) - Curses.addstr("Whoops! That didn't appear to be a valid list of services. Please try again!") - Curses.refresh - end + ask_for_services end end - def valid_services?(services) + def valid_services?(_services) # TODO: Validate the services true end - - def services_to_hash(services) - services_hash = {} - services.each { |service| services_hash[service] = true } - services_hash - end -end \ No newline at end of file +end diff --git a/lib/utils/utilities.rb b/lib/utils/utilities.rb index 7df6869..3f3fb6f 100644 --- a/lib/utils/utilities.rb +++ b/lib/utils/utilities.rb @@ -1,22 +1,62 @@ +# frozen_string_literal: true + +require 'securerandom' +require 'digest' +require 'base64' +require 'openssl' + +# Utiltiies Module module Utilities - # Converts speed from Gbps to Mbps if necessary - def self.convert_speed_to_mbps(speed) - if speed.end_with?('gbps') - speed.to_i * 1000 - else - speed.to_i - end + # Converts speed from Gbps to Mbps if necessary + def convert_speed_to_mbps(speed) + if speed.end_with?('gbps') + speed.to_i * 1000 + else + speed.to_i end - - # Converts an array of services into a hash - def self.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 self.calculate_total_bandwidth(uplink_speed, downlink_speed) - uplink_speed + downlink_speed - end - end \ No newline at end of file + 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(string, key) + cipher = OpenSSL::Cipher.new('chacha20') + cipher.encrypt + cipher.key = Base64.decode64(key) + encrypted = cipher.update(string) + cipher.final + Base64.encode64(encrypted).chomp + end + + def decrypt_string_chacha20(encrypted_string, key) + decipher = OpenSSL::Cipher.new('chacha20') + decipher.decrypt + decipher.key = Base64.decode64(key) + decrypted = Base64.decode64(encrypted_string) + decipher.update(decrypted) + decipher.final + end + + # Encrypts a given data object using Blowfish and returns the encrypted string + def encrypt_data_blowfish(data, key) + plain_text = YAML.dump(data) + encrypt_string_blowfish(plain_text, key) + end + + # Decrypts a given encrypted string using Blowfish and returns the original data object + def decrypt_data_blowfish(encrypted_text, key) + plain_text = decrypt_string_blowfish(encrypted_text, key) + YAML.load(plain_text) + end +end