summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
authoricebaker <icebaker@proton.me>2023-06-03 19:13:26 -0300
committericebaker <icebaker@proton.me>2023-06-03 19:13:26 -0300
commitcb8a84a60773cfe9e7fab03d93fc6430e4574351 (patch)
tree27839477aafb56128804393a328c94d341d5b394 /components
parent2c50a06b68a21ce904e5dfd15833e3569ff64bfa (diff)
add cryptography to state and user identifiers
Diffstat (limited to 'components')
-rw-r--r--components/crypto.rb47
-rw-r--r--components/provider.rb4
-rw-r--r--components/providers/openai.rb19
-rw-r--r--components/storage.rb33
4 files changed, 91 insertions, 12 deletions
diff --git a/components/crypto.rb b/components/crypto.rb
new file mode 100644
index 0000000..3f97f57
--- /dev/null
+++ b/components/crypto.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'singleton'
+require 'rbnacl'
+require 'base64'
+
+module NanoBot
+ module Components
+ class Crypto
+ include Singleton
+
+ def initialize
+ password = ENV.fetch('NANO_BOTS_ENCRYPTION_PASSWORD', nil)
+
+ password = 'UNSAFE' unless password && password != ''
+
+ @box = RbNaCl::SecretBox.new(RbNaCl::Hash.sha256(password))
+ @fixed_nonce = RbNaCl::Hash.sha256(password)[0...@box.nonce_bytes]
+ end
+
+ def encrypt(content, soft: false)
+ return content unless @box
+
+ nonce = soft ? @fixed_nonce : RbNaCl::Random.random_bytes(@box.nonce_bytes)
+ Base64.urlsafe_encode64(nonce + @box.encrypt(nonce, content))
+ end
+
+ def decrypt(content)
+ return content unless @box
+
+ decoded_content = Base64.urlsafe_decode64(content)
+ nonce = decoded_content[0...@box.nonce_bytes]
+ cipher_text = decoded_content[@box.nonce_bytes..]
+
+ @box.decrypt(nonce, cipher_text)
+ end
+
+ def self.encrypt(content, soft: false)
+ instance.encrypt(content, soft:)
+ end
+
+ def self.decrypt(content)
+ instance.decrypt(content)
+ end
+ end
+ end
+end
diff --git a/components/provider.rb b/components/provider.rb
index dbfc8bd..3138cc4 100644
--- a/components/provider.rb
+++ b/components/provider.rb
@@ -7,10 +7,10 @@ require_relative './providers/openai'
module NanoBot
module Components
class Provider
- def self.new(provider)
+ def self.new(provider, environment: {})
case provider[:name]
when 'openai'
- Providers::OpenAI.new(provider[:settings])
+ Providers::OpenAI.new(provider[:settings], environment:)
else
raise "Unsupported provider #{provider[:name]}"
end
diff --git a/components/providers/openai.rb b/components/providers/openai.rb
index c0a6639..c64a588 100644
--- a/components/providers/openai.rb
+++ b/components/providers/openai.rb
@@ -3,6 +3,7 @@
require 'openai'
require_relative './base'
+require_relative '../crypto'
module NanoBot
module Components
@@ -15,8 +16,9 @@ module NanoBot
attr_reader :settings
- def initialize(settings)
+ def initialize(settings, environment: {})
@settings = settings
+ @environment = environment
@client = ::OpenAI::Client.new(
uri_base: "#{@settings[:credentials][:address].sub(%r{/$}, '')}/",
@@ -46,11 +48,16 @@ module NanoBot
)
end
- payload = {
- model: @settings[:model],
- user: @settings[:credentials][:'user-identifier'],
- messages:
- }
+ user = @settings[:credentials][:'user-identifier']
+
+ user_suffix = @environment && (
+ @environment['NANO_BOTS_USER_IDENTIFIER'] ||
+ @environment[:NANO_BOTS_USER_IDENTIFIER]
+ )
+
+ user = "#{user}/#{user_suffix}" if user_suffix && user_suffix != ''
+
+ payload = { model: @settings[:model], user: Crypto.encrypt(user, soft: true), messages: }
CHAT_SETTINGS.each do |key|
payload[key] = @settings[key] if @settings.key?(key)
diff --git a/components/storage.rb b/components/storage.rb
index cba3dd0..b6d8910 100644
--- a/components/storage.rb
+++ b/components/storage.rb
@@ -3,11 +3,12 @@
require 'babosa'
require_relative '../logic/helpers/hash'
+require_relative './crypto'
module NanoBot
module Components
class Storage
- def self.build_path_and_ensure_state_file!(key, cartridge)
+ def self.build_path_and_ensure_state_file!(key, cartridge, environment: {})
path = [
Logic::Helpers::Hash.fetch(cartridge, %i[state directory]),
ENV.fetch('NANO_BOTS_STATE_DIRECTORY', nil)
@@ -17,14 +18,38 @@ module NanoBot
path = "#{user_home!.sub(%r{/$}, '')}/.local/state/nano-bots" if path.nil?
- path = "#{path.sub(%r{/$}, '')}/ruby-nano-bots/#{cartridge[:meta][:author].to_slug.normalize}"
+ prefix = environment && (
+ environment['NANO_BOTS_USER_IDENTIFIER'] ||
+ environment[:NANO_BOTS_USER_IDENTIFIER]
+ )
+
+ path = "#{path.sub(%r{/$}, '')}/ruby-nano-bots/vault"
+
+ if prefix
+ normalized = prefix.split('/').map do |part|
+ Crypto.encrypt(
+ part.to_s.gsub('.', '-').force_encoding('UTF-8').to_slug.normalize,
+ soft: true
+ )
+ end.join('/')
+
+ path = "#{path}/#{normalized}"
+ end
+
+ path = "#{path}/#{cartridge[:meta][:author].to_slug.normalize}"
path = "#{path}/#{cartridge[:meta][:name].to_slug.normalize}"
- path = "#{path}/#{cartridge[:meta][:version].to_s.gsub('.', '-').to_slug.normalize}/#{key}"
+ path = "#{path}/#{cartridge[:meta][:version].to_s.gsub('.', '-').to_slug.normalize}"
+ path = "#{path}/#{Crypto.encrypt(key, soft: true)}"
path = "#{path}/state.json"
FileUtils.mkdir_p(File.dirname(path))
- File.write(path, JSON.generate({ key:, history: [] })) unless File.exist?(path)
+ unless File.exist?(path)
+ File.write(
+ path,
+ Crypto.encrypt(JSON.generate({ key:, history: [] }))
+ )
+ end
path
end