# frozen_string_literal: true module Legion module Crypt module Box def create_keys Legion::Logging.debug 'Legion::Crypt::Box.create_keys has been called' @private_key = RbNaCl::PrivateKey.generate @public_key = @private_key.public_key return unless Dir.exist? './settings' File.open('./settings/private.key', 'w').write(@private_key.to_s) File.open('./settings/public.key', 'w').write(@public_key.to_s) end def delete_keys File.delete('./settings/private.key') if File.exist? './settings/private.key' File.delete('./settings/public.key') if File.exist? './settings/public.key' end def load_keys return unless Dir.exist? './settings' @private_key = RbNaCl::PrivateKey.new(File.read('./settings/private.key').force_encoding('BINARY')) @public_key = RbNaCl::PrivateKey.new(File.read('./settings/public.key').force_encoding('BINARY')) end def encrypt_from_keypair(public_key:, message:, **_opts) Legion::Logging.debug('encrypt_from_keypair') Base64.encode64(RbNaCl::SimpleBox.from_keypair(Base64.decode64(public_key), @private_key).encrypt(message)) end def decrypt_from_keypair(public_key, enciphered_message) Legion::Logging.debug 'decrypt_from_keypair' RbNaCl::SimpleBox .from_keypair(Base64.decode64(public_key), @private_key) .decrypt(Base64.decode64(enciphered_message)) end def encrypt(message) Legion::Logging.debug 'encrypting message' Base64.encode64(@box.encrypt(message)) end def decrypt(message) Legion::Logging.debug 'decrypting message' @box.decrypt(Base64.decode64(message)) end def setup_safe # rubocop:disable Metrics/CyclomaticComplexity,Metrics/AbcSize,Metrics/PerceivedComplexity Legion::Logging.debug 'Setting up Legion::Crypt safe' if Legion::Settings[:crypt][:cluster_secret].nil? if Legion::Settings[:crypt][:vault][:connected] && Legion::Crypt.exist?('crypt') Legion::Settings[:crypt][:cluster_secret] = Base64.decode64(Legion::Crypt.get('crypt')[:cluster_secret]) elsif Legion::Transport::Queue.new('node.crypt', passive: true).consumer_count.zero? Legion::Logging.info 'Legion::Crypt Generating new cluster_secret since this is the first node' Legion::Settings[:crypt][:bootstrapped] = true Legion::Settings[:crypt][:cluster_secret] = RbNaCl::Random.random_bytes(RbNaCl::SecretBox.key_bytes) if Legion::Settings[:crypt][:vault][:connected] Legion::Crypt.write('crypt', :cluster_secret, Base64.encode64(Legion::Settings[:crypt][:cluster_secret])) end else require 'legion/transport/messages/request_cluster_secret' Legion::Logging.info 'Requesting cluster secret via public key' start = Time.now Legion::Transport::Messages::RequestClusterSecret.new.publish sleep_time = 0.001 until !Legion::Settings[:crypt][:cluster_secret].nil? || (Time.now - start) > Legion::Settings[:crypt][:cluster_secret_timeout] sleep(sleep_time) sleep_time *= 2 end unless Legion::Settings[:crypt][:cluster_secret].nil? Legion::Logging.info "Received cluster secret in #{((Time.new - start) * 1000.0).round}ms" end Legion::Logging.warn 'Cluster secret is still nil' if Legion::Settings[:crypt][:cluster_secret].nil? end end @key = Legion::Settings[:crypt][:cluster_secret].to_s @box = RbNaCl::SimpleBox.from_secret_key(@key) unless @key.empty? if !Legion::Settings[:crypt].key?(:encrypted_string) || !Legion::Settings[:crypt].key?(:validation_string) unless Legion::Settings[:crypt][:bootstrapped] Legion::Logging.warn 'Legion::Crypt has been set up but wasn\'t testing with a validation string!' end Legion::Settings[:crypt][:cs_encrypt_ready] = true elsif Legion::Crypt.decrypt(Legion::Settings[:crypt][:encrypted_string]) == Legion::Settings[:crypt][:validation_string] Legion::Logging.info 'Legion::Crypt was set up correctly after string match' Legion::Settings[:crypt][:cs_encrypt_ready] = true else Legion::Logging.fatal 'idk wtf happened' end end end end end