otp-jwt 0.2.4 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 5a6047b41e5b59f65c9a0ab0b138798ba611a113
4
- data.tar.gz: 5b157ecb5af5abebcd324f3b18698279af02d050
2
+ SHA256:
3
+ metadata.gz: e7d17e5145dd260643ff8c5af4e8bdd866282b126d9873d0eb7db432fa289e97
4
+ data.tar.gz: bdedfcdb0ad970bc380f18aa4e518030b15b08f439d0854043ac45d22ba55c81
5
5
  SHA512:
6
- metadata.gz: 3c9ee97ec926b861d0599462def570ae799ac65a3f59040725b376359de451817680b1a538759126fe698895157813b15a911738c4976dd801cce5d17aa0a562
7
- data.tar.gz: d3fede4d63a6121e34fdcad1b8d3c48cd85088e99bfa94b001cf94895ea6574e66e061db7e442a9b4904eb079c7457cd0398d897eaf0085b0d29b50cb3428655
6
+ metadata.gz: b287bc6b7d738be7ef9028d224a77794a27e1da869115de54b693ee9b6c7f5ce094672bf021e4b79956171bae351fd36c39b2506ce4d0c58f5081a43679294d5
7
+ data.tar.gz: bdae8f51b91ef4e488d867b9281a604437524dcf0c40486901402393341ca563ba465c3cc2eb554f76ebda928124a2ae382302acd418852311368c98f39c08a5
@@ -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
@@ -72,7 +72,6 @@ module OTP
72
72
  end
73
73
 
74
74
  private
75
-
76
75
  # Provides a default value for the OTP secret attribute
77
76
  #
78
77
  # @return [String]
@@ -3,7 +3,6 @@ module OTP
3
3
  # [ActionController] concern.
4
4
  module ActionController
5
5
  private
6
-
7
6
  # Authenticates a model and responds with a [JWT] token
8
7
  #
9
8
  # @return [String] with authentication token and country shop ID.
@@ -17,9 +17,13 @@ module OTP
17
17
  val = payload[claim_name]
18
18
  pk_col = self.column_for_attribute(self.primary_key)
19
19
 
20
- # Arel casts the values to the primary key type, which means
21
- # that an UUID will become an integer...
22
- casted_val = self.connection.type_cast(val, pk_col)
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?(:type_cast_from_column)
23
+ casted_val = self.connection.type_cast_from_column(pk_col, val)
24
+ else
25
+ casted_val = self.connection.type_cast(val, pk_col)
26
+ end
23
27
 
24
28
  return if casted_val.to_s != val.to_s.strip
25
29
 
@@ -15,7 +15,7 @@ module OTP
15
15
  #
16
16
  # @return [Hash] the authorization headers
17
17
  def jwt_auth_header(entity_or_subject)
18
- return json_headers unless entity_or_subject.present?
18
+ return json_headers if entity_or_subject.blank?
19
19
 
20
20
  token = entity_or_subject.try(:to_jwt)
21
21
  token ||= OTP::JWT::Token.sign(sub: entity_or_subject)
@@ -1,5 +1,5 @@
1
1
  module OTP
2
2
  module JWT
3
- VERSION = '0.2.4'
3
+ VERSION = '0.2.5'
4
4
  end
5
5
  end
@@ -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
@@ -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
@@ -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
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stas Suscov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-16 00:00:00.000000000 Z
11
+ date: 2021-01-09 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.2.0.pre.beta.0
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.2.0.pre.beta.0
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: '4.1'
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: '4.1'
54
+ version: '6'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -84,16 +84,16 @@ dependencies:
84
84
  name: rails
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: '4'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: '4'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rspec-rails
99
99
  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.81'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '='
123
+ - !ruby/object:Gem::Version
124
+ version: '0.81'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: rubocop-performance
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -166,6 +180,20 @@ dependencies:
166
180
  version: '0'
167
181
  - !ruby/object:Gem::Dependency
168
182
  name: sqlite3
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: 1.3.6
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: 1.3.6
195
+ - !ruby/object:Gem::Dependency
196
+ name: tzinfo-data
169
197
  requirement: !ruby/object:Gem::Requirement
170
198
  requirements:
171
199
  - - ">="
@@ -199,14 +227,8 @@ executables: []
199
227
  extensions: []
200
228
  extra_rdoc_files: []
201
229
  files:
202
- - ".github/main.workflow"
203
- - ".gitignore"
204
- - ".rspec"
205
- - ".rubocop.yml"
206
- - ".yardstick.yml"
207
- - Gemfile
230
+ - LICENSE.txt
208
231
  - README.md
209
- - Rakefile
210
232
  - lib/otp.rb
211
233
  - lib/otp/active_record.rb
212
234
  - lib/otp/jwt.rb
@@ -218,10 +240,15 @@ files:
218
240
  - lib/otp/mailer.rb
219
241
  - lib/otp/mailer/otp.text.erb
220
242
  - lib/otp/sms_job.rb
221
- - otp-jwt.gemspec
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
222
249
  homepage: https://github.com/stas/otp-jwt
223
250
  licenses:
224
- - TBD
251
+ - MIT
225
252
  metadata: {}
226
253
  post_install_message:
227
254
  rdoc_options: []
@@ -238,8 +265,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
238
265
  - !ruby/object:Gem::Version
239
266
  version: '0'
240
267
  requirements: []
241
- rubyforge_project:
242
- rubygems_version: 2.5.2.2
268
+ rubygems_version: 3.0.3
243
269
  signing_key:
244
270
  specification_version: 4
245
271
  summary: Passwordless HTTP APIs
@@ -1,44 +0,0 @@
1
- workflow "Tests" {
2
- on = "push"
3
- resolves = [
4
- "rspec-ruby2.6_rails4",
5
- "rspec-ruby2.6_rails5",
6
- "rspec-ruby2.6_rails6"
7
- ]
8
- }
9
-
10
- action "rspec-ruby2.6_rails4" {
11
- uses = "docker://ruby:2.6-alpine"
12
- env = {
13
- RAILS_VERSION = "~> 4"
14
- SQLITE3_VERSION = "~> 1.3.6"
15
- }
16
- args = [
17
- "sh", "-c",
18
- "apk add -U git build-base sqlite-dev && bundle install && rake"
19
- ]
20
- }
21
-
22
- action "rspec-ruby2.6_rails5" {
23
- uses = "docker://ruby:2.6-alpine"
24
- needs = ["rspec-ruby2.6_rails4"]
25
- env = {
26
- RAILS_VERSION = "~> 5"
27
- }
28
- args = [
29
- "sh", "-c",
30
- "apk add -U git build-base sqlite-dev && bundle install && rake"
31
- ]
32
- }
33
-
34
- action "rspec-ruby2.6_rails6" {
35
- uses = "docker://ruby:2.6-alpine"
36
- needs = ["rspec-ruby2.6_rails5"]
37
- env = {
38
- RAILS_VERSION = "~> 6.0.0.rc1"
39
- }
40
- args = [
41
- "sh", "-c",
42
- "apk add -U git build-base sqlite-dev && bundle install && rake"
43
- ]
44
- }
data/.gitignore DELETED
@@ -1,4 +0,0 @@
1
- coverage
2
- pkg
3
- *.lock
4
- tmp
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
@@ -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
@@ -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
@@ -1,7 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in otp-jwt.gemspec
4
- gemspec
5
-
6
- gem 'rails', ENV['RAILS_VERSION']
7
- gem 'tzinfo-data'
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)
@@ -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', ENV['SQLITE3_VERSION']
35
- spec.add_development_dependency 'yardstick'
36
- end