solidus_jwt 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +35 -0
  3. data/.gem_release.yml +5 -0
  4. data/.github/CODEOWNERS +4 -0
  5. data/.github/stale.yml +17 -0
  6. data/.gitignore +19 -0
  7. data/.rspec +1 -0
  8. data/.rubocop.yml +33 -0
  9. data/.ruby-gemset +1 -0
  10. data/.ruby-version +1 -0
  11. data/Gemfile +31 -0
  12. data/Rakefile +4 -28
  13. data/_config.yml +1 -0
  14. data/app/controllers/spree/api/oauths_controller.rb +12 -5
  15. data/app/decorators/solidus_jwt/spree/api/base_controller_decorator.rb +39 -0
  16. data/app/decorators/solidus_jwt/spree/user_decorator.rb +36 -0
  17. data/app/models/solidus_jwt/base_record.rb +11 -0
  18. data/app/models/solidus_jwt/token.rb +17 -4
  19. data/bin/console +17 -0
  20. data/bin/rails +18 -0
  21. data/bin/sandbox +81 -0
  22. data/bin/setup +8 -0
  23. data/config/locales/en.yml +2 -1
  24. data/db/migrate/20191212083655_add_foreign_key_to_users_table.rb +5 -0
  25. data/lib/generators/solidus_jwt/install/install_generator.rb +1 -11
  26. data/lib/solidus_jwt.rb +2 -0
  27. data/lib/solidus_jwt/concerns/decodeable.rb +5 -1
  28. data/lib/solidus_jwt/concerns/encodeable.rb +12 -2
  29. data/lib/solidus_jwt/devise_strategies/base.rb +23 -0
  30. data/lib/solidus_jwt/devise_strategies/password.rb +5 -11
  31. data/lib/solidus_jwt/devise_strategies/refresh_token.rb +7 -10
  32. data/lib/solidus_jwt/distributor/devise.rb +1 -1
  33. data/lib/solidus_jwt/engine.rb +6 -12
  34. data/lib/solidus_jwt/version.rb +1 -9
  35. data/solidus_jwt.gemspec +36 -0
  36. data/spec/lib/solidus_jwt/concerns/decodeable_spec.rb +0 -0
  37. data/spec/lib/solidus_jwt/concerns/encodeable_spec.rb +0 -0
  38. data/spec/lib/solidus_jwt/config_spec.rb +5 -0
  39. data/spec/lib/solidus_jwt/devise_strategies/password_spec.rb +76 -0
  40. data/spec/lib/solidus_jwt/devise_strategies/refresh_token_spec.rb +72 -0
  41. data/spec/lib/solidus_jwt/preferences_spec.rb +37 -0
  42. data/spec/lib/solidus_jwt_spec.rb +6 -0
  43. data/spec/models/solidus_jwt/token_spec.rb +41 -0
  44. data/spec/requests/spree/api/json_web_tokens_spec.rb +75 -0
  45. data/spec/requests/spree/api/oauths_spec.rb +120 -0
  46. data/spec/spec_helper.rb +24 -0
  47. data/spec/support/shared_examples/decodeable_examples.rb +21 -0
  48. data/spec/support/shared_examples/encodeable_examples.rb +27 -0
  49. metadata +65 -227
  50. data/app/assets/javascripts/spree/backend/solidus_jwt.js +0 -2
  51. data/app/assets/javascripts/spree/frontend/solidus_jwt.js +0 -2
  52. data/app/assets/stylesheets/spree/backend/solidus_jwt.css +0 -4
  53. data/app/assets/stylesheets/spree/frontend/solidus_jwt.css +0 -4
  54. data/app/controllers/spree/api/base_controller/json_web_tokens.rb +0 -22
  55. data/app/controllers/spree/api/base_controller_decorator.rb +0 -17
  56. data/app/models/application_record.rb +0 -3
  57. data/app/models/solidus_jwt/application_record.rb +0 -9
  58. data/app/models/spree/user_decorator.rb +0 -34
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56581878cbe327640f9c05d72e030cbeeb0fc4c5c70d6d5d5d0a78a82fad388b
4
- data.tar.gz: fd8f5ca391a04a4cc5ab3cd53f1b626533fe3e040b238cd2a8c5fb25372874fa
3
+ metadata.gz: 0f3f9ec2c12488185b2ee9bff66409693f0d92ab52bde2adb67cc47df182a82a
4
+ data.tar.gz: a77951e23f7d2352c5a2dde5a2742997f38bfb8e07ac31f1ae4f8be7b6bfc12c
5
5
  SHA512:
6
- metadata.gz: 64a7e377baa923773260008a9940f6fb87239849ad0271dddab69479c74cf991b78f02c775362501dc1aefef4daca52aa01697db7b1ce5583d18fc0a074709f9
7
- data.tar.gz: 8c8dac8527c305d66d52cff3bad1bc6875746f5297493213d3db68f4ce72bcfa5b9ed6f8e95e7c5b787e402317d8cee1486ad78981b4e5768b156da9b816a1c7
6
+ metadata.gz: '058c6e5d8bcc54fa1b623b68ab46848f9e9ffb6feee2e97f048c1047ed6a5c11ce78990aef67b6432d051471e718c09ef00b30717b0419edd88d95cbf0ca8412'
7
+ data.tar.gz: 95993510aecd67280bc85dc283798edae88d9c8388c1997190f8420d2ea4351d6e88273d7f5236449df52ff035e276725c924a5a835144c10dc458146bbe6bb3
@@ -0,0 +1,35 @@
1
+ version: 2.1
2
+
3
+ orbs:
4
+ # Always take the latest version of the orb, this allows us to
5
+ # run specs against Solidus supported versions only without the need
6
+ # to change this configuration every time a Solidus version is released
7
+ # or goes EOL.
8
+ solidusio_extensions: solidusio/extensions@volatile
9
+
10
+ jobs:
11
+ run-specs-with-postgres:
12
+ executor: solidusio_extensions/postgres
13
+ steps:
14
+ - solidusio_extensions/run-tests
15
+ run-specs-with-mysql:
16
+ executor: solidusio_extensions/mysql
17
+ steps:
18
+ - solidusio_extensions/run-tests
19
+
20
+ workflows:
21
+ "Run specs on supported Solidus versions":
22
+ jobs:
23
+ - run-specs-with-postgres
24
+ - run-specs-with-mysql
25
+ "Weekly run specs against master":
26
+ triggers:
27
+ - schedule:
28
+ cron: "0 0 * * 4" # every Thursday
29
+ filters:
30
+ branches:
31
+ only:
32
+ - master
33
+ jobs:
34
+ - run-specs-with-postgres
35
+ - run-specs-with-mysql
data/.gem_release.yml ADDED
@@ -0,0 +1,5 @@
1
+ bump:
2
+ recurse: false
3
+ file: 'lib/solidus_jwt/version.rb'
4
+ message: Bump SolidusJwt to %{version}
5
+ branch: true
@@ -0,0 +1,4 @@
1
+ ##
2
+ # Default Code Owner
3
+ ##
4
+ * @skukx
data/.github/stale.yml ADDED
@@ -0,0 +1,17 @@
1
+ # Number of days of inactivity before an issue becomes stale
2
+ daysUntilStale: 60
3
+ # Number of days of inactivity before a stale issue is closed
4
+ daysUntilClose: 7
5
+ # Issues with these labels will never be considered stale
6
+ exemptLabels:
7
+ - pinned
8
+ - security
9
+ # Label to use when marking an issue as stale
10
+ staleLabel: wontfix
11
+ # Comment to post when marking an issue as stale. Set to `false` to disable
12
+ markComment: >
13
+ This issue has been automatically marked as stale because it has not had
14
+ recent activity. It will be closed if no further activity occurs. Thank you
15
+ for your contributions.
16
+ # Comment to post when closing a stale issue. Set to `false` to disable
17
+ closeComment: false
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ \#*
3
+ *~
4
+ .#*
5
+ .DS_Store
6
+ .idea
7
+ .project
8
+ .sass-cache
9
+ coverage
10
+ Gemfile.lock
11
+ tmp
12
+ nbproject
13
+ pkg
14
+ *.swp
15
+ spec/dummy
16
+ spec/examples.txt
17
+
18
+ sandbox/
19
+ .byebug_history
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,33 @@
1
+ require:
2
+ - solidus_dev_support/rubocop
3
+
4
+ AllCops:
5
+ Exclude:
6
+ - sandbox/**/*
7
+ - spec/dummy/**/*
8
+
9
+ Style/FrozenStringLiteralComment:
10
+ Enabled: false
11
+
12
+ Naming/PredicateName:
13
+ Exclude:
14
+ - app/decorators/solidus_kits/spree/stock/availability_validator_decorator.rb
15
+
16
+ Metrics/LineLength:
17
+ Enabled: false
18
+
19
+ Rails/SkipsModelValidations:
20
+ Exclude:
21
+ - 'spec/**/*'
22
+
23
+ RSpec/BeforeAfterAll:
24
+ Enabled: false
25
+
26
+ RSpec/ContextWording:
27
+ Enabled: false
28
+
29
+ RSpec/MultipleExpectations:
30
+ Enabled: false
31
+
32
+ RSpec/NestedGroups:
33
+ Enabled: false
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ solidus_jwt
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.6.5
data/Gemfile ADDED
@@ -0,0 +1,31 @@
1
+ source 'https://rubygems.org'
2
+ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
3
+
4
+ branch = ENV.fetch('SOLIDUS_BRANCH', 'master')
5
+ gem 'solidus', github: 'solidusio/solidus', branch: branch
6
+
7
+ # Needed to help Bundler figure out how to resolve dependencies,
8
+ # otherwise it takes forever to resolve them.
9
+ # See https://github.com/bundler/bundler/issues/6677
10
+ gem 'rails', '>0.a'
11
+
12
+ # Provides basic authentication functionality for testing parts of your engine
13
+ gem 'solidus_auth_devise'
14
+
15
+ case ENV['DB']
16
+ when 'mysql'
17
+ gem 'mysql2'
18
+ when 'postgresql'
19
+ gem 'pg'
20
+ else
21
+ gem 'sqlite3'
22
+ end
23
+
24
+ gemspec
25
+
26
+ # Use a local Gemfile to include development dependencies that might not be
27
+ # relevant for the project or for other contributors, e.g. pry-byebug.
28
+ #
29
+ # We use `send` instead of calling `eval_gemfile` to work around an issue with
30
+ # how Dependabot parses projects: https://github.com/dependabot/dependabot-core/issues/1658.
31
+ send(:eval_gemfile, 'Gemfile-local') if File.exist? 'Gemfile-local'
data/Rakefile CHANGED
@@ -1,30 +1,6 @@
1
- require 'bundler'
1
+ # frozen_string_literal: true
2
2
 
3
- Bundler::GemHelper.install_tasks
3
+ require 'solidus_dev_support/rake_tasks'
4
+ SolidusDevSupport::RakeTasks.install
4
5
 
5
- begin
6
- require 'spree/testing_support/extension_rake'
7
- require 'rubocop/rake_task'
8
- require 'rspec/core/rake_task'
9
-
10
- RSpec::Core::RakeTask.new(:spec)
11
-
12
- RuboCop::RakeTask.new
13
-
14
- task default: %i(first_run rubocop spec)
15
- rescue LoadError
16
- # no rspec available
17
- end
18
-
19
- task :first_run do
20
- if Dir['spec/dummy'].empty?
21
- Rake::Task[:test_app].invoke
22
- Dir.chdir('../../')
23
- end
24
- end
25
-
26
- desc 'Generates a dummy app for testing'
27
- task :test_app do
28
- ENV['LIB_NAME'] = 'solidus_jwt'
29
- Rake::Task['extension:test_app'].invoke
30
- end
6
+ task default: 'extension:specs'
data/_config.yml ADDED
@@ -0,0 +1 @@
1
+ theme: jekyll-theme-cayman
@@ -4,19 +4,26 @@ module Spree
4
4
  skip_before_action :authenticate_user
5
5
 
6
6
  def token
7
- if user = try_authenticate_user
8
- render_token_for(user)
7
+ result = catch(:warden) do
8
+ try_authenticate_user
9
+ end
10
+
11
+ case result
12
+ when Spree::User
13
+ render json: token_response_json(result)
14
+ when Hash
15
+ render status: :unauthorized, json: { error: I18n.t(result[:message], scope: 'devise.failure') }
9
16
  else
10
- render status: 401, json: { error: 'invalid username or password' }
17
+ render status: :unauthorized, json: { error: I18n.t(:invalid_credentials, scope: 'solidus_jwt') }
11
18
  end
12
19
  end
13
20
 
14
21
  private
15
22
 
16
- def render_token_for(user)
23
+ def token_response_json(user)
17
24
  expires_in = SolidusJwt::Config.jwt_expiration
18
25
 
19
- render json: {
26
+ {
20
27
  token_type: 'bearer',
21
28
  access_token: user.generate_jwt(expires_in: expires_in),
22
29
  expires_in: expires_in,
@@ -0,0 +1,39 @@
1
+ module SolidusJwt
2
+ module Spree
3
+ module Api
4
+ module BaseControllerDecorator
5
+ def self.prepended(base)
6
+ base.rescue_from JWT::DecodeError do
7
+ render "spree/api/errors/invalid_api_key", status: :unauthorized
8
+ end
9
+ end
10
+
11
+ ##
12
+ # Overrides Solidus
13
+ # @see https://github.com/solidusio/solidus/blob/master/api/app/controllers/spree/api/base_controller.rb
14
+ #
15
+ def load_user
16
+ return super if json_web_token.blank?
17
+
18
+ # rubocop:disable Naming/MemoizedInstanceVariableName
19
+ @current_api_user ||= ::Spree.user_class.find_by(id: json_web_token['id'])
20
+ # rubocop:enable Naming/MemoizedInstanceVariableName
21
+ end
22
+
23
+ def json_web_token
24
+ @json_web_token ||= SolidusJwt.decode(api_key).first
25
+ rescue JWT::DecodeError
26
+ # Allow spree to try and authenticate if we still allow it. Otherwise
27
+ # raise an error
28
+ return if SolidusJwt::Config.allow_spree_api_key
29
+
30
+ raise
31
+ end
32
+
33
+ if SolidusSupport.api_available?
34
+ ::Spree::Api::BaseController.prepend self
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,36 @@
1
+ module SolidusJwt
2
+ module Spree
3
+ module UserDecorator
4
+ def self.prepended(base)
5
+ base.has_many :auth_tokens, class_name: 'SolidusJwt::Token'
6
+ end
7
+
8
+ ##
9
+ # Generate a json web token
10
+ # @see https://github.com/jwt/ruby-jwt
11
+ # @return [String]
12
+ #
13
+ def generate_jwt(expires_in: nil)
14
+ SolidusJwt.encode(payload: as_jwt_payload, expires_in: expires_in)
15
+ end
16
+ alias generate_jwt_token generate_jwt
17
+
18
+ ##
19
+ # Serializes user attributes to hash and applies
20
+ # the sub jwt claim.
21
+ #
22
+ # @return [Hash] The payload for json web token
23
+ #
24
+ def as_jwt_payload
25
+ options = SolidusJwt::Config.jwt_options
26
+ claims = { sub: id }
27
+
28
+ as_json(options)
29
+ .merge(claims)
30
+ .as_json
31
+ end
32
+
33
+ ::Spree.user_class.prepend self
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,11 @@
1
+ module SolidusJwt
2
+ base_class = defined?(::ApplicationRecord) ? ::ApplicationRecord : ActiveRecord::Base
3
+
4
+ class BaseRecord < base_class
5
+ self.abstract_class = true
6
+
7
+ def self.table_name_prefix
8
+ 'solidus_jwt_'
9
+ end
10
+ end
11
+ end
@@ -1,9 +1,11 @@
1
1
  module SolidusJwt
2
- class Token < ApplicationRecord
2
+ class Token < BaseRecord
3
3
  attr_readonly :token
4
- enum auth_type: %i[refresh_token access_token]
4
+ enum auth_type: { refresh_token: 0, access_token: 1 }
5
5
 
6
- belongs_to :user, class_name: Spree::UserClassHandle.new
6
+ # rubocop:disable Rails/ReflectionClassName
7
+ belongs_to :user, class_name: ::Spree::UserClassHandle.new
8
+ # rubocop:enable Rails/ReflectionClassName
7
9
 
8
10
  scope :non_expired, -> {
9
11
  where(
@@ -12,7 +14,7 @@ module SolidusJwt
12
14
  )
13
15
  }
14
16
 
15
- enum auth_type: %i[refresh access]
17
+ enum auth_type: { refresh: 0, access: 1 }
16
18
 
17
19
  validates :token, presence: true
18
20
 
@@ -24,9 +26,11 @@ module SolidusJwt
24
26
  # Set all non expired refresh tokens to inactive
25
27
  #
26
28
  def self.invalidate(user)
29
+ # rubocop:disable Rails/SkipsModelValidations
27
30
  non_expired.
28
31
  where(user_id: user.to_param).
29
32
  update_all(active: false)
33
+ # rubocop:enable Rails/SkipsModelValidations
30
34
  end
31
35
 
32
36
  ##
@@ -37,10 +41,19 @@ module SolidusJwt
37
41
  non_expired.where(active: true).find_by(token: token).present?
38
42
  end
39
43
 
44
+ ##
45
+ # Whether the token should be honored.
46
+ # @return [Boolean] Will be true if the token is active and not expired.
47
+ # Otherwise false.
40
48
  def honor?
41
49
  active? && !expired?
42
50
  end
43
51
 
52
+ ##
53
+ # Whether the token is expired
54
+ # @return [Boolean] If the token is older than the configured refresh
55
+ # expiration amount then will be true. Otherwise false.
56
+ #
44
57
  def expired?
45
58
  created_at < SolidusJwt::Config.refresh_expiration.seconds.ago
46
59
  end
data/bin/console ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require "bundler/setup"
6
+ require "solidus_jwt"
7
+
8
+ # You can add fixtures and/or initialization code here to make experimenting
9
+ # with your gem easier. You can also use a different console, if you like.
10
+ $LOAD_PATH.unshift(*Dir["#{__dir__}/../app/*"])
11
+
12
+ # (If you use this, don't forget to add pry to your Gemfile!)
13
+ # require "pry"
14
+ # Pry.start
15
+
16
+ require "irb"
17
+ IRB.start(__FILE__)
data/bin/rails ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ app_root = 'sandbox'
6
+
7
+ unless File.exist? "#{app_root}/bin/rails"
8
+ warn 'Creating the sandbox app...'
9
+ Dir.chdir "#{__dir__}/.." do
10
+ system "#{__dir__}/sandbox" or begin # rubocop:disable Style/AndOr
11
+ warn 'Automatic creation of the sandbox app failed'
12
+ exit 1
13
+ end
14
+ end
15
+ end
16
+
17
+ Dir.chdir app_root
18
+ exec 'bin/rails', *ARGV
data/bin/sandbox ADDED
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ case "$DB" in
6
+ postgres|postgresql)
7
+ RAILSDB="postgresql"
8
+ ;;
9
+ mysql)
10
+ RAILSDB="mysql"
11
+ ;;
12
+ sqlite|'')
13
+ RAILSDB="sqlite3"
14
+ ;;
15
+ *)
16
+ echo "Invalid DB specified: $DB"
17
+ exit 1
18
+ ;;
19
+ esac
20
+
21
+ if [ ! -z $SOLIDUS_BRANCH ]
22
+ then
23
+ BRANCH=$SOLIDUS_BRANCH
24
+ else
25
+ BRANCH="master"
26
+ fi
27
+
28
+ extension_name="solidus_jwt"
29
+
30
+ # Stay away from the bundler env of the containing extension.
31
+ function unbundled {
32
+ ruby -rbundler -e'b = proc {system *ARGV}; Bundler.respond_to?(:with_unbundled_env) ? Bundler.with_unbundled_env(&b) : Bundler.with_clean_env(&b)' -- $@
33
+ }
34
+
35
+ rm -rf ./sandbox
36
+ unbundled bundle exec rails new sandbox --database="$RAILSDB" \
37
+ --skip-bundle \
38
+ --skip-git \
39
+ --skip-keeps \
40
+ --skip-rc \
41
+ --skip-spring \
42
+ --skip-test \
43
+ --skip-javascript
44
+
45
+ if [ ! -d "sandbox" ]; then
46
+ echo 'sandbox rails application failed'
47
+ exit 1
48
+ fi
49
+
50
+ cd ./sandbox
51
+ cat <<RUBY >> Gemfile
52
+ gem 'solidus', github: 'solidusio/solidus', branch: '$BRANCH'
53
+ gem 'solidus_auth_devise', '>= 2.1.0'
54
+ gem 'rails-i18n'
55
+ gem 'solidus_i18n'
56
+ gem '$extension_name', path: '..'
57
+ group :test, :development do
58
+ platforms :mri do
59
+ gem 'pry-byebug'
60
+ end
61
+ end
62
+ RUBY
63
+
64
+ unbundled bundle install --gemfile Gemfile
65
+
66
+ unbundled bundle exec rake db:drop db:create
67
+
68
+ unbundled bundle exec rails generate spree:install \
69
+ --auto-accept \
70
+ --user_class=Spree::User \
71
+ --enforce_available_locales=true \
72
+ $@
73
+
74
+ unbundled bundle exec rails generate solidus:auth:install
75
+
76
+ echo
77
+ echo "🚀 Sandbox app successfully created for $extension_name!"
78
+ echo "🚀 Using $RAILSDB and Solidus $BRANCH"
79
+ echo "🚀 Use 'export DB=[postgres|mysql|sqlite]' to control the DB adapter"
80
+ echo "🚀 Use 'export SOLIDUS_BRANCH=<BRANCH-NAME>' to control the Solidus version"
81
+ echo "🚀 This app is intended for test purposes."