diff --git a/.envrc b/.envrc
new file mode 100644
index 00000000..db2e5864
--- /dev/null
+++ b/.envrc
@@ -0,0 +1,38 @@
+# Run any command in this library's bin/ without the bin/ prefix!
+PATH_add bin
+
+# Only add things to this file that should be shared with the team.
+
+# **dotenv** (See end of file for .env.local integration)
+# .env would override anything in this file, if enabled.
+# .env is a DOCKER standard, and if we use it, it would be in deployed, or DOCKER, environments.
+# Override and customize anything below in your own .env.local
+# If you are using dotenv and not direnv,
+# copy the following `export` statements to your own .env file.
+
+### General Ruby ###
+# Turn off Ruby Warnings about deprecated code
+# export RUBYOPT="-W0"
+
+### External Testing Controls
+export K_SOUP_COV_DO=true # Means you want code coverage
+# Available formats are html, xml, rcov, lcov, json, tty
+export K_SOUP_COV_COMMAND_NAME="RSpec Coverage"
+export K_SOUP_COV_FORMATTERS="html,tty"
+export K_SOUP_COV_MIN_BRANCH=99 # Means you want to enforce X% branch coverage
+export K_SOUP_COV_MIN_LINE=100 # Means you want to enforce X% line coverage
+export K_SOUP_COV_MIN_HARD=true # Means you want the build to fail if the coverage thresholds are not met
+export K_SOUP_COV_MULTI_FORMATTERS=true
+export K_SOUP_COV_OPEN_BIN= # Means don't try to open coverage results in browser
+export MAX_ROWS=1 # Setting for simplecov-console gem for tty output, limits to the worst N rows of bad coverage
+
+# Internal Debugging Controls
+export DEBUG=false # do not allow byebug statements (override in .env.local)
+
+# .env would override anything in this file, if `dotenv` is uncommented below.
+# .env is a DOCKER standard, and if we use it, it would be in deployed, or DOCKER, environments,
+# and that is why we generally want to leave it commented out.
+# dotenv
+
+# .env.local will override anything in this file.
+dotenv_if_exists .env.local
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index f6d2e5aa..e6c57875 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -9,5 +9,5 @@ liberapay: pboling # Replace with a single Liberapay username
open_collective: # Replace with a single Open Collective username
patreon: galtzo # Replace with a single Patreon username
polar: pboling
-thanks_dev: gh/pboling
+thanks_dev: u/gh/pboling
tidelift: rubygems/oauth2 # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 89c4a1c3..dc043b45 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -8,3 +8,7 @@ updates:
open-pull-requests-limit: 10
ignore:
- dependency-name: "rubocop-lts"
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "daily"
diff --git a/.github/workflows/heads.yml b/.github/workflows/heads.yml
index 9bd8f0ae..3292009a 100644
--- a/.github/workflows/heads.yml
+++ b/.github/workflows/heads.yml
@@ -36,9 +36,9 @@ jobs:
- f1
- f2
rubygems:
- - latest
+ - default
bundler:
- - latest
+ - default
ruby:
- truffleruby+graalvm-head
- truffleruby-head
diff --git a/.github/workflows/jruby-head.yml b/.github/workflows/jruby-head.yml
index 8c3960d4..9c0498d9 100644
--- a/.github/workflows/jruby-head.yml
+++ b/.github/workflows/jruby-head.yml
@@ -37,9 +37,9 @@ jobs:
- f1
- f2
rubygems:
- - latest
+ - default
bundler:
- - latest
+ - default
ruby:
- jruby-head
include:
diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml
index d27761a7..edb198fd 100644
--- a/.github/workflows/style.yml
+++ b/.github/workflows/style.yml
@@ -26,7 +26,7 @@ jobs:
bundler:
- latest
ruby:
- - "2.7"
+ - ruby
runs-on: ubuntu-latest
steps:
- name: Checkout
diff --git a/.gitignore b/.gitignore
index 38ac0429..aa5a7c14 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,3 +37,6 @@
# Version Managers
.ruby-version
.tool-versions
+
+# Local config
+.env.local
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 20aa732c..de040959 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,6 +1,19 @@
default:
image: ruby:3.2
+variables:
+ BUNDLE_INSTALL_FLAGS: "--quiet --jobs=$(nproc) --retry=3"
+ BUNDLE_FROZEN: "false" # No lockfile!
+ K_SOUP_COV_DEBUG: true
+ K_SOUP_COV_DO: true
+ K_SOUP_COV_HARD: true
+ K_SOUP_COV_MIN_BRANCH: 98
+ K_SOUP_COV_MIN_LINE: 98
+ K_SOUP_COV_VERBOSE: true
+ K_SOUP_COV_FORMATTERS: "html,xml,rcov,lcov,json,tty"
+ K_SOUP_COV_MULTI_FORMATTERS: true
+ K_SOUP_COV_COMMAND_NAME: "RSpec Coverage"
+
workflow:
rules:
# For merge requests, create a pipeline.
@@ -16,8 +29,8 @@ workflow:
script:
- gem update --system > /dev/null 2>&1
- bundle config --local path vendor
- - bundle install --quiet --jobs 4 --retry 3
- - bundle exec rake test
+ - bundle install
+ - bundle exec rake
cache:
key: ${CI_JOB_IMAGE}
paths:
@@ -28,11 +41,11 @@ workflow:
stage: test
script:
# Because we support EOL Ruby still...
- - gem install rubygems-update -v 3.4.22 > /dev/null 2>&1
+ - gem install rubygems-update -v ${RUBYGEMS_VERSION}
# Actually updates both RubyGems and Bundler!
- - update_rubygems > /dev/null 2>&1
+ - update_rubygems
- bundle config --local path vendor
- - bundle install --quiet --jobs 4 --retry 3
+ - bundle install
- bundle exec rake test
cache:
key: ${CI_JOB_IMAGE}
@@ -40,12 +53,39 @@ workflow:
- vendor/ruby
ruby-current:
+ variables:
+ BUNDLE_GEMFILE: gemfiles/omnibus.gemfile
+ K_SOUP_COV_DO: true
<<: *test_definition-current
parallel:
matrix:
- - RUBY_VERSION: ["3.0", "3.1", "3.2"]
+ - RUBY_VERSION: ["3.2", "3.3", "3.4"]
+
+ruby-ruby3_1:
+ variables:
+ RUBYGEMS_VERSION: "3.6.9"
+ BUNDLE_GEMFILE: gemfiles/vanilla.gemfile
+ K_SOUP_COV_DO: false
+ <<: *test_definition-legacy
+ parallel:
+ matrix:
+ - RUBY_VERSION: ["3.1"]
+
+ruby-ruby3_0:
+ variables:
+ RUBYGEMS_VERSION: "3.5.23"
+ BUNDLE_GEMFILE: gemfiles/vanilla.gemfile
+ K_SOUP_COV_DO: false
+ <<: *test_definition-legacy
+ parallel:
+ matrix:
+ - RUBY_VERSION: ["3.0"]
-ruby-legacy:
+ruby-ruby2_7:
+ variables:
+ RUBYGEMS_VERSION: "3.4.22"
+ BUNDLE_GEMFILE: gemfiles/vanilla.gemfile
+ K_SOUP_COV_DO: false
<<: *test_definition-legacy
parallel:
matrix:
diff --git a/.rspec b/.rspec
index 2db90875..6c6110e5 100644
--- a/.rspec
+++ b/.rspec
@@ -1,4 +1,4 @@
--format documentation
---require spec_helper
--color
+--require spec_helper
--order random
diff --git a/.rubocop.yml b/.rubocop.yml
index 879d964a..32a249f3 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -1,18 +1,8 @@
-inherit_from:
- - .rubocop_todo.yml
- - .rubocop_rspec.yml
-
inherit_gem:
rubocop-lts: rubocop-lts.yml
-require:
- # Try adding back once we reach rubocop-ruby2_3+
- # - 'rubocop-md'
- # Can be added once we reach rubocop-ruby2_3+
- # - 'rubocop-packaging'
- - 'rubocop-performance'
- - 'rubocop-rake'
- - 'rubocop-rspec'
+inherit_from:
+ - .rubocop_rspec.yml
AllCops:
DisplayCopNames: true # Display the name of the failing cops
@@ -22,15 +12,7 @@ AllCops:
- '**/.irbrc'
Metrics/BlockLength:
- ExcludedMethods:
- - context
- - describe
- - it
- - shared_context
- - shared_examples
- - shared_examples_for
- - namespace
- - draw
+ Enabled: false
Gemspec/RequiredRubyVersion:
Enabled: false
@@ -38,7 +20,7 @@ Gemspec/RequiredRubyVersion:
Metrics/BlockNesting:
Max: 2
-Metrics/LineLength:
+Layout/LineLength:
Enabled: false
Metrics/ParameterLists:
@@ -60,12 +42,6 @@ Lint/UnusedBlockArgument:
- 'vendor/**/*'
- '**/.irbrc'
-RSpec/DescribeClass:
- Exclude:
- - 'spec/examples/*'
-
-RSpec/NestedGroups:
- Enabled: false
Style/ClassVars:
Enabled: false
diff --git a/.rubocop_gradual.lock b/.rubocop_gradual.lock
new file mode 100644
index 00000000..469a85d4
--- /dev/null
+++ b/.rubocop_gradual.lock
@@ -0,0 +1,180 @@
+{
+ "README.md:620392337": [
+ [305, 3, 1, "Layout/ClosingParenthesisIndentation: Indent `)` to column 0 (not 2)", 177548]
+ ],
+ "bin/bundle:3976421676": [
+ [66, 5, 20, "ThreadSafety/ClassInstanceVariable: Avoid class instance variables.", 2485198147],
+ [78, 5, 74, "Style/InvertibleUnlessCondition: Prefer `if Gem.rubygems_version >= Gem::Version.new(\"2.7.0\")` over `unless Gem.rubygems_version < Gem::Version.new(\"2.7.0\")`.", 2453573257]
+ ],
+ "lib/oauth2.rb:3930909031": [
+ [31, 5, 21, "ThreadSafety/ClassAndModuleAttributes: Avoid mutating class and module attributes.", 622027168],
+ [34, 11, 7, "ThreadSafety/ClassInstanceVariable: Avoid class instance variables.", 651502127]
+ ],
+ "lib/oauth2/authenticator.rb:3711266135": [
+ [42, 5, 113, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 734523108]
+ ],
+ "lib/oauth2/filtered_attributes.rb:1202323815": [
+ [3, 5, 63, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 2901108034],
+ [9, 9, 25, "ThreadSafety/ClassInstanceVariable: Avoid class instance variables.", 2012823020],
+ [13, 9, 25, "ThreadSafety/ClassInstanceVariable: Avoid class instance variables.", 2012823020]
+ ],
+ "lib/oauth2/response.rb:877496664": [
+ [35, 5, 204, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 996912427]
+ ],
+ "oauth2.gemspec:1672982387": [
+ [5, 6, 12, "Gemspec/RubyVersionGlobalsUsage: Do not use `RUBY_VERSION` in gemspec file.", 31296028],
+ [117, 3, 54, "Gemspec/DependencyVersion: Dependency version specification is required.", 3677216839],
+ [118, 3, 47, "Gemspec/DependencyVersion: Dependency version specification is required.", 2440116108],
+ [120, 3, 46, "Gemspec/DependencyVersion: Dependency version specification is required.", 1075698341],
+ [130, 3, 58, "Gemspec/DependencyVersion: Dependency version specification is required.", 2795510341],
+ [131, 3, 52, "Gemspec/DependencyVersion: Dependency version specification is required.", 804182931],
+ [132, 3, 52, "Gemspec/DependencyVersion: Dependency version specification is required.", 3163430777],
+ [134, 3, 48, "Gemspec/DependencyVersion: Dependency version specification is required.", 425065368]
+ ],
+ "spec/examples/google_spec.rb:1491180421": [
+ [9, 3, 5115, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 1014001606],
+ [97, 5, 1016, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 3156315524],
+ [121, 5, 783, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 1916865261]
+ ],
+ "spec/oauth2/access_token_spec.rb:1576666213": [
+ [3, 1, 34, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/access_token*_spec.rb`.", 1972107547],
+ [25, 3, 1935, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 1152039306],
+ [42, 5, 915, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 1914441490],
+ [56, 7, 507, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 3775341637],
+ [81, 5, 564, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 935902373],
+ [145, 7, 371, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 81675473],
+ [156, 7, 269, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 2703574041],
+ [166, 7, 343, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 571450510],
+ [177, 7, 1671, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 2358061917],
+ [185, 9, 218, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 2937949503],
+ [193, 9, 1213, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 3948450440],
+ [201, 11, 416, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 3896472588],
+ [206, 13, 238, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 669428729],
+ [215, 11, 250, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 962614116],
+ [223, 11, 249, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 1923581233],
+ [471, 5, 968, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 908014549],
+ [500, 5, 1224, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [9/5]", 2179768666],
+ [590, 13, 25, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 770233088],
+ [641, 3, 3135, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [8/5]", 2805647353],
+ [660, 9, 101, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 3022740639],
+ [664, 9, 79, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 2507338967],
+ [672, 5, 472, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [9/5]", 1289485551],
+ [702, 5, 346, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [8/5]", 2554883613],
+ [712, 5, 398, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [8/5]", 2789987624],
+ [723, 5, 413, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [8/5]", 1645012911],
+ [734, 5, 263, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [8/5]", 4224752268],
+ [753, 3, 385, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 293530329]
+ ],
+ "spec/oauth2/authenticator_spec.rb:853320290": [
+ [3, 1, 36, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/authenticator*_spec.rb`.", 819808017],
+ [51, 15, 20, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 482779785],
+ [60, 15, 33, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 297534737],
+ [69, 15, 38, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 1480816240],
+ [79, 13, 23, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 2314399065]
+ ],
+ "spec/oauth2/client_spec.rb:4220405778": [
+ [6, 1, 29, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/client*_spec.rb`.", 439549885],
+ [174, 7, 492, "RSpec/NoExpectationExample: No expectation found in this example.", 1272021224],
+ [193, 7, 592, "RSpec/NoExpectationExample: No expectation found in this example.", 3428877205],
+ [206, 15, 20, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 2320605227],
+ [221, 15, 20, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 1276531672],
+ [236, 15, 43, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 1383956904],
+ [251, 15, 43, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 3376202107],
+ [472, 7, 241, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 1113144453],
+ [479, 7, 233, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 2616254065],
+ [585, 5, 360, "RSpec/NoExpectationExample: No expectation found in this example.", 536201463],
+ [594, 5, 461, "RSpec/NoExpectationExample: No expectation found in this example.", 3392600621],
+ [605, 5, 340, "RSpec/NoExpectationExample: No expectation found in this example.", 244592251],
+ [626, 5, 1711, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 821658737],
+ [638, 7, 564, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 3188010848],
+ [645, 9, 314, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [8/5]", 2323166106],
+ [650, 63, 2, "RSpec/BeEq: Prefer `be` over `eq`.", 5860785],
+ [655, 7, 745, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 2242274228],
+ [658, 9, 379, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 3157074309],
+ [668, 9, 266, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 165934392],
+ [679, 5, 2992, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 3212702825],
+ [695, 11, 99, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 3084776886],
+ [699, 11, 82, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 1524553529],
+ [707, 7, 89, "RSpec/NoExpectationExample: No expectation found in this example.", 4609419],
+ [711, 7, 812, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 3531056573],
+ [719, 9, 505, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 2126944993],
+ [735, 7, 571, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 2450549440],
+ [738, 9, 209, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 1769133328],
+ [746, 9, 262, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [8/5]", 165934392],
+ [756, 7, 275, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 4192619324],
+ [764, 7, 377, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 1634937780],
+ [779, 5, 1920, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 3715188517],
+ [795, 11, 99, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 3084776886],
+ [799, 11, 82, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 1524553529],
+ [807, 7, 298, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 2420524519],
+ [816, 7, 474, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 2129407861],
+ [828, 7, 357, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [6/5]", 1696484657],
+ [879, 17, 12, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 664794325],
+ [904, 5, 459, "RSpec/NoExpectationExample: No expectation found in this example.", 2216851076],
+ [914, 7, 450, "RSpec/NoExpectationExample: No expectation found in this example.", 2619808549]
+ ],
+ "spec/oauth2/error_spec.rb:1209122273": [
+ [23, 1, 28, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/error*_spec.rb`.", 3385870076],
+ [93, 11, 534, "RSpec/NoExpectationExample: No expectation found in this example.", 3347340910],
+ [109, 11, 210, "RSpec/NoExpectationExample: No expectation found in this example.", 3948582233],
+ [241, 11, 534, "RSpec/NoExpectationExample: No expectation found in this example.", 3347340910],
+ [257, 11, 210, "RSpec/NoExpectationExample: No expectation found in this example.", 3948582233],
+ [315, 11, 534, "RSpec/NoExpectationExample: No expectation found in this example.", 3347340910],
+ [376, 11, 534, "RSpec/NoExpectationExample: No expectation found in this example.", 3347340910],
+ [392, 11, 210, "RSpec/NoExpectationExample: No expectation found in this example.", 3948582233]
+ ],
+ "spec/oauth2/response_spec.rb:3742350944": [
+ [3, 1, 31, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/response*_spec.rb`.", 3190869319],
+ [317, 33, 2, "RSpec/BeEq: Prefer `be` over `eq`.", 5860785]
+ ],
+ "spec/oauth2/strategy/assertion_spec.rb:1649395638": [
+ [6, 1, 42, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/strategy/assertion*_spec.rb`.", 3665690869],
+ [39, 3, 8028, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 3790653154],
+ [59, 5, 3399, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [10/5]", 1213098407],
+ [68, 7, 475, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [10/5]", 3673049530],
+ [83, 7, 511, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [10/5]", 1482428850],
+ [94, 9, 174, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [10/5]", 509043384],
+ [101, 7, 626, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [10/5]", 1073364157],
+ [112, 9, 276, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [12/5]", 3402508104],
+ [121, 7, 1463, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [11/5]", 631415582],
+ [124, 9, 431, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [11/5]", 1333000403],
+ [134, 9, 268, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [11/5]", 4208916299],
+ [142, 9, 312, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [11/5]", 4006695562],
+ [152, 9, 300, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [11/5]", 504386954],
+ [164, 5, 2485, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 3985973933],
+ [165, 7, 1368, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 975431363],
+ [190, 7, 1057, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 2712213015],
+ [212, 5, 1639, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [9/5]", 325089515],
+ [217, 9, 1383, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [9/5]", 2493875547],
+ [246, 11, 260, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [9/5]", 3397767518],
+ [254, 11, 223, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [9/5]", 242220550]
+ ],
+ "spec/oauth2/strategy/auth_code_spec.rb:142083698": [
+ [4, 1, 41, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/strategy/auth_code*_spec.rb`.", 1553708922],
+ [4, 1, 5753, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 833437399],
+ [48, 3, 919, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 3083983110],
+ [75, 3, 522, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 1383502446],
+ [94, 3, 672, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 3159970527],
+ [119, 3, 372, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 3139680688],
+ [131, 7, 986, "RSpec/MultipleMemoizedHelpers: Example group has too many memoized helpers [7/5]", 2685471594]
+ ],
+ "spec/oauth2/strategy/base_spec.rb:2524881749": [
+ [3, 1, 37, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/strategy/base*_spec.rb`.", 1951594922]
+ ],
+ "spec/oauth2/strategy/client_credentials_spec.rb:2609739899": [
+ [3, 1, 50, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/strategy/client_credentials*_spec.rb`.", 690311422]
+ ],
+ "spec/oauth2/strategy/implicit_spec.rb:1595799281": [
+ [3, 1, 41, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/strategy/implicit*_spec.rb`.", 3731171632]
+ ],
+ "spec/oauth2/strategy/password_spec.rb:331601826": [
+ [3, 1, 41, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/strategy/password*_spec.rb`.", 3463323840]
+ ],
+ "spec/oauth2/version_spec.rb:2895330438": [
+ [3, 1, 30, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/version*_spec.rb`.", 1099517182]
+ ],
+ "spec/oauth2_spec.rb:1511642301": [
+ [3, 1, 21, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2*_spec.rb`.", 3359091140],
+ [5, 68, 2, "RSpec/BeEq: Prefer `be` over `eq`.", 5860785]
+ ]
+}
diff --git a/.rubocop_rspec.yml b/.rubocop_rspec.yml
index 347777dc..461083ca 100644
--- a/.rubocop_rspec.yml
+++ b/.rubocop_rspec.yml
@@ -1,6 +1,3 @@
-RSpec/FilePath:
- Enabled: false
-
RSpec/MultipleExpectations:
Enabled: false
@@ -24,3 +21,8 @@ RSpec/NestedGroups:
RSpec/ExpectInHook:
Enabled: false
+
+RSpec/DescribeClass:
+ Exclude:
+ - 'spec/examples/*'
+
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
deleted file mode 100644
index ef809e2c..00000000
--- a/.rubocop_todo.yml
+++ /dev/null
@@ -1,46 +0,0 @@
-# This configuration was generated by
-# `rubocop --auto-gen-config`
-# on 2022-09-01 09:04:26 +0700 using RuboCop version 0.68.1.
-# The point is for the user to remove these configuration records
-# one by one as the offenses are removed from the code base.
-# Note that changes in the inspected code, or installation of new
-# versions of RuboCop, may require this file to be generated again.
-
-# Offense count: 9
-Metrics/AbcSize:
- Max: 35
-
-# Offense count: 6
-# Configuration parameters: CountComments, ExcludedMethods.
-# ExcludedMethods: refine
-Metrics/BlockLength:
- Max: 35
-
-# Offense count: 4
-Metrics/CyclomaticComplexity:
- Max: 12
-
-# Offense count: 11
-# Configuration parameters: CountComments, ExcludedMethods.
-Metrics/MethodLength:
- Max: 28
-
-# Offense count: 3
-Metrics/PerceivedComplexity:
- Max: 13
-
-# Offense count: 10
-# Configuration parameters: Prefixes.
-# Prefixes: when, with, without
-RSpec/ContextWording:
- Exclude:
- - 'spec/oauth2/access_token_spec.rb'
- - 'spec/oauth2/authenticator_spec.rb'
- - 'spec/oauth2/client_spec.rb'
-
-# Offense count: 1
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: inline, group
-Style/AccessModifierDeclarations:
- Exclude:
- - 'lib/oauth2.rb'
diff --git a/.simplecov b/.simplecov
index 423aa578..bfe90c08 100644
--- a/.simplecov
+++ b/.simplecov
@@ -1,32 +1,3 @@
-# frozen_string_literal: true
+require "kettle/soup/cover/config"
-# To get coverage
-# On Local, default (HTML) output, it just works, coverage is turned on:
-# bundle exec rspec spec
-# On Local, all output formats:
-# COVER_ALL=true bundle exec rspec spec
-#
-# On CI, all output formats, the ENV variables CI is always set,
-# and COVER_ALL, and CI_CODECOV, are set in the coverage.yml workflow only,
-# so coverage only runs in that workflow, and outputs all formats.
-#
-
-if RUN_COVERAGE
- SimpleCov.start do
- enable_coverage :branch
- primary_coverage :branch
- add_filter 'spec'
- add_filter 'lib/oauth2/version.rb'
- track_files '**/*.rb'
-
- if ALL_FORMATTERS
- command_name "#{ENV['GITHUB_WORKFLOW']} Job #{ENV['GITHUB_RUN_ID']}:#{ENV['GITHUB_RUN_NUMBER']}"
- else
- formatter SimpleCov::Formatter::HTMLFormatter
- end
-
- minimum_coverage(line: 100, branch: 100)
- end
-else
- puts "Not running coverage on #{RUBY_ENGINE} #{RUBY_VERSION}"
-end
+SimpleCov.start
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 265d6adc..cf322133 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2.
## [2.0.10] - 2025-05-12 ([tag][2.0.10t])
### Added
-- [#635](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/635) - `.gitlab-ci.yml` file (@jessieay)
+[!635](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/635) - `.gitlab-ci.yml` file (@jessieay)
- 20 year certificate for signing gem releases, expires 2045-04-29 (@pboling)
- Gemspec metadata (@pboling)
- funding_uri
@@ -21,13 +21,14 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2.
- SHA256 and SHA512 Checksums for release (@pboling)
### Changed
- Gem releases are now cryptographically signed, with a 20-year cert (@pboling)
+ - Allow linux distros to build release without signing, as their package managers sign independently
### Fixed
-- [#633](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/633) - Spaces will now be encoded as `%20` instead of `+` (@nov.matake)
-- [#634](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/634) - `CHANGELOG.md` documentation fix (@skuwa229)
-- [#638](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/638) - fix `expired?` when `expires_in` is `0` (@disep)
-- [#639](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/639) - Only instantiate `OAuth2::Error` if `raise_errors` option is `true` (@glytch2)
-- [#640](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/640) - `README.md` documentation fix (@martinezcoder)
-- [#641](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/641) - Do not include sensitive information in the `inspect` (@manuelvanrijn)
+[!633](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/633) - Spaces will now be encoded as `%20` instead of `+` (@nov.matake)
+[!634](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/634) - `CHANGELOG.md` documentation fix (@skuwa229)
+[!638](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/638) - fix `expired?` when `expires_in` is `0` (@disep)
+[!639](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/639) - Only instantiate `OAuth2::Error` if `raise_errors` option is `true` (@glytch2)
+[!640](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/640) - `README.md` documentation fix (@martinezcoder)
+[!641](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/641) - Do not include sensitive information in the `inspect` (@manuelvanrijn)
## [2.0.9] - 2022-09-16 ([tag][2.0.9t])
### Added
@@ -44,20 +45,20 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2.
## [2.0.7] - 2022-08-22 ([tag][2.0.7t])
### Added
-- [#629](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/629) - Allow POST of JSON to get token (@pboling, @terracatta)
+[!629](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/629) - Allow POST of JSON to get token (@pboling, @terracatta)
### Fixed
-- [#626](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/626) - Fixes a regression in 2.0.6. Will now prefer the key order from the lookup, not the hash keys (@rickselby)
+[!626](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/626) - Fixes a regression in 2.0.6. Will now prefer the key order from the lookup, not the hash keys (@rickselby)
- Note: This fixes compatibility with `omniauth-oauth2` and AWS
-- [#625](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/625) - Fixes the printed version in the post install message (@hasghari)
+[!625](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/625) - Fixes the printed version in the post install message (@hasghari)
## [2.0.6] - 2022-07-13 ([tag][2.0.6t])
### Fixed
-- [#624](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/624) - Fixes a [regression](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/623) in v2.0.5, where an error would be raised in refresh_token flows due to (legitimate) lack of access_token (@pboling)
+[!624](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/624) - Fixes a [regression](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/623) in v2.0.5, where an error would be raised in refresh_token flows due to (legitimate) lack of access_token (@pboling)
## [2.0.5] - 2022-07-07 ([tag][2.0.5t])
### Fixed
-- [#620](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/620) - Documentation improvements, to help with upgrading (@swanson)
-- [#621](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/621) - Fixed [#528](https://gitlab.com/oauth-xx/oauth2/-/issues/528) and [#619](https://gitlab.com/oauth-xx/oauth2/-/issues/619) (@pboling)
+[!620](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/620) - Documentation improvements, to help with upgrading (@swanson)
+[!621](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/621) - Fixed [#528](https://gitlab.com/oauth-xx/oauth2/-/issues/528) and [#619](https://gitlab.com/oauth-xx/oauth2/-/issues/619) (@pboling)
- All data in responses is now returned, with the access token removed and set as `token`
- `refresh_token` is no longer dropped
- **BREAKING**: Microsoft's `id_token` is no longer left as `access_token['id_token']`, but moved to the standard `access_token.token` that all other strategies use
@@ -66,21 +67,21 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2.
## [2.0.4] - 2022-07-01 ([tag][2.0.4t])
### Fixed
-- [#618](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/618) - In some scenarios the `snaky` option default value was not applied (@pboling)
+[!618](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/618) - In some scenarios the `snaky` option default value was not applied (@pboling)
## [2.0.3] - 2022-06-28 ([tag][2.0.3t])
### Added
-- [#611](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/611) - Proper deprecation warnings for `extract_access_token` argument (@pboling)
-- [#612](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/612) - Add `snaky: false` option to skip conversion to `OAuth2::SnakyHash` (default: true) (@pboling)
+[!611](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/611) - Proper deprecation warnings for `extract_access_token` argument (@pboling)
+[!612](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/612) - Add `snaky: false` option to skip conversion to `OAuth2::SnakyHash` (default: true) (@pboling)
### Fixed
-- [#608](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/608) - Wrap `Faraday::TimeoutError` in `OAuth2::TimeoutError` (@nbibler)
-- [#615](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/615) - Fix support for requests with blocks, see `Faraday::Connection#run_request` (@pboling)
+[!608](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/608) - Wrap `Faraday::TimeoutError` in `OAuth2::TimeoutError` (@nbibler)
+[!615](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/615) - Fix support for requests with blocks, see `Faraday::Connection#run_request` (@pboling)
## [2.0.2] - 2022-06-24 ([tag][2.0.2t])
### Fixed
-- [#604](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/604) - Wrap `Faraday::TimeoutError` in `OAuth2::TimeoutError` (@stanhu)
-- [#606](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/606) - Ruby 2.7 deprecation warning fix: Move `access_token_class` parameter into `Client` constructor (@stanhu)
-- [#607](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/607) - CHANGELOG correction, reference to `OAuth2::ConnectionError` (@zavan)
+[!604](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/604) - Wrap `Faraday::TimeoutError` in `OAuth2::TimeoutError` (@stanhu)
+[!606](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/606) - Ruby 2.7 deprecation warning fix: Move `access_token_class` parameter into `Client` constructor (@stanhu)
+[!607](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/607) - CHANGELOG correction, reference to `OAuth2::ConnectionError` (@zavan)
## [2.0.1] - 2022-06-22 ([tag][2.0.1t])
### Added
@@ -89,81 +90,81 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2.
## [2.0.0] - 2022-06-21 ([tag][2.0.0t])
### Added
-- [#158](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/158), [#344](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/344) - Optionally pass raw response to parsers (@niels)
-- [#190](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/190), [#332](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/332), [#334](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/334), [#335](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/335), [#360](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/360), [#426](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/426), [#427](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/427), [#461](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/461) - Documentation (@josephpage, @pboling, @meganemura, @joshRpowell, @elliotcm)
-- [#220](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/220) - Support IETF rfc7523 JWT Bearer Tokens Draft 04+ (@jhmoore)
-- [#298](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/298) - Set the response object on the access token on Client#get_token for debugging (@cpetschnig)
-- [#305](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/305) - Option: `OAuth2::Client#get_token` - `:access_token_class` (`AccessToken`); user specified class to use for all calls to `get_token` (@styd)
-- [#346](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/571) - Modern gem structure (@pboling)
-- [#351](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/351) - Support Jruby 9k (@pboling)
-- [#362](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/362) - Support SemVer release version scheme (@pboling)
-- [#363](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/363) - New method `OAuth2::AccessToken#refresh!` same as old `refresh`, with backwards compatibility alias (@pboling)
-- [#364](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/364) - Support `application/hal+json` format (@pboling)
-- [#365](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/365) - Support `application/vnd.collection+json` format (@pboling)
-- [#376](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/376) - _Documentation_: Example / Test for Google 2-legged JWT (@jhmoore)
-- [#381](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/381) - Spec for extra header params on client credentials (@nikz)
-- [#394](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/394) - Option: `OAuth2::AccessToken#initialize` - `:expires_latency` (`nil`); number of seconds by which AccessToken validity will be reduced to offset latency (@klippx)
-- [#412](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/412) - Support `application/vdn.api+json` format (from jsonapi.org) (@david-christensen)
-- [#413](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/413) - _Documentation_: License scan and report (@meganemura)
-- [#442](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/442) - Option: `OAuth2::Client#initialize` - `:logger` (`::Logger.new($stdout)`) logger to use when OAUTH_DEBUG is enabled (for parity with `1-4-stable` branch) (@rthbound)
-- [#494](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/494) - Support [OIDC 1.0 Private Key JWT](https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication); based on the OAuth JWT assertion specification [(RFC 7523)](https://tools.ietf.org/html/rfc7523) (@SteveyblamWork)
-- [#549](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/549) - Wrap `Faraday::ConnectionFailed` in `OAuth2::ConnectionError` (@nikkypx)
-- [#550](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/550) - Raise error if location header not present when redirecting (@stanhu)
-- [#552](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/552) - Add missing `version.rb` require (@ahorek)
-- [#553](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/553) - Support `application/problem+json` format (@janz93)
-- [#560](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/560) - Support IETF rfc6749, section 2.3.1 - don't set auth params when `nil` (@bouk)
-- [#571](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/571) - Support Ruby 3.1 (@pboling)
-- [#575](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/575) - Support IETF rfc7231, section 7.1.2 - relative location in redirect (@pboling)
-- [#581](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/581) - _Documentation_: of breaking changes (@pboling)
+[!158](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/158), [!344](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/344) - Optionally pass raw response to parsers (@niels)
+[!190](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/190), [!332](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/332), [!334](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/334), [!335](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/335), [!360](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/360), [!426](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/426), [!427](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/427), [!461](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/461) - Documentation (@josephpage, @pboling, @meganemura, @joshRpowell, @elliotcm)
+[!220](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/220) - Support IETF rfc7523 JWT Bearer Tokens Draft 04+ (@jhmoore)
+[!298](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/298) - Set the response object on the access token on Client#get_token for debugging (@cpetschnig)
+[!305](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/305) - Option: `OAuth2::Client#get_token` - `:access_token_class` (`AccessToken`); user specified class to use for all calls to `get_token` (@styd)
+[!346](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/571) - Modern gem structure (@pboling)
+[!351](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/351) - Support Jruby 9k (@pboling)
+[!362](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/362) - Support SemVer release version scheme (@pboling)
+[!363](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/363) - New method `OAuth2::AccessToken#refresh!` same as old `refresh`, with backwards compatibility alias (@pboling)
+[!364](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/364) - Support `application/hal+json` format (@pboling)
+[!365](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/365) - Support `application/vnd.collection+json` format (@pboling)
+[!376](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/376) - _Documentation_: Example / Test for Google 2-legged JWT (@jhmoore)
+[!381](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/381) - Spec for extra header params on client credentials (@nikz)
+[!394](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/394) - Option: `OAuth2::AccessToken#initialize` - `:expires_latency` (`nil`); number of seconds by which AccessToken validity will be reduced to offset latency (@klippx)
+[!412](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/412) - Support `application/vdn.api+json` format (from jsonapi.org) (@david-christensen)
+[!413](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/413) - _Documentation_: License scan and report (@meganemura)
+[!442](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/442) - Option: `OAuth2::Client#initialize` - `:logger` (`::Logger.new($stdout)`) logger to use when OAUTH_DEBUG is enabled (for parity with `1-4-stable` branch) (@rthbound)
+[!494](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/494) - Support [OIDC 1.0 Private Key JWT](https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication); based on the OAuth JWT assertion specification [(RFC 7523)](https://tools.ietf.org/html/rfc7523) (@SteveyblamWork)
+[!549](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/549) - Wrap `Faraday::ConnectionFailed` in `OAuth2::ConnectionError` (@nikkypx)
+[!550](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/550) - Raise error if location header not present when redirecting (@stanhu)
+[!552](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/552) - Add missing `version.rb` require (@ahorek)
+[!553](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/553) - Support `application/problem+json` format (@janz93)
+[!560](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/560) - Support IETF rfc6749, section 2.3.1 - don't set auth params when `nil` (@bouk)
+[!571](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/571) - Support Ruby 3.1 (@pboling)
+[!575](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/575) - Support IETF rfc7231, section 7.1.2 - relative location in redirect (@pboling)
+[!581](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/581) - _Documentation_: of breaking changes (@pboling)
### Changed
-- [#191](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/191) - **BREAKING**: Token is expired if `expired_at` time is `now` (@davestevens)
-- [#312](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/312) - **BREAKING**: Set `:basic_auth` as default for `:auth_scheme` instead of `:request_body`. This was default behavior before 1.3.0. (@tetsuya, @wy193777)
-- [#317](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/317) - _Dependency_: Upgrade `jwt` to 2.x.x (@travisofthenorth)
-- [#338](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/338) - _Dependency_: Switch from `Rack::Utils.escape` to `CGI.escape` (@josephpage)
-- [#339](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/339), [#368](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/368), [#424](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/424), [#479](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/479), [#493](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/493), [#539](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/539), [#542](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/542), [#553](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/553) - CI Updates, code coverage, linting, spelling, type fixes, New VERSION constant (@pboling, @josephpage, @ahorek)
-- [#410](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/410) - **BREAKING**: Removed the ability to call .error from an OAuth2::Response object (@jhmoore)
-- [#414](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/414) - Use Base64.strict_encode64 instead of custom internal logic (@meganemura)
-- [#469](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/469) - **BREAKING**: Default value for option `OAuth2::Client` - `:authorize_url` removed leading slash to work with relative paths by default (`'oauth/authorize'`) (@ghost)
-- [#469](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/469) - **BREAKING**: Default value for option `OAuth2::Client` - `:token_url` removed leading slash to work with relative paths by default (`'oauth/token'`) (@ghost)
-- [#507](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/507), [#575](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/575) - **BREAKING**: Transform keys to snake case, always, by default (ultimately via `rash_alt` gem)
+[!191](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/191) - **BREAKING**: Token is expired if `expired_at` time is `now` (@davestevens)
+[!312](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/312) - **BREAKING**: Set `:basic_auth` as default for `:auth_scheme` instead of `:request_body`. This was default behavior before 1.3.0. (@tetsuya, @wy193777)
+[!317](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/317) - _Dependency_: Upgrade `jwt` to 2.x.x (@travisofthenorth)
+[!338](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/338) - _Dependency_: Switch from `Rack::Utils.escape` to `CGI.escape` (@josephpage)
+[!339](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/339), [!368](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/368), [!424](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/424), [!479](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/479), [!493](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/493), [!539](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/539), [!542](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/542), [!553](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/553) - CI Updates, code coverage, linting, spelling, type fixes, New VERSION constant (@pboling, @josephpage, @ahorek)
+[!410](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/410) - **BREAKING**: Removed the ability to call .error from an OAuth2::Response object (@jhmoore)
+[!414](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/414) - Use Base64.strict_encode64 instead of custom internal logic (@meganemura)
+[!469](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/469) - **BREAKING**: Default value for option `OAuth2::Client` - `:authorize_url` removed leading slash to work with relative paths by default (`'oauth/authorize'`) (@ghost)
+[!469](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/469) - **BREAKING**: Default value for option `OAuth2::Client` - `:token_url` removed leading slash to work with relative paths by default (`'oauth/token'`) (@ghost)
+[!507](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/507), [!575](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/575) - **BREAKING**: Transform keys to snake case, always, by default (ultimately via `rash_alt` gem)
- Original keys will still work as previously, in most scenarios, thanks to `rash_alt` gem.
- However, this is a _breaking_ change if you rely on `response.parsed.to_h`, as the keys in the result will be snake case.
- As of version 2.0.4 you can turn key transformation off with the `snaky: false` option.
-- [#576](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/576) - **BREAKING**: Stop rescuing parsing errors (@pboling)
-- [#591](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/576) - _DEPRECATION_: `OAuth2::Client` - `:extract_access_token` option is deprecated
+[!576](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/576) - **BREAKING**: Stop rescuing parsing errors (@pboling)
+[!591](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/576) - _DEPRECATION_: `OAuth2::Client` - `:extract_access_token` option is deprecated
### Fixed
-- [#158](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/158), [#344](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/344) - Handling of errors when using `omniauth-facebook` (@niels)
-- [#294](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/294) - Fix: "Unexpected middleware set" issue with Faraday when `OAUTH_DEBUG=true` (@spectator, @gafrom)
-- [#300](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/300) - _Documentation_: `Oauth2::Error` - Error codes are strings, not symbols (@NobodysNightmare)
-- [#318](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/318), [#326](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/326), [#343](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/343), [#347](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/347), [#397](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/397), [#464](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/464), [#561](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/561), [#565](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/565) - _Dependency_: Support all versions of `faraday` (see [gemfiles/README.md][gemfiles/readme] for compatibility matrix with Ruby engines & versions) (@pboling, @raimondasv, @zacharywelch, @Fudoshiki, @ryogift, @sj26, @jdelStrother)
-- [#322](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/322), [#331](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/331), [#337](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/337), [#361](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/361), [#371](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/371), [#377](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/377), [#383](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/383), [#392](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/392), [#395](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/395), [#400](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/400), [#401](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/401), [#403](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/403), [#415](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/415), [#567](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/567) - Updated Rubocop, Rubocop plugins and improved code style (@pboling, @bquorning, @lautis, @spectator)
-- [#328](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/328) - _Documentation_: Homepage URL is SSL (@amatsuda)
-- [#339](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/339), [#479](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/479) - Update testing infrastructure for all supported Rubies (@pboling and @josephpage)
-- [#366](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/366) - **Security**: Fix logging to `$stdout` of request and response bodies via Faraday's logger and `ENV["OAUTH_DEBUG"] == 'true'` (@pboling)
-- [#380](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/380) - Fix: Stop attempting to encode non-encodable objects in `Oauth2::Error` (@jhmoore)
-- [#399](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/399) - Fix: Stop duplicating `redirect_uri` in `get_token` (@markus)
-- [#410](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/410) - Fix: `SystemStackError` caused by circular reference between Error and Response classes (@jhmoore)
-- [#460](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/460) - Fix: Stop throwing errors when `raise_errors` is set to `false`; analog of [#524](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/524) for `1-4-stable` branch (@joaolrpaulo)
-- [#472](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/472) - **Security**: Add checks to enforce `client_secret` is *never* passed in authorize_url query params for `implicit` and `auth_code` grant types (@dfockler)
-- [#482](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/482) - _Documentation_: Update last of `intridea` links to `oauth-xx` (@pboling)
-- [#536](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/536) - **Security**: Compatibility with more (and recent) Ruby OpenSSL versions, Github Actions, Rubocop updated, analogous to [#535](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/535) on `1-4-stable` branch (@pboling)
-- [#595](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/595) - Graceful handling of empty responses from `Client#get_token`, respecting `:raise_errors` config (@stanhu)
-- [#596](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/596) - Consistency between `AccessToken#refresh` and `Client#get_token` named arguments (@stanhu)
-- [#598](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/598) - Fix unparseable data not raised as error in `Client#get_token`, respecting `:raise_errors` config (@stanhu)
+[!158](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/158), [!344](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/344) - Handling of errors when using `omniauth-facebook` (@niels)
+[!294](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/294) - Fix: "Unexpected middleware set" issue with Faraday when `OAUTH_DEBUG=true` (@spectator, @gafrom)
+[!300](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/300) - _Documentation_: `Oauth2::Error` - Error codes are strings, not symbols (@NobodysNightmare)
+[!318](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/318), [!326](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/326), [!343](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/343), [!347](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/347), [!397](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/397), [!464](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/464), [!561](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/561), [!565](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/565) - _Dependency_: Support all versions of `faraday` (see [gemfiles/README.md][gemfiles/readme] for compatibility matrix with Ruby engines & versions) (@pboling, @raimondasv, @zacharywelch, @Fudoshiki, @ryogift, @sj26, @jdelStrother)
+[!322](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/322), [!331](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/331), [!337](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/337), [!361](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/361), [!371](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/371), [!377](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/377), [!383](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/383), [!392](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/392), [!395](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/395), [!400](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/400), [!401](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/401), [!403](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/403), [!415](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/415), [!567](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/567) - Updated Rubocop, Rubocop plugins and improved code style (@pboling, @bquorning, @lautis, @spectator)
+[!328](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/328) - _Documentation_: Homepage URL is SSL (@amatsuda)
+[!339](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/339), [!479](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/479) - Update testing infrastructure for all supported Rubies (@pboling and @josephpage)
+[!366](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/366) - **Security**: Fix logging to `$stdout` of request and response bodies via Faraday's logger and `ENV["OAUTH_DEBUG"] == 'true'` (@pboling)
+[!380](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/380) - Fix: Stop attempting to encode non-encodable objects in `Oauth2::Error` (@jhmoore)
+[!399](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/399) - Fix: Stop duplicating `redirect_uri` in `get_token` (@markus)
+[!410](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/410) - Fix: `SystemStackError` caused by circular reference between Error and Response classes (@jhmoore)
+[!460](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/460) - Fix: Stop throwing errors when `raise_errors` is set to `false`; analog of [!524](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/524) for `1-4-stable` branch (@joaolrpaulo)
+[!472](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/472) - **Security**: Add checks to enforce `client_secret` is *never* passed in authorize_url query params for `implicit` and `auth_code` grant types (@dfockler)
+[!482](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/482) - _Documentation_: Update last of `intridea` links to `oauth-xx` (@pboling)
+[!536](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/536) - **Security**: Compatibility with more (and recent) Ruby OpenSSL versions, Github Actions, Rubocop updated, analogous to [!535](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/535) on `1-4-stable` branch (@pboling)
+[!595](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/595) - Graceful handling of empty responses from `Client#get_token`, respecting `:raise_errors` config (@stanhu)
+[!596](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/596) - Consistency between `AccessToken#refresh` and `Client#get_token` named arguments (@stanhu)
+[!598](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/598) - Fix unparseable data not raised as error in `Client#get_token`, respecting `:raise_errors` config (@stanhu)
### Removed
-- [#341](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/341) - Remove Rdoc & Jeweler related files (@josephpage)
-- [#342](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/342) - **BREAKING**: Dropped support for Ruby 1.8 (@josephpage)
-- [#539](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/539) - Remove reliance on globally included OAuth2 in tests, analog of [#538](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/538) for 1-4-stable (@anderscarling)
-- [#566](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/566) - _Dependency_: Removed `wwtd` (@bquorning)
-- [#589](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/589), [#593](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/593) - Remove support for expired MAC token draft spec (@stanhu)
-- [#590](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/590) - _Dependency_: Removed `multi_json` (@stanhu)
+[!341](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/341) - Remove Rdoc & Jeweler related files (@josephpage)
+[!342](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/342) - **BREAKING**: Dropped support for Ruby 1.8 (@josephpage)
+[!539](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/539) - Remove reliance on globally included OAuth2 in tests, analog of [!538](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/538) for 1-4-stable (@anderscarling)
+[!566](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/566) - _Dependency_: Removed `wwtd` (@bquorning)
+[!589](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/589), [!593](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/593) - Remove support for expired MAC token draft spec (@stanhu)
+[!590](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/590) - _Dependency_: Removed `multi_json` (@stanhu)
## [1.4.11] - 2022-09-16 ([tag][1.4.11t])
- Complete migration to main branch as default (@pboling)
- Complete migration to Gitlab, updating all links, and references in VCS-managed files (@pboling)
## [1.4.10] - 2022-07-01 ([tag][1.4.10t])
-- FIPS Compatibility [#587](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/587) (@akostadinov)
+- FIPS Compatibility [!587](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/587) (@akostadinov)
## [1.4.9] - 2022-02-20 ([tag][1.4.9t])
- Fixes compatibility with Faraday v2 [572](https://gitlab.com/oauth-xx/oauth2/-/issues/572)
@@ -176,47 +177,47 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2.
## [1.4.8] - 2022-02-18 ([tag][1.4.8t])
- MFA is now required to push new gem versions (@pboling)
- README overhaul w/ new Ruby Version and Engine compatibility policies (@pboling)
-- [#569](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/569) Backport fixes ([#561](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/561) by @ryogift), and add more fixes, to allow faraday 1.x and 2.x (@jrochkind)
+[!569](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/569) Backport fixes ([!561](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/561) by @ryogift), and add more fixes, to allow faraday 1.x and 2.x (@jrochkind)
- Improve Code Coverage tracking (Coveralls, CodeCov, CodeClimate), and enable branch coverage (@pboling)
- Add CodeQL, Security Policy, Funding info (@pboling)
- Added Ruby 3.1, jruby, jruby-head, truffleruby, truffleruby-head to build matrix (@pboling)
-- [#543](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/543) - Support for more modern Open SSL libraries (@pboling)
+[!543](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/543) - Support for more modern Open SSL libraries (@pboling)
## [1.4.7] - 2021-03-19 ([tag][1.4.7t])
-- [#541](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/541) - Backport fix to expires_at handling [#533](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/533) to 1-4-stable branch. (@dobon)
+[!541](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/541) - Backport fix to expires_at handling [!533](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/533) to 1-4-stable branch. (@dobon)
## [1.4.6] - 2021-03-19 ([tag][1.4.6t])
-- [#540](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/540) - Add VERSION constant (@pboling)
-- [#537](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/537) - Fix crash in OAuth2::Client#get_token (@anderscarling)
-- [#538](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/538) - Remove reliance on globally included OAuth2 in tests, analogous to [#539](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/539) on main branch (@anderscarling)
+[!540](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/540) - Add VERSION constant (@pboling)
+[!537](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/537) - Fix crash in OAuth2::Client#get_token (@anderscarling)
+[!538](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/538) - Remove reliance on globally included OAuth2 in tests, analogous to [!539](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/539) on main branch (@anderscarling)
## [1.4.5] - 2021-03-18 ([tag][1.4.5t])
-- [#535](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/535) - Compatibility with range of supported Ruby OpenSSL versions, Rubocop updates, Github Actions, analogous to [#536](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/536) on main branch (@pboling)
-- [#518](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/518) - Add extract_access_token option to OAuth2::Client (@jonspalmer)
-- [#507](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/507) - Fix camel case content type, response keys (@anvox)
-- [#500](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/500) - Fix YARD documentation formatting (@olleolleolle)
+[!535](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/535) - Compatibility with range of supported Ruby OpenSSL versions, Rubocop updates, Github Actions, analogous to [!536](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/536) on main branch (@pboling)
+[!518](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/518) - Add extract_access_token option to OAuth2::Client (@jonspalmer)
+[!507](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/507) - Fix camel case content type, response keys (@anvox)
+[!500](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/500) - Fix YARD documentation formatting (@olleolleolle)
## [1.4.4] - 2020-02-12 ([tag][1.4.4t])
-- [#408](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/408) - Fixed expires_at for formatted time (@Lomey)
+[!408](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/408) - Fixed expires_at for formatted time (@Lomey)
## [1.4.3] - 2020-01-29 ([tag][1.4.3t])
-- [#483](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/483) - add project metadata to gemspec (@orien)
-- [#495](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/495) - support additional types of access token requests (@SteveyblamFreeagent, @thomcorley, @dgholz)
+[!483](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/483) - add project metadata to gemspec (@orien)
+[!495](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/495) - support additional types of access token requests (@SteveyblamFreeagent, @thomcorley, @dgholz)
- Adds support for private_key_jwt and tls_client_auth
-- [#433](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/433) - allow field names with square brackets and numbers in params (@asm256)
+[!433](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/433) - allow field names with square brackets and numbers in params (@asm256)
## [1.4.2] - 2019-10-01 ([tag][1.4.2t])
-- [#478](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/478) - support latest version of faraday & fix build (@pboling)
+[!478](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/478) - support latest version of faraday & fix build (@pboling)
- Officially support Ruby 2.6 and truffleruby
## [1.4.1] - 2018-10-13 ([tag][1.4.1t])
-- [#417](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/417) - update jwt dependency (@thewoolleyman)
-- [#419](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/419) - remove rubocop dependency (temporary, added back in [#423](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/423)) (@pboling)
-- [#418](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/418) - update faraday dependency (@pboling)
-- [#420](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/420) - update [oauth2.gemspec](https://gitlab.com/oauth-xx/oauth2/-/blob/1-4-stable/oauth2.gemspec) (@pboling)
-- [#421](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/421) - fix [CHANGELOG.md](https://gitlab.com/oauth-xx/oauth2/-/blob/1-4-stable/CHANGELOG.md) for previous releases (@pboling)
-- [#422](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/422) - update [LICENSE](https://gitlab.com/oauth-xx/oauth2/-/blob/1-4-stable/LICENSE) and [README.md](https://gitlab.com/oauth-xx/oauth2/-/blob/1-4-stable/README.md) (@pboling)
-- [#423](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/423) - update [builds](https://travis-ci.org/oauth-xx/oauth2/builds), [Rakefile](https://gitlab.com/oauth-xx/oauth2/-/blob/1-4-stable/Rakefile) (@pboling)
+[!417](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/417) - update jwt dependency (@thewoolleyman)
+[!419](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/419) - remove rubocop dependency (temporary, added back in [!423](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/423)) (@pboling)
+[!418](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/418) - update faraday dependency (@pboling)
+[!420](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/420) - update [oauth2.gemspec](https://gitlab.com/oauth-xx/oauth2/-/blob/1-4-stable/oauth2.gemspec) (@pboling)
+[!421](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/421) - fix [CHANGELOG.md](https://gitlab.com/oauth-xx/oauth2/-/blob/1-4-stable/CHANGELOG.md) for previous releases (@pboling)
+[!422](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/422) - update [LICENSE](https://gitlab.com/oauth-xx/oauth2/-/blob/1-4-stable/LICENSE) and [README.md](https://gitlab.com/oauth-xx/oauth2/-/blob/1-4-stable/README.md) (@pboling)
+[!423](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/423) - update [builds](https://travis-ci.org/oauth-xx/oauth2/builds), [Rakefile](https://gitlab.com/oauth-xx/oauth2/-/blob/1-4-stable/Rakefile) (@pboling)
- officially document supported Rubies
* Ruby 1.9.3
* Ruby 2.0.0
@@ -308,7 +309,7 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2.
## [0.0.5] - 2010-04-23 ([tag][0.0.5t])
## [0.0.4] - 2010-04-22 ([tag][0.0.4t])
-
+
## [0.0.3] - 2010-04-22 ([tag][0.0.3t])
## [0.0.2] - 2010-04-22 ([tag][0.0.2t])
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 1b81c846..b4401666 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,38 +2,138 @@
Bug reports and pull requests are welcome on GitLab at [https://gitlab.com/oauth-xx/oauth2][🚎src-main]
. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to
-the [code of conduct][conduct].
-
-To submit a patch, please fork the project and create a patch with
-tests. Once you're happy with it send a pull request and post a message to the
-[google group][mailinglist] or on the [gitter chat][🏘chat].
-
-## Detailed instructions on Submitting a Pull Request
-1. [Fork the repository.][fork]
-2. [Create a topic branch.][branch]
-3. Add specs for your unimplemented feature or bug fix.
-4. Run `bundle exec rake spec`. If your specs pass, return to step 3.
-5. Implement your feature or bug fix.
-6. Run `bundle exec rake`. If your specs fail, return to step 5.
-7. Run `open coverage/index.html`. If your changes are not completely covered
- by your tests, return to step 3.
-8. Add documentation for your feature or bug fix.
-9. Run `bundle exec rake verify_measurements`. If your changes are not 100%
- documented, go back to step 8.
-10. Commit and push your changes.
-11. [Submit a pull request.][pr]
-
-[fork]: http://help.github.com/fork-a-repo/
-[branch]: http://learn.github.com/p/branching.html
-[pr]: http://help.github.com/send-pull-requests/
+the [code of conduct][🤝conduct].
+
+To submit a patch, please fork the project and create a patch with tests.
+Once you're happy with it send a pull request.
+
+We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
+
+## You can help!
+
+Take a look at the `reek` list which is the file called `REEK` and find something to improve.
+
+Simply follow these instructions:
+
+1. Fork the repository
+2. Create your feature branch (`git checkout -b my-new-feature`)
+3. Make some fixes.
+4. Commit your changes (`git commit -am 'Added some feature'`)
+5. Push to the branch (`git push origin my-new-feature`)
+6. Make sure to add tests for it. This is important, so it doesn't break in a future release.
+7. Create new Pull Request.
+
+## Appraisals
+
+From time to time the appraisal gemfiles in `gemfiles/` will need to be updated.
+They are created and updated with the commands:
+
+NOTE: We run on a [fork][🚎appraisal-fork] of Appraisal.
+
+Please upvote the PR for `eval_gemfile` [support][🚎appraisal-eval-gemfile-pr]
+
+```shell
+BUNDLE_GEMFILE=Appraisal.root.gemfile bundle
+BUNDLE_GEMFILE=Appraisal.root.gemfile bundle exec appraisal update
+bundle exec rake rubocop_gradual:autocorrect
+```
+
+When adding an appraisal to CI check the [runner tool cache][🏃♂️runner-tool-cache] to see which runner to use.
+
+## The Reek List
+
+Take a look at the `reek` list which is the file called `REEK` and find something to improve.
+
+To refresh the `reek` list:
+
+```bash
+bundle exec reek > REEK
+```
+
+## Run Tests
+
+To run all tests
+
+```bash
+bundle exec rake test
+```
+
+## Lint It
+
+Run all the default tasks, which includes running the gradually autocorrecting linter, `rubocop-gradual`.
+
+```bash
+bundle exec rake
+```
+
+Or just run the linter.
+
+```bash
+bundle exec rake rubocop_gradual:autocorrect
+```
## Contributors
-See: [https://gitlab.com/oauth-xx/oauth2/-/graphs/main][🚎contributors]
+Your picture could be here!
+
+[![Contributors][🖐contributors-img]][🖐contributors]
+
+Made with [contributors-img][🖐contrib-rocks].
+
+Also see GitLab Contributors: [https://gitlab.com/oauth-xx/oauth2/-/graphs/main][🚎contributors-gl]
+
+## For Maintainers
+
+### One-time, Per-maintainer, Setup
+
+**IMPORTANT**: If you want to sign the build you create,
+your public key for signing gems will need to be picked up by the line in the
+`gemspec` defining the `spec.cert_chain` (check the relevant ENV variables there).
+All releases to RubyGems.org will be signed.
+See: [RubyGems Security Guide][🔒️rubygems-security-guide]
+
+NOTE: To build without signing the gem you must set `SKIP_GEM_SIGNING` to some value in your environment.
+
+### To release a new version:
+
+1. Run `bin/setup && bin/rake` as a tests, coverage, & linting sanity check
+2. Update the version number in `version.rb`, and ensure `CHANGELOG.md` reflects changes
+3. Run `bin/setup && bin/rake` again as a secondary check, and to update `Gemfile.lock`
+4. Run `git commit -am "🔖 Prepare release v"` to commit the changes
+5. Run `git push` to trigger the final CI pipeline before release, & merge PRs
+ - NOTE: Remember to [check the build][🧪build]!
+6. Run `export GIT_TRUNK_BRANCH_NAME="$(git remote show origin | grep 'HEAD branch' | cut -d ' ' -f5)" && echo $GIT_TRUNK_BRANCH_NAME`
+7. Run `git checkout $GIT_TRUNK_BRANCH_NAME`
+8. Run `git pull origin $GIT_TRUNK_BRANCH_NAME` to ensure you will release the latest trunk code
+9. Set `SOURCE_DATE_EPOCH` so `rake build` and `rake release` use same timestamp, and generate same checksums
+ - Run `export SOURCE_DATE_EPOCH=$EPOCHSECONDS && echo $SOURCE_DATE_EPOCH`
+ - If the echo above has no output, then it didn't work.
+ - Note that you'll need the `zsh/datetime` module, if running `zsh`.
+ - In older versions of `bash` you can use `date +%s` instead, i.e. `export SOURCE_DATE_EPOCH=$(date +%s) && echo $SOURCE_DATE_EPOCH`
+10. Run `bundle exec rake build`
+11. Run `bin/gem_checksums` (more context [1][🔒️rubygems-checksums-pr], [2][🔒️rubygems-guides-pr])
+ to create SHA-256 and SHA-512 checksums. This functionality is provided by the `stone_checksums`
+ [gem][💎stone_checksums].
+ - Checksums will be committed automatically by the script, but not pushed
+12. Run `bundle exec rake release` which will create a git tag for the version,
+ push git commits and tags, and push the `.gem` file to [rubygems.org][💎rubygems]
-[comment]: <> (Following links are used by README, CONTRIBUTING, Homepage)
-[conduct]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CODE_OF_CONDUCT.md
-[🚎contributors]: https://gitlab.com/oauth-xx/oauth2/-/graphs/main
-[mailinglist]: http://groups.google.com/group/oauth-ruby
-[🚎src-main]: https://gitlab.com/oauth-xx/oauth2/-/tree/main
-[🏘chat]: https://gitter.im/oauth-xx/oauth2
\ No newline at end of file
+[🚎src-main]: https://gitlab.com/oauth-xx/oauth2
+[🧪build]: https://github.com/oauth-xx/oauth2/actions
+[🤝conduct]: https://gitlab.com/oauth-xx/oauth2/-/blob/main/CODE_OF_CONDUCT.md
+[🖐contrib-rocks]: https://contrib.rocks
+[🖐contributors]: https://github.com/oauth-xx/oauth2/graphs/contributors
+[🚎contributors-gl]: https://gitlab.com/oauth-xx/oauth2/-/graphs/main
+[🖐contributors-img]: https://contrib.rocks/image?repo=oauth-xx/oauth2
+[💎rubygems]: https://rubygems.org
+[🔒️rubygems-security-guide]: https://guides.rubygems.org/security/#building-gems
+[🔒️rubygems-checksums-pr]: https://github.com/rubygems/rubygems/pull/6022
+[🔒️rubygems-guides-pr]: https://github.com/rubygems/guides/pull/325
+[💎stone_checksums]: https://github.com/pboling/stone_checksums
+[📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
+[📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-FFDD67.svg?style=flat
+[📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139
+[📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
+[🚎appraisal-eval-gemfile-pr]: https://github.com/thoughtbot/appraisal/pull/248
+[🚎appraisal-fork]: https://github.com/pboling/appraisal/tree/galtzo
+[🏃♂️runner-tool-cache]: https://github.com/ruby/ruby-builder/releases/tag/toolcache
diff --git a/Dangerfile b/Dangerfile
index 2f8600bb..a01a246d 100644
--- a/Dangerfile
+++ b/Dangerfile
@@ -5,11 +5,11 @@
# e.g. github.pr_title.include? "#trivial"
# Make it more obvious that a PR is a work in progress and shouldn't be merged yet
-warn('PR is classed as Work in Progress') if github.pr_title.include? '[WIP]'
+warn("PR is classed as Work in Progress") if github.pr_title.include?("[WIP]")
# Warn when there is a big PR
-warn('Big PR') if git.lines_of_code > 500
+warn("Big PR") if git.lines_of_code > 500
# Don't let testing shortcuts get into main by accident
-raise('fdescribe left in tests') if `grep -r fdescribe specs/ `.length > 1
-raise('fit left in tests') if `grep -r fit specs/ `.length > 1
+raise("fdescribe left in tests") if %x(grep -r fdescribe specs/).length > 1
+raise("fit left in tests") if %x(grep -r fit specs/).length > 1
diff --git a/Gemfile b/Gemfile
index 96cff377..b031a325 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,58 +1,31 @@
# frozen_string_literal: true
-source 'https://rubygems.org'
-
-gemspec
+source "https://rubygems.org"
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
git_source(:gitlab) { |repo_name| "https://gitlab.com/#{repo_name}" }
-gem 'rake', '~> 13.0'
-
-gem 'rspec', '~> 3.0'
-
-ruby_version = Gem::Version.new(RUBY_VERSION)
-minimum_version = ->(version, engine = 'ruby') { ruby_version >= Gem::Version.new(version) && RUBY_ENGINE == engine }
-linting = minimum_version.call('2.7')
-coverage = minimum_version.call('2.7')
-debug = minimum_version.call('2.5')
-
-gem 'overcommit', '~> 0.58' if linting
-
-platforms :mri do
- if linting
- # Danger is incompatible with Faraday 2 (for now)
- # see: https://github.com/danger/danger/issues/1349
- # gem 'danger', '~> 8.4'
- # Commented out rubocop-md because of the <--rubocop/md--> bug
- # gem 'rubocop-md', require: false
- # Can be added once we reach rubocop-lts >= v10 (i.e. drop Ruby 2.2)
- # gem 'rubocop-packaging', require: false
- gem 'rubocop-performance', require: false
- gem 'rubocop-rake', require: false
- gem 'rubocop-rspec', require: false
- gem 'rubocop-thread_safety', require: false
- end
- if coverage
- gem 'codecov', '~> 0.6' # For CodeCov
- gem 'simplecov', '~> 0.21', require: false
- gem 'simplecov-cobertura' # XML for Jenkins
- gem 'simplecov-json' # For CodeClimate
- gem 'simplecov-lcov', '~> 0.8', require: false
- end
- if debug
- # Add `byebug` to your code where you want to drop to REPL
- gem 'byebug'
- end
-end
-platforms :jruby do
- # Add `binding.pry` to your code where you want to drop to REPL
- gem 'pry-debugger-jruby'
-end
+#### IMPORTANT #######################################################
+# Gemfile is for local development ONLY; Gemfile is NOT loaded in CI #
+####################################################### IMPORTANT ####
+
+# Include dependencies from .gemspec
+gemspec
-### deps for documentation and rdoc.info
-group :documentation do
- gem 'github-markup', platform: :mri
- gem 'redcarpet', platform: :mri
- gem 'yard', require: false
+platform :mri do
+ # Use binding.break, binding.b, or debugger in code
+ gem "debug", ">= 1.0.0" # ruby >= 2.7
+ gem "gem_bench", "~> 2.0", ">= 2.0.5"
end
+
+# Security Audit
+eval_gemfile "gemfiles/modular/audit.gemfile"
+
+# Code Coverage
+eval_gemfile "gemfiles/modular/coverage.gemfile"
+
+# Linting
+eval_gemfile "gemfiles/modular/style.gemfile"
+
+# Documentation
+eval_gemfile "gemfiles/modular/documentation.gemfile"
diff --git a/Gemfile.lock b/Gemfile.lock
index 14452141..6ca4debd 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,3 +1,15 @@
+GIT
+ remote: https://github.com/pboling/yard-junk
+ revision: 54ccebabbfa9a9cd44d0b991687ebbfd22c32b55
+ branch: next
+ specs:
+ yard-junk (0.0.10)
+ backports (>= 3.18)
+ benchmark
+ ostruct
+ rainbow
+ yard
+
PATH
remote: .
specs:
@@ -7,144 +19,280 @@ PATH
multi_xml (~> 0.5)
rack (>= 1.2, < 4)
snaky_hash (~> 2.0)
- version_gem (~> 1.1)
+ version_gem (>= 1.1.8, < 3)
GEM
remote: https://rubygems.org/
specs:
- addressable (2.8.1)
- public_suffix (>= 2.0.2, < 6.0)
- ast (2.4.2)
- backports (3.23.0)
- byebug (11.1.3)
- childprocess (4.1.0)
- codecov (0.6.0)
- simplecov (>= 0.15, < 0.22)
- diff-lcs (1.5.0)
- docile (1.4.0)
- faraday (2.5.2)
- faraday-net_http (>= 2.0, < 3.1)
- ruby2_keywords (>= 0.0.4)
- faraday-net_http (3.0.0)
- github-markup (4.0.1)
+ addressable (2.8.7)
+ public_suffix (>= 2.0.2, < 7.0)
+ ansi (1.5.0)
+ ast (2.4.3)
+ backports (3.25.1)
+ base64 (0.2.0)
+ benchmark (0.4.0)
+ bigdecimal (3.1.9)
+ bundler-audit (0.9.2)
+ bundler (>= 1.2.0, < 3)
+ thor (~> 1.0)
+ concurrent-ruby (1.3.5)
+ date (3.4.1)
+ debug (1.10.0)
+ irb (~> 1.10)
+ reline (>= 0.3.8)
+ diff-lcs (1.6.2)
+ diffy (3.4.3)
+ docile (1.4.1)
+ dry-configurable (1.3.0)
+ dry-core (~> 1.1)
+ zeitwerk (~> 2.6)
+ dry-core (1.1.0)
+ concurrent-ruby (~> 1.0)
+ logger
+ zeitwerk (~> 2.6)
+ dry-inflector (1.2.0)
+ dry-initializer (3.2.0)
+ dry-logic (1.6.0)
+ bigdecimal
+ concurrent-ruby (~> 1.0)
+ dry-core (~> 1.1)
+ zeitwerk (~> 2.6)
+ dry-schema (1.14.1)
+ concurrent-ruby (~> 1.0)
+ dry-configurable (~> 1.0, >= 1.0.1)
+ dry-core (~> 1.1)
+ dry-initializer (~> 3.2)
+ dry-logic (~> 1.5)
+ dry-types (~> 1.8)
+ zeitwerk (~> 2.6)
+ dry-types (1.8.2)
+ bigdecimal (~> 3.0)
+ concurrent-ruby (~> 1.0)
+ dry-core (~> 1.0)
+ dry-inflector (~> 1.0)
+ dry-logic (~> 1.4)
+ zeitwerk (~> 2.6)
+ faraday (2.13.1)
+ faraday-net_http (>= 2.0, < 3.5)
+ json
+ logger
+ faraday-net_http (3.4.0)
+ net-http (>= 0.5.0)
+ gem_bench (2.0.5)
+ bundler (>= 1.14)
+ version_gem (~> 1.1, >= 1.1.4)
hashie (5.0.0)
- iniparse (1.5.0)
- jaro_winkler (1.5.4)
- json (2.6.2)
- jwt (2.5.0)
- multi_xml (0.6.0)
- overcommit (0.59.1)
- childprocess (>= 0.6.3, < 5)
- iniparse (~> 1.4)
- rexml (~> 3.2)
- parallel (1.22.1)
- parser (3.1.2.1)
+ io-console (0.8.0)
+ irb (1.15.2)
+ pp (>= 0.6.0)
+ rdoc (>= 4.0.0)
+ reline (>= 0.4.2)
+ json (2.12.0)
+ jwt (2.10.1)
+ base64
+ kettle-soup-cover (1.0.6)
+ simplecov (~> 0.22)
+ simplecov-cobertura (~> 2.1)
+ simplecov-console (~> 0.9, >= 0.9.1)
+ simplecov-html (~> 0.12)
+ simplecov-lcov (~> 0.8)
+ simplecov-rcov (~> 0.3, >= 0.3.3)
+ simplecov_json_formatter (~> 0.1, >= 0.1.4)
+ version_gem (~> 1.1, >= 1.1.7)
+ language_server-protocol (3.17.0.5)
+ lint_roller (1.1.0)
+ logger (1.7.0)
+ multi_xml (0.7.2)
+ bigdecimal (~> 3.1)
+ net-http (0.6.0)
+ uri
+ nkf (0.2.0)
+ ostruct (0.6.1)
+ parallel (1.27.0)
+ parser (3.3.8.0)
ast (~> 2.4.1)
- public_suffix (5.0.0)
- rack (3.0.0)
- rainbow (2.2.2)
- rake
- rake (13.0.6)
- redcarpet (3.5.1)
- rexml (3.2.5)
- rspec (3.11.0)
- rspec-core (~> 3.11.0)
- rspec-expectations (~> 3.11.0)
- rspec-mocks (~> 3.11.0)
- rspec-block_is_expected (1.0.2)
- rspec-core
- rspec-core (3.11.0)
- rspec-support (~> 3.11.0)
- rspec-expectations (3.11.1)
+ racc
+ pp (0.6.2)
+ prettyprint
+ prettyprint (0.2.0)
+ prism (1.4.0)
+ psych (5.2.6)
+ date
+ stringio
+ public_suffix (6.0.2)
+ racc (1.8.1)
+ rack (3.1.14)
+ rainbow (3.1.1)
+ rake (13.2.1)
+ rdoc (6.13.1)
+ psych (>= 4.0.0)
+ reek (6.5.0)
+ dry-schema (~> 1.13)
+ logger (~> 1.6)
+ parser (~> 3.3.0)
+ rainbow (>= 2.0, < 4.0)
+ rexml (~> 3.1)
+ regexp_parser (2.10.0)
+ reline (0.6.1)
+ io-console (~> 0.5)
+ rexml (3.4.1)
+ rspec (3.13.0)
+ rspec-core (~> 3.13.0)
+ rspec-expectations (~> 3.13.0)
+ rspec-mocks (~> 3.13.0)
+ rspec-block_is_expected (1.0.6)
+ rspec-core (3.13.3)
+ rspec-support (~> 3.13.0)
+ rspec-expectations (3.13.4)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.11.0)
- rspec-mocks (3.11.1)
+ rspec-support (~> 3.13.0)
+ rspec-mocks (3.13.4)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.11.0)
- rspec-pending_for (0.1.16)
- rspec-core
- ruby_engine (>= 1, < 3)
+ rspec-support (~> 3.13.0)
+ rspec-pending_for (0.1.17)
+ rake (>= 10)
+ rspec-core (~> 3.0)
+ ruby_engine (~> 2.0)
ruby_version (~> 1.0)
- rspec-stubbed_env (1.0.0)
- rspec (>= 3.0)
- rspec-support (3.11.1)
- rubocop (0.68.1)
- jaro_winkler (~> 1.5.1)
+ rspec-stubbed_env (1.0.2)
+ rspec-support (3.13.3)
+ rubocop (1.75.5)
+ json (~> 2.3)
+ language_server-protocol (~> 3.17.0.2)
+ lint_roller (~> 1.1.0)
parallel (~> 1.10)
- parser (>= 2.5, != 2.5.1.1)
+ parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
+ regexp_parser (>= 2.9.3, < 3.0)
+ rubocop-ast (>= 1.44.0, < 2.0)
ruby-progressbar (~> 1.7)
- unicode-display_width (>= 1.4.0, < 1.6)
- rubocop-lts (8.0.2)
- rubocop-ruby2_2 (~> 1.0.4)
- rubocop-performance (1.3.0)
- rubocop (>= 0.68.0)
- rubocop-rake (0.5.1)
- rubocop
- rubocop-rspec (1.41.0)
- rubocop (>= 0.68.1)
- rubocop-ruby2_2 (1.0.4)
- rubocop (= 0.68.1)
- rubocop-thread_safety (0.4.4)
- rubocop (>= 0.53.0)
- ruby-progressbar (1.11.0)
- ruby2_keywords (0.0.5)
- ruby_engine (2.0.0)
- ruby_version (1.0.2)
- silent_stream (1.0.6)
- simplecov (0.21.2)
+ unicode-display_width (>= 2.4.0, < 4.0)
+ rubocop-ast (1.44.1)
+ parser (>= 3.3.7.2)
+ prism (~> 1.4)
+ rubocop-gradual (0.3.6)
+ diff-lcs (>= 1.2.0, < 2.0)
+ diffy (~> 3.0)
+ parallel (~> 1.10)
+ rainbow (>= 2.2.2, < 4.0)
+ rubocop (~> 1.0)
+ rubocop-lts (8.1.1)
+ rubocop-ruby2_2 (>= 2.0.3, < 3)
+ standard-rubocop-lts (>= 1.0.3, < 3)
+ version_gem (>= 1.1.2, < 3)
+ rubocop-md (1.2.4)
+ rubocop (>= 1.45)
+ rubocop-packaging (0.6.0)
+ lint_roller (~> 1.1.0)
+ rubocop (>= 1.72.1, < 2.0)
+ rubocop-performance (1.25.0)
+ lint_roller (~> 1.1)
+ rubocop (>= 1.75.0, < 2.0)
+ rubocop-ast (>= 1.38.0, < 2.0)
+ rubocop-rake (0.7.1)
+ lint_roller (~> 1.1)
+ rubocop (>= 1.72.1)
+ rubocop-rspec (3.6.0)
+ lint_roller (~> 1.1)
+ rubocop (~> 1.72, >= 1.72.1)
+ rubocop-ruby2_2 (2.0.5)
+ rubocop-gradual (~> 0.3, >= 0.3.1)
+ rubocop-md (~> 1.2)
+ rubocop-rake (~> 0.6)
+ rubocop-shopify (~> 2.14)
+ rubocop-thread_safety (~> 0.5, >= 0.5.1)
+ standard-rubocop-lts (~> 1.0, >= 1.0.7)
+ version_gem (>= 1.1.3, < 3)
+ rubocop-shopify (2.17.0)
+ rubocop (~> 1.62)
+ rubocop-thread_safety (0.7.2)
+ lint_roller (~> 1.1)
+ rubocop (~> 1.72, >= 1.72.1)
+ ruby-progressbar (1.13.0)
+ ruby_engine (2.0.3)
+ ruby_version (1.0.3)
+ silent_stream (1.0.10)
+ logger (>= 1.4.4)
+ version_gem (~> 1.1, >= 1.1.7)
+ simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
simplecov_json_formatter (~> 0.1)
simplecov-cobertura (2.1.0)
rexml
simplecov (~> 0.19)
- simplecov-html (0.12.3)
- simplecov-json (0.2.3)
- json
+ simplecov-console (0.9.3)
+ ansi
simplecov
+ terminal-table
+ simplecov-html (0.13.1)
simplecov-lcov (0.8.0)
+ simplecov-rcov (0.3.7)
+ simplecov (>= 0.4.1)
simplecov_json_formatter (0.1.4)
snaky_hash (2.0.1)
hashie
version_gem (~> 1.1, >= 1.1.1)
- unicode-display_width (1.5.0)
- version_gem (1.1.1)
- webrick (1.7.0)
- yard (0.9.28)
- webrick (~> 1.7.0)
+ standard (1.50.0)
+ language_server-protocol (~> 3.17.0.2)
+ lint_roller (~> 1.0)
+ rubocop (~> 1.75.5)
+ standard-custom (~> 1.0.0)
+ standard-performance (~> 1.8)
+ standard-custom (1.0.2)
+ lint_roller (~> 1.0)
+ rubocop (~> 1.50)
+ standard-performance (1.8.0)
+ lint_roller (~> 1.1)
+ rubocop-performance (~> 1.25.0)
+ standard-rubocop-lts (1.0.10)
+ rspec-block_is_expected (~> 1.0, >= 1.0.5)
+ standard (>= 1.35.1, < 2)
+ standard-custom (>= 1.0.2, < 2)
+ standard-performance (>= 1.3.1, < 2)
+ version_gem (>= 1.1.4, < 3)
+ stringio (3.1.7)
+ terminal-table (4.0.0)
+ unicode-display_width (>= 1.1.1, < 4)
+ thor (1.3.2)
+ unicode-display_width (3.1.4)
+ unicode-emoji (~> 4.0, >= 4.0.4)
+ unicode-emoji (4.0.4)
+ uri (1.0.3)
+ version_gem (1.1.8)
+ yard (0.9.37)
+ zeitwerk (2.7.2)
PLATFORMS
x86_64-darwin-21
+ x86_64-linux
DEPENDENCIES
addressable (>= 2)
backports (>= 3)
- bundler (>= 2)
- byebug
- codecov (~> 0.6)
- github-markup
+ benchmark (~> 0.4)
+ bundler-audit (~> 0.9.2)
+ debug (>= 1.0.0)
+ gem_bench (~> 2.0, >= 2.0.5)
+ kettle-soup-cover (~> 1.0, >= 1.0.6)
+ nkf (~> 0.2)
oauth2!
- overcommit (~> 0.58)
- pry-debugger-jruby
- rake (~> 13.0)
- redcarpet
+ rake (>= 12)
+ rdoc (~> 6.11)
+ reek (~> 6.4)
rexml (>= 3)
- rspec (~> 3.0)
+ rspec (>= 3)
rspec-block_is_expected
rspec-pending_for
rspec-stubbed_env
+ rubocop (~> 1.73, >= 1.73.2)
rubocop-lts (~> 8.0)
- rubocop-performance
- rubocop-rake
- rubocop-rspec
- rubocop-thread_safety
+ rubocop-packaging (~> 0.5, >= 0.5.2)
+ rubocop-rspec (~> 3.2)
silent_stream
- simplecov (~> 0.21)
- simplecov-cobertura
- simplecov-json
- simplecov-lcov (~> 0.8)
- yard
+ standard (~> 1.47)
+ yard (~> 0.9, >= 0.9.37)
+ yard-junk (~> 0.0, >= 0.0.10)!
BUNDLED WITH
- 2.3.22
+ 2.6.8
diff --git a/README.md b/README.md
index 473cdc47..831cd55f 100644
--- a/README.md
+++ b/README.md
@@ -7,14 +7,43 @@
+ Copyright (c) 2011 - 2013 Michael Bleigh and Intridea, Inc.
+
+
+
+## 🤑 One more thing
+
+You made it to the bottom of the page,
+so perhaps you'll indulge me for another 20 seconds.
+I maintain many dozens of gems, including this one,
+because I want Ruby to be a great place for people to solve problems, big and small.
+Please consider supporting my efforts via the giant yellow link below,
+or one of the others at the head of this README.
+
+[![Buy me a latte][🖇buyme-img]][🖇buyme]
-Made with [contributors-img](https://contrib.rocks).
+[⛳gg-discussions]: https://groups.google.com/g/oauth-ruby
+[⛳gg-discussions-img]: https://img.shields.io/badge/google-group-purple.svg?style=flat
+
+[✇bundle-group-pattern]: https://gist.github.com/pboling/4564780
+[⛳️gem-namespace]: https://github.com/oauth-xx/oauth2
+[⛳️namespace-img]: https://img.shields.io/badge/namespace-OAuth2-brightgreen.svg?style=flat&logo=ruby&logoColor=white
+[⛳️gem-name]: https://rubygems.org/gems/oauth2
+[⛳️name-img]: https://img.shields.io/badge/name-oauth2-brightgreen.svg?style=flat&logo=rubygems&logoColor=red
+[🚂bdfl-blog]: http://www.railsbling.com/tags/oauth2
+[🚂bdfl-blog-img]: https://img.shields.io/badge/blog-railsbling-0093D0.svg?style=for-the-badge&logo=rubyonrails&logoColor=orange
+[🚂bdfl-contact]: http://www.railsbling.com/contact
+[🚂bdfl-contact-img]: https://img.shields.io/badge/Contact-BDFL-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red
+[💖🖇linkedin]: http://www.linkedin.com/in/peterboling
+[💖🖇linkedin-img]: https://img.shields.io/badge/PeterBoling-LinkedIn-0B66C2?style=flat&logo=newjapanprowrestling
+[💖✌️wellfound]: https://angel.co/u/peter-boling
+[💖✌️wellfound-img]: https://img.shields.io/badge/peter--boling-orange?style=flat&logo=wellfound
+[💖💲crunchbase]: https://www.crunchbase.com/person/peter-boling
+[💖💲crunchbase-img]: https://img.shields.io/badge/peter--boling-purple?style=flat&logo=crunchbase
+[💖🐘ruby-mast]: https://ruby.social/@galtzo
+[💖🐘ruby-mast-img]: https://img.shields.io/mastodon/follow/109447111526622197?domain=https%3A%2F%2Fruby.social&style=flat&logo=mastodon&label=Ruby%20%40galtzo
+[💖🦋bluesky]: https://bsky.app/profile/galtzo.com
+[💖🦋bluesky-img]: https://img.shields.io/badge/@galtzo.com-0285FF?style=flat&logo=bluesky&logoColor=white
+[💖🌳linktree]: https://linktr.ee/galtzo
+[💖🌳linktree-img]: https://img.shields.io/badge/galtzo-purple?style=flat&logo=linktree
+[💖💁🏼♂️devto]: https://dev.to/galtzo
+[💖💁🏼♂️devto-img]: https://img.shields.io/badge/dev.to-0A0A0A?style=flat&logo=devdotto&logoColor=white
+[💖💁🏼♂️aboutme]: https://about.me/peter.boling
+[💖💁🏼♂️aboutme-img]: https://img.shields.io/badge/about.me-0A0A0A?style=flat&logo=aboutme&logoColor=white
+[💖🧊berg]: https://codeberg.org/pboling
+[💖🐙hub]: https://github.org/pboling
+[💖🛖hut]: https://sr.ht/~galtzo/
+[💖🧪lab]: https://gitlab.com/pboling
+[👨🏼🏫expsup-upwork]: https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share
+[👨🏼🏫expsup-upwork-img]: https://img.shields.io/badge/UpWork-13544E?style=for-the-badge&logo=Upwork&logoColor=white
+[👨🏼🏫expsup-codementor]: https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github
+[👨🏼🏫expsup-codementor-img]: https://img.shields.io/badge/CodeMentor-Get_Help-1abc9c?style=for-the-badge&logo=CodeMentor&logoColor=white
+[🏙️entsup-tidelift]: https://tidelift.com/subscription
+[🏙️entsup-tidelift-img]: https://img.shields.io/badge/Tidelift_and_Sonar-Enterprise_Support-FD3456?style=for-the-badge&logo=sonar&logoColor=white
+[🏙️entsup-tidelift-sonar]: https://blog.tidelift.com/tidelift-joins-sonar
+[💁🏼♂️peterboling]: http://www.peterboling.com
+[🚂railsbling]: http://www.railsbling.com
+[📜src-gl-img]: https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge&logo=Gitlab&logoColor=orange
+[📜src-gl]: https://gitlab.com/oauth-xx/oauth2/
+[📜src-cb-img]: https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge&logo=CodeBerg&logoColor=blue
+[📜src-cb]: https://codeberg.org/oauth-xx/oauth2
+[📜src-gh-img]: https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=Github&logoColor=green
+[📜src-gh]: https://github.com/oauth-xx/oauth2
+[📜docs-cr-rd-img]: https://img.shields.io/badge/RubyDoc-Current_Release-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
+[📜docs-head-rd-img]: https://img.shields.io/badge/RubyDoc-HEAD-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white
+[📜wiki]: https://gitlab.com/oauth-xx/oauth2/-/wikis/home
+[📜wiki-img]: https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=Wiki&logoColor=white
+[👽dl-rank]: https://rubygems.org/gems/oauth2
+[👽dl-ranki]: https://img.shields.io/gem/rd/oauth2.svg
+[👽oss-help]: https://www.codetriage.com/oauth-xx/oauth2
+[👽oss-helpi]: https://www.codetriage.com/oauth-xx/oauth2/badges/users.svg
+[👽version]: https://rubygems.org/gems/oauth2
+[👽versioni]: https://img.shields.io/gem/v/oauth2.svg
+[🔑cc-mnt]: https://qlty.sh/gh/oauth-xx/projects/oauth2
+[🔑cc-mnti♻️]: https://qlty.sh/badges/d3370c2c-8791-4202-9759-76f527f76005/maintainability.svg
+[🔑cc-cov]: https://qlty.sh/gh/oauth-xx/projects/oauth2
+[🔑cc-covi♻️]: https://qlty.sh/badges/d3370c2c-8791-4202-9759-76f527f76005/test_coverage.svg
+[🔑codecov]: https://codecov.io/gh/oauth-xx/oauth2
+[🔑codecovi♻️]: https://codecov.io/gh/oauth-xx/oauth2/branch/main/graph/badge.svg?token=bNqSzNiuo2
+[🔑coveralls]: https://coveralls.io/github/oauth-xx/oauth2?branch=main
+[🔑coveralls-img]: https://coveralls.io/repos/github/oauth-xx/oauth2/badge.svg?branch=main
+[🔑depfu]: https://depfu.com/github/oauth-xx/oauth2?project_id=5884
+[🔑depfui♻️]: https://badges.depfu.com/badges/6d34dc1ba682bbdf9ae2a97848241743/count.svg
+[🖐codeQL]: https://github.com/oauth-xx/oauth2/security/code-scanning
+[🖐codeQL-img]: https://github.com/oauth-xx/oauth2/actions/workflows/codeql-analysis.yml/badge.svg
+[🚎1-an-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/ancient.yml
+[🚎1-an-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/ancient.yml/badge.svg
+[🚎2-cov-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/coverage.yml
+[🚎2-cov-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/coverage.yml/badge.svg
+[🚎3-hd-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/heads.yml
+[🚎3-hd-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/heads.yml/badge.svg
+[🚎4-lg-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/legacy.yml
+[🚎4-lg-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/legacy.yml/badge.svg
+[🚎5-st-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/style.yml
+[🚎5-st-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/style.yml/badge.svg
+[🚎6-s-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/supported.yml
+[🚎6-s-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/supported.yml/badge.svg
+[🚎7-us-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/unsupported.yml
+[🚎7-us-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/unsupported.yml/badge.svg
+[🚎8-ho-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/hoary.yml
+[🚎8-ho-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/hoary.yml/badge.svg
+[🚎9-t-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/truffle.yml
+[🚎9-t-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/truffle.yml/badge.svg
+[🚎10-j-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/jruby.yml
+[🚎10-j-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/jruby.yml/badge.svg
+[🚎11-c-wf]: https://github.com/oauth-xx/oauth2/actions/workflows/current.yml
+[🚎11-c-wfi]: https://github.com/oauth-xx/oauth2/actions/workflows/current.yml/badge.svg
+[⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay
+[⛳liberapay]: https://liberapay.com/pboling/donate
+[🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
+[🖇sponsor]: https://github.com/sponsors/pboling
+[🖇polar-img]: https://img.shields.io/badge/polar-donate-yellow.svg
+[🖇polar]: https://polar.sh/pboling
+[🖇kofi-img]: https://img.shields.io/badge/a_more_different_coffee-✓-yellow.svg
+[🖇kofi]: https://ko-fi.com/O5O86SNP4
+[🖇patreon-img]: https://img.shields.io/badge/patreon-donate-yellow.svg
+[🖇patreon]: https://patreon.com/galtzo
+[🖇buyme-img]: https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20latte&emoji=&slug=pboling&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff
+[🖇buyme]: https://www.buymeacoffee.com/pboling
+[🖇buyme-small-img]: https://img.shields.io/badge/buy_me_a_coffee-✓-yellow.svg?style=flat
+[💎ruby-2.3i]: https://img.shields.io/badge/Ruby-2.3-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
+[💎ruby-2.4i]: https://img.shields.io/badge/Ruby-2.4-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
+[💎ruby-2.5i]: https://img.shields.io/badge/Ruby-2.5-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
+[💎ruby-2.6i]: https://img.shields.io/badge/Ruby-2.6-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
+[💎ruby-2.7i]: https://img.shields.io/badge/Ruby-2.7-DF00CA?style=for-the-badge&logo=ruby&logoColor=white
+[💎ruby-3.0i]: https://img.shields.io/badge/Ruby-3.0-CC342D?style=for-the-badge&logo=ruby&logoColor=white
+[💎ruby-3.1i]: https://img.shields.io/badge/Ruby-3.1-CC342D?style=for-the-badge&logo=ruby&logoColor=white
+[💎ruby-3.2i]: https://img.shields.io/badge/Ruby-3.2-CC342D?style=for-the-badge&logo=ruby&logoColor=white
+[💎ruby-3.3i]: https://img.shields.io/badge/Ruby-3.3-CC342D?style=for-the-badge&logo=ruby&logoColor=white
+[💎ruby-c-i]: https://img.shields.io/badge/Ruby-current-CC342D?style=for-the-badge&logo=ruby&logoColor=green
+[💎ruby-headi]: https://img.shields.io/badge/Ruby-HEAD-CC342D?style=for-the-badge&logo=ruby&logoColor=blue
+[💎truby-22.3i]: https://img.shields.io/badge/Truffle_Ruby-22.3-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
+[💎truby-23.0i]: https://img.shields.io/badge/Truffle_Ruby-23.0-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
+[💎truby-23.1i]: https://img.shields.io/badge/Truffle_Ruby-23.1-34BCB1?style=for-the-badge&logo=ruby&logoColor=pink
+[💎truby-c-i]: https://img.shields.io/badge/Truffle_Ruby-current-34BCB1?style=for-the-badge&logo=ruby&logoColor=green
+[💎truby-headi]: https://img.shields.io/badge/Truffle_Ruby-HEAD-34BCB1?style=for-the-badge&logo=ruby&logoColor=blue
+[💎jruby-9.1i]: https://img.shields.io/badge/JRuby-9.1-FBE742?style=for-the-badge&logo=ruby&logoColor=red
+[💎jruby-9.2i]: https://img.shields.io/badge/JRuby-9.2-FBE742?style=for-the-badge&logo=ruby&logoColor=red
+[💎jruby-9.3i]: https://img.shields.io/badge/JRuby-9.3-FBE742?style=for-the-badge&logo=ruby&logoColor=red
+[💎jruby-9.4i]: https://img.shields.io/badge/JRuby-9.4-FBE742?style=for-the-badge&logo=ruby&logoColor=red
+[💎jruby-c-i]: https://img.shields.io/badge/JRuby-current-FBE742?style=for-the-badge&logo=ruby&logoColor=green
+[💎jruby-headi]: https://img.shields.io/badge/JRuby-HEAD-FBE742?style=for-the-badge&logo=ruby&logoColor=blue
+[🤝issues]: https://github.com/oauth-xx/oauth2/issues
+[🤝pulls]: https://github.com/oauth-xx/oauth2/pulls
+[🤝contributing]: CONTRIBUTING.md
+[🔑codecov-g♻️]: https://codecov.io/gh/oauth-xx/oauth2/graphs/tree.svg?token=bNqSzNiuo2
+[🖐contrib-rocks]: https://contrib.rocks
+[🖐contributors]: https://github.com/oauth-xx/oauth2/graphs/contributors
+[🖐contributors-img]: https://contrib.rocks/image?repo=oauth-xx/oauth2
+[🚎contributors-gl]: https://gitlab.com/oauth-xx/oauth2/-/graphs/main
+[🪇conduct]: CODE_OF_CONDUCT.md
+[🪇conduct-img]: https://img.shields.io/badge/Contributor_Covenant-2.1-4baaaa.svg
+[📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
+[📌semver]: https://semver.org/spec/v2.0.0.html
+[📌semver-img]: https://img.shields.io/badge/semver-2.0.0-FFDD67.svg?style=flat
+[📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139
+[📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
+[📌changelog]: CHANGELOG.md
+[📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
+[📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-FFDD67.svg?style=flat
+[📌gitmoji]:https://gitmoji.dev
+[📌gitmoji-img]:https://img.shields.io/badge/gitmoji-%20😜%20😍-FFDD67.svg?style=flat-square
+[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
+[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.073-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
+[🔐security]: SECURITY.md
+[🔐security-img]: https://img.shields.io/badge/security-policy-brightgreen.svg?style=flat
+[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
+[📄license]: LICENSE.txt
+[📄license-ref]: https://opensource.org/licenses/MIT
+[📄license-img]: https://img.shields.io/badge/License-MIT-green.svg
+[📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
+[📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-brightgreen.svg?style=flat
+[🚎yard-current]: http://rubydoc.info/gems/oauth2
+[🚎yard-head]: https://rubydoc.info/github/oauth-xx/oauth2/main
+[💎stone_checksums]: https://github.com/pboling/stone_checksums
+[💎SHA_checksums]: https://gitlab.com/oauth-xx/oauth2/-/tree/main/checksums
+[💎rlts]: https://github.com/rubocop-lts/rubocop-lts
+[💎rlts-img]: https://img.shields.io/badge/code_style-rubocop--lts-brightgreen.svg?plastic&logo=ruby&logoColor=white
+[🏘fossa]: https://app.fossa.io/projects/git%2Bgithub.com%2Foauth-xx%2Foauth2?ref=badge_shield
+[🏘fossa-img]: https://app.fossa.io/api/projects/git%2Bgithub.com%2Foauth-xx%2Foauth2.svg?type=shield
-## Code of Conduct
+
+
+ rel="me" Social Proofs
+
-Everyone interacting in the OAuth2 project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://gitlab.com/oauth-xx/oauth2/-/blob/main/CODE_OF_CONDUCT.md).
+
+
+
diff --git a/Rakefile b/Rakefile
index 9449ebe8..cdd18938 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,43 +1,88 @@
-# encoding: utf-8
-# frozen_string_literal: true
+require "bundler/gem_tasks"
-# !/usr/bin/env rake
+defaults = []
-require 'bundler/gem_tasks'
+# See: https://docs.gitlab.com/ci/variables/predefined_variables/
+is_gitlab = ENV.fetch("GITLAB_CI", "false").casecmp("true") == 0
+# Setup Bundle Audit
begin
- require 'rspec/core/rake_task'
+ require "bundler/audit/task"
+
+ Bundler::Audit::Task.new
+ defaults.push("bundle:audit:update", "bundle:audit")
+rescue LoadError
+ desc("(stub) bundle:audit is unavailable")
+ task("bundle:audit") do
+ warn("NOTE: bundler-audit isn't installed, or is disabled for #{RUBY_VERSION} in the current environment")
+ end
+ desc("(stub) bundle:audit:update is unavailable")
+ task("bundle:audit:update") do
+ warn("NOTE: bundler-audit isn't installed, or is disabled for #{RUBY_VERSION} in the current environment")
+ end
+end
+
+begin
+ require "rspec/core/rake_task"
+
RSpec::Core::RakeTask.new(:spec)
+ defaults << "spec"
rescue LoadError
- desc 'spec task stub'
- task :spec do
- warn 'rspec is disabled'
+ desc("spec task stub")
+ task(:spec) do
+ warn("NOTE: rspec isn't installed, or is disabled for #{RUBY_VERSION} in the current environment")
end
end
-desc 'alias test task to spec'
+
+desc "run spec task with test task"
task test: :spec
+# Setup RuboCop-LTS
begin
- require 'rubocop/rake_task'
- RuboCop::RakeTask.new do |task|
- task.options = ['-D'] # Display the name of the failing cops
+ require "rubocop/lts"
+
+ Rubocop::Lts.install_tasks
+ defaults << "rubocop_gradual"
+rescue LoadError
+ desc("(stub) rubocop_gradual is unavailable")
+ task(:rubocop_gradual) do
+ warn("NOTE: rubocop-lts isn't installed, or is disabled for #{RUBY_VERSION} in the current environment")
+ end
+end
+
+# Setup Yard
+begin
+ require "yard"
+
+ YARD::Rake::YardocTask.new(:yard) do |t|
+ t.files = [
+ # Splats (alphabetical)
+ "lib/**/*.rb",
+ ]
+ end
+ defaults << "yard"
+rescue LoadError
+ desc("(stub) yard is unavailable")
+ task(:yard) do
+ warn("NOTE: yard isn't installed, or is disabled for #{RUBY_VERSION} in the current environment")
+ end
+end
+
+# Setup Reek
+begin
+ require "reek/rake/task"
+
+ Reek::Rake::Task.new do |t|
+ t.fail_on_error = true
+ t.verbose = false
+ t.source_files = "{lib,spec}/**/*.rb"
end
+ defaults << "reek" unless is_gitlab
rescue LoadError
- desc 'rubocop task stub'
- task :rubocop do
- warn 'RuboCop is disabled'
+ desc("(stub) reek is unavailable")
+ task(:reek) do
+ warn("NOTE: reek isn't installed, or is disabled for #{RUBY_VERSION} in the current environment")
end
end
-# namespace :doc do
-# require 'rdoc/task'
-# require 'oauth2/version'
-# RDoc::Task.new do |rdoc|
-# rdoc.rdoc_dir = 'rdoc'
-# rdoc.title = "oauth2 #{OAuth2::Version}"
-# rdoc.main = 'README.md'
-# rdoc.rdoc_files.include('README.md', 'LICENSE.txt', 'lib/**/*.rb')
-# end
-# end
-
-task default: %i[test rubocop]
+task default: defaults
diff --git a/SECURITY.md b/SECURITY.md
index 274337d2..f41dda1f 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -4,8 +4,8 @@
| Version | Supported | EOL | Post-EOL / Enterprise |
|----------|-----------|---------|---------------------------------------|
-| 2.latest | ✅ | 04/2024 | [Tidelift Subscription][tidelift-ref] |
-| 1.latest | ✅ | 04/2023 | [Tidelift Subscription][tidelift-ref] |
+| 2.latest | ✅ | 04/2026 | [Tidelift Subscription][tidelift-ref] |
+| 1.latest | ✅ | 10/2025 | [Tidelift Subscription][tidelift-ref] |
| <= 1 | ⛔ | ⛔ | ⛔ |
### EOL Policy
diff --git a/bin/bundle b/bin/bundle
index fece50fe..4a95618e 100755
--- a/bin/bundle
+++ b/bin/bundle
@@ -8,7 +8,7 @@
# this file is here to facilitate running it.
#
-require 'rubygems'
+require "rubygems"
m = Module.new do
module_function
@@ -18,18 +18,18 @@ module_function
end
def env_var_version
- ENV['BUNDLER_VERSION']
+ ENV["BUNDLER_VERSION"]
end
def cli_arg_version
return unless invoked_as_script? # don't want to hijack other binstubs
- return unless 'update'.start_with?(ARGV.first || ' ') # must be running `bundle update`
+ return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
bundler_version = nil
update_index = nil
ARGV.each_with_index do |a, i|
bundler_version = a if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
- next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
+ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/o
bundler_version = Regexp.last_match(1)
update_index = i
@@ -38,16 +38,16 @@ module_function
end
def gemfile
- gemfile = ENV['BUNDLE_GEMFILE']
+ gemfile = ENV["BUNDLE_GEMFILE"]
return gemfile if gemfile && !gemfile.empty?
- File.expand_path('../Gemfile', __dir__)
+ File.expand_path("../Gemfile", __dir__)
end
def lockfile
lockfile =
case File.basename(gemfile)
- when 'gems.rb' then gemfile.sub(/\.rb$/, gemfile)
+ when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
else "#{gemfile}.lock"
end
File.expand_path(lockfile)
@@ -57,7 +57,7 @@ module_function
return unless File.file?(lockfile)
lockfile_contents = File.read(lockfile)
- return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
+ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/o
Regexp.last_match(1)
end
@@ -75,32 +75,32 @@ module_function
requirement = bundler_gem_version.approximate_recommendation
- return requirement unless Gem.rubygems_version < Gem::Version.new('2.7.0')
+ return requirement unless Gem.rubygems_version < Gem::Version.new("2.7.0")
- requirement += '.a' if bundler_gem_version.prerelease?
+ requirement += ".a" if bundler_gem_version.prerelease?
requirement
end
def load_bundler!
- ENV['BUNDLE_GEMFILE'] ||= gemfile
+ ENV["BUNDLE_GEMFILE"] ||= gemfile
activate_bundler
end
def activate_bundler
gem_error = activation_error_handling do
- gem 'bundler', bundler_requirement
+ gem("bundler", bundler_requirement)
end
return if gem_error.nil?
require_error = activation_error_handling do
- require 'bundler/version'
+ require "bundler/version"
end
return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
- warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
- exit 42
+ warn("Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`")
+ exit(42)
end
def activation_error_handling
@@ -113,4 +113,4 @@ end
m.load_bundler!
-load Gem.bin_path('bundler', 'bundle') if m.invoked_as_script?
+load Gem.bin_path("bundler", "bundle") if m.invoked_as_script?
diff --git a/bin/bundle-audit b/bin/bundle-audit
new file mode 100644
index 00000000..a0e7ba0e
--- /dev/null
+++ b/bin/bundle-audit
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'bundle-audit' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("bundler-audit", "bundle-audit")
diff --git a/bin/bundler-audit b/bin/bundler-audit
new file mode 100644
index 00000000..334a7378
--- /dev/null
+++ b/bin/bundler-audit
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'bundler-audit' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("bundler-audit", "bundler-audit")
diff --git a/bin/code_climate_reek b/bin/code_climate_reek
new file mode 100644
index 00000000..afe0d79f
--- /dev/null
+++ b/bin/code_climate_reek
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'code_climate_reek' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("reek", "code_climate_reek")
diff --git a/bin/coderay b/bin/coderay
new file mode 100644
index 00000000..b13b22e9
--- /dev/null
+++ b/bin/coderay
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'coderay' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("coderay", "coderay")
diff --git a/bin/console b/bin/console
index d8fb16d0..53fc8fd9 100755
--- a/bin/console
+++ b/bin/console
@@ -1,16 +1,15 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
-require 'bundler/setup'
-require 'oauth2'
+require "bundler/setup"
+require "oauth2"
# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.
-require 'byebug' if ENV['DEBUG'] == 'true'
# (If you use this, don't forget to add pry to your Gemfile!)
# require "pry"
# Pry.start
-require 'irb'
+require "irb"
IRB.start(__FILE__)
diff --git a/bin/github-markup b/bin/github-markup
new file mode 100644
index 00000000..5cb47930
--- /dev/null
+++ b/bin/github-markup
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'github-markup' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("github-markup", "github-markup")
diff --git a/bin/htmldiff b/bin/htmldiff
new file mode 100644
index 00000000..0aeaec87
--- /dev/null
+++ b/bin/htmldiff
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'htmldiff' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("diff-lcs", "htmldiff")
diff --git a/bin/irb b/bin/irb
new file mode 100644
index 00000000..e7de6d6c
--- /dev/null
+++ b/bin/irb
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'irb' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("irb", "irb")
diff --git a/bin/ldiff b/bin/ldiff
new file mode 100644
index 00000000..8173edec
--- /dev/null
+++ b/bin/ldiff
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'ldiff' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("diff-lcs", "ldiff")
diff --git a/bin/racc b/bin/racc
new file mode 100644
index 00000000..81900158
--- /dev/null
+++ b/bin/racc
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'racc' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("racc", "racc")
diff --git a/bin/rake b/bin/rake
index 5f615c2a..51e10c4a 100755
--- a/bin/rake
+++ b/bin/rake
@@ -8,9 +8,9 @@
# this file is here to facilitate running it.
#
-ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
-bundle_binstub = File.expand_path('bundle', __dir__)
+bundle_binstub = File.expand_path("bundle", __dir__)
if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
@@ -21,7 +21,7 @@ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this
end
end
-require 'rubygems'
-require 'bundler/setup'
+require "rubygems"
+require "bundler/setup"
-load Gem.bin_path('rake', 'rake')
+load Gem.bin_path("rake", "rake")
diff --git a/bin/rdbg b/bin/rdbg
new file mode 100644
index 00000000..5e3b279f
--- /dev/null
+++ b/bin/rdbg
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'rdbg' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("debug", "rdbg")
diff --git a/bin/rdoc b/bin/rdoc
new file mode 100644
index 00000000..d2b6bcf8
--- /dev/null
+++ b/bin/rdoc
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'rdoc' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("rdoc", "rdoc")
diff --git a/bin/redcarpet b/bin/redcarpet
new file mode 100644
index 00000000..76a1cb80
--- /dev/null
+++ b/bin/redcarpet
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'redcarpet' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("redcarpet", "redcarpet")
diff --git a/bin/reek b/bin/reek
new file mode 100644
index 00000000..2ec45920
--- /dev/null
+++ b/bin/reek
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'reek' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("reek", "reek")
diff --git a/bin/ri b/bin/ri
new file mode 100644
index 00000000..72e25813
--- /dev/null
+++ b/bin/ri
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'ri' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("rdoc", "ri")
diff --git a/bin/rspec b/bin/rspec
index d3f4959a..757e79b3 100755
--- a/bin/rspec
+++ b/bin/rspec
@@ -8,9 +8,9 @@
# this file is here to facilitate running it.
#
-ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
-bundle_binstub = File.expand_path('bundle', __dir__)
+bundle_binstub = File.expand_path("bundle", __dir__)
if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
@@ -21,7 +21,7 @@ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this
end
end
-require 'rubygems'
-require 'bundler/setup'
+require "rubygems"
+require "bundler/setup"
-load Gem.bin_path('rspec-core', 'rspec')
+load Gem.bin_path("rspec-core", "rspec")
diff --git a/bin/rubocop b/bin/rubocop
index cc105e8d..2b1fa1f7 100755
--- a/bin/rubocop
+++ b/bin/rubocop
@@ -8,9 +8,9 @@
# this file is here to facilitate running it.
#
-ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
-bundle_binstub = File.expand_path('bundle', __dir__)
+bundle_binstub = File.expand_path("bundle", __dir__)
if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
@@ -21,7 +21,7 @@ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this
end
end
-require 'rubygems'
-require 'bundler/setup'
+require "rubygems"
+require "bundler/setup"
-load Gem.bin_path('rubocop', 'rubocop')
+load Gem.bin_path("rubocop", "rubocop")
diff --git a/bin/rubocop-gradual b/bin/rubocop-gradual
new file mode 100644
index 00000000..07520055
--- /dev/null
+++ b/bin/rubocop-gradual
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'rubocop-gradual' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("rubocop-gradual", "rubocop-gradual")
diff --git a/bin/ruby-parse b/bin/ruby-parse
new file mode 100644
index 00000000..d8ebc68d
--- /dev/null
+++ b/bin/ruby-parse
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'ruby-parse' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("parser", "ruby-parse")
diff --git a/bin/ruby-rewrite b/bin/ruby-rewrite
new file mode 100644
index 00000000..b4574aba
--- /dev/null
+++ b/bin/ruby-rewrite
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'ruby-rewrite' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("parser", "ruby-rewrite")
diff --git a/bin/standardrb b/bin/standardrb
new file mode 100644
index 00000000..b329561c
--- /dev/null
+++ b/bin/standardrb
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'standardrb' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("standard", "standardrb")
diff --git a/bin/thor b/bin/thor
new file mode 100644
index 00000000..ec401151
--- /dev/null
+++ b/bin/thor
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'thor' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("thor", "thor")
diff --git a/bin/yard b/bin/yard
new file mode 100644
index 00000000..ea9daf5f
--- /dev/null
+++ b/bin/yard
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'yard' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("yard", "yard")
diff --git a/bin/yard-junk b/bin/yard-junk
new file mode 100644
index 00000000..be420a5c
--- /dev/null
+++ b/bin/yard-junk
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'yard-junk' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("yard-junk", "yard-junk")
diff --git a/bin/yardoc b/bin/yardoc
new file mode 100644
index 00000000..e1324dc1
--- /dev/null
+++ b/bin/yardoc
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'yardoc' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("yard", "yardoc")
diff --git a/bin/yri b/bin/yri
new file mode 100644
index 00000000..f968fde1
--- /dev/null
+++ b/bin/yri
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'yri' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("yard", "yri")
diff --git a/certs/pboling.pem b/certs/pboling.pem
index f11daea5..d5c7e8bb 100644
--- a/certs/pboling.pem
+++ b/certs/pboling.pem
@@ -1,27 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEgDCCAuigAwIBAgIBATANBgkqhkiG9w0BAQsFADBDMRUwEwYDVQQDDAxwZXRl
ci5ib2xpbmcxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkW
-A2NvbTAeFw0yMjA5MTgyMzEyMzBaFw0yMzA5MTgyMzEyMzBaMEMxFTATBgNVBAMM
+A2NvbTAeFw0yNTA1MDQxNTMzMDlaFw00NTA0MjkxNTMzMDlaMEMxFTATBgNVBAMM
DHBldGVyLmJvbGluZzEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPy
-LGQBGRYDY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA2Dn1GM3W
-8K2/rvN1zz+06bQMcxD16ZKTihVwi7Pb1v3T98rM4Omnxohm3s+CwpDWGeiB9pj6
-0I/CTce0e4e3s8GKJSOrg93veImPSoH2PfsMsRsuB8wtqyiOCjLbF5o6S29x87r0
-LA5EawH+Lh4xqrkkPjdffsmLk7TaCig/vlmNvnzxXKBdey/X/aEJZXzzBiWRfVdh
-O1fmMbVKyieGv9HK7+pLotIoT08bjDv8NP6V7zZslwQRqW27bQc6cqC2LGIbTYO3
-3jt1kQxfMWmhOictS6SzG9VtKSrXf0L4Neq0Gh7CLBZBvJFWJYZPfb92YNITDbd8
-emPOAQlXXNMN4mMXsEqtEhCPZRMnmwO+fOk/cC4AyglKi9lnQugCQoFV1XDMZST/
-CYbzdQyadOdPDInTntG6V+Uw51d2QGXZ6PDDfrx9+toc/3sl5h68rCUGgE6Q3jPz
-srinqmBsxv2vTpmd4FjmiAtEnwH5/ooLpQYL8UdAjEoeysxS3AwIh+5dAgMBAAGj
-fzB9MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBQWU6D156a2cle+
-lb5RBfvVXlxTwjAhBgNVHREEGjAYgRZwZXRlci5ib2xpbmdAZ21haWwuY29tMCEG
+LGQBGRYDY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAruUoo0WA
+uoNuq6puKWYeRYiZekz/nsDeK5x/0IEirzcCEvaHr3Bmz7rjo1I6On3gGKmiZs61
+LRmQ3oxy77ydmkGTXBjruJB+pQEn7UfLSgQ0xa1/X3kdBZt6RmabFlBxnHkoaGY5
+mZuZ5+Z7walmv6sFD9ajhzj+oIgwWfnEHkXYTR8I6VLN7MRRKGMPoZ/yvOmxb2DN
+coEEHWKO9CvgYpW7asIihl/9GMpKiRkcYPm9dGQzZc6uTwom1COfW0+ZOFrDVBuV
+FMQRPswZcY4Wlq0uEBLPU7hxnCL9nKK6Y9IhdDcz1mY6HZ91WImNslOSI0S8hRpj
+yGOWxQIhBT3fqCBlRIqFQBudrnD9jSNpSGsFvbEijd5ns7Z9ZMehXkXDycpGAUj1
+to/5cuTWWw1JqUWrKJYoifnVhtE1o1DZ+LkPtWxHtz5kjDG/zR3MG0Ula0UOavlD
+qbnbcXPBnwXtTFeZ3C+yrWpE4pGnl3yGkZj9SMTlo9qnTMiPmuWKQDatAgMBAAGj
+fzB9MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBQE8uWvNbPVNRXZ
+HlgPbc2PCzC4bjAhBgNVHREEGjAYgRZwZXRlci5ib2xpbmdAZ21haWwuY29tMCEG
A1UdEgQaMBiBFnBldGVyLmJvbGluZ0BnbWFpbC5jb20wDQYJKoZIhvcNAQELBQAD
-ggGBAJ4SqhPlgUiLYIrphGXIaxXScHyvx4kixuvdrwhI4VoQV2qXvO7R6ZjOXVwX
-f/z84BWPiTZ8lzThPbt1UV/BGwkvLw9I4RjOdzvUz3J42j9Ly6q63isall07bo3F
-QWe/OBvIMBF1IbjC3q5vKPg4rq8+TkNRJNoE86U2gfR+PkW3jYYs9uiy0GloHDCP
-k5xgaj0vSL0Uy5mTOPdk3K6a/sUGZyYniWK05zdhIi956ynhfGaFO988FFdVw5Jq
-LHtXfIpAU8F7ES04syZSslxOluw7VlcSKyRdVIr737J92ZTduppB4PRGSKRgBsWV
-hXTahRE72Kyw53Q7FAuzF3v102WxAAQ7BuMjW+MyCUT75fwPm3W4ELPL8HYkNGE7
-2oA5CPghFitRnvYS3GNrDG+9bNiRMEskeaBYwZ9UgReBQIwGYVj7LZk3UhiAsn44
-gwGrEXGQGDZ0NIgBcmvMOqlXjkGQwQvugKycJ024z89+fz2332vdZIKTrSxJrXGk
-4/bR9A==
+ggGBAJbnUwfJQFPkBgH9cL7hoBfRtmWiCvdqdjeTmi04u8zVNCUox0A4gT982DE9
+wmuN12LpdajxZONqbXuzZvc+nb0StFwmFYZG6iDwaf4BPywm2e/Vmq0YG45vZXGR
+L8yMDSK1cQXjmA+ZBKOHKWavxP6Vp7lWvjAhz8RFwqF9GuNIdhv9NpnCAWcMZtpm
+GUPyIWw/Cw/2wZp74QzZj6Npx+LdXoLTF1HMSJXZ7/pkxLCsB8m4EFVdb/IrW/0k
+kNSfjtAfBHO8nLGuqQZVH9IBD1i9K6aSs7pT6TW8itXUIlkIUI2tg5YzW6OFfPzq
+QekSkX3lZfY+HTSp/o+YvKkqWLUV7PQ7xh1ZYDtocpaHwgxe/j3bBqHE+CUPH2vA
+0V/FwdTRWcwsjVoOJTrYcff8pBZ8r2MvtAc54xfnnhGFzeRHfcltobgFxkAXdE6p
+DVjBtqT23eugOqQ73umLcYDZkc36vnqGxUBSsXrzY9pzV5gGr2I8YUxMqf6ATrZt
+L9nRqA==
-----END CERTIFICATE-----
diff --git a/checksums/oauth2-2.0.10.gem.sha256 b/checksums/oauth2-2.0.10.gem.sha256
deleted file mode 100644
index e0e65592..00000000
--- a/checksums/oauth2-2.0.10.gem.sha256
+++ /dev/null
@@ -1 +0,0 @@
-e0bbe33434c32cdd01bc970f265c64db42b44f42d2036896710b1cf3e682e704
\ No newline at end of file
diff --git a/checksums/oauth2-2.0.10.gem.sha512 b/checksums/oauth2-2.0.10.gem.sha512
deleted file mode 100644
index 02ad7661..00000000
--- a/checksums/oauth2-2.0.10.gem.sha512
+++ /dev/null
@@ -1 +0,0 @@
-a73cc4c6502893f219e4b1cc5d2df480184bbf11069b43e08b781f4d278ce7219097e8904710948b644d22de95b98cdad575de1d1864d815d0e3064c2601a270
\ No newline at end of file
diff --git a/gemfiles/README.md b/gemfiles/README.md
index 1ac3a713..b217d4cf 100644
--- a/gemfiles/README.md
+++ b/gemfiles/README.md
@@ -4,7 +4,7 @@
and thus is the oldest version oauth2 is compatible with.
```ruby
-gem 'faraday', ['>= 0.17.3', '< 3.0']
+gem "faraday", [">= 0.17.3", "< 3.0"]
```
# Ruby
diff --git a/gemfiles/f0.gemfile b/gemfiles/f0.gemfile
index 4cb7f887..dc8d3f31 100644
--- a/gemfiles/f0.gemfile
+++ b/gemfiles/f0.gemfile
@@ -1,11 +1,11 @@
# frozen_string_literal: true
-source 'https://rubygems.org'
+source "https://rubygems.org"
# See README.md in this directory
# 0.17.3 is the first version that stops using &Proc.new for block forwarding,
# and thus is the oldest version oauth2 is compatible with.
-gem 'faraday', '~> 0.17.4'
+gem "faraday", "~> 0.17.4"
-gemspec path: '../'
+gemspec path: "../"
diff --git a/gemfiles/f1.gemfile b/gemfiles/f1.gemfile
index 94cba5c6..40043bca 100644
--- a/gemfiles/f1.gemfile
+++ b/gemfiles/f1.gemfile
@@ -1,9 +1,9 @@
# frozen_string_literal: true
-source 'https://rubygems.org'
+source "https://rubygems.org"
# See README.md in this directory
-gem 'faraday', '~> 1.10'
+gem "faraday", "~> 1.10"
-gemspec path: '../'
+gemspec path: "../"
diff --git a/gemfiles/f2.gemfile b/gemfiles/f2.gemfile
index 7c3868df..44081f52 100644
--- a/gemfiles/f2.gemfile
+++ b/gemfiles/f2.gemfile
@@ -1,9 +1,9 @@
# frozen_string_literal: true
-source 'https://rubygems.org'
+source "https://rubygems.org"
# See README.md in this directory
-gem 'faraday', '~> 2.2'
+gem "faraday", "~> 2.2"
-gemspec path: '../'
+gemspec path: "../"
diff --git a/gemfiles/jruby_9.1.gemfile b/gemfiles/jruby_9.1.gemfile
index fb2b9158..7573a1b5 100644
--- a/gemfiles/jruby_9.1.gemfile
+++ b/gemfiles/jruby_9.1.gemfile
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-source 'https://rubygems.org'
+source "https://rubygems.org"
-gemspec path: '../'
+gemspec path: "../"
diff --git a/gemfiles/jruby_9.2.gemfile b/gemfiles/jruby_9.2.gemfile
index fb2b9158..7573a1b5 100644
--- a/gemfiles/jruby_9.2.gemfile
+++ b/gemfiles/jruby_9.2.gemfile
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-source 'https://rubygems.org'
+source "https://rubygems.org"
-gemspec path: '../'
+gemspec path: "../"
diff --git a/gemfiles/jruby_head.gemfile b/gemfiles/jruby_head.gemfile
index fb2b9158..7573a1b5 100644
--- a/gemfiles/jruby_head.gemfile
+++ b/gemfiles/jruby_head.gemfile
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-source 'https://rubygems.org'
+source "https://rubygems.org"
-gemspec path: '../'
+gemspec path: "../"
diff --git a/gemfiles/modular/audit.gemfile b/gemfiles/modular/audit.gemfile
new file mode 100644
index 00000000..e5cc9199
--- /dev/null
+++ b/gemfiles/modular/audit.gemfile
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+# Many gems are dropping support for Ruby < 3,
+# so we only want to run our security audit in CI on Ruby 3+
+gem "bundler-audit", "~> 0.9.2"
diff --git a/gemfiles/modular/coverage.gemfile b/gemfiles/modular/coverage.gemfile
new file mode 100644
index 00000000..5ef0c45a
--- /dev/null
+++ b/gemfiles/modular/coverage.gemfile
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+# We run code coverage on the latest version of Ruby only.
+
+# Coverage
+gem "kettle-soup-cover", "~> 1.0", ">= 1.0.6", require: false
diff --git a/gemfiles/modular/documentation.gemfile b/gemfiles/modular/documentation.gemfile
new file mode 100644
index 00000000..5cccab2e
--- /dev/null
+++ b/gemfiles/modular/documentation.gemfile
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+# Documentation
+gem "yard", "~> 0.9", ">= 0.9.37", require: false
+gem "yard-junk", "~> 0.0", ">= 0.0.10", github: "pboling/yard-junk", branch: "next"
+
+# Std Lib extractions
+gem "rdoc", "~> 6.11"
diff --git a/gemfiles/modular/style.gemfile b/gemfiles/modular/style.gemfile
new file mode 100644
index 00000000..8966ca93
--- /dev/null
+++ b/gemfiles/modular/style.gemfile
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+# We run rubocop on the latest version of Ruby,
+# but in support of the oldest supported version of Ruby
+
+gem "reek", "~> 6.4"
+gem "rubocop", "~> 1.73", ">= 1.73.2"
+# gem "rubocop-lts", "~> 0.1", ">= 0.1.1" # Linting for Ruby >= 1.8
+gem "rubocop-packaging", "~> 0.5", ">= 0.5.2"
+gem "rubocop-rspec", "~> 3.2"
+gem "standard", "~> 1.47"
+
+# Std Lib extractions
+gem "benchmark", "~> 0.4" # Removed from Std Lib in Ruby 3.5
+
+# gem "rubocop-lts", :path => "/home/pboling/src/rubocop-lts/rubocop-lts"
+# gem "rubocop-lts-rspec", :path => "/home/pboling/src/rubocop-lts/rubocop-lts-rspec"
+# gem "rubocop-ruby1_8", :path => "/home/pboling/src/rubocop-lts/rubocop-ruby1_8"
+# gem "standard-rubocop-lts", :path => "/home/pboling/src/rubocop-lts/standard-rubocop-lts"
diff --git a/gemfiles/omnibus.gemfile b/gemfiles/omnibus.gemfile
new file mode 100644
index 00000000..553053f5
--- /dev/null
+++ b/gemfiles/omnibus.gemfile
@@ -0,0 +1,18 @@
+# This gemfile is used for GitLab CI, current ruby pipeline.
+# This gemfile includes all dependencies necessary to run the naked `rake default` set of tasks
+
+source "https://rubygems.org"
+
+git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
+git_source(:gitlab) { |repo_name| "https://gitlab.com/#{repo_name}" }
+
+eval_gemfile "modular/audit.gemfile"
+eval_gemfile "modular/coverage.gemfile"
+eval_gemfile "modular/documentation.gemfile"
+eval_gemfile "modular/style.gemfile"
+
+# Root Gemfile is only for local development.
+# On CI, we only need the gemspec dependencies (including development dependencies).
+# Exceptions, if any, will be found in gemfiles/*.gemfile
+
+gemspec path: "../"
diff --git a/gemfiles/ruby_head.gemfile b/gemfiles/ruby_head.gemfile
index fb2b9158..7573a1b5 100644
--- a/gemfiles/ruby_head.gemfile
+++ b/gemfiles/ruby_head.gemfile
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-source 'https://rubygems.org'
+source "https://rubygems.org"
-gemspec path: '../'
+gemspec path: "../"
diff --git a/gemfiles/truffleruby.gemfile b/gemfiles/truffleruby.gemfile
index fb2b9158..7573a1b5 100644
--- a/gemfiles/truffleruby.gemfile
+++ b/gemfiles/truffleruby.gemfile
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-source 'https://rubygems.org'
+source "https://rubygems.org"
-gemspec path: '../'
+gemspec path: "../"
diff --git a/gemfiles/vanilla.gemfile b/gemfiles/vanilla.gemfile
new file mode 100644
index 00000000..78c20166
--- /dev/null
+++ b/gemfiles/vanilla.gemfile
@@ -0,0 +1,11 @@
+# This gemfile is used for GitLab CI, current ruby pipeline.
+# This gemfile includes all dependencies necessary to run the naked `rake default` set of tasks
+
+source "https://rubygems.org"
+
+# Root Gemfile is only for local development.
+# On CI, we only need the gemspec dependencies (including development dependencies).
+# Exceptions, if any, will be found in gemfiles/*.gemfile
+
+# The vanilla gemfile is intended to what we can with *only* gemspec dependencies.
+gemspec path: "../"
diff --git a/lib/oauth2.rb b/lib/oauth2.rb
index 00f51b08..2f950419 100644
--- a/lib/oauth2.rb
+++ b/lib/oauth2.rb
@@ -1,27 +1,27 @@
# frozen_string_literal: true
# includes modules from stdlib
-require 'cgi'
-require 'time'
+require "cgi"
+require "time"
# third party gems
-require 'snaky_hash'
-require 'version_gem'
+require "snaky_hash"
+require "version_gem"
# includes gem files
-require 'oauth2/version'
-require 'oauth2/filtered_attributes'
-require 'oauth2/error'
-require 'oauth2/authenticator'
-require 'oauth2/client'
-require 'oauth2/strategy/base'
-require 'oauth2/strategy/auth_code'
-require 'oauth2/strategy/implicit'
-require 'oauth2/strategy/password'
-require 'oauth2/strategy/client_credentials'
-require 'oauth2/strategy/assertion'
-require 'oauth2/access_token'
-require 'oauth2/response'
+require "oauth2/version"
+require "oauth2/filtered_attributes"
+require "oauth2/error"
+require "oauth2/authenticator"
+require "oauth2/client"
+require "oauth2/strategy/base"
+require "oauth2/strategy/auth_code"
+require "oauth2/strategy/implicit"
+require "oauth2/strategy/password"
+require "oauth2/strategy/client_credentials"
+require "oauth2/strategy/assertion"
+require "oauth2/access_token"
+require "oauth2/response"
# The namespace of this library
module OAuth2
diff --git a/lib/oauth2/access_token.rb b/lib/oauth2/access_token.rb
index 45682629..04a2049d 100644
--- a/lib/oauth2/access_token.rb
+++ b/lib/oauth2/access_token.rb
@@ -76,19 +76,21 @@ def initialize(client, token, opts = {})
error = Error.new(opts)
raise(error)
else
- warn('OAuth2::AccessToken has no token')
+ warn("OAuth2::AccessToken has no token")
end
end
# @option opts [Fixnum, String] :expires is deprecated
- @expires_in ||= opts.delete('expires')
+ @expires_in ||= opts.delete("expires")
@expires_in &&= @expires_in.to_i
@expires_at &&= convert_expires_at(@expires_at)
@expires_latency &&= @expires_latency.to_i
@expires_at ||= Time.now.to_i + @expires_in if @expires_in && !@expires_in.zero?
@expires_at -= @expires_latency if @expires_latency
- @options = {mode: opts.delete(:mode) || :header,
- header_format: opts.delete(:header_format) || 'Bearer %s',
- param_name: opts.delete(:param_name) || 'access_token'}
+ @options = {
+ mode: opts.delete(:mode) || :header,
+ header_format: opts.delete(:header_format) || "Bearer %s",
+ param_name: opts.delete(:param_name) || "access_token",
+ }
@params = opts
end
@@ -118,9 +120,9 @@ def expired?
# @return [AccessToken] a new AccessToken
# @note options should be carried over to the new AccessToken
def refresh(params = {}, access_token_opts = {})
- raise('A refresh_token is not available') unless refresh_token
+ raise("A refresh_token is not available") unless refresh_token
- params[:grant_type] = 'refresh_token'
+ params[:grant_type] = "refresh_token"
params[:refresh_token] = refresh_token
new_token = @client.get_token(params, access_token_opts)
new_token.options = options
@@ -133,7 +135,7 @@ def refresh(params = {}, access_token_opts = {})
end
# A compatibility alias
# @note does not modify the receiver, so bang is not the default method
- alias refresh! refresh
+ alias_method :refresh!, :refresh
# Convert AccessToken to a hash which can be used to rebuild itself with AccessToken.from_hash
#
@@ -190,7 +192,7 @@ def delete(path, opts = {}, &block)
# Get the headers hash (includes Authorization token)
def headers
- {'Authorization' => options[:header_format] % token}
+ {"Authorization" => options[:header_format] % token}
end
private
diff --git a/lib/oauth2/authenticator.rb b/lib/oauth2/authenticator.rb
index f3e2888a..512d1cd7 100644
--- a/lib/oauth2/authenticator.rb
+++ b/lib/oauth2/authenticator.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'base64'
+require "base64"
module OAuth2
class Authenticator
@@ -49,8 +49,8 @@ def self.encode_basic_auth(user, password)
# already set.
def apply_params_auth(params)
result = {}
- result['client_id'] = id unless id.nil?
- result['client_secret'] = secret unless secret.nil?
+ result["client_id"] = id unless id.nil?
+ result["client_secret"] = secret unless secret.nil?
result.merge(params)
end
@@ -58,7 +58,7 @@ def apply_params_auth(params)
# we don't want to send the secret
def apply_client_id(params)
result = {}
- result['client_id'] = id unless id.nil?
+ result["client_id"] = id unless id.nil?
result.merge(params)
end
@@ -72,7 +72,7 @@ def apply_basic_auth(params)
# @see https://datatracker.ietf.org/doc/html/rfc2617#section-2
def basic_auth_header
- {'Authorization' => self.class.encode_basic_auth(id, secret)}
+ {"Authorization" => self.class.encode_basic_auth(id, secret)}
end
end
end
diff --git a/lib/oauth2/client.rb b/lib/oauth2/client.rb
index e87a5cd0..4176cc25 100644
--- a/lib/oauth2/client.rb
+++ b/lib/oauth2/client.rb
@@ -1,11 +1,11 @@
# frozen_string_literal: true
-require 'faraday'
-require 'logger'
+require "faraday"
+require "logger"
if Faraday::Utils.respond_to?(:default_space_encoding)
# This setting doesn't exist in faraday 0.x
- Faraday::Utils.default_space_encoding = '%20'
+ Faraday::Utils.default_space_encoding = "%20"
end
module OAuth2
@@ -49,10 +49,10 @@ def initialize(client_id, client_secret, options = {}, &block)
@secret = client_secret
@site = opts.delete(:site)
ssl = opts.delete(:ssl)
- warn('OAuth2::Client#initialize argument `extract_access_token` will be removed in oauth2 v3. Refactor to use `access_token_class`.') if opts[:extract_access_token]
+ warn("OAuth2::Client#initialize argument `extract_access_token` will be removed in oauth2 v3. Refactor to use `access_token_class`.") if opts[:extract_access_token]
@options = {
- authorize_url: 'oauth/authorize',
- token_url: 'oauth/token',
+ authorize_url: "oauth/authorize",
+ token_url: "oauth/token",
token_method: :post,
auth_scheme: :basic_auth,
connection_opts: {},
@@ -81,8 +81,8 @@ def connection
if options[:connection_build]
options[:connection_build].call(builder)
else
- builder.request :url_encoded # form-encode POST params
- builder.adapter Faraday.default_adapter # make requests with Net::HTTP
+ builder.request(:url_encoded) # form-encode POST params
+ builder.adapter(Faraday.default_adapter) # make requests with Net::HTTP
end
end
end
@@ -131,7 +131,7 @@ def request(verb, url, opts = {}, &block)
verb = :get
opts.delete(:body)
end
- location = response.headers['location']
+ location = response.headers["location"]
if location
full_location = response.response.env.url.merge(location)
request(verb, full_location, opts)
@@ -165,7 +165,7 @@ def request(verb, url, opts = {}, &block)
# @yield [req] @see Faraday::Connection#run_request
# @return [AccessToken] the initialized AccessToken
def get_token(params, access_token_opts = {}, extract_access_token = nil, &block)
- warn('OAuth2::Client#get_token argument `extract_access_token` will be removed in oauth2 v3. Refactor to use `access_token_class` on #initialize.') if extract_access_token
+ warn("OAuth2::Client#get_token argument `extract_access_token` will be removed in oauth2 v3. Refactor to use `access_token_class` on #initialize.") if extract_access_token
extract_access_token ||= options[:extract_access_token]
parse, snaky, params, headers = parse_snaky_params_headers(params)
@@ -178,13 +178,13 @@ def get_token(params, access_token_opts = {}, extract_access_token = nil, &block
# NOTE: If proliferation of request types continues we should implement a parser solution for Request,
# just like we have with Response.
- request_opts[:body] = if headers['Content-Type'] == 'application/json'
- params.to_json
- else
- params
- end
+ request_opts[:body] = if headers["Content-Type"] == "application/json"
+ params.to_json
+ else
+ params
+ end
- request_opts[:headers] = {'Content-Type' => 'application/x-www-form-urlencoded'}
+ request_opts[:headers] = {"Content-Type" => "application/x-www-form-urlencoded"}
else
request_opts[:params] = params
request_opts[:headers] = {}
@@ -261,7 +261,7 @@ def assertion
# @return [Hash] the params to add to a request or URL
def redirection_params
if options[:redirect_uri]
- {'redirect_uri' => options[:redirect_uri]}
+ {"redirect_uri" => options[:redirect_uri]}
else
{}
end
@@ -358,7 +358,7 @@ def build_access_token_legacy(response, access_token_opts, extract_access_token)
end
def oauth_debug_logging(builder)
- builder.response :logger, options[:logger], bodies: true if ENV['OAUTH_DEBUG'] == 'true'
+ builder.response(:logger, options[:logger], bodies: true) if ENV["OAUTH_DEBUG"] == "true"
end
end
end
diff --git a/lib/oauth2/error.rb b/lib/oauth2/error.rb
index cd99ff86..076abbe0 100644
--- a/lib/oauth2/error.rb
+++ b/lib/oauth2/error.rb
@@ -11,18 +11,18 @@ def initialize(response)
@response = response
if response.respond_to?(:parsed)
if response.parsed.is_a?(Hash)
- @code = response.parsed['error']
- @description = response.parsed['error_description']
+ @code = response.parsed["error"]
+ @description = response.parsed["error_description"]
end
elsif response.is_a?(Hash)
- @code = response['error']
- @description = response['error_description']
+ @code = response["error"]
+ @description = response["error_description"]
end
@body = if response.respond_to?(:body)
- response.body
- else
- @response
- end
+ response.body
+ else
+ @response
+ end
message_opts = parse_error_description(@code, @description)
super(error_message(@body, message_opts))
end
@@ -35,11 +35,11 @@ def error_message(response_body, opts = {})
lines << opts[:error_description] if opts[:error_description]
error_string = if response_body.respond_to?(:encode) && opts[:error_description].respond_to?(:encoding)
- script_encoding = opts[:error_description].encoding
- response_body.encode(script_encoding, invalid: :replace, undef: :replace)
- else
- response_body
- end
+ script_encoding = opts[:error_description].encoding
+ response_body.encode(script_encoding, invalid: :replace, undef: :replace)
+ else
+ response_body
+ end
lines << error_string
@@ -49,7 +49,7 @@ def error_message(response_body, opts = {})
def parse_error_description(code, description)
return {} unless code || description
- error_description = ''
+ error_description = ""
error_description += "#{code}: " if code
error_description += description if description
diff --git a/lib/oauth2/filtered_attributes.rb b/lib/oauth2/filtered_attributes.rb
index 299d2d92..2794b94b 100644
--- a/lib/oauth2/filtered_attributes.rb
+++ b/lib/oauth2/filtered_attributes.rb
@@ -25,7 +25,7 @@ def inspect
"#{var}=#{instance_variable_get(var).inspect}"
end
end
- "#<#{self.class}:#{object_id} #{inspected_vars.join(', ')}>"
+ "#<#{self.class}:#{object_id} #{inspected_vars.join(", ")}>"
end
end
end
diff --git a/lib/oauth2/response.rb b/lib/oauth2/response.rb
index c5bbb3ba..7003bf20 100644
--- a/lib/oauth2/response.rb
+++ b/lib/oauth2/response.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
-require 'json'
-require 'multi_xml'
-require 'rack'
+require "json"
+require "multi_xml"
+require "rack"
module OAuth2
# OAuth2::Response class
@@ -23,8 +23,8 @@ class Response
# Content type assignments for various potential HTTP content types.
@@content_types = {
- 'application/x-www-form-urlencoded' => :query,
- 'text/plain' => :text,
+ "application/x-www-form-urlencoded" => :query,
+ "text/plain" => :text,
}
# Adds a new content type parser.
@@ -68,7 +68,7 @@ def status
# The HTTP response body
def body
- response.body || ''
+ response.body || ""
end
# The {#response} {#body} as parsed by {#parser}.
@@ -97,9 +97,9 @@ def parsed
# Attempts to determine the content type of the response.
def content_type
- return nil unless response.headers
+ return unless response.headers
- ((response.headers.values_at('content-type', 'Content-Type').compact.first || '').split(';').first || '').strip.downcase
+ ((response.headers.values_at("content-type", "Content-Type").compact.first || "").split(";").first || "").strip.downcase
end
# Determines the parser (a Proc or other Object which responds to #call)
@@ -133,16 +133,16 @@ def parser
end
end
-OAuth2::Response.register_parser(:xml, ['text/xml', 'application/rss+xml', 'application/rdf+xml', 'application/atom+xml', 'application/xml']) do |body|
+OAuth2::Response.register_parser(:xml, ["text/xml", "application/rss+xml", "application/rdf+xml", "application/atom+xml", "application/xml"]) do |body|
next body unless body.respond_to?(:to_str)
MultiXml.parse(body)
end
-OAuth2::Response.register_parser(:json, ['application/json', 'text/javascript', 'application/hal+json', 'application/vnd.collection+json', 'application/vnd.api+json', 'application/problem+json']) do |body|
+OAuth2::Response.register_parser(:json, ["application/json", "text/javascript", "application/hal+json", "application/vnd.collection+json", "application/vnd.api+json", "application/problem+json"]) do |body|
next body unless body.respond_to?(:to_str)
- body = body.dup.force_encoding(::Encoding::ASCII_8BIT) if body.respond_to?(:force_encoding)
+ body = body.dup.force_encoding(Encoding::ASCII_8BIT) if body.respond_to?(:force_encoding)
- ::JSON.parse(body)
+ JSON.parse(body)
end
diff --git a/lib/oauth2/strategy/assertion.rb b/lib/oauth2/strategy/assertion.rb
index 5d921fbc..800a4a78 100644
--- a/lib/oauth2/strategy/assertion.rb
+++ b/lib/oauth2/strategy/assertion.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'jwt'
+require "jwt"
module OAuth2
module Strategy
@@ -34,7 +34,7 @@ class Assertion < Base
#
# @raise [NotImplementedError]
def authorize_url
- raise(NotImplementedError, 'The authorization endpoint is not used in this strategy')
+ raise(NotImplementedError, "The authorization endpoint is not used in this strategy")
end
# Retrieve an access token given the specified client.
@@ -87,13 +87,13 @@ def get_token(claims, encoding_opts, request_opts = {}, response_opts = {})
def build_request(assertion, request_opts = {})
{
- grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
+ grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
assertion: assertion,
}.merge(request_opts)
end
def build_assertion(claims, encoding_opts)
- raise ArgumentError.new(message: 'Please provide an encoding_opts hash with :algorithm and :key') if !encoding_opts.is_a?(Hash) || (%i[algorithm key] - encoding_opts.keys).any?
+ raise ArgumentError.new(message: "Please provide an encoding_opts hash with :algorithm and :key") if !encoding_opts.is_a?(Hash) || (%i[algorithm key] - encoding_opts.keys).any?
JWT.encode(claims, encoding_opts[:key], encoding_opts[:algorithm])
end
diff --git a/lib/oauth2/strategy/auth_code.rb b/lib/oauth2/strategy/auth_code.rb
index f3aaad0a..96eedf5d 100644
--- a/lib/oauth2/strategy/auth_code.rb
+++ b/lib/oauth2/strategy/auth_code.rb
@@ -10,7 +10,7 @@ class AuthCode < Base
#
# @param [Hash] params additional query parameters
def authorize_params(params = {})
- params.merge('response_type' => 'code', 'client_id' => @client.id)
+ params.merge("response_type" => "code", "client_id" => @client.id)
end
# The authorization URL endpoint of the provider
@@ -28,7 +28,7 @@ def authorize_url(params = {})
# @param [Hash] opts access_token_opts, @see Client#get_token
# @note that you must also provide a :redirect_uri with most OAuth 2.0 providers
def get_token(code, params = {}, opts = {})
- params = {'grant_type' => 'authorization_code', 'code' => code}.merge(@client.redirection_params).merge(params)
+ params = {"grant_type" => "authorization_code", "code" => code}.merge(@client.redirection_params).merge(params)
params_dup = params.dup
params.each_key do |key|
params_dup[key.to_s] = params_dup.delete(key) if key.is_a?(Symbol)
@@ -40,7 +40,7 @@ def get_token(code, params = {}, opts = {})
private
def assert_valid_params(params)
- raise(ArgumentError, 'client_secret is not allowed in authorize URL query params') if params.key?(:client_secret) || params.key?('client_secret')
+ raise(ArgumentError, "client_secret is not allowed in authorize URL query params") if params.key?(:client_secret) || params.key?("client_secret")
end
end
end
diff --git a/lib/oauth2/strategy/client_credentials.rb b/lib/oauth2/strategy/client_credentials.rb
index 2fba0e86..00a3ed80 100644
--- a/lib/oauth2/strategy/client_credentials.rb
+++ b/lib/oauth2/strategy/client_credentials.rb
@@ -10,7 +10,7 @@ class ClientCredentials < Base
#
# @raise [NotImplementedError]
def authorize_url
- raise(NotImplementedError, 'The authorization endpoint is not used in this strategy')
+ raise(NotImplementedError, "The authorization endpoint is not used in this strategy")
end
# Retrieve an access token given the specified client.
@@ -18,7 +18,7 @@ def authorize_url
# @param [Hash] params additional params
# @param [Hash] opts options
def get_token(params = {}, opts = {})
- params = params.merge('grant_type' => 'client_credentials')
+ params = params.merge("grant_type" => "client_credentials")
@client.get_token(params, opts)
end
end
diff --git a/lib/oauth2/strategy/implicit.rb b/lib/oauth2/strategy/implicit.rb
index 5e61d1d6..e9efe5c2 100644
--- a/lib/oauth2/strategy/implicit.rb
+++ b/lib/oauth2/strategy/implicit.rb
@@ -10,7 +10,7 @@ class Implicit < Base
#
# @param [Hash] params additional query parameters
def authorize_params(params = {})
- params.merge('response_type' => 'token', 'client_id' => @client.id)
+ params.merge("response_type" => "token", "client_id" => @client.id)
end
# The authorization URL endpoint of the provider
@@ -25,13 +25,13 @@ def authorize_url(params = {})
#
# @raise [NotImplementedError]
def get_token(*)
- raise(NotImplementedError, 'The token is accessed differently in this strategy')
+ raise(NotImplementedError, "The token is accessed differently in this strategy")
end
private
def assert_valid_params(params)
- raise(ArgumentError, 'client_secret is not allowed in authorize URL query params') if params.key?(:client_secret) || params.key?('client_secret')
+ raise(ArgumentError, "client_secret is not allowed in authorize URL query params") if params.key?(:client_secret) || params.key?("client_secret")
end
end
end
diff --git a/lib/oauth2/strategy/password.rb b/lib/oauth2/strategy/password.rb
index d41ca07a..79acf654 100644
--- a/lib/oauth2/strategy/password.rb
+++ b/lib/oauth2/strategy/password.rb
@@ -10,7 +10,7 @@ class Password < Base
#
# @raise [NotImplementedError]
def authorize_url
- raise(NotImplementedError, 'The authorization endpoint is not used in this strategy')
+ raise(NotImplementedError, "The authorization endpoint is not used in this strategy")
end
# Retrieve an access token given the specified End User username and password.
@@ -19,9 +19,11 @@ def authorize_url
# @param [String] password the End User password
# @param [Hash] params additional params
def get_token(username, password, params = {}, opts = {})
- params = {'grant_type' => 'password',
- 'username' => username,
- 'password' => password}.merge(params)
+ params = {
+ "grant_type" => "password",
+ "username" => username,
+ "password" => password,
+ }.merge(params)
@client.get_token(params, opts)
end
end
diff --git a/lib/oauth2/version.rb b/lib/oauth2/version.rb
index c4c3e3bd..42e2e99c 100644
--- a/lib/oauth2/version.rb
+++ b/lib/oauth2/version.rb
@@ -2,6 +2,6 @@
module OAuth2
module Version
- VERSION = '2.0.10'.freeze
+ VERSION = "2.0.10"
end
end
diff --git a/oauth2.gemspec b/oauth2.gemspec
index 9e08984e..9c77ef34 100644
--- a/oauth2.gemspec
+++ b/oauth2.gemspec
@@ -1,30 +1,46 @@
# encoding: utf-8
# frozen_string_literal: true
-require_relative 'lib/oauth2/version'
+gem_version =
+ if RUBY_VERSION >= "3.1"
+ # Loading version into an anonymous module allows version.rb to get code coverage from SimpleCov!
+ # See: https://github.com/simplecov-ruby/simplecov/issues/557#issuecomment-2630782358
+ Module.new.tap { |mod| Kernel.load("lib/oauth2/version.rb", mod) }::OAuth2::Version::VERSION
+ else
+ lib = File.expand_path("lib", __dir__)
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
+ require "oauth2/version"
+ OAuth2::Version::VERSION
+ end
Gem::Specification.new do |spec|
- spec.add_dependency 'faraday', ['>= 0.17.3', '< 3.0']
- spec.add_dependency 'jwt', ['>= 1.0', '< 3.0']
- spec.add_dependency 'multi_xml', '~> 0.5'
- spec.add_dependency 'rack', ['>= 1.2', '< 4']
- spec.add_dependency 'snaky_hash', '~> 2.0'
- spec.add_dependency 'version_gem', '~> 1.1'
+ # Linux distros may package ruby gems differently,
+ # and securely certify them independently via alternate package management systems.
+ # Ref: https://gitlab.com/oauth-xx/version_gem/-/issues/3
+ # Hence, only enable signing if the cert_file is present.
+ # See CONTRIBUTING.md
+ default_user_cert = "certs/#{ENV.fetch("GEM_CERT_USER", ENV["USER"])}.pem"
+ default_user_cert_path = File.join(__dir__, default_user_cert)
+ cert_file_path = ENV.fetch("GEM_CERT_PATH", default_user_cert_path)
+ cert_chain = cert_file_path.split(",")
+ if cert_file_path && cert_chain.map { |fp| File.exist?(fp) }
+ spec.cert_chain = cert_chain
+ if $PROGRAM_NAME.end_with?("gem", "rake") && ARGV[0] == "build"
+ spec.signing_key = File.expand_path("~/.ssh/gem-private_key.pem")
+ end
+ end
- spec.cert_chain = ['certs/pboling.pem']
- spec.signing_key = File.expand_path('~/.ssh/gem-private_key.pem') if $PROGRAM_NAME.end_with?('gem')
-
- spec.authors = ['Peter Boling', 'Erik Michaels-Ober', 'Michael Bleigh']
- spec.summary = 'OAuth 2.0 Core Ruby implementation'
- spec.description = 'A Ruby wrapper for the OAuth 2.0 protocol built with a similar style to the original OAuth spec.'
- spec.email = ['peter.boling@gmail.com', 'oauth-ruby@googlegroups.com']
- spec.homepage = 'https://gitlab.com/oauth-xx/oauth2'
- spec.licenses = 'MIT'
- spec.name = 'oauth2'
- spec.required_ruby_version = '>= 2.2.0'
- spec.version = OAuth2::Version::VERSION
- spec.post_install_message = "
-You have installed oauth2 version #{OAuth2::Version::VERSION}, congratulations!
+ spec.authors = ["Peter Boling", "Erik Michaels-Ober", "Michael Bleigh"]
+ spec.summary = "OAuth 2.0 Core Ruby implementation"
+ spec.description = "A Ruby wrapper for the OAuth 2.0 protocol built with a similar style to the original OAuth spec."
+ spec.email = ["peter.boling@gmail.com", "oauth-ruby@googlegroups.com"]
+ spec.homepage = "https://gitlab.com/oauth-xx/oauth2"
+ spec.licenses = "MIT"
+ spec.name = "oauth2"
+ spec.required_ruby_version = ">= 2.2.0"
+ spec.version = gem_version
+ spec.post_install_message = %{
+You have installed oauth2 version #{gem_version}, congratulations!
There are BREAKING changes if you are upgrading from < v2, but most will not encounter them, and updating your code should be easy!
Please see:
@@ -32,64 +48,88 @@ Please see:
• #{spec.homepage}/-/blob/v#{spec.version}/CHANGELOG.md#200-2022-06-21-tag
• Summary of most important breaking changes: #{spec.homepage}#what-is-new-for-v20
-Major updates:
-1. master branch renamed to main
-• Update your local: git checkout master; git branch -m master main; git branch --unset-upstream; git branch -u origin/main
-2. Github has been replaced with Gitlab; I wrote about some of the reasons here:
-• https://dev.to/galtzo/im-leaving-github-50ba
-• Update your local: git remote set-url origin git@gitlab.com:oauth-xx/oauth2.git
-3. Google Group is active (again)!
+There are BUGFIXES in v2.0.10, which depending on how you relied on them instead of reporting and fixing them, may be BREAKING for you.
+For more information please see:
+https://railsbling.com/tags/oauth2
+
+Important News:
+1. Google Group is "active" (again)!
• https://groups.google.com/g/oauth-ruby/c/QA_dtrXWXaE
-4. Gitter Chat is active (still)!
-• https://gitter.im/oauth-xx/
-5. Non-commercial support for the 2.x series will end by April, 2024. Please make a plan to upgrade to the next version prior to that date.
-Support will be dropped for Ruby 2.2, 2.3, 2.4, 2.5, 2.6, 2.7 and any other Ruby versions which will also have reached EOL by then.
-6. Gem releases are now cryptographically signed for security.
+2. Non-commercial support for the 2.x series will end by April, 2026. Please make a plan to upgrade to the next version prior to that date.
+Support will be dropped for Ruby 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 3.0, 3.1 and any other Ruby versions which will also have reached EOL by then.
+3. Gem releases are now cryptographically signed with a 20-year cert, with checksums by stone_checksums.
+4. I need your support.
-If you are a human, please consider a donation as I move toward supporting myself with Open Source work:
+If you are sentient, please consider a donation as I move toward supporting myself with Open Source work:
• https://liberapay.com/pboling
• https://ko-fi.com/pboling
-• https://patreon.com/galtzo
+• https://www.buymeacoffee.com/pboling
+• https://github.com/sponsors/pboling
If you are a corporation, please consider supporting this project, and open source work generally, with a TideLift subscription.
• https://tidelift.com/funding/github/rubygems/oauth
• Or hire me. I am looking for a job!
-Please report issues, and support the project!
+Please report issues, and star the project!
Thanks, |7eter l-|. l3oling
-"
+}
- spec.metadata['homepage_uri'] = spec.homepage
- spec.metadata['source_code_uri'] = "#{spec.homepage}/-/tree/v#{spec.version}"
- spec.metadata['changelog_uri'] = "#{spec.homepage}/-/blob/v#{spec.version}/CHANGELOG.md"
- spec.metadata['bug_tracker_uri'] = "#{spec.homepage}/-/issues"
- spec.metadata['documentation_uri'] = "https://www.rubydoc.info/gems/#{spec.name}/#{spec.version}"
- spec.metadata['wiki_uri'] = "#{spec.homepage}/-/wiki"
- spec.metadata['mailing_list_uri'] = 'https://groups.google.com/g/oauth-ruby'
- spec.metadata['funding_uri'] = 'https://liberapay.com/pboling'
- spec.metadata['rubygems_mfa_required'] = 'true'
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = "#{spec.homepage}/-/tree/v#{spec.version}"
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/-/blob/v#{spec.version}/CHANGELOG.md"
+ spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/-/issues"
+ spec.metadata["documentation_uri"] = "https://www.rubydoc.info/gems/#{spec.name}/#{spec.version}"
+ spec.metadata["wiki_uri"] = "#{spec.homepage}/-/wiki"
+ spec.metadata["mailing_list_uri"] = "https://groups.google.com/g/oauth-ruby"
+ spec.metadata["news_uri"] = "https://www.railsbling.com/tags/#{spec.name}"
+ spec.metadata["funding_uri"] = "https://liberapay.com/pboling"
+ spec.metadata["rubygems_mfa_required"] = "true"
- spec.require_paths = %w[lib]
+ # Specify which files should be added to the gem when it is released.
spec.files = Dir[
- 'lib/**/*',
- 'CHANGELOG.md',
- 'CODE_OF_CONDUCT.md',
- 'CONTRIBUTING.md',
- 'LICENSE.txt',
- 'README.md',
- 'SECURITY.md',
+ # Splats (alphabetical)
+ "lib/**/*",
+ ]
+ # Automatically included with gem package, no need to list again in files.
+ spec.extra_rdoc_files = Dir[
+ # Files (alphabetical)
+ "CHANGELOG.md",
+ "CODE_OF_CONDUCT.md",
+ "CONTRIBUTING.md",
+ "LICENSE.txt",
+ "README.md",
+ "SECURITY.md",
]
+ spec.rdoc_options += [
+ "--title",
+ "#{spec.name} - #{spec.summary}",
+ "--main",
+ "README.md",
+ "--line-numbers",
+ "--inline-source",
+ "--quiet",
+ ]
+ spec.require_paths = ["lib"]
+ spec.bindir = "exe"
+ spec.executables = []
+
+ spec.add_dependency("faraday", [">= 0.17.3", "< 3.0"])
+ spec.add_dependency("jwt", [">= 1.0", "< 3.0"])
+ spec.add_dependency("multi_xml", "~> 0.5")
+ spec.add_dependency("rack", [">= 1.2", "< 4"])
+ spec.add_dependency("snaky_hash", "~> 2.0")
+ spec.add_dependency("version_gem", ">= 1.1.8", "< 3") # Ruby >= 2.2.0
- spec.add_development_dependency 'addressable', '>= 2'
- spec.add_development_dependency 'backports', '>= 3'
- spec.add_development_dependency 'bundler', '>= 2'
- spec.add_development_dependency 'rake', '>= 12'
- spec.add_development_dependency 'rexml', '>= 3'
- spec.add_development_dependency 'rspec', '>= 3'
- spec.add_development_dependency 'rspec-block_is_expected'
- spec.add_development_dependency 'rspec-pending_for'
- spec.add_development_dependency 'rspec-stubbed_env'
- spec.add_development_dependency 'rubocop-lts', '~> 8.0'
- spec.add_development_dependency 'silent_stream'
+ spec.add_development_dependency("addressable", ">= 2")
+ spec.add_development_dependency("backports", ">= 3")
+ spec.add_development_dependency("nkf", "~> 0.2")
+ spec.add_development_dependency("rake", ">= 12")
+ spec.add_development_dependency("rexml", ">= 3")
+ spec.add_development_dependency("rspec", ">= 3")
+ spec.add_development_dependency("rspec-block_is_expected")
+ spec.add_development_dependency("rspec-pending_for")
+ spec.add_development_dependency("rspec-stubbed_env")
+ spec.add_development_dependency("rubocop-lts", "~> 8.0")
+ spec.add_development_dependency("silent_stream")
end
diff --git a/spec/config/constants.rb b/spec/config/constants.rb
new file mode 100644
index 00000000..0c1b205b
--- /dev/null
+++ b/spec/config/constants.rb
@@ -0,0 +1 @@
+VERBS = %i[get post put delete patch].freeze
diff --git a/spec/config/debug.rb b/spec/config/debug.rb
new file mode 100644
index 00000000..140b10e3
--- /dev/null
+++ b/spec/config/debug.rb
@@ -0,0 +1,5 @@
+load_debugger = ENV.fetch("DEBUG", "false").casecmp("true") == 0
+
+puts "LOADING DEBUGGER: #{load_debugger}" if load_debugger
+
+require "debug" if load_debugger
diff --git a/spec/config/faraday.rb b/spec/config/faraday.rb
index 2051ebb1..e9158898 100644
--- a/spec/config/faraday.rb
+++ b/spec/config/faraday.rb
@@ -1,3 +1,5 @@
# frozen_string_literal: true
+require "faraday"
+
Faraday.default_adapter = :test
diff --git a/spec/config/multi_xml.rb b/spec/config/multi_xml.rb
index 2d788eb5..8d579c28 100644
--- a/spec/config/multi_xml.rb
+++ b/spec/config/multi_xml.rb
@@ -1,3 +1,5 @@
# frozen_string_literal: true
+require "multi_xml"
+
MultiXml.parser = :rexml
diff --git a/spec/config/rspec/rspec_core.rb b/spec/config/rspec/rspec_core.rb
index 7ee40059..b960d8c0 100644
--- a/spec/config/rspec/rspec_core.rb
+++ b/spec/config/rspec/rspec_core.rb
@@ -2,7 +2,7 @@
RSpec.configure do |config|
# Enable flags like --only-failures and --next-failure
- config.example_status_persistence_file_path = '.rspec_status'
+ config.example_status_persistence_file_path = ".rspec_status"
# Disable RSpec exposing methods globally on `Module` and `main`
config.disable_monkey_patching!
diff --git a/spec/examples/google_spec.rb b/spec/examples/google_spec.rb
index cf1aa7ee..425abb07 100644
--- a/spec/examples/google_spec.rb
+++ b/spec/examples/google_spec.rb
@@ -1,20 +1,20 @@
# frozen_string_literal: true
-require 'jwt'
+require "jwt"
-RSpec.describe 'using OAuth2 with Google' do
+RSpec.describe "using OAuth2 with Google" do
# This describes authenticating to a Google API via a service account.
# See their docs: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
- describe 'via 2-legged JWT assertion' do
+ describe "via 2-legged JWT assertion" do
let(:client) do
OAuth2::Client.new(
- '',
- '',
- site: 'https://accounts.google.com',
- authorize_url: '/o/oauth2/auth',
- token_url: '/o/oauth2/token',
- auth_scheme: :request_body
+ "",
+ "",
+ site: "https://accounts.google.com",
+ authorize_url: "/o/oauth2/auth",
+ token_url: "/o/oauth2/token",
+ auth_scheme: :request_body,
)
end
@@ -22,38 +22,38 @@
let(:required_claims) do
{
- 'iss' => '761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com',
+ "iss" => "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
# The email address of the service account.
- 'scope' => 'https://www.googleapis.com/auth/devstorage.readonly https://www.googleapis.com/auth/prediction',
+ "scope" => "https://www.googleapis.com/auth/devstorage.readonly https://www.googleapis.com/auth/prediction",
# A space-delimited list of the permissions that the application requests.
- 'aud' => 'https://www.googleapis.com/oauth2/v4/token',
+ "aud" => "https://www.googleapis.com/oauth2/v4/token",
# A descriptor of the intended target of the assertion. When making an access token request this value
# is always https://www.googleapis.com/oauth2/v4/token.
- 'exp' => Time.now.to_i + 3600,
+ "exp" => Time.now.to_i + 3600,
# The expiration time of the assertion, specified as seconds since 00:00:00 UTC, January 1, 1970. This value
# has a maximum of 1 hour after the issued time.
- 'iat' => Time.now.to_i,
+ "iat" => Time.now.to_i,
# The time the assertion was issued, specified as seconds since 00:00:00 UTC, January 1, 1970.
}
end
let(:optional_claims) do
{
- 'sub' => 'some.user@example.com',
+ "sub" => "some.user@example.com",
# The email address of the user for which the application is requesting delegated access.
}
end
- let(:algorithm) { 'RS256' }
+ let(:algorithm) { "RS256" }
# Per Google: "Service accounts rely on the RSA SHA-256 algorithm"
let(:key) do
begin
- OpenSSL::PKCS12.new(File.read('spec/fixtures/google_service_account_key.p12'), 'notasecret').key
+ OpenSSL::PKCS12.new(File.read("spec/fixtures/google_service_account_key.p12"), "notasecret").key
# This simulates the .p12 file that Google gives you to download and keep somewhere. This is meant to
# illustrate extracting the key and using it to generate the JWT.
rescue OpenSSL::PKCS12::PKCS12Error
@@ -73,20 +73,20 @@
client.connection = Faraday.new(client.site, client.options[:connection_opts]) do |builder|
builder.request :url_encoded
builder.adapter :test do |stub|
- stub.post('https://accounts.google.com/o/oauth2/token') do |token_request|
+ stub.post("https://accounts.google.com/o/oauth2/token") do |token_request|
@request_body = Rack::Utils.parse_nested_query(token_request.body).transform_keys(&:to_sym)
[
200,
{
- 'Content-Type' => 'application/json',
+ "Content-Type" => "application/json",
},
{
- 'access_token' => '1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M',
- 'token_type' => 'Bearer',
- 'expires_in' => 3600,
+ "access_token" => "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M",
+ "token_type" => "Bearer",
+ "expires_in" => 3600,
}.to_json,
]
end
@@ -94,18 +94,18 @@
end
end
- context 'when passing the required claims' do
+ context "when passing the required claims" do
let(:claims) { required_claims }
- it 'sends a JWT with the 5 keys' do
+ it "sends a JWT with the 5 keys" do
client.assertion.get_token(claims, encoding_options)
- expect(@request_body).not_to be_nil, 'No access token request was made!'
- expect(@request_body[:grant_type]).to eq('urn:ietf:params:oauth:grant-type:jwt-bearer')
+ expect(@request_body).not_to be_nil, "No access token request was made!"
+ expect(@request_body[:grant_type]).to eq("urn:ietf:params:oauth:grant-type:jwt-bearer")
expect(@request_body[:assertion]).to be_a(String)
payload, header = JWT.decode(@request_body[:assertion], key, true, algorithm: algorithm)
- expect(header['alg']).to eq('RS256')
+ expect(header["alg"]).to eq("RS256")
expect(payload.keys).to match_array(%w[iss scope aud exp iat])
# Note that these specifically do _not_ include the 'sub' claim, which is indicated as being 'required'
@@ -118,18 +118,18 @@
end
end
- context 'when including the optional `sub` claim' do
+ context "when including the optional `sub` claim" do
let(:claims) { required_claims.merge(optional_claims) }
- it 'sends a JWT with the 6 keys' do
+ it "sends a JWT with the 6 keys" do
client.assertion.get_token(claims, encoding_options)
- expect(@request_body).not_to be_nil, 'No access token request was made!'
- expect(@request_body[:grant_type]).to eq('urn:ietf:params:oauth:grant-type:jwt-bearer')
+ expect(@request_body).not_to be_nil, "No access token request was made!"
+ expect(@request_body[:grant_type]).to eq("urn:ietf:params:oauth:grant-type:jwt-bearer")
expect(@request_body[:assertion]).to be_a(String)
payload, header = JWT.decode(@request_body[:assertion], key, true, algorithm: algorithm)
- expect(header['alg']).to eq('RS256')
+ expect(header["alg"]).to eq("RS256")
expect(payload.keys).to match_array(%w[iss scope aud exp iat sub])
payload.each do |key, value|
diff --git a/spec/ext/backports.rb b/spec/ext/backports.rb
index 5811858b..21f76e1c 100644
--- a/spec/ext/backports.rb
+++ b/spec/ext/backports.rb
@@ -1,3 +1,3 @@
# frozen_string_literal: true
-require 'backports/2.5.0/hash/transform_keys'
+require "backports/2.5.0/hash/transform_keys"
diff --git a/spec/oauth2/access_token_spec.rb b/spec/oauth2/access_token_spec.rb
index ae828fa2..8c1ef0a5 100644
--- a/spec/oauth2/access_token_spec.rb
+++ b/spec/oauth2/access_token_spec.rb
@@ -3,57 +3,57 @@
RSpec.describe OAuth2::AccessToken do
subject { described_class.new(client, token) }
- let(:base_options) { {site: 'https://api.example.com'} }
+ let(:base_options) { {site: "https://api.example.com"} }
let(:options) { {} }
- let(:token) { 'monkey' }
- let(:refresh_body) { JSON.dump(access_token: 'refreshed_foo', expires_in: 600, refresh_token: 'refresh_bar') }
+ let(:token) { "monkey" }
+ let(:refresh_body) { JSON.dump(access_token: "refreshed_foo", expires_in: 600, refresh_token: "refresh_bar") }
let(:client) do
- OAuth2::Client.new('abc', 'def', options.merge(base_options)) do |builder|
+ OAuth2::Client.new("abc", "def", options.merge(base_options)) do |builder|
builder.request :url_encoded
builder.adapter :test do |stub|
VERBS.each do |verb|
- stub.send(verb, '/token/header') { |env| [200, {}, env[:request_headers]['Authorization']] }
- stub.send(verb, "/token/query?access_token=#{token}") { |env| [200, {}, Addressable::URI.parse(env[:url]).query_values['access_token']] }
- stub.send(verb, '/token/query_string') { |env| [200, {}, CGI.unescape(Addressable::URI.parse(env[:url]).query)] }
- stub.send(verb, '/token/body') { |env| [200, {}, env[:body]] }
+ stub.send(verb, "/token/header") { |env| [200, {}, env[:request_headers]["Authorization"]] }
+ stub.send(verb, "/token/query?access_token=#{token}") { |env| [200, {}, Addressable::URI.parse(env[:url]).query_values["access_token"]] }
+ stub.send(verb, "/token/query_string") { |env| [200, {}, CGI.unescape(Addressable::URI.parse(env[:url]).query)] }
+ stub.send(verb, "/token/body") { |env| [200, {}, env[:body]] }
end
- stub.post('/oauth/token') { |_env| [200, {'Content-Type' => 'application/json'}, refresh_body] }
+ stub.post("/oauth/token") { |_env| [200, {"Content-Type" => "application/json"}, refresh_body] }
end
end
end
- describe '.from_hash' do
+ describe ".from_hash" do
subject(:target) { described_class.from_hash(client, hash) }
let(:hash) do
{
:access_token => token,
- :id_token => 'confusing bug here',
- :refresh_token => 'foobar',
+ :id_token => "confusing bug here",
+ :refresh_token => "foobar",
:expires_at => Time.now.to_i + 200,
- 'foo' => 'bar',
+ "foo" => "bar",
}
end
- it 'return a hash equals to the hash used to initialize access token' do
+ it "return a hash equals to the hash used to initialize access token" do
expect(target.to_hash).to eq(hash)
end
- context 'with warning for too many tokens' do
+ context "with warning for too many tokens" do
subject(:printed) do
capture(:stderr) do
target
end
end
- it 'warns on STDERR' do
+ it "warns on STDERR" do
msg = <<-MSG.lstrip
OAuth2::AccessToken.from_hash: `hash` contained more than one 'token' key ([:access_token, :id_token]); using :access_token.
MSG
expect(printed).to eq(msg)
end
- context 'when silenced' do
+ context "when silenced" do
subject(:printed) do
capture(:stderr) do
target
@@ -72,13 +72,13 @@
end
end
- it 'does not warn on STDERR' do
- expect(printed).to eq('')
+ it "does not warn on STDERR" do
+ expect(printed).to eq("")
end
end
end
- context 'with keys in a different order to the lookup' do
+ context "with keys in a different order to the lookup" do
subject(:printed) do
capture(:stderr) do
target
@@ -87,12 +87,12 @@
let(:hash) do
{
- id_token: 'confusing bug here',
+ id_token: "confusing bug here",
access_token: token,
}
end
- it 'warns on STDERR and selects the correct key' do
+ it "warns on STDERR and selects the correct key" do
msg = <<-MSG.lstrip
OAuth2::AccessToken.from_hash: `hash` contained more than one 'token' key ([:access_token, :id_token]); using :access_token.
MSG
@@ -101,96 +101,96 @@
end
end
- describe '#initialize' do
- it 'assigns client and token' do
+ describe "#initialize" do
+ it "assigns client and token" do
expect(subject.client).to eq(client)
expect(subject.token).to eq(token)
end
- it 'assigns extra params' do
- target = described_class.new(client, token, 'foo' => 'bar')
- expect(target.params).to include('foo')
- expect(target.params['foo']).to eq('bar')
+ it "assigns extra params" do
+ target = described_class.new(client, token, "foo" => "bar")
+ expect(target.params).to include("foo")
+ expect(target.params["foo"]).to eq("bar")
end
def assert_initialized_token(target)
expect(target.token).to eq(token)
expect(target).to be_expires
- expect(target.params.keys).to include('foo')
- expect(target.params['foo']).to eq('bar')
+ expect(target.params.keys).to include("foo")
+ expect(target.params["foo"]).to eq("bar")
end
- it 'initializes with a Hash' do
- hash = {:access_token => token, :expires_at => Time.now.to_i + 200, 'foo' => 'bar'}
+ it "initializes with a Hash" do
+ hash = {:access_token => token, :expires_at => Time.now.to_i + 200, "foo" => "bar"}
target = described_class.from_hash(client, hash)
assert_initialized_token(target)
end
- it 'from_hash does not modify opts hash' do
+ it "from_hash does not modify opts hash" do
hash = {access_token: token, expires_at: Time.now.to_i}
hash_before = hash.dup
described_class.from_hash(client, hash)
expect(hash).to eq(hash_before)
end
- it 'initializes with a form-urlencoded key/value string' do
+ it "initializes with a form-urlencoded key/value string" do
kvform = "access_token=#{token}&expires_at=#{Time.now.to_i + 200}&foo=bar"
target = described_class.from_kvform(client, kvform)
assert_initialized_token(target)
end
- context 'with options' do
+ context "with options" do
subject(:target) { described_class.new(client, token, **options) }
- context 'with body mode' do
+ context "with body mode" do
let(:mode) { :body }
- let(:options) { {param_name: 'foo', header_format: 'Bearer %', mode: mode} }
+ let(:options) { {param_name: "foo", header_format: "Bearer %", mode: mode} }
- it 'sets options' do
- expect(target.options[:param_name]).to eq('foo')
- expect(target.options[:header_format]).to eq('Bearer %')
+ it "sets options" do
+ expect(target.options[:param_name]).to eq("foo")
+ expect(target.options[:header_format]).to eq("Bearer %")
expect(target.options[:mode]).to eq(mode)
end
end
- context 'with header mode' do
+ context "with header mode" do
let(:mode) { :header }
let(:options) { {headers: {}, mode: mode} }
- it 'sets options' do
+ it "sets options" do
expect(target.options[:headers]).to be_nil
expect(target.options[:mode]).to eq(mode)
end
end
- context 'with query mode' do
+ context "with query mode" do
let(:mode) { :query }
- let(:options) { {params: {}, param_name: 'foo', mode: mode} }
+ let(:options) { {params: {}, param_name: "foo", mode: mode} }
- it 'sets options' do
- expect(target.options[:param_name]).to eq('foo')
+ it "sets options" do
+ expect(target.options[:param_name]).to eq("foo")
expect(target.options[:params]).to be_nil
expect(target.options[:mode]).to eq(mode)
end
end
- context 'with invalid mode' do
+ context "with invalid mode" do
let(:mode) { :this_is_bad }
let(:options) { {mode: mode} }
- it 'does not raise on initialize' do
+ it "does not raise on initialize" do
block_is_expected.not_to raise_error
end
- context 'with request' do
- subject(:request) { target.post('/token/header') }
+ context "with request" do
+ subject(:request) { target.post("/token/header") }
- it 'raises' do
+ it "raises" do
block_is_expected.to raise_error("invalid :mode option of #{mode}")
end
end
- context 'with client.options[:raise_errors] = true' do
+ context "with client.options[:raise_errors] = true" do
let(:mode) { :this_is_bad }
let(:options) { {mode: mode, raise_errors: true} }
@@ -198,101 +198,101 @@ def assert_initialized_token(target)
expect(client.options[:raise_errors]).to be(true)
end
- context 'when there is a token' do
- it 'does not raise on initialize' do
+ context "when there is a token" do
+ it "does not raise on initialize" do
block_is_expected.not_to raise_error
end
- context 'with request' do
- subject(:request) { target.post('/token/header') }
+ context "with request" do
+ subject(:request) { target.post("/token/header") }
- it 'raises' do
+ it "raises" do
block_is_expected.to raise_error("invalid :mode option of #{mode}")
end
end
end
- context 'when there is empty token' do
- let(:token) { '' }
+ context "when there is empty token" do
+ let(:token) { "" }
- it 'raises on initialize' do
- block_is_expected.to raise_error(OAuth2::Error, '{:mode=>:this_is_bad, :raise_errors=>true}')
+ it "raises on initialize" do
+ block_is_expected.to raise_error(OAuth2::Error, {mode: :this_is_bad, raise_errors: true}.to_s)
end
end
- context 'when there is nil token' do
+ context "when there is nil token" do
let(:token) { nil }
- it 'raises on initialize' do
- block_is_expected.to raise_error(OAuth2::Error, '{:mode=>:this_is_bad, :raise_errors=>true}')
+ it "raises on initialize" do
+ block_is_expected.to raise_error(OAuth2::Error, {mode: :this_is_bad, raise_errors: true}.to_s)
end
end
end
end
- context 'with client.options[:raise_errors] = false' do
+ context "with client.options[:raise_errors] = false" do
let(:options) { {raise_errors: false} }
before do
expect(client.options[:raise_errors]).to be(false)
end
- context 'when there is a token' do
- let(:token) { 'hurdygurdy' }
+ context "when there is a token" do
+ let(:token) { "hurdygurdy" }
- it 'does not raise on initialize' do
+ it "does not raise on initialize" do
block_is_expected.not_to raise_error
end
- it 'has token' do
+ it "has token" do
expect(target.token).to eq(token)
end
- it 'has no refresh_token' do
+ it "has no refresh_token" do
expect(target.refresh_token).to be_nil
end
- context 'when there is refresh_token' do
- let(:options) { {raise_errors: false, refresh_token: 'zxcv'} }
+ context "when there is refresh_token" do
+ let(:options) { {raise_errors: false, refresh_token: "zxcv"} }
- it 'does not raise on initialize' do
+ it "does not raise on initialize" do
block_is_expected.not_to raise_error
end
- it 'has token' do
+ it "has token" do
expect(target.token).to eq(token)
end
- it 'has refresh_token' do
- expect(target.refresh_token).to eq('zxcv')
+ it "has refresh_token" do
+ expect(target.refresh_token).to eq("zxcv")
end
end
end
- context 'when there is empty token' do
- let(:token) { '' }
+ context "when there is empty token" do
+ let(:token) { "" }
- context 'when there is no refresh_token' do
- it 'does not raise on initialize' do
+ context "when there is no refresh_token" do
+ it "does not raise on initialize" do
block_is_expected.not_to raise_error
end
- it 'has no token' do
- expect(target.token).to eq('')
+ it "has no token" do
+ expect(target.token).to eq("")
end
- it 'has no refresh_token' do
+ it "has no refresh_token" do
expect(target.refresh_token).to be_nil
end
- context 'with warning for no token' do
+ context "with warning for no token" do
subject(:printed) do
capture(:stderr) do
target
end
end
- it 'warns on STDERR' do
+ it "warns on STDERR" do
msg = <<-MSG.lstrip
OAuth2::AccessToken has no token
MSG
@@ -301,47 +301,47 @@ def assert_initialized_token(target)
end
end
- context 'when there is refresh_token' do
- let(:options) { {raise_errors: false, refresh_token: 'qwer'} }
+ context "when there is refresh_token" do
+ let(:options) { {raise_errors: false, refresh_token: "qwer"} }
- it 'does not raise on initialize' do
+ it "does not raise on initialize" do
block_is_expected.not_to raise_error
end
- it 'has no token' do
- expect(target.token).to eq('')
+ it "has no token" do
+ expect(target.token).to eq("")
end
- it 'has refresh_token' do
- expect(target.refresh_token).to eq('qwer')
+ it "has refresh_token" do
+ expect(target.refresh_token).to eq("qwer")
end
end
end
- context 'when there is nil token' do
+ context "when there is nil token" do
let(:token) { nil }
- context 'when there is no refresh_token' do
- it 'does not raise on initialize' do
+ context "when there is no refresh_token" do
+ it "does not raise on initialize" do
block_is_expected.not_to raise_error
end
- it 'has no token' do
- expect(target.token).to eq('')
+ it "has no token" do
+ expect(target.token).to eq("")
end
- it 'has no refresh_token' do
+ it "has no refresh_token" do
expect(target.refresh_token).to be_nil
end
- context 'with warning for no token' do
+ context "with warning for no token" do
subject(:printed) do
capture(:stderr) do
target
end
end
- it 'warns on STDERR' do
+ it "warns on STDERR" do
msg = <<-MSG.lstrip
OAuth2::AccessToken has no token
MSG
@@ -350,154 +350,154 @@ def assert_initialized_token(target)
end
end
- context 'when there is refresh_token' do
- let(:options) { {raise_errors: false, refresh_token: 'asdf'} }
+ context "when there is refresh_token" do
+ let(:options) { {raise_errors: false, refresh_token: "asdf"} }
- it 'does not raise on initialize' do
+ it "does not raise on initialize" do
block_is_expected.not_to raise_error
end
- it 'has no token' do
- expect(target.token).to eq('')
+ it "has no token" do
+ expect(target.token).to eq("")
end
- it 'has refresh_token' do
- expect(target.refresh_token).to eq('asdf')
+ it "has refresh_token" do
+ expect(target.refresh_token).to eq("asdf")
end
end
end
end
- context 'with client.options[:raise_errors] = true' do
+ context "with client.options[:raise_errors] = true" do
let(:options) { {raise_errors: true} }
before do
expect(client.options[:raise_errors]).to be(true)
end
- context 'when there is a token' do
- let(:token) { 'hurdygurdy' }
+ context "when there is a token" do
+ let(:token) { "hurdygurdy" }
- it 'does not raise on initialize' do
+ it "does not raise on initialize" do
block_is_expected.not_to raise_error
end
- it 'has token' do
+ it "has token" do
expect(target.token).to eq(token)
end
- it 'has no refresh_token' do
+ it "has no refresh_token" do
expect(target.refresh_token).to be_nil
end
- context 'when there is refresh_token' do
- let(:options) { {raise_errors: true, refresh_token: 'zxcv'} }
+ context "when there is refresh_token" do
+ let(:options) { {raise_errors: true, refresh_token: "zxcv"} }
- it 'does not raise on initialize' do
+ it "does not raise on initialize" do
block_is_expected.not_to raise_error
end
- it 'has token' do
+ it "has token" do
expect(target.token).to eq(token)
end
- it 'has refresh_token' do
- expect(target.refresh_token).to eq('zxcv')
+ it "has refresh_token" do
+ expect(target.refresh_token).to eq("zxcv")
end
end
end
- context 'when there is empty token' do
- let(:token) { '' }
+ context "when there is empty token" do
+ let(:token) { "" }
- context 'when there is no refresh_token' do
- it 'raises on initialize' do
- block_is_expected.to raise_error(OAuth2::Error, '{:raise_errors=>true}')
+ context "when there is no refresh_token" do
+ it "raises on initialize" do
+ block_is_expected.to raise_error(OAuth2::Error, {raise_errors: true}.to_s)
end
end
- context 'when there is refresh_token' do
- let(:options) { {raise_errors: true, refresh_token: 'qwer'} }
+ context "when there is refresh_token" do
+ let(:options) { {raise_errors: true, refresh_token: "qwer"} }
- it 'does not raise on initialize' do
+ it "does not raise on initialize" do
block_is_expected.not_to raise_error
end
- it 'has no token' do
- expect(target.token).to eq('')
+ it "has no token" do
+ expect(target.token).to eq("")
end
- it 'has refresh_token' do
- expect(target.refresh_token).to eq('qwer')
+ it "has refresh_token" do
+ expect(target.refresh_token).to eq("qwer")
end
end
end
- context 'when there is nil token' do
+ context "when there is nil token" do
let(:token) { nil }
- context 'when there is no refresh_token' do
- it 'raises on initialize' do
- block_is_expected.to raise_error(OAuth2::Error, '{:raise_errors=>true}')
+ context "when there is no refresh_token" do
+ it "raises on initialize" do
+ block_is_expected.to raise_error(OAuth2::Error, {raise_errors: true}.to_s)
end
end
- context 'when there is refresh_token' do
- let(:options) { {raise_errors: true, refresh_token: 'asdf'} }
+ context "when there is refresh_token" do
+ let(:options) { {raise_errors: true, refresh_token: "asdf"} }
- it 'does not raise on initialize' do
+ it "does not raise on initialize" do
block_is_expected.not_to raise_error
end
- it 'has no token' do
- expect(target.token).to eq('')
+ it "has no token" do
+ expect(target.token).to eq("")
end
- it 'has refresh_token' do
- expect(target.refresh_token).to eq('asdf')
+ it "has refresh_token" do
+ expect(target.refresh_token).to eq("asdf")
end
end
end
end
end
- it 'does not modify opts hash' do
- opts = {param_name: 'foo', header_format: 'Bearer %', mode: :body}
+ it "does not modify opts hash" do
+ opts = {param_name: "foo", header_format: "Bearer %", mode: :body}
opts_before = opts.dup
described_class.new(client, token, opts)
expect(opts).to eq(opts_before)
end
- describe 'expires_at' do
+ describe "expires_at" do
let(:expires_at) { 1_361_396_829 }
let(:hash) do
{
:access_token => token,
:expires_at => expires_at.to_s,
- 'foo' => 'bar',
+ "foo" => "bar",
}
end
- it 'initializes with an integer timestamp expires_at' do
+ it "initializes with an integer timestamp expires_at" do
target = described_class.from_hash(client, hash.merge(expires_at: expires_at))
assert_initialized_token(target)
expect(target.expires_at).to eql(expires_at)
end
- it 'initializes with a string timestamp expires_at' do
+ it "initializes with a string timestamp expires_at" do
target = described_class.from_hash(client, hash)
assert_initialized_token(target)
expect(target.expires_at).to eql(expires_at)
end
- it 'initializes with a string time expires_at' do
+ it "initializes with a string time expires_at" do
target = described_class.from_hash(client, hash.merge(expires_at: Time.at(expires_at).iso8601))
assert_initialized_token(target)
expect(target.expires_at).to eql(expires_at)
end
end
- describe 'expires_latency' do
+ describe "expires_latency" do
let(:expires_at) { 1_530_000_000 }
let(:expires_in) { 100 }
let(:expires_latency) { 10 }
@@ -509,224 +509,232 @@ def assert_initialized_token(target)
}
end
- it 'sets it via options' do
+ it "sets it via options" do
target = described_class.from_hash(client, hash.merge(expires_latency: expires_latency.to_s))
expect(target.expires_latency).to eq expires_latency
end
- it 'sets it nil by default' do
+ it "sets it nil by default" do
hash.delete(:expires_latency)
target = described_class.from_hash(client, hash)
expect(target.expires_latency).to be_nil
end
- it 'reduces expires_at by the given amount' do
+ it "reduces expires_at by the given amount" do
allow(Time).to receive(:now).and_return(expires_at)
target = described_class.from_hash(client, hash)
expect(target.expires_at).to eq(expires_at + expires_in - expires_latency)
end
- it 'reduces expires_at by the given amount if expires_at is provided as option' do
+ it "reduces expires_at by the given amount if expires_at is provided as option" do
target = described_class.from_hash(client, hash.merge(expires_at: expires_at))
expect(target.expires_at).to eq(expires_at - expires_latency)
end
end
end
- describe '#request' do
- context 'with :mode => :header' do
+ describe "#request" do
+ context "with :mode => :header" do
before do
subject.options[:mode] = :header
end
VERBS.each do |verb|
it "sends the token in the Authorization header for a #{verb.to_s.upcase} request" do
- expect(subject.post('/token/header').body).to include(token)
+ expect(subject.post("/token/header").body).to include(token)
end
end
end
- context 'with :mode => :query' do
+ context "with :mode => :query" do
before do
subject.options[:mode] = :query
end
VERBS.each do |verb|
it "sends the token in the body for a #{verb.to_s.upcase} request" do
- expect(subject.post('/token/query').body).to eq(token)
+ expect(subject.post("/token/query").body).to eq(token)
end
it "sends a #{verb.to_s.upcase} request and options[:param_name] include [number]." do
- subject.options[:param_name] = 'auth[1]'
- expect(subject.__send__(verb, '/token/query_string').body).to include("auth[1]=#{token}")
+ subject.options[:param_name] = "auth[1]"
+ expect(subject.__send__(verb, "/token/query_string").body).to include("auth[1]=#{token}")
end
end
end
- context 'with :mode => :body' do
+ context "with :mode => :body" do
before do
subject.options[:mode] = :body
end
VERBS.each do |verb|
it "sends the token in the body for a #{verb.to_s.upcase} request" do
- expect(subject.post('/token/body').body.split('=').last).to eq(token)
+ expect(subject.post("/token/body").body.split("=").last).to eq(token)
end
- context 'when options[:param_name] include [number]' do
+ context "when options[:param_name] include [number]" do
it "sends a #{verb.to_s.upcase} request when body is a hash" do
- subject.options[:param_name] = 'auth[1]'
- expect(subject.__send__(verb, '/token/body', body: {hi: 'there'}).body).to include("auth%5B1%5D=#{token}")
+ subject.options[:param_name] = "auth[1]"
+ expect(subject.__send__(verb, "/token/body", body: {hi: "there"}).body).to include("auth%5B1%5D=#{token}")
end
it "sends a #{verb.to_s.upcase} request when body is overridden as string" do
- subject.options[:param_name] = 'snoo[1]'
- expect(subject.__send__(verb, '/token/body', body: 'hi_there').body).to include("hi_there&snoo[1]=#{token}")
+ subject.options[:param_name] = "snoo[1]"
+ expect(subject.__send__(verb, "/token/body", body: "hi_there").body).to include("hi_there&snoo[1]=#{token}")
end
end
end
end
- context 'params include [number]' do
+ context "params include [number]" do
VERBS.each do |verb|
it "sends #{verb.to_s.upcase} correct query" do
- expect(subject.__send__(verb, '/token/query_string', params: {'foo[bar][1]' => 'val'}).body).to include('foo[bar][1]=val')
+ expect(subject.__send__(verb, "/token/query_string", params: {"foo[bar][1]" => "val"}).body).to include("foo[bar][1]=val")
end
end
end
end
- describe '#expires?' do
- it 'is false if there is no expires_at' do
+ describe "#expires?" do
+ it "is false if there is no expires_at" do
expect(described_class.new(client, token)).not_to be_expires
end
- it 'is true if there is an expires_in' do
- expect(described_class.new(client, token, refresh_token: 'abaca', expires_in: 600)).to be_expires
+ it "is true if there is an expires_in" do
+ expect(described_class.new(client, token, refresh_token: "abaca", expires_in: 600)).to be_expires
end
- it 'is true if there is an expires_at' do
- expect(described_class.new(client, token, refresh_token: 'abaca', expires_in: Time.now.getutc.to_i + 600)).to be_expires
+ it "is true if there is an expires_at" do
+ expect(described_class.new(client, token, refresh_token: "abaca", expires_in: Time.now.getutc.to_i + 600)).to be_expires
end
end
- describe '#expired?' do
- it 'is false if there is no expires_in or expires_at' do
+ describe "#expired?" do
+ it "is false if there is no expires_in or expires_at" do
expect(described_class.new(client, token)).not_to be_expired
end
- it 'is false if expires_in is 0 (token is permanent)' do
- expect(described_class.new(client, token, refresh_token: 'abaca', expires_in: 0)).not_to be_expired
+ it "is false if expires_in is 0 (token is permanent)" do
+ expect(described_class.new(client, token, refresh_token: "abaca", expires_in: 0)).not_to be_expired
end
- it 'is false if expires_in is in the future' do
- expect(described_class.new(client, token, refresh_token: 'abaca', expires_in: 10_800)).not_to be_expired
+ it "is false if expires_in is in the future" do
+ expect(described_class.new(client, token, refresh_token: "abaca", expires_in: 10_800)).not_to be_expired
end
- it 'is true if expires_at is in the past' do
- access = described_class.new(client, token, refresh_token: 'abaca', expires_in: 600)
+ it "is true if expires_at is in the past" do
+ access = described_class.new(client, token, refresh_token: "abaca", expires_in: 600)
@now = Time.now + 10_800
allow(Time).to receive(:now).and_return(@now)
expect(access).to be_expired
end
- it 'is true if expires_at is now' do
+ it "is true if expires_at is now" do
@now = Time.now
- access = described_class.new(client, token, refresh_token: 'abaca', expires_at: @now.to_i)
+ access = described_class.new(client, token, refresh_token: "abaca", expires_at: @now.to_i)
allow(Time).to receive(:now).and_return(@now)
expect(access).to be_expired
end
end
- describe '#refresh' do
+ describe "#refresh" do
let(:options) { {access_token_class: access_token_class} }
let(:access_token_class) { NewAccessToken }
let(:access) do
- described_class.new(client, token, refresh_token: 'abaca',
- expires_in: 600,
- param_name: 'o_param',
- access_token_class: access_token_class)
+ described_class.new(
+ client,
+ token,
+ refresh_token: "abaca",
+ expires_in: 600,
+ param_name: "o_param",
+ access_token_class: access_token_class,
+ )
end
let(:new_access) do
- NewAccessToken.new(client, token, refresh_token: 'abaca')
+ NewAccessToken.new(client, token, refresh_token: "abaca")
end
before do
custom_class = Class.new(described_class) do
def self.from_hash(client, hash)
- new(client, hash.delete('access_token'), hash)
+ new(client, hash.delete("access_token"), hash)
end
def self.contains_token?(hash)
- hash.key?('refresh_token')
+ hash.key?("refresh_token")
end
end
- stub_const('NewAccessToken', custom_class)
+ stub_const("NewAccessToken", custom_class)
end
- context 'without refresh_token' do
+ context "without refresh_token" do
subject(:no_refresh) { no_access.refresh }
let(:no_access) do
- described_class.new(client, token, refresh_token: nil,
- expires_in: 600,
- param_name: 'o_param',
- access_token_class: access_token_class)
+ described_class.new(
+ client,
+ token,
+ refresh_token: nil,
+ expires_in: 600,
+ param_name: "o_param",
+ access_token_class: access_token_class,
+ )
end
- it 'raises when no refresh_token' do
- block_is_expected.to raise_error('A refresh_token is not available')
+ it "raises when no refresh_token" do
+ block_is_expected.to raise_error("A refresh_token is not available")
end
end
- it 'returns a refresh token with appropriate values carried over' do
+ it "returns a refresh token with appropriate values carried over" do
refreshed = access.refresh
expect(access.client).to eq(refreshed.client)
expect(access.options[:param_name]).to eq(refreshed.options[:param_name])
end
- it 'returns a refresh token of the same access token class' do
+ it "returns a refresh token of the same access token class" do
refreshed = new_access.refresh!
expect(new_access.class).to eq(refreshed.class)
end
- context 'with a nil refresh_token in the response' do
- let(:refresh_body) { JSON.dump(access_token: 'refreshed_foo', expires_in: 600, refresh_token: nil) }
+ context "with a nil refresh_token in the response" do
+ let(:refresh_body) { JSON.dump(access_token: "refreshed_foo", expires_in: 600, refresh_token: nil) }
- it 'copies the refresh_token from the original token' do
+ it "copies the refresh_token from the original token" do
refreshed = access.refresh
expect(refreshed.refresh_token).to eq(access.refresh_token)
end
end
- context 'with a not-nil refresh_token in the response' do
- let(:refresh_body) { JSON.dump(access_token: 'refreshed_foo', expires_in: 600, refresh_token: 'qerwer') }
+ context "with a not-nil refresh_token in the response" do
+ let(:refresh_body) { JSON.dump(access_token: "refreshed_foo", expires_in: 600, refresh_token: "qerwer") }
- it 'copies the refresh_token from the original token' do
+ it "copies the refresh_token from the original token" do
refreshed = access.refresh
- expect(refreshed.token).to eq('refreshed_foo')
- expect(refreshed.refresh_token).to eq('qerwer')
+ expect(refreshed.token).to eq("refreshed_foo")
+ expect(refreshed.refresh_token).to eq("qerwer")
end
end
- context 'with a not-nil, not camel case, refresh_token in the response' do
- let(:refresh_body) { JSON.dump(accessToken: 'refreshed_foo', expires_in: 600, refreshToken: 'qerwer') }
+ context "with a not-nil, not camel case, refresh_token in the response" do
+ let(:refresh_body) { JSON.dump(accessToken: "refreshed_foo", expires_in: 600, refreshToken: "qerwer") }
- it 'copies the refresh_token from the original token' do
+ it "copies the refresh_token from the original token" do
refreshed = access.refresh
- expect(refreshed.token).to eq('refreshed_foo')
- expect(refreshed.refresh_token).to eq('qerwer')
+ expect(refreshed.token).to eq("refreshed_foo")
+ expect(refreshed.refresh_token).to eq("qerwer")
end
end
- context 'with a custom access_token_class' do
+ context "with a custom access_token_class" do
let(:access_token_class) { NewAccessToken }
- it 'returns a refresh token of NewAccessToken' do
+ it "returns a refresh token of NewAccessToken" do
refreshed = access.refresh!
expect(new_access.class).to eq(refreshed.class)
@@ -734,23 +742,23 @@ def self.contains_token?(hash)
end
end
- describe '#to_hash' do
- it 'return a hash equal to the hash used to initialize access token' do
- hash = {:access_token => token, :refresh_token => 'foobar', :expires_at => Time.now.to_i + 200, 'foo' => 'bar'}
+ describe "#to_hash" do
+ it "return a hash equal to the hash used to initialize access token" do
+ hash = {:access_token => token, :refresh_token => "foobar", :expires_at => Time.now.to_i + 200, "foo" => "bar"}
access_token = described_class.from_hash(client, hash.clone)
expect(access_token.to_hash).to eq(hash)
end
end
- describe '#inspect' do
- let(:inspect_result) { described_class.new(nil, 'secret-token', { refresh_token: 'secret-refresh-token' }).inspect }
+ describe "#inspect" do
+ let(:inspect_result) { described_class.new(nil, "secret-token", {refresh_token: "secret-refresh-token"}).inspect }
- it 'filters out the @token value' do
- expect(inspect_result).to include('@token=[FILTERED]')
+ it "filters out the @token value" do
+ expect(inspect_result).to include("@token=[FILTERED]")
end
- it 'filters out the @refresh_token value' do
- expect(inspect_result).to include('@refresh_token=[FILTERED]')
+ it "filters out the @refresh_token value" do
+ expect(inspect_result).to include("@refresh_token=[FILTERED]")
end
end
end
diff --git a/spec/oauth2/authenticator_spec.rb b/spec/oauth2/authenticator_spec.rb
index 158bc593..f7396c5e 100644
--- a/spec/oauth2/authenticator_spec.rb
+++ b/spec/oauth2/authenticator_spec.rb
@@ -5,128 +5,170 @@
described_class.new(client_id, client_secret, mode)
end
- let(:client_id) { 'foo' }
- let(:client_secret) { 'bar' }
+ let(:client_id) { "foo" }
+ let(:client_secret) { "bar" }
let(:mode) { :undefined }
- it 'raises NotImplementedError for unknown authentication mode' do
+ it "raises NotImplementedError for unknown authentication mode" do
expect { subject.apply({}) }.to raise_error(NotImplementedError)
end
- describe '#apply' do
- context 'with parameter-based authentication' do
+ describe "#apply" do
+ context "with parameter-based authentication" do
let(:mode) { :request_body }
- it 'adds client_id and client_secret to params' do
+ it "adds client_id and client_secret to params" do
output = subject.apply({})
- expect(output).to eq('client_id' => 'foo', 'client_secret' => 'bar')
+ expect(output).to eq("client_id" => "foo", "client_secret" => "bar")
end
- context 'when client_id nil' do
+ context "when client_id nil" do
let(:client_id) { nil }
- it 'ignores client_id, but adds client_secret to params' do
+ it "ignores client_id, but adds client_secret to params" do
output = subject.apply({})
- expect(output).to eq('client_secret' => 'bar')
+ expect(output).to eq("client_secret" => "bar")
end
end
- it 'does not overwrite existing credentials' do
- input = {'client_secret' => 's3cr3t'}
+ it "does not overwrite existing credentials" do
+ input = {"client_secret" => "s3cr3t"}
output = subject.apply(input)
- expect(output).to eq('client_id' => 'foo', 'client_secret' => 's3cr3t')
+ expect(output).to eq("client_id" => "foo", "client_secret" => "s3cr3t")
end
- it 'preserves other parameters' do
- input = {'state' => '42', :headers => {'A' => 'b'}}
+ it "preserves other parameters" do
+ input = {"state" => "42", :headers => {"A" => "b"}}
output = subject.apply(input)
expect(output).to eq(
- 'client_id' => 'foo',
- 'client_secret' => 'bar',
- 'state' => '42',
- :headers => {'A' => 'b'}
+ "client_id" => "foo",
+ "client_secret" => "bar",
+ "state" => "42",
+ :headers => {"A" => "b"},
)
end
- context 'passing nil secret' do
+ context "passing nil secret" do
let(:client_secret) { nil }
- it 'does not set nil client_secret' do
+ it "does not set nil client_secret" do
output = subject.apply({})
- expect(output).to eq('client_id' => 'foo')
+ expect(output).to eq("client_id" => "foo")
end
end
- context 'using tls client authentication' do
+ context "using tls client authentication" do
let(:mode) { :tls_client_auth }
- it 'does not add client_secret' do
+ it "does not add client_secret" do
output = subject.apply({})
- expect(output).to eq('client_id' => 'foo')
+ expect(output).to eq("client_id" => "foo")
end
end
- context 'using private key jwt authentication' do
+ context "using private key jwt authentication" do
let(:mode) { :private_key_jwt }
- it 'does not include client_id or client_secret' do
+ it "does not include client_id or client_secret" do
output = subject.apply({})
expect(output).to eq({})
end
end
end
- context 'using tls_client_auth' do
+ context "using tls_client_auth" do
let(:mode) { :tls_client_auth }
- context 'when client_id present' do
- let(:client_id) { 'foobar' }
+ context "when client_id present" do
+ let(:client_id) { "foobar" }
- it 'adds client_id to params' do
+ it "adds client_id to params" do
output = subject.apply({})
- expect(output).to eq('client_id' => 'foobar')
+ expect(output).to eq("client_id" => "foobar")
end
end
- context 'when client_id nil' do
+ context "when client_id nil" do
let(:client_id) { nil }
- it 'ignores client_id for params' do
+ it "ignores client_id for params" do
output = subject.apply({})
expect(output).to eq({})
end
end
end
- context 'with Basic authentication' do
+ context "with Basic authentication" do
let(:mode) { :basic_auth }
let(:header) { "Basic #{Base64.strict_encode64("#{client_id}:#{client_secret}")}" }
- it 'encodes credentials in headers' do
+ it "encodes credentials in headers" do
output = subject.apply({})
- expect(output).to eq(headers: {'Authorization' => header})
+ expect(output).to eq(headers: {"Authorization" => header})
end
- it 'does not overwrite existing credentials' do
- input = {headers: {'Authorization' => 'Bearer abc123'}}
+ it "does not overwrite existing credentials" do
+ input = {headers: {"Authorization" => "Bearer abc123"}}
output = subject.apply(input)
- expect(output).to eq(headers: {'Authorization' => 'Bearer abc123'})
+ expect(output).to eq(headers: {"Authorization" => "Bearer abc123"})
end
- it 'does not overwrite existing params or headers' do
- input = {'state' => '42', :headers => {'A' => 'b'}}
+ it "does not overwrite existing params or headers" do
+ input = {"state" => "42", :headers => {"A" => "b"}}
output = subject.apply(input)
expect(output).to eq(
- 'state' => '42',
- :headers => {'A' => 'b', 'Authorization' => header}
+ "state" => "42",
+ :headers => {"A" => "b", "Authorization" => header},
)
end
end
end
- describe '#inspect' do
- it 'filters out the @secret value' do
- expect(subject.inspect).to include('@secret=[FILTERED]')
+ describe "#inspect" do
+ it "filters secret by default" do
+ expect(described_class.filtered_attribute_names).to include(:secret)
+ end
+
+ it "filters out the @secret value" do
+ expect(subject.inspect).to include("@secret=[FILTERED]")
+ end
+
+ context "when filter is changed" do
+ before do
+ @original_filter = described_class.filtered_attribute_names
+ described_class.filtered_attributes :vanilla
+ end
+
+ after do
+ described_class.filtered_attributes(*@original_filter)
+ end
+
+ it "changes the filter" do
+ expect(described_class.filtered_attribute_names).to eq([:vanilla])
+ end
+
+ it "does not filter out the @secret value" do
+ expect(subject.inspect).to include("@secret=\"bar\"")
+ end
+ end
+
+ context "when filter is empty" do
+ before do
+ @original_filter = described_class.filtered_attribute_names
+ described_class.filtered_attributes
+ end
+
+ after do
+ described_class.filtered_attributes(*@original_filter)
+ end
+
+ it "changes the filter" do
+ expect(described_class.filtered_attribute_names).to eq([])
+ end
+
+ it "does not filter out the @secret value" do
+ expect(subject.inspect).to include("@secret=\"bar\"")
+ end
end
end
end
diff --git a/spec/oauth2/client_spec.rb b/spec/oauth2/client_spec.rb
index d87d61ec..8855827f 100644
--- a/spec/oauth2/client_spec.rb
+++ b/spec/oauth2/client_spec.rb
@@ -1,129 +1,129 @@
# coding: utf-8
# frozen_string_literal: true
-require 'nkf'
+require "nkf"
RSpec.describe OAuth2::Client do
subject(:instance) do
- described_class.new('abc', 'def', {site: 'https://api.example.com'}.merge(options)) do |builder|
+ described_class.new("abc", "def", {site: "https://api.example.com"}.merge(options)) do |builder|
builder.adapter :test do |stub|
- stub.get('/success') { |_env| [200, {'Content-Type' => 'text/awesome'}, 'yay'] }
- stub.get('/reflect') { |env| [200, {}, env[:body]] }
- stub.post('/reflect') { |env| [200, {}, env[:body]] }
- stub.get('/unauthorized') { |_env| [401, {'Content-Type' => 'application/json'}, JSON.dump(error: error_value, error_description: error_description_value)] }
- stub.get('/conflict') { |_env| [409, {'Content-Type' => 'text/plain'}, 'not authorized'] }
- stub.get('/redirect') { |_env| [302, {'Content-Type' => 'text/plain', 'location' => '/success'}, ''] }
- stub.get('/redirect_no_loc') { |_env| [302, {'Content-Type' => 'text/plain'}, ''] }
- stub.post('/redirect') { |_env| [303, {'Content-Type' => 'text/plain', 'location' => '/reflect'}, ''] }
- stub.get('/error') { |_env| [500, {'Content-Type' => 'text/plain'}, 'unknown error'] }
- stub.get('/unparsable_error') { |_env| [500, {'Content-Type' => 'application/json'}, 'unknown error'] }
- stub.get('/empty_get') { |_env| [204, {}, nil] }
- stub.get('/different_encoding') { |_env| [500, {'Content-Type' => 'application/json'}, NKF.nkf('-We', JSON.dump(error: error_value, error_description: '∞'))] }
- stub.get('/ascii_8bit_encoding') { |_env| [500, {'Content-Type' => 'application/json'}, JSON.dump(error: 'invalid_request', error_description: 'é').force_encoding('ASCII-8BIT')] }
- stub.get('/unhandled_status') { |_env| [600, {}, nil] }
+ stub.get("/success") { |_env| [200, {"Content-Type" => "text/awesome"}, "yay"] }
+ stub.get("/reflect") { |env| [200, {}, env[:body]] }
+ stub.post("/reflect") { |env| [200, {}, env[:body]] }
+ stub.get("/unauthorized") { |_env| [401, {"Content-Type" => "application/json"}, JSON.dump(error: error_value, error_description: error_description_value)] }
+ stub.get("/conflict") { |_env| [409, {"Content-Type" => "text/plain"}, "not authorized"] }
+ stub.get("/redirect") { |_env| [302, {"Content-Type" => "text/plain", "location" => "/success"}, ""] }
+ stub.get("/redirect_no_loc") { |_env| [302, {"Content-Type" => "text/plain"}, ""] }
+ stub.post("/redirect") { |_env| [303, {"Content-Type" => "text/plain", "location" => "/reflect"}, ""] }
+ stub.get("/error") { |_env| [500, {"Content-Type" => "text/plain"}, "unknown error"] }
+ stub.get("/unparsable_error") { |_env| [500, {"Content-Type" => "application/json"}, "unknown error"] }
+ stub.get("/empty_get") { |_env| [204, {}, nil] }
+ stub.get("/different_encoding") { |_env| [500, {"Content-Type" => "application/json"}, NKF.nkf("-We", JSON.dump(error: error_value, error_description: "∞"))] }
+ stub.get("/ascii_8bit_encoding") { |_env| [500, {"Content-Type" => "application/json"}, JSON.dump(error: "invalid_request", error_description: "é").force_encoding("ASCII-8BIT")] }
+ stub.get("/unhandled_status") { |_env| [600, {}, nil] }
end
end
end
- let!(:error_value) { 'invalid_token' }
- let!(:error_description_value) { 'bad bad token' }
+ let!(:error_value) { "invalid_token" }
+ let!(:error_description_value) { "bad bad token" }
let(:options) { {} }
- describe '#initialize' do
- it 'assigns id and secret' do
- expect(subject.id).to eq('abc')
- expect(subject.secret).to eq('def')
+ describe "#initialize" do
+ it "assigns id and secret" do
+ expect(subject.id).to eq("abc")
+ expect(subject.secret).to eq("def")
end
- it 'assigns site from the options hash' do
- expect(subject.site).to eq('https://api.example.com')
+ it "assigns site from the options hash" do
+ expect(subject.site).to eq("https://api.example.com")
end
- it 'assigns Faraday::Connection#host' do
- expect(subject.connection.host).to eq('api.example.com')
+ it "assigns Faraday::Connection#host" do
+ expect(subject.connection.host).to eq("api.example.com")
end
- it 'leaves Faraday::Connection#ssl unset' do
+ it "leaves Faraday::Connection#ssl unset" do
expect(subject.connection.ssl).to be_empty
end
- it 'is able to pass a block to configure the connection' do
- builder = double('builder')
+ it "is able to pass a block to configure the connection" do
+ builder = double("builder")
allow(Faraday).to receive(:new).and_yield(builder)
allow(builder).to receive(:response)
expect(builder).to receive(:adapter).with(:test)
- described_class.new('abc', 'def') do |client|
+ described_class.new("abc", "def") do |client|
client.adapter :test
end.connection
end
- it 'defaults raise_errors to true' do
+ it "defaults raise_errors to true" do
expect(subject.options[:raise_errors]).to be true
end
- it 'allows true/false for raise_errors option' do
- client = described_class.new('abc', 'def', site: 'https://api.example.com', raise_errors: false)
+ it "allows true/false for raise_errors option" do
+ client = described_class.new("abc", "def", site: "https://api.example.com", raise_errors: false)
expect(client.options[:raise_errors]).to be false
- client = described_class.new('abc', 'def', site: 'https://api.example.com', raise_errors: true)
+ client = described_class.new("abc", "def", site: "https://api.example.com", raise_errors: true)
expect(client.options[:raise_errors]).to be true
end
- it 'allows override of raise_errors option' do
- client = described_class.new('abc', 'def', site: 'https://api.example.com', raise_errors: true) do |builder|
+ it "allows override of raise_errors option" do
+ client = described_class.new("abc", "def", site: "https://api.example.com", raise_errors: true) do |builder|
builder.adapter :test do |stub|
- stub.get('/notfound') { |_env| [404, {}, nil] }
+ stub.get("/notfound") { |_env| [404, {}, nil] }
end
end
expect(client.options[:raise_errors]).to be true
- expect { client.request(:get, '/notfound') }.to raise_error(OAuth2::Error)
- response = client.request(:get, '/notfound', raise_errors: false)
+ expect { client.request(:get, "/notfound") }.to raise_error(OAuth2::Error)
+ response = client.request(:get, "/notfound", raise_errors: false)
expect(response.status).to eq(404)
end
- it 'allows get/post for access_token_method option' do
- client = described_class.new('abc', 'def', site: 'https://api.example.com', access_token_method: :get)
+ it "allows get/post for access_token_method option" do
+ client = described_class.new("abc", "def", site: "https://api.example.com", access_token_method: :get)
expect(client.options[:access_token_method]).to eq(:get)
- client = described_class.new('abc', 'def', site: 'https://api.example.com', access_token_method: :post)
+ client = described_class.new("abc", "def", site: "https://api.example.com", access_token_method: :post)
expect(client.options[:access_token_method]).to eq(:post)
end
- it 'does not mutate the opts hash argument' do
- opts = {site: 'http://example.com/'}
+ it "does not mutate the opts hash argument" do
+ opts = {site: "http://example.com/"}
opts2 = opts.dup
- described_class.new 'abc', 'def', opts
+ described_class.new "abc", "def", opts
expect(opts).to eq(opts2)
end
- it 'raises exception if JSON is expected, but server returns invalid JSON' do
+ it "raises exception if JSON is expected, but server returns invalid JSON" do
client = instance
- expect { client.request(:get, '/unparsable_error') }.to raise_error(JSON::ParserError)
- response = client.request(:get, '/unparsable_error', raise_errors: false)
+ expect { client.request(:get, "/unparsable_error") }.to raise_error(JSON::ParserError)
+ response = client.request(:get, "/unparsable_error", raise_errors: false)
expect(response.status).to eq(500)
end
end
- describe '#site=(val)' do
+ describe "#site=(val)" do
subject(:site) { instance.site = new_site }
let(:options) do
- {site: 'https://example.com/blog'}
+ {site: "https://example.com/blog"}
end
- let(:new_site) { 'https://example.com/sharpie' }
+ let(:new_site) { "https://example.com/sharpie" }
- it 'sets site' do
- block_is_expected.to change(instance, :site).from('https://example.com/blog').to('https://example.com/sharpie')
+ it "sets site" do
+ block_is_expected.to change(instance, :site).from("https://example.com/blog").to("https://example.com/sharpie")
end
- context 'with connection' do
+ context "with connection" do
before do
instance.connection
end
- it 'allows connection to reset with new url prefix' do
- block_is_expected.to change { instance.connection.url_prefix }.from(URI('https://example.com/blog')).to(URI('https://example.com/sharpie'))
+ it "allows connection to reset with new url prefix" do
+ block_is_expected.to change { instance.connection.url_prefix }.from(URI("https://example.com/blog")).to(URI("https://example.com/sharpie"))
end
end
end
@@ -135,237 +135,237 @@
end
it "is settable via the :#{url_type}_url option" do
- subject.options[:"#{url_type}_url"] = '/oauth/custom'
- expect(subject.send("#{url_type}_url")).to eq('https://api.example.com/oauth/custom')
+ subject.options[:"#{url_type}_url"] = "/oauth/custom"
+ expect(subject.send("#{url_type}_url")).to eq("https://api.example.com/oauth/custom")
end
- it 'allows a different host than the site' do
- subject.options[:"#{url_type}_url"] = 'https://api.foo.com/oauth/custom'
- expect(subject.send("#{url_type}_url")).to eq('https://api.foo.com/oauth/custom')
+ it "allows a different host than the site" do
+ subject.options[:"#{url_type}_url"] = "https://api.foo.com/oauth/custom"
+ expect(subject.send("#{url_type}_url")).to eq("https://api.foo.com/oauth/custom")
end
- context 'when a URL with path is used in the site' do
+ context "when a URL with path is used in the site" do
let(:options) do
- {site: 'https://example.com/blog'}
+ {site: "https://example.com/blog"}
end
- it 'generates an authorization URL relative to the site' do
+ it "generates an authorization URL relative to the site" do
expect(subject.send("#{url_type}_url")).to eq("https://example.com/blog/oauth/#{url_type}")
end
end
end
end
- describe ':redirect_uri option' do
+ describe ":redirect_uri option" do
let(:auth_code_params) do
{
- 'client_id' => 'abc',
- 'client_secret' => 'def',
- 'code' => 'code',
- 'grant_type' => 'authorization_code',
+ "client_id" => "abc",
+ "client_secret" => "def",
+ "code" => "code",
+ "grant_type" => "authorization_code",
}
end
- context 'when blank' do
- it 'there is no redirect_uri param added to authorization URL' do
- expect(subject.authorize_url('a' => 'b')).to eq('https://api.example.com/oauth/authorize?a=b')
+ context "when blank" do
+ it "there is no redirect_uri param added to authorization URL" do
+ expect(subject.authorize_url("a" => "b")).to eq("https://api.example.com/oauth/authorize?a=b")
end
- it 'does not add the redirect_uri param to the auth_code token exchange request' do
- client = described_class.new('abc', 'def', site: 'https://api.example.com', auth_scheme: :request_body) do |builder|
+ it "does not add the redirect_uri param to the auth_code token exchange request" do
+ client = described_class.new("abc", "def", site: "https://api.example.com", auth_scheme: :request_body) do |builder|
builder.adapter :test do |stub|
- stub.post('/oauth/token', auth_code_params) do
- [200, {'Content-Type' => 'application/json'}, '{"access_token":"token"}']
+ stub.post("/oauth/token", auth_code_params) do
+ [200, {"Content-Type" => "application/json"}, '{"access_token":"token"}']
end
end
end
- client.auth_code.get_token('code')
+ client.auth_code.get_token("code")
end
end
- context 'when set' do
- before { subject.options[:redirect_uri] = 'https://site.com/oauth/callback' }
+ context "when set" do
+ before { subject.options[:redirect_uri] = "https://site.com/oauth/callback" }
- it 'adds the redirect_uri param to authorization URL' do
- expect(subject.authorize_url('a' => 'b')).to eq('https://api.example.com/oauth/authorize?a=b&redirect_uri=https%3A%2F%2Fsite.com%2Foauth%2Fcallback')
+ it "adds the redirect_uri param to authorization URL" do
+ expect(subject.authorize_url("a" => "b")).to eq("https://api.example.com/oauth/authorize?a=b&redirect_uri=https%3A%2F%2Fsite.com%2Foauth%2Fcallback")
end
- it 'adds the redirect_uri param to the auth_code token exchange request' do
- client = described_class.new('abc', 'def', redirect_uri: 'https://site.com/oauth/callback', site: 'https://api.example.com', auth_scheme: :request_body) do |builder|
+ it "adds the redirect_uri param to the auth_code token exchange request" do
+ client = described_class.new("abc", "def", redirect_uri: "https://site.com/oauth/callback", site: "https://api.example.com", auth_scheme: :request_body) do |builder|
builder.adapter :test do |stub|
- stub.post('/oauth/token', auth_code_params.merge('redirect_uri' => 'https://site.com/oauth/callback')) do
- [200, {'Content-Type' => 'application/json'}, '{"access_token":"token"}']
+ stub.post("/oauth/token", auth_code_params.merge("redirect_uri" => "https://site.com/oauth/callback")) do
+ [200, {"Content-Type" => "application/json"}, '{"access_token":"token"}']
end
end
end
- client.auth_code.get_token('code')
+ client.auth_code.get_token("code")
end
end
- describe 'custom headers' do
- context 'string key headers' do
- it 'adds the custom headers to request' do
- client = described_class.new('abc', 'def', site: 'https://api.example.com', auth_scheme: :request_body) do |builder|
+ describe "custom headers" do
+ context "string key headers" do
+ it "adds the custom headers to request" do
+ client = described_class.new("abc", "def", site: "https://api.example.com", auth_scheme: :request_body) do |builder|
builder.adapter :test do |stub|
- stub.post('/oauth/token') do |env|
- expect(env.request_headers).to include('CustomHeader' => 'CustomHeader')
- [200, {'Content-Type' => 'application/json'}, '{"access_token":"token"}']
+ stub.post("/oauth/token") do |env|
+ expect(env.request_headers).to include("CustomHeader" => "CustomHeader")
+ [200, {"Content-Type" => "application/json"}, '{"access_token":"token"}']
end
end
end
- header_params = {'headers' => {'CustomHeader' => 'CustomHeader'}}
- client.auth_code.get_token('code', header_params)
+ header_params = {"headers" => {"CustomHeader" => "CustomHeader"}}
+ client.auth_code.get_token("code", header_params)
end
end
- context 'symbol key headers' do
- it 'adds the custom headers to request' do
- client = described_class.new('abc', 'def', site: 'https://api.example.com', auth_scheme: :request_body) do |builder|
+ context "symbol key headers" do
+ it "adds the custom headers to request" do
+ client = described_class.new("abc", "def", site: "https://api.example.com", auth_scheme: :request_body) do |builder|
builder.adapter :test do |stub|
- stub.post('/oauth/token') do |env|
- expect(env.request_headers).to include('CustomHeader' => 'CustomHeader')
- [200, {'Content-Type' => 'application/json'}, '{"access_token":"token"}']
+ stub.post("/oauth/token") do |env|
+ expect(env.request_headers).to include("CustomHeader" => "CustomHeader")
+ [200, {"Content-Type" => "application/json"}, '{"access_token":"token"}']
end
end
end
- header_params = {headers: {'CustomHeader' => 'CustomHeader'}}
- client.auth_code.get_token('code', header_params)
+ header_params = {headers: {"CustomHeader" => "CustomHeader"}}
+ client.auth_code.get_token("code", header_params)
end
end
- context 'string key custom headers with basic auth' do
- it 'adds the custom headers to request' do
- client = described_class.new('abc', 'def', site: 'https://api.example.com') do |builder|
+ context "string key custom headers with basic auth" do
+ it "adds the custom headers to request" do
+ client = described_class.new("abc", "def", site: "https://api.example.com") do |builder|
builder.adapter :test do |stub|
- stub.post('/oauth/token') do |env|
- expect(env.request_headers).to include('CustomHeader' => 'CustomHeader')
- [200, {'Content-Type' => 'application/json'}, '{"access_token":"token"}']
+ stub.post("/oauth/token") do |env|
+ expect(env.request_headers).to include("CustomHeader" => "CustomHeader")
+ [200, {"Content-Type" => "application/json"}, '{"access_token":"token"}']
end
end
end
- header_params = {'headers' => {'CustomHeader' => 'CustomHeader'}}
- client.auth_code.get_token('code', header_params)
+ header_params = {"headers" => {"CustomHeader" => "CustomHeader"}}
+ client.auth_code.get_token("code", header_params)
end
end
- context 'symbol key custom headers with basic auth' do
- it 'adds the custom headers to request' do
- client = described_class.new('abc', 'def', site: 'https://api.example.com') do |builder|
+ context "symbol key custom headers with basic auth" do
+ it "adds the custom headers to request" do
+ client = described_class.new("abc", "def", site: "https://api.example.com") do |builder|
builder.adapter :test do |stub|
- stub.post('/oauth/token') do |env|
- expect(env.request_headers).to include('CustomHeader' => 'CustomHeader')
- [200, {'Content-Type' => 'application/json'}, '{"access_token":"token"}']
+ stub.post("/oauth/token") do |env|
+ expect(env.request_headers).to include("CustomHeader" => "CustomHeader")
+ [200, {"Content-Type" => "application/json"}, '{"access_token":"token"}']
end
end
end
- header_params = {headers: {'CustomHeader' => 'CustomHeader'}}
- client.auth_code.get_token('code', header_params)
+ header_params = {headers: {"CustomHeader" => "CustomHeader"}}
+ client.auth_code.get_token("code", header_params)
end
end
end
end
- describe '#connection' do
- context 'when debugging' do
- include_context 'with stubbed env'
+ describe "#connection" do
+ context "when debugging" do
+ include_context "with stubbed env"
before do
- stub_env('OAUTH_DEBUG' => debug_value)
+ stub_env("OAUTH_DEBUG" => debug_value)
end
- context 'when OAUTH_DEBUG=true' do
- let(:debug_value) { 'true' }
+ context "when OAUTH_DEBUG=true" do
+ let(:debug_value) { "true" }
- it 'smoothly handles successive requests' do
+ it "smoothly handles successive requests" do
silence_all do
# first request (always goes smoothly)
- subject.request(:get, '/success')
+ subject.request(:get, "/success")
end
expect do
# second request (used to throw Faraday::RackBuilder::StackLocked)
- subject.request(:get, '/success')
+ subject.request(:get, "/success")
end.not_to raise_error
end
- it 'prints both request and response bodies to STDOUT' do
+ it "prints both request and response bodies to STDOUT" do
printed = capture(:stdout) do
- subject.request(:get, '/success')
- subject.request(:get, '/reflect', body: 'this is magical')
+ subject.request(:get, "/success")
+ subject.request(:get, "/reflect", body: "this is magical")
end
- expect(printed).to match 'request: GET https://api.example.com/success'
- expect(printed).to match 'response: Content-Type:'
- expect(printed).to match 'response: yay'
- expect(printed).to match 'request: this is magical'
- expect(printed).to match 'response: this is magical'
+ expect(printed).to match "request: GET https://api.example.com/success"
+ expect(printed).to match "response: Content-Type:"
+ expect(printed).to match "response: yay"
+ expect(printed).to match "request: this is magical"
+ expect(printed).to match "response: this is magical"
end
end
- context 'when OAUTH_DEBUG=false' do
- let(:debug_value) { 'false' }
+ context "when OAUTH_DEBUG=false" do
+ let(:debug_value) { "false" }
- it 'smoothly handles successive requests' do
+ it "smoothly handles successive requests" do
silence_all do
# first request (always goes smoothly)
- subject.request(:get, '/success')
+ subject.request(:get, "/success")
end
expect do
# second request (used to throw Faraday::RackBuilder::StackLocked)
- subject.request(:get, '/success')
+ subject.request(:get, "/success")
end.not_to raise_error
end
- it 'prints nothing to STDOUT' do
+ it "prints nothing to STDOUT" do
printed = capture(:stdout) do
- subject.request(:get, '/success')
- subject.request(:get, '/reflect', body: 'this is magical')
+ subject.request(:get, "/success")
+ subject.request(:get, "/reflect", body: "this is magical")
end
- expect(printed).to eq ''
+ expect(printed).to eq ""
end
end
end
end
- describe '#authorize_url' do
+ describe "#authorize_url" do
subject { instance.authorize_url(params) }
- context 'when space included' do
+ context "when space included" do
let(:params) do
- {scope: 'email profile'}
+ {scope: "email profile"}
end
- it 'encoded as %20' do
- expect(subject).to include 'email%20profile'
+ it "encoded as %20" do
+ expect(subject).to include "email%20profile"
end
end
end
- describe '#request' do
- it 'works with a null response body' do
- expect(subject.request(:get, 'empty_get').body).to eq('')
+ describe "#request" do
+ it "works with a null response body" do
+ expect(subject.request(:get, "empty_get").body).to eq("")
end
- it 'returns on a successful response' do
- response = subject.request(:get, '/success')
- expect(response.body).to eq('yay')
+ it "returns on a successful response" do
+ response = subject.request(:get, "/success")
+ expect(response.body).to eq("yay")
expect(response.status).to eq(200)
- expect(response.headers).to eq('Content-Type' => 'text/awesome')
+ expect(response.headers).to eq("Content-Type" => "text/awesome")
end
- context 'with ENV' do
- include_context 'with stubbed env'
- context 'when OAUTH_DEBUG=true' do
+ context "with ENV" do
+ include_context "with stubbed env"
+ context "when OAUTH_DEBUG=true" do
before do
- stub_env('OAUTH_DEBUG' => 'true')
+ stub_env("OAUTH_DEBUG" => "true")
end
- it 'outputs to $stdout when OAUTH_DEBUG=true' do
+ it "outputs to $stdout when OAUTH_DEBUG=true" do
output = capture(:stdout) do
- subject.request(:get, '/success')
+ subject.request(:get, "/success")
end
logs = [
- 'request: GET https://api.example.com/success',
- 'response: Status 200',
+ "request: GET https://api.example.com/success",
+ "response: Status 200",
'response: Content-Type: "text/awesome"',
]
expect(output).to include(*logs)
@@ -373,62 +373,62 @@
end
end
- it 'posts a body' do
- response = subject.request(:post, '/reflect', body: 'foo=bar')
- expect(response.body).to eq('foo=bar')
+ it "posts a body" do
+ response = subject.request(:post, "/reflect", body: "foo=bar")
+ expect(response.body).to eq("foo=bar")
end
- it 'follows redirects properly' do
- response = subject.request(:get, '/redirect')
- expect(response.body).to eq('yay')
+ it "follows redirects properly" do
+ response = subject.request(:get, "/redirect")
+ expect(response.body).to eq("yay")
expect(response.status).to eq(200)
- expect(response.headers).to eq('Content-Type' => 'text/awesome')
- expect(response.response.env.url.to_s).to eq('https://api.example.com/success')
+ expect(response.headers).to eq("Content-Type" => "text/awesome")
+ expect(response.response.env.url.to_s).to eq("https://api.example.com/success")
end
- it 'redirects using GET on a 303' do
- response = subject.request(:post, '/redirect', body: 'foo=bar')
+ it "redirects using GET on a 303" do
+ response = subject.request(:post, "/redirect", body: "foo=bar")
expect(response.body).to be_empty
expect(response.status).to eq(200)
- expect(response.response.env.url.to_s).to eq('https://api.example.com/reflect')
+ expect(response.response.env.url.to_s).to eq("https://api.example.com/reflect")
end
- it 'raises an error if a redirect has no Location header' do
- expect { subject.request(:get, '/redirect_no_loc') }.to raise_error(OAuth2::Error, 'Got 302 status code, but no Location header was present')
+ it "raises an error if a redirect has no Location header" do
+ expect { subject.request(:get, "/redirect_no_loc") }.to raise_error(OAuth2::Error, "Got 302 status code, but no Location header was present")
end
- it 'obeys the :max_redirects option' do
+ it "obeys the :max_redirects option" do
max_redirects = subject.options[:max_redirects]
subject.options[:max_redirects] = 0
- response = subject.request(:get, '/redirect')
+ response = subject.request(:get, "/redirect")
expect(response.status).to eq(302)
subject.options[:max_redirects] = max_redirects
end
- it 'returns if raise_errors is false' do
+ it "returns if raise_errors is false" do
subject.options[:raise_errors] = false
- response = subject.request(:get, '/unauthorized')
+ response = subject.request(:get, "/unauthorized")
expect(response.status).to eq(401)
- expect(response.headers).to eq('Content-Type' => 'application/json')
+ expect(response.headers).to eq("Content-Type" => "application/json")
end
%w[/unauthorized /conflict /error /different_encoding /ascii_8bit_encoding].each do |error_path|
it "raises OAuth2::Error on error response to path #{error_path}" do
- pending_for(engine: 'jruby', reason: 'https://github.com/jruby/jruby/issues/4921') if error_path == '/different_encoding'
+ pending_for(engine: "jruby", reason: "https://github.com/jruby/jruby/issues/4921") if error_path == "/different_encoding"
expect { subject.request(:get, error_path) }.to raise_error(OAuth2::Error)
end
end
- it 're-encodes response body in the error message' do
- expect { subject.request(:get, '/ascii_8bit_encoding') }.to raise_error do |ex|
+ it "re-encodes response body in the error message" do
+ expect { subject.request(:get, "/ascii_8bit_encoding") }.to raise_error do |ex|
expect(ex.message).to eq("invalid_request: é\n{\"error\":\"invalid_request\",\"error_description\":\"��\"}")
- expect(ex.message.encoding.name).to eq('UTF-8')
+ expect(ex.message.encoding.name).to eq("UTF-8")
end
end
- it 'parses OAuth2 standard error response' do
- expect { subject.request(:get, '/unauthorized') }.to raise_error do |ex|
+ it "parses OAuth2 standard error response" do
+ expect { subject.request(:get, "/unauthorized") }.to raise_error do |ex|
expect(ex.code).to eq(error_value)
expect(ex.description).to eq(error_description_value)
expect(ex.to_s).to match(/#{error_value}/)
@@ -436,257 +436,254 @@
end
end
- it 'provides the response in the Exception' do
- expect { subject.request(:get, '/error') }.to raise_error do |ex|
+ it "provides the response in the Exception" do
+ expect { subject.request(:get, "/error") }.to raise_error do |ex|
expect(ex.response).not_to be_nil
expect(ex.to_s).to match(/unknown error/)
end
end
- it 'informs about unhandled status code' do
- expect { subject.request(:get, '/unhandled_status') }.to raise_error do |ex|
+ it "informs about unhandled status code" do
+ expect { subject.request(:get, "/unhandled_status") }.to raise_error do |ex|
expect(ex.response).not_to be_nil
expect(ex.to_s).to match(/Unhandled status code value of 600/)
end
end
- context 'when errors are raised by Faraday' do
+ context "when errors are raised by Faraday" do
let(:connection) { instance_double(Faraday::Connection, build_url: double) }
before do
allow(connection).to(
- receive(:run_request).and_raise(faraday_exception)
+ receive(:run_request).and_raise(faraday_exception),
)
allow(subject).to receive(:connection).and_return(connection) # rubocop:disable RSpec/SubjectStub
end
- shared_examples 'failed connection handler' do
- it 'rescues the exception' do
- expect { subject.request(:get, '/redirect') }.to raise_error do |e|
+ shared_examples "failed connection handler" do
+ it "rescues the exception" do
+ expect { subject.request(:get, "/redirect") }.to raise_error do |e|
expect(e.class).to eq(expected_exception)
expect(e.message).to eq(faraday_exception.message)
end
end
end
- context 'with Faraday::ConnectionFailed' do
- let(:faraday_exception) { Faraday::ConnectionFailed.new('fail') }
+ context "with Faraday::ConnectionFailed" do
+ let(:faraday_exception) { Faraday::ConnectionFailed.new("fail") }
let(:expected_exception) { OAuth2::ConnectionError }
- it_behaves_like 'failed connection handler'
+ it_behaves_like "failed connection handler"
end
- context 'with Faraday::TimeoutError' do
- let(:faraday_exception) { Faraday::TimeoutError.new('timeout') }
+ context "with Faraday::TimeoutError" do
+ let(:faraday_exception) { Faraday::TimeoutError.new("timeout") }
let(:expected_exception) { OAuth2::TimeoutError }
- it_behaves_like 'failed connection handler'
+ it_behaves_like "failed connection handler"
end
end
end
- describe '#get_token' do
- it 'returns a configured AccessToken' do
+ describe "#get_token" do
+ it "returns a configured AccessToken" do
client = stubbed_client do |stub|
- stub.post('/oauth/token') do
- [200, {'Content-Type' => 'application/json'}, JSON.dump('access_token' => 'the-token')]
+ stub.post("/oauth/token") do
+ [200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-token")]
end
end
token = client.get_token({})
expect(token).to be_a OAuth2::AccessToken
- expect(token.token).to eq('the-token')
+ expect(token.token).to eq("the-token")
end
- context 'when parse: :automatic' do
- it 'returns a configured AccessToken' do
+ context "when parse: :automatic" do
+ it "returns a configured AccessToken" do
client = stubbed_client do |stub|
- stub.post('/oauth/token') do
- [200, {'Content-Type' => 'application/json'}, JSON.dump('access_token' => 'the-token')]
+ stub.post("/oauth/token") do
+ [200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-token")]
end
end
token = client.get_token(parse: :automatic)
expect(token).to be_a OAuth2::AccessToken
- expect(token.token).to eq('the-token')
+ expect(token.token).to eq("the-token")
end
end
- context 'when parse: :xml but response is JSON' do
- it 'returns a configured AccessToken' do
+ context "when parse: :xml but response is JSON" do
+ it "returns a configured AccessToken" do
client = stubbed_client do |stub|
- stub.post('/oauth/token') do
- [200, {'Content-Type' => 'application/json'}, JSON.dump('access_token' => 'the-token')]
+ stub.post("/oauth/token") do
+ [200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-token")]
end
end
- expect { client.get_token(parse: :xml) }.to raise_error(
- MultiXml::ParseError,
- 'The document "{\"access_token\":\"the-token\"}" does not have a valid root'
- )
+ expect { client.get_token(parse: :xml) }.to raise_error(MultiXml::ParseError)
end
end
- context 'when parse is fuzzed' do
- it 'returns a configured AccessToken' do
+ context "when parse is fuzzed" do
+ it "returns a configured AccessToken" do
client = stubbed_client do |stub|
- stub.post('/oauth/token') do
- [200, {'Content-Type' => 'application/json'}, JSON.dump('access_token' => 'the-token')]
+ stub.post("/oauth/token") do
+ [200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-token")]
end
end
- token = client.get_token(parse: 'random')
+ token = client.get_token(parse: "random")
expect(token).to be_a OAuth2::AccessToken
- expect(token.token).to eq('the-token')
+ expect(token.token).to eq("the-token")
end
end
- context 'when parse is correct' do
- it 'returns a configured AccessToken' do
+ context "when parse is correct" do
+ it "returns a configured AccessToken" do
client = stubbed_client do |stub|
- stub.post('/oauth/token') do
- [200, {'Content-Type' => 'application/json'}, JSON.dump('access_token' => 'the-token')]
+ stub.post("/oauth/token") do
+ [200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-token")]
end
end
token = client.get_token(parse: :json)
expect(token).to be_a OAuth2::AccessToken
- expect(token.token).to eq('the-token')
+ expect(token.token).to eq("the-token")
end
end
- context 'when snaky is falsy, but response is snaky' do
- it 'returns a configured AccessToken' do
+ context "when snaky is falsy, but response is snaky" do
+ it "returns a configured AccessToken" do
client = stubbed_client do |stub|
- stub.post('/oauth/token') do
- [200, {'Content-Type' => 'application/json'}, JSON.dump('access_token' => 'the-token')]
+ stub.post("/oauth/token") do
+ [200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-token")]
end
end
token = client.get_token(snaky: false)
expect(token).to be_a OAuth2::AccessToken
- expect(token.token).to eq('the-token')
- expect(token.response.parsed.to_h).to eq('access_token' => 'the-token')
+ expect(token.token).to eq("the-token")
+ expect(token.response.parsed.to_h).to eq("access_token" => "the-token")
end
end
- context 'when snaky is falsy, but response is not snaky' do
- it 'returns a configured AccessToken' do
+ context "when snaky is falsy, but response is not snaky" do
+ it "returns a configured AccessToken" do
client = stubbed_client do |stub|
- stub.post('/oauth/token') do
- [200, {'Content-Type' => 'application/json'}, JSON.dump('accessToken' => 'the-token')]
+ stub.post("/oauth/token") do
+ [200, {"Content-Type" => "application/json"}, JSON.dump("accessToken" => "the-token")]
end
end
- token = client.get_token({snaky: false}, {param_name: 'accessToken'})
+ token = client.get_token({snaky: false}, {param_name: "accessToken"})
expect(token).to be_a OAuth2::AccessToken
- expect(token.token).to eq('the-token')
- expect(token.response.parsed.to_h).to eq('accessToken' => 'the-token')
+ expect(token.token).to eq("the-token")
+ expect(token.response.parsed.to_h).to eq("accessToken" => "the-token")
end
end
- it 'authenticates with request parameters' do
+ it "authenticates with request parameters" do
client = stubbed_client(auth_scheme: :request_body) do |stub|
- stub.post('/oauth/token', 'client_id' => 'abc', 'client_secret' => 'def') do |_env|
- [200, {'Content-Type' => 'application/json'}, JSON.dump('access_token' => 'the-token')]
+ stub.post("/oauth/token", "client_id" => "abc", "client_secret" => "def") do |_env|
+ [200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-token")]
end
end
client.get_token({})
end
- it 'authenticates with Basic auth' do
+ it "authenticates with Basic auth" do
client = stubbed_client(auth_scheme: :basic_auth) do |stub|
- stub.post('/oauth/token') do |env|
- raise Faraday::Adapter::Test::Stubs::NotFound unless env[:request_headers]['Authorization'] == OAuth2::Authenticator.encode_basic_auth('abc', 'def')
+ stub.post("/oauth/token") do |env|
+ raise Faraday::Adapter::Test::Stubs::NotFound unless env[:request_headers]["Authorization"] == OAuth2::Authenticator.encode_basic_auth("abc", "def")
- [200, {'Content-Type' => 'application/json'}, JSON.dump('access_token' => 'the-token')]
+ [200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-token")]
end
end
client.get_token({})
end
- it 'authenticates with JSON' do
+ it "authenticates with JSON" do
client = stubbed_client(auth_scheme: :basic_auth) do |stub|
- stub.post('/oauth/token') do |env|
- [200, {'Content-Type' => 'application/json'}, JSON.dump('access_token' => 'the-token')]
+ stub.post("/oauth/token") do |env|
+ [200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-token")]
end
end
- client.get_token(headers: {'Content-Type' => 'application/json'})
+ client.get_token(headers: {"Content-Type" => "application/json"})
end
- it 'sets the response object on the access token' do
+ it "sets the response object on the access token" do
client = stubbed_client do |stub|
- stub.post('/oauth/token') do
- [200, {'Content-Type' => 'application/json'}, JSON.dump('access_token' => 'the-token')]
+ stub.post("/oauth/token") do
+ [200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-token")]
end
end
token = client.get_token({})
expect(token.response).to be_a OAuth2::Response
- expect(token.response.parsed).to eq('access_token' => 'the-token')
+ expect(token.response.parsed).to eq("access_token" => "the-token")
end
- context 'when the :raise_errors flag is set to false' do
+ context "when the :raise_errors flag is set to false" do
let(:body) { nil }
let(:status_code) { 500 }
- let(:content_type) { 'application/json' }
+ let(:content_type) { "application/json" }
let(:client) do
stubbed_client(raise_errors: false) do |stub|
- stub.post('/oauth/token') do
- [status_code, {'Content-Type' => content_type}, body]
+ stub.post("/oauth/token") do
+ [status_code, {"Content-Type" => content_type}, body]
end
end
end
- context 'when the request body is nil' do
+ context "when the request body is nil" do
subject(:get_token) { client.get_token({}) }
- it 'raises error JSON::ParserError' do
+ it "raises error JSON::ParserError" do
block_is_expected { get_token }.to raise_error(JSON::ParserError)
end
- context 'when extract_access_token raises an exception' do
+ context "when extract_access_token raises an exception" do
let(:status_code) { 200 }
let(:extract_proc) { proc { |client, hash| raise ArgumentError } }
- it 'returns a nil :access_token' do
+ it "returns a nil :access_token" do
expect(client.get_token({}, {}, extract_proc)).to eq(nil)
end
end
end
- context 'when status code is 200' do
+ context "when status code is 200" do
let(:status_code) { 200 }
- context 'when the request body is not nil' do
- let(:body) { JSON.dump('access_token' => 'the-token') }
+ context "when the request body is not nil" do
+ let(:body) { JSON.dump("access_token" => "the-token") }
- it 'returns the parsed :access_token from body' do
+ it "returns the parsed :access_token from body" do
token = client.get_token({})
expect(token.response).to be_a OAuth2::Response
- expect(token.response.parsed).to eq('access_token' => 'the-token')
+ expect(token.response.parsed).to eq("access_token" => "the-token")
end
end
- context 'when Content-Type is not JSON' do
- let(:content_type) { 'text/plain' }
- let(:body) { 'hello world' }
+ context "when Content-Type is not JSON" do
+ let(:content_type) { "text/plain" }
+ let(:body) { "hello world" }
- it 'returns the parsed :access_token from body' do
+ it "returns the parsed :access_token from body" do
expect(client.get_token({})).to be_nil
end
end
end
end
- describe 'with custom access_token_class option' do
+ describe "with custom access_token_class option" do
let(:options) { {access_token_class: CustomAccessToken} }
- let(:payload) { {'custom_token' => 'the-token'} }
- let(:content_type) { 'application/json' }
+ let(:payload) { {"custom_token" => "the-token"} }
+ let(:content_type) { "application/json" }
let(:client) do
stubbed_client(options) do |stub|
- stub.post('/oauth/token') do
- [200, {'Content-Type' => content_type}, JSON.dump(payload)]
+ stub.post("/oauth/token") do
+ [200, {"Content-Type" => content_type}, JSON.dump(payload)]
end
end
end
@@ -696,96 +693,96 @@
attr_accessor :response
def self.from_hash(client, hash)
- new(client, hash.delete('custom_token'))
+ new(client, hash.delete("custom_token"))
end
def self.contains_token?(hash)
- hash.key?('custom_token')
+ hash.key?("custom_token")
end
end
- stub_const('CustomAccessToken', custom_class)
+ stub_const("CustomAccessToken", custom_class)
end
- it 'returns the parsed :custom_token from body' do
+ it "returns the parsed :custom_token from body" do
client.get_token({})
end
- context 'when the :raise_errors flag is set to true' do
+ context "when the :raise_errors flag is set to true" do
let(:options) { {access_token_class: CustomAccessToken, raise_errors: true} }
let(:payload) { {} }
- it 'raises an error' do
+ it "raises an error" do
expect { client.get_token({}) }.to raise_error(OAuth2::Error)
end
- context 'when the legacy extract_access_token' do
+ context "when the legacy extract_access_token" do
let(:extract_access_token) do
proc do |client, hash|
- token = hash['data']['access_token']
+ token = hash["data"]["access_token"]
OAuth2::AccessToken.new(client, token, hash)
end
end
let(:options) { {raise_errors: true} }
let(:payload) { {} }
- it 'raises an error' do
+ it "raises an error" do
expect { client.get_token({}, {}, extract_access_token) }.to raise_error(OAuth2::Error)
end
end
end
- context 'when status code is 200' do
+ context "when status code is 200" do
let(:status_code) { 200 }
- context 'when the request body is blank' do
+ context "when the request body is blank" do
let(:payload) { {} }
- it 'raises an error' do
+ it "raises an error" do
expect { client.get_token({}) }.to raise_error(OAuth2::Error)
end
end
- context 'when Content-Type is not JSON' do
- let(:content_type) { 'text/plain' }
- let(:body) { 'hello world' }
+ context "when Content-Type is not JSON" do
+ let(:content_type) { "text/plain" }
+ let(:body) { "hello world" }
- it 'raises an error' do
+ it "raises an error" do
expect { client.get_token({}) }.to raise_error(OAuth2::Error)
end
end
end
- context 'when access token instance responds to response=' do
+ context "when access token instance responds to response=" do
let(:options) { {access_token_class: CustomAccessToken, raise_errors: false} }
- it 'sets response' do
+ it "sets response" do
expect(client.get_token({}).response).to be_a(OAuth2::Response)
end
end
- context 'when request has a block' do
+ context "when request has a block" do
subject(:request) do
client.get_token({}) do |req|
- raise 'Block is executing'
+ raise "Block is executing"
end
end
let(:options) { {access_token_class: CustomAccessToken, raise_errors: false} }
- it 'sets response' do
- block_is_expected.to raise_error('Block is executing')
+ it "sets response" do
+ block_is_expected.to raise_error("Block is executing")
end
end
end
- describe 'abnormal custom access_token_class option' do
- let(:payload) { {'custom_token' => 'the-token'} }
- let(:content_type) { 'application/json' }
+ describe "abnormal custom access_token_class option" do
+ let(:payload) { {"custom_token" => "the-token"} }
+ let(:content_type) { "application/json" }
let(:client) do
stubbed_client(options) do |stub|
- stub.post('/oauth/token') do
- [200, {'Content-Type' => content_type}, JSON.dump(payload)]
+ stub.post("/oauth/token") do
+ [200, {"Content-Type" => content_type}, JSON.dump(payload)]
end
end
end
@@ -796,31 +793,31 @@ def initialize(client, hash)
end
def self.from_hash(client, hash)
- new(client, hash.delete('custom_token'))
+ new(client, hash.delete("custom_token"))
end
def self.contains_token?(hash)
- hash.key?('custom_token')
+ hash.key?("custom_token")
end
end
- stub_const('StrangeAccessToken', custom_class)
+ stub_const("StrangeAccessToken", custom_class)
end
- context 'when the :raise_errors flag is set to true' do
+ context "when the :raise_errors flag is set to true" do
let(:options) { {access_token_class: StrangeAccessToken, raise_errors: true} }
let(:payload) { {} }
- it 'raises an error' do
+ it "raises an error" do
expect { client.get_token({}) }.to raise_error(OAuth2::Error)
end
end
- context 'when access token instance does not responds to response=' do
+ context "when access token instance does not responds to response=" do
let(:options) { {access_token_class: StrangeAccessToken} }
- let(:payload) { {'custom_token' => 'the-token'} }
+ let(:payload) { {"custom_token" => "the-token"} }
- it 'sets response' do
+ it "sets response" do
token_access = client.get_token({})
expect(token_access).to be_a(StrangeAccessToken)
expect(token_access).not_to respond_to(:response=)
@@ -828,58 +825,58 @@ def self.contains_token?(hash)
end
end
- context 'when request has a block' do
+ context "when request has a block" do
subject(:request) do
client.get_token({}) do |req|
- raise 'Block is executing'
+ raise "Block is executing"
end
end
let(:options) { {access_token_class: StrangeAccessToken} }
- it 'sets response' do
- block_is_expected.to raise_error('Block is executing')
+ it "sets response" do
+ block_is_expected.to raise_error("Block is executing")
end
end
end
- describe 'with extract_access_token option' do
+ describe "with extract_access_token option" do
let(:client) do
stubbed_client(extract_access_token: extract_access_token) do |stub|
- stub.post('/oauth/token') do
- [200, {'Content-Type' => 'application/json'}, JSON.dump('data' => {'access_token' => 'the-token'})]
+ stub.post("/oauth/token") do
+ [200, {"Content-Type" => "application/json"}, JSON.dump("data" => {"access_token" => "the-token"})]
end
end
end
let(:extract_access_token) do
proc do |client, hash|
- token = hash['data']['access_token']
+ token = hash["data"]["access_token"]
OAuth2::AccessToken.new(client, token, hash)
end
end
- it 'returns a configured AccessToken' do
+ it "returns a configured AccessToken" do
token = client.get_token({})
expect(token).to be_a OAuth2::AccessToken
- expect(token.token).to eq('the-token')
+ expect(token.token).to eq("the-token")
end
- context 'with deprecation' do
+ context "with deprecation" do
subject(:printed) do
capture(:stderr) do
client.get_token({})
end
end
- it 'warns on STDERR' do
+ it "warns on STDERR" do
msg = <<-MSG.lstrip
OAuth2::Client#initialize argument `extract_access_token` will be removed in oauth2 v3. Refactor to use `access_token_class`.
MSG
expect(printed).to eq(msg)
end
- context 'on request' do
+ context "on request" do
subject(:printed) do
capture(:stderr) do
client.get_token({}, {}, extract_access_token)
@@ -888,13 +885,13 @@ def self.contains_token?(hash)
let(:client) do
stubbed_client do |stub|
- stub.post('/oauth/token') do
- [200, {'Content-Type' => 'application/json'}, JSON.dump('data' => {'access_token' => 'the-token'})]
+ stub.post("/oauth/token") do
+ [200, {"Content-Type" => "application/json"}, JSON.dump("data" => {"access_token" => "the-token"})]
end
end
end
- it 'warns on STDERR' do
+ it "warns on STDERR" do
msg = <<-MSG.lstrip
OAuth2::Client#get_token argument `extract_access_token` will be removed in oauth2 v3. Refactor to use `access_token_class` on #initialize.
MSG
@@ -904,73 +901,73 @@ def self.contains_token?(hash)
end
end
- it 'forwards given token parameters' do
+ it "forwards given token parameters" do
client = stubbed_client(auth_scheme: :request_body) do |stub|
- stub.post('/oauth/token', 'arbitrary' => 'parameter', 'client_id' => 'abc', 'client_secret' => 'def') do |_env|
- [200, {'Content-Type' => 'application/json'}, JSON.dump('access_token' => 'the-token')]
+ stub.post("/oauth/token", "arbitrary" => "parameter", "client_id" => "abc", "client_secret" => "def") do |_env|
+ [200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-token")]
end
end
- client.get_token({'arbitrary' => 'parameter'}) # rubocop:disable Style/BracesAroundHashParameters
+ client.get_token({"arbitrary" => "parameter"}) # rubocop:disable Style/BracesAroundHashParameters
end
- context 'when token_method is set to post_with_query_string' do
- it 'uses the http post method and passes parameters in the query string' do
+ context "when token_method is set to post_with_query_string" do
+ it "uses the http post method and passes parameters in the query string" do
client = stubbed_client(token_method: :post_with_query_string) do |stub|
- stub.post('/oauth/token?state=abc123') do |_env|
- [200, {'Content-Type' => 'application/json'}, JSON.dump('access_token' => 'the-token')]
+ stub.post("/oauth/token?state=abc123") do |_env|
+ [200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-token")]
end
end
- client.get_token({'state' => 'abc123'}) # rubocop:disable Style/BracesAroundHashParameters
+ client.get_token({"state" => "abc123"}) # rubocop:disable Style/BracesAroundHashParameters
end
end
def stubbed_client(params = {}, &stubs)
- params = {site: 'https://api.example.com'}.merge(params)
- OAuth2::Client.new('abc', 'def', params) do |builder|
+ params = {site: "https://api.example.com"}.merge(params)
+ OAuth2::Client.new("abc", "def", params) do |builder|
builder.adapter :test, &stubs
end
end
end
- it 'instantiates an HTTP Method with this client' do
- expect(subject.http_method).to be_kind_of(Symbol)
+ it "instantiates an HTTP Method with this client" do
+ expect(subject.http_method).to be_a(Symbol)
end
- it 'instantiates an AuthCode strategy with this client' do
- expect(subject.auth_code).to be_kind_of(OAuth2::Strategy::AuthCode)
+ it "instantiates an AuthCode strategy with this client" do
+ expect(subject.auth_code).to be_a(OAuth2::Strategy::AuthCode)
end
- it 'instantiates an Implicit strategy with this client' do
- expect(subject.implicit).to be_kind_of(OAuth2::Strategy::Implicit)
+ it "instantiates an Implicit strategy with this client" do
+ expect(subject.implicit).to be_a(OAuth2::Strategy::Implicit)
end
- context 'with SSL options' do
+ context "with SSL options" do
subject do
- cli = described_class.new('abc', 'def', site: 'https://api.example.com', ssl: {ca_file: 'foo.pem'})
+ cli = described_class.new("abc", "def", site: "https://api.example.com", ssl: {ca_file: "foo.pem"})
cli.connection = Faraday.new(cli.site, cli.options[:connection_opts]) do |b|
b.adapter :test
end
cli
end
- it 'passes the SSL options along to Faraday::Connection#ssl' do
- expect(subject.connection.ssl.fetch(:ca_file)).to eq('foo.pem')
+ it "passes the SSL options along to Faraday::Connection#ssl" do
+ expect(subject.connection.ssl.fetch(:ca_file)).to eq("foo.pem")
end
end
- context 'without a connection-configuration block' do
+ context "without a connection-configuration block" do
subject do
- described_class.new('abc', 'def', site: 'https://api.example.com')
+ described_class.new("abc", "def", site: "https://api.example.com")
end
- it 'applies default faraday middleware to the connection' do
+ it "applies default faraday middleware to the connection" do
expect(subject.connection.builder.handlers).to include(Faraday::Request::UrlEncoded)
end
end
- describe '#inspect' do
- it 'filters out the @secret value' do
- expect(subject.inspect).to include('@secret=[FILTERED]')
+ describe "#inspect" do
+ it "filters out the @secret value" do
+ expect(subject.inspect).to include("@secret=[FILTERED]")
end
end
end
diff --git a/spec/oauth2/error_spec.rb b/spec/oauth2/error_spec.rb
index fb1ed492..893dce35 100644
--- a/spec/oauth2/error_spec.rb
+++ b/spec/oauth2/error_spec.rb
@@ -1,4 +1,4 @@
-# encoding: UTF-8
+# encoding: utf-8
# frozen_string_literal: true
class StirredHash < Hash
@@ -14,7 +14,7 @@ class XmledString < String
� Cool � XmledString
-'.freeze
+'
def to_str
XML
end
@@ -27,119 +27,119 @@ def to_str
raw_response = Faraday::Response.new(
status: 418,
response_headers: response_headers,
- body: response_body
+ body: response_body,
)
OAuth2::Response.new(raw_response)
end
- let(:response_headers) { {'Content-Type' => 'application/json'} }
- let(:response_body) { {text: 'Coffee brewing failed'}.to_json }
+ let(:response_headers) { {"Content-Type" => "application/json"} }
+ let(:response_body) { {text: "Coffee brewing failed"}.to_json }
- it 'sets the response object to #response on self' do
+ it "sets the response object to #response on self" do
error = described_class.new(response)
expect(error.response).to equal(response)
end
- describe 'attr_readers' do
- it 'has code' do
+ describe "attr_readers" do
+ it "has code" do
expect(subject).to respond_to(:code)
end
- it 'has description' do
+ it "has description" do
expect(subject).to respond_to(:description)
end
- it 'has response' do
+ it "has response" do
expect(subject).to respond_to(:response)
end
end
- context 'when the response is parsed' do
+ context "when the response is parsed" do
let(:response_body) { response_hash.to_json }
- let(:response_hash) { {text: 'Coffee brewing failed'} }
+ let(:response_hash) { {text: "Coffee brewing failed"} }
- context 'when the response has an error and error_description' do
+ context "when the response has an error and error_description" do
before do
- response_hash['error_description'] = 'Short and stout'
- response_hash['error'] = 'i_am_a_teapot'
+ response_hash["error_description"] = "Short and stout"
+ response_hash["error"] = "i_am_a_teapot"
end
- it 'sets the code attribute' do
- expect(subject.code).to eq('i_am_a_teapot')
+ it "sets the code attribute" do
+ expect(subject.code).to eq("i_am_a_teapot")
end
- it 'sets the description attribute' do
- expect(subject.description).to eq('Short and stout')
+ it "sets the description attribute" do
+ expect(subject.description).to eq("Short and stout")
end
- it 'prepends to the error message with a return character' do
+ it "prepends to the error message with a return character" do
expect(subject.message.each_line.to_a).to eq(
[
"i_am_a_teapot: Short and stout\n",
'{"text":"Coffee brewing failed","error_description":"Short and stout","error":"i_am_a_teapot"}',
- ]
+ ],
)
end
- context 'when the response needs to be encoded' do
- let(:response_body) { JSON.dump(response_hash).force_encoding('ASCII-8BIT') }
+ context "when the response needs to be encoded" do
+ let(:response_body) { JSON.dump(response_hash).force_encoding("ASCII-8BIT") }
- context 'with invalid characters present' do
+ context "with invalid characters present" do
before do
- response_body.gsub!('stout', "\255 invalid \255")
+ response_body.gsub!("stout", "\255 invalid \255")
end
- it 'replaces them' do
+ it "replaces them" do
# The skip can be removed once support for < 2.1 is dropped.
- encoding = {reason: 'encode/scrub only works as of Ruby 2.1'}
- skip_for(encoding.merge(engine: 'jruby'))
+ encoding = {reason: "encode/scrub only works as of Ruby 2.1"}
+ skip_for(encoding.merge(engine: "jruby"))
# See https://bibwild.wordpress.com/2013/03/12/removing-illegal-bytes-for-encoding-in-ruby-1-9-strings/
- raise 'Invalid characters not replaced' unless subject.message.include?('� invalid �')
+ raise "Invalid characters not replaced" unless subject.message.include?("� invalid �")
# This will fail if {:invalid => replace} is not passed into `encode`
end
end
- context 'with undefined characters present' do
+ context "with undefined characters present" do
before do
- response_hash['error_description'] += ": 'A magical voyage of tea 🍵'"
+ response_hash["error_description"] += ": 'A magical voyage of tea 🍵'"
end
- it 'replaces them' do
- raise 'Undefined characters not replaced' unless subject.message.include?('tea �')
+ it "replaces them" do
+ raise "Undefined characters not replaced" unless subject.message.include?("tea �")
# This will fail if {:undef => replace} is not passed into `encode`
end
end
end
- context 'when the response is not an encodable thing' do
- let(:response_headers) { {'Content-Type' => 'who knows'} }
- let(:response_body) { {text: 'Coffee brewing failed'} }
+ context "when the response is not an encodable thing" do
+ let(:response_headers) { {"Content-Type" => "who knows"} }
+ let(:response_body) { {text: "Coffee brewing failed"} }
before do
expect(response_body).not_to respond_to(:encode)
# i.e. a Ruby hash
end
- it 'does not try to encode the message string' do
+ it "does not try to encode the message string" do
expect(subject.message).to eq(response_body.to_s)
end
end
- context 'when using :json parser with non-encodable data' do
- let(:response_headers) { {'Content-Type' => 'application/hal+json'} }
+ context "when using :json parser with non-encodable data" do
+ let(:response_headers) { {"Content-Type" => "application/hal+json"} }
let(:response_body) do
- StirredHash.new(
+ StirredHash[
"_links": {
- "self": {"href": '/orders/523'},
- "warehouse": {"href": '/warehouse/56'},
- "invoice": {"href": '/invoices/873'},
+ "self": {"href": "/orders/523"},
+ "warehouse": {"href": "/warehouse/56"},
+ "invoice": {"href": "/invoices/873"},
},
- "currency": 'USD',
- "status": 'shipped',
- "total": 10.20
- )
+ "currency": "USD",
+ "status": "shipped",
+ "total": 10.20,
+ ]
end
before do
@@ -147,13 +147,13 @@ def to_str
expect(response_body).to respond_to(:to_str)
end
- it 'does not force encode the message' do
+ it "does not force encode the message" do
expect(subject.message).to eq('{"hello":"� Cool � StirredHash"}')
end
end
- context 'when using :xml parser' do
- let(:response_headers) { {'Content-Type' => 'text/xml'} }
+ context "when using :xml parser" do
+ let(:response_headers) { {"Content-Type" => "text/xml"} }
let(:response_body) do
XmledString.new(XmledString::XML)
end
@@ -162,482 +162,492 @@ def to_str
expect(response_body).to respond_to(:to_str)
end
- it 'parses the XML' do
+ it "parses the XML" do
expect(subject.message).to eq(XmledString::XML)
end
end
- context 'when using :xml parser with non-String-like thing' do
- let(:response_headers) { {'Content-Type' => 'text/xml'} }
+ context "when using :xml parser with non-String-like thing" do
+ let(:response_headers) { {"Content-Type" => "text/xml"} }
let(:response_body) { {hello: :world} }
before do
expect(response_body).not_to respond_to(:to_str)
end
- it 'just returns the thing if it can' do
- expect(subject.message).to eq('{:hello=>:world}')
+ it "just returns the thing if it can" do
+ expect(subject.message).to eq({hello: :world}.to_s)
end
end
end
- it 'sets the code attribute to nil' do
+ it "sets the code attribute to nil" do
expect(subject.code).to be_nil
end
- it 'sets the description attribute' do
+ it "sets the description attribute" do
expect(subject.description).to be_nil
end
- context 'when there is no error description' do
+ context "when there is no error description" do
before do
- expect(response_hash).not_to have_key('error')
- expect(response_hash).not_to have_key('error_description')
+ expect(response_hash).not_to have_key("error")
+ expect(response_hash).not_to have_key("error_description")
end
- it 'does not prepend anything to the message' do
+ it "does not prepend anything to the message" do
expect(subject.message.lines.count).to eq(1)
expect(subject.message).to eq '{"text":"Coffee brewing failed"}'
end
- it 'does not set code' do
+ it "does not set code" do
expect(subject.code).to be_nil
end
- it 'does not set description' do
+ it "does not set description" do
expect(subject.description).to be_nil
end
end
- context 'when there is code (error)' do
+ context "when there is code (error)" do
before do
- response_hash['error_description'] = 'Short and stout'
- response_hash['error'] = 'i_am_a_teapot'
- response_hash['status'] = '418'
+ response_hash["error_description"] = "Short and stout"
+ response_hash["error"] = "i_am_a_teapot"
+ response_hash["status"] = "418"
end
- it 'prepends to the error message with a return character' do
+ it "prepends to the error message with a return character" do
expect(subject.message.each_line.to_a).to eq(
[
"i_am_a_teapot: Short and stout\n",
{
- "text": 'Coffee brewing failed',
- "error_description": 'Short and stout',
- "error": 'i_am_a_teapot',
- "status": '418',
+ "text": "Coffee brewing failed",
+ "error_description": "Short and stout",
+ "error": "i_am_a_teapot",
+ "status": "418",
}.to_json,
- ]
+ ],
)
end
- context 'when the response needs to be encoded' do
- let(:response_body) { JSON.dump(response_hash).force_encoding('ASCII-8BIT') }
+ context "when the response needs to be encoded" do
+ let(:response_body) { JSON.dump(response_hash).force_encoding("ASCII-8BIT") }
- context 'with invalid characters present' do
+ context "with invalid characters present" do
before do
- response_body.gsub!('stout', "\255 invalid \255")
+ response_body.gsub!("stout", "\255 invalid \255")
end
- it 'replaces them' do
+ it "replaces them" do
# The skip can be removed once support for < 2.1 is dropped.
- encoding = {reason: 'encode/scrub only works as of Ruby 2.1'}
- skip_for(encoding.merge(engine: 'jruby'))
+ encoding = {reason: "encode/scrub only works as of Ruby 2.1"}
+ skip_for(encoding.merge(engine: "jruby"))
# See https://bibwild.wordpress.com/2013/03/12/removing-illegal-bytes-for-encoding-in-ruby-1-9-strings/
- raise 'Invalid characters not replaced' unless subject.message.include?('� invalid �')
+ raise "Invalid characters not replaced" unless subject.message.include?("� invalid �")
# This will fail if {:invalid => replace} is not passed into `encode`
end
end
- context 'with undefined characters present' do
+ context "with undefined characters present" do
before do
- response_hash['error_description'] += ": 'A magical voyage of tea 🍵'"
+ response_hash["error_description"] += ": 'A magical voyage of tea 🍵'"
end
- it 'replaces them' do
- raise 'Undefined characters not replaced' unless subject.message.include?('tea �')
+ it "replaces them" do
+ raise "Undefined characters not replaced" unless subject.message.include?("tea �")
# This will fail if {:undef => replace} is not passed into `encode`
end
end
end
- context 'when the response is not an encodable thing' do
- let(:response_headers) { {'Content-Type' => 'who knows'} }
- let(:response_body) { {text: 'Coffee brewing failed'} }
+ context "when the response is not an encodable thing" do
+ let(:response_headers) { {"Content-Type" => "who knows"} }
+ let(:response_body) { {text: "Coffee brewing failed"} }
before do
expect(response_body).not_to respond_to(:encode)
# i.e. a Ruby hash
end
- it 'does not try to encode the message string' do
+ it "does not try to encode the message string" do
expect(subject.message).to eq(response_body.to_s)
end
end
- it 'sets the code attribute' do
- expect(subject.code).to eq('i_am_a_teapot')
+ it "sets the code attribute" do
+ expect(subject.code).to eq("i_am_a_teapot")
end
- it 'sets the description attribute' do
- expect(subject.description).to eq('Short and stout')
+ it "sets the description attribute" do
+ expect(subject.description).to eq("Short and stout")
end
end
- context 'when there is code (error) but no error_description' do
+ context "when there is code (error) but no error_description" do
before do
- response_hash.delete('error_description')
- response_hash['error'] = 'i_am_a_teapot'
- response_hash['status'] = '418'
+ response_hash.delete("error_description")
+ response_hash["error"] = "i_am_a_teapot"
+ response_hash["status"] = "418"
end
- it 'prepends to the error message with a return character' do
+ it "prepends to the error message with a return character" do
expect(subject.message.each_line.to_a).to eq(
[
"i_am_a_teapot: \n",
{
- "text": 'Coffee brewing failed',
- "error": 'i_am_a_teapot',
- "status": '418',
+ "text": "Coffee brewing failed",
+ "error": "i_am_a_teapot",
+ "status": "418",
}.to_json,
- ]
+ ],
)
end
- context 'when the response needs to be encoded' do
- let(:response_body) { JSON.dump(response_hash).force_encoding('ASCII-8BIT') }
+ context "when the response needs to be encoded" do
+ let(:response_body) { JSON.dump(response_hash).force_encoding("ASCII-8BIT") }
- context 'with invalid characters present' do
+ context "with invalid characters present" do
before do
- response_body.gsub!('brewing', "\255 invalid \255")
+ response_body.gsub!("brewing", "\255 invalid \255")
end
- it 'replaces them' do
+ it "replaces them" do
# The skip can be removed once support for < 2.1 is dropped.
- encoding = {reason: 'encode/scrub only works as of Ruby 2.1'}
- skip_for(encoding.merge(engine: 'jruby'))
+ encoding = {reason: "encode/scrub only works as of Ruby 2.1"}
+ skip_for(encoding.merge(engine: "jruby"))
# See https://bibwild.wordpress.com/2013/03/12/removing-illegal-bytes-for-encoding-in-ruby-1-9-strings/
- raise 'Invalid characters not replaced' unless subject.message.include?('� invalid �')
+ raise "Invalid characters not replaced" unless subject.message.include?("� invalid �")
# This will fail if {:invalid => replace} is not passed into `encode`
end
end
end
- context 'when the response is not an encodable thing' do
- let(:response_headers) { {'Content-Type' => 'who knows'} }
- let(:response_body) { {text: 'Coffee brewing failed'} }
+ context "when the response is not an encodable thing" do
+ let(:response_headers) { {"Content-Type" => "who knows"} }
+ let(:response_body) { {text: "Coffee brewing failed"} }
before do
expect(response_body).not_to respond_to(:encode)
# i.e. a Ruby hash
end
- it 'does not try to encode the message string' do
+ it "does not try to encode the message string" do
expect(subject.message).to eq(response_body.to_s)
end
end
- it 'sets the code attribute from error' do
- expect(subject.code).to eq('i_am_a_teapot')
+ it "sets the code attribute from error" do
+ expect(subject.code).to eq("i_am_a_teapot")
end
- it 'does not set the description attribute' do
+ it "does not set the description attribute" do
expect(subject.description).to be_nil
end
end
- context 'when there is error_description but no code (error)' do
+ context "when there is error_description but no code (error)" do
before do
- response_hash['error_description'] = 'Short and stout'
- response_hash.delete('error')
+ response_hash["error_description"] = "Short and stout"
+ response_hash.delete("error")
end
- it 'prepends to the error message with a return character' do
+ it "prepends to the error message with a return character" do
expect(subject.message.each_line.to_a).to eq(
[
"Short and stout\n",
{
- "text": 'Coffee brewing failed',
- "error_description": 'Short and stout',
+ "text": "Coffee brewing failed",
+ "error_description": "Short and stout",
}.to_json,
- ]
+ ],
)
end
- context 'when the response needs to be encoded' do
- let(:response_body) { JSON.dump(response_hash).force_encoding('ASCII-8BIT') }
+ context "when the response needs to be encoded" do
+ let(:response_body) { JSON.dump(response_hash).force_encoding("ASCII-8BIT") }
- context 'with invalid characters present' do
+ context "with invalid characters present" do
before do
- response_body.gsub!('stout', "\255 invalid \255")
+ response_body.gsub!("stout", "\255 invalid \255")
end
- it 'replaces them' do
+ it "replaces them" do
# The skip can be removed once support for < 2.1 is dropped.
- encoding = {reason: 'encode/scrub only works as of Ruby 2.1'}
- skip_for(encoding.merge(engine: 'jruby'))
+ encoding = {reason: "encode/scrub only works as of Ruby 2.1"}
+ skip_for(encoding.merge(engine: "jruby"))
# See https://bibwild.wordpress.com/2013/03/12/removing-illegal-bytes-for-encoding-in-ruby-1-9-strings/
- raise 'Invalid characters not replaced' unless subject.message.include?('� invalid �')
+ raise "Invalid characters not replaced" unless subject.message.include?("� invalid �")
# This will fail if {:invalid => replace} is not passed into `encode`
end
end
- context 'with undefined characters present' do
+ context "with undefined characters present" do
before do
- response_hash['error_description'] += ": 'A magical voyage of tea 🍵'"
+ response_hash["error_description"] += ": 'A magical voyage of tea 🍵'"
end
- it 'replaces them' do
- raise 'Undefined characters not replaced' unless subject.message.include?('tea �')
+ it "replaces them" do
+ raise "Undefined characters not replaced" unless subject.message.include?("tea �")
# This will fail if {:undef => replace} is not passed into `encode`
end
end
end
- context 'when the response is not an encodable thing' do
- let(:response_headers) { {'Content-Type' => 'who knows'} }
- let(:response_body) { {text: 'Coffee brewing failed'} }
+ context "when the response is not an encodable thing" do
+ let(:response_headers) { {"Content-Type" => "who knows"} }
+ let(:response_body) { {text: "Coffee brewing failed"} }
before do
expect(response_body).not_to respond_to(:encode)
# i.e. a Ruby hash
end
- it 'does not try to encode the message string' do
+ it "does not try to encode the message string" do
expect(subject.message).to eq(response_body.to_s)
end
end
- it 'sets the code attribute' do
+ it "sets the code attribute" do
expect(subject.code).to be_nil
end
- it 'sets the description attribute' do
- expect(subject.description).to eq('Short and stout')
+ it "sets the description attribute" do
+ expect(subject.description).to eq("Short and stout")
end
end
end
- context 'when the response is simple hash, not parsed' do
+ context "when the response is simple hash, not parsed" do
subject { described_class.new(response_hash) }
- let(:response_hash) { {text: 'Coffee brewing failed'} }
+ let(:response_hash) { {text: "Coffee brewing failed"} }
- it 'sets the code attribute to nil' do
+ it "sets the code attribute to nil" do
expect(subject.code).to be_nil
end
- it 'sets the description attribute' do
+ it "sets the description attribute" do
expect(subject.description).to be_nil
end
- context 'when the response has an error and error_description' do
+ context "when the response has an error and error_description" do
before do
- response_hash['error_description'] = 'Short and stout'
- response_hash['error'] = 'i_am_a_teapot'
+ response_hash["error_description"] = "Short and stout"
+ response_hash["error"] = "i_am_a_teapot"
end
- it 'sets the code attribute' do
- expect(subject.code).to eq('i_am_a_teapot')
+ it "sets the code attribute" do
+ expect(subject.code).to eq("i_am_a_teapot")
end
- it 'sets the description attribute' do
- expect(subject.description).to eq('Short and stout')
+ it "sets the description attribute" do
+ expect(subject.description).to eq("Short and stout")
end
- it 'prepends to the error message with a return character' do
+ it "prepends to the error message with a return character" do
expect(subject.message.each_line.to_a).to eq(
[
"i_am_a_teapot: Short and stout\n",
- '{:text=>"Coffee brewing failed", "error_description"=>"Short and stout", "error"=>"i_am_a_teapot"}',
- ]
+ {:text => "Coffee brewing failed", "error_description" => "Short and stout", "error" => "i_am_a_teapot"}.to_s,
+ ],
)
end
- context 'when using :xml parser with non-String-like thing' do
- let(:response_headers) { {'Content-Type' => 'text/xml'} }
+ context "when using :xml parser with non-String-like thing" do
+ let(:response_headers) { {"Content-Type" => "text/xml"} }
let(:response_hash) { {hello: :world} }
before do
expect(response_hash).not_to respond_to(:to_str)
end
- it 'just returns whatever it can' do
- expect(subject.message).to eq("i_am_a_teapot: Short and stout\n{:hello=>:world, \"error_description\"=>\"Short and stout\", \"error\"=>\"i_am_a_teapot\"}")
+ it "just returns whatever it can" do
+ expect(subject.message.each_line.to_a).to eq(
+ [
+ "i_am_a_teapot: Short and stout\n",
+ {:hello => :world, "error_description" => "Short and stout", "error" => "i_am_a_teapot"}.to_s,
+ ],
+ )
end
end
end
- context 'when using :xml parser with non-String-like thing' do
- let(:response_headers) { {'Content-Type' => 'text/xml'} }
+ context "when using :xml parser with non-String-like thing" do
+ let(:response_headers) { {"Content-Type" => "text/xml"} }
let(:response_hash) { {hello: :world} }
before do
expect(response_hash).not_to respond_to(:to_str)
end
- it 'just returns the thing if it can' do
- expect(subject.message).to eq('{:hello=>:world}')
+ it "just returns the thing if it can" do
+ expect(subject.message).to eq({hello: :world}.to_s)
end
end
- context 'when there is no error description' do
+ context "when there is no error description" do
before do
- expect(response_hash).not_to have_key('error')
- expect(response_hash).not_to have_key('error_description')
+ expect(response_hash).not_to have_key("error")
+ expect(response_hash).not_to have_key("error_description")
end
- it 'does not prepend anything to the message' do
+ it "does not prepend anything to the message" do
expect(subject.message.lines.count).to eq(1)
- expect(subject.message).to eq '{:text=>"Coffee brewing failed"}'
+ expect(subject.message).to eq({text: "Coffee brewing failed"}.to_s)
end
- it 'does not set code' do
+ it "does not set code" do
expect(subject.code).to be_nil
end
- it 'does not set description' do
+ it "does not set description" do
expect(subject.description).to be_nil
end
end
- context 'when there is code (error)' do
+ context "when there is code (error)" do
before do
- response_hash['error_description'] = 'Short and stout'
- response_hash['error'] = 'i_am_a_teapot'
- response_hash['status'] = '418'
+ response_hash["error_description"] = "Short and stout"
+ response_hash["error"] = "i_am_a_teapot"
+ response_hash["status"] = "418"
end
- it 'prepends to the error message with a return character' do
+ it "prepends to the error message with a return character" do
expect(subject.message.each_line.to_a).to eq(
[
"i_am_a_teapot: Short and stout\n",
- '{:text=>"Coffee brewing failed", "error_description"=>"Short and stout", "error"=>"i_am_a_teapot", "status"=>"418"}',
- ]
+ {:text => "Coffee brewing failed", "error_description" => "Short and stout", "error" => "i_am_a_teapot", "status" => "418"}.to_s,
+ ],
)
end
- it 'sets the code attribute' do
- expect(subject.code).to eq('i_am_a_teapot')
+ it "sets the code attribute" do
+ expect(subject.code).to eq("i_am_a_teapot")
end
- it 'sets the description attribute' do
- expect(subject.description).to eq('Short and stout')
+ it "sets the description attribute" do
+ expect(subject.description).to eq("Short and stout")
end
end
- context 'when there is code (error) but no error_description' do
+ context "when there is code (error) but no error_description" do
before do
- response_hash.delete('error_description')
- response_hash['error'] = 'i_am_a_teapot'
- response_hash['status'] = '418'
+ response_hash.delete("error_description")
+ response_hash["error"] = "i_am_a_teapot"
+ response_hash["status"] = "418"
end
- it 'sets the code attribute from error' do
- expect(subject.code).to eq('i_am_a_teapot')
+ it "sets the code attribute from error" do
+ expect(subject.code).to eq("i_am_a_teapot")
end
- it 'does not set the description attribute' do
+ it "does not set the description attribute" do
expect(subject.description).to be_nil
end
- it 'prepends to the error message with a return character' do
+ it "prepends to the error message with a return character" do
expect(subject.message.each_line.to_a).to eq(
[
"i_am_a_teapot: \n",
- '{:text=>"Coffee brewing failed", "error"=>"i_am_a_teapot", "status"=>"418"}',
- ]
+ {:text => "Coffee brewing failed", "error" => "i_am_a_teapot", "status" => "418"}.to_s,
+ ],
)
end
end
- context 'when there is error_description but no code (error)' do
+ context "when there is error_description but no code (error)" do
before do
- response_hash['error_description'] = 'Short and stout'
- response_hash.delete('error')
+ response_hash["error_description"] = "Short and stout"
+ response_hash.delete("error")
end
- it 'prepends to the error message with a return character' do
+ it "prepends to the error message with a return character" do
expect(subject.message.each_line.to_a).to eq(
[
"Short and stout\n",
- '{:text=>"Coffee brewing failed", "error_description"=>"Short and stout"}',
- ]
+ {:text => "Coffee brewing failed", "error_description" => "Short and stout"}.to_s,
+ ],
)
end
- context 'when the response is not an encodable thing' do
- let(:response_headers) { {'Content-Type' => 'who knows'} }
- let(:response_hash) { {text: 'Coffee brewing failed'} }
+ context "when the response is not an encodable thing" do
+ let(:response_headers) { {"Content-Type" => "who knows"} }
+ let(:response_hash) { {text: "Coffee brewing failed"} }
before do
expect(response_hash).not_to respond_to(:encode)
# i.e. a Ruby hash
end
- it 'does not try to encode the message string' do
- expect(subject.message).to eq("Short and stout\n{:text=>\"Coffee brewing failed\", \"error_description\"=>\"Short and stout\"}")
+ it "does not try to encode the message string" do
+ expect(subject.message.each_line.to_a).to eq(
+ [
+ "Short and stout\n",
+ {:text => "Coffee brewing failed", "error_description" => "Short and stout"}.to_s,
+ ],
+ )
end
end
- it 'sets the code attribute' do
+ it "sets the code attribute" do
expect(subject.code).to be_nil
end
- it 'sets the description attribute' do
- expect(subject.description).to eq('Short and stout')
+ it "sets the description attribute" do
+ expect(subject.description).to eq("Short and stout")
end
end
end
- context 'when the response is not a hash, not parsed' do
+ context "when the response is not a hash, not parsed" do
subject { described_class.new(response_thing) }
- let(:response_thing) { [200, 'Success'] }
+ let(:response_thing) { [200, "Success"] }
- it 'sets the code attribute to nil' do
+ it "sets the code attribute to nil" do
expect(subject.code).to be_nil
end
- it 'sets the description attribute' do
+ it "sets the description attribute" do
expect(subject.description).to be_nil
end
- it 'sets the body attribute' do
+ it "sets the body attribute" do
expect(subject.body).to eq(response_thing)
end
- it 'sets the response attribute' do
+ it "sets the response attribute" do
expect(subject.response).to eq(response_thing)
end
end
- context 'when the response does not parse to a hash' do
- let(:response_headers) { {'Content-Type' => 'text/html'} }
- let(:response_body) { 'Hello, I am a teapot' }
+ context "when the response does not parse to a hash" do
+ let(:response_headers) { {"Content-Type" => "text/html"} }
+ let(:response_body) { "Hello, I am a teapot" }
before do
expect(response.parsed).not_to be_a(Hash)
end
- it 'does not do anything to the message' do
+ it "does not do anything to the message" do
expect(subject.message.lines.count).to eq(1)
expect(subject.message).to eq(response_body)
end
- it 'does not set code' do
+ it "does not set code" do
expect(subject.code).to be_nil
end
- it 'does not set description' do
+ it "does not set description" do
expect(subject.description).to be_nil
end
end
- describe 'parsing json' do
- it 'does not blow up' do
+ describe "parsing json" do
+ it "does not blow up" do
expect { subject.to_json }.not_to raise_error
expect { subject.response.to_json }.not_to raise_error
end
diff --git a/spec/oauth2/response_spec.rb b/spec/oauth2/response_spec.rb
index 4ceb228f..5a0689f2 100644
--- a/spec/oauth2/response_spec.rb
+++ b/spec/oauth2/response_spec.rb
@@ -5,201 +5,204 @@
let(:raw_response) { Faraday::Response.new(status: status, response_headers: headers, body: body) }
let(:status) { 200 }
- let(:headers) { {'foo' => 'bar'} }
- let(:body) { 'foo' }
+ let(:headers) { {"foo" => "bar"} }
+ let(:body) { "foo" }
- describe '#initialize' do
- it 'returns the status, headers and body' do
+ describe "#initialize" do
+ it "returns the status, headers and body" do
expect(subject.headers).to eq(headers)
expect(subject.status).to eq(status)
expect(subject.body).to eq(body)
end
end
- describe '.register_parser' do
+ describe ".register_parser" do
let(:response) do
- double('response', headers: {'Content-Type' => 'application/foo-bar'},
- status: 200,
- body: 'baz')
+ double(
+ "response",
+ headers: {"Content-Type" => "application/foo-bar"},
+ status: 200,
+ body: "baz",
+ )
end
before do
- described_class.register_parser(:foobar, ['application/foo-bar']) do |body|
+ described_class.register_parser(:foobar, ["application/foo-bar"]) do |body|
"foobar #{body}"
end
end
- it 'adds to the content types and parsers' do
+ it "adds to the content types and parsers" do
expect(described_class.send(:class_variable_get, :@@parsers).keys).to include(:foobar)
- expect(described_class.send(:class_variable_get, :@@content_types).keys).to include('application/foo-bar')
+ expect(described_class.send(:class_variable_get, :@@content_types).keys).to include("application/foo-bar")
end
- it 'is able to parse that content type automatically' do
- expect(described_class.new(response).parsed).to eq('foobar baz')
+ it "is able to parse that content type automatically" do
+ expect(described_class.new(response).parsed).to eq("foobar baz")
end
end
- describe '#content_type' do
- context 'when headers are blank' do
+ describe "#content_type" do
+ context "when headers are blank" do
let(:headers) { nil }
- it 'returns nil' do
+ it "returns nil" do
expect(subject.content_type).to be_nil
end
end
- context 'when content-type is not present' do
- let(:headers) { {'a fuzzy' => 'fuzzer'} }
+ context "when content-type is not present" do
+ let(:headers) { {"a fuzzy" => "fuzzer"} }
- it 'returns empty string' do
- expect(subject.content_type).to eq('')
+ it "returns empty string" do
+ expect(subject.content_type).to eq("")
end
end
- context 'when content-type is present' do
- let(:headers) { {'Content-Type' => 'application/x-www-form-urlencoded'} }
+ context "when content-type is present" do
+ let(:headers) { {"Content-Type" => "application/x-www-form-urlencoded"} }
- it 'returns the content type header contents' do
- expect(subject.content_type).to eq('application/x-www-form-urlencoded')
+ it "returns the content type header contents" do
+ expect(subject.content_type).to eq("application/x-www-form-urlencoded")
end
end
end
- describe '#parsed' do
+ describe "#parsed" do
subject(:parsed) do
- headers = {'Content-Type' => content_type}
- response = double('response', headers: headers, body: body)
+ headers = {"Content-Type" => content_type}
+ response = double("response", headers: headers, body: body)
instance = described_class.new(response)
instance.parsed
end
- shared_examples_for 'parsing JSON-like' do
- it 'has num keys' do
+ shared_examples_for "parsing JSON-like" do
+ it "has num keys" do
expect(parsed.keys.size).to eq(6)
end
- it 'parses string' do
- expect(parsed['foo']).to eq('bar')
- expect(parsed.key('bar')).to eq('foo')
+ it "parses string" do
+ expect(parsed["foo"]).to eq("bar")
+ expect(parsed.key("bar")).to eq("foo")
end
- it 'parses non-zero number' do
- expect(parsed['answer']).to eq(42)
- expect(parsed.key(42)).to eq('answer')
+ it "parses non-zero number" do
+ expect(parsed["answer"]).to eq(42)
+ expect(parsed.key(42)).to eq("answer")
end
- it 'parses nil as NilClass' do
- expect(parsed['krill']).to be_nil
- expect(parsed.key(nil)).to eq('krill')
+ it "parses nil as NilClass" do
+ expect(parsed["krill"]).to be_nil
+ expect(parsed.key(nil)).to eq("krill")
end
- it 'parses zero as number' do
- expect(parsed['zero']).to eq(0)
- expect(parsed.key(0)).to eq('zero')
+ it "parses zero as number" do
+ expect(parsed["zero"]).to eq(0)
+ expect(parsed.key(0)).to eq("zero")
end
- it 'parses false as FalseClass' do
- expect(parsed['malign']).to be(false)
- expect(parsed.key(false)).to eq('malign')
+ it "parses false as FalseClass" do
+ expect(parsed["malign"]).to be(false)
+ expect(parsed.key(false)).to eq("malign")
end
- it 'parses false as TrueClass' do
- expect(parsed['shine']).to be(true)
- expect(parsed.key(true)).to eq('shine')
+ it "parses false as TrueClass" do
+ expect(parsed["shine"]).to be(true)
+ expect(parsed.key(true)).to eq("shine")
end
end
- context 'when application/json' do
- let(:content_type) { 'application/json' }
- let(:body) { JSON.dump(foo: 'bar', answer: 42, krill: nil, zero: 0, malign: false, shine: true) }
+ context "when application/json" do
+ let(:content_type) { "application/json" }
+ let(:body) { JSON.dump(foo: "bar", answer: 42, krill: nil, zero: 0, malign: false, shine: true) }
- it_behaves_like 'parsing JSON-like'
+ it_behaves_like "parsing JSON-like"
end
- context 'when application/Json' do
- let(:content_type) { 'application/Json' }
- let(:body) { JSON.dump(foo: 'bar', answer: 42, krill: nil, zero: 0, malign: false, shine: true) }
+ context "when application/Json" do
+ let(:content_type) { "application/Json" }
+ let(:body) { JSON.dump(foo: "bar", answer: 42, krill: nil, zero: 0, malign: false, shine: true) }
- it_behaves_like 'parsing JSON-like'
+ it_behaves_like "parsing JSON-like"
end
- context 'when application/hal+json' do
- let(:content_type) { 'application/hal+json' }
- let(:body) { JSON.dump(foo: 'bar', answer: 42, krill: nil, zero: 0, malign: false, shine: true) }
+ context "when application/hal+json" do
+ let(:content_type) { "application/hal+json" }
+ let(:body) { JSON.dump(foo: "bar", answer: 42, krill: nil, zero: 0, malign: false, shine: true) }
- it_behaves_like 'parsing JSON-like'
+ it_behaves_like "parsing JSON-like"
end
- context 'when application/x-www-form-urlencoded' do
- let(:content_type) { 'application/x-www-form-urlencoded' }
- let(:body) { 'foo=bar&answer=42&krill=&zero=0&malign=false&shine=true' }
+ context "when application/x-www-form-urlencoded" do
+ let(:content_type) { "application/x-www-form-urlencoded" }
+ let(:body) { "foo=bar&answer=42&krill=&zero=0&malign=false&shine=true" }
- it 'has num keys' do
+ it "has num keys" do
expect(parsed.keys.size).to eq(6)
end
- it 'parses string' do
- expect(parsed['foo']).to eq('bar')
- expect(parsed.key('bar')).to eq('foo')
+ it "parses string" do
+ expect(parsed["foo"]).to eq("bar")
+ expect(parsed.key("bar")).to eq("foo")
end
- it 'parses non-zero number as string' do
- expect(parsed['answer']).to eq('42')
- expect(parsed.key('42')).to eq('answer')
+ it "parses non-zero number as string" do
+ expect(parsed["answer"]).to eq("42")
+ expect(parsed.key("42")).to eq("answer")
end
- it 'parses nil as empty string' do
- expect(parsed['krill']).to eq('')
- expect(parsed.key('')).to eq('krill')
+ it "parses nil as empty string" do
+ expect(parsed["krill"]).to eq("")
+ expect(parsed.key("")).to eq("krill")
end
- it 'parses zero as string' do
- expect(parsed['zero']).to eq('0')
- expect(parsed.key('0')).to eq('zero')
+ it "parses zero as string" do
+ expect(parsed["zero"]).to eq("0")
+ expect(parsed.key("0")).to eq("zero")
end
- it 'parses false as string' do
- expect(parsed['malign']).to eq('false')
- expect(parsed.key('false')).to eq('malign')
+ it "parses false as string" do
+ expect(parsed["malign"]).to eq("false")
+ expect(parsed.key("false")).to eq("malign")
end
- it 'parses true as string' do
- expect(parsed['shine']).to eq('true')
- expect(parsed.key('true')).to eq('shine')
+ it "parses true as string" do
+ expect(parsed["shine"]).to eq("true")
+ expect(parsed.key("true")).to eq("shine")
end
end
- it 'parses application/vnd.collection+json body' do
- headers = {'Content-Type' => 'application/vnd.collection+json'}
+ it "parses application/vnd.collection+json body" do
+ headers = {"Content-Type" => "application/vnd.collection+json"}
body = JSON.dump(collection: {})
- response = double('response', headers: headers, body: body)
+ response = double("response", headers: headers, body: body)
subject = described_class.new(response)
expect(subject.parsed.keys.size).to eq(1)
end
- it 'parses application/vnd.api+json body' do
- headers = {'Content-Type' => 'application/vnd.api+json'}
+ it "parses application/vnd.api+json body" do
+ headers = {"Content-Type" => "application/vnd.api+json"}
body = JSON.dump(collection: {})
- response = double('response', headers: headers, body: body)
+ response = double("response", headers: headers, body: body)
subject = described_class.new(response)
expect(subject.parsed.keys.size).to eq(1)
end
- it 'parses application/problem+json body' do
- headers = {'Content-Type' => 'application/problem+json'}
- body = JSON.dump(type: 'https://tools.ietf.org/html/rfc7231#section-6.5.4', title: 'Not Found')
- response = double('response', headers: headers, body: body)
+ it "parses application/problem+json body" do
+ headers = {"Content-Type" => "application/problem+json"}
+ body = JSON.dump(type: "https://tools.ietf.org/html/rfc7231#section-6.5.4", title: "Not Found")
+ response = double("response", headers: headers, body: body)
subject = described_class.new(response)
expect(subject.parsed.keys.size).to eq(2)
- expect(subject.parsed['type']).to eq('https://tools.ietf.org/html/rfc7231#section-6.5.4')
- expect(subject.parsed['title']).to eq('Not Found')
+ expect(subject.parsed["type"]).to eq("https://tools.ietf.org/html/rfc7231#section-6.5.4")
+ expect(subject.parsed["title"]).to eq("Not Found")
end
it "doesn't try to parse other content-types" do
- headers = {'Content-Type' => 'text/html'}
- body = ''
+ headers = {"Content-Type" => "text/html"}
+ body = ""
- response = double('response', headers: headers, body: body)
+ response = double("response", headers: headers, body: body)
expect(JSON).not_to receive(:parse)
expect(Rack::Utils).not_to receive(:parse_query)
@@ -209,10 +212,10 @@
end
it "doesn't parse bodies which have previously been parsed" do
- headers = {'Content-Type' => 'application/json'}
- body = {foo: 'bar', answer: 42, krill: nil, zero: 0, malign: false, shine: true}
+ headers = {"Content-Type" => "application/json"}
+ body = {foo: "bar", answer: 42, krill: nil, zero: 0, malign: false, shine: true}
- response = double('response', headers: headers, body: body)
+ response = double("response", headers: headers, body: body)
expect(JSON).not_to receive(:parse)
expect(Rack::Utils).not_to receive(:parse_query)
@@ -221,93 +224,93 @@
expect(subject.parsed.keys.size).to eq(6)
end
- it 'snakecases json keys when parsing' do
- headers = {'Content-Type' => 'application/json'}
- body = JSON.dump('accessToken' => 'bar', 'MiGever' => 'Ani')
- response = double('response', headers: headers, body: body)
+ it "snakecases json keys when parsing" do
+ headers = {"Content-Type" => "application/json"}
+ body = JSON.dump("accessToken" => "bar", "MiGever" => "Ani")
+ response = double("response", headers: headers, body: body)
subject = described_class.new(response)
expect(subject.parsed.keys.size).to eq(2)
- expect(subject.parsed['access_token']).to eq('bar')
- expect(subject.parsed['mi_gever']).to eq('Ani')
+ expect(subject.parsed["access_token"]).to eq("bar")
+ expect(subject.parsed["mi_gever"]).to eq("Ani")
end
- context 'when not snaky' do
- it 'does not snakecase json keys when parsing' do
- headers = {'Content-Type' => 'application/json'}
- body = JSON.dump('accessToken' => 'bar', 'MiGever' => 'Ani')
- response = double('response', headers: headers, body: body)
+ context "when not snaky" do
+ it "does not snakecase json keys when parsing" do
+ headers = {"Content-Type" => "application/json"}
+ body = JSON.dump("accessToken" => "bar", "MiGever" => "Ani")
+ response = double("response", headers: headers, body: body)
subject = described_class.new(response, snaky: false)
expect(subject.parsed.keys.size).to eq(2)
- expect(subject.parsed['accessToken']).to eq('bar')
- expect(subject.parsed['MiGever']).to eq('Ani')
- expect(subject.parsed['access_token']).to be_nil
- expect(subject.parsed['mi_gever']).to be_nil
+ expect(subject.parsed["accessToken"]).to eq("bar")
+ expect(subject.parsed["MiGever"]).to eq("Ani")
+ expect(subject.parsed["access_token"]).to be_nil
+ expect(subject.parsed["mi_gever"]).to be_nil
end
end
- it 'supports registered parsers with arity == 0; passing nothing' do
+ it "supports registered parsers with arity == 0; passing nothing" do
described_class.register_parser(:arity_0, []) do
- 'a-ok'
+ "a-ok"
end
- headers = {'Content-Type' => 'text/html'}
- body = ''
- response = double('response', headers: headers, body: body)
+ headers = {"Content-Type" => "text/html"}
+ body = ""
+ response = double("response", headers: headers, body: body)
subject = described_class.new(response, parse: :arity_0)
- expect(subject.parsed).to eq('a-ok')
+ expect(subject.parsed).to eq("a-ok")
end
- it 'supports registered parsers with arity == 2; passing body and response' do
- headers = {'Content-Type' => 'text/html'}
- body = ''
- response = double('response', headers: headers, body: body)
+ it "supports registered parsers with arity == 2; passing body and response" do
+ headers = {"Content-Type" => "text/html"}
+ body = ""
+ response = double("response", headers: headers, body: body)
described_class.register_parser(:arity_2, []) do |passed_body, passed_response|
expect(passed_body).to eq(body)
expect(passed_response).to eq(response)
- 'a-ok'
+ "a-ok"
end
subject = described_class.new(response, parse: :arity_2)
- expect(subject.parsed).to eq('a-ok')
+ expect(subject.parsed).to eq("a-ok")
end
- it 'supports registered parsers with arity > 2; passing body and response' do
- headers = {'Content-Type' => 'text/html'}
- body = ''
- response = double('response', headers: headers, body: body)
+ it "supports registered parsers with arity > 2; passing body and response" do
+ headers = {"Content-Type" => "text/html"}
+ body = ""
+ response = double("response", headers: headers, body: body)
described_class.register_parser(:arity_3, []) do |passed_body, passed_response, *args|
expect(passed_body).to eq(body)
expect(passed_response).to eq(response)
expect(args).to eq([])
- 'a-ok'
+ "a-ok"
end
subject = described_class.new(response, parse: :arity_3)
- expect(subject.parsed).to eq('a-ok')
+ expect(subject.parsed).to eq("a-ok")
end
- it 'supports directly passed parsers' do
- headers = {'Content-Type' => 'text/html'}
- body = ''
- response = double('response', headers: headers, body: body)
+ it "supports directly passed parsers" do
+ headers = {"Content-Type" => "text/html"}
+ body = ""
+ response = double("response", headers: headers, body: body)
- subject = described_class.new(response, parse: -> { 'a-ok' })
+ subject = described_class.new(response, parse: -> { "a-ok" })
- expect(subject.parsed).to eq('a-ok')
+ expect(subject.parsed).to eq("a-ok")
end
- it 'supports no parsing' do
- headers = {'Content-Type' => 'text/html'}
- body = ''
- response = double('response', headers: headers, body: body)
+ it "supports no parsing" do
+ headers = {"Content-Type" => "text/html"}
+ body = ""
+ response = double("response", headers: headers, body: body)
subject = described_class.new(response, parse: false)
@@ -315,30 +318,30 @@
end
end
- context 'with xml parser registration' do
- it 'tries to load multi_xml.rb and use it' do
+ context "with xml parser registration" do
+ it "tries to load multi_xml.rb and use it" do
expect(described_class.send(:class_variable_get, :@@parsers)[:xml]).not_to be_nil
end
- it 'is able to parse xml' do
- headers = {'Content-Type' => 'text/xml'}
+ it "is able to parse xml" do
+ headers = {"Content-Type" => "text/xml"}
body = 'baz'
- response = double('response', headers: headers, body: body)
- expect(described_class.new(response).parsed).to eq('foo' => {'bar' => 'baz'})
+ response = double("response", headers: headers, body: body)
+ expect(described_class.new(response).parsed).to eq("foo" => {"bar" => "baz"})
end
- it 'is able to parse application/xml' do
- headers = {'Content-Type' => 'application/xml'}
+ it "is able to parse application/xml" do
+ headers = {"Content-Type" => "application/xml"}
body = 'baz'
- response = double('response', headers: headers, body: body)
- expect(described_class.new(response).parsed).to eq('foo' => {'bar' => 'baz'})
+ response = double("response", headers: headers, body: body)
+ expect(described_class.new(response).parsed).to eq("foo" => {"bar" => "baz"})
end
end
- describe 'converting to json' do
- it 'does not blow up' do
+ describe "converting to json" do
+ it "does not blow up" do
expect { subject.to_json }.not_to raise_error
end
end
diff --git a/spec/oauth2/strategy/assertion_spec.rb b/spec/oauth2/strategy/assertion_spec.rb
index 43e498eb..64498d53 100644
--- a/spec/oauth2/strategy/assertion_spec.rb
+++ b/spec/oauth2/strategy/assertion_spec.rb
@@ -1,26 +1,26 @@
# frozen_string_literal: true
-require 'openssl'
-require 'jwt'
+require "openssl"
+require "jwt"
RSpec.describe OAuth2::Strategy::Assertion do
let(:client_assertion) { client.assertion }
let(:client) do
- cli = OAuth2::Client.new('abc', 'def', site: 'http://api.example.com', auth_scheme: auth_scheme)
+ cli = OAuth2::Client.new("abc", "def", site: "http://api.example.com", auth_scheme: auth_scheme)
cli.connection = Faraday.new(cli.site, cli.options[:connection_opts]) do |b|
b.request :url_encoded
b.adapter :test do |stub|
- stub.post('/oauth/token') do |token_request|
+ stub.post("/oauth/token") do |token_request|
@request_body = Rack::Utils.parse_nested_query(token_request.body).transform_keys(&:to_sym)
case @response_format
- when 'formencoded'
- [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, 'expires_in=600&access_token=salmon&refresh_token=trout']
- when 'json'
- [200, {'Content-Type' => 'application/json'}, '{"expires_in":600,"access_token":"salmon","refresh_token":"trout"}']
+ when "formencoded"
+ [200, {"Content-Type" => "application/x-www-form-urlencoded"}, "expires_in=600&access_token=salmon&refresh_token=trout"]
+ when "json"
+ [200, {"Content-Type" => "application/json"}, '{"expires_in":600,"access_token":"salmon","refresh_token":"trout"}']
else
- raise 'Please define @response_format to choose a response content type!'
+ raise "Please define @response_format to choose a response content type!"
end
end
end
@@ -30,33 +30,33 @@
let(:auth_scheme) { :request_body }
- describe '#authorize_url' do
- it 'raises NotImplementedError' do
+ describe "#authorize_url" do
+ it "raises NotImplementedError" do
expect { client_assertion.authorize_url }.to raise_error(NotImplementedError)
end
end
- describe '#get_token' do
- let(:algorithm) { 'HS256' }
- let(:key) { 'arowana' }
+ describe "#get_token" do
+ let(:algorithm) { "HS256" }
+ let(:key) { "arowana" }
let(:timestamp) { Time.now.to_i }
let(:claims) do
{
- iss: 'carp@example.com',
- scope: 'https://oauth.example.com/auth/flounder',
- aud: 'https://sturgeon.example.com/oauth2/token',
+ iss: "carp@example.com",
+ scope: "https://oauth.example.com/auth/flounder",
+ aud: "https://sturgeon.example.com/oauth2/token",
exp: timestamp + 3600,
iat: timestamp,
- sub: '12345',
- custom_claim: 'ling cod',
+ sub: "12345",
+ custom_claim: "ling cod",
}
end
before do
- @response_format = 'json'
+ @response_format = "json"
end
- describe 'assembling a JWT assertion' do
+ describe "assembling a JWT assertion" do
let(:jwt) do
payload, header = JWT.decode(@request_body[:assertion], key, true, algorithm: algorithm)
{payload: payload, header: header}
@@ -65,13 +65,13 @@
let(:payload) { jwt[:payload] }
let(:header) { jwt[:header] }
- shared_examples_for 'encodes the JWT' do
- it 'indicates algorithm in the header' do
+ shared_examples_for "encodes the JWT" do
+ it "indicates algorithm in the header" do
expect(header).not_to be_nil
- expect(header['alg']).to eq(algorithm)
+ expect(header["alg"]).to eq(algorithm)
end
- it 'has claims' do
+ it "has claims" do
expect(payload).not_to be_nil
expect(payload.keys).to match_array(%w[iss scope aud exp iat sub custom_claim])
payload.each do |key, claim|
@@ -80,136 +80,136 @@
end
end
- context 'when encoding as HS256' do
- let(:algorithm) { 'HS256' }
- let(:key) { 'super_secret!' }
+ context "when encoding as HS256" do
+ let(:algorithm) { "HS256" }
+ let(:key) { "super_secret!" }
before do
client_assertion.get_token(claims, algorithm: algorithm, key: key)
- raise 'No request made!' if @request_body.nil?
+ raise "No request made!" if @request_body.nil?
end
- it_behaves_like 'encodes the JWT'
+ it_behaves_like "encodes the JWT"
- context 'with real key' do
- let(:key) { '1883be842495c3b58f68ca71fbf1397fbb9ed2fdf8990f8404a25d0a1b995943' }
+ context "with real key" do
+ let(:key) { "1883be842495c3b58f68ca71fbf1397fbb9ed2fdf8990f8404a25d0a1b995943" }
- it_behaves_like 'encodes the JWT'
+ it_behaves_like "encodes the JWT"
end
end
- context 'when encoding as RS256' do
- let(:algorithm) { 'RS256' }
+ context "when encoding as RS256" do
+ let(:algorithm) { "RS256" }
let(:key) { OpenSSL::PKey::RSA.new(1024) }
before do
client_assertion.get_token(claims, algorithm: algorithm, key: key)
- raise 'No request made!' if @request_body.nil?
+ raise "No request made!" if @request_body.nil?
end
- it_behaves_like 'encodes the JWT'
+ it_behaves_like "encodes the JWT"
- context 'with private key' do
- let(:private_key_file) { 'spec/fixtures/RS256/jwtRS256.key' }
- let(:password) { '' }
+ context "with private key" do
+ let(:private_key_file) { "spec/fixtures/RS256/jwtRS256.key" }
+ let(:password) { "" }
let(:key) { OpenSSL::PKey::RSA.new(File.read(private_key_file), password) }
- it_behaves_like 'encodes the JWT'
+ it_behaves_like "encodes the JWT"
end
end
- context 'with bad encoding params' do
+ context "with bad encoding params" do
let(:encoding_opts) { {algorithm: algorithm, key: key} }
- describe 'non-supported algorithms' do
- let(:algorithm) { 'the blockchain' }
- let(:key) { 'machine learning' }
+ describe "non-supported algorithms" do
+ let(:algorithm) { "the blockchain" }
+ let(:key) { "machine learning" }
- it 'raises NotImplementedError' do
+ it "raises JWT::EncodeError" do
# this behavior is handled by the JWT gem, but this should make sure it is consistent
- expect { client_assertion.get_token(claims, encoding_opts) }.to raise_error(NotImplementedError)
+ expect { client_assertion.get_token(claims, encoding_opts) }.to raise_error(JWT::EncodeError, "Unsupported signing method")
end
end
- describe 'of a wrong object type' do
- let(:encoding_opts) { 'the cloud' }
+ describe "of a wrong object type" do
+ let(:encoding_opts) { "the cloud" }
- it 'raises ArgumentError' do
+ it "raises ArgumentError" do
expect { client_assertion.get_token(claims, encoding_opts) }.to raise_error(ArgumentError, /encoding_opts/)
end
end
- describe 'missing encoding_opts[:algorithm]' do
+ describe "missing encoding_opts[:algorithm]" do
before do
encoding_opts.delete(:algorithm)
end
- it 'raises ArgumentError' do
+ it "raises ArgumentError" do
expect { client_assertion.get_token(claims, encoding_opts) }.to raise_error(ArgumentError, /encoding_opts/)
end
end
- describe 'missing encoding_opts[:key]' do
+ describe "missing encoding_opts[:key]" do
before do
encoding_opts.delete(:key)
end
- it 'raises ArgumentError' do
+ it "raises ArgumentError" do
expect { client_assertion.get_token(claims, encoding_opts) }.to raise_error(ArgumentError, /encoding_opts/)
end
end
end
end
- describe 'POST request parameters' do
- context 'when using :auth_scheme => :request_body' do
+ describe "POST request parameters" do
+ context "when using :auth_scheme => :request_body" do
let(:auth_scheme) { :request_body }
- it 'includes assertion and grant_type, along with the client parameters' do
+ it "includes assertion and grant_type, along with the client parameters" do
client_assertion.get_token(claims, algorithm: algorithm, key: key)
expect(@request_body).not_to be_nil
expect(@request_body.keys).to match_array(%i[assertion grant_type client_id client_secret])
- expect(@request_body[:grant_type]).to eq('urn:ietf:params:oauth:grant-type:jwt-bearer')
+ expect(@request_body[:grant_type]).to eq("urn:ietf:params:oauth:grant-type:jwt-bearer")
expect(@request_body[:assertion]).to be_a(String)
- expect(@request_body[:client_id]).to eq('abc')
- expect(@request_body[:client_secret]).to eq('def')
+ expect(@request_body[:client_id]).to eq("abc")
+ expect(@request_body[:client_secret]).to eq("def")
end
- it 'includes other params via request_options' do
- client_assertion.get_token(claims, {algorithm: algorithm, key: key}, {scope: 'dover sole'})
+ it "includes other params via request_options" do
+ client_assertion.get_token(claims, {algorithm: algorithm, key: key}, {scope: "dover sole"})
expect(@request_body).not_to be_nil
expect(@request_body.keys).to match_array(%i[assertion grant_type scope client_id client_secret])
- expect(@request_body[:grant_type]).to eq('urn:ietf:params:oauth:grant-type:jwt-bearer')
+ expect(@request_body[:grant_type]).to eq("urn:ietf:params:oauth:grant-type:jwt-bearer")
expect(@request_body[:assertion]).to be_a(String)
- expect(@request_body[:scope]).to eq('dover sole')
- expect(@request_body[:client_id]).to eq('abc')
- expect(@request_body[:client_secret]).to eq('def')
+ expect(@request_body[:scope]).to eq("dover sole")
+ expect(@request_body[:client_id]).to eq("abc")
+ expect(@request_body[:client_secret]).to eq("def")
end
end
- context 'when using :auth_scheme => :basic_auth' do
+ context "when using :auth_scheme => :basic_auth" do
let(:auth_scheme) { :basic_auth }
- it 'includes assertion and grant_type by default' do
+ it "includes assertion and grant_type by default" do
client_assertion.get_token(claims, algorithm: algorithm, key: key)
expect(@request_body).not_to be_nil
expect(@request_body.keys).to match_array(%i[assertion grant_type])
- expect(@request_body[:grant_type]).to eq('urn:ietf:params:oauth:grant-type:jwt-bearer')
+ expect(@request_body[:grant_type]).to eq("urn:ietf:params:oauth:grant-type:jwt-bearer")
expect(@request_body[:assertion]).to be_a(String)
end
- it 'includes other params via request_options' do
- client_assertion.get_token(claims, {algorithm: algorithm, key: key}, {scope: 'dover sole'})
+ it "includes other params via request_options" do
+ client_assertion.get_token(claims, {algorithm: algorithm, key: key}, {scope: "dover sole"})
expect(@request_body).not_to be_nil
expect(@request_body.keys).to match_array(%i[assertion grant_type scope])
- expect(@request_body[:grant_type]).to eq('urn:ietf:params:oauth:grant-type:jwt-bearer')
+ expect(@request_body[:grant_type]).to eq("urn:ietf:params:oauth:grant-type:jwt-bearer")
expect(@request_body[:assertion]).to be_a(String)
- expect(@request_body[:scope]).to eq('dover sole')
+ expect(@request_body[:scope]).to eq("dover sole")
end
end
end
- describe 'returning the response' do
+ describe "returning the response" do
let(:access_token) { client_assertion.get_token(claims, {algorithm: algorithm, key: key}, {}, response_opts) }
let(:response_opts) { {} }
@@ -219,42 +219,42 @@
@response_format = mode
end
- it 'returns an AccessToken' do
+ it "returns an AccessToken" do
expect(access_token).to be_an(OAuth2::AccessToken)
end
- it 'returns AccessToken with same Client' do
+ it "returns AccessToken with same Client" do
expect(access_token.client).to eq(client)
end
- it 'returns AccessToken with #token' do
- expect(access_token.token).to eq('salmon')
+ it "returns AccessToken with #token" do
+ expect(access_token.token).to eq("salmon")
end
- it 'returns AccessToken with #expires_in' do
+ it "returns AccessToken with #expires_in" do
expect(access_token.expires_in).to eq(600)
end
- it 'returns AccessToken with #expires_at' do
+ it "returns AccessToken with #expires_at" do
expect(access_token.expires_at).not_to be_nil
end
- it 'sets AccessToken#refresh_token to nil' do
- expect(access_token.refresh_token).to eq('trout')
+ it "sets AccessToken#refresh_token to nil" do
+ expect(access_token.refresh_token).to eq("trout")
end
- context 'with custom response_opts' do
- let(:response_opts) { {'custom_token_option' => 'mackerel'} }
+ context "with custom response_opts" do
+ let(:response_opts) { {"custom_token_option" => "mackerel"} }
- it 'passes them into the token params' do
+ it "passes them into the token params" do
expect(access_token.params).to eq(response_opts)
end
end
- context 'when no custom opts are passed in' do
+ context "when no custom opts are passed in" do
let(:response_opts) { {} }
- it 'does not set any params by default' do
+ it "does not set any params by default" do
expect(access_token.params).to eq({})
end
end
diff --git a/spec/oauth2/strategy/auth_code_spec.rb b/spec/oauth2/strategy/auth_code_spec.rb
index e1997b1a..ed3817b4 100644
--- a/spec/oauth2/strategy/auth_code_spec.rb
+++ b/spec/oauth2/strategy/auth_code_spec.rb
@@ -4,125 +4,125 @@
RSpec.describe OAuth2::Strategy::AuthCode do
subject { client.auth_code }
- let(:code) { 'sushi' }
- let(:kvform_token) { 'expires_in=600&access_token=salmon&refresh_token=trout&extra_param=steve' }
- let(:facebook_token) { kvform_token.gsub('_in', '') }
- let(:json_token) { JSON.dump(expires_in: 600, access_token: 'salmon', refresh_token: 'trout', extra_param: 'steve') }
- let(:redirect_uri) { 'http://example.com/redirect_uri' }
- let(:microsoft_token) { 'id_token=i_am_MSFT' }
+ let(:code) { "sushi" }
+ let(:kvform_token) { "expires_in=600&access_token=salmon&refresh_token=trout&extra_param=steve" }
+ let(:facebook_token) { kvform_token.gsub("_in", "") }
+ let(:json_token) { JSON.dump(expires_in: 600, access_token: "salmon", refresh_token: "trout", extra_param: "steve") }
+ let(:redirect_uri) { "http://example.com/redirect_uri" }
+ let(:microsoft_token) { "id_token=i_am_MSFT" }
let(:client) do
- OAuth2::Client.new('abc', 'def', site: 'http://api.example.com') do |builder|
+ OAuth2::Client.new("abc", "def", site: "http://api.example.com") do |builder|
builder.adapter :test do |stub|
stub.get("/oauth/token?client_id=abc&code=#{code}&grant_type=authorization_code") do |_env|
case @mode
- when 'formencoded'
- [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, kvform_token]
- when 'json'
- [200, {'Content-Type' => 'application/json'}, json_token]
- when 'from_facebook'
- [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, facebook_token]
- when 'from_microsoft'
- [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, microsoft_token]
+ when "formencoded"
+ [200, {"Content-Type" => "application/x-www-form-urlencoded"}, kvform_token]
+ when "json"
+ [200, {"Content-Type" => "application/json"}, json_token]
+ when "from_facebook"
+ [200, {"Content-Type" => "application/x-www-form-urlencoded"}, facebook_token]
+ when "from_microsoft"
+ [200, {"Content-Type" => "application/x-www-form-urlencoded"}, microsoft_token]
else raise ArgumentError, "Bad @mode: #{@mode}"
end
end
- stub.post('/oauth/token', 'client_id' => 'abc', 'client_secret' => 'def', 'code' => 'sushi', 'grant_type' => 'authorization_code') do |_env|
+ stub.post("/oauth/token", "client_id" => "abc", "client_secret" => "def", "code" => "sushi", "grant_type" => "authorization_code") do |_env|
case @mode
- when 'formencoded'
- [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, kvform_token]
- when 'json'
- [200, {'Content-Type' => 'application/json'}, json_token]
- when 'from_facebook'
- [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, facebook_token]
+ when "formencoded"
+ [200, {"Content-Type" => "application/x-www-form-urlencoded"}, kvform_token]
+ when "json"
+ [200, {"Content-Type" => "application/json"}, json_token]
+ when "from_facebook"
+ [200, {"Content-Type" => "application/x-www-form-urlencoded"}, facebook_token]
else raise ArgumentError, "Bad @mode: #{@mode}"
end
end
- stub.post('/oauth/token', 'client_id' => 'abc', 'client_secret' => 'def', 'code' => 'sushi', 'grant_type' => 'authorization_code', 'redirect_uri' => redirect_uri) do |_env|
- [200, {'Content-Type' => 'application/json'}, json_token]
+ stub.post("/oauth/token", "client_id" => "abc", "client_secret" => "def", "code" => "sushi", "grant_type" => "authorization_code", "redirect_uri" => redirect_uri) do |_env|
+ [200, {"Content-Type" => "application/json"}, json_token]
end
end
end
end
- describe '#authorize_url' do
- it 'includes the client_id' do
- expect(subject.authorize_url).to include('client_id=abc')
+ describe "#authorize_url" do
+ it "includes the client_id" do
+ expect(subject.authorize_url).to include("client_id=abc")
end
- it 'includes the type' do
- expect(subject.authorize_url).to include('response_type=code')
+ it "includes the type" do
+ expect(subject.authorize_url).to include("response_type=code")
end
- it 'does not include the client_secret' do
- expect(subject.authorize_url).not_to include('client_secret=def')
+ it "does not include the client_secret" do
+ expect(subject.authorize_url).not_to include("client_secret=def")
end
- it 'raises an error if the client_secret is passed in' do
- expect { subject.authorize_url(client_secret: 'def') }.to raise_error(ArgumentError)
+ it "raises an error if the client_secret is passed in" do
+ expect { subject.authorize_url(client_secret: "def") }.to raise_error(ArgumentError)
end
- it 'raises an error if the client_secret is passed in with string keys' do
- expect { subject.authorize_url('client_secret' => 'def') }.to raise_error(ArgumentError)
+ it "raises an error if the client_secret is passed in with string keys" do
+ expect { subject.authorize_url("client_secret" => "def") }.to raise_error(ArgumentError)
end
- it 'includes passed in options' do
- cb = 'http://myserver.local/oauth/callback'
+ it "includes passed in options" do
+ cb = "http://myserver.local/oauth/callback"
expect(subject.authorize_url(redirect_uri: cb)).to include("redirect_uri=#{CGI.escape(cb)}")
end
end
- describe '#get_token (with dynamic redirect_uri)' do
+ describe "#get_token (with dynamic redirect_uri)" do
before do
- @mode = 'json'
+ @mode = "json"
client.options[:token_method] = :post
client.options[:auth_scheme] = :request_body
client.options[:redirect_uri] = redirect_uri
end
- it 'does not raise error' do
+ it "does not raise error" do
expect { subject.get_token(code, redirect_uri: redirect_uri) }.not_to raise_error
end
- it 'gets a token' do
+ it "gets a token" do
access = subject.get_token(code, redirect_uri: redirect_uri)
- expect(access.token).to eq('salmon')
+ expect(access.token).to eq("salmon")
end
end
- describe '#get_token (handling utf-8 data)' do
- let(:json_token) { JSON.dump(expires_in: 600, access_token: 'salmon', refresh_token: 'trout', extra_param: 'André') }
+ describe "#get_token (handling utf-8 data)" do
+ let(:json_token) { JSON.dump(expires_in: 600, access_token: "salmon", refresh_token: "trout", extra_param: "André") }
before do
- @mode = 'json'
+ @mode = "json"
client.options[:token_method] = :post
client.options[:auth_scheme] = :request_body
end
- it 'does not raise an error' do
+ it "does not raise an error" do
expect { subject.get_token(code) }.not_to raise_error
end
- it 'does not create an error instance' do
+ it "does not create an error instance" do
expect(OAuth2::Error).not_to receive(:new)
subject.get_token(code)
end
- it 'can get a token' do
+ it "can get a token" do
access = subject.get_token(code)
- expect(access.token).to eq('salmon')
+ expect(access.token).to eq("salmon")
end
end
- describe '#get_token (from microsoft)' do
+ describe "#get_token (from microsoft)" do
it "doesn't treat an OpenID Connect token with only an id_token (like from Microsoft) as invalid" do
- @mode = 'from_microsoft'
+ @mode = "from_microsoft"
client.options[:token_method] = :get
client.options[:auth_scheme] = :request_body
@access = subject.get_token(code)
- expect(@access.token).to eq('i_am_MSFT')
+ expect(@access.token).to eq("i_am_MSFT")
end
end
@@ -136,28 +136,28 @@
@access = subject.get_token(code)
end
- it 'returns AccessToken with same Client' do
+ it "returns AccessToken with same Client" do
expect(@access.client).to eq(client)
end
- it 'returns AccessToken with #token' do
- expect(@access.token).to eq('salmon')
+ it "returns AccessToken with #token" do
+ expect(@access.token).to eq("salmon")
end
- it 'returns AccessToken with #refresh_token' do
- expect(@access.refresh_token).to eq('trout')
+ it "returns AccessToken with #refresh_token" do
+ expect(@access.refresh_token).to eq("trout")
end
- it 'returns AccessToken with #expires_in' do
+ it "returns AccessToken with #expires_in" do
expect(@access.expires_in).to eq(600)
end
- it 'returns AccessToken with #expires_at' do
- expect(@access.expires_at).to be_kind_of(Integer)
+ it "returns AccessToken with #expires_at" do
+ expect(@access.expires_at).to be_a(Integer)
end
- it 'returns AccessToken with params accessible via []' do
- expect(@access['extra_param']).to eq('steve')
+ it "returns AccessToken with params accessible via []" do
+ expect(@access["extra_param"]).to eq("steve")
end
end
end
diff --git a/spec/oauth2/strategy/base_spec.rb b/spec/oauth2/strategy/base_spec.rb
index 33b98389..4d0e4dec 100644
--- a/spec/oauth2/strategy/base_spec.rb
+++ b/spec/oauth2/strategy/base_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
RSpec.describe OAuth2::Strategy::Base do
- it 'initializes with a Client' do
- expect { described_class.new(OAuth2::Client.new('abc', 'def')) }.not_to raise_error
+ it "initializes with a Client" do
+ expect { described_class.new(OAuth2::Client.new("abc", "def")) }.not_to raise_error
end
end
diff --git a/spec/oauth2/strategy/client_credentials_spec.rb b/spec/oauth2/strategy/client_credentials_spec.rb
index b9480098..e0baad92 100644
--- a/spec/oauth2/strategy/client_credentials_spec.rb
+++ b/spec/oauth2/strategy/client_credentials_spec.rb
@@ -3,30 +3,30 @@
RSpec.describe OAuth2::Strategy::ClientCredentials do
subject { client.client_credentials }
- let(:kvform_token) { 'expires_in=600&access_token=salmon&refresh_token=trout' }
+ let(:kvform_token) { "expires_in=600&access_token=salmon&refresh_token=trout" }
let(:json_token) { '{"expires_in":600,"access_token":"salmon","refresh_token":"trout"}' }
let(:client) do
- OAuth2::Client.new('abc', 'def', site: 'http://api.example.com') do |builder|
+ OAuth2::Client.new("abc", "def", site: "http://api.example.com") do |builder|
builder.adapter :test do |stub|
- stub.post('/oauth/token', 'grant_type' => 'client_credentials') do |env|
- client_id, client_secret = Base64.decode64(env[:request_headers]['Authorization'].split(' ', 2)[1]).split(':', 2)
- (client_id == 'abc' && client_secret == 'def') || raise(Faraday::Adapter::Test::Stubs::NotFound)
+ stub.post("/oauth/token", "grant_type" => "client_credentials") do |env|
+ client_id, client_secret = Base64.decode64(env[:request_headers]["Authorization"].split(" ", 2)[1]).split(":", 2)
+ (client_id == "abc" && client_secret == "def") || raise(Faraday::Adapter::Test::Stubs::NotFound)
@last_headers = env[:request_headers]
case @mode
- when 'formencoded'
- [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, kvform_token]
- when 'json'
- [200, {'Content-Type' => 'application/json'}, json_token]
+ when "formencoded"
+ [200, {"Content-Type" => "application/x-www-form-urlencoded"}, kvform_token]
+ when "json"
+ [200, {"Content-Type" => "application/json"}, json_token]
else raise ArgumentError, "Bad @mode: #{@mode}"
end
end
- stub.post('/oauth/token', 'client_id' => 'abc', 'client_secret' => 'def', 'grant_type' => 'client_credentials') do |_env|
+ stub.post("/oauth/token", "client_id" => "abc", "client_secret" => "def", "grant_type" => "client_credentials") do |_env|
case @mode
- when 'formencoded'
- [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, kvform_token]
- when 'json'
- [200, {'Content-Type' => 'application/json'}, json_token]
+ when "formencoded"
+ [200, {"Content-Type" => "application/x-www-form-urlencoded"}, kvform_token]
+ when "json"
+ [200, {"Content-Type" => "application/json"}, json_token]
else raise ArgumentError, "Bad @mode: #{@mode}"
end
end
@@ -34,8 +34,8 @@
end
end
- describe '#authorize_url' do
- it 'raises NotImplementedError' do
+ describe "#authorize_url" do
+ it "raises NotImplementedError" do
expect { subject.authorize_url }.to raise_error(NotImplementedError)
end
end
@@ -49,49 +49,49 @@
@access = subject.get_token
end
- it 'returns AccessToken with same Client' do
+ it "returns AccessToken with same Client" do
expect(@access.client).to eq(client)
end
- it 'returns AccessToken with #token' do
- expect(@access.token).to eq('salmon')
+ it "returns AccessToken with #token" do
+ expect(@access.token).to eq("salmon")
end
- it 'returns AccessToken without #refresh_token' do
- expect(@access.refresh_token).to eq('trout')
+ it "returns AccessToken without #refresh_token" do
+ expect(@access.refresh_token).to eq("trout")
end
- it 'returns AccessToken with #expires_in' do
+ it "returns AccessToken with #expires_in" do
expect(@access.expires_in).to eq(600)
end
- it 'returns AccessToken with #expires_at' do
+ it "returns AccessToken with #expires_at" do
expect(@access.expires_at).not_to be_nil
end
end
end
end
- describe '#get_token (with extra header parameters)' do
+ describe "#get_token (with extra header parameters)" do
before do
- @mode = 'json'
- @access = subject.get_token(headers: {'X-Extra-Header' => 'wow'})
+ @mode = "json"
+ @access = subject.get_token(headers: {"X-Extra-Header" => "wow"})
end
- it 'sends the header correctly.' do
- expect(@last_headers['X-Extra-Header']).to eq('wow')
+ it "sends the header correctly." do
+ expect(@last_headers["X-Extra-Header"]).to eq("wow")
end
end
- describe '#get_token (with option overriding response)' do
+ describe "#get_token (with option overriding response)" do
before do
- @mode = 'json'
- @access = subject.get_token({}, {'refresh_token' => 'guppy'})
+ @mode = "json"
+ @access = subject.get_token({}, {"refresh_token" => "guppy"})
end
- it 'override is applied' do
- expect(@access.token).to eq('salmon')
- expect(@access.refresh_token).to eq('guppy')
+ it "override is applied" do
+ expect(@access.token).to eq("salmon")
+ expect(@access.refresh_token).to eq("guppy")
end
end
end
diff --git a/spec/oauth2/strategy/implicit_spec.rb b/spec/oauth2/strategy/implicit_spec.rb
index 18588fea..b443da48 100644
--- a/spec/oauth2/strategy/implicit_spec.rb
+++ b/spec/oauth2/strategy/implicit_spec.rb
@@ -3,37 +3,37 @@
RSpec.describe OAuth2::Strategy::Implicit do
subject { client.implicit }
- let(:client) { OAuth2::Client.new('abc', 'def', site: 'http://api.example.com') }
+ let(:client) { OAuth2::Client.new("abc", "def", site: "http://api.example.com") }
- describe '#authorize_url' do
- it 'includes the client_id' do
- expect(subject.authorize_url).to include('client_id=abc')
+ describe "#authorize_url" do
+ it "includes the client_id" do
+ expect(subject.authorize_url).to include("client_id=abc")
end
- it 'includes the type' do
- expect(subject.authorize_url).to include('response_type=token')
+ it "includes the type" do
+ expect(subject.authorize_url).to include("response_type=token")
end
- it 'does not include the client_secret' do
- expect(subject.authorize_url).not_to include('client_secret=def')
+ it "does not include the client_secret" do
+ expect(subject.authorize_url).not_to include("client_secret=def")
end
- it 'raises an error if the client_secret is passed in' do
- expect { subject.authorize_url(client_secret: 'def') }.to raise_error(ArgumentError)
+ it "raises an error if the client_secret is passed in" do
+ expect { subject.authorize_url(client_secret: "def") }.to raise_error(ArgumentError)
end
- it 'raises an error if the client_secret is passed in with string keys' do
- expect { subject.authorize_url('client_secret' => 'def') }.to raise_error(ArgumentError)
+ it "raises an error if the client_secret is passed in with string keys" do
+ expect { subject.authorize_url("client_secret" => "def") }.to raise_error(ArgumentError)
end
- it 'includes passed in options' do
- cb = 'http://myserver.local/oauth/callback'
+ it "includes passed in options" do
+ cb = "http://myserver.local/oauth/callback"
expect(subject.authorize_url(redirect_uri: cb)).to include("redirect_uri=#{CGI.escape(cb)}")
end
end
- describe '#get_token' do
- it 'raises NotImplementedError' do
+ describe "#get_token" do
+ it "raises NotImplementedError" do
expect { subject.get_token }.to raise_error(NotImplementedError)
end
end
diff --git a/spec/oauth2/strategy/password_spec.rb b/spec/oauth2/strategy/password_spec.rb
index 040b6455..b3dbe9e8 100644
--- a/spec/oauth2/strategy/password_spec.rb
+++ b/spec/oauth2/strategy/password_spec.rb
@@ -4,16 +4,16 @@
subject { client.password }
let(:client) do
- cli = OAuth2::Client.new('abc', 'def', site: 'http://api.example.com')
+ cli = OAuth2::Client.new("abc", "def", site: "http://api.example.com")
cli.connection = Faraday.new(cli.site, cli.options[:connection_opts]) do |b|
b.request :url_encoded
b.adapter :test do |stub|
- stub.post('/oauth/token') do |_env|
+ stub.post("/oauth/token") do |_env|
case @mode
- when 'formencoded'
- [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, 'expires_in=600&access_token=salmon&refresh_token=trout']
- when 'json'
- [200, {'Content-Type' => 'application/json'}, '{"expires_in":600,"access_token":"salmon","refresh_token":"trout"}']
+ when "formencoded"
+ [200, {"Content-Type" => "application/x-www-form-urlencoded"}, "expires_in=600&access_token=salmon&refresh_token=trout"]
+ when "json"
+ [200, {"Content-Type" => "application/json"}, '{"expires_in":600,"access_token":"salmon","refresh_token":"trout"}']
else raise ArgumentError, "Bad @mode: #{@mode}"
end
end
@@ -22,8 +22,8 @@
cli
end
- describe '#authorize_url' do
- it 'raises NotImplementedError' do
+ describe "#authorize_url" do
+ it "raises NotImplementedError" do
expect { subject.authorize_url }.to raise_error(NotImplementedError)
end
end
@@ -32,26 +32,26 @@
describe "#get_token (#{mode})" do
before do
@mode = mode
- @access = subject.get_token('username', 'password')
+ @access = subject.get_token("username", "password")
end
- it 'returns AccessToken with same Client' do
+ it "returns AccessToken with same Client" do
expect(@access.client).to eq(client)
end
- it 'returns AccessToken with #token' do
- expect(@access.token).to eq('salmon')
+ it "returns AccessToken with #token" do
+ expect(@access.token).to eq("salmon")
end
- it 'returns AccessToken with #refresh_token' do
- expect(@access.refresh_token).to eq('trout')
+ it "returns AccessToken with #refresh_token" do
+ expect(@access.refresh_token).to eq("trout")
end
- it 'returns AccessToken with #expires_in' do
+ it "returns AccessToken with #expires_in" do
expect(@access.expires_in).to eq(600)
end
- it 'returns AccessToken with #expires_at' do
+ it "returns AccessToken with #expires_at" do
expect(@access.expires_at).not_to be_nil
end
end
diff --git a/spec/oauth2/version_spec.rb b/spec/oauth2/version_spec.rb
index 250a3039..1f2edbe1 100644
--- a/spec/oauth2/version_spec.rb
+++ b/spec/oauth2/version_spec.rb
@@ -1,39 +1,39 @@
# frozen_string_literal: true
RSpec.describe OAuth2::Version do
- it 'has a version number' do
+ it "has a version number" do
expect(described_class).not_to be_nil
end
- it 'can be a string' do
+ it "can be a string" do
expect(described_class.to_s).to be_a(String)
end
- it 'allows Constant access' do
+ it "allows Constant access" do
expect(described_class::VERSION).to be_a(String)
end
- it 'is greater than 0.1.0' do
- expect(Gem::Version.new(described_class) > Gem::Version.new('0.1.0')).to be(true)
+ it "is greater than 0.1.0" do
+ expect(Gem::Version.new(described_class) > Gem::Version.new("0.1.0")).to be(true)
end
- it 'major version is an integer' do
+ it "major version is an integer" do
expect(described_class.major).to be_a(Integer)
end
- it 'minor version is an integer' do
+ it "minor version is an integer" do
expect(described_class.minor).to be_a(Integer)
end
- it 'patch version is an integer' do
+ it "patch version is an integer" do
expect(described_class.patch).to be_a(Integer)
end
- it 'returns a Hash' do
+ it "returns a Hash" do
expect(described_class.to_h.keys).to match_array(%i[major minor patch pre])
end
- it 'returns an Array' do
+ it "returns an Array" do
expect(described_class.to_a).to be_a(Array)
end
end
diff --git a/spec/oauth2_spec.rb b/spec/oauth2_spec.rb
index 62b824fd..51ed31fc 100644
--- a/spec/oauth2_spec.rb
+++ b/spec/oauth2_spec.rb
@@ -1,11 +1,11 @@
# frozen_string_literal: true
RSpec.describe OAuth2 do
- it 'has a default config for silence_extra_tokens_warning' do
+ it "has a default config for silence_extra_tokens_warning" do
expect(described_class.config.silence_extra_tokens_warning).to eq(false)
end
- describe '.configure' do
+ describe ".configure" do
subject(:configure) do
described_class.configure do |config|
config.silence_extra_tokens_warning = true
@@ -24,7 +24,7 @@
end
end
- it 'can change setting of silence_extra_tokens_warning' do
+ it "can change setting of silence_extra_tokens_warning" do
block_is_expected.to change(described_class.config, :silence_extra_tokens_warning).from(false).to(true)
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index a770c36d..4821f668 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,71 +1,37 @@
# frozen_string_literal: true
# ensure test env
-ENV['RACK_ENV'] = 'test'
+ENV["RACK_ENV"] = "test"
# Third Party Libraries
-require 'rspec'
-require 'rspec/stubbed_env'
-require 'silent_stream'
-require 'addressable/uri'
-require 'rspec/pending_for'
-require 'rspec/block_is_expected'
+require "rspec/stubbed_env"
+require "silent_stream"
+require "addressable/uri"
+require "rspec/pending_for"
+require "rspec/block_is_expected"
# Extensions
-require 'ext/backports'
-
-DEBUG = ENV['DEBUG'] == 'true'
-
-ruby_version = Gem::Version.new(RUBY_VERSION)
-minimum_version = ->(version, engine = 'ruby') { ruby_version >= Gem::Version.new(version) && RUBY_ENGINE == engine }
-actual_version = lambda do |major, minor|
- actual = Gem::Version.new(ruby_version)
- major == actual.segments[0] && minor == actual.segments[1] && RUBY_ENGINE == 'ruby'
-end
-debugging = minimum_version.call('2.7') && DEBUG
-RUN_COVERAGE = minimum_version.call('2.6') && (ENV['COVER_ALL'] || ENV['CI_CODECOV'] || ENV['CI'].nil?)
-ALL_FORMATTERS = actual_version.call(2, 7) && (ENV['COVER_ALL'] || ENV['CI_CODECOV'] || ENV['CI'])
-
-if DEBUG
- if debugging
- require 'byebug'
- elsif minimum_version.call('2.7', 'jruby')
- require 'pry-debugger-jruby'
- end
-end
-
-if RUN_COVERAGE
- require 'simplecov' # Config file `.simplecov` is run immediately when simplecov loads
- require 'codecov'
- require 'simplecov-json'
- require 'simplecov-lcov'
- require 'simplecov-cobertura'
- # This will override the formatter set in .simplecov
- if ALL_FORMATTERS
- SimpleCov::Formatter::LcovFormatter.config do |c|
- c.report_with_single_file = true
- c.single_report_path = 'coverage/lcov.info'
- end
-
- SimpleCov.formatters = [
- SimpleCov::Formatter::HTMLFormatter,
- SimpleCov::Formatter::CoberturaFormatter, # XML for Jenkins
- SimpleCov::Formatter::LcovFormatter,
- SimpleCov::Formatter::JSONFormatter, # For CodeClimate
- SimpleCov::Formatter::Codecov, # For CodeCov
- ]
- end
-end
-
-# This gem
-require 'oauth2'
+require_relative "ext/backports"
# Library Configs
-require 'config/multi_xml'
-require 'config/faraday'
+require_relative "config/debug"
+require_relative "config/multi_xml"
+require_relative "config/faraday"
+require_relative "config/constants"
# RSpec Configs
-require 'config/rspec/rspec_core'
-require 'config/rspec/silent_stream'
+require_relative "config/rspec/rspec_core"
+require_relative "config/rspec/silent_stream"
+
+# NOTE: Gemfiles for older rubies won't have kettle-soup-cover.
+# The rescue LoadError handles that scenario.
+begin
+ require "kettle-soup-cover"
+ require "simplecov" if Kettle::Soup::Cover::DO_COV # `.simplecov` is run here!
+rescue LoadError => error
+ # check the error message, if you are so inclined, and re-raise if not what is expected
+ raise error unless error.message.include?("kettle")
+end
-VERBS = %i[get post put delete patch].freeze
+# This gem
+require "oauth2"