mirror of
https://github.com/we-promise/sure.git
synced 2026-06-01 16:59:03 +00:00
Expand financial providers (#1407)
* Initial implementation * Tiingo fixes * Adds 2 providers, remove 2 * Add extra checks * FIX a big hotwire race condition // Fix hotwire_combobox race condition: when typing quickly, a slow response for // an early query (e.g. "A") can overwrite the correct results for the final query // (e.g. "AAPL"). We abort the previous in-flight request whenever a new one fires, // so stale Turbo Stream responses never reach the DOM. * pipelock * Update price_test.rb * Reviews * i8n * fixes * fixes * Update tiingo.rb * fixes * Improvements * Big revamp * optimisations * Update 20260408151837_add_offline_reason_to_securities.rb * Add missing tests, fixes * small rank tests * FIX tests * Update show.html.erb * Update resolver.rb * Update usd_converter.rb * Update holdings_controller.rb * Update holdings_controller.rb * Update holdings_controller.rb * Update holdings_controller.rb * Update holdings_controller.rb * Update _yahoo_finance_settings.html.erb
This commit is contained in:
@@ -36,6 +36,83 @@ class Setting < RailsSettings::Base
|
||||
field :exchange_rate_provider, type: :string, default: ENV.fetch("EXCHANGE_RATE_PROVIDER", "twelve_data")
|
||||
field :securities_provider, type: :string, default: ENV.fetch("SECURITIES_PROVIDER", "twelve_data")
|
||||
|
||||
# Multi-provider: comma-separated list of enabled securities providers
|
||||
field :securities_providers, type: :string, default: ENV.fetch("SECURITIES_PROVIDERS", "")
|
||||
|
||||
# New provider API keys (encrypted at rest — see EncryptedSettingFields below)
|
||||
field :tiingo_api_key, type: :string, default: ENV["TIINGO_API_KEY"]
|
||||
field :eodhd_api_key, type: :string, default: ENV["EODHD_API_KEY"]
|
||||
field :alpha_vantage_api_key, type: :string, default: ENV["ALPHA_VANTAGE_API_KEY"]
|
||||
|
||||
# Transparent encryption for API key fields. The `field` macro defines the
|
||||
# raw getter/setter on the class. By prepending this module we intercept
|
||||
# reads (decrypt) and writes (encrypt) while `super` delegates to the
|
||||
# original getter/setter generated by rails-settings-cached.
|
||||
#
|
||||
# Backward-compatible: if decryption fails (e.g. the value was stored before
|
||||
# encryption was enabled) the raw value is returned as-is.
|
||||
module EncryptedSettingFields
|
||||
ENCRYPTED_FIELDS = %i[
|
||||
twelve_data_api_key
|
||||
tiingo_api_key
|
||||
eodhd_api_key
|
||||
alpha_vantage_api_key
|
||||
openai_access_token
|
||||
external_assistant_token
|
||||
].freeze
|
||||
|
||||
ENCRYPTED_FIELDS.each do |field_name|
|
||||
define_method(field_name) do
|
||||
raw = super()
|
||||
decrypt_setting(raw)
|
||||
end
|
||||
|
||||
define_method(:"#{field_name}=") do |value|
|
||||
super(encrypt_setting(value))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def setting_encryptor
|
||||
@setting_encryptor ||= begin
|
||||
key = ActiveSupport::KeyGenerator.new(
|
||||
Rails.application.secret_key_base
|
||||
).generate_key("setting_encryption", 32)
|
||||
ActiveSupport::MessageEncryptor.new(key)
|
||||
end
|
||||
end
|
||||
|
||||
def encrypt_setting(value)
|
||||
return value if value.blank?
|
||||
setting_encryptor.encrypt_and_sign(value)
|
||||
end
|
||||
|
||||
def decrypt_setting(value)
|
||||
return value if value.blank?
|
||||
setting_encryptor.decrypt_and_verify(value)
|
||||
rescue ActiveSupport::MessageVerifier::InvalidSignature,
|
||||
ActiveSupport::MessageEncryptor::InvalidMessage
|
||||
# Value was stored before encryption was enabled — return as-is.
|
||||
# It will be re-encrypted on next write.
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
class << self
|
||||
prepend EncryptedSettingFields
|
||||
end
|
||||
|
||||
def self.enabled_securities_providers
|
||||
plural = ENV["SECURITIES_PROVIDERS"].presence || securities_providers.presence
|
||||
if plural.present?
|
||||
plural.to_s.split(",").map(&:strip).reject(&:blank?)
|
||||
else
|
||||
# Backward compat: fall back to singular setting
|
||||
[ ENV["SECURITIES_PROVIDER"].presence || securities_provider ].compact
|
||||
end
|
||||
end
|
||||
|
||||
# Sync settings - check both provider env vars for default
|
||||
# Only defaults to true if neither provider explicitly disables pending
|
||||
SYNCS_INCLUDE_PENDING_DEFAULT = begin
|
||||
|
||||
Reference in New Issue
Block a user