diff --git a/lib/spendthrift.rb b/lib/spendthrift.rb index e62e59a..6c2b2a0 100644 --- a/lib/spendthrift.rb +++ b/lib/spendthrift.rb @@ -4,3 +4,4 @@ require 'spendthrift/reporting' require 'spendthrift/mailer' require 'spendthrift/db' +require 'spendthrift/secrets' diff --git a/lib/spendthrift/db.rb b/lib/spendthrift/db.rb index 2359ed5..fddbcd4 100644 --- a/lib/spendthrift/db.rb +++ b/lib/spendthrift/db.rb @@ -10,8 +10,14 @@ module DynamoDB def self.load_report(report) + secrets = (Spendthrift::Secrets.get_secrets)[:aws] - dynamodb = Aws::DynamoDB::Client.new + Aws.config.update({ + credentials: Aws::Credentials.new(secrets[:AWS_ACCESS_KEY_ID], secrets[:AWS_SECRET_ACCESS_KEY]), + region: secrets[:AWS_DEFAULT_REGION], + }) + + dynamodb = Aws::DynamoDB::Client.new() report.each do |key, value| params = { diff --git a/lib/spendthrift/mailer.rb b/lib/spendthrift/mailer.rb index ea9cd83..3576673 100644 --- a/lib/spendthrift/mailer.rb +++ b/lib/spendthrift/mailer.rb @@ -3,11 +3,12 @@ module Spendthrift module Mailer def self.send_mail(content:, subject:) - RestClient.post "https://api:#{ENV.fetch('MAILGUN_API_KEY')}"\ - "@api.mailgun.net/v3/#{ENV.fetch('MAILGUN_DOMAIN_NAME')}/messages", - :from => "Syed Abbas ", - :to => ENV.fetch("MAILGUN_RECIPIENTS"), - :subject => subject, + secrets = (Spendthrift::Secrets.get_secrets)[:app] + RestClient.post "https://api:#{secrets[:MAILGUN_API_KEY]}"\ + "@api.mailgun.net/v3/#{secrets[:MAILGUN_DOMAIN_NAME]}/messages", + :from => "Syed Abbas ", + :to => secrets[:MAILGUN_RECIPIENTS], + :subject => subject, :html => content end end diff --git a/lib/spendthrift/plaid_client.rb b/lib/spendthrift/plaid_client.rb index 6340b5c..830a3f2 100644 --- a/lib/spendthrift/plaid_client.rb +++ b/lib/spendthrift/plaid_client.rb @@ -6,13 +6,10 @@ module Spendthrift module PlaidGateway - class CredentialsError < StandardError + class VaultError < StandardError end - class AccountAccessTokensError < StandardError - end - class AccountTypeError < StandardError end @@ -23,15 +20,13 @@ class PlaidClient def initialize + secrets = load_secrets_from_vault + @raw_client = Plaid::Client.new(env: :development, + client_id: secrets[:PLAID_CLIENT_ID], + secret: secrets[:PLAID_SECRET], + public_key: secrets[:PLAID_PUBLIC_KEY]) - - client_id, secret, public_key = load_credentials_from_env - @raw_client = Plaid::Client.new(env: :development, - client_id: client_id, - secret: secret, - public_key: public_key) - - @access_tokens = load_access_tokens_from_env + @access_tokens = secrets[:PLAID_ACCESS_TOKENS].split ':' end @@ -61,7 +56,6 @@ def get_credit_card_accounts get_accounts_by_type 'credit', 'credit card' end - def get_savings_accounts get_accounts_by_type 'depository', 'savings' end @@ -75,30 +69,16 @@ def get_checking_accounts private - def load_credentials_from_env - credentials = ENV['PLAID_CLIENT_ID'], ENV['PLAID_SECRET'], ENV['PLAID_PUBLIC_KEY'] - if credentials.any? {|c| c.nil?} - raise CredentialsError.new( - 'PLAID_CLIENT_ID, PLAID_SECRET and PLAID_PUBLIC_KEY must be set as environment variables' - ) - end - - credentials - - end - - - def load_access_tokens_from_env - if ENV.has_key? 'PLAID_ACCESS_TOKENS' - ENV['PLAID_ACCESS_TOKENS'].split ':' - else - raise AccountAccessTokensError.new( - 'Account access tokens must be set in the PLAID_ACCESS_TOKENS environment variable' + def load_secrets_from_vault + secrets = (Spendthrift::Secrets.get_secrets)[:app] + if secrets.nil? + raise VaultError.new( + 'app secrets not found in vault' ) end + secrets end - def get_accounts_by_type(type, subtype) @access_tokens.map do |token| response = @raw_client.accounts.get token diff --git a/lib/spendthrift/secrets.rb b/lib/spendthrift/secrets.rb new file mode 100644 index 0000000..03acda0 --- /dev/null +++ b/lib/spendthrift/secrets.rb @@ -0,0 +1,36 @@ +require "json" +require "rest-client" + +module Spendthrift + + module Secrets + + VAULT_LOCATION = "http://127.0.0.1:8200/v1/secret/" + + def self.get_secrets + app = get_secrets_at_path(app_secrets_path) + aws = get_secrets_at_path(aws_secrets_path) + {app: app[:data], aws: aws[:data]} + + end + + private + + def self.get_secrets_at_path(path) + response = RestClient.get( + path, + headers={"X-Vault-Token" => ENV["VAULT_TOKEN"], + "content-type" => "application/json" } + ) + JSON.parse(response.body, :symbolize_names=>true) + end + + def self.aws_secrets_path + "#{VAULT_LOCATION}/aws" + end + + def self.app_secrets_path + "#{VAULT_LOCATION}/spendthrift" + end + end +end diff --git a/spec/plaid_client_spec.rb b/spec/plaid_client_spec.rb index 0dea7fe..feed03e 100644 --- a/spec/plaid_client_spec.rb +++ b/spec/plaid_client_spec.rb @@ -3,72 +3,50 @@ RSpec.describe Spendthrift::PlaidGateway::PlaidClient do + def stub_vault + allow(Spendthrift::Secrets).to receive(:get_secrets) { + { + app: { + PLAID_CLIENT_ID: 'test', + PLAID_SECRET: 'test', + PLAID_PUBLIC_KEY: 'test', + PLAID_ACCESS_TOKENS: 'test' + } + } + } + end describe '#new' do - before :example do - clear_env - end - - - context 'when client instantiated with access tokens but no login credentials' do - it 'raises CredentialsError' do - - ENV['PLAID_ACCESS_TOKENS'] = 'test' - - expect {Spendthrift::PlaidGateway::PlaidClient.new} - .to raise_error Spendthrift::PlaidGateway::CredentialsError - end - end - - - context 'when client instantiated with credentials but without access tokens' do - it 'raises AccountAccessTokensError' do - - ENV['PLAID_CLIENT_ID'] = 'test' - ENV['PLAID_SECRET'] = 'test' - ENV['PLAID_PUBLIC_KEY'] = 'test' - + context 'when client cannot access secrets' do + it 'raises' do + allow(Spendthrift::Secrets).to receive(:get_secrets) {{app: nil}} expect {Spendthrift::PlaidGateway::PlaidClient.new} - .to raise_error Spendthrift::PlaidGateway::AccountAccessTokensError + .to raise_error "app secrets not found in vault" end end - - - after :example do - restore_env - end end - describe '#get_credit_card_accounts' do - - - before :example do - clear_env - prepare_env - end - - it 'only returns credit card accounts' do - + stub_vault test_data = { - accounts: [{ - account_id: '123', - type: 'credit', - subtype: 'credit card' - }, - - { - account_id: '456', - type: 'depository', - subtype: 'savings' - }, - { - account_id: '789', - type: 'depository', - subtype: 'checking' - }, - ] + accounts: [{ + account_id: '123', + type: 'credit', + subtype: 'credit card' + }, + + { + account_id: '456', + type: 'depository', + subtype: 'savings' + }, + { + account_id: '789', + type: 'depository', + subtype: 'checking' + }, + ] } allow_any_instance_of(Plaid::Accounts).to receive(:get).and_return(test_data) @@ -78,43 +56,31 @@ expect(accounts.length).to eq 1 expect(accounts.first[:accounts].first[:account_id]).to eq '123' end - - - after :each do - restore_env - end end describe '#get_savings_accounts' do - - before :each do - clear_env - prepare_env - end - - it 'only returns savings accounts' do - + stub_vault test_data = { - accounts: [{ - account_id: '123', - type: 'credit', - subtype: 'credit card' - }, - - { - account_id: '456', - type: 'depository', - subtype: 'savings' - }, - { - account_id: '789', - type: 'depository', - subtype: 'checking' - }, - ] + accounts: [{ + account_id: '123', + type: 'credit', + subtype: 'credit card' + }, + + { + account_id: '456', + type: 'depository', + subtype: 'savings' + }, + { + account_id: '789', + type: 'depository', + subtype: 'checking' + }, + ] } allow_any_instance_of(Plaid::Accounts).to receive(:get).and_return(test_data) @@ -125,41 +91,30 @@ expect(accounts.first[:accounts].first[:account_id]).to eq '456' end - - after :each do - restore_env - end end describe '#get_checking_accounts' do - - before :each do - clear_env - prepare_env - end - - it 'only returns checking accounts' do - + stub_vault test_data = { - accounts: [{ - account_id: '123', - type: 'credit', - subtype: 'credit card' - }, - - { - account_id: '456', - type: 'depository', - subtype: 'savings' - }, - { - account_id: '789', - type: 'depository', - subtype: 'checking' - }, - ] + accounts: [{ + account_id: '123', + type: 'credit', + subtype: 'credit card' + }, + + { + account_id: '456', + type: 'depository', + subtype: 'savings' + }, + { + account_id: '789', + type: 'depository', + subtype: 'checking' + }, + ] } allow_any_instance_of(Plaid::Accounts).to receive(:get).and_return(test_data) @@ -169,42 +124,5 @@ expect(accounts.length).to eq 1 expect(accounts.first[:accounts].first[:account_id]).to eq '789' end - - - after :each do - ENV['PLAID_ACCESS_TOKENS'] = @access_tokens - end end - - - def prepare_env - ENV['PLAID_CLIENT_ID'] = 'test' - ENV['PLAID_SECRET'] = 'test' - ENV['PLAID_PUBLIC_KEY'] = 'test' - ENV['PLAID_ACCESS_TOKENS'] = 'test' - end - - - def clear_env - ENV['keep_PLAID_CLIENT_ID'] = ENV.delete 'PLAID_CLIENT_ID' - ENV['keep_PLAID_SECRET'] = ENV.delete 'PLAID_SECRET' - ENV['keep_PLAID_PUBLIC_KEY'] = ENV.delete 'PLAID_PUBLIC_KEY' - ENV['keep_PLAID_ACCESS_TOKENS'] = ENV.delete 'PLAID_ACCESS_TOKENS' - - end - - - def restore_env - ENV['PLAID_CLIENT_ID'] = ENV['keep_PLAID_CLIENT_ID'] - ENV['PLAID_SECRET'] = ENV['keep_PLAID_SECRET'] - ENV['PLAID_PUBLIC_KEY'] = ENV['keep_PLAID_PUBLIC_KEY'] - ENV['PLAID_ACCESS_TOKENS'] = ENV['keep_PLAID_ACCESS_TOKENS'] - - ENV.delete 'keep_PLAID_CLIENT_ID' - ENV.delete 'keep_PLAID_SECRET' - ENV.delete 'keep_PLAID_PUBLIC_KEY' - ENV.delete 'keep_PLAID_ACCESS_TOKENS' - end - - end diff --git a/spec/reporting_spec.rb b/spec/reporting_spec.rb index 8793b92..26970e7 100644 --- a/spec/reporting_spec.rb +++ b/spec/reporting_spec.rb @@ -90,7 +90,6 @@ it 'generates html tables' do template = Spendthrift::Reporting.generate_html_report(@sample_data) - File.open('test.html', 'w') {|f| f.puts template} expect(Nokogiri.HTML(template).search("table").length).to eq(2) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7d0f74d..a86d4f5 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -4,4 +4,5 @@ require "spendthrift/sanitize" require "spendthrift/reporting" require "spendthrift/mailer" +require "spendthrift/secrets"