mail_xoauth2 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/LICENSE +21 -0
 - data/README.markdown +30 -0
 - data/lib/mail_xoauth2/imap_xoauth2_authenticator.rb +24 -0
 - data/lib/mail_xoauth2/oauth2_string.rb +17 -0
 - data/lib/mail_xoauth2/smtp_xoauth2_authenticator.rb +38 -0
 - data/lib/mail_xoauth2/version.rb +3 -0
 - data/lib/mail_xoauth2.rb +5 -0
 - data/test/helper.rb +46 -0
 - data/test/test_imap_xoauth2_authenticator.rb +30 -0
 - data/test/test_oauth2_string.rb +35 -0
 - data/test/test_smtp_xoauth2_authenticator.rb +56 -0
 - metadata +84 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA256:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 27a0ef9770c2172e574541dbb950bc4f7b074163a42903acfeadf2570c95609c
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 499e917ef4edf4e6f4f3a3f8f51f5305f60c1d67bd6706ce94f8644ef331a2ff
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: b0dcd0f7f2c8fbd565b680866e7a29e72e9c8acb3891be7a36e521913dd53ff392a9490d5c3ef94354324f127efe0e78c881ddc9294ecd65cadf56529c7c0ba0
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 9a4f954d7350be1d603de16aa1cd813c2046d1516ffe99cb7b4ee13b5e4bece972a0fcd9b778777f166e39a44fc71a5049f755bd1acaecf1a201b6db66518d14
         
     | 
    
        data/LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            MIT License
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Copyright (c) 2018 Mailbutler
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy
         
     | 
| 
      
 6 
     | 
    
         
            +
            of this software and associated documentation files (the "Software"), to deal
         
     | 
| 
      
 7 
     | 
    
         
            +
            in the Software without restriction, including without limitation the rights
         
     | 
| 
      
 8 
     | 
    
         
            +
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         
     | 
| 
      
 9 
     | 
    
         
            +
            copies of the Software, and to permit persons to whom the Software is
         
     | 
| 
      
 10 
     | 
    
         
            +
            furnished to do so, subject to the following conditions:
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be included in all
         
     | 
| 
      
 13 
     | 
    
         
            +
            copies or substantial portions of the Software.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         
     | 
| 
      
 16 
     | 
    
         
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         
     | 
| 
      
 17 
     | 
    
         
            +
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         
     | 
| 
      
 18 
     | 
    
         
            +
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         
     | 
| 
      
 19 
     | 
    
         
            +
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         
     | 
| 
      
 20 
     | 
    
         
            +
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
         
     | 
| 
      
 21 
     | 
    
         
            +
            SOFTWARE.
         
     | 
    
        data/README.markdown
    ADDED
    
    | 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # mail_xoauth2 
         
     | 
| 
      
 2 
     | 
    
         
            +
            Get access to IMAP and STMP via OAuth2, using the standard Ruby Net libraries.
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            This gem is based on and inspired by [gmail_xoauth](https://github.com/nfo/gmail_xoauth).
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            ### IMAP OAuth 2.0
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 11 
     | 
    
         
            +
            require 'mail_xoauth2'
         
     | 
| 
      
 12 
     | 
    
         
            +
            imap = Net::IMAP.new('imap.gmail.com', 993, usessl = true, certs = nil, verify = false)
         
     | 
| 
      
 13 
     | 
    
         
            +
            imap.authenticate('XOAUTH2', 'myemail@gmail.com', my_oauth2_token)
         
     | 
| 
      
 14 
     | 
    
         
            +
            messages_count = imap.status('INBOX', ['MESSAGES'])['MESSAGES']
         
     | 
| 
      
 15 
     | 
    
         
            +
            puts "Seeing #{messages_count} messages in INBOX"
         
     | 
| 
      
 16 
     | 
    
         
            +
            ```
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            ### SMTP OAuth 2.0
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 21 
     | 
    
         
            +
            require 'mail_xoauth2'
         
     | 
| 
      
 22 
     | 
    
         
            +
            smtp = Net::SMTP.new('smtp.gmail.com', 587)
         
     | 
| 
      
 23 
     | 
    
         
            +
            smtp.enable_starttls_auto
         
     | 
| 
      
 24 
     | 
    
         
            +
            smtp.start('gmail.com', 'myemail@gmail.com', my_oauth2_token, :xoauth2)
         
     | 
| 
      
 25 
     | 
    
         
            +
            smtp.finish
         
     | 
| 
      
 26 
     | 
    
         
            +
            ```
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            ## License
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            See LICENSE for details.
         
     | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'net/imap'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module MailXoauth2
         
     | 
| 
      
 6 
     | 
    
         
            +
              class ImapXoauth2Authenticator
         
     | 
| 
      
 7 
     | 
    
         
            +
                def process(_data)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  build_oauth2_string(@user, @oauth2_token, true)
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                private
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                # +user+ is an email address: roger@gmail.com
         
     | 
| 
      
 14 
     | 
    
         
            +
                # +oauth2_token+ is the OAuth2 token
         
     | 
| 
      
 15 
     | 
    
         
            +
                def initialize(user, oauth2_token)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @user = user
         
     | 
| 
      
 17 
     | 
    
         
            +
                  @oauth2_token = oauth2_token
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                include Oauth2String
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            Net::IMAP.add_authenticator('XOAUTH2', MailXoauth2::ImapXoauth2Authenticator)
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MailXoauth2
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Oauth2String
         
     | 
| 
      
 3 
     | 
    
         
            +
                private
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                #
         
     | 
| 
      
 6 
     | 
    
         
            +
                # Builds the "oauth2 protocol authentication string". See https://developers.google.com/google-apps/gmail/xoauth2_protocol
         
     | 
| 
      
 7 
     | 
    
         
            +
                #
         
     | 
| 
      
 8 
     | 
    
         
            +
                #   +user+ is an email address: roger@gmail.com
         
     | 
| 
      
 9 
     | 
    
         
            +
                #   +oauth2_token+ is the oauth2 token
         
     | 
| 
      
 10 
     | 
    
         
            +
                def build_oauth2_string(user, oauth2_token, encode_base64 = false)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  oauth2_string = format("user=%<user>s\1auth=Bearer %<token>s\1\1".encode('us-ascii'), user: user, token: oauth2_token)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  oauth2_string = Base64.strict_encode64(oauth2_string) if encode_base64
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  oauth2_string
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'net/smtp'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'base64'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module MailXoauth2
         
     | 
| 
      
 5 
     | 
    
         
            +
              module SmtpXoauth2Authenticator
         
     | 
| 
      
 6 
     | 
    
         
            +
                def send_xoauth2(auth_token)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  critical do
         
     | 
| 
      
 8 
     | 
    
         
            +
                    get_response("AUTH XOAUTH2 #{auth_token}")
         
     | 
| 
      
 9 
     | 
    
         
            +
                  end
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
                private :send_xoauth2
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def get_final_status
         
     | 
| 
      
 14 
     | 
    
         
            +
                  critical do
         
     | 
| 
      
 15 
     | 
    
         
            +
                    get_response('')
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
                private :get_final_status
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def auth_xoauth2(user, oauth2_token)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  check_auth_args user, oauth2_token
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  auth_string = build_oauth2_string(user, oauth2_token, true)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  res = send_xoauth2(auth_string)
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  # See note about SMTP protocol exchange in https://developers.google.com/gmail/xoauth2_protocol
         
     | 
| 
      
 27 
     | 
    
         
            +
                  res = get_final_status if res.continue?
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  check_auth_response res
         
     | 
| 
      
 30 
     | 
    
         
            +
                  res
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                include Oauth2String
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
            end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            # Not pretty, right ?
         
     | 
| 
      
 38 
     | 
    
         
            +
            Net::SMTP.__send__('include', MailXoauth2::SmtpXoauth2Authenticator)
         
     | 
    
        data/lib/mail_xoauth2.rb
    ADDED
    
    
    
        data/test/helper.rb
    ADDED
    
    | 
         @@ -0,0 +1,46 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'yaml'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'test/unit'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'mocha/test_unit'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
         
     | 
| 
      
 8 
     | 
    
         
            +
            $LOAD_PATH.unshift(File.dirname(__FILE__))
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'mail_xoauth2'
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            # Wanna debug ? Activate the IMAP debug mode, it will show the client/server conversation
         
     | 
| 
      
 12 
     | 
    
         
            +
            # Net::IMAP.debug = true
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            # SMTP debugging can only be enabled on Net::SMTP instances
         
     | 
| 
      
 15 
     | 
    
         
            +
            # Net::SMTP.class_eval do
         
     | 
| 
      
 16 
     | 
    
         
            +
            #   def initialize_with_debug(*args)
         
     | 
| 
      
 17 
     | 
    
         
            +
            #     initialize_without_debug(*args)
         
     | 
| 
      
 18 
     | 
    
         
            +
            #     @debug_output = STDERR
         
     | 
| 
      
 19 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 20 
     | 
    
         
            +
            #   alias_method :initialize_without_debug, :initialize
         
     | 
| 
      
 21 
     | 
    
         
            +
            #   alias_method :initialize, :initialize_with_debug
         
     | 
| 
      
 22 
     | 
    
         
            +
            # end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            VALID_CREDENTIALS = begin
         
     | 
| 
      
 25 
     | 
    
         
            +
              YAML.load_file(File.join(File.dirname(__FILE__), 'valid_credentials.yml'))
         
     | 
| 
      
 26 
     | 
    
         
            +
            rescue Errno::ENOENT
         
     | 
| 
      
 27 
     | 
    
         
            +
              STDERR.puts '
         
     | 
| 
      
 28 
     | 
    
         
            +
            Warning: some tests are disabled because they require valid credentials.
         
     | 
| 
      
 29 
     | 
    
         
            +
            To enable them, create a file "test/valid_credentials.yml".
         
     | 
| 
      
 30 
     | 
    
         
            +
            It should also ontain a valid OAuth2 access token.
         
     | 
| 
      
 31 
     | 
    
         
            +
            Of course, this file is .gitignored. Template:
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            ---
         
     | 
| 
      
 34 
     | 
    
         
            +
            :email: someuser@gmail.com
         
     | 
| 
      
 35 
     | 
    
         
            +
            :consumer_key: anonymous # "anonymous" is a valid value for testing
         
     | 
| 
      
 36 
     | 
    
         
            +
            :consumer_secret: anonymous # "anonymous" is a valid value for testing
         
     | 
| 
      
 37 
     | 
    
         
            +
            :token: 1/nE2xBCDOU0429bTeJySE11kRE95qzKQNlfTaaBcDeFg
         
     | 
| 
      
 38 
     | 
    
         
            +
            :token_secret: 123Z/bMsi9fFhN6qHFWOabcd
         
     | 
| 
      
 39 
     | 
    
         
            +
            :oauth2_token: ya29.AHES6ZTIpsLuSyMwnh-3C40WWcuiOe4N7he0a8xnkvDk_6Q_6yUg7E
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            '
         
     | 
| 
      
 42 
     | 
    
         
            +
              false
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
            class Test::Unit::TestCase
         
     | 
| 
      
 46 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class TestImapXoauth2Authenticator < Test::Unit::TestCase
         
     | 
| 
      
 4 
     | 
    
         
            +
              def setup; end
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              def test_xoauth2_authenticator_is_enabled
         
     | 
| 
      
 7 
     | 
    
         
            +
                authenticators = Net::IMAP.__send__('class_variable_get', '@@authenticators')
         
     | 
| 
      
 8 
     | 
    
         
            +
                assert_not_nil authenticators['XOAUTH2']
         
     | 
| 
      
 9 
     | 
    
         
            +
                assert_equal authenticators['XOAUTH2'], GmailXoauth::ImapXoauth2Authenticator
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              def test_authenticate_with_invalid_credentials
         
     | 
| 
      
 13 
     | 
    
         
            +
                imap = Net::IMAP.new('imap.gmail.com', 993, usessl = true, certs = nil, verify = false)
         
     | 
| 
      
 14 
     | 
    
         
            +
                assert_raise(Net::IMAP::NoResponseError) do
         
     | 
| 
      
 15 
     | 
    
         
            +
                  imap.authenticate('XOAUTH2', 'roger@moore.com', 'a')
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              def test_authenticate_with_valid_credentials
         
     | 
| 
      
 20 
     | 
    
         
            +
                return unless VALID_CREDENTIALS
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                imap = Net::IMAP.new('imap.gmail.com', 993, usessl = true, certs = nil, verify = false)
         
     | 
| 
      
 23 
     | 
    
         
            +
                imap.authenticate('XOAUTH2', VALID_CREDENTIALS[:email], VALID_CREDENTIALS[:oauth2_token])
         
     | 
| 
      
 24 
     | 
    
         
            +
                mailboxes = imap.list('', '*')
         
     | 
| 
      
 25 
     | 
    
         
            +
                assert_instance_of Array, mailboxes
         
     | 
| 
      
 26 
     | 
    
         
            +
                assert_instance_of Net::IMAP::MailboxList, mailboxes.first
         
     | 
| 
      
 27 
     | 
    
         
            +
              ensure
         
     | 
| 
      
 28 
     | 
    
         
            +
                imap.disconnect if imap
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,35 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'helper'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            class TestOauth2String < Test::Unit::TestCase
         
     | 
| 
      
 6 
     | 
    
         
            +
              def setup; end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              def test_build_oauth2_string
         
     | 
| 
      
 9 
     | 
    
         
            +
                user = 'somebody@gmail.com'
         
     | 
| 
      
 10 
     | 
    
         
            +
                oauth2_access_token = SecureRandom.urlsafe_base64
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                oauth2_string = SomeNetClass.new.__send__('build_oauth2_string', user, oauth2_access_token)
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                assert_equal(
         
     | 
| 
      
 15 
     | 
    
         
            +
                  "user=#{user}\1auth=Bearer #{oauth2_access_token}\1\1",
         
     | 
| 
      
 16 
     | 
    
         
            +
                  oauth2_string
         
     | 
| 
      
 17 
     | 
    
         
            +
                )
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              def test_build_encoded_oauth2_string
         
     | 
| 
      
 21 
     | 
    
         
            +
                user = 'somebody@gmail.com'
         
     | 
| 
      
 22 
     | 
    
         
            +
                oauth2_access_token = SecureRandom.urlsafe_base64
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                oauth2_string = SomeNetClass.new.__send__('build_oauth2_string', user, oauth2_access_token, true)
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                assert_equal(
         
     | 
| 
      
 27 
     | 
    
         
            +
                  Base64.strict_encode64("user=#{user}\1auth=Bearer #{oauth2_access_token}\1\1"),
         
     | 
| 
      
 28 
     | 
    
         
            +
                  oauth2_string
         
     | 
| 
      
 29 
     | 
    
         
            +
                )
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            class SomeNetClass
         
     | 
| 
      
 34 
     | 
    
         
            +
              include MailXoauth2::Oauth2String
         
     | 
| 
      
 35 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,56 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class TestSmtpXoauth2Authenticator < Test::Unit::TestCase
         
     | 
| 
      
 4 
     | 
    
         
            +
              def setup; end
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              def test_smtp_authenticator_is_enabled
         
     | 
| 
      
 7 
     | 
    
         
            +
                assert Net::SMTP.new(nil).respond_to?(:auth_xoauth2), 'The Net::SMTP class should define the method :auth_xoauth2'
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              def test_authenticate_with_invalid_credentials
         
     | 
| 
      
 11 
     | 
    
         
            +
                smtp = Net::SMTP.new('smtp.gmail.com', 587)
         
     | 
| 
      
 12 
     | 
    
         
            +
                smtp.enable_starttls_auto
         
     | 
| 
      
 13 
     | 
    
         
            +
                assert_raise(Net::SMTPAuthenticationError) do
         
     | 
| 
      
 14 
     | 
    
         
            +
                  smtp.start('gmail.com', 'roger@moore.com', 'a', :xoauth2)
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              def test_authenticate_with_valid_credentials
         
     | 
| 
      
 19 
     | 
    
         
            +
                return unless VALID_CREDENTIALS
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                smtp = Net::SMTP.new('smtp.gmail.com', 587)
         
     | 
| 
      
 22 
     | 
    
         
            +
                smtp.enable_starttls_auto
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                assert_nothing_raised do
         
     | 
| 
      
 25 
     | 
    
         
            +
                  smtp.start('gmail.com', VALID_CREDENTIALS[:email], VALID_CREDENTIALS[:oauth2_token], :xoauth2)
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
              ensure
         
     | 
| 
      
 28 
     | 
    
         
            +
                smtp.finish if smtp&.started?
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              # Test the handling of 3xx response to an "AUTH XOAUTH2" request... client
         
     | 
| 
      
 32 
     | 
    
         
            +
              # should send a "\r\n" to get the actual error that occurred.
         
     | 
| 
      
 33 
     | 
    
         
            +
              #
         
     | 
| 
      
 34 
     | 
    
         
            +
              # See note about SMTP protocol exchange in https://developers.google.com/
         
     | 
| 
      
 35 
     | 
    
         
            +
              # gmail/xoauth2_protocol
         
     | 
| 
      
 36 
     | 
    
         
            +
              #
         
     | 
| 
      
 37 
     | 
    
         
            +
              def test_authenticate_with_continuation
         
     | 
| 
      
 38 
     | 
    
         
            +
                smtp = Net::SMTP.new('smtp.gmail.com', 587)
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                # Stub return from initial "AUTH XOAUTH2" request as well as the empty line sent to get final error
         
     | 
| 
      
 41 
     | 
    
         
            +
                smtp.stubs(:send_xoauth2).returns(Net::SMTP::Response.parse('334 eyJzdGF0dXMiOiI0MDAiLCJzY2hlbWVzIjoiQmVhcmVyIiwic2NvcGUiOiJodHRwczovL21haWwuZ29vZ2xlLmNvbS8ifQ=='))
         
     | 
| 
      
 42 
     | 
    
         
            +
                smtp.stubs(:get_final_status).returns(Net::SMTP::Response.parse('454 4.7.0 Too many login attempts, please try again later. j63sm3521185itj.19 - gsmtp'))
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                smtp.enable_starttls_auto
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                # Validate an error is still raised
         
     | 
| 
      
 47 
     | 
    
         
            +
                ex = assert_raise(Net::SMTPAuthenticationError) do
         
     | 
| 
      
 48 
     | 
    
         
            +
                  smtp.start('gmail.com', 'roger@moore.com', 'a', :xoauth2)
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                # ...and that the 334 is not passed back to the caller.
         
     | 
| 
      
 52 
     | 
    
         
            +
                assert_equal('454 4.7.0 Too many login attempts, please try again later. j63sm3521185itj.19 - gsmtp', ex.message)
         
     | 
| 
      
 53 
     | 
    
         
            +
              ensure
         
     | 
| 
      
 54 
     | 
    
         
            +
                smtp.finish if smtp&.started?
         
     | 
| 
      
 55 
     | 
    
         
            +
              end
         
     | 
| 
      
 56 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,84 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: mail_xoauth2
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: '1.0'
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Fabian Jäger
         
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 9 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 10 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2018-06-07 00:00:00.000000000 Z
         
     | 
| 
      
 12 
     | 
    
         
            +
            dependencies:
         
     | 
| 
      
 13 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 14 
     | 
    
         
            +
              name: mocha
         
     | 
| 
      
 15 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 16 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 17 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 18 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 19 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 20 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 21 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 22 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 23 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 24 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 25 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 26 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 27 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 28 
     | 
    
         
            +
              name: shoulda
         
     | 
| 
      
 29 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 30 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 31 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 32 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 33 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 34 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 35 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 36 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 37 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 38 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 39 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 40 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 41 
     | 
    
         
            +
            description: Get access to IMAP and STMP via OAuth2, using the standard Ruby Net libraries
         
     | 
| 
      
 42 
     | 
    
         
            +
            email:
         
     | 
| 
      
 43 
     | 
    
         
            +
            - fabian@mailbutler.io
         
     | 
| 
      
 44 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 45 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 46 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 47 
     | 
    
         
            +
            files:
         
     | 
| 
      
 48 
     | 
    
         
            +
            - LICENSE
         
     | 
| 
      
 49 
     | 
    
         
            +
            - README.markdown
         
     | 
| 
      
 50 
     | 
    
         
            +
            - lib/mail_xoauth2.rb
         
     | 
| 
      
 51 
     | 
    
         
            +
            - lib/mail_xoauth2/imap_xoauth2_authenticator.rb
         
     | 
| 
      
 52 
     | 
    
         
            +
            - lib/mail_xoauth2/oauth2_string.rb
         
     | 
| 
      
 53 
     | 
    
         
            +
            - lib/mail_xoauth2/smtp_xoauth2_authenticator.rb
         
     | 
| 
      
 54 
     | 
    
         
            +
            - lib/mail_xoauth2/version.rb
         
     | 
| 
      
 55 
     | 
    
         
            +
            - test/helper.rb
         
     | 
| 
      
 56 
     | 
    
         
            +
            - test/test_imap_xoauth2_authenticator.rb
         
     | 
| 
      
 57 
     | 
    
         
            +
            - test/test_oauth2_string.rb
         
     | 
| 
      
 58 
     | 
    
         
            +
            - test/test_smtp_xoauth2_authenticator.rb
         
     | 
| 
      
 59 
     | 
    
         
            +
            homepage: https://github.com/Mailbutler/mail_xoauth2
         
     | 
| 
      
 60 
     | 
    
         
            +
            licenses:
         
     | 
| 
      
 61 
     | 
    
         
            +
            - MIT
         
     | 
| 
      
 62 
     | 
    
         
            +
            metadata: {}
         
     | 
| 
      
 63 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 64 
     | 
    
         
            +
            rdoc_options:
         
     | 
| 
      
 65 
     | 
    
         
            +
            - "--charset=UTF-8"
         
     | 
| 
      
 66 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 67 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 68 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 69 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 70 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 71 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 72 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 73 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 74 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 75 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 76 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 77 
     | 
    
         
            +
                  version: 1.3.6
         
     | 
| 
      
 78 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 79 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 80 
     | 
    
         
            +
            rubygems_version: 2.7.6
         
     | 
| 
      
 81 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 82 
     | 
    
         
            +
            specification_version: 4
         
     | 
| 
      
 83 
     | 
    
         
            +
            summary: Get access to IMAP and STMP via OAuth2, using the standard Ruby Net libraries
         
     | 
| 
      
 84 
     | 
    
         
            +
            test_files: []
         
     |