otp-jwt 0.2.2 → 0.2.7
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 +5 -5
- data/LICENSE.txt +21 -0
- data/README.md +8 -0
- data/lib/otp/active_record.rb +2 -2
- data/lib/otp/jwt/action_controller.rb +0 -1
- data/lib/otp/jwt/active_record.rb +23 -4
- data/lib/otp/jwt/test_helpers.rb +9 -2
- data/lib/otp/jwt/version.rb +1 -1
- data/spec/dummy.rb +82 -0
- data/spec/otp/jwt/token_spec.rb +54 -0
- data/spec/spec_helper.rb +70 -0
- data/spec/tokens_controller_spec.rb +50 -0
- data/spec/user_spec.rb +63 -0
- data/spec/users_controller_spec.rb +23 -0
- metadata +47 -22
- data/.github/main.workflow +0 -30
- data/.gitignore +0 -2
- data/.rspec +0 -3
- data/.rubocop.yml +0 -46
- data/.yardstick.yml +0 -29
- data/Gemfile +0 -6
- data/Gemfile.lock +0 -197
- data/Rakefile +0 -30
- data/otp-jwt.gemspec +0 -36
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: 16fc6a7023ef65ec63c539e7a43ad48b6a5a8a64b41269687c8c1db53e321c4b
         | 
| 4 | 
            +
              data.tar.gz: 4c7e06c0dd6e1b29ea12de1f75c4f25310c8557965c7d8bbdeaf294c244683c2
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 7ee896f4d70eb673ce977a8db560cc8f193255802f36da5074791b883cfa453045a5e57c98f98ad919735eee0bbd191025e12cdaa253447f7b5fae71aed429a3
         | 
| 7 | 
            +
              data.tar.gz: b9a82e89ba20bf80d5e7ebfe3d292452d8fa487b5f3645ea3b94862f77078386c20f77ac97cecdfd5e9740a1aee592480ab53dd6e5c6d50f7cbcf423cd1aea90
         | 
    
        data/LICENSE.txt
    ADDED
    
    | @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            The MIT License (MIT)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Copyright (c) 2021 Stas Suscov
         | 
| 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
         | 
| 13 | 
            +
            all 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
         | 
| 21 | 
            +
            THE SOFTWARE.
         | 
    
        data/README.md
    CHANGED
    
    | @@ -10,6 +10,8 @@ One time password (email, SMS) authentication support for HTTP APIs. | |
| 10 10 | 
             
            This project provides a couple of mixins to help you build
         | 
| 11 11 | 
             
            applications/HTTP APIs without asking your users to provide passwords.
         | 
| 12 12 |  | 
| 13 | 
            +
            [Your browser probably can work seamlessly with OTPs](https://web.dev/web-otp/)!!! :heart_eyes: 
         | 
| 14 | 
            +
             | 
| 13 15 | 
             
            ## About
         | 
| 14 16 |  | 
| 15 17 | 
             
            The goal of this project is to provide support for one time passwords
         | 
| @@ -103,6 +105,12 @@ A migration to add these two looks like this: | |
| 103 105 | 
             
            $ rails g migration add_otp_to_users otp_secret:string otp_counter:integer
         | 
| 104 106 | 
             
            ```
         | 
| 105 107 |  | 
| 108 | 
            +
            Generate `opt_secret` by running the following in rails console if you have preexisting user data:
         | 
| 109 | 
            +
            ```
         | 
| 110 | 
            +
            User.all.each do |u|
         | 
| 111 | 
            +
              u.save()
         | 
| 112 | 
            +
            end
         | 
| 113 | 
            +
            ```
         | 
| 106 114 | 
             
            #### Mailer support
         | 
| 107 115 |  | 
| 108 116 | 
             
            You can use the built-in mailer to deliver the OTP, just require it and
         | 
    
        data/lib/otp/active_record.rb
    CHANGED
    
    | @@ -36,7 +36,8 @@ module OTP | |
| 36 36 | 
             
                def verify_otp(otp)
         | 
| 37 37 | 
             
                  return nil if !valid? || !persisted? || otp_secret.blank?
         | 
| 38 38 |  | 
| 39 | 
            -
                   | 
| 39 | 
            +
                  otp_digits = self.class.const_get(:OTP_DIGITS)
         | 
| 40 | 
            +
                  hotp = ROTP::HOTP.new(otp_secret, digits: otp_digits)
         | 
| 40 41 | 
             
                  transaction do
         | 
| 41 42 | 
             
                    otp_status = hotp.verify(otp.to_s, otp_counter)
         | 
| 42 43 | 
             
                    increment!(:otp_counter)
         | 
| @@ -72,7 +73,6 @@ module OTP | |
| 72 73 | 
             
                end
         | 
| 73 74 |  | 
| 74 75 | 
             
                private
         | 
| 75 | 
            -
             | 
| 76 76 | 
             
                # Provides a default value for the OTP secret attribute
         | 
| 77 77 | 
             
                #
         | 
| 78 78 | 
             
                # @return [String]
         | 
| @@ -10,19 +10,38 @@ module OTP | |
| 10 10 | 
             
                    # Returns a record based on the [JWT] token subject
         | 
| 11 11 | 
             
                    #
         | 
| 12 12 | 
             
                    # @param token [String] representing a [JWT] token
         | 
| 13 | 
            +
                    # @param claim_name [String] the claim name to be used, default is `sub`
         | 
| 13 14 | 
             
                    # @return [ActiveRecord::Base] model
         | 
| 14 | 
            -
                    def from_jwt(token)
         | 
| 15 | 
            +
                    def from_jwt(token, claim_name = 'sub')
         | 
| 15 16 | 
             
                      OTP::JWT::Token.decode(token) do |payload|
         | 
| 16 | 
            -
                         | 
| 17 | 
            +
                        val = payload[claim_name]
         | 
| 18 | 
            +
                        pk_col = self.column_for_attribute(self.primary_key)
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                        # Arel casts the values to the primary key type,
         | 
| 21 | 
            +
                        # which means that an UUID becomes an integer by default...
         | 
| 22 | 
            +
                        if self.connection.respond_to?(:lookup_cast_type_from_column)
         | 
| 23 | 
            +
                          pk_type = self.connection.lookup_cast_type_from_column(pk_col)
         | 
| 24 | 
            +
                          casted_val = pk_type.serialize(val)
         | 
| 25 | 
            +
                        else
         | 
| 26 | 
            +
                          casted_val = self.connection.type_cast(val, pk_col)
         | 
| 27 | 
            +
                        end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                        return if casted_val.to_s != val.to_s.strip
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                        self.find_by(self.primary_key => val)
         | 
| 17 32 | 
             
                      end
         | 
| 18 33 | 
             
                    end
         | 
| 19 34 | 
             
                  end
         | 
| 20 35 |  | 
| 21 36 | 
             
                  # Returns a [JWT] token for this record
         | 
| 22 37 | 
             
                  #
         | 
| 38 | 
            +
                  # @param claims [Hash] extra claims to be included
         | 
| 23 39 | 
             
                  # @return [ActiveRecord::Base] model
         | 
| 24 | 
            -
                  def to_jwt
         | 
| 25 | 
            -
                    OTP::JWT::Token.sign( | 
| 40 | 
            +
                  def to_jwt(claims = nil)
         | 
| 41 | 
            +
                    OTP::JWT::Token.sign(
         | 
| 42 | 
            +
                      sub: self.send(self.class.primary_key),
         | 
| 43 | 
            +
                      **(claims || {})
         | 
| 44 | 
            +
                    )
         | 
| 26 45 | 
             
                  end
         | 
| 27 46 | 
             
                end
         | 
| 28 47 | 
             
              end
         | 
    
        data/lib/otp/jwt/test_helpers.rb
    CHANGED
    
    | @@ -4,16 +4,23 @@ module OTP | |
| 4 4 | 
             
              module JWT
         | 
| 5 5 | 
             
                # Helpers to help you test the [JWT] requests.
         | 
| 6 6 | 
             
                module TestHelpers
         | 
| 7 | 
            +
                  # Helper provides JSON content type headers
         | 
| 8 | 
            +
                  #
         | 
| 9 | 
            +
                  # @return [Hash] the relevant content type &co
         | 
| 10 | 
            +
                  def json_headers
         | 
| 11 | 
            +
                    { 'Content-Type': Mime[:json].to_s }
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 7 14 | 
             
                  # Helper to handle authentication requests easier
         | 
| 8 15 | 
             
                  #
         | 
| 9 16 | 
             
                  # @return [Hash] the authorization headers
         | 
| 10 17 | 
             
                  def jwt_auth_header(entity_or_subject)
         | 
| 11 | 
            -
                    return  | 
| 18 | 
            +
                    return json_headers if entity_or_subject.blank?
         | 
| 12 19 |  | 
| 13 20 | 
             
                    token = entity_or_subject.try(:to_jwt)
         | 
| 14 21 | 
             
                    token ||= OTP::JWT::Token.sign(sub: entity_or_subject)
         | 
| 15 22 |  | 
| 16 | 
            -
                    { 'Authorization': "Bearer #{token}" }
         | 
| 23 | 
            +
                    { 'Authorization': "Bearer #{token}" }.merge(json_headers)
         | 
| 17 24 | 
             
                  end
         | 
| 18 25 |  | 
| 19 26 | 
             
                  # Parses and returns a deserialized JSON
         | 
    
        data/lib/otp/jwt/version.rb
    CHANGED
    
    
    
        data/spec/dummy.rb
    ADDED
    
    | @@ -0,0 +1,82 @@ | |
| 1 | 
            +
            require 'active_record/railtie'
         | 
| 2 | 
            +
            require 'action_controller/railtie'
         | 
| 3 | 
            +
            require 'global_id/railtie'
         | 
| 4 | 
            +
            require 'otp/mailer'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            class Dummy < Rails::Application
         | 
| 7 | 
            +
              secrets.secret_key_base = '_'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              config.hosts << 'www.example.com' if config.respond_to?(:hosts)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              config.logger = Logger.new($stdout)
         | 
| 12 | 
            +
              config.logger.level = ENV['LOG_LEVEL'] || Logger::WARN
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              routes.draw do
         | 
| 15 | 
            +
                resources :users, only: [:index]
         | 
| 16 | 
            +
                resources :tokens, only: [:create]
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            GlobalID.app = Dummy
         | 
| 21 | 
            +
            Rails.logger = Dummy.config.logger
         | 
| 22 | 
            +
            ActiveRecord::Base.logger = Dummy.config.logger
         | 
| 23 | 
            +
            ActiveRecord::Base.establish_connection(
         | 
| 24 | 
            +
              ENV['DATABASE_URL'] || 'sqlite3::memory:'
         | 
| 25 | 
            +
            )
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            ActiveRecord::Schema.define do
         | 
| 28 | 
            +
              create_table :users, force: true do |t|
         | 
| 29 | 
            +
                t.string :email
         | 
| 30 | 
            +
                t.string :full_name
         | 
| 31 | 
            +
                t.string :phone_number
         | 
| 32 | 
            +
                t.string :otp_secret
         | 
| 33 | 
            +
                t.integer :otp_counter
         | 
| 34 | 
            +
                t.timestamp :last_login_at
         | 
| 35 | 
            +
                t.timestamps
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
            end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            class User < ActiveRecord::Base
         | 
| 40 | 
            +
              include GlobalID::Identification
         | 
| 41 | 
            +
              include OTP::ActiveRecord
         | 
| 42 | 
            +
              include OTP::JWT::ActiveRecord
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              def email_otp
         | 
| 45 | 
            +
                OTP::Mailer.otp(email, otp, self).deliver_later
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
            end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            class ApplicationController < ActionController::Base
         | 
| 50 | 
            +
              include OTP::JWT::ActionController
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              private
         | 
| 53 | 
            +
              def current_user
         | 
| 54 | 
            +
                @jwt_user ||= User.from_jwt(request_authorization_header)
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              def current_user!
         | 
| 58 | 
            +
                current_user || raise('User authentication failed')
         | 
| 59 | 
            +
              rescue
         | 
| 60 | 
            +
                head(:unauthorized)
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
            end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
            class UsersController < ApplicationController
         | 
| 65 | 
            +
              before_action :current_user!
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              def index
         | 
| 68 | 
            +
                render json: current_user
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
            end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
            class TokensController < ApplicationController
         | 
| 73 | 
            +
              def create
         | 
| 74 | 
            +
                user = User.find_by(email: params[:email])
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                jwt_from_otp(user, params[:otp]) do |auth_user|
         | 
| 77 | 
            +
                  auth_user.update_column(:last_login_at, DateTime.current)
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  render json: { token: auth_user.to_jwt }, status: :created
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
            end
         | 
| @@ -0,0 +1,54 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            RSpec.describe OTP::JWT::Token, type: :model do
         | 
| 4 | 
            +
              let(:payload) { { 'sub' => FFaker::Internet.password } }
         | 
| 5 | 
            +
              let(:token) do
         | 
| 6 | 
            +
                JWT.encode(
         | 
| 7 | 
            +
                  payload.dup.merge(exp: Time.now.to_i + described_class.jwt_lifetime),
         | 
| 8 | 
            +
                  described_class.jwt_signature_key,
         | 
| 9 | 
            +
                  described_class.jwt_algorithm
         | 
| 10 | 
            +
                )
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              describe '#sign' do
         | 
| 14 | 
            +
                it { expect(described_class.sign(payload)).to eq(token) }
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              describe '#verify' do
         | 
| 18 | 
            +
                it do
         | 
| 19 | 
            +
                  expect(described_class.verify(token).first).to include(payload)
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                it 'with a bad token' do
         | 
| 23 | 
            +
                  expect { described_class.verify(FFaker::Internet.password) }
         | 
| 24 | 
            +
                    .to raise_error(JWT::DecodeError)
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                it 'with an expired token' do
         | 
| 28 | 
            +
                  token = OTP::JWT::Token.sign(
         | 
| 29 | 
            +
                    sub: FFaker::Internet.password, exp: DateTime.now.to_i
         | 
| 30 | 
            +
                  )
         | 
| 31 | 
            +
                  expect { described_class.verify(token) }
         | 
| 32 | 
            +
                    .to raise_error(JWT::ExpiredSignature)
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              describe '#decode' do
         | 
| 37 | 
            +
                let(:user) { create_user }
         | 
| 38 | 
            +
                let(:payload) { { 'sub' => user.id } }
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                it do
         | 
| 41 | 
            +
                  expect(
         | 
| 42 | 
            +
                    described_class.decode(token) { |p| User.find(p['sub']) }
         | 
| 43 | 
            +
                  ).to eq(user)
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                context 'with a bad token' do
         | 
| 47 | 
            +
                  let(:token) { FFaker::Internet.password }
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  it do
         | 
| 50 | 
            +
                    expect(described_class.decode(token)).to eq(nil)
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
            end
         | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | @@ -0,0 +1,70 @@ | |
| 1 | 
            +
            require 'bundler/setup'
         | 
| 2 | 
            +
            require 'simplecov'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            SimpleCov.start do
         | 
| 5 | 
            +
              add_group 'Lib', 'lib'
         | 
| 6 | 
            +
              add_group 'Tests', 'spec'
         | 
| 7 | 
            +
            end
         | 
| 8 | 
            +
            SimpleCov.minimum_coverage 90
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            require 'otp'
         | 
| 11 | 
            +
            require 'otp/jwt'
         | 
| 12 | 
            +
            require 'otp/jwt/test_helpers'
         | 
| 13 | 
            +
            require_relative 'dummy'
         | 
| 14 | 
            +
            require 'ffaker'
         | 
| 15 | 
            +
            require 'rspec/rails'
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            OTP::JWT::Token.jwt_signature_key = '_'
         | 
| 18 | 
            +
            OTP::Mailer.default from: '_'
         | 
| 19 | 
            +
            ActiveJob::Base.queue_adapter = :test
         | 
| 20 | 
            +
            ActionMailer::Base.delivery_method = :test
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            module OTP::JWT::FactoryHelpers
         | 
| 23 | 
            +
              # Creates an user
         | 
| 24 | 
            +
              #
         | 
| 25 | 
            +
              # @return [User]
         | 
| 26 | 
            +
              def create_user
         | 
| 27 | 
            +
                User.create!(
         | 
| 28 | 
            +
                  full_name: FFaker::Name.name,
         | 
| 29 | 
            +
                  email: FFaker::Internet.email,
         | 
| 30 | 
            +
                  phone_number: FFaker::PhoneNumber.phone_number
         | 
| 31 | 
            +
                )
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            module Rails4RequestMethods
         | 
| 36 | 
            +
              [:get, :post, :put, :delete].each do |method_name|
         | 
| 37 | 
            +
                define_method(method_name) do |path, named_args|
         | 
| 38 | 
            +
                  super(
         | 
| 39 | 
            +
                    path,
         | 
| 40 | 
            +
                    named_args.delete(:params),
         | 
| 41 | 
            +
                    named_args.delete(:headers)
         | 
| 42 | 
            +
                  )
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
            end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            RSpec.configure do |config|
         | 
| 48 | 
            +
              config.use_transactional_fixtures = true
         | 
| 49 | 
            +
              config.mock_with :rspec
         | 
| 50 | 
            +
              config.filter_run_when_matching :focus
         | 
| 51 | 
            +
              config.disable_monkey_patching!
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              config.expect_with :rspec do |c|
         | 
| 54 | 
            +
                c.syntax = :expect
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              config.include OTP::JWT::TestHelpers, type: :model
         | 
| 58 | 
            +
              config.include OTP::JWT::FactoryHelpers, type: :model
         | 
| 59 | 
            +
              config.include ActiveJob::TestHelper, type: :model
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              config.include OTP::JWT::TestHelpers, type: :request
         | 
| 62 | 
            +
              config.include OTP::JWT::FactoryHelpers, type: :request
         | 
| 63 | 
            +
              config.include ActiveJob::TestHelper, type: :request
         | 
| 64 | 
            +
              config.include Dummy.routes.url_helpers, type: :request
         | 
| 65 | 
            +
             | 
| 66 | 
            +
              if ::Rails::VERSION::MAJOR == 4
         | 
| 67 | 
            +
                config.include Rails4RequestMethods, type: :request
         | 
| 68 | 
            +
                config.include Rails4RequestMethods, type: :controller
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
            end
         | 
| @@ -0,0 +1,50 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            RSpec.describe TokensController, type: :request do
         | 
| 4 | 
            +
              let(:user) { create_user }
         | 
| 5 | 
            +
              let(:params) { }
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              around do |examp|
         | 
| 8 | 
            +
                perform_enqueued_jobs(&examp)
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              before do
         | 
| 12 | 
            +
                ActionMailer::Base.deliveries.clear
         | 
| 13 | 
            +
                ActiveJob::Base.queue_adapter.performed_jobs.clear
         | 
| 14 | 
            +
                post(tokens_path, params: params.to_json, headers: json_headers)
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              it { expect(response).to have_http_status(:forbidden) }
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              context 'with good email and no otp' do
         | 
| 20 | 
            +
                let(:params) { { email: user.email } }
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                it do
         | 
| 23 | 
            +
                  expect(response).to have_http_status(:bad_request)
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  mail = ActionMailer::Base.deliveries.last
         | 
| 26 | 
            +
                  expect(mail.subject).to eq(OTP::Mailer.default[:subject])
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              context 'with good email and bad otp' do
         | 
| 31 | 
            +
                let(:params) { { email: user.email, otp: FFaker::Internet.password } }
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                it do
         | 
| 34 | 
            +
                  expect(response).to have_http_status(:forbidden)
         | 
| 35 | 
            +
                  expect(ActionMailer::Base.deliveries.size).to eq(0)
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              context 'with good email and good otp' do
         | 
| 40 | 
            +
                let(:params) { { email: user.email, otp: user.otp } }
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                it do
         | 
| 43 | 
            +
                  expect(response).to have_http_status(:created)
         | 
| 44 | 
            +
                  expect(User.from_jwt(response_json['token'])).to eq(user)
         | 
| 45 | 
            +
                  expect(ActionMailer::Base.deliveries.size).to eq(0)
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  expect(user.reload.last_login_at).not_to be_blank
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
            end
         | 
    
        data/spec/user_spec.rb
    ADDED
    
    | @@ -0,0 +1,63 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            RSpec.describe User, type: :model do
         | 
| 4 | 
            +
              let(:user) { create_user }
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              it { expect(User.new.otp_secret).not_to be_blank }
         | 
| 7 | 
            +
              it { expect(User.new.deliver_otp).to be_blank }
         | 
| 8 | 
            +
              it { expect(User.new.otp).to be_blank }
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              describe '#from_jwt' do
         | 
| 11 | 
            +
                let(:token) { user.to_jwt }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                it do
         | 
| 14 | 
            +
                  expect(User.from_jwt(token)).to eq(user)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                context 'with a cast-able subject value' do
         | 
| 18 | 
            +
                  let(:token) { OTP::JWT::Token.sign(sub: user.id.to_s + '_text') }
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  it do
         | 
| 21 | 
            +
                    expect(User.from_jwt(token)).to be_nil
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                context 'with a custom claim name' do
         | 
| 26 | 
            +
                  let(:claim_value) { FFaker::Internet.password }
         | 
| 27 | 
            +
                  let(:token) { user.to_jwt(my_claim_name: claim_value) }
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  it do
         | 
| 30 | 
            +
                    expect(OTP::JWT::Token.decode(token)['my_claim_name'])
         | 
| 31 | 
            +
                      .to eq(claim_value)
         | 
| 32 | 
            +
                    expect(User.from_jwt(token, 'my_claim_name')).to be_nil
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              describe '#otp' do
         | 
| 38 | 
            +
                it do
         | 
| 39 | 
            +
                  expect { user.otp }.to change(user, :otp_counter).by(1)
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                context 'without a secret' do
         | 
| 43 | 
            +
                  it do
         | 
| 44 | 
            +
                    user.update_column(:otp_secret, nil)
         | 
| 45 | 
            +
                    expect(user.otp).to be_nil
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
              describe '#verify_otp' do
         | 
| 51 | 
            +
                it 'increments the otp counter after verification' do
         | 
| 52 | 
            +
                  expect(user.verify_otp(user.otp)).to be_truthy
         | 
| 53 | 
            +
                  expect { user.verify_otp(user.otp) }.to change(user, :otp_counter).by(2)
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                context 'without a secret' do
         | 
| 57 | 
            +
                  it do
         | 
| 58 | 
            +
                    user.update_column(:otp_secret, nil)
         | 
| 59 | 
            +
                    expect(user.verify_otp(rand(1000..2000).to_s)).to be_nil
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
            end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            RSpec.describe UsersController, type: :request do
         | 
| 4 | 
            +
              let(:user) { nil }
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              before do
         | 
| 7 | 
            +
                get(users_path, headers: jwt_auth_header(user))
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              it { expect(response).to have_http_status(:unauthorized) }
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              context 'with known subject token' do
         | 
| 13 | 
            +
                let(:user) { create_user }
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                it { expect(response).to have_http_status(:ok) }
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              context 'with bad subject' do
         | 
| 19 | 
            +
                let(:user) { FFaker::Internet.password }
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                it { expect(response).to have_http_status(:unauthorized) }
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: otp-jwt
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.2. | 
| 4 | 
            +
              version: 0.2.7
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Stas Suscov
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2021-02-15 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: activesupport
         | 
| @@ -30,28 +30,28 @@ dependencies: | |
| 30 30 | 
             
                requirements:
         | 
| 31 31 | 
             
                - - "~>"
         | 
| 32 32 | 
             
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            -
                    version: 2 | 
| 33 | 
            +
                    version: '2'
         | 
| 34 34 | 
             
              type: :runtime
         | 
| 35 35 | 
             
              prerelease: false
         | 
| 36 36 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 37 | 
             
                requirements:
         | 
| 38 38 | 
             
                - - "~>"
         | 
| 39 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            -
                    version: 2 | 
| 40 | 
            +
                    version: '2'
         | 
| 41 41 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 42 42 | 
             
              name: rotp
         | 
| 43 43 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 44 | 
             
                requirements:
         | 
| 45 45 | 
             
                - - "~>"
         | 
| 46 46 | 
             
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            -
                    version: ' | 
| 47 | 
            +
                    version: '6'
         | 
| 48 48 | 
             
              type: :runtime
         | 
| 49 49 | 
             
              prerelease: false
         | 
| 50 50 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 51 | 
             
                requirements:
         | 
| 52 52 | 
             
                - - "~>"
         | 
| 53 53 | 
             
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            -
                    version: ' | 
| 54 | 
            +
                    version: '6'
         | 
| 55 55 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 56 56 | 
             
              name: bundler
         | 
| 57 57 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -108,6 +108,20 @@ dependencies: | |
| 108 108 | 
             
                - - ">="
         | 
| 109 109 | 
             
                  - !ruby/object:Gem::Version
         | 
| 110 110 | 
             
                    version: '0'
         | 
| 111 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 112 | 
            +
              name: rubocop
         | 
| 113 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 114 | 
            +
                requirements:
         | 
| 115 | 
            +
                - - ">="
         | 
| 116 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 117 | 
            +
                    version: '0'
         | 
| 118 | 
            +
              type: :development
         | 
| 119 | 
            +
              prerelease: false
         | 
| 120 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 121 | 
            +
                requirements:
         | 
| 122 | 
            +
                - - ">="
         | 
| 123 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 124 | 
            +
                    version: '0'
         | 
| 111 125 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 112 126 | 
             
              name: rubocop-performance
         | 
| 113 127 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -168,16 +182,30 @@ dependencies: | |
| 168 182 | 
             
              name: sqlite3
         | 
| 169 183 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 170 184 | 
             
                requirements:
         | 
| 171 | 
            -
                - - " | 
| 185 | 
            +
                - - ">="
         | 
| 186 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 187 | 
            +
                    version: '0'
         | 
| 188 | 
            +
              type: :development
         | 
| 189 | 
            +
              prerelease: false
         | 
| 190 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 191 | 
            +
                requirements:
         | 
| 192 | 
            +
                - - ">="
         | 
| 193 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 194 | 
            +
                    version: '0'
         | 
| 195 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 196 | 
            +
              name: tzinfo-data
         | 
| 197 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 198 | 
            +
                requirements:
         | 
| 199 | 
            +
                - - ">="
         | 
| 172 200 | 
             
                  - !ruby/object:Gem::Version
         | 
| 173 | 
            -
                    version:  | 
| 201 | 
            +
                    version: '0'
         | 
| 174 202 | 
             
              type: :development
         | 
| 175 203 | 
             
              prerelease: false
         | 
| 176 204 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 177 205 | 
             
                requirements:
         | 
| 178 | 
            -
                - - " | 
| 206 | 
            +
                - - ">="
         | 
| 179 207 | 
             
                  - !ruby/object:Gem::Version
         | 
| 180 | 
            -
                    version:  | 
| 208 | 
            +
                    version: '0'
         | 
| 181 209 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 182 210 | 
             
              name: yardstick
         | 
| 183 211 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -199,15 +227,8 @@ executables: [] | |
| 199 227 | 
             
            extensions: []
         | 
| 200 228 | 
             
            extra_rdoc_files: []
         | 
| 201 229 | 
             
            files:
         | 
| 202 | 
            -
            -  | 
| 203 | 
            -
            - ".gitignore"
         | 
| 204 | 
            -
            - ".rspec"
         | 
| 205 | 
            -
            - ".rubocop.yml"
         | 
| 206 | 
            -
            - ".yardstick.yml"
         | 
| 207 | 
            -
            - Gemfile
         | 
| 208 | 
            -
            - Gemfile.lock
         | 
| 230 | 
            +
            - LICENSE.txt
         | 
| 209 231 | 
             
            - README.md
         | 
| 210 | 
            -
            - Rakefile
         | 
| 211 232 | 
             
            - lib/otp.rb
         | 
| 212 233 | 
             
            - lib/otp/active_record.rb
         | 
| 213 234 | 
             
            - lib/otp/jwt.rb
         | 
| @@ -219,10 +240,15 @@ files: | |
| 219 240 | 
             
            - lib/otp/mailer.rb
         | 
| 220 241 | 
             
            - lib/otp/mailer/otp.text.erb
         | 
| 221 242 | 
             
            - lib/otp/sms_job.rb
         | 
| 222 | 
            -
            -  | 
| 243 | 
            +
            - spec/dummy.rb
         | 
| 244 | 
            +
            - spec/otp/jwt/token_spec.rb
         | 
| 245 | 
            +
            - spec/spec_helper.rb
         | 
| 246 | 
            +
            - spec/tokens_controller_spec.rb
         | 
| 247 | 
            +
            - spec/user_spec.rb
         | 
| 248 | 
            +
            - spec/users_controller_spec.rb
         | 
| 223 249 | 
             
            homepage: https://github.com/stas/otp-jwt
         | 
| 224 250 | 
             
            licenses:
         | 
| 225 | 
            -
            -  | 
| 251 | 
            +
            - MIT
         | 
| 226 252 | 
             
            metadata: {}
         | 
| 227 253 | 
             
            post_install_message: 
         | 
| 228 254 | 
             
            rdoc_options: []
         | 
| @@ -239,8 +265,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 239 265 | 
             
                - !ruby/object:Gem::Version
         | 
| 240 266 | 
             
                  version: '0'
         | 
| 241 267 | 
             
            requirements: []
         | 
| 242 | 
            -
             | 
| 243 | 
            -
            rubygems_version: 2.5.2.2
         | 
| 268 | 
            +
            rubygems_version: 3.2.3
         | 
| 244 269 | 
             
            signing_key: 
         | 
| 245 270 | 
             
            specification_version: 4
         | 
| 246 271 | 
             
            summary: Passwordless HTTP APIs
         | 
    
        data/.github/main.workflow
    DELETED
    
    | @@ -1,30 +0,0 @@ | |
| 1 | 
            -
            workflow "Tests" {
         | 
| 2 | 
            -
              on = "push"
         | 
| 3 | 
            -
              resolves = [
         | 
| 4 | 
            -
                "rspec-ruby2.6_rails4",
         | 
| 5 | 
            -
                "rspec-ruby2.6_rails5"
         | 
| 6 | 
            -
              ]
         | 
| 7 | 
            -
            }
         | 
| 8 | 
            -
             | 
| 9 | 
            -
            action "rspec-ruby2.6_rails4" {
         | 
| 10 | 
            -
              uses = "docker://ruby:2.6-alpine"
         | 
| 11 | 
            -
              env = {
         | 
| 12 | 
            -
                RAILS_VERSION = "~> 4"
         | 
| 13 | 
            -
              }
         | 
| 14 | 
            -
              args = [
         | 
| 15 | 
            -
                "sh", "-c",
         | 
| 16 | 
            -
                "apk add -U git build-base sqlite-dev && rm Gemfile.lock && bundle install && rake"
         | 
| 17 | 
            -
              ]
         | 
| 18 | 
            -
            }
         | 
| 19 | 
            -
             | 
| 20 | 
            -
            action "rspec-ruby2.6_rails5" {
         | 
| 21 | 
            -
              uses = "docker://ruby:2.6-alpine"
         | 
| 22 | 
            -
              needs = ["rspec-ruby2.6_rails4"]
         | 
| 23 | 
            -
              env = {
         | 
| 24 | 
            -
                RAILS_VERSION = "~> 5"
         | 
| 25 | 
            -
              }
         | 
| 26 | 
            -
              args = [
         | 
| 27 | 
            -
                "sh", "-c",
         | 
| 28 | 
            -
                "apk add -U git build-base sqlite-dev && rm Gemfile.lock && bundle install && rake"
         | 
| 29 | 
            -
              ]
         | 
| 30 | 
            -
            }
         | 
    
        data/.gitignore
    DELETED
    
    
    
        data/.rspec
    DELETED
    
    
    
        data/.rubocop.yml
    DELETED
    
    | @@ -1,46 +0,0 @@ | |
| 1 | 
            -
            inherit_gem:
         | 
| 2 | 
            -
              rubocop-rails_config:
         | 
| 3 | 
            -
                - config/rails.yml
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            require:
         | 
| 6 | 
            -
              - rubocop-performance
         | 
| 7 | 
            -
              - rubocop-rspec
         | 
| 8 | 
            -
             | 
| 9 | 
            -
            Rails:
         | 
| 10 | 
            -
              Enabled: true
         | 
| 11 | 
            -
             | 
| 12 | 
            -
            RSpec:
         | 
| 13 | 
            -
              Enabled: true
         | 
| 14 | 
            -
             | 
| 15 | 
            -
            RSpec/MultipleExpectations:
         | 
| 16 | 
            -
              Enabled: false
         | 
| 17 | 
            -
             | 
| 18 | 
            -
            Performance:
         | 
| 19 | 
            -
              Enabled: true
         | 
| 20 | 
            -
             | 
| 21 | 
            -
            Bundler:
         | 
| 22 | 
            -
              Enabled: true
         | 
| 23 | 
            -
             | 
| 24 | 
            -
            Gemspec:
         | 
| 25 | 
            -
              Enabled: true
         | 
| 26 | 
            -
             | 
| 27 | 
            -
            Style/StringLiterals:
         | 
| 28 | 
            -
              Enabled: true
         | 
| 29 | 
            -
              EnforcedStyle: single_quotes
         | 
| 30 | 
            -
             | 
| 31 | 
            -
            Style/FrozenStringLiteralComment:
         | 
| 32 | 
            -
              Enabled: false
         | 
| 33 | 
            -
             | 
| 34 | 
            -
            Metrics/LineLength:
         | 
| 35 | 
            -
              Max: 80
         | 
| 36 | 
            -
             | 
| 37 | 
            -
            Metrics/BlockLength:
         | 
| 38 | 
            -
              Exclude:
         | 
| 39 | 
            -
                - 'spec/**/*_spec.rb'
         | 
| 40 | 
            -
                - '**/*.gemspec'
         | 
| 41 | 
            -
             | 
| 42 | 
            -
            Layout/IndentationConsistency:
         | 
| 43 | 
            -
              EnforcedStyle: normal
         | 
| 44 | 
            -
             | 
| 45 | 
            -
            Style/BlockDelimiters:
         | 
| 46 | 
            -
              Enabled: true
         | 
    
        data/.yardstick.yml
    DELETED
    
    | @@ -1,29 +0,0 @@ | |
| 1 | 
            -
            ---
         | 
| 2 | 
            -
            path: ['lib/**/*.rb']
         | 
| 3 | 
            -
            threshold: 100
         | 
| 4 | 
            -
            rules:
         | 
| 5 | 
            -
              ApiTag::Presence:
         | 
| 6 | 
            -
                enabled: false
         | 
| 7 | 
            -
              ApiTag::Inclusion:
         | 
| 8 | 
            -
                enabled: false
         | 
| 9 | 
            -
              ApiTag::ProtectedMethod:
         | 
| 10 | 
            -
                enabled: false
         | 
| 11 | 
            -
              ApiTag::PrivateMethod:
         | 
| 12 | 
            -
                enabled: false
         | 
| 13 | 
            -
              ExampleTag:
         | 
| 14 | 
            -
                enabled: false
         | 
| 15 | 
            -
              ReturnTag:
         | 
| 16 | 
            -
                enabled: true
         | 
| 17 | 
            -
                exclude: []
         | 
| 18 | 
            -
              Summary::Presence:
         | 
| 19 | 
            -
                enabled: true
         | 
| 20 | 
            -
                exclude: []
         | 
| 21 | 
            -
              Summary::Length:
         | 
| 22 | 
            -
                enabled: true
         | 
| 23 | 
            -
                exclude: []
         | 
| 24 | 
            -
              Summary::Delimiter:
         | 
| 25 | 
            -
                enabled: true
         | 
| 26 | 
            -
                exclude: []
         | 
| 27 | 
            -
              Summary::SingleLine:
         | 
| 28 | 
            -
                enabled: true
         | 
| 29 | 
            -
                exclude: []
         | 
    
        data/Gemfile
    DELETED
    
    
    
        data/Gemfile.lock
    DELETED
    
    | @@ -1,197 +0,0 @@ | |
| 1 | 
            -
            PATH
         | 
| 2 | 
            -
              remote: .
         | 
| 3 | 
            -
              specs:
         | 
| 4 | 
            -
                otp-jwt (0.2.2)
         | 
| 5 | 
            -
                  activesupport
         | 
| 6 | 
            -
                  jwt (~> 2.2.0.pre.beta.0)
         | 
| 7 | 
            -
                  rotp (~> 4.1)
         | 
| 8 | 
            -
             | 
| 9 | 
            -
            GEM
         | 
| 10 | 
            -
              remote: https://rubygems.org/
         | 
| 11 | 
            -
              specs:
         | 
| 12 | 
            -
                actioncable (5.2.3)
         | 
| 13 | 
            -
                  actionpack (= 5.2.3)
         | 
| 14 | 
            -
                  nio4r (~> 2.0)
         | 
| 15 | 
            -
                  websocket-driver (>= 0.6.1)
         | 
| 16 | 
            -
                actionmailer (5.2.3)
         | 
| 17 | 
            -
                  actionpack (= 5.2.3)
         | 
| 18 | 
            -
                  actionview (= 5.2.3)
         | 
| 19 | 
            -
                  activejob (= 5.2.3)
         | 
| 20 | 
            -
                  mail (~> 2.5, >= 2.5.4)
         | 
| 21 | 
            -
                  rails-dom-testing (~> 2.0)
         | 
| 22 | 
            -
                actionpack (5.2.3)
         | 
| 23 | 
            -
                  actionview (= 5.2.3)
         | 
| 24 | 
            -
                  activesupport (= 5.2.3)
         | 
| 25 | 
            -
                  rack (~> 2.0)
         | 
| 26 | 
            -
                  rack-test (>= 0.6.3)
         | 
| 27 | 
            -
                  rails-dom-testing (~> 2.0)
         | 
| 28 | 
            -
                  rails-html-sanitizer (~> 1.0, >= 1.0.2)
         | 
| 29 | 
            -
                actionview (5.2.3)
         | 
| 30 | 
            -
                  activesupport (= 5.2.3)
         | 
| 31 | 
            -
                  builder (~> 3.1)
         | 
| 32 | 
            -
                  erubi (~> 1.4)
         | 
| 33 | 
            -
                  rails-dom-testing (~> 2.0)
         | 
| 34 | 
            -
                  rails-html-sanitizer (~> 1.0, >= 1.0.3)
         | 
| 35 | 
            -
                activejob (5.2.3)
         | 
| 36 | 
            -
                  activesupport (= 5.2.3)
         | 
| 37 | 
            -
                  globalid (>= 0.3.6)
         | 
| 38 | 
            -
                activemodel (5.2.3)
         | 
| 39 | 
            -
                  activesupport (= 5.2.3)
         | 
| 40 | 
            -
                activerecord (5.2.3)
         | 
| 41 | 
            -
                  activemodel (= 5.2.3)
         | 
| 42 | 
            -
                  activesupport (= 5.2.3)
         | 
| 43 | 
            -
                  arel (>= 9.0)
         | 
| 44 | 
            -
                activestorage (5.2.3)
         | 
| 45 | 
            -
                  actionpack (= 5.2.3)
         | 
| 46 | 
            -
                  activerecord (= 5.2.3)
         | 
| 47 | 
            -
                  marcel (~> 0.3.1)
         | 
| 48 | 
            -
                activesupport (5.2.3)
         | 
| 49 | 
            -
                  concurrent-ruby (~> 1.0, >= 1.0.2)
         | 
| 50 | 
            -
                  i18n (>= 0.7, < 2)
         | 
| 51 | 
            -
                  minitest (~> 5.1)
         | 
| 52 | 
            -
                  tzinfo (~> 1.1)
         | 
| 53 | 
            -
                addressable (2.6.0)
         | 
| 54 | 
            -
                  public_suffix (>= 2.0.2, < 4.0)
         | 
| 55 | 
            -
                arel (9.0.0)
         | 
| 56 | 
            -
                ast (2.4.0)
         | 
| 57 | 
            -
                builder (3.2.3)
         | 
| 58 | 
            -
                concurrent-ruby (1.1.5)
         | 
| 59 | 
            -
                crass (1.0.4)
         | 
| 60 | 
            -
                diff-lcs (1.3)
         | 
| 61 | 
            -
                docile (1.3.1)
         | 
| 62 | 
            -
                erubi (1.8.0)
         | 
| 63 | 
            -
                ffaker (2.10.0)
         | 
| 64 | 
            -
                globalid (0.4.2)
         | 
| 65 | 
            -
                  activesupport (>= 4.2.0)
         | 
| 66 | 
            -
                i18n (1.6.0)
         | 
| 67 | 
            -
                  concurrent-ruby (~> 1.0)
         | 
| 68 | 
            -
                jaro_winkler (1.5.2)
         | 
| 69 | 
            -
                json (2.2.0)
         | 
| 70 | 
            -
                jwt (2.2.0.pre.beta.0)
         | 
| 71 | 
            -
                loofah (2.2.3)
         | 
| 72 | 
            -
                  crass (~> 1.0.2)
         | 
| 73 | 
            -
                  nokogiri (>= 1.5.9)
         | 
| 74 | 
            -
                mail (2.7.1)
         | 
| 75 | 
            -
                  mini_mime (>= 0.1.1)
         | 
| 76 | 
            -
                marcel (0.3.3)
         | 
| 77 | 
            -
                  mimemagic (~> 0.3.2)
         | 
| 78 | 
            -
                method_source (0.9.2)
         | 
| 79 | 
            -
                mimemagic (0.3.3)
         | 
| 80 | 
            -
                mini_mime (1.0.1)
         | 
| 81 | 
            -
                mini_portile2 (2.4.0)
         | 
| 82 | 
            -
                minitest (5.11.3)
         | 
| 83 | 
            -
                nio4r (2.3.1)
         | 
| 84 | 
            -
                nokogiri (1.10.2)
         | 
| 85 | 
            -
                  mini_portile2 (~> 2.4.0)
         | 
| 86 | 
            -
                parallel (1.16.2)
         | 
| 87 | 
            -
                parser (2.6.2.0)
         | 
| 88 | 
            -
                  ast (~> 2.4.0)
         | 
| 89 | 
            -
                psych (3.1.0)
         | 
| 90 | 
            -
                public_suffix (3.0.3)
         | 
| 91 | 
            -
                rack (2.0.6)
         | 
| 92 | 
            -
                rack-test (1.1.0)
         | 
| 93 | 
            -
                  rack (>= 1.0, < 3)
         | 
| 94 | 
            -
                rails (5.2.3)
         | 
| 95 | 
            -
                  actioncable (= 5.2.3)
         | 
| 96 | 
            -
                  actionmailer (= 5.2.3)
         | 
| 97 | 
            -
                  actionpack (= 5.2.3)
         | 
| 98 | 
            -
                  actionview (= 5.2.3)
         | 
| 99 | 
            -
                  activejob (= 5.2.3)
         | 
| 100 | 
            -
                  activemodel (= 5.2.3)
         | 
| 101 | 
            -
                  activerecord (= 5.2.3)
         | 
| 102 | 
            -
                  activestorage (= 5.2.3)
         | 
| 103 | 
            -
                  activesupport (= 5.2.3)
         | 
| 104 | 
            -
                  bundler (>= 1.3.0)
         | 
| 105 | 
            -
                  railties (= 5.2.3)
         | 
| 106 | 
            -
                  sprockets-rails (>= 2.0.0)
         | 
| 107 | 
            -
                rails-dom-testing (2.0.3)
         | 
| 108 | 
            -
                  activesupport (>= 4.2.0)
         | 
| 109 | 
            -
                  nokogiri (>= 1.6)
         | 
| 110 | 
            -
                rails-html-sanitizer (1.0.4)
         | 
| 111 | 
            -
                  loofah (~> 2.2, >= 2.2.2)
         | 
| 112 | 
            -
                railties (5.2.3)
         | 
| 113 | 
            -
                  actionpack (= 5.2.3)
         | 
| 114 | 
            -
                  activesupport (= 5.2.3)
         | 
| 115 | 
            -
                  method_source
         | 
| 116 | 
            -
                  rake (>= 0.8.7)
         | 
| 117 | 
            -
                  thor (>= 0.19.0, < 2.0)
         | 
| 118 | 
            -
                rainbow (3.0.0)
         | 
| 119 | 
            -
                rake (12.3.2)
         | 
| 120 | 
            -
                rotp (4.1.0)
         | 
| 121 | 
            -
                  addressable (~> 2.5)
         | 
| 122 | 
            -
                rspec-core (3.8.0)
         | 
| 123 | 
            -
                  rspec-support (~> 3.8.0)
         | 
| 124 | 
            -
                rspec-expectations (3.8.2)
         | 
| 125 | 
            -
                  diff-lcs (>= 1.2.0, < 2.0)
         | 
| 126 | 
            -
                  rspec-support (~> 3.8.0)
         | 
| 127 | 
            -
                rspec-mocks (3.8.0)
         | 
| 128 | 
            -
                  diff-lcs (>= 1.2.0, < 2.0)
         | 
| 129 | 
            -
                  rspec-support (~> 3.8.0)
         | 
| 130 | 
            -
                rspec-rails (3.8.2)
         | 
| 131 | 
            -
                  actionpack (>= 3.0)
         | 
| 132 | 
            -
                  activesupport (>= 3.0)
         | 
| 133 | 
            -
                  railties (>= 3.0)
         | 
| 134 | 
            -
                  rspec-core (~> 3.8.0)
         | 
| 135 | 
            -
                  rspec-expectations (~> 3.8.0)
         | 
| 136 | 
            -
                  rspec-mocks (~> 3.8.0)
         | 
| 137 | 
            -
                  rspec-support (~> 3.8.0)
         | 
| 138 | 
            -
                rspec-support (3.8.0)
         | 
| 139 | 
            -
                rubocop (0.66.0)
         | 
| 140 | 
            -
                  jaro_winkler (~> 1.5.1)
         | 
| 141 | 
            -
                  parallel (~> 1.10)
         | 
| 142 | 
            -
                  parser (>= 2.5, != 2.5.1.1)
         | 
| 143 | 
            -
                  psych (>= 3.1.0)
         | 
| 144 | 
            -
                  rainbow (>= 2.2.2, < 4.0)
         | 
| 145 | 
            -
                  ruby-progressbar (~> 1.7)
         | 
| 146 | 
            -
                  unicode-display_width (>= 1.4.0, < 1.6)
         | 
| 147 | 
            -
                rubocop-performance (1.0.0)
         | 
| 148 | 
            -
                  rubocop (>= 0.58.0)
         | 
| 149 | 
            -
                rubocop-rails_config (0.4.4)
         | 
| 150 | 
            -
                  railties (>= 3.0)
         | 
| 151 | 
            -
                  rubocop (~> 0.58)
         | 
| 152 | 
            -
                rubocop-rspec (1.32.0)
         | 
| 153 | 
            -
                  rubocop (>= 0.60.0)
         | 
| 154 | 
            -
                ruby-progressbar (1.10.0)
         | 
| 155 | 
            -
                simplecov (0.16.1)
         | 
| 156 | 
            -
                  docile (~> 1.1)
         | 
| 157 | 
            -
                  json (>= 1.8, < 3)
         | 
| 158 | 
            -
                  simplecov-html (~> 0.10.0)
         | 
| 159 | 
            -
                simplecov-html (0.10.2)
         | 
| 160 | 
            -
                sprockets (3.7.2)
         | 
| 161 | 
            -
                  concurrent-ruby (~> 1.0)
         | 
| 162 | 
            -
                  rack (> 1, < 3)
         | 
| 163 | 
            -
                sprockets-rails (3.2.1)
         | 
| 164 | 
            -
                  actionpack (>= 4.0)
         | 
| 165 | 
            -
                  activesupport (>= 4.0)
         | 
| 166 | 
            -
                  sprockets (>= 3.0.0)
         | 
| 167 | 
            -
                sqlite3 (1.3.13)
         | 
| 168 | 
            -
                thor (0.20.3)
         | 
| 169 | 
            -
                thread_safe (0.3.6)
         | 
| 170 | 
            -
                tzinfo (1.2.5)
         | 
| 171 | 
            -
                  thread_safe (~> 0.1)
         | 
| 172 | 
            -
                unicode-display_width (1.5.0)
         | 
| 173 | 
            -
                websocket-driver (0.7.0)
         | 
| 174 | 
            -
                  websocket-extensions (>= 0.1.0)
         | 
| 175 | 
            -
                websocket-extensions (0.1.3)
         | 
| 176 | 
            -
                yard (0.9.18)
         | 
| 177 | 
            -
                yardstick (0.9.9)
         | 
| 178 | 
            -
                  yard (~> 0.8, >= 0.8.7.2)
         | 
| 179 | 
            -
             | 
| 180 | 
            -
            PLATFORMS
         | 
| 181 | 
            -
              ruby
         | 
| 182 | 
            -
             | 
| 183 | 
            -
            DEPENDENCIES
         | 
| 184 | 
            -
              bundler
         | 
| 185 | 
            -
              ffaker
         | 
| 186 | 
            -
              otp-jwt!
         | 
| 187 | 
            -
              rails
         | 
| 188 | 
            -
              rspec-rails
         | 
| 189 | 
            -
              rubocop-performance
         | 
| 190 | 
            -
              rubocop-rails_config
         | 
| 191 | 
            -
              rubocop-rspec
         | 
| 192 | 
            -
              simplecov
         | 
| 193 | 
            -
              sqlite3 (~> 1.3.6)
         | 
| 194 | 
            -
              yardstick
         | 
| 195 | 
            -
             | 
| 196 | 
            -
            BUNDLED WITH
         | 
| 197 | 
            -
               1.17.3
         | 
    
        data/Rakefile
    DELETED
    
    | @@ -1,30 +0,0 @@ | |
| 1 | 
            -
            require 'bundler/gem_tasks'
         | 
| 2 | 
            -
            require 'rspec/core/rake_task'
         | 
| 3 | 
            -
            require 'rubocop/rake_task'
         | 
| 4 | 
            -
            require 'yaml'
         | 
| 5 | 
            -
            require 'yardstick'
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            desc('Documentation stats and measurements')
         | 
| 8 | 
            -
            task('qa:docs') do
         | 
| 9 | 
            -
              yaml = YAML.load_file(File.expand_path('../.yardstick.yml', __FILE__))
         | 
| 10 | 
            -
              config = Yardstick::Config.coerce(yaml)
         | 
| 11 | 
            -
              measure = Yardstick.measure(config)
         | 
| 12 | 
            -
              measure.puts
         | 
| 13 | 
            -
              coverage = Yardstick.round_percentage(measure.coverage * 100)
         | 
| 14 | 
            -
              exit(1) if coverage < config.threshold
         | 
| 15 | 
            -
            end
         | 
| 16 | 
            -
             | 
| 17 | 
            -
            desc('Codestyle check and linter')
         | 
| 18 | 
            -
            RuboCop::RakeTask.new('qa:code') do |task|
         | 
| 19 | 
            -
              task.fail_on_error = true
         | 
| 20 | 
            -
              task.patterns = [
         | 
| 21 | 
            -
                'lib/**/*.rb',
         | 
| 22 | 
            -
                'spec/**/*.rb'
         | 
| 23 | 
            -
              ]
         | 
| 24 | 
            -
            end
         | 
| 25 | 
            -
             | 
| 26 | 
            -
            desc('Run CI QA tasks')
         | 
| 27 | 
            -
            task(qa: ['qa:docs', 'qa:code'])
         | 
| 28 | 
            -
             | 
| 29 | 
            -
            RSpec::Core::RakeTask.new(spec: :qa)
         | 
| 30 | 
            -
            task(default: :spec)
         | 
    
        data/otp-jwt.gemspec
    DELETED
    
    | @@ -1,36 +0,0 @@ | |
| 1 | 
            -
            lib = File.expand_path('../lib', __FILE__)
         | 
| 2 | 
            -
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            require 'otp/jwt/version'
         | 
| 5 | 
            -
             | 
| 6 | 
            -
            Gem::Specification.new do |spec|
         | 
| 7 | 
            -
              spec.name          = 'otp-jwt'
         | 
| 8 | 
            -
              spec.version       = OTP::JWT::VERSION
         | 
| 9 | 
            -
              spec.authors       = ['Stas Suscov']
         | 
| 10 | 
            -
              spec.email         = ['stas@nerd.ro']
         | 
| 11 | 
            -
             | 
| 12 | 
            -
              spec.summary       = 'Passwordless HTTP APIs'
         | 
| 13 | 
            -
              spec.description   = 'OTP (email, SMS) JWT authentication for HTTP APIs.'
         | 
| 14 | 
            -
              spec.homepage      = 'https://github.com/stas/otp-jwt'
         | 
| 15 | 
            -
              spec.license       = 'TBD'
         | 
| 16 | 
            -
             | 
| 17 | 
            -
              spec.files         = Dir.chdir(File.expand_path('..', __FILE__)) do
         | 
| 18 | 
            -
                `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec)/}) }
         | 
| 19 | 
            -
              end
         | 
| 20 | 
            -
              spec.require_paths = ['lib']
         | 
| 21 | 
            -
             | 
| 22 | 
            -
              spec.add_dependency 'activesupport'
         | 
| 23 | 
            -
              spec.add_dependency 'jwt', '~> 2.2.0.pre.beta.0'
         | 
| 24 | 
            -
              spec.add_dependency 'rotp', '~> 4.1'
         | 
| 25 | 
            -
             | 
| 26 | 
            -
              spec.add_development_dependency 'bundler'
         | 
| 27 | 
            -
              spec.add_development_dependency 'ffaker'
         | 
| 28 | 
            -
              spec.add_development_dependency 'rails'
         | 
| 29 | 
            -
              spec.add_development_dependency 'rspec-rails'
         | 
| 30 | 
            -
              spec.add_development_dependency 'rubocop-performance'
         | 
| 31 | 
            -
              spec.add_development_dependency 'rubocop-rails_config'
         | 
| 32 | 
            -
              spec.add_development_dependency 'rubocop-rspec'
         | 
| 33 | 
            -
              spec.add_development_dependency 'simplecov'
         | 
| 34 | 
            -
              spec.add_development_dependency 'sqlite3', '~> 1.3.6'
         | 
| 35 | 
            -
              spec.add_development_dependency 'yardstick'
         | 
| 36 | 
            -
            end
         |