diff --git a/.qlty/qlty.toml b/.qlty/qlty.toml new file mode 100644 index 00000000..e69ec730 --- /dev/null +++ b/.qlty/qlty.toml @@ -0,0 +1,78 @@ +# For a guide to configuration, visit https://qlty.sh/d/config +# Or for a full reference, visit https://qlty.sh/d/qlty-toml +config_version = "0" + +exclude_patterns = [ + "*_min.*", + "*-min.*", + "*.min.*", + "**/.yarn/**", + "**/*.d.ts", + "**/assets/**", + "**/bin/**", + "**/bower_components/**", + "**/build/**", + "**/cache/**", + "**/config/**", + "**/.devcontainer", + "**/db/**", + "**/deps/**", + "**/dist/**", + "**/doc/**", + "**/extern/**", + "**/external/**", + "**/generated/**", + "**/Godeps/**", + "**/gradlew/**", + "**/mvnw/**", + "**/node_modules/**", + "**/protos/**", + "**/seed/**", + "**/target/**", + "**/templates/**", + "**/testdata/**", + "**/vendor/**", +] + + +test_patterns = [ + "**/test/**", + "**/spec/**", + "**/*.test.*", + "**/*.spec.*", + "**/*_test.*", + "**/*_spec.*", + "**/test_*.*", + "**/spec_*.*", +] + +[smells] +mode = "comment" + +[smells.boolean_logic] +threshold = 4 +enabled = true + +[smells.file_complexity] +threshold = 55 +enabled = false + +[smells.return_statements] +threshold = 4 +enabled = true + +[smells.nested_control_flow] +threshold = 4 +enabled = true + +[smells.function_parameters] +threshold = 4 +enabled = true + +[smells.function_complexity] +threshold = 5 +enabled = true + +[smells.duplication] +enabled = true +threshold = 20 \ No newline at end of file diff --git a/.rubocop_gradual.lock b/.rubocop_gradual.lock index 43be1b50..eaf00efa 100644 --- a/.rubocop_gradual.lock +++ b/.rubocop_gradual.lock @@ -18,10 +18,10 @@ [9, 9, 25, "ThreadSafety/ClassInstanceVariable: Avoid class instance variables.", 2012823020], [13, 9, 25, "ThreadSafety/ClassInstanceVariable: Avoid class instance variables.", 2012823020] ], - "lib/oauth2/response.rb:2808363818": [ - [35, 5, 204, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 996912427] + "lib/oauth2/response.rb:2054901929": [ + [53, 5, 204, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 996912427] ], - "oauth2.gemspec:1301437182": [ + "oauth2.gemspec:3059367295": [ [5, 23, 12, "Gemspec/RubyVersionGlobalsUsage: Do not use `RUBY_VERSION` in gemspec file.", 31296028] ], "spec/oauth2/access_token_spec.rb:1202129469": [ @@ -37,7 +37,7 @@ [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:1455422151": [ + "spec/oauth2/client_spec.rb:3334307042": [ [6, 1, 29, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/client*_spec.rb`.", 439549885], [175, 7, 492, "RSpec/NoExpectationExample: No expectation found in this example.", 1272021224], [194, 7, 592, "RSpec/NoExpectationExample: No expectation found in this example.", 3428877205], @@ -45,15 +45,15 @@ [222, 15, 20, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 1276531672], [237, 15, 43, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 1383956904], [252, 15, 43, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 3376202107], - [827, 5, 360, "RSpec/NoExpectationExample: No expectation found in this example.", 536201463], - [836, 5, 461, "RSpec/NoExpectationExample: No expectation found in this example.", 3392600621], - [847, 5, 340, "RSpec/NoExpectationExample: No expectation found in this example.", 244592251], - [975, 11, 99, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 3084776886], - [979, 11, 82, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 1524553529], - [987, 7, 89, "RSpec/NoExpectationExample: No expectation found in this example.", 4609419], - [1075, 11, 99, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 3084776886], - [1079, 11, 82, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 1524553529], - [1159, 17, 12, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 664794325] + [839, 5, 360, "RSpec/NoExpectationExample: No expectation found in this example.", 536201463], + [848, 5, 461, "RSpec/NoExpectationExample: No expectation found in this example.", 3392600621], + [859, 5, 340, "RSpec/NoExpectationExample: No expectation found in this example.", 244592251], + [987, 11, 99, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 3084776886], + [991, 11, 82, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 1524553529], + [999, 7, 89, "RSpec/NoExpectationExample: No expectation found in this example.", 4609419], + [1087, 11, 99, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 3084776886], + [1091, 11, 82, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 1524553529], + [1171, 17, 12, "RSpec/ContextWording: Context description should match /^when\\b/, /^with\\b/, or /^without\\b/.", 664794325] ], "spec/oauth2/error_spec.rb:1692696277": [ [23, 1, 28, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/error*_spec.rb`.", 3385870076], @@ -65,9 +65,8 @@ [375, 11, 534, "RSpec/NoExpectationExample: No expectation found in this example.", 3347340910], [391, 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/response_spec.rb:2248532534": [ + [3, 1, 31, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/response*_spec.rb`.", 3190869319] ], "spec/oauth2/strategy/assertion_spec.rb:793170256": [ [6, 1, 42, "RSpec/SpecFilePathFormat: Spec path should end with `o_auth2/strategy/assertion*_spec.rb`.", 3665690869] diff --git a/CHANGELOG.md b/CHANGELOG.md index 3465797e..b55b576c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,21 +6,37 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2. ## [Unreleased] ### Added +### Changed +### Deprecated +### Removed +### Fixed +### Security + +## [2.0.11] - 2025-05-23 +- TAG: [v2.0.11][2.0.11t] +- COVERAGE: 100.00% -- 518/518 lines in 14 files +- BRANCH COVERAGE: 100.00% -- 172/172 branches in 14 files +- 80.00% documented +### Added +- [gh651](https://github.com/oauth-xx/oauth2/pull/651) - `:snaky_hash_klass` option (@pboling) +- More documentation - Codeberg as ethical mirror (@pboling) - https://codeberg.org/oauth-xx/oauth2 - Don't check for cert if SKIP_GEM_SIGNING is set (@pboling) - All runtime deps, including oauth-xx sibling gems, are now tested against HEAD (@pboling) -- YARD config, GFM compatible with relative file links -- Documentation site on GitHub Pages +- YARD config, GFM compatible with relative file links (@pboling) +- Documentation site on GitHub Pages (@pboling) - [oauth2.galtzo.com](https://oauth2.galtzo.com) -- [!649](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/649) - Test compatibility with all key minor versions of Hashie v0, v1, v2, v3, v4, v5, HEAD +- [!649](https://gitlab.com/oauth-xx/oauth2/-/merge_requests/649) - Test compatibility with all key minor versions of Hashie v0, v1, v2, v3, v4, v5, HEAD (@pboling) +- [gh651](https://github.com/oauth-xx/oauth2/pull/651) - Mock OAuth2 server for testing (@pboling) + - https://github.com/navikt/mock-oauth2-server ### Changed -- Updated `spec.homepage_uri` in gemspec to GitHub Pages YARD documentation site -### Deprecated -### Removed +- [gh651](https://github.com/oauth-xx/oauth2/pull/651) - Upgraded to snaky_hash v2.0.3 (@pboling) + - Provides solution for serialization issues +- Updated `spec.homepage_uri` in gemspec to GitHub Pages YARD documentation site (@pboling) ### Fixed +- [gh650](https://github.com/oauth-xx/oauth2/pull/650) - Regression in return type of `OAuth2::Response#parsed` (@pboling) - Incorrect documentation related to silencing warnings (@pboling) -### Security ## [2.0.10] - 2025-05-17 - TAG: [v2.0.10][2.0.10t] @@ -379,7 +395,9 @@ and this project adheres to [Semantic Versioning v2](https://semver.org/spec/v2. [gemfiles/readme]: gemfiles/README.md -[Unreleased]: https://gitlab.com/oauth-xx/oauth2/-/compare/v2.0.10...HEAD +[Unreleased]: https://gitlab.com/oauth-xx/oauth2/-/compare/v2.0.11...HEAD +[2.0.11]: https://gitlab.com/oauth-xx/oauth2/-/compare/v2.0.10...v2.0.11 +[2.0.11t]: https://gitlab.com/oauth-xx/oauth2/-/tags/v2.0.11 [2.0.10]: https://gitlab.com/oauth-xx/oauth2/-/compare/v2.0.9...v2.0.10 [2.0.10t]: https://gitlab.com/oauth-xx/oauth2/-/tags/v2.0.10 [2.0.9]: https://gitlab.com/oauth-xx/oauth2/-/compare/v2.0.8...v2.0.9 diff --git a/Gemfile.lock b/Gemfile.lock index f08b86d4..97ec5ac4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -23,13 +23,13 @@ GIT PATH remote: . specs: - oauth2 (2.0.10) + oauth2 (2.0.11) faraday (>= 0.17.3, < 4.0) jwt (>= 1.0, < 4.0) logger (~> 1.2) multi_xml (~> 0.5) rack (>= 1.2, < 4) - snaky_hash (~> 2.0, >= 2.0.2) + snaky_hash (~> 2.0, >= 2.0.3) version_gem (>= 1.1.8, < 3) GEM @@ -251,7 +251,7 @@ GEM simplecov-rcov (0.3.7) simplecov (>= 0.4.1) simplecov_json_formatter (0.1.4) - snaky_hash (2.0.2) + snaky_hash (2.0.3) hashie (>= 0.1.0, < 6) version_gem (>= 1.1.8, < 3) standard (1.50.0) diff --git a/README.md b/README.md index b19cd064..31f61ded 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ ## 🔐 OAuth2 -[![Version][👽versioni]][👽version] [![License: MIT][📄license-img]][📄license-ref] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![Open Source Helpers][👽oss-helpi]][👽oss-help] [![Depfu][🔑depfui♻️]][🔑depfu] [![Coveralls Test Coverage][🔑coveralls-img]][🔑coveralls] [![QLTY Test Coverage][🔑qlty-covi♻️]][🔑qlty-cov] [![CI Heads][🚎3-hd-wfi]][🚎3-hd-wf] [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]][🚎12-crh-wf] [![CI Current][🚎11-c-wfi]][🚎11-c-wf] [![CI Truffle Ruby][🚎9-t-wfi]][🚎9-t-wf] [![CI JRuby][🚎10-j-wfi]][🚎10-j-wf] [![CI Supported][🚎6-s-wfi]][🚎6-s-wf] [![CI Legacy][🚎4-lg-wfi]][🚎4-lg-wf] [![CI Unsupported][🚎7-us-wfi]][🚎7-us-wf] [![CI Ancient][🚎1-an-wfi]][🚎1-an-wf] [![CI Caboose is an absolute WAGON][🚎13-cbs-wfi]][🚎13-cbs-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![CodeQL][🖐codeQL-img]][🖐codeQL] +[![Version][👽versioni]][👽version] [![License: MIT][📄license-img]][📄license-ref] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![Open Source Helpers][👽oss-helpi]][👽oss-help] [![Depfu][🔑depfui♻️]][🔑depfu] [![Coveralls Test Coverage][🔑coveralls-img]][🔑coveralls] [![QLTY Test Coverage][🔑qlty-covi♻️]][🔑qlty-cov] [![QLTY Maintainability][🔑qlty-mnti♻️]][🔑qlty-mnt] [![CI Heads][🚎3-hd-wfi]][🚎3-hd-wf] [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]][🚎12-crh-wf] [![CI Current][🚎11-c-wfi]][🚎11-c-wf] [![CI Truffle Ruby][🚎9-t-wfi]][🚎9-t-wf] [![CI JRuby][🚎10-j-wfi]][🚎10-j-wf] [![CI Supported][🚎6-s-wfi]][🚎6-s-wf] [![CI Legacy][🚎4-lg-wfi]][🚎4-lg-wf] [![CI Unsupported][🚎7-us-wfi]][🚎7-us-wf] [![CI Ancient][🚎1-an-wfi]][🚎1-an-wf] [![CI Caboose is an absolute WAGON][🚎13-cbs-wfi]][🚎13-cbs-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![CodeQL][🖐codeQL-img]][🖐codeQL] --- @@ -145,7 +145,7 @@ One of these might be what you are looking for: | Works with JRuby | [![JRuby 9.2 Compat][💎jruby-9.2i]][🚎10-j-wf] [![JRuby 9.3 Compat][💎jruby-9.3i]][🚎10-j-wf] [![JRuby 9.4 Compat][💎jruby-9.4i]][🚎10-j-wf] [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf] | | Works with Truffle Ruby | [![Truffle Ruby 23.1 Compat][💎truby-23.1i]][🚎9-t-wf] [![Truffle Ruby 24.1 Compat][💎truby-c-i]][🚎11-c-wf] [![Truffle Ruby HEAD Compat][💎truby-headi]][🚎3-hd-wf] | | Works with MRI Ruby 3 | [![Ruby 3.0 Compat][💎ruby-3.0i]][🚎4-lg-wf] [![Ruby 3.1 Compat][💎ruby-3.1i]][🚎6-s-wf] [![Ruby 3.2 Compat][💎ruby-3.2i]][🚎6-s-wf] [![Ruby 3.3 Compat][💎ruby-3.3i]][🚎6-s-wf] [![Ruby 3.4 Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf] | -| Works with MRI Ruby 2 | [![Ruby 2.3 Compat][💎ruby-2.3i]][🚎1-an-wf] [![Ruby 2.4 Compat][💎ruby-2.4i]][🚎1-an-wf] [![Ruby 2.5 Compat][💎ruby-2.5i]][🚎1-an-wf] [![Ruby 2.6 Compat][💎ruby-2.6i]][🚎7-us-wf] [![Ruby 2.7 Compat][💎ruby-2.7i]][🚎7-us-wf] | +| Works with MRI Ruby 2 | [![Ruby 2.3 Compat][💎ruby-2.3i]][🚎13-cbs-wf] [![Ruby 2.4 Compat][💎ruby-2.4i]][🚎1-an-wf] [![Ruby 2.5 Compat][💎ruby-2.5i]][🚎1-an-wf] [![Ruby 2.6 Compat][💎ruby-2.6i]][🚎7-us-wf] [![Ruby 2.7 Compat][💎ruby-2.7i]][🚎7-us-wf] | | Source | [![Source on GitLab.com][📜src-gl-img]][📜src-gl] [![Source on CodeBerg.org][📜src-cb-img]][📜src-cb] [![Source on Github.com][📜src-gh-img]][📜src-gh] [![The best SHA: dQw4w9WgXcQ!][🧮kloc-img]][🧮kloc] | | Documentation | [![Discussion][⛳gg-discussions-img]][⛳gg-discussions] [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![HEAD on RubyDoc.info][📜docs-head-rd-img]][🚎yard-head] [![BDFL Blog][🚂bdfl-blog-img]][🚂bdfl-blog] [![Wiki][📜wiki-img]][📜wiki] | | Compliance | [![License: MIT][📄license-img]][📄license-ref] [![📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] | @@ -328,9 +328,7 @@ For more see [SECURITY.md][🔐security]. ## What is new for v2.0? -- Officially support Ruby versions >= 2.7 -- Unofficially support Ruby versions >= 2.5 -- Incidentally support Ruby versions >= 2.2 +- Works with Ruby versions >= 2.2 - Drop support for the expired MAC Draft (all versions) - Support IETF rfc7523 JWT Bearer Tokens - Support IETF rfc7231 Relative Location in Redirect @@ -338,9 +336,9 @@ For more see [SECURITY.md][🔐security]. - Support IETF rfc7009 Token Revocation (since v2.0.10) - 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) - Support new formats, including from [jsonapi.org](http://jsonapi.org/format/): `application/vdn.api+json`, `application/vnd.collection+json`, `application/hal+json`, `application/problem+json` -- Adds new option to `OAuth2::Client#get_token`: +- Adds option to `OAuth2::Client#get_token`: - `:access_token_class` (`AccessToken`); user specified class to use for all calls to `get_token` -- Adds new option to `OAuth2::AccessToken#initialize`: +- Adds option to `OAuth2::AccessToken#initialize`: - `:expires_latency` (`nil`); number of seconds by which AccessToken validity will be reduced to offset latency - By default, keys are transformed to snake case. - Original keys will still work as previously, in most scenarios, thanks to [snaky_hash][snaky_hash] gem. @@ -487,16 +485,16 @@ response.parsed.class.name # => SnakyHash::StringKeyed (from snaky_hash g As of v2.0.11, if you need to serialize the parsed result, you can! -There are two ways to do this. +There are two ways to do this, and the second option recommended. + +1. Globally configure `SnakyHash::StringKeyed` to use the serializer. Put this in your code somewhere reasonable (like an initializer for Rails): -1. Global: put this in your code somewhere reasonable (like an initializer for Rails): ```ruby SnakyHash::StringKeyed.class_eval do extend SnakyHash::Serializer end ``` -2. #### What if I hate snakes and/or indifference? @@ -510,7 +508,7 @@ response.parsed.class.name # => Hash (just, regular old Hash) ```
- Debugging + Debugging & Logging Set an environment variable as per usual (e.g. with [dotenv](https://github.com/bkeepers/dotenv)). diff --git a/REEK b/REEK index b6f33d5c..5f8ba210 100644 --- a/REEK +++ b/REEK @@ -1,9 +1,9 @@ spec/oauth2/access_token_spec.rb -- 1 warning: [300, 301]:DuplicateMethodCall: assert_initialized_token calls 'target.params' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] spec/oauth2/client_spec.rb -- 3 warnings: - [1072]:UnusedParameters: initialize has unused parameter 'client' [https://github.com/troessner/reek/blob/v6.5.0/docs/Unused-Parameters.md] - [1072]:UnusedParameters: initialize has unused parameter 'hash' [https://github.com/troessner/reek/blob/v6.5.0/docs/Unused-Parameters.md] - [1208]:UtilityFunction: stubbed_client doesn't depend on instance state (maybe move it to another class?) [https://github.com/troessner/reek/blob/v6.5.0/docs/Utility-Function.md] + [1084]:UnusedParameters: initialize has unused parameter 'client' [https://github.com/troessner/reek/blob/v6.5.0/docs/Unused-Parameters.md] + [1084]:UnusedParameters: initialize has unused parameter 'hash' [https://github.com/troessner/reek/blob/v6.5.0/docs/Unused-Parameters.md] + [1220]:UtilityFunction: stubbed_client doesn't depend on instance state (maybe move it to another class?) [https://github.com/troessner/reek/blob/v6.5.0/docs/Utility-Function.md] spec/oauth2/error_spec.rb -- 3 warnings: [10]:IrresponsibleModule: XmledString has no descriptive comment [https://github.com/troessner/reek/blob/v6.5.0/docs/Irresponsible-Module.md] [4]:SubclassedFromCoreClass: StirredHash inherits from core class 'Hash' [https://github.com/troessner/reek/blob/v6.5.0/docs/Subclassed-From-Core-Class.md] @@ -43,32 +43,32 @@ lib/oauth2/authenticator.rb -- 5 warnings: lib/oauth2/client.rb -- 28 warnings: [28]:Attribute: OAuth2::Client#connection is a writable attribute [https://github.com/troessner/reek/blob/v6.5.0/docs/Attribute.md] [27]:Attribute: OAuth2::Client#options is a writable attribute [https://github.com/troessner/reek/blob/v6.5.0/docs/Attribute.md] - [208, 469, 536]:DataClump: OAuth2::Client takes parameters ['access_token_opts', 'extract_access_token'] to 3 methods [https://github.com/troessner/reek/blob/v6.5.0/docs/Data-Clump.md] - [469, 492, 517, 536]:DataClump: OAuth2::Client takes parameters ['access_token_opts', 'response'] to 4 methods [https://github.com/troessner/reek/blob/v6.5.0/docs/Data-Clump.md] + [208, 485, 552]:DataClump: OAuth2::Client takes parameters ['access_token_opts', 'extract_access_token'] to 3 methods [https://github.com/troessner/reek/blob/v6.5.0/docs/Data-Clump.md] + [485, 508, 533, 552]:DataClump: OAuth2::Client takes parameters ['access_token_opts', 'response'] to 4 methods [https://github.com/troessner/reek/blob/v6.5.0/docs/Data-Clump.md] [89, 90]:DuplicateMethodCall: OAuth2::Client#connection calls 'options[:connection_build]' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] - [433, 433]:DuplicateMethodCall: OAuth2::Client#execute_request calls 'req_opts[:params]' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] + [449, 449]:DuplicateMethodCall: OAuth2::Client#execute_request calls 'req_opts[:params]' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] [336, 337]:DuplicateMethodCall: OAuth2::Client#redirection_params calls 'options[:redirect_uri]' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] [152, 153, 154]:DuplicateMethodCall: OAuth2::Client#request calls 'req_opts[:redirect_count]' 3 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] [260, 261, 262]:DuplicateMethodCall: OAuth2::Client#revoke_token calls 'req_opts[:params]' 3 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] - [519, 519]:FeatureEnvy: OAuth2::Client#build_access_token refers to 'access_token' more than self (maybe move it to another class?) [https://github.com/troessner/reek/blob/v6.5.0/docs/Feature-Envy.md] - [354, 357, 363, 365, 366, 368]:FeatureEnvy: OAuth2::Client#params_to_req_opts refers to 'req_opts' more than self (maybe move it to another class?) [https://github.com/troessner/reek/blob/v6.5.0/docs/Feature-Envy.md] - [388, 395, 395, 396, 396, 397, 397, 400]:FeatureEnvy: OAuth2::Client#parse_snaky_params_headers refers to 'params' more than self (maybe move it to another class?) [https://github.com/troessner/reek/blob/v6.5.0/docs/Feature-Envy.md] + [535, 535]:FeatureEnvy: OAuth2::Client#build_access_token refers to 'access_token' more than self (maybe move it to another class?) [https://github.com/troessner/reek/blob/v6.5.0/docs/Feature-Envy.md] + [366, 369, 375, 377, 378, 380]:FeatureEnvy: OAuth2::Client#params_to_req_opts refers to 'req_opts' more than self (maybe move it to another class?) [https://github.com/troessner/reek/blob/v6.5.0/docs/Feature-Envy.md] + [403, 410, 410, 411, 411, 412, 412, 413, 413, 416]:FeatureEnvy: OAuth2::Client#parse_snaky_params_headers refers to 'params' more than self (maybe move it to another class?) [https://github.com/troessner/reek/blob/v6.5.0/docs/Feature-Envy.md] [16]:IrresponsibleModule: OAuth2::ConnectionError has no descriptive comment [https://github.com/troessner/reek/blob/v6.5.0/docs/Irresponsible-Module.md] [17]:IrresponsibleModule: OAuth2::TimeoutError has no descriptive comment [https://github.com/troessner/reek/blob/v6.5.0/docs/Irresponsible-Module.md] - [519]:ManualDispatch: OAuth2::Client#build_access_token manually dispatches method call [https://github.com/troessner/reek/blob/v6.5.0/docs/Manual-Dispatch.md] + [535]:ManualDispatch: OAuth2::Client#build_access_token manually dispatches method call [https://github.com/troessner/reek/blob/v6.5.0/docs/Manual-Dispatch.md] [20]:TooManyInstanceVariables: OAuth2::Client has at least 5 instance variables [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Instance-Variables.md] [20]:TooManyMethods: OAuth2::Client has at least 25 methods [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Methods.md] - [424]:TooManyStatements: OAuth2::Client#execute_request has approx 16 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] + [440]:TooManyStatements: OAuth2::Client#execute_request has approx 16 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] [208]:TooManyStatements: OAuth2::Client#get_token has approx 6 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] - [346]:TooManyStatements: OAuth2::Client#params_to_req_opts has approx 9 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] - [492]:TooManyStatements: OAuth2::Client#parse_response has approx 6 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] - [387]:TooManyStatements: OAuth2::Client#parse_snaky_params_headers has approx 11 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] + [357]:TooManyStatements: OAuth2::Client#params_to_req_opts has approx 9 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] + [508]:TooManyStatements: OAuth2::Client#parse_response has approx 6 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] + [402]:TooManyStatements: OAuth2::Client#parse_snaky_params_headers has approx 13 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] [146]:TooManyStatements: OAuth2::Client#request has approx 18 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] [257]:TooManyStatements: OAuth2::Client#revoke_token has approx 6 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] [15]:UncommunicativeModuleName: OAuth2 has the name 'OAuth2' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Module-Name.md] - [436, 438]:UncommunicativeVariableName: OAuth2::Client#execute_request has the variable name 'e' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] - [428]:UncommunicativeVariableName: OAuth2::Client#execute_request has the variable name 'k' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] - [429]:UncommunicativeVariableName: OAuth2::Client#execute_request has the variable name 'p' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] + [452, 454]:UncommunicativeVariableName: OAuth2::Client#execute_request has the variable name 'e' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] + [444]:UncommunicativeVariableName: OAuth2::Client#execute_request has the variable name 'k' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] + [445]:UncommunicativeVariableName: OAuth2::Client#execute_request has the variable name 'p' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Variable-Name.md] lib/oauth2/error.rb -- 8 warnings: [35, 35, 37, 38]:DuplicateMethodCall: OAuth2::Error#error_message calls 'opts[:error_description]' 4 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] [13, 14, 15]:DuplicateMethodCall: OAuth2::Error#initialize calls 'response.parsed' 3 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] @@ -86,17 +86,17 @@ lib/oauth2/filtered_attributes.rb -- 6 warnings: [17]:TooManyStatements: OAuth2::FilteredAttributes#inspect has approx 7 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] [1]:UncommunicativeModuleName: OAuth2 has the name 'OAuth2' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Module-Name.md] lib/oauth2/response.rb -- 12 warnings: - [15]:Attribute: OAuth2::Response#options is a writable attribute [https://github.com/troessner/reek/blob/v6.5.0/docs/Attribute.md] - [51]:BooleanParameter: OAuth2::Response#initialize has boolean parameter 'snaky' [https://github.com/troessner/reek/blob/v6.5.0/docs/Boolean-Parameter.md] - [25, 39, 133]:ClassVariable: OAuth2::Response declares the class variable '@@content_types' [https://github.com/troessner/reek/blob/v6.5.0/docs/Class-Variable.md] - [19, 37, 130, 133]:ClassVariable: OAuth2::Response declares the class variable '@@parsers' [https://github.com/troessner/reek/blob/v6.5.0/docs/Class-Variable.md] - [102, 104]:DuplicateMethodCall: OAuth2::Response#content_type calls 'response.headers' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] - [127, 128, 129, 130]:DuplicateMethodCall: OAuth2::Response#parser calls 'options[:parse]' 4 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] - [9]:InstanceVariableAssumption: OAuth2::Response assumes too much for instance variable '@parsed' [https://github.com/troessner/reek/blob/v6.5.0/docs/Instance-Variable-Assumption.md] - [9]:InstanceVariableAssumption: OAuth2::Response assumes too much for instance variable '@parser' [https://github.com/troessner/reek/blob/v6.5.0/docs/Instance-Variable-Assumption.md] - [82]:ManualDispatch: OAuth2::Response#parsed manually dispatches method call [https://github.com/troessner/reek/blob/v6.5.0/docs/Manual-Dispatch.md] - [127]:ManualDispatch: OAuth2::Response#parser manually dispatches method call [https://github.com/troessner/reek/blob/v6.5.0/docs/Manual-Dispatch.md] - [78]:TooManyStatements: OAuth2::Response#parsed has approx 6 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] + [26]:Attribute: OAuth2::Response#options is a writable attribute [https://github.com/troessner/reek/blob/v6.5.0/docs/Attribute.md] + [72]:BooleanParameter: OAuth2::Response#initialize has boolean parameter 'snaky' [https://github.com/troessner/reek/blob/v6.5.0/docs/Boolean-Parameter.md] + [41, 57, 162]:ClassVariable: OAuth2::Response declares the class variable '@@content_types' [https://github.com/troessner/reek/blob/v6.5.0/docs/Class-Variable.md] + [32, 55, 159, 162]:ClassVariable: OAuth2::Response declares the class variable '@@parsers' [https://github.com/troessner/reek/blob/v6.5.0/docs/Class-Variable.md] + [133, 135]:DuplicateMethodCall: OAuth2::Response#content_type calls 'response.headers' 2 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] + [156, 157, 158, 159]:DuplicateMethodCall: OAuth2::Response#parser calls 'options[:parse]' 4 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md] + [12]:InstanceVariableAssumption: OAuth2::Response assumes too much for instance variable '@parsed' [https://github.com/troessner/reek/blob/v6.5.0/docs/Instance-Variable-Assumption.md] + [12]:InstanceVariableAssumption: OAuth2::Response assumes too much for instance variable '@parser' [https://github.com/troessner/reek/blob/v6.5.0/docs/Instance-Variable-Assumption.md] + [110]:ManualDispatch: OAuth2::Response#parsed manually dispatches method call [https://github.com/troessner/reek/blob/v6.5.0/docs/Manual-Dispatch.md] + [156]:ManualDispatch: OAuth2::Response#parser manually dispatches method call [https://github.com/troessner/reek/blob/v6.5.0/docs/Manual-Dispatch.md] + [106]:TooManyStatements: OAuth2::Response#parsed has approx 7 statements [https://github.com/troessner/reek/blob/v6.5.0/docs/Too-Many-Statements.md] [7]:UncommunicativeModuleName: OAuth2 has the name 'OAuth2' [https://github.com/troessner/reek/blob/v6.5.0/docs/Uncommunicative-Module-Name.md] lib/oauth2/strategy/assertion.rb -- 5 warnings: [96, 96, 98, 98]:FeatureEnvy: OAuth2::Strategy::Assertion#build_assertion refers to 'encoding_opts' more than self (maybe move it to another class?) [https://github.com/troessner/reek/blob/v6.5.0/docs/Feature-Envy.md] diff --git a/config-ssl.json b/config-ssl.json new file mode 100644 index 00000000..f0a8da2e --- /dev/null +++ b/config-ssl.json @@ -0,0 +1,7 @@ +{ + "interactiveLogin": true, + "httpServer": { + "type": "NettyWrapper", + "ssl": {} + } +} \ No newline at end of file diff --git a/doc/OAuth2.html b/doc/OAuth2.html index 269f3588..322a2374 100644 --- a/doc/OAuth2.html +++ b/doc/OAuth2.html @@ -326,7 +326,7 @@

diff --git a/doc/OAuth2/AccessToken.html b/doc/OAuth2/AccessToken.html index 5648430b..330192f2 100644 --- a/doc/OAuth2/AccessToken.html +++ b/doc/OAuth2/AccessToken.html @@ -3069,7 +3069,7 @@

diff --git a/doc/OAuth2/Authenticator.html b/doc/OAuth2/Authenticator.html index 53d768b8..65220ce2 100644 --- a/doc/OAuth2/Authenticator.html +++ b/doc/OAuth2/Authenticator.html @@ -631,7 +631,7 @@

diff --git a/doc/OAuth2/Client.html b/doc/OAuth2/Client.html index c94105f6..168d06bb 100644 --- a/doc/OAuth2/Client.html +++ b/doc/OAuth2/Client.html @@ -141,7 +141,7 @@

RESERVED_PARAM_KEYS =
-
(RESERVED_REQ_KEYS + %w[parse snaky token_method]).freeze
+
(RESERVED_REQ_KEYS + %w[parse snaky snaky_hash_klass token_method]).freeze
@@ -2651,7 +2651,7 @@

diff --git a/doc/OAuth2/Error.html b/doc/OAuth2/Error.html index bb717c6a..25969726 100644 --- a/doc/OAuth2/Error.html +++ b/doc/OAuth2/Error.html @@ -518,7 +518,7 @@

diff --git a/doc/OAuth2/FilteredAttributes.html b/doc/OAuth2/FilteredAttributes.html index 71336486..a1091784 100644 --- a/doc/OAuth2/FilteredAttributes.html +++ b/doc/OAuth2/FilteredAttributes.html @@ -268,7 +268,7 @@

diff --git a/doc/OAuth2/FilteredAttributes/ClassMethods.html b/doc/OAuth2/FilteredAttributes/ClassMethods.html index fbb49460..103e2ee2 100644 --- a/doc/OAuth2/FilteredAttributes/ClassMethods.html +++ b/doc/OAuth2/FilteredAttributes/ClassMethods.html @@ -218,7 +218,7 @@

diff --git a/doc/OAuth2/Response.html b/doc/OAuth2/Response.html index fe27e27d..3c037338 100644 --- a/doc/OAuth2/Response.html +++ b/doc/OAuth2/Response.html @@ -101,13 +101,29 @@

Overview

-

OAuth2::Response class

+

The Response class handles HTTP responses in the OAuth2 gem, providing methods
+to access and parse response data in various formats.

+

Since:

+
@@ -119,24 +135,98 @@

DEFAULT_OPTIONS = - +
+
+

Default configuration options for Response instances

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash) + + + + — +

    The default options hash

    +
    + +
  • + +
+

Since:

+
    + +
  • + + + + + +

    1.0.0

    +
    + +
  • + +
+ +
{
   parse: :automatic,
   snaky: true,
+  snaky_hash_klass: SnakyHash::StringKeyed,
 }.freeze
@@parsers =
-

Procs that, when called, will parse a response body according
-to the specified format.

+

Storage for response body parser procedures

+

Returns:

+
    + +
  • + + + (Hash<Symbol, Proc>) + + + + — +

    Hash of parser procs keyed by format symbol

    +
    + +
  • + +
+

Since:

+
    + +
  • + + + + + +

    1.0.0

    +
    + +
  • + +
@@ -148,13 +238,45 @@

@@content_types =
-

Content type assignments for various potential HTTP content types.

+

Maps content types to parser symbols

+

Returns:

+
    + +
  • + + + (Hash<String, Symbol>) + + + + — +

    Hash of content types mapped to parser symbols

    +
    + +
  • + +
+

Since:

+
    + +
  • + + + + + +

    1.0.0

    +
    + +
  • + +
@@ -175,7 +297,7 @@

Instance Attribute Summary collaps
  • - #options ⇒ Object + #options ⇒ Hash @@ -192,7 +314,7 @@

    Instance Attribute Summary collaps -

    Returns the value of attribute options.

    +

    The options hash for this instance.

  • @@ -201,7 +323,7 @@

    Instance Attribute Summary collaps
  • - #response ⇒ Object + #response ⇒ Faraday::Response @@ -220,7 +342,7 @@

    Instance Attribute Summary collaps -

    Returns the value of attribute response.

    +

    The raw Faraday response object.

  • @@ -242,7 +364,7 @@

  • - .register_parser(key, mime_types) {|String| ... } ⇒ Object + .register_parser(key, mime_types) {|String| ... } ⇒ void @@ -274,7 +396,7 @@

  • - #body ⇒ Object + #body ⇒ String @@ -297,7 +419,7 @@

  • - #content_type ⇒ Object + #content_type ⇒ String? @@ -311,7 +433,7 @@

    -

    Attempts to determine the content type of the response.

    +

    Determines the content type of the response.

  • @@ -320,7 +442,7 @@

  • - #headers ⇒ Object + #headers ⇒ Hash @@ -343,7 +465,7 @@

  • - #initialize(response, parse: :automatic, snaky: true, **options) ⇒ Response + #initialize(response, parse: :automatic, snaky: true, snaky_hash_klass: nil, **options) ⇒ OAuth2::Response @@ -382,7 +504,7 @@

    -

    The #response #body as parsed by #parser.

    +

    The parsed response body.

  • @@ -405,7 +527,7 @@

    -

    Determines the parser (a Proc or other Object which responds to #call) that will be passed the #body (and optional #response) to supply #parsed.

    +

    Determines the parser to be used for the response body.

  • @@ -414,7 +536,7 @@

  • - #status ⇒ Object + #status ⇒ Integer @@ -443,7 +565,7 @@

    Constructor Details

    - #initialize(response, parse: :automatic, snaky: true, **options) ⇒ Response + #initialize(response, parse: :automatic, snaky: true, snaky_hash_klass: nil, **options) ⇒ OAuth2::Response @@ -487,8 +609,7 @@

    — -

    (:automatic) how to parse the response body. one of :query (for x-www-form-urlencoded),
    -:json, or :automatic (determined by Content-Type response header)

    +

    (:automatic) How to parse the response body

  • @@ -498,15 +619,31 @@

    snaky - (true, false) + (Boolean) (defaults to: true) — -

    (true) Convert @parsed to a snake-case,
    -indifferent-access SnakyHash::StringKeyed, which is a subclass of Hashie::Mash (from hashie gem)?

    +

    (true) Whether to convert parsed response to snake_case using SnakyHash

    +
    + +

  • + +
  • + + snaky_hash_klass + + + (Class, nil) + + + (defaults to: nil) + + + — +

    (nil) Custom class for snake_case hash conversion

  • @@ -521,13 +658,90 @@

    — -

    all other options for initializing the instance

    +

    Additional options for the response

  • + + + + + + + + + + + +

    Options Hash (**options):

    +
      + +
    • + :parse + (Symbol) + + + — default: + :automatic + + + + —

      Parse strategy (:query, :json, or :automatic)

      +
      + +
    • + +
    • + :snaky + (Boolean) + + + — default: + true + + + + —

      Enable/disable snake_case conversion

      +
      + +
    • + +
    • + :snaky_hash_klass + (Class) + + + — default: + SnakyHash::StringKeyed + + + + —

      Class to use for hash conversion

      +
      + +
    • + +
    + + +

    Since:

    +
      + +
    • + + + + + +

      1.0.0

      +
      + +
    • + +
    @@ -535,22 +749,24 @@

     
     
    -51
    -52
    -53
    -54
    -55
    -56
    -57
    +72 +73 +74 +75 +76 +77 +78 +79

    @@ -568,7 +784,7 @@

    Instance Attribute Details

    - #optionsObject + #optionsHash @@ -576,13 +792,45 @@

    -

    Returns the value of attribute options.

    +

    Returns The options hash for this instance.

    +

    Returns:

    +
      + +
    • + + + (Hash) + + + + — +

      The options hash for this instance

      +
      + +
    • + +
    +

    Since:

    +
      + +
    • + + + + + +

      1.0.0

      +
      + +
    • + +
    -
    # File 'lib/oauth2/response.rb', line 51
    +      
    # File 'lib/oauth2/response.rb', line 72
     
    -def initialize(response, parse: :automatic, snaky: true, **options)
    +def initialize(response, parse: :automatic, snaky: true, snaky_hash_klass: nil, **options)
       @response = response
       @options = {
         parse: parse,
         snaky: snaky,
    +    snaky_hash_klass: snaky_hash_klass,
       }.merge(options)
     end
    @@ -590,12 +838,12 @@

     
     
    -15
    -16
    -17
    +26 +27 +28

    -
    # File 'lib/oauth2/response.rb', line 15
    +      
    # File 'lib/oauth2/response.rb', line 26
     
     def options
       @options
    @@ -610,7 +858,7 @@ 

    - #responseObject (readonly) + #responseFaraday::Response (readonly) @@ -618,13 +866,45 @@

    -

    Returns the value of attribute response.

    +

    Returns The raw Faraday response object.

    +

    Returns:

    +
      + +
    • + + + (Faraday::Response) + + + + — +

      The raw Faraday response object

      +
      + +
    • + +
    +

    Since:

    +
      + +
    • + + + + + +

      1.0.0

      +
      + +
    • + +
    @@ -632,12 +912,12 @@

     
     
    -14
    -15
    -16
    +23 +24 +25

    -
    # File 'lib/oauth2/response.rb', line 14
    +      
    # File 'lib/oauth2/response.rb', line 23
     
     def response
       @response
    @@ -657,7 +937,7 @@ 

    Class Method Details

    - .register_parser(key, mime_types) {|String| ... } ⇒ Object + .register_parser(key, mime_types) {|String| ... } ⇒ void @@ -665,7 +945,7 @@

    -

    Adds a new content type parser.

    +

    This method returns an undefined value.

    Adds a new content type parser.

    @@ -684,7 +964,7 @@

    — -

    A descriptive symbol key such as :json or :query.

    +

    A descriptive symbol key such as :json or :query

    @@ -694,12 +974,12 @@

    mime_types - (Array) + (Array<String>, String) — -

    One or more mime types to which this parser applies.

    +

    One or more mime types to which this parser applies

    @@ -717,7 +997,41 @@

    — -

    A block returning parsed content.

    +

    Block that will be called to parse the response body

    +
    + + + + +

    Yield Parameters:

    +
      + +
    • + + body + + + (String) + + + + — +

      The response body to parse

      +
      + +
    • + +
    +

    Since:

    +
      + +
    • + + + + + +

      1.0.0

    • @@ -730,16 +1044,16 @@

       
       
      -35
      -36
      -37
      -38
      -39
      -40
      -41
      +53 +54 +55 +56 +57 +58 +59

    -
    # File 'lib/oauth2/response.rb', line 35
    +      
    # File 'lib/oauth2/response.rb', line 53
     
     def self.register_parser(key, mime_types, &block)
       key = key.to_sym
    @@ -762,7 +1076,7 @@ 

    Instance Method Details

    - #bodyObject + #bodyString @@ -777,6 +1091,38 @@

    +

    Returns:

    +
      + +
    • + + + (String) + + + + — +

      The response body or empty string if nil

      +
      + +
    • + +
    +

    Since:

    +
      + +
    • + + + + + +

      1.0.0

      +
      + +
    • + +
    @@ -784,12 +1130,12 @@

     
     
    -70
    -71
    -72
    +98 +99 +100

    -
    # File 'lib/oauth2/response.rb', line 70
    +      
    # File 'lib/oauth2/response.rb', line 98
     
     def body
       response.body || ""
    @@ -802,7 +1148,7 @@ 

    - #content_typeObject + #content_typeString? @@ -810,13 +1156,45 @@

    -

    Attempts to determine the content type of the response.

    +

    Determines the content type of the response

    +

    Returns:

    +
      + +
    • + + + (String, nil) + + + + — +

      The content type or nil if headers are not present

      +
      + +
    • + +
    +

    Since:

    +
      + +
    • + + + + + +

      1.0.0

      +
      + +
    • + +
    @@ -824,14 +1202,14 @@

     
     
    -101
    -102
    -103
    -104
    -105
    +132 +133 +134 +135 +136

    -
    # File 'lib/oauth2/response.rb', line 101
    +      
    # File 'lib/oauth2/response.rb', line 132
     
     def content_type
       return unless response.headers
    @@ -846,7 +1224,7 @@ 

    - #headersObject + #headersHash @@ -861,6 +1239,38 @@

    +

    Returns:

    +
      + +
    • + + + (Hash) + + + + — +

      The response headers

      +
      + +
    • + +
    +

    Since:

    +
      + +
    • + + + + + +

      1.0.0

      +
      + +
    • + +
    @@ -868,12 +1278,12 @@

     
     
    -60
    -61
    -62
    +84 +85 +86

    -
    # File 'lib/oauth2/response.rb', line 60
    +      
    # File 'lib/oauth2/response.rb', line 84
     
     def headers
       response.headers
    @@ -894,7 +1304,7 @@ 

    -

    The #response #body as parsed by #parser.

    +

    The parsed response body

    @@ -912,7 +1322,7 @@

    — -

    As returned by #parser if #call-able; snaky hash if options[:snaky].

    +

    The parsed response body

    @@ -925,7 +1335,22 @@

    — -

    If the #parser is not #call-able.

    +

    If no parser is available

    +
    + + + + +

    Since:

    +
      + +
    • + + + + + +

      1.0.0

    • @@ -938,30 +1363,31 @@

       
       
      -78
      -79
      -80
      -81
      -82
      -83
      -84
      -85
      -86
      -87
      -88
      -89
      -90
      -91
      -92
      -93
      -94
      -95
      -96
      -97
      -98
      +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127

    -
    # File 'lib/oauth2/response.rb', line 78
    +      
    # File 'lib/oauth2/response.rb', line 106
     
     def parsed
       return @parsed if defined?(@parsed)
    @@ -979,7 +1405,8 @@ 

    end if options[:snaky] && @parsed.is_a?(Hash) - @parsed = SnakyHash::StringKeyed.new(@parsed) + hash_klass = options[:snaky_hash_klass] || DEFAULT_OPTIONS[:snaky_hash_klass] + @parsed = hash_klass[@parsed] end @parsed @@ -1000,19 +1427,30 @@

    -

    Determines the parser (a Proc or other Object which responds to #call)
    -that will be passed the #body (and optional #response) to supply
    -#parsed.

    - -

    The parser can be supplied as the +:parse+ option in the form of a Proc
    + +

    + Note: +

    The parser can be supplied as the +:parse+ option in the form of a Proc
    (or other Object responding to #call) or a Symbol. In the latter case,
    the actual parser will be looked up in @@parsers by the supplied Symbol.

    +
    +
    -

    If no +:parse+ option is supplied, the lookup Symbol will be determined
    +

    + Note: +

    If no +:parse+ option is supplied, the lookup Symbol will be determined
    by looking up #content_type in @@content_types.

    +
    +
    -

    If #parser is a Proc, it will be called with no arguments, just
    +

    + Note: +

    If #parser is a Proc, it will be called with no arguments, just
    #body, or #body and #response, depending on the Proc’s arity.

    +
    +
    + +

    Determines the parser to be used for the response body

    @@ -1030,7 +1468,7 @@

    — -

    If a parser was found.

    +

    The parser proc or callable object

    @@ -1043,7 +1481,22 @@

    — -

    If no parser was found.

    +

    If no suitable parser is found

    +
    + + + + +

    Since:

    +
      + +
    • + + + + + +

      1.0.0

    • @@ -1056,21 +1509,21 @@

       
       
      -123
      -124
      -125
      -126
      -127
      -128
      -129
      -130
      -131
      -132
      -133
      -134
      +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163

    -
    # File 'lib/oauth2/response.rb', line 123
    +      
    # File 'lib/oauth2/response.rb', line 152
     
     def parser
       return @parser if defined?(@parser)
    @@ -1092,7 +1545,7 @@ 

    - #statusObject + #statusInteger @@ -1107,6 +1560,38 @@

    +

    Returns:

    +
      + +
    • + + + (Integer) + + + + — +

      The response status code

      +
      + +
    • + +
    +

    Since:

    +
      + +
    • + + + + + +

      1.0.0

      +
      + +
    • + +
    @@ -1114,12 +1599,12 @@

     
     
    -65
    -66
    -67
    +91 +92 +93

    @@ -497,9 +497,7 @@

    Security contact information

    What is new for v2.0?

      -
    • Officially support Ruby versions >= 2.7
    • -
    • Unofficially support Ruby versions >= 2.5
    • -
    • Incidentally support Ruby versions >= 2.2
    • +
    • Works with Ruby versions >= 2.2
    • Drop support for the expired MAC Draft (all versions)
    • Support IETF rfc7523 JWT Bearer Tokens
    • Support IETF rfc7231 Relative Location in Redirect
    • @@ -509,14 +507,14 @@

      What is new for v2.0?

    • Support new formats, including from jsonapi.org: application/vdn.api+json, application/vnd.collection+json, application/hal+json, application/problem+json
    • -
    • Adds new option to OAuth2::Client#get_token: +
    • Adds option to OAuth2::Client#get_token:
      • :access_token_class (AccessToken); user specified class to use for all calls to get_token
    • -
    • Adds new option to OAuth2::AccessToken#initialize: +
    • Adds option to OAuth2::AccessToken#initialize:
      • :expires_latency (nil); number of seconds by which AccessToken validity will be reduced to offset latency
      • @@ -702,18 +700,16 @@

        Serialization

        As of v2.0.11, if you need to serialize the parsed result, you can!

        -

        There are two ways to do this.

        +

        There are two ways to do this, and the second option recommended.

          -
        1. Global: put this in your code somewhere reasonable (like an initializer for Rails): -
          SnakyHash::StringKeyed.class_eval do
          +  
        2. Globally configure SnakyHash::StringKeyed to use the serializer. Put this in your code somewhere reasonable (like an initializer for Rails):
        3. +
        + +
        SnakyHash::StringKeyed.class_eval do
           extend SnakyHash::Serializer
         end
         
        - - - -

        2.

        What if I hate snakes and/or indifference?

        @@ -726,7 +722,7 @@

        What if I hate snakes and/or i
        - Debugging + Debugging & Logging Set an environment variable as per usual (e.g. with [dotenv](https://github.com/bkeepers/dotenv)). @@ -973,7 +969,7 @@

        🤑 One more thing

        diff --git a/doc/file.SECURITY.html b/doc/file.SECURITY.html index a3f453b4..53052274 100644 --- a/doc/file.SECURITY.html +++ b/doc/file.SECURITY.html @@ -110,7 +110,7 @@

        OAuth2 for Enterprise

        diff --git a/doc/index.html b/doc/index.html index fe06b210..c4f78d7e 100644 --- a/doc/index.html +++ b/doc/index.html @@ -68,7 +68,7 @@

        🔐 OAuth2

        -

        Version License: MIT Downloads Rank Open Source Helpers Depfu Coveralls Test Coverage QLTY Test Coverage CI Heads CI Runtime Dependencies @ HEAD CI Current CI Truffle Ruby CI JRuby CI Supported CI Legacy CI Unsupported CI Ancient CI Caboose is an absolute WAGON CI Test Coverage CI Style CodeQL

        +

        Version License: MIT Downloads Rank Open Source Helpers Depfu Coveralls Test Coverage QLTY Test Coverage QLTY Maintainability CI Heads CI Runtime Dependencies @ HEAD CI Current CI Truffle Ruby CI JRuby CI Supported CI Legacy CI Unsupported CI Ancient CI Caboose is an absolute WAGON CI Test Coverage CI Style CodeQL


        @@ -324,7 +324,7 @@

        💡 Info you can shake a stick at

    @@ -497,9 +497,7 @@

    Security contact information

    What is new for v2.0?

      -
    • Officially support Ruby versions >= 2.7
    • -
    • Unofficially support Ruby versions >= 2.5
    • -
    • Incidentally support Ruby versions >= 2.2
    • +
    • Works with Ruby versions >= 2.2
    • Drop support for the expired MAC Draft (all versions)
    • Support IETF rfc7523 JWT Bearer Tokens
    • Support IETF rfc7231 Relative Location in Redirect
    • @@ -509,14 +507,14 @@

      What is new for v2.0?

    • Support new formats, including from jsonapi.org: application/vdn.api+json, application/vnd.collection+json, application/hal+json, application/problem+json
    • -
    • Adds new option to OAuth2::Client#get_token: +
    • Adds option to OAuth2::Client#get_token:
      • :access_token_class (AccessToken); user specified class to use for all calls to get_token
    • -
    • Adds new option to OAuth2::AccessToken#initialize: +
    • Adds option to OAuth2::AccessToken#initialize:
      • :expires_latency (nil); number of seconds by which AccessToken validity will be reduced to offset latency
      • @@ -702,18 +700,16 @@

        Serialization

        As of v2.0.11, if you need to serialize the parsed result, you can!

        -

        There are two ways to do this.

        +

        There are two ways to do this, and the second option recommended.

          -
        1. Global: put this in your code somewhere reasonable (like an initializer for Rails): -
          SnakyHash::StringKeyed.class_eval do
          +  
        2. Globally configure SnakyHash::StringKeyed to use the serializer. Put this in your code somewhere reasonable (like an initializer for Rails):
        3. +
        + +
        SnakyHash::StringKeyed.class_eval do
           extend SnakyHash::Serializer
         end
         
        - - - -

        2.

        What if I hate snakes and/or indifference?

        @@ -726,7 +722,7 @@

        What if I hate snakes and/or i
        - Debugging + Debugging & Logging Set an environment variable as per usual (e.g. with [dotenv](https://github.com/bkeepers/dotenv)). @@ -973,7 +969,7 @@

        🤑 One more thing

        diff --git a/doc/top-level-namespace.html b/doc/top-level-namespace.html index eb9808e4..6aa75086 100644 --- a/doc/top-level-namespace.html +++ b/doc/top-level-namespace.html @@ -100,7 +100,7 @@

        Defined Under Namespace

        diff --git a/docker-compose-ssl.yml b/docker-compose-ssl.yml new file mode 100644 index 00000000..9a17fbba --- /dev/null +++ b/docker-compose-ssl.yml @@ -0,0 +1,12 @@ +services: + mock-oauth2-server: + image: ghcr.io/navikt/mock-oauth2-server:2.1.11 + ports: + - "8080:8080" + hostname: host.docker.internal + volumes: + - ./config-ssl.json:/app/config.json:Z + environment: + LOG_LEVEL: "debug" + SERVER_PORT: 8080 + JSON_CONFIG_PATH: /app/config.json diff --git a/lib/oauth2/client.rb b/lib/oauth2/client.rb index b1496195..41d97338 100644 --- a/lib/oauth2/client.rb +++ b/lib/oauth2/client.rb @@ -19,7 +19,7 @@ module OAuth2 # The OAuth2::Client class class Client # rubocop:disable Metrics/ClassLength RESERVED_REQ_KEYS = %w[body headers params redirect_count].freeze - RESERVED_PARAM_KEYS = (RESERVED_REQ_KEYS + %w[parse snaky token_method]).freeze + RESERVED_PARAM_KEYS = (RESERVED_REQ_KEYS + %w[parse snaky snaky_hash_klass token_method]).freeze include FilteredAttributes @@ -342,14 +342,26 @@ def redirection_params private - # A generic token request options parser + # Processes request parameters and transforms them into request options + # + # @param [Hash] params the request parameters to process + # @option params [Symbol] :parse (:automatic) parsing strategy for the response + # @option params [Boolean] :snaky (true) whether to convert response keys to snake_case + # @option params [Class] :snaky_hash_klass (SnakyHash::StringKeyed) class to use for snake_case hash conversion + # @option params [Symbol] :token_method (:post) HTTP method to use for token request + # @option params [Hash] :headers Additional HTTP headers for the request + # + # @return [Hash] the processed request options + # + # @api private def params_to_req_opts(params) - parse, snaky, token_method, params, headers = parse_snaky_params_headers(params) + parse, snaky, snaky_hash_klass, token_method, params, headers = parse_snaky_params_headers(params) req_opts = { raise_errors: options[:raise_errors], token_method: token_method || options[:token_method], parse: parse, snaky: snaky, + snaky_hash_klass: snaky_hash_klass, } if req_opts[:token_method] == :post # NOTE: If proliferation of request types continues, we should implement a parser solution for Request, @@ -369,19 +381,22 @@ def params_to_req_opts(params) req_opts end - # Processes and transforms the input parameters for OAuth requests + # Processes and transforms parameters for OAuth requests # # @param [Hash] params the input parameters to process - # @option params [Symbol, nil] :parse (:automatic) parsing strategy for the response + # @option params [Symbol] :parse (:automatic) parsing strategy for the response # @option params [Boolean] :snaky (true) whether to convert response keys to snake_case + # @option params [Class] :snaky_hash_klass (SnakyHash::StringKeyed) class to use for snake_case hash conversion + # @option params [Symbol] :token_method overrides the default token method for this request # @option params [Hash] :headers HTTP headers for the request # - # @return [Array<(Symbol, Boolean, Hash, Hash)>] Returns an array containing: - # - [Symbol, nil] parse strategy - # - [Boolean] snaky flag for response key transformation - # - [Symbol, nil] token_method overrides options[:token_method] for a request - # - [Hash] processed parameters - # - [Hash] HTTP headers + # @return [Array<(Symbol, Boolean, Class, Symbol, Hash, Hash)>] Returns an array containing: + # - parse strategy (Symbol) + # - snaky flag for response key transformation (Boolean) + # - hash class for snake_case conversion (Class) + # - token method override (Symbol, nil) + # - processed parameters (Hash) + # - HTTP headers (Hash) # # @api private def parse_snaky_params_headers(params) @@ -394,11 +409,12 @@ def parse_snaky_params_headers(params) end.to_h parse = params.key?(:parse) ? params.delete(:parse) : Response::DEFAULT_OPTIONS[:parse] snaky = params.key?(:snaky) ? params.delete(:snaky) : Response::DEFAULT_OPTIONS[:snaky] + snaky_hash_klass = params.key?(:snaky_hash_klass) ? params.delete(:snaky_hash_klass) : Response::DEFAULT_OPTIONS[:snaky_hash_klass] token_method = params.delete(:token_method) if params.key?(:token_method) params = authenticator.apply(params) # authenticator may add :headers, and we separate them from params here headers = params.delete(:headers) || {} - [parse, snaky, token_method, params, headers] + [parse, snaky, snaky_hash_klass, token_method, params, headers] end # Executes an HTTP request with error handling and response processing diff --git a/lib/oauth2/response.rb b/lib/oauth2/response.rb index fe03cd43..fb47c381 100644 --- a/lib/oauth2/response.rb +++ b/lib/oauth2/response.rb @@ -5,23 +5,39 @@ require "rack" module OAuth2 - # OAuth2::Response class + # The Response class handles HTTP responses in the OAuth2 gem, providing methods + # to access and parse response data in various formats. + # + # @since 1.0.0 class Response + # Default configuration options for Response instances + # + # @return [Hash] The default options hash DEFAULT_OPTIONS = { parse: :automatic, snaky: true, + snaky_hash_klass: SnakyHash::StringKeyed, }.freeze + + # @return [Faraday::Response] The raw Faraday response object attr_reader :response + + # @return [Hash] The options hash for this instance attr_accessor :options - # Procs that, when called, will parse a response body according - # to the specified format. + # @private + # Storage for response body parser procedures + # + # @return [Hash] Hash of parser procs keyed by format symbol @@parsers = { query: ->(body) { Rack::Utils.parse_query(body) }, text: ->(body) { body }, } - # Content type assignments for various potential HTTP content types. + # @private + # Maps content types to parser symbols + # + # @return [Hash] Hash of content types mapped to parser symbols @@content_types = { "application/x-www-form-urlencoded" => :query, "text/plain" => :text, @@ -29,9 +45,11 @@ class Response # Adds a new content type parser. # - # @param [Symbol] key A descriptive symbol key such as :json or :query. - # @param [Array] mime_types One or more mime types to which this parser applies. - # @yield [String] A block returning parsed content. + # @param [Symbol] key A descriptive symbol key such as :json or :query + # @param [Array, String] mime_types One or more mime types to which this parser applies + # @yield [String] Block that will be called to parse the response body + # @yieldparam [String] body The response body to parse + # @return [void] def self.register_parser(key, mime_types, &block) key = key.to_sym @@parsers[key] = block @@ -43,38 +61,48 @@ def self.register_parser(key, mime_types, &block) # Initializes a Response instance # # @param [Faraday::Response] response The Faraday response instance - # @param [Symbol] parse (:automatic) how to parse the response body. one of :query (for x-www-form-urlencoded), - # :json, or :automatic (determined by Content-Type response header) - # @param [true, false] snaky (true) Convert @parsed to a snake-case, - # indifferent-access SnakyHash::StringKeyed, which is a subclass of Hashie::Mash (from hashie gem)? - # @param [Hash] options all other options for initializing the instance - def initialize(response, parse: :automatic, snaky: true, **options) + # @param [Symbol] parse (:automatic) How to parse the response body + # @param [Boolean] snaky (true) Whether to convert parsed response to snake_case using SnakyHash + # @param [Class, nil] snaky_hash_klass (nil) Custom class for snake_case hash conversion + # @param [Hash] options Additional options for the response + # @option options [Symbol] :parse (:automatic) Parse strategy (:query, :json, or :automatic) + # @option options [Boolean] :snaky (true) Enable/disable snake_case conversion + # @option options [Class] :snaky_hash_klass (SnakyHash::StringKeyed) Class to use for hash conversion + # @return [OAuth2::Response] The new Response instance + def initialize(response, parse: :automatic, snaky: true, snaky_hash_klass: nil, **options) @response = response @options = { parse: parse, snaky: snaky, + snaky_hash_klass: snaky_hash_klass, }.merge(options) end # The HTTP response headers + # + # @return [Hash] The response headers def headers response.headers end # The HTTP response status code + # + # @return [Integer] The response status code def status response.status end # The HTTP response body + # + # @return [String] The response body or empty string if nil def body response.body || "" end - # The {#response} {#body} as parsed by {#parser}. + # The parsed response body # - # @return [Object, SnakyHash::StringKeyed] As returned by {#parser} if #call-able; snaky hash if options[:snaky]. - # @return [nil] If the {#parser} is not #call-able. + # @return [Object, SnakyHash::StringKeyed] The parsed response body + # @return [nil] If no parser is available def parsed return @parsed if defined?(@parsed) @@ -91,35 +119,36 @@ def parsed end if options[:snaky] && @parsed.is_a?(Hash) - @parsed = SnakyHash::StringKeyed.new(@parsed) + hash_klass = options[:snaky_hash_klass] || DEFAULT_OPTIONS[:snaky_hash_klass] + @parsed = hash_klass[@parsed] end @parsed end - # Attempts to determine the content type of the response. + # Determines the content type of the response + # + # @return [String, nil] The content type or nil if headers are not present def content_type return unless response.headers ((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) - # that will be passed the {#body} (and optional {#response}) to supply - # {#parsed}. + # Determines the parser to be used for the response body # - # The parser can be supplied as the +:parse+ option in the form of a Proc - # (or other Object responding to #call) or a Symbol. In the latter case, - # the actual parser will be looked up in {@@parsers} by the supplied Symbol. + # @note The parser can be supplied as the +:parse+ option in the form of a Proc + # (or other Object responding to #call) or a Symbol. In the latter case, + # the actual parser will be looked up in {@@parsers} by the supplied Symbol. # - # If no +:parse+ option is supplied, the lookup Symbol will be determined - # by looking up {#content_type} in {@@content_types}. + # @note If no +:parse+ option is supplied, the lookup Symbol will be determined + # by looking up {#content_type} in {@@content_types}. # - # If {#parser} is a Proc, it will be called with no arguments, just - # {#body}, or {#body} and {#response}, depending on the Proc's arity. + # @note If {#parser} is a Proc, it will be called with no arguments, just + # {#body}, or {#body} and {#response}, depending on the Proc's arity. # - # @return [Proc, #call] If a parser was found. - # @return [nil] If no parser was found. + # @return [Proc, #call] The parser proc or callable object + # @return [nil] If no suitable parser is found def parser return @parser if defined?(@parser) @@ -135,12 +164,16 @@ def parser end end +# Register XML parser +# @api private 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 +# Register JSON parser +# @api private 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) diff --git a/lib/oauth2/version.rb b/lib/oauth2/version.rb index 42e2e99c..14e7ed0f 100644 --- a/lib/oauth2/version.rb +++ b/lib/oauth2/version.rb @@ -2,6 +2,6 @@ module OAuth2 module Version - VERSION = "2.0.10" + VERSION = "2.0.11" end end diff --git a/oauth2.gemspec b/oauth2.gemspec index 6b8d7ec4..a461461e 100644 --- a/oauth2.gemspec +++ b/oauth2.gemspec @@ -131,7 +131,7 @@ Thanks, |7eter l-|. l3oling spec.add_dependency("logger", "~> 1.2") # Ruby >= 0 spec.add_dependency("multi_xml", "~> 0.5") # Ruby >= 0 spec.add_dependency("rack", [">= 1.2", "< 4"]) # Ruby >= 0 - spec.add_dependency("snaky_hash", "~> 2.0", ">= 2.0.2") # Ruby >= 2.2 + spec.add_dependency("snaky_hash", "~> 2.0", ">= 2.0.3") # Ruby >= 2.2 spec.add_dependency("version_gem", ">= 1.1.8", "< 3") # Ruby >= 2.2 spec.add_development_dependency("addressable", "~> 2.8", ">= 2.8.7") # ruby >= 2.2 diff --git a/spec/oauth2/client_spec.rb b/spec/oauth2/client_spec.rb index abe17787..545e5259 100644 --- a/spec/oauth2/client_spec.rb +++ b/spec/oauth2/client_spec.rb @@ -525,6 +525,18 @@ expect(token.token).to eq("the-token") end + it "works with a standard Hash if keys are correct" do + client = stubbed_client do |stub| + stub.post("/oauth/token") do + [200, {"Content-Type" => "application/json"}, JSON.dump("access_token" => "the-token")] + end + end + + token = client.get_token({snaky_hash_klass: Hash}) + expect(token).to be_a OAuth2::AccessToken + expect(token.token).to eq("the-token") + end + context "when parse: :automatic" do it "returns a configured AccessToken" do client = stubbed_client do |stub| diff --git a/spec/oauth2/response_spec.rb b/spec/oauth2/response_spec.rb index 5a0689f2..68112a42 100644 --- a/spec/oauth2/response_spec.rb +++ b/spec/oauth2/response_spec.rb @@ -314,7 +314,7 @@ subject = described_class.new(response, parse: false) - expect(subject.parsed).to eq(nil) + expect(subject.parsed).to be_nil end end @@ -345,4 +345,380 @@ expect { subject.to_json }.not_to raise_error end end + + describe "with custom vanilla snaky_hash_klass" do + let(:parsed_response) { {"some_key" => "some_value"} } + let(:custom_hash_class) do + Class.new(Hash) + end + + before do + @response = double( + "response", + headers: {"Content-Type" => "application/json"}, + status: 200, + body: parsed_response.to_json, + ) + end + + it "uses the specified hash class when snaky is true" do + response = described_class.new(@response, parse: :automatic, snaky: true, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(custom_hash_class) + expect(response.parsed).not_to be_a(OAuth2::Response::DEFAULT_OPTIONS[:snaky_hash_klass]) + expect(response.parsed).to eq({"some_key" => "some_value"}) + expect(response.parsed["some_key"]).to eq("some_value") + end + + it "uses the default hash class when snaky_hash_klass is not specified" do + response = described_class.new(@response, parse: :automatic, snaky: true) + expect(response.parsed).not_to be_a(custom_hash_class) + expect(response.parsed).to be_a(OAuth2::Response::DEFAULT_OPTIONS[:snaky_hash_klass]) + end + + it "doesn't convert to any special hash class when snaky is false" do + response = described_class.new(@response, parse: :automatic, snaky: false, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(Hash) + expect(response.parsed).not_to be_a(custom_hash_class) + end + end + + describe "with dump_value & load_value extensions" do + let(:custom_hash_class) do + klass = Class.new(SnakyHash::StringKeyed) do + # Give this class has `dump` and `load` abilities! + extend SnakyHash::Serializer + + unless instance_methods.include?(:transform_keys) + # Patch our custom Hash to support Ruby < 2.4.2 + def transform_keys! + keys.each do |key| + ref = delete(key) + self[key] = yield(ref) + end + end + + def transform_keys + dup.transform_keys! { |key| yield(key) } + end + end + end + + # Act on the non-hash values as they are dumped to JSON + klass.dump_value_extensions.add(:to_fruit) do |value| + "banana" + end + + # Act on the non-hash values as they are loaded from the JSON dump + klass.load_value_extensions.add(:to_stars) do |value| + "asdf***qwer" + end + + klass + end + + before do + @response = double( + "response", + headers: {"Content-Type" => "application/json"}, + status: 200, + body: parsed_response.to_json, + ) + end + + context "when hash with top-level hashes" do + let(:parsed_response) { {"a-b_c-d_e-F_G-H" => "i-j_k-l_m-n_o-P_Q-R", "arr" => [1, 2, 3]} } + + it "uses the specified hash class when snaky is true" do + response = described_class.new(@response, parse: :automatic, snaky: true, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(custom_hash_class) + expect(response.parsed).to eq("a_b_c_d_e_f_g_h" => "i-j_k-l_m-n_o-P_Q-R", "arr" => [1, 2, 3]) + expect(response.parsed["a_b_c_d_e_f_g_h"]).to eq("i-j_k-l_m-n_o-P_Q-R") + expect(response.parsed[:a_b_c_d_e_f_g_h]).to eq("i-j_k-l_m-n_o-P_Q-R") + expect(response.parsed.a_b_c_d_e_f_g_h).to eq("i-j_k-l_m-n_o-P_Q-R") + expect(response.parsed["arr"]).to eq([1, 2, 3]) + expect(response.parsed[:arr]).to eq([1, 2, 3]) + expect(response.parsed.arr).to eq([1, 2, 3]) + end + + it "can dump the hash" do + response = described_class.new(@response, parse: :automatic, snaky: true, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(custom_hash_class) + expect(response.parsed.class.dump_value_extensions.has?(:to_fruit)).to be(true) + dump = custom_hash_class.dump(response.parsed) + expect(dump).to eq("{\"a_b_c_d_e_f_g_h\":\"banana\",\"arr\":[\"banana\",\"banana\",\"banana\"]}") + end + + it "can load the dump, and run extensions on values" do + response = described_class.new(@response, parse: :automatic, snaky: true, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(custom_hash_class) + expect(response.parsed.class.load_value_extensions.has?(:to_stars)).to be(true) + dump = custom_hash_class.dump(response.parsed) + hydrated = custom_hash_class.load(dump) + expect(hydrated).not_to eq(response.parsed.to_hash) + expect(hydrated).to eq({ + "a_b_c_d_e_f_g_h" => "asdf***qwer", + "arr" => %w[asdf***qwer asdf***qwer asdf***qwer], + }) + expect(hydrated["a_b_c_d_e_f_g_h"]).to eq("asdf***qwer") + expect(hydrated[:a_b_c_d_e_f_g_h]).to eq("asdf***qwer") + expect(hydrated.a_b_c_d_e_f_g_h).to eq("asdf***qwer") + expect(hydrated["arr"]).to eq(%w[asdf***qwer asdf***qwer asdf***qwer]) + expect(hydrated[:arr]).to eq(%w[asdf***qwer asdf***qwer asdf***qwer]) + expect(hydrated.arr).to eq(%w[asdf***qwer asdf***qwer asdf***qwer]) + end + + it "doesn't convert to any special hash class when snaky is false" do + response = described_class.new(@response, parse: :automatic, snaky: false, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(Hash) + expect(response.parsed).not_to be_a(custom_hash_class) + expect(response.parsed).to eq("a-b_c-d_e-F_G-H" => "i-j_k-l_m-n_o-P_Q-R", "arr" => [1, 2, 3]) + expect(response.parsed["a-b_c-d_e-F_G-H"]).to eq("i-j_k-l_m-n_o-P_Q-R") + expect(response.parsed["arr"]).to eq([1, 2, 3]) + end + end + + context "when hash with nested hashes" do + let(:parsed_response) { {"a-b_c-d_e-F_G-H" => {"i-j_k-l_m-n_o-P_Q-R" => "s-t_u-v_w-X_Y-Z"}, "arr" => [1, 2, 3]} } + + it "uses the specified hash class when snaky is true" do + response = described_class.new(@response, parse: :automatic, snaky: true, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(custom_hash_class) + expect(response.parsed).to eq("a_b_c_d_e_f_g_h" => {"i_j_k_l_m_n_o_p_q_r" => "s-t_u-v_w-X_Y-Z"}, "arr" => [1, 2, 3]) + expect(response.parsed["a_b_c_d_e_f_g_h"]).to eq({"i_j_k_l_m_n_o_p_q_r" => "s-t_u-v_w-X_Y-Z"}) + expect(response.parsed[:a_b_c_d_e_f_g_h]).to eq({"i_j_k_l_m_n_o_p_q_r" => "s-t_u-v_w-X_Y-Z"}) + expect(response.parsed.a_b_c_d_e_f_g_h).to eq({"i_j_k_l_m_n_o_p_q_r" => "s-t_u-v_w-X_Y-Z"}) + expect(response.parsed["arr"]).to eq([1, 2, 3]) + expect(response.parsed[:arr]).to eq([1, 2, 3]) + expect(response.parsed.arr).to eq([1, 2, 3]) + end + + it "can dump the hash" do + response = described_class.new(@response, parse: :automatic, snaky: true, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(custom_hash_class) + expect(response.parsed.class.dump_value_extensions.has?(:to_fruit)).to be(true) + dump = custom_hash_class.dump(response.parsed) + expect(dump).to eq("{\"a_b_c_d_e_f_g_h\":{\"i_j_k_l_m_n_o_p_q_r\":\"banana\"},\"arr\":[\"banana\",\"banana\",\"banana\"]}") + end + + it "can load the dump, and run extensions on values" do + response = described_class.new(@response, parse: :automatic, snaky: true, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(custom_hash_class) + expect(response.parsed.class.load_value_extensions.has?(:to_stars)).to be(true) + dump = custom_hash_class.dump(response.parsed) + hydrated = custom_hash_class.load(dump) + expect(hydrated).not_to eq(response.parsed.to_hash) + expect(hydrated).to eq({ + "a_b_c_d_e_f_g_h" => + { + "i_j_k_l_m_n_o_p_q_r" => "asdf***qwer", + }, + "arr" => %w[asdf***qwer asdf***qwer asdf***qwer], + }) + expect(hydrated["a_b_c_d_e_f_g_h"]).to eq({"i_j_k_l_m_n_o_p_q_r" => "asdf***qwer"}) + expect(hydrated[:a_b_c_d_e_f_g_h]).to eq({"i_j_k_l_m_n_o_p_q_r" => "asdf***qwer"}) + expect(hydrated.a_b_c_d_e_f_g_h).to eq({"i_j_k_l_m_n_o_p_q_r" => "asdf***qwer"}) + expect(hydrated["arr"]).to eq(%w[asdf***qwer asdf***qwer asdf***qwer]) + expect(hydrated[:arr]).to eq(%w[asdf***qwer asdf***qwer asdf***qwer]) + expect(hydrated.arr).to eq(%w[asdf***qwer asdf***qwer asdf***qwer]) + end + + it "doesn't convert to any special hash class when snaky is false" do + response = described_class.new(@response, parse: :automatic, snaky: false, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(Hash) + expect(response.parsed).not_to be_a(custom_hash_class) + expect(response.parsed).to eq("a-b_c-d_e-F_G-H" => {"i-j_k-l_m-n_o-P_Q-R" => "s-t_u-v_w-X_Y-Z"}, "arr" => [1, 2, 3]) + expect(response.parsed["a-b_c-d_e-F_G-H"]).to eq({"i-j_k-l_m-n_o-P_Q-R" => "s-t_u-v_w-X_Y-Z"}) + expect(response.parsed["arr"]).to eq([1, 2, 3]) + end + end + end + + describe "with dump_hash & load_hash extensions" do + let(:custom_hash_class) do + klass = Class.new(SnakyHash::StringKeyed) do + # Give this class has `dump` and `load` abilities! + extend SnakyHash::Serializer + + unless instance_methods.include?(:transform_keys) + # Patch our custom Hash to support Ruby < 2.4.2 + def transform_keys! + keys.each do |key| + ref = delete(key) + self[key] = yield(ref) + end + end + + def transform_keys + dup.transform_keys! { |key| yield(key) } + end + end + end + + # Act on the entire hash as it is prepared for dumping to JSON + klass.dump_hash_extensions.add(:to_cheese) do |value| + if value.is_a?(Hash) + # TODO: Drop this hack when dropping support for Ruby 2.6 + ref = value.transform_keys do |key| + # This is an example tailored to this specific test! + # It is not a generalized solution for anything! + split = key.split("_") + first_word = split[0] + key.sub(first_word, "cheese") + end + # TODO: Drop this hack when dropping support for Ruby <= 2.4 + if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.4.2") + ref + else + puts + klass[ref] + end + else + value + end + end + + # Act on the entire hash as it is loaded from the JSON dump + klass.load_hash_extensions.add(:to_pizza) do |value| + if value.is_a?(Hash) + # TODO: Drop this hack when dropping support for Ruby <= 2.4 + if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.4.2") + value.transform_keys do |key| + # This is an example tailored to this specific test! + # It is not a generalized solution for anything! + split = key.split("_") + last_word = split[-1] + key.sub(last_word, "pizza") + end + else + res = klass.new + value.keys.each_with_object(res) do |key, result| + split = key.split("_") + last_word = split[-1] + new_key = key.sub(last_word, "pizza") + result[new_key] = value[key] + end + res + end + else + value + end + end + + klass + end + + before do + @response = double( + "response", + headers: {"Content-Type" => "application/json"}, + status: 200, + body: parsed_response.to_json, + ) + end + + context "when hash with top-level hashes" do + let(:parsed_response) { {"a-b_c-d_e-F_G-H" => "i-j_k-l_m-n_o-P_Q-R", "arr" => [1, 2, 3]} } + + it "uses the specified hash class when snaky is true" do + response = described_class.new(@response, parse: :automatic, snaky: true, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(custom_hash_class) + expect(response.parsed).to eq("a_b_c_d_e_f_g_h" => "i-j_k-l_m-n_o-P_Q-R", "arr" => [1, 2, 3]) + expect(response.parsed["a_b_c_d_e_f_g_h"]).to eq("i-j_k-l_m-n_o-P_Q-R") + expect(response.parsed[:a_b_c_d_e_f_g_h]).to eq("i-j_k-l_m-n_o-P_Q-R") + expect(response.parsed.a_b_c_d_e_f_g_h).to eq("i-j_k-l_m-n_o-P_Q-R") + expect(response.parsed["arr"]).to eq([1, 2, 3]) + expect(response.parsed[:arr]).to eq([1, 2, 3]) + expect(response.parsed.arr).to eq([1, 2, 3]) + end + + it "can dump the hash" do + response = described_class.new(@response, parse: :automatic, snaky: true, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(custom_hash_class) + expect(response.parsed.class.dump_hash_extensions.has?(:to_cheese)).to be(true) + puts "response.parsed: #{response.parsed.inspect} (#{response.parsed})" + dump = custom_hash_class.dump(response.parsed) + expect(dump).to eq("{\"cheese_b_c_d_e_f_g_h\":\"i-j_k-l_m-n_o-P_Q-R\",\"cheese\":[1,2,3]}") + end + + it "can load the dump, and run extensions on values" do + response = described_class.new(@response, parse: :automatic, snaky: true, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(custom_hash_class) + expect(response.parsed.class.load_hash_extensions.has?(:to_pizza)).to be(true) + dump = custom_hash_class.dump(response.parsed) + hydrated = custom_hash_class.load(dump) + expect(hydrated).not_to eq(response.parsed.to_hash) + expect(hydrated).to eq({ + "cpizzaeese_b_c_d_e_f_g_h" => "i-j_k-l_m-n_o-P_Q-R", + "pizza" => [1, 2, 3], + }) + expect(hydrated["cpizzaeese_b_c_d_e_f_g_h"]).to eq("i-j_k-l_m-n_o-P_Q-R") + expect(hydrated[:cpizzaeese_b_c_d_e_f_g_h]).to eq("i-j_k-l_m-n_o-P_Q-R") + expect(hydrated.cpizzaeese_b_c_d_e_f_g_h).to eq("i-j_k-l_m-n_o-P_Q-R") + expect(hydrated["pizza"]).to eq([1, 2, 3]) + expect(hydrated[:pizza]).to eq([1, 2, 3]) + expect(hydrated.pizza).to eq([1, 2, 3]) + end + + it "doesn't convert to any special hash class when snaky is false" do + response = described_class.new(@response, parse: :automatic, snaky: false, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(Hash) + expect(response.parsed).not_to be_a(custom_hash_class) + expect(response.parsed).to eq("a-b_c-d_e-F_G-H" => "i-j_k-l_m-n_o-P_Q-R", "arr" => [1, 2, 3]) + expect(response.parsed["a-b_c-d_e-F_G-H"]).to eq("i-j_k-l_m-n_o-P_Q-R") + expect(response.parsed["arr"]).to eq([1, 2, 3]) + end + end + + context "when hash with nested hashes" do + let(:parsed_response) { {"a-b_c-d_e-F_G-H" => {"i-j_k-l_m-n_o-P_Q-R" => "s-t_u-v_w-X_Y-Z"}, "arr" => [1, 2, 3]} } + + it "uses the specified hash class when snaky is true" do + response = described_class.new(@response, parse: :automatic, snaky: true, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(custom_hash_class) + expect(response.parsed).to eq("a_b_c_d_e_f_g_h" => {"i_j_k_l_m_n_o_p_q_r" => "s-t_u-v_w-X_Y-Z"}, "arr" => [1, 2, 3]) + expect(response.parsed["a_b_c_d_e_f_g_h"]).to eq({"i_j_k_l_m_n_o_p_q_r" => "s-t_u-v_w-X_Y-Z"}) + expect(response.parsed[:a_b_c_d_e_f_g_h]).to eq({"i_j_k_l_m_n_o_p_q_r" => "s-t_u-v_w-X_Y-Z"}) + expect(response.parsed.a_b_c_d_e_f_g_h).to eq({"i_j_k_l_m_n_o_p_q_r" => "s-t_u-v_w-X_Y-Z"}) + expect(response.parsed["arr"]).to eq([1, 2, 3]) + expect(response.parsed[:arr]).to eq([1, 2, 3]) + expect(response.parsed.arr).to eq([1, 2, 3]) + end + + it "can dump the hash" do + response = described_class.new(@response, parse: :automatic, snaky: true, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(custom_hash_class) + expect(response.parsed.class.dump_hash_extensions.has?(:to_cheese)).to be(true) + dump = custom_hash_class.dump(response.parsed) + expect(dump).to eq("{\"cheese_b_c_d_e_f_g_h\":{\"cheese_j_k_l_m_n_o_p_q_r\":\"s-t_u-v_w-X_Y-Z\"},\"cheese\":[1,2,3]}") + end + + it "can load the dump, and run extensions on values" do + response = described_class.new(@response, parse: :automatic, snaky: true, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(custom_hash_class) + expect(response.parsed.class.load_hash_extensions.has?(:to_pizza)).to be(true) + dump = custom_hash_class.dump(response.parsed) + hydrated = custom_hash_class.load(dump) + expect(hydrated).not_to eq(response.parsed.to_hash) + expect(hydrated).to eq({ + "cpizzaeese_b_c_d_e_f_g_h" => {"cheese_j_k_l_m_n_o_p_q_pizza" => "s-t_u-v_w-X_Y-Z"}, + "pizza" => [1, 2, 3], + }) + expect(hydrated["cpizzaeese_b_c_d_e_f_g_h"]).to eq({"cheese_j_k_l_m_n_o_p_q_pizza" => "s-t_u-v_w-X_Y-Z"}) + expect(hydrated[:cpizzaeese_b_c_d_e_f_g_h]).to eq({"cheese_j_k_l_m_n_o_p_q_pizza" => "s-t_u-v_w-X_Y-Z"}) + expect(hydrated.cpizzaeese_b_c_d_e_f_g_h).to eq({"cheese_j_k_l_m_n_o_p_q_pizza" => "s-t_u-v_w-X_Y-Z"}) + expect(hydrated["pizza"]).to eq([1, 2, 3]) + expect(hydrated[:pizza]).to eq([1, 2, 3]) + expect(hydrated.pizza).to eq([1, 2, 3]) + end + + it "doesn't convert to any special hash class when snaky is false" do + response = described_class.new(@response, parse: :automatic, snaky: false, snaky_hash_klass: custom_hash_class) + expect(response.parsed).to be_a(Hash) + expect(response.parsed).not_to be_a(custom_hash_class) + expect(response.parsed).to eq("a-b_c-d_e-F_G-H" => {"i-j_k-l_m-n_o-P_Q-R" => "s-t_u-v_w-X_Y-Z"}, "arr" => [1, 2, 3]) + expect(response.parsed["a-b_c-d_e-F_G-H"]).to eq({"i-j_k-l_m-n_o-P_Q-R" => "s-t_u-v_w-X_Y-Z"}) + expect(response.parsed["arr"]).to eq([1, 2, 3]) + end + end + end end

    -
    # File 'lib/oauth2/response.rb', line 65
    +      
    # File 'lib/oauth2/response.rb', line 91
     
     def status
       response.status
    @@ -1134,7 +1619,7 @@ 

    diff --git a/doc/OAuth2/Strategy.html b/doc/OAuth2/Strategy.html index e81809eb..89c18b0c 100644 --- a/doc/OAuth2/Strategy.html +++ b/doc/OAuth2/Strategy.html @@ -107,7 +107,7 @@

    Defined Under Namespace

    diff --git a/doc/OAuth2/Strategy/Assertion.html b/doc/OAuth2/Strategy/Assertion.html index 19d57804..92fb4706 100644 --- a/doc/OAuth2/Strategy/Assertion.html +++ b/doc/OAuth2/Strategy/Assertion.html @@ -481,7 +481,7 @@

    diff --git a/doc/OAuth2/Strategy/AuthCode.html b/doc/OAuth2/Strategy/AuthCode.html index dfa7cc0a..6ee779cb 100644 --- a/doc/OAuth2/Strategy/AuthCode.html +++ b/doc/OAuth2/Strategy/AuthCode.html @@ -469,7 +469,7 @@

    diff --git a/doc/OAuth2/Strategy/Base.html b/doc/OAuth2/Strategy/Base.html index c8516ebe..0a6f58ec 100644 --- a/doc/OAuth2/Strategy/Base.html +++ b/doc/OAuth2/Strategy/Base.html @@ -195,7 +195,7 @@

    diff --git a/doc/OAuth2/Strategy/ClientCredentials.html b/doc/OAuth2/Strategy/ClientCredentials.html index 9c19ce0c..4f30bca4 100644 --- a/doc/OAuth2/Strategy/ClientCredentials.html +++ b/doc/OAuth2/Strategy/ClientCredentials.html @@ -343,7 +343,7 @@

    diff --git a/doc/OAuth2/Strategy/Implicit.html b/doc/OAuth2/Strategy/Implicit.html index fd85df31..6d9cd21a 100644 --- a/doc/OAuth2/Strategy/Implicit.html +++ b/doc/OAuth2/Strategy/Implicit.html @@ -410,7 +410,7 @@

    diff --git a/doc/OAuth2/Strategy/Password.html b/doc/OAuth2/Strategy/Password.html index 41751289..37d2d38a 100644 --- a/doc/OAuth2/Strategy/Password.html +++ b/doc/OAuth2/Strategy/Password.html @@ -364,7 +364,7 @@

    diff --git a/doc/OAuth2/Version.html b/doc/OAuth2/Version.html index 7f0f9662..c6cfe405 100644 --- a/doc/OAuth2/Version.html +++ b/doc/OAuth2/Version.html @@ -95,7 +95,7 @@

    VERSION =
    -
    "2.0.10"
    +
    "2.0.11"
    @@ -111,7 +111,7 @@

    diff --git a/doc/_index.html b/doc/_index.html index 6dc6d351..403b6253 100644 --- a/doc/_index.html +++ b/doc/_index.html @@ -300,7 +300,7 @@

    Namespace Listing A-Z

    diff --git a/doc/file.CHANGELOG.html b/doc/file.CHANGELOG.html index 59a898cd..a0c87c0d 100644 --- a/doc/file.CHANGELOG.html +++ b/doc/file.CHANGELOG.html @@ -63,9 +63,27 @@

    The format (since v2) is based on Keep a Changelog v1,
    and this project adheres to Semantic Versioning v2.

    -

    Unreleased

    +

    Unreleased

    Added

    +

    Changed

    +

    Deprecated

    +

    Removed

    +

    Fixed

    +

    Security

    + +

    +2.0.11 - 2025-05-23

      +
    • TAG: v2.0.11 +
    • +
    • COVERAGE: 100.00% – 518/518 lines in 14 files
    • +
    • BRANCH COVERAGE: 100.00% – 172/172 branches in 14 files
    • +
    • 80.00% documented +

      Added

      +
    • +
    • +gh651 - :snaky_hash_klass option (@pboling)
    • +
    • More documentation
    • Codeberg as ethical mirror (@pboling)
      • https://codeberg.org/oauth-xx/oauth2
      • @@ -73,24 +91,34 @@

        Added

      • Don’t check for cert if SKIP_GEM_SIGNING is set (@pboling)
      • All runtime deps, including oauth-xx sibling gems, are now tested against HEAD (@pboling)
      • -
      • YARD config, GFM compatible with relative file links
      • -
      • Documentation site on GitHub Pages +
      • YARD config, GFM compatible with relative file links (@pboling)
      • +
      • Documentation site on GitHub Pages (@pboling)
      • -!649 - Test compatibility with all key minor versions of Hashie v0, v1, v2, v3, v4, v5, HEAD -

        Changed

        +!649 - Test compatibility with all key minor versions of Hashie v0, v1, v2, v3, v4, v5, HEAD (@pboling)
      • +
      • +gh651 - Mock OAuth2 server for testing (@pboling) +
          +
        • https://github.com/navikt/mock-oauth2-server +

          Changed

          +
        • +
      • -
      • Updated spec.homepage_uri in gemspec to GitHub Pages YARD documentation site -

        Deprecated

        -

        Removed

        -

        Fixed

        +
      • +gh651 - Upgraded to snaky_hash v2.0.3 (@pboling) +
          +
        • Provides solution for serialization issues
        • +
      • -
      • Incorrect documentation related to silencing warnings (@pboling) -

        Security

        +
      • Updated spec.homepage_uri in gemspec to GitHub Pages YARD documentation site (@pboling) +

        Fixed

      • +
      • +gh650 - Regression in return type of OAuth2::Response#parsed (@pboling)
      • +
      • Incorrect documentation related to silencing warnings (@pboling)

      @@ -101,7 +129,7 @@

    • COVERAGE: 100.00% – 518/518 lines in 14 files
    • BRANCH COVERAGE: 100.00% – 170/170 branches in 14 files
    • 79.05% documented -

      Added

      +

      Added

    • gh!632 - Added funding.yml (@Aboling0)
    • @@ -144,7 +172,7 @@

      Added

      gh!644, gh!645 - Added CITATION.cff (@Aboling0)
    • !648 - Improved documentation (@pboling) -

      Changed

      +

      Changed

    • Default value of OAuth2.config.silence_extra_tokens_warning was false, now true (@pboling)
    • Gem releases are now cryptographically signed, with a 20-year cert (@pboling) @@ -158,7 +186,7 @@

      Changed

      !647 - OAuth2.config is no longer writable (@pboling)
    • !647 - Errors raised by OAuth2::AccessToken are now always OAuth2::Error and have better metadata (@pboling) -

      Fixed

      +

      Fixed

    • #95 - restoring an access token via AccessToken#from_hash (@pboling) @@ -194,10 +222,10 @@

      2.0.9 - 2022-09-16

      • TAG: v2.0.9 -

        Added

        +

        Added

      • More specs (@pboling) -

        Changed

        +

        Changed

      • Complete migration to main branch as default (@pboling)
      • Complete migration to Gitlab, updating all links, and references in VCS-managed files (@pboling)
      • @@ -207,11 +235,11 @@

        2.0.8 - 2022-09-01

        • TAG: v2.0.8 -

          Changed

          +

          Changed

        • !630 - Extract snaky_hash to external dependency (@pboling) -

          Added

          +

          Added

        • !631 - New global configuration option OAuth2.config.silence_extra_tokens_warning (default: false) fixes #628 @@ -222,11 +250,11 @@

          2.0.7 - 2022-08-22

          • TAG: v2.0.7 -

            Added

            +

            Added

          • !629 - Allow POST of JSON to get token (@pboling, @terracatta) -

            Fixed

            +

            Fixed

          • !626 - Fixes a regression in 2.0.6. Will now prefer the key order from the lookup, not the hash keys (@rickselby) @@ -242,7 +270,7 @@

            2.0.6 - 2022-07-13

            • TAG: v2.0.6 -

              Fixed

              +

              Fixed

            • !624 - Fixes a regression in v2.0.5, where an error would be raised in refresh_token flows due to (legitimate) lack of access_token (@pboling)
            • @@ -252,7 +280,7 @@

              2.0.5 - 2022-07-07

              • TAG: v2.0.5 -

                Fixed

                +

                Fixed

              • !620 - Documentation improvements, to help with upgrading (@swanson)
              • @@ -277,7 +305,7 @@

                2.0.4 - 2022-07-01

                • TAG: v2.0.4 -

                  Fixed

                  +

                  Fixed

                • !618 - In some scenarios the snaky option default value was not applied (@pboling)
                • @@ -287,13 +315,13 @@

                  2.0.3 - 2022-06-28

                  • TAG: v2.0.3 -

                    Added

                    +

                    Added

                  • !611 - Proper deprecation warnings for extract_access_token argument (@pboling)
                  • !612 - Add snaky: false option to skip conversion to OAuth2::SnakyHash (default: true) (@pboling) -

                    Fixed

                    +

                    Fixed

                  • !608 - Wrap Faraday::TimeoutError in OAuth2::TimeoutError (@nbibler)
                  • @@ -305,7 +333,7 @@

                    2.0.2 - 2022-06-24

                    • TAG: v2.0.2 -

                      Fixed

                      +

                      Fixed

                    • !604 - Wrap Faraday::TimeoutError in OAuth2::TimeoutError (@stanhu)
                    • @@ -319,7 +347,7 @@

                      2.0.1 - 2022-06-22

                      • TAG: v2.0.1 -

                        Added

                        +

                        Added

                      • Documentation improvements (@pboling)
                      • Increased test coverage to 99% (@pboling)
                      • @@ -329,7 +357,7 @@

                        2.0.0 - 2022-06-21

                        • TAG: v2.0.0 -

                          Added

                          +

                          Added

                        • !158, !344 - Optionally pass raw response to parsers (@niels)
                        • @@ -383,7 +411,7 @@

                          Added

                          !575 - Support IETF rfc7231, section 7.1.2 - relative location in redirect (@pboling)
                        • !581 - Documentation: of breaking changes (@pboling) -

                          Changed

                          +

                          Changed

                        • !191 - BREAKING: Token is expired if expired_at time is now (@davestevens)
                        • @@ -415,7 +443,7 @@

                          Changed

                          !576 - BREAKING: Stop rescuing parsing errors (@pboling)
                        • !591 - DEPRECATION: OAuth2::Client - :extract_access_token option is deprecated -

                          Fixed

                          +

                          Fixed

                        • !158, !344 - Handling of errors when using omniauth-facebook (@niels)
                        • @@ -689,17 +717,17 @@

                          1.0.0 - 2014-07-09 (tag)

                          -

                          Added

                          +

                          Added

                          • Add an implementation of the MAC token spec. -

                            Fixed

                            +

                            Fixed

                          • Fix Base64.strict_encode64 incompatibility with Ruby 1.8.7.

                          0.5.0 - 2011-07-29 (tag)

                          -

                          Changed

                          +

                          Changed

                          • breaking oauth_token renamed to oauth_bearer.
                          • @@ -773,7 +801,7 @@

                            diff --git a/doc/file.CODE_OF_CONDUCT.html b/doc/file.CODE_OF_CONDUCT.html index 5f7374ba..e6db8c07 100644 --- a/doc/file.CODE_OF_CONDUCT.html +++ b/doc/file.CODE_OF_CONDUCT.html @@ -192,7 +192,7 @@

                            Attribution

                            diff --git a/doc/file.CONTRIBUTING.html b/doc/file.CONTRIBUTING.html index 6e6dd4a3..b8a09a3f 100644 --- a/doc/file.CONTRIBUTING.html +++ b/doc/file.CONTRIBUTING.html @@ -195,7 +195,7 @@

                            To release a new version:

                            diff --git a/doc/file.LICENSE.html b/doc/file.LICENSE.html index 0567285a..dbe4983f 100644 --- a/doc/file.LICENSE.html +++ b/doc/file.LICENSE.html @@ -60,7 +60,7 @@
                            MIT License

                            Copyright (c) 2011 - 2013 Michael Bleigh and Intridea, Inc.
                            Copyright (c) 2017 - 2025 Peter H. Boling, of RailsBling.com, and OAuth2 contributors

                            Permission is hereby granted, free of charge, to any person obtaining a copy
                            of this software and associated documentation files (the "Software"), to deal
                            in the Software without restriction, including without limitation the rights
                            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                            copies of the Software, and to permit persons to whom the Software is
                            furnished to do so, subject to the following conditions:

                            The above copyright notice and this permission notice shall be included in all
                            copies or substantial portions of the Software.

                            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
                            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
                            SOFTWARE.
                            diff --git a/doc/file.README.html b/doc/file.README.html index 2259f860..2354948e 100644 --- a/doc/file.README.html +++ b/doc/file.README.html @@ -68,7 +68,7 @@

                            🔐 OAuth2

                            -

                            Version License: MIT Downloads Rank Open Source Helpers Depfu Coveralls Test Coverage QLTY Test Coverage CI Heads CI Runtime Dependencies @ HEAD CI Current CI Truffle Ruby CI JRuby CI Supported CI Legacy CI Unsupported CI Ancient CI Caboose is an absolute WAGON CI Test Coverage CI Style CodeQL

                            +

                            Version License: MIT Downloads Rank Open Source Helpers Depfu Coveralls Test Coverage QLTY Test Coverage QLTY Maintainability CI Heads CI Runtime Dependencies @ HEAD CI Current CI Truffle Ruby CI JRuby CI Supported CI Legacy CI Unsupported CI Ancient CI Caboose is an absolute WAGON CI Test Coverage CI Style CodeQL


                            @@ -324,7 +324,7 @@

                            💡 Info you can shake a stick at

    Works with MRI Ruby 2 -Ruby 2.3 Compat Ruby 2.4 Compat Ruby 2.5 Compat Ruby 2.6 Compat Ruby 2.7 Compat +Ruby 2.3 Compat Ruby 2.4 Compat Ruby 2.5 Compat Ruby 2.6 Compat Ruby 2.7 Compat
    Works with MRI Ruby 2 -Ruby 2.3 Compat Ruby 2.4 Compat Ruby 2.5 Compat Ruby 2.6 Compat Ruby 2.7 Compat +Ruby 2.3 Compat Ruby 2.4 Compat Ruby 2.5 Compat Ruby 2.6 Compat Ruby 2.7 Compat