diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b6ecf951..ca641157 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,23 +19,30 @@ jobs: fail-fast: false matrix: ruby: [2.7, '3.0', 3.1, 3.2, 3.3, jruby-9.4] - rails: [7.1, 7.2, main] + rails: [7.1, 7.2, '8.0', main] exclude: - # Rails 7.2 dropped support for older rubygems + # Rails 7.2 is Ruby >= 3.1 - rails: 7.2 ruby: 2.7 - rails: 7.2 ruby: 3.0 + # Rails 8.0 is Ruby >= 3.2 + - rails: '8.0' + ruby: 2.7 + - rails: '8.0' + ruby: 3.0 + - rails: '8.0' + ruby: 3.1 + - rails: '8.0' + ruby: jruby-9.4 + # Rails main is Ruby >= 3.2 - rails: main ruby: 2.7 - rails: main ruby: 3.0 - rails: main ruby: 3.1 - # JDBC adapters don't support the latest Rails - - rails: 7.2 - ruby: jruby-9.4 - rails: main ruby: jruby-9.4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 41f309c1..ac544085 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,10 @@ Unreleased Changes * Issue - Add deprecation warning to `Aws::Rails.add_action_mailer_delivery_method` to instead use `ActionMailer::Base.add_delivery_method`. This method will be removed in the next major version. +* Feature - ActionMailbox SES ingress now lives in the `aws-actionmailbox-ses` gem. + +* Issue - The `Aws::Rails::ActionMailbox::RSpec` module has been moved to `Aws::ActionMailbox::SES::RSpec` and will be removed in aws-sdk-rails ~> 5. + 4.1.0 (2024-09-27) ------------------ diff --git a/Gemfile b/Gemfile index 3169ba2e..bd8d6d65 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,7 @@ source 'https://rubygems.org' gemspec gem 'aws-actiondispatch-dynamodb', git: 'https://github.com/aws/aws-actiondispatch-dynamodb-ruby' +gem 'aws-actionmailbox-ses', git: 'https://github.com/aws/aws-actionmailbox-ses-ruby' gem 'aws-actionmailer-ses', git: 'https://github.com/aws/aws-actionmailer-ses-ruby' group :development, :test do diff --git a/README.md b/README.md index bbc3c885..014fb701 100644 --- a/README.md +++ b/README.md @@ -222,7 +222,30 @@ In your environment configuration, set the delivery method to config.action_mailer.delivery_method = :ses # or :ses_v2 ``` -## Amazon Simple Email Service (SES) as an ActionMailbox Method +### Using ARNs with SES + +This gem uses [\`Aws::SES::Client#send_raw_email\`](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/SES/Client.html#send_raw_email-instance_method) +and [\`Aws::SESV2::Client#send_email\`](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/SESV2/Client.html#send_email-instance_method) +to send emails. This operation allows you to specify a cross-account identity +for the email's Source, From, and Return-Path. To set these ARNs, use any of the +following headers on your `Mail::Message` object returned by your Mailer class: + +* X-SES-SOURCE-ARN + +* X-SES-FROM-ARN + +* X-SES-RETURN-PATH-ARN + +Example: + +``` +# in your Rails controller +message = MyMailer.send_email(options) +message['X-SES-FROM-ARN'] = 'arn:aws:ses:us-west-2:012345678910:identity/bigchungus@memes.com' +message.deliver +``` + +## Amazon Simple Email Service (SES) as an ActionMailbox Ingress ### Configuration @@ -307,28 +330,6 @@ You may also pass the following keyword arguments to both helpers: * `topic`: The _SNS_ topic used for each notification (default: `topic:arn:default`). * `authentic`: The `Aws::SNS::MessageVerifier` class is stubbed by these helpers; set `authentic` to `true` or `false` to define how it will verify incoming notifications (default: `true`). -### Using ARNs with SES - -This gem uses [\`Aws::SES::Client#send_raw_email\`](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/SES/Client.html#send_raw_email-instance_method) -and [\`Aws::SESV2::Client#send_email\`](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/SESV2/Client.html#send_email-instance_method) -to send emails. This operation allows you to specify a cross-account identity -for the email's Source, From, and Return-Path. To set these ARNs, use any of the -following headers on your `Mail::Message` object returned by your Mailer class: - -* X-SES-SOURCE-ARN - -* X-SES-FROM-ARN - -* X-SES-RETURN-PATH-ARN - -Example: - -``` -# in your Rails controller -message = MyMailer.send_email(options) -message['X-SES-FROM-ARN'] = 'arn:aws:ses:us-west-2:012345678910:identity/bigchungus@memes.com' -message.deliver -``` ## Active Support Notifications for AWS SDK calls diff --git a/Rakefile b/Rakefile index d1bfc73e..6a411ab5 100644 --- a/Rakefile +++ b/Rakefile @@ -4,9 +4,6 @@ require 'rspec/core/rake_task' require 'rake/testtask' require 'rubocop/rake_task' -$REPO_ROOT = File.dirname(__FILE__) -$VERSION = ENV['VERSION'] || File.read(File.join($REPO_ROOT, 'VERSION')).strip - Dir.glob('**/*.rake').each do |task_file| load task_file end @@ -24,14 +21,6 @@ Rake::TestTask.new('test:rails') do |t| t.warning = false end -task :db_migrate do - Dir.chdir('spec/dummy') do - version = ENV.delete('VERSION') # ActiveRecord uses this - `RAILS_ENV=test rake -I ../../lib db:migrate` - ENV['VERSION'] = version - end -end - -task test: [:db_migrate, :spec, 'test:rails'] +task test: [:spec, 'test:rails'] task default: :test task 'release:test' => :test diff --git a/app/controllers/action_mailbox/ingresses/ses/inbound_emails_controller.rb b/app/controllers/action_mailbox/ingresses/ses/inbound_emails_controller.rb deleted file mode 100644 index 83af84a6..00000000 --- a/app/controllers/action_mailbox/ingresses/ses/inbound_emails_controller.rb +++ /dev/null @@ -1,79 +0,0 @@ -# frozen_string_literal: true - -require 'aws/rails/action_mailbox/sns_notification' - -module ActionMailbox - module Ingresses - module Ses - # Ingests inbound emails from Amazon SES/SNS and confirms subscriptions. - # - # Subscription requests must provide the following parameters in a JSON body: - # - +Message+: Notification content - # - +MessagId+: Notification unique identifier - # - +Timestamp+: iso8601 timestamp - # - +TopicArn+: Topic identifier - # - +Type+: Type of event ("Subscription") - # - # Inbound email events must provide the following parameters in a JSON body: - # - +Message+: Notification content - # - +MessagId+: Notification unique identifier - # - +Timestamp+: iso8601 timestamp - # - +SubscribeURL+: Topic identifier - # - +TopicArn+: Topic identifier - # - +Type+: Type of event ("SubscriptionConfirmation") - # - # All requests are authenticated by validating the provided AWS signature. - # - # Returns: - # - # - 204 No Content if a request is successfully processed - # - 401 Unauthorized if a request does not contain a valid signature - # - 404 Not Found if the Amazon ingress has not been configured - # - 422 Unprocessable Entity if a request provides invalid parameters - class InboundEmailsController < ActionMailbox::BaseController - before_action :verify_authenticity, :validate_topic, :confirm_subscription - - def create - head :bad_request unless notification.message_content.present? - - ActionMailbox::InboundEmail.create_and_extract_message_id!(notification.message_content) - head :no_content - end - - private - - def verify_authenticity - head :bad_request unless notification.present? - head :unauthorized unless notification.verified? - end - - def confirm_subscription - return unless notification.type == 'SubscriptionConfirmation' - return head :ok if notification.subscription_confirmed? - - Rails.logger.error('SNS subscription confirmation request rejected.') - head :unprocessable_entity - end - - def validate_topic - return if valid_topic == notification.topic - - Rails.logger.warn("Ignoring unknown topic: #{topic}") - head :unauthorized - end - - def notification - @notification ||= Aws::Rails::ActionMailbox::SnsNotification.new(request.raw_post) - end - - def topic - @topic ||= notification.topic - end - - def valid_topic - ::Rails.configuration.action_mailbox.ses.subscribed_topic - end - end - end - end -end diff --git a/aws-sdk-rails.gemspec b/aws-sdk-rails.gemspec index 589732fc..18c56a3e 100644 --- a/aws-sdk-rails.gemspec +++ b/aws-sdk-rails.gemspec @@ -11,20 +11,18 @@ Gem::Specification.new do |spec| spec.description = 'Integrates the AWS SDK for Ruby with Ruby on Rails' spec.homepage = 'https://github.com/aws/aws-sdk-rails' spec.license = 'Apache-2.0' - spec.files = Dir['LICENSE.txt', 'CHANGELOG.md', 'VERSION', 'lib/**/*', 'bin/*', 'app/**/*', 'config/*'] + spec.files = Dir['LICENSE.txt', 'CHANGELOG.md', 'VERSION', 'lib/**/*', 'bin/*'] spec.executables = ['aws_sqs_active_job'] # These will be removed in aws-sdk-rails ~> 5 spec.add_dependency('aws-actiondispatch-dynamodb', '~> 0') + spec.add_dependency('aws-actionmailbox-ses', '~> 0') spec.add_dependency('aws-actionmailer-ses', '~> 0') spec.add_dependency('aws-record', '~> 2') # for Aws::Record integration # Require these versions for user_agent_framework configs - spec.add_dependency('aws-sdk-s3', '~> 1', '>= 1.123.0') - spec.add_dependency('aws-sdk-sns', '~> 1', '>= 1.61.0') # for ActionMailbox spec.add_dependency('aws-sdk-sqs', '~> 1', '>= 1.56.0') # for ActiveJob - spec.add_dependency('actionmailbox', '>= 7.1.0') # for SES ActionMailbox spec.add_dependency('concurrent-ruby', '~> 1.3', '>= 1.3.1') # Utilities for concurrent processing spec.add_dependency('railties', '>= 7.1.0') # Minimum supported Rails version diff --git a/config/routes.rb b/config/routes.rb deleted file mode 100644 index 2a46e464..00000000 --- a/config/routes.rb +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true - -Rails.application.routes.draw do - scope '/rails/action_mailbox', module: 'action_mailbox/ingresses' do - post '/ses/inbound_emails' => 'ses/inbound_emails#create', - as: :rails_ses_inbound_emails - end -end diff --git a/gemfiles/rails-7.1.gemfile b/gemfiles/rails-7.1.gemfile index 337c3aae..babb65fd 100644 --- a/gemfiles/rails-7.1.gemfile +++ b/gemfiles/rails-7.1.gemfile @@ -3,19 +3,3 @@ eval_gemfile '../Gemfile' gem 'rails', '~> 7.1.0' - -group :test do - # JDBC versions track Rails versions - gem 'activerecord-jdbc-adapter', '~> 71.0', - platform: :jruby, - # this is not published for some reason - git: 'https://github.com/jruby/activerecord-jdbc-adapter', - glob: 'activerecord-jdbc-adapter.gemspec' - gem 'activerecord-jdbcsqlite3-adapter', '~> 71.0', - platform: :jruby, - # this is not published for some reason - git: 'https://github.com/jruby/activerecord-jdbc-adapter', - glob: 'activerecord-jdbcsqlite3-adapter/activerecord-jdbcsqlite3-adapter.gemspec' - # last supported version of sqlite3 for minimum ruby - gem 'sqlite3', '~> 1.6.0', platform: :ruby -end diff --git a/gemfiles/rails-7.2.gemfile b/gemfiles/rails-7.2.gemfile index fe96d354..6866a47a 100644 --- a/gemfiles/rails-7.2.gemfile +++ b/gemfiles/rails-7.2.gemfile @@ -3,19 +3,3 @@ eval_gemfile '../Gemfile' gem 'rails', '~> 7.2.0' - -group :test do - # JDBC versions track Rails versions - gem 'activerecord-jdbc-adapter', '~> 71.0', - platform: :jruby, - # this is not published for some reason - git: 'https://github.com/jruby/activerecord-jdbc-adapter', - glob: 'activerecord-jdbc-adapter.gemspec' - gem 'activerecord-jdbcsqlite3-adapter', '~> 71.0', - platform: :jruby, - # this is not published for some reason - git: 'https://github.com/jruby/activerecord-jdbc-adapter', - glob: 'activerecord-jdbcsqlite3-adapter/activerecord-jdbcsqlite3-adapter.gemspec' - # last supported version of sqlite3 for minimum ruby - gem 'sqlite3', '~> 1.6.0', platform: :ruby -end diff --git a/gemfiles/rails-8.0.gemfile b/gemfiles/rails-8.0.gemfile new file mode 100644 index 00000000..cd3dbac3 --- /dev/null +++ b/gemfiles/rails-8.0.gemfile @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +eval_gemfile '../Gemfile' + +gem 'rails', '~> 8.0.0' diff --git a/gemfiles/rails-main.gemfile b/gemfiles/rails-main.gemfile index cd228adf..80b01d94 100644 --- a/gemfiles/rails-main.gemfile +++ b/gemfiles/rails-main.gemfile @@ -3,18 +3,3 @@ eval_gemfile '../Gemfile' gem 'rails', github: 'rails/rails' - -group :test do - # JDBC versions track Rails versions - gem 'activerecord-jdbc-adapter', '~> 71.0', - platform: :jruby, - # this is not published for some reason - git: 'https://github.com/jruby/activerecord-jdbc-adapter', - glob: 'activerecord-jdbc-adapter.gemspec' - gem 'activerecord-jdbcsqlite3-adapter', '~> 71.0', - platform: :jruby, - # this is not published for some reason - git: 'https://github.com/jruby/activerecord-jdbc-adapter', - glob: 'activerecord-jdbcsqlite3-adapter/activerecord-jdbcsqlite3-adapter.gemspec' - gem 'sqlite3', platform: :ruby -end diff --git a/lib/aws-sdk-rails.rb b/lib/aws-sdk-rails.rb index 11f16883..05ce309f 100644 --- a/lib/aws-sdk-rails.rb +++ b/lib/aws-sdk-rails.rb @@ -1,13 +1,13 @@ # frozen_string_literal: true require_relative 'aws/rails/railtie' -require_relative 'aws/rails/action_mailbox/engine' require_relative 'aws/rails/notifications' require_relative 'aws/rails/sqs_active_job' require_relative 'aws/rails/middleware/ebs_sqs_active_job_middleware' # remove this in aws-sdk-rails 5 require 'aws-actiondispatch-dynamodb' +require 'aws-actionmailbox-ses' if defined?(ActionMailbox::Engine) require 'aws-actionmailer-ses' module Aws diff --git a/lib/aws/rails/action_mailbox/engine.rb b/lib/aws/rails/action_mailbox/engine.rb deleted file mode 100644 index e682d904..00000000 --- a/lib/aws/rails/action_mailbox/engine.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -if defined?(ActionMailbox::Engine) - module Aws - module Rails - module ActionMailbox - # @api private - class Engine < ::Rails::Engine - config.action_mailbox.ses = ActiveSupport::OrderedOptions.new - config.action_mailbox.ses.s3_client_options ||= {} - - initializer 'aws-sdk-rails.mount_engine' do |app| - app.routes.append do - mount Engine => '/' - end - end - end - end - end - end -end diff --git a/lib/aws/rails/action_mailbox/rspec.rb b/lib/aws/rails/action_mailbox/rspec.rb index d03b2d6e..51d33680 100644 --- a/lib/aws/rails/action_mailbox/rspec.rb +++ b/lib/aws/rails/action_mailbox/rspec.rb @@ -1,69 +1,9 @@ # frozen_string_literal: true -require 'aws/rails/action_mailbox/rspec/email' -require 'aws/rails/action_mailbox/rspec/subscription_confirmation' -require 'aws-sdk-sns' -require 'aws/rails/action_mailbox/sns_message_verifier' +# This can be deleted in aws-sdk-rails ~> 5 -module Aws - module Rails - module ActionMailbox - # Include the `Aws::Rails::ActionMailbox::RSpec` extension in your tests, like so: - # require 'aws/rails/action_mailbox/rspec' - # RSpec.configure do |config| - # config.include Aws::Rails::ActionMailbox::RSpec - # end - # Then, in a request spec, use like so: - # RSpec.describe 'amazon emails', type: :request do - # it 'delivers a subscription notification' do - # action_mailbox_ses_deliver_subscription_confirmation - # expect(response).to have_http_status :ok - # end +require 'aws/action_mailbox/ses/rspec' +Aws::Rails::ActionMailbox::Rspec = Aws::ActionMailbox::SES::Rspec - # it 'delivers an email notification' do - # action_mailbox_ses_deliver_email(mail: Mail.new(to: 'user@example.com')) - # expect(ActionMailbox::InboundEmail.last.mail.recipients).to eql ['user@example.com'] - # end - # end - module RSpec - def action_mailbox_ses_deliver_subscription_confirmation(options = {}) - subscription_confirmation = SubscriptionConfirmation.new(**options) - stub_aws_sns_message_verifier(subscription_confirmation) - stub_aws_sns_subscription_request - - post subscription_confirmation.url, - params: subscription_confirmation.params, - headers: subscription_confirmation.headers, - as: :json - end - - def action_mailbox_ses_deliver_email(options = {}) - email = Email.new(**options) - stub_aws_sns_message_verifier(email) - - post email.url, - params: email.params, - headers: email.headers, - as: :json - end - - private - - def message_verifier(subscription_confirmation) - instance_double(Aws::SNS::MessageVerifier, authentic?: subscription_confirmation.authentic?) - end - - def stub_aws_sns_message_verifier(notification) - allow(Aws::Rails::ActionMailbox::SnsMessageVerifier).to receive(:verifier) { message_verifier(notification) } - end - - def stub_aws_sns_subscription_request - allow(Net::HTTP).to receive(:get_response).and_call_original - allow(Net::HTTP) - .to receive(:get_response) - .with(URI('http://example.com/subscribe')) { double(code: '200') } - end - end - end - end -end +Kernel.warn('Aws::Rails::ActionMailbox::Rspec is deprecated in aws-sdk-rails ~> 5. Use Aws::ActionMailbox::SES::Rspec instead.') +Kernel.warn('Please require "aws/action_mailbox/ses/rspec" instead of "aws/rails/action_mailbox/rspec"') diff --git a/lib/aws/rails/action_mailbox/rspec/email.rb b/lib/aws/rails/action_mailbox/rspec/email.rb deleted file mode 100644 index 9ca4d8c5..00000000 --- a/lib/aws/rails/action_mailbox/rspec/email.rb +++ /dev/null @@ -1,50 +0,0 @@ -# frozen_string_literal: true - -module Aws - module Rails - module ActionMailbox - module RSpec - # @api private - class Email - def initialize(authentic: true, topic: 'topic:arn:default', mail: default_mail, message_params: {}) - @authentic = authentic - @topic = topic - @mail = mail - @message_params = message_params - end - - def headers - { 'content-type' => 'application/json' } - end - - def url - '/rails/action_mailbox/ses/inbound_emails' - end - - def params - { - 'Type' => 'Notification', - 'TopicArn' => @topic, - 'Message' => message_json - } - end - - def message_json - { - 'notificationType' => 'Received', - 'content' => @mail.encoded - }.merge(@message_params).to_json - end - - def authentic? - @authentic - end - - def default_mail - Mail.new - end - end - end - end - end -end diff --git a/lib/aws/rails/action_mailbox/rspec/subscription_confirmation.rb b/lib/aws/rails/action_mailbox/rspec/subscription_confirmation.rb deleted file mode 100644 index 52023dbc..00000000 --- a/lib/aws/rails/action_mailbox/rspec/subscription_confirmation.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -module Aws - module Rails - module ActionMailbox - module RSpec - # @api private - class SubscriptionConfirmation - def initialize(authentic: true, topic: 'topic:arn:default') - @authentic = authentic - @topic = topic - end - - def url - '/rails/action_mailbox/ses/inbound_emails' - end - - def headers - { 'content-type' => 'application/json' } - end - - def params - { - 'Type' => 'SubscriptionConfirmation', - 'TopicArn' => @topic, - 'SubscribeURL' => 'http://example.com/subscribe' - } - end - - def authentic? - @authentic - end - end - end - end - end -end diff --git a/lib/aws/rails/action_mailbox/s3_client.rb b/lib/aws/rails/action_mailbox/s3_client.rb deleted file mode 100644 index fa996c90..00000000 --- a/lib/aws/rails/action_mailbox/s3_client.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -require 'aws-sdk-s3' - -module Aws - module Rails - module ActionMailbox - # @api private - class S3Client - class << self - def client - @client ||= build_client - end - - private - - def build_client - client = Aws::S3::Client.new( - **::Rails.configuration.action_mailbox.ses.s3_client_options - ) - client.config.user_agent_frameworks << 'aws-sdk-rails' - client - end - end - end - end - end -end diff --git a/lib/aws/rails/action_mailbox/sns_message_verifier.rb b/lib/aws/rails/action_mailbox/sns_message_verifier.rb deleted file mode 100644 index 62560de8..00000000 --- a/lib/aws/rails/action_mailbox/sns_message_verifier.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -require 'aws-sdk-sns' - -module Aws - module Rails - module ActionMailbox - # @api private - class SnsMessageVerifier - class << self - def verifier - @verifier ||= Aws::SNS::MessageVerifier.new - end - end - end - end - end -end diff --git a/lib/aws/rails/action_mailbox/sns_notification.rb b/lib/aws/rails/action_mailbox/sns_notification.rb deleted file mode 100644 index 18d97fb2..00000000 --- a/lib/aws/rails/action_mailbox/sns_notification.rb +++ /dev/null @@ -1,99 +0,0 @@ -# frozen_string_literal: true - -require 'aws-sdk-sns' -require 'aws/rails/action_mailbox/s3_client' -require 'aws/rails/action_mailbox/sns_message_verifier' - -module Aws - module Rails - module ActionMailbox - # @api private - class SnsNotification - class MessageContentError < StandardError; end - - def initialize(request_body) - @request_body = request_body - end - - def subscription_confirmed? - (200..299).cover?(confirmation_response.code.to_i) - end - - def verified? - SnsMessageVerifier.verifier.authentic?(@request_body) - end - - def topic - notification.fetch(:TopicArn) - end - - def type - notification.fetch(:Type) - end - - def message_content - raise MessageContentError, 'Incoming emails must have notificationType `Received`' unless receipt? - - if content_in_s3? - s3_content - else - return message[:content] unless destination - - "X-Original-To: #{destination}\n#{message[:content]}" - end - end - - private - - def notification - @notification ||= JSON.parse(@request_body, symbolize_names: true) - rescue JSON::ParserError => e - Rails.logger.warn("Unable to parse SNS notification: #{e}") - nil - end - - def s3_content - S3Client - .client - .get_object(key: key, bucket: bucket) - .body - .string - end - - def message - @message ||= JSON.parse(notification[:Message], symbolize_names: true) - end - - def destination - message.dig(:mail, :destination)&.first - end - - def action - return unless message[:receipt] - - message.fetch(:receipt).fetch(:action) - end - - def bucket - action.fetch(:bucketName) - end - - def key - action.fetch(:objectKey) - end - - def content_in_s3? - action&.fetch(:type) == 'S3' - end - - def receipt? - message.fetch(:notificationType) == 'Received' - end - - def confirmation_response - @confirmation_response ||= Net::HTTP.get_response(URI(notification[:SubscribeURL])) - end - end - end - end -end diff --git a/sample-app/Gemfile b/sample-app/Gemfile index f7a52193..d11b9191 100644 --- a/sample-app/Gemfile +++ b/sample-app/Gemfile @@ -2,8 +2,9 @@ source "https://rubygems.org" # Our gems gem 'aws-sdk-rails', path: '../' -gem 'aws-sessionstore-dynamodb' #, path: '../../aws-sessionstore-dynamodb-ruby' -gem 'aws-actionmailer-ses', git: 'https://github.com/aws/aws-actionmailer-ses-ruby', branch: 'init' +gem 'aws-actiondispatch-dynamodb', git: 'https://github.com/aws/aws-actiondispatch-dynamodb-ruby' +gem 'aws-actionmailbox-ses', git: 'https://github.com/aws/aws-actionmailbox-ses-ruby', branch: 'init' +gem 'aws-actionmailer-ses', git: 'https://github.com/aws/aws-actionmailer-ses-ruby' # Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] gem 'bcrypt' diff --git a/sample-app/README.md b/sample-app/README.md index c7ab89b1..c22f722e 100644 --- a/sample-app/README.md +++ b/sample-app/README.md @@ -114,3 +114,64 @@ Start the service with `ACTION_MAILER_EMAIL= bundle exec rails serve > **Important**: The email address in SES must be verified. Visit `http://127.0.0.1:3000/send_ses_email` or `http://127.0.0.1:3000/send_ses_v2_email` and check your email. + +## Action Mailbox + +### Setup + +Following [this guide](https://guides.rubyonrails.org/action_mailbox_basics.html), ActionMailbox was setup with `bundle exec bin/rails action_mailbox:install`. + +The database was migrated with: `bundle exec rails db:migrate`. + +The ingress and ActiveStorage was configured in `config/environments/development.rb` with: + +```ruby +config.active_storage.service = :local +config.action_mailbox.ingress = :ses +``` + +A default route was added to `app/mailboxes/application_mailbox.rb`. + +The test mailbox was created with `bundle exec rails generate mailbox test`. + +### Testing + +This feature can't fully be tested end to end unless the rails application is hosted on a domain. The SNS topic would have to notify a route such as `https://example.com/rails/action_mailbox/ses/inbound_emails`. + +Future work could deploy this sample-app behind a domain to fully test it. + +Start the service with `bundle exec rails server` and visit `http://127.0.0.1:3000/rails/conductor/action_mailbox/inbound_emails`. + +Click "New inbound email by source". + +Use the following message (other messages can be created and signed in aws-actionmailbox-ses): + +``` +Return-Path: +Received: from example.com (example.com [127.0.0.1]) + by inbound-smtp.us-east-1.amazonaws.com with SMTP id 17at0jiq08p0449huhf16qsmdi6sa1ltm069t801 + for test@test.example.com; + Wed, 02 Sep 2020 01:30:50 +0000 (UTC) +X-SES-Spam-Verdict: PASS +X-SES-Virus-Verdict: PASS +X-SES-RECEIPT: AEFBQUFBQUFBQUFHMWlxem9Gb1ZOemNkamlTeFlYdlZUSmUwVVZhYndjK213dHFIM0dVRTYwUlk1UlpBQVVVTXhQRUd1MTN6YTFJalp0TFdMZjhOOUZGSlJCYkxEV2craXhpOG02d2xDc2FtY2dNdVMvRE9QWWpNVkxBWVZzMyt5MHBTUXV5KzM5aDY1Vng5UnZsZTdTK2dGVDF5RVc1QndOd0xvbndNRlR3TDZjd2cxT2c2UVFQbVN2andMS09VM2R5elFrTGk3RnF0WXI3WDZ1alhkUzJxdzhzU1dwT3FPZEFsU0VNc3RpTWM0QStFZDB5RFd5SnpRelBJWnJjelZPRytudEVpNTc5dVZRUXMra2lrby9wOExhR3JqTi9xNkZnNHREN3BmSmVYS25Jeis2NDRyaEE9PQ== +X-SES-DKIM-SIGNATURE: a=rsa-sha256; q=dns/txt; b=WGBoUguIq9047YXpCaubVCtm/ISR3JEVkvm/yAfL2MrAryQcYsTdUM6zzStPyvOm0QsonOKsWJ0O2YyuQDX1dvBmggdeUqZq08laD+Xuy1L6ODm0O/EQE9wDitj0KqXxOgMr3oM7tpcTTGLcCgXERFZbmI+1ACeeA7fbylMasIM=; c=relaxed/simple; s=224i4yxa5dv7c2xz3womw6peuasteono; d=amazonses.com; t=1599010250; v=1; bh=FUugtX/z1FFtLvVfaVhPhqhi4Gvo1Aam67iRPZYKfTo=; h=From:To:Cc:Bcc:Subject:Date:Message-ID:MIME-Version:Content-Type:X-SES-RECEIPT; +From: "Smith, Bob E" +To: "test@test.example.com" + +Subject: Test 500 +Thread-Topic: Test 500 +Thread-Index: AQHWgMisvDz2gn/lKEK/giPayBxk7g== +Date: Wed, 2 Sep 2020 01:30:43 +0000 +Message-ID: <1344C740-07D3-476E-BEE7-6EB162294DF6@example.com> +Accept-Language: en-US +Content-Language: en-US +Content-Type: text/plain; charset="us-ascii" +Content-ID: +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + +Aaaron +``` + +You should see the message say delivered and not bounced. \ No newline at end of file diff --git a/spec/dummy/app/mailboxes/application_mailbox.rb b/sample-app/app/mailboxes/application_mailbox.rb similarity index 56% rename from spec/dummy/app/mailboxes/application_mailbox.rb rename to sample-app/app/mailboxes/application_mailbox.rb index ac22d03c..53a139c3 100644 --- a/spec/dummy/app/mailboxes/application_mailbox.rb +++ b/sample-app/app/mailboxes/application_mailbox.rb @@ -1,3 +1,3 @@ class ApplicationMailbox < ActionMailbox::Base - # routing /something/i => :somewhere + routing /.*/ => :test end diff --git a/sample-app/app/mailboxes/test_mailbox.rb b/sample-app/app/mailboxes/test_mailbox.rb new file mode 100644 index 00000000..2f77e107 --- /dev/null +++ b/sample-app/app/mailboxes/test_mailbox.rb @@ -0,0 +1,4 @@ +class TestMailbox < ApplicationMailbox + def process + end +end diff --git a/sample-app/config/environments/development.rb b/sample-app/config/environments/development.rb index b3b0a8ba..1bcedab6 100644 --- a/sample-app/config/environments/development.rb +++ b/sample-app/config/environments/development.rb @@ -1,6 +1,9 @@ require "active_support/core_ext/integer/time" Rails.application.configure do + config.active_storage.service = :local + config.action_mailbox.ingress = :ses + # Settings specified here will take precedence over those in config/application.rb. # In the development environment your application's code is reloaded any time diff --git a/sample-app/config/environments/production.rb b/sample-app/config/environments/production.rb index 8daf2739..1ae152e7 100644 --- a/sample-app/config/environments/production.rb +++ b/sample-app/config/environments/production.rb @@ -1,6 +1,9 @@ require "active_support/core_ext/integer/time" Rails.application.configure do + # Prepare the ingress controller used to receive mail + # config.action_mailbox.ingress = :relay + # Settings specified here will take precedence over those in config/application.rb. # Code is not reloaded between requests. diff --git a/sample-app/config/initializers/action_mailer.rb b/sample-app/config/initializers/action_mailer.rb index f0104bae..a6ccf50c 100644 --- a/sample-app/config/initializers/action_mailer.rb +++ b/sample-app/config/initializers/action_mailer.rb @@ -1,3 +1,3 @@ options = {} -ActionMailer::Base.add_delivery_method :ses, Aws::ActionMailer::SESMailer, **options -ActionMailer::Base.add_delivery_method :ses_v2, Aws::ActionMailer::SESV2Mailer, **options +ActionMailer::Base.add_delivery_method :ses, Aws::ActionMailer::SES::Mailer, **options +ActionMailer::Base.add_delivery_method :ses_v2, Aws::ActionMailer::SESV2::Mailer, **options diff --git a/spec/dummy/config/storage.yml b/sample-app/config/storage.yml similarity index 89% rename from spec/dummy/config/storage.yml rename to sample-app/config/storage.yml index 6861af3b..ff552906 100644 --- a/spec/dummy/config/storage.yml +++ b/sample-app/config/storage.yml @@ -1,3 +1,3 @@ -test: +local: service: Disk root: <%= Rails.root.join("tmp/storage") %> diff --git a/sample-app/db/migrate/20241113202339_create_active_storage_tables.active_storage.rb b/sample-app/db/migrate/20241113202339_create_active_storage_tables.active_storage.rb new file mode 100644 index 00000000..6bd8bd08 --- /dev/null +++ b/sample-app/db/migrate/20241113202339_create_active_storage_tables.active_storage.rb @@ -0,0 +1,57 @@ +# This migration comes from active_storage (originally 20170806125915) +class CreateActiveStorageTables < ActiveRecord::Migration[7.0] + def change + # Use Active Record's configured type for primary and foreign keys + primary_key_type, foreign_key_type = primary_and_foreign_key_types + + create_table :active_storage_blobs, id: primary_key_type do |t| + t.string :key, null: false + t.string :filename, null: false + t.string :content_type + t.text :metadata + t.string :service_name, null: false + t.bigint :byte_size, null: false + t.string :checksum + + if connection.supports_datetime_with_precision? + t.datetime :created_at, precision: 6, null: false + else + t.datetime :created_at, null: false + end + + t.index [ :key ], unique: true + end + + create_table :active_storage_attachments, id: primary_key_type do |t| + t.string :name, null: false + t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type + t.references :blob, null: false, type: foreign_key_type + + if connection.supports_datetime_with_precision? + t.datetime :created_at, precision: 6, null: false + else + t.datetime :created_at, null: false + end + + t.index [ :record_type, :record_id, :name, :blob_id ], name: :index_active_storage_attachments_uniqueness, unique: true + t.foreign_key :active_storage_blobs, column: :blob_id + end + + create_table :active_storage_variant_records, id: primary_key_type do |t| + t.belongs_to :blob, null: false, index: false, type: foreign_key_type + t.string :variation_digest, null: false + + t.index [ :blob_id, :variation_digest ], name: :index_active_storage_variant_records_uniqueness, unique: true + t.foreign_key :active_storage_blobs, column: :blob_id + end + end + + private + def primary_and_foreign_key_types + config = Rails.configuration.generators + setting = config.options[config.orm][:primary_key_type] + primary_key_type = setting || :primary_key + foreign_key_type = setting || :bigint + [ primary_key_type, foreign_key_type ] + end +end diff --git a/sample-app/db/migrate/20241113202340_create_action_mailbox_tables.action_mailbox.rb b/sample-app/db/migrate/20241113202340_create_action_mailbox_tables.action_mailbox.rb new file mode 100644 index 00000000..7b2b8079 --- /dev/null +++ b/sample-app/db/migrate/20241113202340_create_action_mailbox_tables.action_mailbox.rb @@ -0,0 +1,20 @@ +# This migration comes from action_mailbox (originally 20180917164000) +class CreateActionMailboxTables < ActiveRecord::Migration[6.0] + def change + create_table :action_mailbox_inbound_emails, id: primary_key_type do |t| + t.integer :status, default: 0, null: false + t.string :message_id, null: false + t.string :message_checksum, null: false + + t.timestamps + + t.index [ :message_id, :message_checksum ], name: "index_action_mailbox_inbound_emails_uniqueness", unique: true + end + end + + private + def primary_key_type + config = Rails.configuration.generators + config.options[config.orm][:primary_key_type] || :primary_key + end +end diff --git a/sample-app/db/schema.rb b/sample-app/db/schema.rb index f7d30f8a..6ee7c2f5 100644 --- a/sample-app/db/schema.rb +++ b/sample-app/db/schema.rb @@ -10,7 +10,44 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2024_11_06_152613) do +ActiveRecord::Schema[7.2].define(version: 2024_11_13_202340) do + create_table "action_mailbox_inbound_emails", force: :cascade do |t| + t.integer "status", default: 0, null: false + t.string "message_id", null: false + t.string "message_checksum", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["message_id", "message_checksum"], name: "index_action_mailbox_inbound_emails_uniqueness", unique: true + end + + create_table "active_storage_attachments", force: :cascade do |t| + t.string "name", null: false + t.string "record_type", null: false + t.bigint "record_id", null: false + t.bigint "blob_id", null: false + t.datetime "created_at", null: false + t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id" + t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true + end + + create_table "active_storage_blobs", force: :cascade do |t| + t.string "key", null: false + t.string "filename", null: false + t.string "content_type" + t.text "metadata" + t.string "service_name", null: false + t.bigint "byte_size", null: false + t.string "checksum" + t.datetime "created_at", null: false + t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true + end + + create_table "active_storage_variant_records", force: :cascade do |t| + t.bigint "blob_id", null: false + t.string "variation_digest", null: false + t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true + end + create_table "users", force: :cascade do |t| t.string "email" t.string "password_digest" @@ -18,4 +55,7 @@ t.datetime "updated_at", null: false t.index ["email"], name: "index_users_on_email", unique: true end + + add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" + add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" end diff --git a/sample-app/storage/development.sqlite3 b/sample-app/storage/development.sqlite3 index 189f5763..92122c7c 100644 Binary files a/sample-app/storage/development.sqlite3 and b/sample-app/storage/development.sqlite3 differ diff --git a/sample-app/test/mailboxes/test_mailbox_test.rb b/sample-app/test/mailboxes/test_mailbox_test.rb new file mode 100644 index 00000000..d9840536 --- /dev/null +++ b/sample-app/test/mailboxes/test_mailbox_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class TestMailboxTest < ActionMailbox::TestCase + # test "receive mail" do + # receive_inbound_email_from_mail \ + # to: '"someone" ', + # from: '"else" ', + # subject: "Hello world!", + # body: "Hello?" + # end +end diff --git a/spec/aws/rails/action_mailbox/requests/inbound_email_spec.rb b/spec/aws/rails/action_mailbox/requests/inbound_email_spec.rb deleted file mode 100644 index d40d3428..00000000 --- a/spec/aws/rails/action_mailbox/requests/inbound_email_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -describe 'inbound email', type: :request do - let(:inbound_email_url) { '/rails/action_mailbox/ses/inbound_emails' } - - before do - stub_request( - :get, - 'https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem' - ).and_return(body: fixture_for(:certificate, type: :pem)) - end - - it 'receives inbound email' do - post inbound_email_url, params: JSON.parse(fixture_for(:inbound_email, type: :json)), as: :json - - expect(response).to have_http_status(:no_content) - expect(ActionMailbox::InboundEmail.count).to eql 1 - end - - it 'receives an inbound email with data in s3' do - s3_email = fixture_for(:s3_email, type: :txt) - - s3_client = Aws::S3::Client.new(stub_responses: true) - s3_client.stub_responses(:head_object, { content_length: s3_email.size, parts_count: 1 }) - s3_client.stub_responses(:get_object, { body: s3_email }) - - allow(Aws::S3::Client).to receive(:new).and_return(s3_client) - - expect do - post inbound_email_url, - params: JSON.parse(fixture_for(:inbound_email_s3, type: :json)), - as: :json - end.to change(ActionMailbox::InboundEmail, :count).by(1) - - expect(response).to have_http_status(:no_content) - - inbound_email = ActionMailbox::InboundEmail.last - expect(s3_email).to eq(inbound_email.raw_email.download) - end -end diff --git a/spec/aws/rails/action_mailbox/requests/rspec_spec.rb b/spec/aws/rails/action_mailbox/requests/rspec_spec.rb deleted file mode 100644 index 356eeded..00000000 --- a/spec/aws/rails/action_mailbox/requests/rspec_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' -require 'aws/rails/action_mailbox/rspec' - -describe 'rspec', type: :request do - include Aws::Rails::ActionMailbox::RSpec - - before do - allow(Rails.configuration.action_mailbox.ses).to receive(:subscribed_topic) { topic } - end - - describe 'topic subscription' do - describe 'recognized topic' do - let(:topic) { 'topic:arn:default' } - it 'renders 200 OK' do - action_mailbox_ses_deliver_subscription_confirmation - expect(response).to have_http_status :ok - end - end - - describe 'unrecognized topic' do - let(:topic) { 'topic:arn:other' } - it 'renders 401 Unauthorized' do - action_mailbox_ses_deliver_subscription_confirmation - expect(response).to have_http_status :unauthorized - end - end - end - - describe 'email delivery' do - describe 'when recognized topic' do - let(:topic) { 'topic:arn:default' } - it 'renders 204 No Content' do - action_mailbox_ses_deliver_email(mail: Mail.new) - expect(response).to have_http_status :no_content - end - - it 'delivers an email to inbox' do - action_mailbox_ses_deliver_email(mail: Mail.new(to: 'user@example.com')) - expect(ActionMailbox::InboundEmail.last.mail.recipients).to eql ['user@example.com'] - end - end - - describe 'when unrecognized topic' do - let(:topic) { 'topic:arn:other' } - it 'renders 401 Unauthorized' do - action_mailbox_ses_deliver_email - expect(response).to have_http_status :unauthorized - end - end - - describe 'with destination parameter set' do - let(:topic) { 'topic:arn:default' } - - it 'extracts recipient email from SNS notification content' do - action_mailbox_ses_deliver_email( - mail: Mail.new(to: 'user@example.com'), - message_params: { 'mail' => { 'destination' => ['bcc_user@example.com'] } } - ) - - expect(ActionMailbox::InboundEmail.last.mail.recipients).to contain_exactly( - 'user@example.com', 'bcc_user@example.com' - ) - end - end - end -end diff --git a/spec/aws/rails/action_mailbox/requests/subscription_confirmation_spec.rb b/spec/aws/rails/action_mailbox/requests/subscription_confirmation_spec.rb deleted file mode 100644 index 27889d36..00000000 --- a/spec/aws/rails/action_mailbox/requests/subscription_confirmation_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -describe 'subscription confirmation', type: :request do - let!(:subscription_confirmation_request) do - query = Rack::Utils.build_query(subscription_params) - stub_request(:get, "https://sns.eu-west-1.amazonaws.com/?#{query}") - end - - let(:subscription_params) do - { - Action: 'ConfirmSubscription', - Token: 'abcd1234' * 32, - TopicArn: "arn:aws:sns:eu-west-1:012345678910:#{topic}" - } - end - - let(:topic) { 'example-topic' } - - let(:action) do - post '/rails/action_mailbox/ses/inbound_emails', - headers: { 'Content-Type' => 'application/json' }, - params: fixture_for(type, type: :json) - end - - before do - stub_request( - :get, - 'https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem' - ).and_return(body: fixture_for(:certificate, type: :pem)) - end - - context 'when valid Amazon SSL signature' do - let(:type) { 'valid_signature' } - - it 'fetches subscription URL' do - action - expect(subscription_confirmation_request).to have_been_requested - end - end - - context 'when invalid Amazon SSL signature' do - let(:type) { 'invalid_signature' } - - it 'does not fetch subscription URL' do - action - expect(subscription_confirmation_request).to_not have_been_requested - end - end - - context 'when unrecognized topic' do - let(:type) { 'unrecognized_topic_subscription_request' } - let(:topic) { 'unrecognized-topic' } - - it 'does not fetch subscription URL' do - action - expect(subscription_confirmation_request).to_not have_been_requested - end - end -end diff --git a/spec/aws/rails/action_mailbox/rspec/email_spec.rb b/spec/aws/rails/action_mailbox/rspec/email_spec.rb deleted file mode 100644 index 366e2a37..00000000 --- a/spec/aws/rails/action_mailbox/rspec/email_spec.rb +++ /dev/null @@ -1,50 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -describe Aws::Rails::ActionMailbox::RSpec::Email do - let(:email) { described_class.new(authentic: authentic, mail: mail, topic: topic) } - let(:topic) { 'topic:arn:default' } - let(:authentic) { true } - let(:mail) { instance_double(Mail::Message, encoded: 'raw encoded email') } - let(:expected_params) do - { - 'Type' => 'Notification', - 'TopicArn' => topic, - 'Message' => { - 'notificationType' => 'Received', - 'content' => 'raw encoded email' - }.to_json - } - end - - it 'has the correct data' do - expect(email.url).to eq('/rails/action_mailbox/ses/inbound_emails') - expect(email.headers).to eq('content-type' => 'application/json') - expect(email.params).to eq(expected_params) - end - - describe '#authentic?' do - subject(:email_authentic) { email.authentic? } - - context 'when authentic' do - let(:authentic) { true } - - it { is_expected.to be(true) } - end - - context 'when not authentic' do - let(:authentic) { false } - - it { is_expected.to be(false) } - end - end - - context 'when custom topic' do - let(:topic) { 'custom-topic' } - - it 'has topic' do - expect(email.params).to include('TopicArn' => topic) - end - end -end diff --git a/spec/aws/rails/action_mailbox/rspec/subscription_confirmation_spec.rb b/spec/aws/rails/action_mailbox/rspec/subscription_confirmation_spec.rb deleted file mode 100644 index 10512f56..00000000 --- a/spec/aws/rails/action_mailbox/rspec/subscription_confirmation_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -describe Aws::Rails::ActionMailbox::RSpec::SubscriptionConfirmation do - let(:subscription) { described_class.new(authentic: authentic, topic: topic) } - - let(:authentic) { true } - let(:topic) { 'topic:arn:default' } - let(:expected_params) do - { - 'Type' => 'SubscriptionConfirmation', - 'TopicArn' => topic, - 'SubscribeURL' => 'http://example.com/subscribe' - } - end - - it 'has the correct data' do - expect(subscription.url).to eq('/rails/action_mailbox/ses/inbound_emails') - expect(subscription.headers).to eq('content-type' => 'application/json') - expect(subscription.params).to eq(expected_params) - end - - describe '#authentic?' do - subject(:subscription_authentic) { subscription.authentic? } - - context 'when authentic' do - let(:authentic) { true } - - it { is_expected.to be(true) } - end - - context 'when not authentic' do - let(:authentic) { false } - - it { is_expected.to be(false) } - end - end - - context 'when custom topic' do - let(:topic) { 'custom-topic' } - - it 'has topic' do - expect(subscription.params).to include('TopicArn' => topic) - end - end -end diff --git a/spec/dummy/config/application.rb b/spec/dummy/config/application.rb index 865d1e87..a2a62377 100644 --- a/spec/dummy/config/application.rb +++ b/spec/dummy/config/application.rb @@ -1,12 +1,10 @@ # frozen_string_literal: true require 'rails' -require 'activerecord-jdbc-adapter' if defined? JRUBY_VERSION require 'active_job/railtie' require 'action_controller/railtie' require 'action_mailer/railtie' require 'action_view/railtie' -require 'action_mailbox/engine' require 'aws-sdk-rails' module Dummy diff --git a/spec/dummy/config/database.yml b/spec/dummy/config/database.yml deleted file mode 100644 index 800589fa..00000000 --- a/spec/dummy/config/database.yml +++ /dev/null @@ -1,3 +0,0 @@ -test: - adapter: sqlite3 - database: db/test.db diff --git a/spec/dummy/config/environments/test.rb b/spec/dummy/config/environments/test.rb index e10d3fa5..f5fd48f4 100644 --- a/spec/dummy/config/environments/test.rb +++ b/spec/dummy/config/environments/test.rb @@ -1,7 +1,4 @@ Rails.application.configure do - config.active_storage.service = :test - config.action_mailbox.ingress = :ses - config.action_mailbox.ses.subscribed_topic = 'arn:aws:sns:eu-west-1:012345678910:example-topic' config.action_dispatch.show_exceptions = :none config.eager_load = true end diff --git a/spec/fixtures/json/inbound_email.json b/spec/fixtures/json/inbound_email.json deleted file mode 100644 index 91d30ff4..00000000 --- a/spec/fixtures/json/inbound_email.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "Type": "Notification", - "MessageId": "abc12345-abc1-abc1-abc1-abc123456789", - "TopicArn": "arn:aws:sns:eu-west-1:012345678910:example-topic", - "Subject": "Amazon SES Email Receipt Notification", - "Message": "{\"notificationType\":\"Received\",\"mail\":{\"timestamp\":\"2020-05-09T09:16:15.982Z\",\"source\":\"sender@example.com\",\"messageId\":\"abcdef0123456789abcdef0123456789abcdef01\",\"destination\":[\"recipient@example.com\"],\"headersTruncated\":false,\"headers\":[{\"name\":\"Return-Path\",\"value\":\"\"},{\"name\":\"Received\",\"value\":\"from mail.example.com (mail.example.com [1.2.3.4]) by inbound-smtp.eu-west-1.amazonaws.com with SMTP id abcdef0123456789abcdef0123456789abcdef01 for recipient@example.com; Sat, 09 May 2020 09:16:15 +0000 (UTC)\"},{\"name\":\"X-SES-Spam-Verdict\",\"value\":\"PASS\"},{\"name\":\"X-SES-Virus-Verdict\",\"value\":\"PASS\"},{\"name\":\"Received-SPF\",\"value\":\"pass (spfCheck: domain of example.com designates 1.2.3.4 as permitted sender) client-ip=5.5.5.5; envelope-from=sender@example.com; helo=mail.example.com;\"},{\"name\":\"Authentication-Results\",\"value\":\"amazonses.com; spf=pass (spfCheck: domain of example.com designates 5.5.5.5 as permitted sender) client-ip=5.5.5.5; envelope-from=sender@example.com; helo=mail.example.com; dkim=pass header.i=@example.com; dmarc=none header.from=example.com;\"},{\"name\":\"X-SES-RECEIPT\",\"value\":\"AEFBQUFBQUFBQUFFNkFrOCtYbmRzcE13djhXN3hhOEttYU02NUhLMGZYYzBpQUx4SG5wcEI5KzNQakdHTWNEbjExMTlnRlNBbWNsVVFJd2YzQjY1RU5aeGM5dzdlbE9wcmpibjNSZ2NBMmx6dmJhQmM3SmxDdmljc25KUnpuTlpSdnhhVkx6MFRpc2dXWTFZY3RFU2hXcUs1YllxZ1RVUFo3cmJaN0NpeTU3VjhtN1liclpYVXN4K3lmWm5FQ1B6dkp5b3hsQ3pJd3VUUWd4M3lzSm1uc0QzQVRieE1FTGdMdFU5anA2Z2RUKzEyOVZYV1ZyN0hHNHR6SURBSUI4VkxaVEJqaHhRWTRqenltKzIyTG9IaWYwM1huVVlIK1ZGMmNBazc4dVdCaUNkQmtIcWd1VWs2M0E9PQ==\"},{\"name\":\"X-SES-DKIM-SIGNATURE\",\"value\":\"a=rsa-sha256; q=dns/txt; b=XH7Cy8VtplePQbGI2JndadMaSQRzuFCUCQl3RRIFpN+eZgS06eyYut3gar8ds6b1mHzNwSsBB5cj5YAF/GompbFbWV2GL04XqDSxvfrdlTkv+qA0SQLnveyFUDJTKlPPr8TjF2G+k2s8BFgchLyR+IBbmPHeH+jNknvqNArh77w=; c=relaxed/simple; s=shh3fegwg5fppqsuzphvschd53n6ihuv; d=amazonses.com; t=1589015776; v=1; bh=h0K5Yz299OBRJv28xIMZ/L633w+wjm31dUktgDO7sHg=; h=From:To:Cc:Bcc:Subject:Date:Message-ID:MIME-Version:Content-Type:X-SES-RECEIPT;\"},{\"name\":\"Received\",\"value\":\"by mail-oi1-f180.google.com with SMTP id o7so10735431oif.2 for ; Sat, 09 May 2020 02:16:15 -0700 (PDT)\"},{\"name\":\"DKIM-Signature\",\"value\":\"v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com; s=google; h=mime-version:from:date:message-id:subject:to; bh=h0K5Yz299OBRJv28xIMZ/L633w+wjm31dUktgDO7sHg=; b=Vg0zgLNrgypVuHn7dOM1j1xZz9zifdKm/8BJSVCZMPza8e5bsCI/MOPqQxv8KaKTOZKPpq2uNMhw/ueG/bc04WvoJrYX3/vAzMDXLf8oPvLuLyjfaePc68hSQr5fHzOxzmuLei9sKo7CthTQIrW0s1a27xWHc3UT96fEdw2BdSI=\"},{\"name\":\"X-Google-DKIM-Signature\",\"value\":\"v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=h0K5Yz299OBRJv28xIMZ/L633w+wjm31dUktgDO7sHg=; b=sINpYmONoM0qeQnebY9hQK4EtWUq8xq5tnbjE7box8LHPsGMrrQyIiH9/IIbiH7oUg NE0FItezKdzD4RiOh3C48RpvrP7yGg3w9n3FyuJ/8JjJ6endtnGRwIma3LkJygz+3FzE Sire7dZVCwij0WquBXJ2WKjemFiPPg6M002pYD8F6ZpNPjuL1+qtUiLoSUGFy6hYvMNa FVRUyVZil8Sd6n3DL5R3FhVSNB1MptWm2CTIgv2+dEyXf5cO0sn6LDPgO3Jx2LO5/oyn +SdNJsc86nbXEjA7aL9pMlU0YdRMIbpwYHPvvyWT3K5hB6wnYF+hAyTn454ACXdduYi3 E72g==\"},{\"name\":\"X-Gm-Message-State\",\"value\":\"AGi0PuZnRiX/3B0rQ6UV4cR4oucLl9xNu5Vm2LQzGB+wZPNGquEwxctp xqfK7mfh70F01tIxZ1H74HKDGTD71OiJ6e9D8hHn+J8t\"},{\"name\":\"X-Google-Smtp-Source\",\"value\":\"APiQypJYIgvF7HgWijswlpCCmdg46BkfhUhhqSk1JllbbMoxs1ntBGx8iXfpjMD1ton1sdL3L4HFJsawRsBwK4+ZDF4=\"},{\"name\":\"X-Received\",\"value\":\"by 2002:aca:ba86:: with SMTP id k128mr13817762oif.60.1589015774221; Sat, 09 May 2020 02:16:14 -0700 (PDT)\"},{\"name\":\"MIME-Version\",\"value\":\"1.0\"},{\"name\":\"From\",\"value\":\"Email Sender \"},{\"name\":\"Date\",\"value\":\"Sat, 9 May 2020 10:16:03 +0100\"},{\"name\":\"Message-ID\",\"value\":\"\"},{\"name\":\"Subject\",\"value\":\"testing\"},{\"name\":\"To\",\"value\":\"recipient@example.com\"},{\"name\":\"Content-Type\",\"value\":\"multipart/alternative; boundary=\\\"000000000000c3f47c05a533908c\\\"\"}],\"commonHeaders\":{\"returnPath\":\"sender@example.com\",\"from\":[\"Email Sender \"],\"date\":\"Sat, 9 May 2020 10:16:03 +0100\",\"to\":[\"recipient@example.com\"],\"messageId\":\"\",\"subject\":\"testing\"}},\"receipt\":{\"timestamp\":\"2020-05-09T09:16:15.982Z\",\"processingTimeMillis\":414,\"recipients\":[\"recipient@example.com\"],\"spamVerdict\":{\"status\":\"PASS\"},\"virusVerdict\":{\"status\":\"PASS\"},\"spfVerdict\":{\"status\":\"PASS\"},\"dkimVerdict\":{\"status\":\"PASS\"},\"dmarcVerdict\":{\"status\":\"GRAY\"},\"action\":{\"type\":\"SNS\",\"topicArn\":\"arn:aws:sns:eu-west-1:012345678910:example-topic\",\"encoding\":\"UTF8\"}},\"content\":\"Return-Path: \\r\\nReceived: from mail-oi1-f180.google.com (mail-oi1-f180.google.com [209.85.167.180])\\r\\n by inbound-smtp.eu-west-1.amazonaws.com with SMTP id 7nt592nn42m2fh53jk2vmig13rvr5hdm5i31ca01\\r\\n for recipient@example.com;\\r\\n Sat, 09 May 2020 09:16:15 +0000 (UTC)\\r\\nX-SES-Spam-Verdict: PASS\\r\\nX-SES-Virus-Verdict: PASS\\r\\nReceived-SPF: pass (spfCheck: domain of example.com designates 209.85.167.180 as permitted sender) client-ip=209.85.167.180; envelope-from=sender@example.com; helo=mail-oi1-f180.google.com;\\r\\nAuthentication-Results: amazonses.com;\\r\\n spf=pass (spfCheck: domain of example.com designates 209.85.167.180 as permitted sender) client-ip=209.85.167.180; envelope-from=sender@example.com; helo=mail-oi1-f180.google.com;\\r\\n dkim=pass header.i=@example.com;\\r\\n dmarc=none header.from=example.com;\\r\\nX-SES-RECEIPT: AEFBQUFBQUFBQUFFNkFrOCtYbmRzcE13djhXN3hhOEttYU02NUhLMGZYYzBpQUx4SG5wcEI5KzNQakdHTWNEbjExMTlnRlNBbWNsVVFJd2YzQjY1RU5aeGM5dzdlbE9wcmpibjNSZ2NBMmx6dmJhQmM3SmxDdmljc25KUnpuTlpSdnhhVkx6MFRpc2dXWTFZY3RFU2hXcUs1YllxZ1RVUFo3cmJaN0NpeTU3VjhtN1liclpYVXN4K3lmWm5FQ1B6dkp5b3hsQ3pJd3VUUWd4M3lzSm1uc0QzQVRieE1FTGdMdFU5anA2Z2RUKzEyOVZYV1ZyN0hHNHR6SURBSUI4VkxaVEJqaHhRWTRqenltKzIyTG9IaWYwM1huVVlIK1ZGMmNBazc4dVdCaUNkQmtIcWd1VWs2M0E9PQ==\\r\\nX-SES-DKIM-SIGNATURE: a=rsa-sha256; q=dns/txt; b=XH7Cy8VtplePQbGI2JndadMaSQRzuFCUCQl3RRIFpN+eZgS06eyYut3gar8ds6b1mHzNwSsBB5cj5YAF/GompbFbWV2GL04XqDSxvfrdlTkv+qA0SQLnveyFUDJTKlPPr8TjF2G+k2s8BFgchLyR+IBbmPHeH+jNknvqNArh77w=; c=relaxed/simple; s=shh3fegwg5fppqsuzphvschd53n6ihuv; d=amazonses.com; t=1589015776; v=1; bh=h0K5Yz299OBRJv28xIMZ/L633w+wjm31dUktgDO7sHg=; h=From:To:Cc:Bcc:Subject:Date:Message-ID:MIME-Version:Content-Type:X-SES-RECEIPT;\\r\\nReceived: by mail-oi1-f180.google.com with SMTP id o7so10735431oif.2\\r\\n for ; Sat, 09 May 2020 02:16:15 -0700 (PDT)\\r\\nDKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;\\r\\n d=example.com; s=google;\\r\\n h=mime-version:from:date:message-id:subject:to;\\r\\n bh=h0K5Yz299OBRJv28xIMZ/L633w+wjm31dUktgDO7sHg=;\\r\\n b=Vg0zgLNrgypVuHn7dOM1j1xZz9zifdKm/8BJSVCZMPza8e5bsCI/MOPqQxv8KaKTOZ\\r\\n KPpq2uNMhw/ueG/bc04WvoJrYX3/vAzMDXLf8oPvLuLyjfaePc68hSQr5fHzOxzmuLei\\r\\n 9sKo7CthTQIrW0s1a27xWHc3UT96fEdw2BdSI=\\r\\nX-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;\\r\\n d=1e100.net; s=20161025;\\r\\n h=x-gm-message-state:mime-version:from:date:message-id:subject:to;\\r\\n bh=h0K5Yz299OBRJv28xIMZ/L633w+wjm31dUktgDO7sHg=;\\r\\n b=sINpYmONoM0qeQnebY9hQK4EtWUq8xq5tnbjE7box8LHPsGMrrQyIiH9/IIbiH7oUg\\r\\n NE0FItezKdzD4RiOh3C48RpvrP7yGg3w9n3FyuJ/8JjJ6endtnGRwIma3LkJygz+3FzE\\r\\n Sire7dZVCwij0WquBXJ2WKjemFiPPg6M002pYD8F6ZpNPjuL1+qtUiLoSUGFy6hYvMNa\\r\\n FVRUyVZil8Sd6n3DL5R3FhVSNB1MptWm2CTIgv2+dEyXf5cO0sn6LDPgO3Jx2LO5/oyn\\r\\n +SdNJsc86nbXEjA7aL9pMlU0YdRMIbpwYHPvvyWT3K5hB6wnYF+hAyTn454ACXdduYi3\\r\\n E72g==\\r\\nX-Gm-Message-State: AGi0PuZnRiX/3B0rQ6UV4cR4oucLl9xNu5Vm2LQzGB+wZPNGquEwxctp\\r\\n\\txqfK7mfh70F01tIxZ1H74HKDGTD71OiJ6e9D8hHn+J8t\\r\\nX-Google-Smtp-Source: APiQypJYIgvF7HgWijswlpCCmdg46BkfhUhhqSk1JllbbMoxs1ntBGx8iXfpjMD1ton1sdL3L4HFJsawRsBwK4+ZDF4=\\r\\nX-Received: by 2002:aca:ba86:: with SMTP id k128mr13817762oif.60.1589015774221;\\r\\n Sat, 09 May 2020 02:16:14 -0700 (PDT)\\r\\nMIME-Version: 1.0\\r\\nFrom: Email Sender \\r\\nDate: Sat, 9 May 2020 10:16:03 +0100\\r\\nMessage-ID: \\r\\nSubject: testing\\r\\nTo: recipient@example.com\\r\\nContent-Type: multipart/alternative; boundary=\\\"000000000000c3f47c05a533908c\\\"\\r\\n\\r\\n--000000000000c3f47c05a533908c\\r\\nContent-Type: text/plain; charset=\\\"UTF-8\\\"\\r\\n\\r\\ntest message\\r\\n\\r\\n--000000000000c3f47c05a533908c\\r\\nContent-Type: text/html; charset=\\\"UTF-8\\\"\\r\\n\\r\\n
test message
\\r\\n\\r\\n--000000000000c3f47c05a533908c--\\r\\n\"}", - "Timestamp": "2020-05-09T09:16:16.406Z", - "SignatureVersion": "1", - "Signature": "0Qyky3c4BopZI4B0dGGgZJxR56ayW4j9Pulx/+z7bs+KsRuOew8zHkCuEil4\nLZ75+9Xtt5dJRbtV0FZXF7m80PwiB0n0XfMuLCALqWtuki+4oxnVn+vFHCxR\n/96EVmrd/bOT9wwaQ5xmaku1bmXyYUiXCGr5I0VLMGENT6dlL/Nu1bI7WTOf\nLI3DV8ed8UCCgwYCZlVJqQbUwBjZsZRWFelk2dsH23TT0kH7emU4HYPm9Rpp\ngXZkz5VzPuT0xTYcQ9iLpw6CLNRn1RSYHmpf0rGnt5xXgsT6rHdqmCOII280\nxILxGdOo+wnwZC1txZ3D1e/BfqztexZpG/6pQZfyXw==\n", - "SigningCertURL": "https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem", - "UnsubscribeURL": "https://sns.eu-west-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:eu-west-1:012345678910:example-topic:abcdef01-abc1-abc1-abc1-abcdef123456" -} \ No newline at end of file diff --git a/spec/fixtures/json/inbound_email_s3.json b/spec/fixtures/json/inbound_email_s3.json deleted file mode 100644 index 55f3c6ff..00000000 --- a/spec/fixtures/json/inbound_email_s3.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "Type": "Notification", - "MessageId": "abc12345-abc1-abc1-abc1-abc123456789", - "TopicArn": "arn:aws:sns:eu-west-1:012345678910:example-topic", - "Subject": "Amazon SES Email Receipt Notification", - "Message": "{\"notificationType\":\"Received\",\"mail\":{\"timestamp\":\"2020-09-02T01:30:50.233Z\",\"source\":\"sender@example.com\",\"messageId\":\"17at0jiq08p0449huhf16qsmdi6sa1ltm069t801\",\"destination\":[\"recipient@example.com\"],\"headersTruncated\":false,\"headers\":[{\"name\":\"Return-Path\",\"value\":\"\"},{\"name\":\"Received\",\"value\":\"from NAM11-DM6-obe.outbound.protection.outlook.com (mail-dm6nam11on2115.outbound.protection.outlook.com [40.107.223.115]) by inbound-smtp.us-east-1.amazonaws.com with SMTP id 17at0jiq08p0449huhf16qsmdi6sa1ltm069t801 for recipient@example.com; Wed, 02 Sep 2020 01:30:50 +0000 (UTC)\"},{\"name\":\"X-SES-Spam-Verdict\",\"value\":\"PASS\"},{\"name\":\"X-SES-Virus-Verdict\",\"value\":\"PASS\"},{\"name\":\"Received-SPF\",\"value\":\"none (spfCheck: 40.107.223.115 is neither permitted nor denied by domain of uiowa.edu) client-ip=40.107.223.115; envelope-from=sender@example.com; helo=mail-dm6nam11on2115.outbound.protection.outlook.com;\"},{\"name\":\"Authentication-Results\",\"value\":\"amazonses.com; spf=none (spfCheck: 40.107.223.115 is neither permitted nor denied by domain of uiowa.edu) client-ip=40.107.223.115; envelope-from=sender@example.com; helo=mail-dm6nam11on2115.outbound.protection.outlook.com; dkim=pass header.i=@iowa.onmicrosoft.com; dmarc=fail header.from=uiowa.edu;\"},{\"name\":\"X-SES-RECEIPT\",\"value\":\"AEFBQUFBQUFBQUFHMWlxem9Gb1ZOemNkamlTeFlYdlZUSmUwVVZhYndjK213dHFIM0dVRTYwUlk1UlpBQVVVTXhQRUd1MTN6YTFJalp0TFdMZjhOOUZGSlJCYkxEV2craXhpOG02d2xDc2FtY2dNdVMvRE9QWWpNVkxBWVZzMyt5MHBTUXV5KzM5aDY1Vng5UnZsZTdTK2dGVDF5RVc1QndOd0xvbndNRlR3TDZjd2cxT2c2UVFQbVN2andMS09VM2R5elFrTGk3RnF0WXI3WDZ1alhkUzJxdzhzU1dwT3FPZEFsU0VNc3RpTWM0QStFZDB5RFd5SnpRelBJWnJjelZPRytudEVpNTc5dVZRUXMra2lrby9wOExhR3JqTi9xNkZnNHREN3BmSmVYS25Jeis2NDRyaEE9PQ==\"},{\"name\":\"X-SES-DKIM-SIGNATURE\",\"value\":\"a=rsa-sha256; q=dns/txt; b=WGBoUguIq9047YXpCaubVCtm/ISR3JEVkvm/yAfL2MrAryQcYsTdUM6zzStPyvOm0QsonOKsWJ0O2YyuQDX1dvBmggdeUqZq08laD+Xuy1L6ODm0O/EQE9wDitj0KqXxOgMr3oM7tpcTTGLcCgXERFZbmI+1ACeeA7fbylMasIM=; c=relaxed/simple; s=224i4yxa5dv7c2xz3womw6peuasteono; d=amazonses.com; t=1599010250; v=1; bh=FUugtX/z1FFtLvVfaVhPhqhi4Gvo1Aam67iRPZYKfTo=; h=From:To:Cc:Bcc:Subject:Date:Message-ID:MIME-Version:Content-Type:X-SES-RECEIPT;\"},{\"name\":\"ARC-Seal\",\"value\":\"i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Q/Sjx2jglTDjAuzScT/G47EngqUbAoJ6QRr1YXHzCJo7FLHyH16OuE+DmmOqQGiiAQjV4jooqaOGMg/iYLGvebTH3O//kXe1LfK+b6Ixwrom9B2X0KkHdBrRrbtD503NjUGzbjXruZVDajQnhmjA79YhqedZPTfrz7OijinyTQNLWhtp5JrC9olVfGNGvj9h1kU7t2j6sWc/8Fi9REDT/HYEJOBxwSoKVcDtyGw9+3D/RhrTGycE0xcWWmtgAgDmmGzvhXef/FBENzObP3VPMeSyty2Lr/j8nxgtnC4Lv/SFE4eKIVAMbabN26Oqbe4ZaRjlouqVJuDUm5ZS/9NE2w==\"},{\"name\":\"ARC-Message-Signature\",\"value\":\"i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=FUugtX/z1FFtLvVfaVhPhqhi4Gvo1Aam67iRPZYKfTo=; b=a75mHcfAxpG1bEdE+DrfQxdjffOeG5B90ORE3hHh4zwotRp0S4ZHYCZmDBEEsk6QeF92941w7fDQuNxdto+Ah309oHlfxvuJT+EYNNvFAdGY1y7zUQGV0a7OfquOU8FWgchRUkz09vVtfFxiF9znbApaWpIbsVXeZ1+D3JcVsUXEpENNSOn+jYZEA30VlKNRESzHeAnniWn5E6FlQfQebRpgHTx3iGo0r1ykVq0pzzDrVsB9308U/TivWqoGVvhEy5ocx8Lx6I12pAny6XoD8RQRjxanteJG8hSzPuNJLqrcLeJTeC+/vDytmRd9WHjF3XlqfrZh3Q2A+nn1dY0LUg==\"},{\"name\":\"ARC-Authentication-Results\",\"value\":\"i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=uiowa.edu; dmarc=pass action=none header.from=uiowa.edu; dkim=pass header.d=uiowa.edu; arc=none\"},{\"name\":\"DKIM-Signature\",\"value\":\"v=1; a=rsa-sha256; c=relaxed/relaxed; d=iowa.onmicrosoft.com; s=selector2-iowa-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=FUugtX/z1FFtLvVfaVhPhqhi4Gvo1Aam67iRPZYKfTo=; b=UWYfhLXbr1DsFV4wrrkIF4AqHgLrYQvwUdnGvSdvjv1F5Gc/0UzgvxVxmmeJ4Zf/j4AK3itFqt78HuyfOu32ofFFiZ9YIGrUZLF6XBb/cxqo+B1sF8qObP7QB4G8EpcswBtutMHMgX3WMNm3R637j7Xxho7TUWmKoD+Y758WDxk=\"},{\"name\":\"Received\",\"value\":\"from BN6PR04MB0962.namprd04.prod.outlook.com (2603:10b6:405:3e::26) by BN6PR04MB1172.namprd04.prod.outlook.com (2603:10b6:404:97::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3326.19; Wed, 2 Sep 2020 01:30:43 +0000\"},{\"name\":\"Received\",\"value\":\"from BN6PR04MB0962.namprd04.prod.outlook.com ([fe80::81b1:3359:e0e8:7ef4]) by BN6PR04MB0962.namprd04.prod.outlook.com ([fe80::81b1:3359:e0e8:7ef4%5]) with mapi id 15.20.3326.025; Wed, 2 Sep 2020 01:30:43 +0000\"},{\"name\":\"From\",\"value\":\"\\\"Sender\\\" \"},{\"name\":\"To\",\"value\":\"\\\"recipient@example.com\\\" \"},{\"name\":\"Subject\",\"value\":\"Test 500\"},{\"name\":\"Thread-Topic\",\"value\":\"Test 500\"},{\"name\":\"Thread-Index\",\"value\":\"AQHWgMisvDz2gn/lKEK/giPayBxk7g==\"},{\"name\":\"Date\",\"value\":\"Wed, 2 Sep 2020 01:30:43 +0000\"},{\"name\":\"Message-ID\",\"value\":\"<1344C740-07D3-476E-BEE7-6EB162294DF6@uiowa.edu>\"},{\"name\":\"Accept-Language\",\"value\":\"en-US\"},{\"name\":\"Content-Language\",\"value\":\"en-US\"},{\"name\":\"X-MS-Has-Attach\",\"value\":\"\"},{\"name\":\"X-MS-TNEF-Correlator\",\"value\":\"\"},{\"name\":\"x-mailer\",\"value\":\"Apple Mail (2.3608.120.23.2.1)\"},{\"name\":\"authentication-results\",\"value\":\"icts-oasis-aya.aws.cloud.uiowa.edu; dkim=none (message not signed) header.d=none;icts-oasis-aya.aws.cloud.uiowa.edu; dmarc=none action=none header.from=uiowa.edu;\"},{\"name\":\"x-originating-ip\",\"value\":\"[208.126.206.243]\"},{\"name\":\"x-ms-publictraffictype\",\"value\":\"Email\"},{\"name\":\"x-ms-office365-filtering-correlation-id\",\"value\":\"6ec767f9-50fe-47f8-f3f2-08d84edfcf64\"},{\"name\":\"x-ms-traffictypediagnostic\",\"value\":\"BN6PR04MB1172:\"},{\"name\":\"x-microsoft-antispam-prvs\",\"value\":\"\"},{\"name\":\"x-ms-oob-tlc-oobclassifiers\",\"value\":\"OLM:1728;\"},{\"name\":\"x-ms-exchange-senderadcheck\",\"value\":\"1\"},{\"name\":\"x-microsoft-antispam\",\"value\":\"BCL:0;\"},{\"name\":\"x-microsoft-antispam-message-info\",\"value\":\"HpEwIChVAhsQnQ3n5mZXWg906Tt+O7BVntxsud4Ur/yuUGPG4p0kH9GZCWshG/hT0+S/B+zgZ+LPmjIXZ2RKea4J3RQZrT2xuBZ9wUvkwSEF8Su1xvMVqqtoSGsayne41kRtpWEXo82HYqRYA9wWZuUsCpug4QOTN/ivvbEqCzKEEf+VrJ2WAzTD3qYJVqzdxlo4CJav7MXOdM4DaTBPgkEvI7arkhnJVwvrfW+SKrMAT7SdUX9jPk/mveWiiwCyfMG/9mQPLW241uWnoRIY1ruXUmCgUrcWzIw4DYfDpFnvPHtJlZiHmvN3MXAYKysyT4jlS1+2g2SQ3FSZ7y4xJg==\"},{\"name\":\"x-forefront-antispam-report\",\"value\":\"CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:BN6PR04MB0962.namprd04.prod.outlook.com;PTR:;CAT:NONE;SFS:(4636009)(39860400002)(376002)(136003)(396003)(366004)(346002)(478600001)(2616005)(8676002)(6512007)(26005)(186003)(75432002)(66476007)(64756008)(66446008)(6506007)(6486002)(66946007)(91956017)(76116006)(66556008)(6916009)(2906002)(36756003)(8936002)(7116003)(316002)(558084003)(296002)(71200400001)(86362001)(19618925003)(33656002)(786003)(239884005)(558944008)(19559445001)(15288005002);DIR:OUT;SFP:1102;\"},{\"name\":\"x-ms-exchange-antispam-messagedata\",\"value\":\"UWWfowj4v8QhFJ48meC6ss7DXF28aXo/r7e6BUMtRz53j+lxuv9earKL7TTePwyVwaU3DHCfwCbNuuhej7zI6sJrn9eV81CVEjR29vZoVPtCgdyMQ/ah/ksInpHswnADVEu0hcs8oVQByrhnT7QRQfowYJC3FBeOta2/Vy2zf8TsfY32ddQdBr3qT2akkJp34AI1GDKgCqZKgojFTw5Lp08YJ9VMNXxCChQbnrtUSBOn+jTMU9/NuDazCrQ/HQGZm3WTaq6Z97MBYwMyeGUmhlT/h3lUVC+5r59NYofVentjcGPSQS7NQ7T5QLfM6JymE9dNR43zIK2nfL713wtC70cfNrQjrEXB0uX7pjLfVeWm4zamJa3kGj9ca/FaAY/ZUv9S3dte3r/I9Tj7SxJk5d7E6IHcq+YoDL/X35N1/+0DQ4JRsCL32AomZHS2+EoSMMjyjatEn/EHngMmD60Zrnr8GKQz7RuuAvCsW5EFzeuPNv2ZvBV2iXe5FyCpXXMI5Ka+4ETl43YZLH8GqGAARkaShPO4W9fnJ/TwDqsERyLm1epqB71M9r+359eA1bMGqfRb0B8IMDYOav3/8216r1vJPi81JN6QVNIJi/FbUDwJ9CespzH7QlTrlvgq/N8ksQqveVv5K38LfIG7CJULaA==\"},{\"name\":\"x-ms-exchange-transport-forked\",\"value\":\"True\"},{\"name\":\"Content-Type\",\"value\":\"text/plain; charset=\\\"us-ascii\\\"\"},{\"name\":\"Content-ID\",\"value\":\"\"},{\"name\":\"Content-Transfer-Encoding\",\"value\":\"quoted-printable\"},{\"name\":\"MIME-Version\",\"value\":\"1.0\"},{\"name\":\"X-OriginatorOrg\",\"value\":\"uiowa.edu\"},{\"name\":\"X-MS-Exchange-CrossTenant-AuthAs\",\"value\":\"Internal\"},{\"name\":\"X-MS-Exchange-CrossTenant-AuthSource\",\"value\":\"BN6PR04MB0962.namprd04.prod.outlook.com\"},{\"name\":\"X-MS-Exchange-CrossTenant-Network-Message-Id\",\"value\":\"6ec767f9-50fe-47f8-f3f2-08d84edfcf64\"},{\"name\":\"X-MS-Exchange-CrossTenant-originalarrivaltime\",\"value\":\"02 Sep 2020 01:30:43.6328 (UTC)\"},{\"name\":\"X-MS-Exchange-CrossTenant-fromentityheader\",\"value\":\"Hosted\"},{\"name\":\"X-MS-Exchange-CrossTenant-id\",\"value\":\"1bc44595-9aba-4fc3-b8ec-7b94a5586fdc\"},{\"name\":\"X-MS-Exchange-CrossTenant-mailboxtype\",\"value\":\"HOSTED\"},{\"name\":\"X-MS-Exchange-CrossTenant-userprincipalname\",\"value\":\"bL8rIxZl0Sld3xLq4rMTj0vEP7WADWvl5tk2iCPL4YSID4PRlR8zvzmNO2cf7dk8dtcfLmTHpKvS3wOY9ihFdA==\"},{\"name\":\"X-MS-Exchange-Transport-CrossTenantHeadersStamped\",\"value\":\"BN6PR04MB1172\"}],\"commonHeaders\":{\"returnPath\":\"sender@example.com\",\"from\":[\"\\\"Sender\\\" \"],\"date\":\"Wed, 2 Sep 2020 01:30:43 +0000\",\"to\":[\"\\\"recipient@example.com\\\" \"],\"messageId\":\"<1344C740-07D3-476E-BEE7-6EB162294DF6@uiowa.edu>\",\"subject\":\"Test 500\"}},\"receipt\":{\"timestamp\":\"2020-09-02T01:30:50.233Z\",\"processingTimeMillis\":607,\"recipients\":[\"recipient@example.com\"],\"spamVerdict\":{\"status\":\"PASS\"},\"virusVerdict\":{\"status\":\"PASS\"},\"spfVerdict\":{\"status\":\"GRAY\"},\"dkimVerdict\":{\"status\":\"GRAY\"},\"dmarcVerdict\":{\"status\":\"FAIL\"},\"action\":{\"type\":\"S3\",\"topicArn\":\"arn:aws:sns:us-east-1:433802195282:yourapp-receipt-sns\",\"bucketName\":\"yourapp-uploads20200818192940697500000001\",\"objectKey\":\"17at0jiq08p0449huhf16qsmdi6sa1ltm069t801\"},\"dmarcPolicy\":\"none\"}}", - "Timestamp": "2020-09-02T01:30:50.862Z", - "SignatureVersion": "1", - "Signature": "RNDPMv2Z5x09OECBbuuR3T4OiGuUpo4BdUVVaez5dFFiO3x29vA1D8QixUNl\n2K0sxEqgEe++GMNWSOgEfXF51fj6n0fD0xuol6FlcPN+ST/83+rKwe3KNajj\n+Voc1MPm5Htb328Lnhc3MFZyeM0YIgykqE75zAk0+3lAhk/4tnKsi0Cz7PIz\nq3mT6BwZbo9tRNBoniKg4hpEy4ePNLX3FZ9B4jFyaHXJ+KbpvEY0LYsIDbUA\nO4VP7+Q4gjfhKO4s1N+0KW5soBl/98ymgiBA4Yo9QBZeFwkQKItwdr/utuWA\noBdRkgpqv/Ac5/dIMTXT/K1SUkqMgxOEPWtk6RiI3A==\n", - "SigningCertURL": "https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem", - "UnsubscribeURL": "https://sns.eu-west-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:eu-west-1:012345678910:example-topic:abcdef01-abc1-abc1-abc1-abcdef123456" -} \ No newline at end of file diff --git a/spec/fixtures/json/invalid_signature.json b/spec/fixtures/json/invalid_signature.json deleted file mode 100644 index 7b9fb5bd..00000000 --- a/spec/fixtures/json/invalid_signature.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "Type" : "SubscriptionConfirmation", - "MessageId" : "abc12345-abc1-abc1-abc1-abc123456789", - "Token" : "abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1", - "TopicArn" : "arn:aws:sns:eu-west-1:012345678910:example-topic", - "Message" : "You have chosen to subscribe to the topic arn:aws:sns:eu-west-1:012345678910:example-topic. To confirm the subscription, visit the SubscribeURL included in this message.", - "SubscribeURL" : "https://sns.eu-west-1.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:eu-west-1:012345678910:example-topic&Token=abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234", - "Timestamp" : "2020-05-07T07:25:25.364Z", - "SignatureVersion" : "1", - "Signature" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==", - "SigningCertURL" : "https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem" -} diff --git a/spec/fixtures/json/recognized_topic_subscription_request.json b/spec/fixtures/json/recognized_topic_subscription_request.json deleted file mode 100644 index a1ca6fb4..00000000 --- a/spec/fixtures/json/recognized_topic_subscription_request.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "Type": "SubscriptionConfirmation", - "MessageId": "abc12345-abc1-abc1-abc1-abc123456789", - "Token": "abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1", - "TopicArn": "arn:aws:sns:eu-west-1:012345678910:recognized-topic", - "Message": "You have chosen to subscribe to the topic arn:aws:sns:eu-west-1:012345678910:recognized-topic. To confirm the subscription, visit the SubscribeURL included in this message.", - "SubscribeURL": "https://sns.eu-west-1.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:eu-west-1:012345678910:recognized-topic&Token=abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234", - "Timestamp": "2020-05-07T07:25:25.364Z", - "SignatureVersion": "1", - "Signature": "cjaRd4N8UcSsW7HszXfmAxECIJNcE1LDnUMocbksvw3naD7eGaK0adcRm54u\nzhypWoEUFSbxzysdo5JIzzgoSHV+1X/mmK45ToDCNrV2djfMUl301aslcM7g\n76lSCDlR7fH6d/V7OcCmxxW18VQfFCm0RR6/w1P/Ds1+++UDmt5OM57LrJ3x\nvxPLV6TfO/q2kBrQwQFXP8ewhieBnNJnlGmmMIOZi5vfepzTlxiniV8V/1zY\nxgmZfla3u7ugIG0PKLv+iTVCy4E/Z6bCUqPUY7d551iBTbaHP4YjhQ07P5NR\nrRSzlJYu52mBRtR5QAxSI7QItwt2EIVVcOI2npzM7g==\n", - "SigningCertURL": "https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem" -} \ No newline at end of file diff --git a/spec/fixtures/json/unrecognized_topic_subscription_request.json b/spec/fixtures/json/unrecognized_topic_subscription_request.json deleted file mode 100644 index b5348a86..00000000 --- a/spec/fixtures/json/unrecognized_topic_subscription_request.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "Type": "SubscriptionConfirmation", - "MessageId": "abc12345-abc1-abc1-abc1-abc123456789", - "Token": "abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1", - "TopicArn": "arn:aws:sns:eu-west-1:012345678910:unrecognized-topic", - "Message": "You have chosen to subscribe to the topic arn:aws:sns:eu-west-1:012345678910:unrecognized-topic. To confirm the subscription, visit the SubscribeURL included in this message.", - "SubscribeURL": "https://sns.eu-west-1.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:eu-west-1:012345678910:unrecognized-topic&Token=abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234", - "Timestamp": "2020-05-07T07:25:25.364Z", - "SignatureVersion": "1", - "Signature": "kxMQFU2DTFmvTrVWjPT6Op962Nad0a9oCv5iLqGL+sa2wb5DVGXdRwoo2IOo\nwGYvVGDkaI2sJxiMvdsOMc/2hQP+S1lDDvmDvs/QjM5ww8SdENrAYpBRfi5i\nYP7dupKyZ5XcpDOHoB++ORuq7Ydg7+AWrRnbEMn5mGYiHV+PGqQVzomNz5HO\ntNtxoO/bhIwPSPp+pPM/bX40U/jAR1xzVzmeAPwqCVseqcG9Mju0znA9nW0p\nVpKtAR6Be90mBbsm+6b5BzZyZsdYAmiqGP91MFP1r1tPb/gNNtfOcyWNT6pO\nwWq0a/+e+wp953ydLTJUKze4AkuTHzuhP7cPEPSKSQ==\n", - "SigningCertURL": "https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem" -} \ No newline at end of file diff --git a/spec/fixtures/json/valid_signature.json b/spec/fixtures/json/valid_signature.json deleted file mode 100644 index 5dc99eae..00000000 --- a/spec/fixtures/json/valid_signature.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "Type": "SubscriptionConfirmation", - "MessageId": "abc12345-abc1-abc1-abc1-abc123456789", - "Token": "abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1", - "TopicArn": "arn:aws:sns:eu-west-1:012345678910:example-topic", - "Message": "You have chosen to subscribe to the topic arn:aws:sns:eu-west-1:012345678910:example-topic. To confirm the subscription, visit the SubscribeURL included in this message.", - "SubscribeURL": "https://sns.eu-west-1.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:eu-west-1:012345678910:example-topic&Token=abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234", - "Timestamp": "2020-05-07T07:25:25.364Z", - "SignatureVersion": "1", - "Signature": "1a13u6m1qaBul+9lPdIX0E0c/qDaRSlFcTiETJnMizRoMS9YrKi/ZXYi/dVr\n4kaHt8c++dWoHgOiXm+AZrmYqyIUC5pjtJkHSowf4SkABQLuCDiEkl5lN5jx\niORunX/7Cuu7u0tgqfSIOtgiKUxSMttM+HvM0jeL67Osklu6cS/dxgPN5gv0\nKghMV/+aeCZ59YjBHhWlR3XXlVnlO2ttQ1UQI/PwrC3CRojla7jZX7s/Vjbu\nZFbdxzsR9iRaJJsVl0Glc9fAkvHbpX+7ulw1NuXToJyOwStEJqUIAmJXEbwA\nDANNncnQNpGJMbsCP7mSCZ5jNNZ7iF2E72sMN2zfDg==\n", - "SigningCertURL": "https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem" -} \ No newline at end of file diff --git a/spec/fixtures/pem/certificate.pem b/spec/fixtures/pem/certificate.pem deleted file mode 100644 index 8a2debae..00000000 --- a/spec/fixtures/pem/certificate.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDQjCCAiqgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBLMRMwEQYKCZImiZPyLGQB -GRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVieS1sYW5nMRkwFwYDVQQDDBBSdWJ5 -IGNlcnRpZmljYXRlMB4XDTI0MDcxODEzNTYwMloXDTI1MDcxODEzNTYwMlowSzET -MBEGCgmSJomT8ixkARkWA29yZzEZMBcGCgmSJomT8ixkARkWCXJ1YnktbGFuZzEZ -MBcGA1UEAwwQUnVieSBjZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBANo4bPJC3wSyz08AdqQ+0wd61fyilOcSR0+5+ZKHCz//0hbk064F -BEvQ1ir1AS2hprAAqKQoKX62OWdaJgtsp/fgmJmjG1XPT/MTc9Zdnn9MO5MrA94G -IcnFhty8YI5/+HtSuVDQedtriZEQDTNorYhkX2zUX4zyv34RGEEYmwAJVPEApNMS -1xFVjBBmcHZqHavsKFSDmdHK6m5bhk1V4sLqHPVeaOA9EuZm1TeKY9VxL3PoEJwv -0hXEZKHxKQuGhzBGgsMQJnPsWnZJ0WPNM6/ka7Qfonp/U/CErXuPQl2XoHl85aSV -0X0EIfSw8PKEB1IUJC6aAZDrrD8yNurR4M0CAwEAAaMxMC8wDgYDVR0PAQH/BAQD -AgeAMB0GA1UdDgQWBBRp3PGg7ef7OHxvS/OcvR7aLl79KjANBgkqhkiG9w0BAQsF -AAOCAQEArNP7O/WqYNm9si4JvBFNSqX6pI3JQ4KdmLLJZDb1tu5tBZEbZx/Dc3TX -E8nfC0agNs15tgLRXDQPQ5UcLt/2Qy488gMiONFwAHbRWj6Sr/DagFXFzPpd+LEk -/bgYsCuRqYy1tje72I5grLWFm/rt8uFhquAoaEuYPe3sJXdXxKq+yV0VqWPDKyBc -tNKqAOrSUYfGAB4JQYBmRBMQnGlMEcZrvtDcLkAyRadI3RjLMfnBAflz/KyI5Dbc -WUNsE4LjECSdznehnhhJyPvb/+CRWwMwde3EhZjgalC6POVM54DPOeDLk+v21hKN -OKOpvfyLB+vnTma8CHpSVdSder8tmA== ------END CERTIFICATE----- diff --git a/spec/fixtures/pem/privatekey.pem b/spec/fixtures/pem/privatekey.pem deleted file mode 100644 index 193ff0cc..00000000 --- a/spec/fixtures/pem/privatekey.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEA2jhs8kLfBLLPTwB2pD7TB3rV/KKU5xJHT7n5kocLP//SFuTT -rgUES9DWKvUBLaGmsACopCgpfrY5Z1omC2yn9+CYmaMbVc9P8xNz1l2ef0w7kysD -3gYhycWG3Lxgjn/4e1K5UNB522uJkRANM2itiGRfbNRfjPK/fhEYQRibAAlU8QCk -0xLXEVWMEGZwdmodq+woVIOZ0crqbluGTVXiwuoc9V5o4D0S5mbVN4pj1XEvc+gQ -nC/SFcRkofEpC4aHMEaCwxAmc+xadknRY80zr+RrtB+ien9T8ISte49CXZegeXzl -pJXRfQQh9LDw8oQHUhQkLpoBkOusPzI26tHgzQIDAQABAoIBAE5RjABSsbn89txS -vUHrbk+z7VLzgt9/tupNQ94r64S3qs4eqD4/fLA9LnBSaG7ZInrucZgg9euNOQL3 -3smg4JPdHsedO3VLp1UFOUDJbtYfJQ6HlKa9qqjA5MsaLMlX8nVIVkxD1khCyyeu -DB7URdu6smjbu8NZaBK1ze+nBhI3nP+Dr5tM6XCvHMu6D7BMgTBIPf/+ODlXXuDC -Sj+VE6IIbLYGgma6X1hl4mllg2yt6fjhE2WobMsfUOVAoqPcxEehmVXn44nNIVQM -sG0qHJH+SGnOZux+05IVD5lXE/onSd+njtGpyTjSgZQmZkx+fJuQw4BVfNuzNQJ8 -4jyJ1OECgYEA/6dmP2C27BDGxkz9pH9pkgxPzjHZcFd0AT7HT1oWxUrhZO6C83Lt -/xiGF4qFH22yPXFkbkitxIZdXcwI4EAAeoPPdmEasIvvbChlDpnoWcgELVzShRSx -321Qxh4VdLBQrSlOqtJvEduY8U7/75EEDSCdidoDgW263J1X6kuQ/RUCgYEA2oQN -lET06mhwPOwCATc/ZQJ/QaIaDpPjbi+DB2ZcptKIcbCv5Y+maK3mBYzOGUUyXKcG -EEn/V+m3PaQChAUNK+Uuq700+WBHxynxpGnOG1PjqBlMNuOL/6n/N+QD3LR6uY2S -aSxJAFx+dgZfjm0l4+cGOdf6dMMCTq7nV1lYctkCgYEAj56qKTaa7JksIeDEqTHO -y/ZQqwSEI8FtcPmknGZ+3k0HvFzlggBxxVowkm8GBDbq5+uYwP/hZsMZFoV2AwzR -eAIufVFl3gJu+XLj+sTpq+5asmUv+wU6O8s8kl/6K7iVSgInqH1ZWk3kaMO5sgrk -nL9S4UtxprdPP3rBFeVnyVUCgYBZOjz1Q2ci5LyYE+MJrg6j524hVdkABOGEl8AQ -YHsK38M5cWWR/qN78S6RK5ro9LmI3eb69cxfkJ7ze6pPUGS9fNse46bjAa6to/H5 -Kf8wZ4P5m0Lk0uvS3Q7LOr9c+xF1/VpAugWhMSOufBG+7dDgC/Ed45Rw40Ro7sCm -iWQ1mQKBgQD4eIVgi6ae9rfND52TAMidzzEShWFB6ruoVSCDHjY5pinwy1qQpDGl -qz/4WfOp7+HOcPed95EhfNIKvW71oUBgrmcCFfZ7vEmmUCRbk9D563SHkCri3Vjk -FAOgPBSOQyeZxHDUIQifV3dP/0YxgAjlzyDCI8Pbj62T0FtpY3hLcw== ------END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/spec/fixtures/txt/s3_email.txt b/spec/fixtures/txt/s3_email.txt deleted file mode 100644 index 0e1ace70..00000000 --- a/spec/fixtures/txt/s3_email.txt +++ /dev/null @@ -1,25 +0,0 @@ -Return-Path: -Received: from example.com (example.com [127.0.0.1]) - by inbound-smtp.us-east-1.amazonaws.com with SMTP id 17at0jiq08p0449huhf16qsmdi6sa1ltm069t801 - for test@test.example.com; - Wed, 02 Sep 2020 01:30:50 +0000 (UTC) -X-SES-Spam-Verdict: PASS -X-SES-Virus-Verdict: PASS -X-SES-RECEIPT: AEFBQUFBQUFBQUFHMWlxem9Gb1ZOemNkamlTeFlYdlZUSmUwVVZhYndjK213dHFIM0dVRTYwUlk1UlpBQVVVTXhQRUd1MTN6YTFJalp0TFdMZjhOOUZGSlJCYkxEV2craXhpOG02d2xDc2FtY2dNdVMvRE9QWWpNVkxBWVZzMyt5MHBTUXV5KzM5aDY1Vng5UnZsZTdTK2dGVDF5RVc1QndOd0xvbndNRlR3TDZjd2cxT2c2UVFQbVN2andMS09VM2R5elFrTGk3RnF0WXI3WDZ1alhkUzJxdzhzU1dwT3FPZEFsU0VNc3RpTWM0QStFZDB5RFd5SnpRelBJWnJjelZPRytudEVpNTc5dVZRUXMra2lrby9wOExhR3JqTi9xNkZnNHREN3BmSmVYS25Jeis2NDRyaEE9PQ== -X-SES-DKIM-SIGNATURE: a=rsa-sha256; q=dns/txt; b=WGBoUguIq9047YXpCaubVCtm/ISR3JEVkvm/yAfL2MrAryQcYsTdUM6zzStPyvOm0QsonOKsWJ0O2YyuQDX1dvBmggdeUqZq08laD+Xuy1L6ODm0O/EQE9wDitj0KqXxOgMr3oM7tpcTTGLcCgXERFZbmI+1ACeeA7fbylMasIM=; c=relaxed/simple; s=224i4yxa5dv7c2xz3womw6peuasteono; d=amazonses.com; t=1599010250; v=1; bh=FUugtX/z1FFtLvVfaVhPhqhi4Gvo1Aam67iRPZYKfTo=; h=From:To:Cc:Bcc:Subject:Date:Message-ID:MIME-Version:Content-Type:X-SES-RECEIPT; -From: "Smith, Bob E" -To: "test@test.example.com" - -Subject: Test 500 -Thread-Topic: Test 500 -Thread-Index: AQHWgMisvDz2gn/lKEK/giPayBxk7g== -Date: Wed, 2 Sep 2020 01:30:43 +0000 -Message-ID: <1344C740-07D3-476E-BEE7-6EB162294DF6@example.com> -Accept-Language: en-US -Content-Language: en-US -Content-Type: text/plain; charset="us-ascii" -Content-ID: -Content-Transfer-Encoding: quoted-printable -MIME-Version: 1.0 - -Aaaron diff --git a/spec/test_helper.rb b/spec/test_helper.rb index 920ed2c6..5a731e20 100644 --- a/spec/test_helper.rb +++ b/spec/test_helper.rb @@ -3,24 +3,4 @@ ENV['RAILS_ENV'] = 'test' require_relative 'dummy/config/environment' -require 'webmock/rspec' require 'rspec/rails' - -ActiveRecord::Migration.maintain_test_schema! - -class TestMailer < ActionMailer::Base - layout nil - - def deliverable(options = {}) - headers(options.delete(:headers)) - mail(options) - end -end - -def fixture_for(name, type:) - File.read(File.join('spec', 'fixtures', type.to_s, "#{name}.#{type}")) -end - -RSpec.configure do |config| - config.use_transactional_fixtures = true -end diff --git a/tasks/fixtures.rake b/tasks/fixtures.rake deleted file mode 100644 index e183ce21..00000000 --- a/tasks/fixtures.rake +++ /dev/null @@ -1,68 +0,0 @@ -# frozen_string_literal: true - -require 'openssl' -require 'json' -require 'base64' - -PRIVATE_KEY = 'spec/fixtures/pem/privatekey.pem' -CERTIFICATE = 'spec/fixtures/pem/certificate.pem' -AWS_FIXTURES = FileList['spec/fixtures/json/*.json'].exclude('**/*/invalid_signature.json') -SIGNABLE_KEYS = %w[ - Message - MessageId - Subject - SubscribeURL - Timestamp - Token - TopicArn - Type -].freeze - -file PRIVATE_KEY do |t| - key = OpenSSL::PKey::RSA.new 2048 - File.write(t.name, key.to_pem) -end - -file CERTIFICATE => PRIVATE_KEY do |t| - key = OpenSSL::PKey::RSA.new File.read(PRIVATE_KEY) - cert = OpenSSL::X509::Certificate.new - cert.version = 2 - cert.serial = 2 - cert.subject = OpenSSL::X509::Name.parse '/DC=org/DC=ruby-lang/CN=Ruby certificate' - cert.issuer = cert.subject # root CA is the issuer - cert.public_key = key.public_key - cert.not_before = Time.now - cert.not_after = cert.not_before + (1 * 365 * 24 * 60 * 60) # 10 years validity - ef = OpenSSL::X509::ExtensionFactory.new - ef.subject_certificate = cert - ef.issuer_certificate = cert - cert.add_extension(ef.create_extension('keyUsage', 'digitalSignature', true)) - cert.add_extension(ef.create_extension('subjectKeyIdentifier', 'hash', false)) - cert.sign(key, OpenSSL::Digest.new('SHA256')) - - File.write(t.name, cert.to_pem) -end -task certificates: [PRIVATE_KEY, CERTIFICATE] - -desc 'Sign AWS SES fixtures, must be called if fixtures are modified.' -task sign_aws_fixtures: :certificates do - def canonical_string(message) - parts = [] - - SIGNABLE_KEYS.each do |key| - value = message[key] - parts << "#{key}\n#{value}\n" unless value.nil? || value.empty? - end - parts.join - end - - key = OpenSSL::PKey::RSA.new File.read(PRIVATE_KEY) - - AWS_FIXTURES.each do |fixture| - data = JSON.parse File.read(fixture) - string = canonical_string(data) - signed_string = key.sign('SHA1', string) - data['Signature'] = Base64.encode64(signed_string) - File.write(fixture, JSON.pretty_generate(data)) - end -end