From 8d6792a74fd5ac1a3d987948d7b9148062360707 Mon Sep 17 00:00:00 2001 From: Erik Berlin Date: Thu, 10 Aug 2023 07:23:20 -0700 Subject: [PATCH] Update for 2023 --- .github/workflows/main.yml | 29 +++ .gitignore | 17 +- .rubocop.yml | 91 +++++--- CHANGELOG.md | 5 + Gemfile | 27 +-- LICENSE.md | 35 +-- README.md | 50 ++-- Rakefile | 29 +-- bin/console | 10 + bin/setup | 8 + lib/simple_oauth.rb | 3 +- lib/simple_oauth/header.rb | 61 +++-- lib/simple_oauth/version.rb | 3 + simple_oauth.gemspec | 40 +++- spec/helper.rb | 21 +- spec/simple_oauth/header_spec.rb | 385 +++++++++++++++---------------- spec/support/rsa.rb | 2 +- 17 files changed, 423 insertions(+), 393 deletions(-) create mode 100644 .github/workflows/main.yml create mode 100644 CHANGELOG.md create mode 100755 bin/console create mode 100755 bin/setup create mode 100644 lib/simple_oauth/version.rb diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..7520e84 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,29 @@ +name: Ruby + +on: + push: + branches: + - master + + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + name: Ruby ${{ matrix.ruby }} + strategy: + matrix: + ruby: + - "3.0" + - "3.1" + - "3.2" + + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + - name: Run the default task + run: bundle exec rake diff --git a/.gitignore b/.gitignore index 3bc69ed..4ea5798 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,9 @@ -*.rbc -.DS_Store -.bundle -.yardoc +/.bundle/ +/.yardoc +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ Gemfile.lock -coverage -doc -measurement -pkg -rdoc diff --git a/.rubocop.yml b/.rubocop.yml index c8c3cab..49d6982 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,57 +1,72 @@ -Metrics/AbcSize: - Max: 16 +require: + - standard + - standard-performance + - rubocop-rspec + - rubocop-performance + - rubocop-rake -Metrics/BlockNesting: - Max: 1 +AllCops: + NewCops: enable + TargetRubyVersion: 3.0 -Metrics/LineLength: - AllowURI: true +Layout/ArgumentAlignment: + Enabled: true + EnforcedStyle: with_fixed_indentation + +Layout/ArrayAlignment: + Enabled: true + EnforcedStyle: with_fixed_indentation + +Layout/EndAlignment: + Enabled: true + EnforcedStyleAlignWith: variable + +Layout/HashAlignment: + Enabled: true + EnforcedHashRocketStyle: key + EnforcedColonStyle: key + EnforcedLastArgumentHashStyle: always_inspect + +Layout/LineLength: Enabled: false -Metrics/MethodLength: - CountComments: false - Max: 7 +Layout/ParameterAlignment: + Enabled: true + EnforcedStyle: with_fixed_indentation + IndentationWidth: ~ + +Layout/SpaceInsideHashLiteralBraces: + Enabled: false Metrics/ParameterLists: - Max: 4 - CountKeywordArgs: true + CountKeywordArgs: false -Style/AccessModifierIndentation: - EnforcedStyle: outdent - -Style/CollectionMethods: - PreferredMethods: - map: 'collect' - reduce: 'inject' - find: 'detect' - find_all: 'select' - -Style/Documentation: +RSpec/MultipleExpectations: Enabled: false -Style/DotPosition: - EnforcedStyle: trailing - -Style/DoubleNegation: +RSpec/ExampleLength: Enabled: false -Style/EachWithObject: +RSpec/MessageSpies: Enabled: false -Style/Encoding: +RSpec/PendingWithoutReason: Enabled: false -Style/HashSyntax: - EnforcedStyle: hash_rockets - -Style/Lambda: +RSpec/FilePath: Enabled: false -Style/RaiseArgs: - EnforcedStyle: compact +Style/Alias: + Enabled: true + EnforcedStyle: prefer_alias_method -Style/SpaceInsideHashLiteralBraces: - EnforcedStyle: no_space +Style/FrozenStringLiteralComment: + Enabled: false -Style/TrailingComma: - EnforcedStyleForMultiline: 'comma' +Style/StringLiterals: + Enabled: true + EnforcedStyle: double_quotes + +Style/StringLiteralsInInterpolation: + Enabled: true + EnforcedStyle: double_quotes diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..2b2c641 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +## [Unreleased] + +## [0.4.0] - 2023-08-10 + +- Update diff --git a/Gemfile b/Gemfile index 8a27421..4bf4946 100644 --- a/Gemfile +++ b/Gemfile @@ -1,17 +1,14 @@ -source 'https://rubygems.org' - -gem 'jruby-openssl', :platforms => :jruby -gem 'rake' - -group :test do - gem 'backports' - gem 'coveralls' - gem 'mime-types', '~> 1.25', :platforms => [:jruby, :ruby_18] - gem 'rest-client', '~> 1.6.0', :platforms => [:jruby, :ruby_18] - gem 'rspec', '>= 2.14' - gem 'rubocop', '>= 0.28', :platforms => [:ruby_19, :ruby_20, :ruby_21] - gem 'simplecov', '>= 0.9' - gem 'yardstick' -end +source "https://rubygems.org" +# Specify your gem's dependencies in simple_oauth.gemspec gemspec + +gem "rake", ">= 13.0.6" +gem "rspec", ">= 3.12" +gem "rubocop", ">= 1.21" +gem "rubocop-performance", ">= 1.18" +gem "rubocop-rake", ">= 0.6" +gem "rubocop-rspec", ">= 0.31" +gem "simplecov", ">= 0.22" +gem "standard", ">= 1.30.1" +gem "webmock", ">= 3.18.1" diff --git a/LICENSE.md b/LICENSE.md index 1d6d23e..b2431d2 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,20 +1,21 @@ -Copyright (c) 2010-2013 Steve Richert, Erik Michaels-Ober +The MIT License (MIT) -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: +Copyright (c) 2010-2023 Steve Richert, Erik Michaels-Ober -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. +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 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. +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/README.md b/README.md index 9b48b41..d48ee85 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,24 @@ # simple_oauth -[![Gem Version](http://img.shields.io/gem/v/simple_oauth.svg)][gem] -[![Build Status](http://img.shields.io/travis/laserlemon/simple_oauth.svg)][travis] -[![Dependency Status](http://img.shields.io/gemnasium/laserlemon/simple_oauth.svg)][gemnasium] -[![Code Climate](http://img.shields.io/codeclimate/github/laserlemon/simple_oauth.svg)][codeclimate] -[![Coverage Status](http://img.shields.io/coveralls/laserlemon/simple_oauth.svg)][coveralls] - -[gem]: https://rubygems.org/gems/simple_oauth -[travis]: http://travis-ci.org/laserlemon/simple_oauth -[gemnasium]: https://gemnasium.com/laserlemon/simple_oauth -[codeclimate]: https://codeclimate.com/github/laserlemon/simple_oauth -[coveralls]: https://coveralls.io/r/laserlemon/simple_oauth - Simply builds and verifies OAuth headers -## Supported Rubies -This library aims to support and is [tested -against](http://travis-ci.org/laserlemon/simple_oauth) the following Ruby -implementations: +## Installation -* Ruby 1.8.7 -* Ruby 1.9.3 -* Ruby 2.0.0 -* Ruby 2.1 -* [JRuby](http://jruby.org/) -* [Rubinius](http://rubini.us/) +Install the gem and add to the application's Gemfile by executing: -If something doesn't work on one of these interpreters, it's a bug. + $ bundle add simple_oauth -This library may inadvertently work (or seem to work) on other Ruby -implementations, however support will only be provided for the versions listed -above. +If bundler is not being used to manage dependencies, install the gem by executing: -If you would like this library to support another Ruby version, you may -volunteer to be a maintainer. Being a maintainer entails making sure all tests -run and pass on that implementation. When something breaks on your -implementation, you will be responsible for providing patches in a timely -fashion. If critical issues for a particular implementation exist at the time -of a major release, support for that Ruby version may be dropped. + $ gem install simple_oauth -## Copyright -Copyright (c) 2010-2013 Steve Richert, Erik Michaels-Ober. See -[LICENSE](LICENSE.md) for details. + +## Contributing + +Bug reports and pull requests are welcome on GitHub at https://github.com/laserlemon/simple_oauth. + +This project conforms to [Standard Ruby](https://github.com/standardrb/standard). Patches that don’t maintain that standard will not be accepted. + +## License + +The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). diff --git a/Rakefile b/Rakefile index 1d5e9b3..c4938f5 100644 --- a/Rakefile +++ b/Rakefile @@ -1,27 +1,10 @@ -require 'bundler/gem_tasks' -require 'rspec/core/rake_task' +require "bundler/gem_tasks" +require "rspec/core/rake_task" +require "rubocop/rake_task" +require "standard/rake" RSpec::Core::RakeTask.new(:spec) -task :test => :spec +RuboCop::RakeTask.new -begin - require 'rubocop/rake_task' - RuboCop::RakeTask.new -rescue LoadError - task :rubocop do - $stderr.puts 'RuboCop is disabled' - end -end - -require 'yardstick/rake/measurement' -Yardstick::Rake::Measurement.new do |measurement| - measurement.output = 'measurement/report.txt' -end - -require 'yardstick/rake/verify' -Yardstick::Rake::Verify.new do |verify| - verify.threshold = 47 -end - -task :default => [:spec, :rubocop, :verify_measurements] +task default: %i[spec rubocop standard] diff --git a/bin/console b/bin/console new file mode 100755 index 0000000..96342bf --- /dev/null +++ b/bin/console @@ -0,0 +1,10 @@ +#!/usr/bin/env ruby + +require "bundler/setup" +require "simple_oauth" + +# You can add fixtures and/or initialization code here to make experimenting +# with your gem easier. You can also use a different console, if you like. + +require "irb" +IRB.start(__FILE__) diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..dce67d8 --- /dev/null +++ b/bin/setup @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here diff --git a/lib/simple_oauth.rb b/lib/simple_oauth.rb index f2bc580..9db2442 100644 --- a/lib/simple_oauth.rb +++ b/lib/simple_oauth.rb @@ -1 +1,2 @@ -require 'simple_oauth/header' +require_relative "simple_oauth/header" +require_relative "simple_oauth/version" diff --git a/lib/simple_oauth/header.rb b/lib/simple_oauth/header.rb index fdeb4b3..52660a4 100644 --- a/lib/simple_oauth/header.rb +++ b/lib/simple_oauth/header.rb @@ -1,35 +1,36 @@ -require 'openssl' -require 'uri' -require 'base64' -require 'cgi' +require "openssl" +require "uri" +require "base64" +require "cgi" module SimpleOAuth + # Generates OAuth header for HTTP request class Header - ATTRIBUTE_KEYS = [:callback, :consumer_key, :nonce, :signature_method, :timestamp, :token, :verifier, :version] unless defined? ::SimpleOAuth::Header::ATTRIBUTE_KEYS + ATTRIBUTE_KEYS = %i[callback consumer_key nonce signature_method timestamp token verifier version].freeze unless defined? ::SimpleOAuth::Header::ATTRIBUTE_KEYS - IGNORED_KEYS = [:consumer_secret, :token_secret, :signature] unless defined? ::SimpleOAuth::Header::IGNORED_KEYS + IGNORED_KEYS = %i[consumer_secret token_secret signature].freeze unless defined? ::SimpleOAuth::Header::IGNORED_KEYS attr_reader :method, :params, :options class << self def default_options { - :nonce => OpenSSL::Random.random_bytes(16).unpack('H*')[0], - :signature_method => 'HMAC-SHA1', - :timestamp => Time.now.to_i.to_s, - :version => '1.0', + nonce: OpenSSL::Random.random_bytes(16).unpack1("H*"), + signature_method: "HMAC-SHA1", + timestamp: Time.now.to_i.to_s, + version: "1.0" } end def parse(header) - header.to_s.sub(/^OAuth\s/, '').split(/,\s*/).inject({}) do |attributes, pair| - match = pair.match(/^(\w+)\=\"([^\"]*)\"$/) - attributes.merge(match[1].sub(/^oauth_/, '').to_sym => unescape(match[2])) + header.to_s.sub(/^OAuth\s/, "").split(/,\s*/).inject({}) do |attributes, pair| + match = pair.match(/^(\w+)="([^"]*)"$/) + attributes.merge(match[1].sub(/^oauth_/, "").to_sym => unescape(match[2])) end end def escape(value) - uri_parser.escape(value.to_s, /[^a-z0-9\-\.\_\~]/i) + uri_parser.escape(value.to_s, /[^a-z0-9\-._~]/i) end alias_method :encode, :escape @@ -38,10 +39,10 @@ module SimpleOAuth end alias_method :decode, :unescape - private + private def uri_parser - @uri_parser ||= URI.const_defined?(:Parser) ? URI::Parser.new : URI + @uri_parser ||= URI.const_defined?(:Parser) ? URI::DEFAULT_PARSER : URI end end @@ -74,44 +75,42 @@ module SimpleOAuth end def signed_attributes - attributes.merge(:oauth_signature => signature) + attributes.merge(oauth_signature: signature) end - private + private def normalized_attributes - signed_attributes.sort_by { |k, _| k.to_s }.collect { |k, v| %(#{k}="#{self.class.escape(v)}") }.join(', ') + signed_attributes.sort_by { |k, _| k.to_s }.collect { |k, v| %(#{k}="#{self.class.escape(v)}") }.join(", ") end def attributes matching_keys, extra_keys = options.keys.partition { |key| ATTRIBUTE_KEYS.include?(key) } extra_keys -= IGNORED_KEYS - if options[:ignore_extra_keys] || extra_keys.empty? - Hash[options.select { |key, _| matching_keys.include?(key) }.collect { |key, value| [:"oauth_#{key}", value] }] - else - fail "SimpleOAuth: Found extra option keys not matching ATTRIBUTE_KEYS:\n [#{extra_keys.collect(&:inspect).join(', ')}]" - end + raise "SimpleOAuth: Found extra option keys not matching ATTRIBUTE_KEYS:\n [#{extra_keys.collect(&:inspect).join(", ")}]" unless options[:ignore_extra_keys] || extra_keys.empty? + + options.select { |key, _| matching_keys.include?(key) }.transform_keys { |key| :"oauth_#{key}" } end def signature - send(options[:signature_method].downcase.tr('-', '_') + '_signature') + send("#{options[:signature_method].downcase.tr("-", "_")}_signature") end def hmac_sha1_signature - Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, secret, signature_base)).chomp.gsub(/\n/, '') + Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new("SHA1"), secret, signature_base)).chomp.delete("\n") end def secret - options.values_at(:consumer_secret, :token_secret).collect { |v| self.class.escape(v) }.join('&') + options.values_at(:consumer_secret, :token_secret).collect { |v| self.class.escape(v) }.join("&") end alias_method :plaintext_signature, :secret def signature_base - [method, url, normalized_params].collect { |v| self.class.escape(v) }.join('&') + [method, url, normalized_params].collect { |v| self.class.escape(v) }.join("&") end def normalized_params - signature_params.collect { |p| p.collect { |v| self.class.escape(v) } }.sort.collect { |p| p.join('=') }.join('&') + signature_params.collect { |p| p.collect { |v| self.class.escape(v) } }.sort.collect { |p| p.join("=") }.join("&") end def signature_params @@ -119,11 +118,11 @@ module SimpleOAuth end def url_params - CGI.parse(@uri.query || '').inject([]) { |p, (k, vs)| p + vs.sort.collect { |v| [k, v] } } + CGI.parse(@uri.query || "").inject([]) { |p, (k, vs)| p + vs.sort.collect { |v| [k, v] } } end def rsa_sha1_signature - Base64.encode64(private_key.sign(OpenSSL::Digest::SHA1.new, signature_base)).chomp.gsub(/\n/, '') + Base64.encode64(private_key.sign(OpenSSL::Digest.new("SHA1"), signature_base)).chomp.delete("\n") end def private_key diff --git a/lib/simple_oauth/version.rb b/lib/simple_oauth/version.rb new file mode 100644 index 0000000..6d56441 --- /dev/null +++ b/lib/simple_oauth/version.rb @@ -0,0 +1,3 @@ +module SimpleOauth + VERSION = "0.1.0".freeze +end diff --git a/simple_oauth.gemspec b/simple_oauth.gemspec index 970d879..d2175c4 100644 --- a/simple_oauth.gemspec +++ b/simple_oauth.gemspec @@ -1,15 +1,33 @@ +require_relative "lib/simple_oauth/version" + Gem::Specification.new do |spec| - spec.add_development_dependency 'bundler', '~> 1.0' - spec.name = 'simple_oauth' - spec.version = '0.3.1' + spec.name = "simple_oauth" + spec.version = SimpleOauth::VERSION + spec.authors = ["Steve Richert", "Erik Berlin"] + spec.email = ["steve.richert@gmail.com", "sferik@gmail.com"] - spec.authors = ['Steve Richert', 'Erik Michaels-Ober'] - spec.email = %w(steve.richert@gmail.com sferik@gmail.com) - spec.description = 'Simply builds and verifies OAuth headers' - spec.summary = spec.description - spec.homepage = 'https://github.com/laserlemon/simple_oauth' - spec.licenses = %w(MIT) + spec.summary = "Simply builds and verifies OAuth headers" + spec.description = spec.summary + spec.homepage = "https://github.com/laserlemon/simple_oauth" + spec.license = "MIT" + spec.required_ruby_version = ">= 3.0" - spec.files = `git ls-files -z`.split("\x0").reject { |f| f.start_with?('spec/') } - spec.require_paths = %w(lib) + spec.metadata["allowed_push_host"] = "https://rubygems.org" + + spec.metadata["homepage_uri"] = spec.homepage + spec.metadata["source_code_uri"] = "https://github.com/laserlemon/simple_oauth" + spec.metadata["changelog_uri"] = "https://github.com/laserlemon/simple_oauth/blob/master/CHANGELOG.md" + + # Specify which files should be added to the gem when it is released. + # The `git ls-files -z` loads the files in the RubyGem that have been added into git. + spec.files = Dir.chdir(__dir__) do + `git ls-files -z`.split("\x0").reject do |f| + (File.expand_path(f) == __FILE__) || + f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile]) + end + end + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] + spec.metadata["rubygems_mfa_required"] = "true" end diff --git a/spec/helper.rb b/spec/helper.rb index 24aa1f6..e0ae1f4 100644 --- a/spec/helper.rb +++ b/spec/helper.rb @@ -1,20 +1,17 @@ -if RUBY_VERSION >= '1.9' - require 'simplecov' - require 'coveralls' +$LOAD_PATH.unshift File.expand_path("../lib", __dir__) - SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter] +require "simplecov" - SimpleCov.start do - add_filter '/spec/' - minimum_coverage(100) - end +SimpleCov.start do + add_filter "/spec/" + minimum_coverage(100) end -require 'simple_oauth' -require 'rspec' +require "rspec" +require "simple_oauth" def uri_parser - @uri_parser ||= URI.const_defined?(:Parser) ? URI::Parser.new : URI + @uri_parser ||= URI.const_defined?(:Parser) ? URI::DEFAULT_PARSER : URI end RSpec.configure do |config| @@ -23,4 +20,4 @@ RSpec.configure do |config| end end -Dir[File.expand_path('../support/**/*.rb', __FILE__)].each { |f| require f } +Dir[File.expand_path("support/**/*.rb", __dir__)].each { |f| require f } diff --git a/spec/simple_oauth/header_spec.rb b/spec/simple_oauth/header_spec.rb index 5be9cb9..7ac6a0e 100644 --- a/spec/simple_oauth/header_spec.rb +++ b/spec/simple_oauth/header_spec.rb @@ -1,379 +1,364 @@ -# encoding: utf-8 - -require 'helper' +require "helper" describe SimpleOAuth::Header do - describe '.default_options' do - let(:default_options) { SimpleOAuth::Header.default_options } + describe ".default_options" do + let(:default_options) { described_class.default_options } - it 'is different every time' do - expect(SimpleOAuth::Header.default_options).not_to eq default_options + it "is different every time" do + expect(described_class.default_options).not_to eq default_options end - it 'is used for new headers' do - allow(SimpleOAuth::Header).to receive(:default_options).and_return(default_options) - header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json', {}) + it "is used for new headers" do + allow(described_class).to receive(:default_options).and_return(default_options) + header = described_class.new(:get, "https://api.twitter.com/1/statuses/friendships.json", {}) expect(header.options).to eq default_options end - it 'includes a signature method and an OAuth version' do + it "includes a signature method and an OAuth version" do expect(default_options[:signature_method]).not_to be_nil expect(default_options[:version]).not_to be_nil end end - describe '.escape' do - it 'escapes (most) non-word characters' do - [' ', '!', '@', '#', '$', '%', '^', '&'].each do |character| - escaped = SimpleOAuth::Header.escape(character) + describe ".escape" do + it "escapes (most) non-word characters" do + [" ", "!", "@", "#", "$", "%", "^", "&"].each do |character| + escaped = described_class.escape(character) expect(escaped).not_to eq character expect(escaped).to eq uri_parser.escape(character, /.*/) end end - it 'does not escape - . or ~' do - ['-', '.', '~'].each do |character| - escaped = SimpleOAuth::Header.escape(character) + it "does not escape - . or ~" do + ["-", ".", "~"].each do |character| + escaped = described_class.escape(character) expect(escaped).to eq character end end - def self.test_special_characters - it 'escapes non-ASCII characters' do - expect(SimpleOAuth::Header.escape('é')).to eq '%C3%A9' - end - - it 'escapes multibyte characters' do - expect(SimpleOAuth::Header.escape('あ')).to eq '%E3%81%82' - end + it "escapes non-ASCII characters" do + expect(described_class.escape("é")).to eq "%C3%A9" end - if RUBY_VERSION >= '1.9' - test_special_characters - else - %w(n N e E s S u U).each do |kcode| - describe %(when $KCODE = "#{kcode}") do - original_kcode = $KCODE # rubocop:disable GlobalVars - begin - $KCODE = kcode # rubocop:disable GlobalVars - test_special_characters - ensure - $KCODE = original_kcode # rubocop:disable GlobalVars - end - end - end + it "escapes multibyte characters" do + expect(described_class.escape("あ")).to eq "%E3%81%82" end end - describe '.unescape' do + describe ".unescape" do pending end - describe '.parse' do - let(:header) { SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}) } - let(:parsed_options) { SimpleOAuth::Header.parse(header) } + describe ".parse" do + let(:header) { described_class.new(:get, "https://api.twitter.com/1/statuses/friends.json", {}) } + let(:parsed_options) { described_class.parse(header) } - it 'returns a hash' do + it "returns a hash" do expect(parsed_options).to be_a(Hash) end - it 'includes the options used to build the header' do - expect(parsed_options.reject { |k, _| k == :signature }).to eq header.options + it "includes the options used to build the header" do + expect(parsed_options.except(:signature)).to eq header.options end - it 'includes a signature' do + it "includes a signature" do expect(header.options).not_to have_key(:signature) expect(parsed_options).to have_key(:signature) expect(parsed_options[:signature]).not_to be_nil end it "handles optional 'linear white space'" do - parsed_header_with_spaces = SimpleOAuth::Header.parse 'OAuth oauth_consumer_key="abcd", oauth_nonce="oLKtec51GQy", oauth_signature="efgh%26mnop", oauth_signature_method="PLAINTEXT", oauth_timestamp="1286977095", oauth_token="ijkl", oauth_version="1.0"' - expect(parsed_header_with_spaces).to be_a_kind_of(Hash) + parsed_header_with_spaces = described_class.parse 'OAuth oauth_consumer_key="abcd", oauth_nonce="oLKtec51GQy", oauth_signature="efgh%26mnop", oauth_signature_method="PLAINTEXT", oauth_timestamp="1286977095", oauth_token="ijkl", oauth_version="1.0"' + expect(parsed_header_with_spaces).to be_a(Hash) expect(parsed_header_with_spaces.keys.size).to eq 7 - parsed_header_with_tabs = SimpleOAuth::Header.parse 'OAuth oauth_consumer_key="abcd", oauth_nonce="oLKtec51GQy", oauth_signature="efgh%26mnop", oauth_signature_method="PLAINTEXT", oauth_timestamp="1286977095", oauth_token="ijkl", oauth_version="1.0"' - expect(parsed_header_with_tabs).to be_a_kind_of(Hash) + parsed_header_with_tabs = described_class.parse 'OAuth oauth_consumer_key="abcd", oauth_nonce="oLKtec51GQy", oauth_signature="efgh%26mnop", oauth_signature_method="PLAINTEXT", oauth_timestamp="1286977095", oauth_token="ijkl", oauth_version="1.0"' + expect(parsed_header_with_tabs).to be_a(Hash) expect(parsed_header_with_tabs.keys.size).to eq 7 - parsed_header_with_spaces_and_tabs = SimpleOAuth::Header.parse 'OAuth oauth_consumer_key="abcd", oauth_nonce="oLKtec51GQy", oauth_signature="efgh%26mnop", oauth_signature_method="PLAINTEXT", oauth_timestamp="1286977095", oauth_token="ijkl", oauth_version="1.0"' - expect(parsed_header_with_spaces_and_tabs).to be_a_kind_of(Hash) + parsed_header_with_spaces_and_tabs = described_class.parse 'OAuth oauth_consumer_key="abcd", oauth_nonce="oLKtec51GQy", oauth_signature="efgh%26mnop", oauth_signature_method="PLAINTEXT", oauth_timestamp="1286977095", oauth_token="ijkl", oauth_version="1.0"' + expect(parsed_header_with_spaces_and_tabs).to be_a(Hash) expect(parsed_header_with_spaces_and_tabs.keys.size).to eq 7 - parsed_header_without_spaces = SimpleOAuth::Header.parse 'OAuth oauth_consumer_key="abcd",oauth_nonce="oLKtec51GQy",oauth_signature="efgh%26mnop",oauth_signature_method="PLAINTEXT",oauth_timestamp="1286977095",oauth_token="ijkl",oauth_version="1.0"' - expect(parsed_header_without_spaces).to be_a_kind_of(Hash) + parsed_header_without_spaces = described_class.parse 'OAuth oauth_consumer_key="abcd",oauth_nonce="oLKtec51GQy",oauth_signature="efgh%26mnop",oauth_signature_method="PLAINTEXT",oauth_timestamp="1286977095",oauth_token="ijkl",oauth_version="1.0"' + expect(parsed_header_without_spaces).to be_a(Hash) expect(parsed_header_without_spaces.keys.size).to eq 7 end end - describe '#initialize' do - let(:header) { SimpleOAuth::Header.new(:get, 'HTTPS://api.TWITTER.com:443/1/statuses/friendships.json?foo=bar#anchor', {}) } - - it 'stringifies and uppercases the request method' do - expect(header.method).to eq 'GET' + describe "#initialize" do + let(:header) do + described_class.new(:get, "HTTPS://api.TWITTER.com:443/1/statuses/friendships.json?foo=bar#anchor", {}) end - it 'downcases the scheme and authority' do + it "stringifies and uppercases the request method" do + expect(header.method).to eq "GET" + end + + it "downcases the scheme and authority" do expect(header.url).to match %r{^https://api\.twitter\.com/} end - it 'ignores the query and fragment' do + it "ignores the query and fragment" do expect(header.url).to match %r{/1/statuses/friendships\.json$} end end - describe '#valid?' do - context 'using the HMAC-SHA1 signature method' do - it 'requires consumer and token secrets' do - secrets = {:consumer_secret => 'CONSUMER_SECRET', :token_secret => 'TOKEN_SECRET'} - header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, secrets) - parsed_header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, header) + describe "#valid?" do + context "when using the HMAC-SHA1 signature method" do + it "requires consumer and token secrets" do + secrets = {consumer_secret: "CONSUMER_SECRET", token_secret: "TOKEN_SECRET"} + header = described_class.new(:get, "https://api.twitter.com/1/statuses/friends.json", {}, secrets) + parsed_header = described_class.new(:get, "https://api.twitter.com/1/statuses/friends.json", {}, header) expect(parsed_header).not_to be_valid expect(parsed_header).to be_valid(secrets) end end - context 'using the RSA-SHA1 signature method' do - it 'requires an identical private key' do - secrets = {:consumer_secret => rsa_private_key} - header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, secrets.merge(:signature_method => 'RSA-SHA1')) - parsed_header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, header) - expect { parsed_header.valid? }.to raise_error + context "when using the RSA-SHA1 signature method" do + it "requires an identical private key" do + secrets = {consumer_secret: rsa_private_key} + header = described_class.new(:get, "https://api.twitter.com/1/statuses/friends.json", {}, + secrets.merge(signature_method: "RSA-SHA1")) + parsed_header = described_class.new(:get, "https://api.twitter.com/1/statuses/friends.json", {}, header) + expect { parsed_header.valid? }.to raise_error(TypeError) expect(parsed_header).to be_valid(secrets) end end - context 'using the PLAINTEXT signature method' do - it 'requires consumer and token secrets' do - secrets = {:consumer_secret => 'CONSUMER_SECRET', :token_secret => 'TOKEN_SECRET'} - header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, secrets.merge(:signature_method => 'PLAINTEXT')) - parsed_header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, header) + context "when using the PLAINTEXT signature method" do + it "requires consumer and token secrets" do + secrets = {consumer_secret: "CONSUMER_SECRET", token_secret: "TOKEN_SECRET"} + header = described_class.new(:get, "https://api.twitter.com/1/statuses/friends.json", {}, + secrets.merge(signature_method: "PLAINTEXT")) + parsed_header = described_class.new(:get, "https://api.twitter.com/1/statuses/friends.json", {}, header) expect(parsed_header).not_to be_valid expect(parsed_header).to be_valid(secrets) end end end - describe '#normalized_attributes' do - let(:header) { SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}) } + describe "#normalized_attributes" do + let(:header) { described_class.new(:get, "https://api.twitter.com/1/statuses/friends.json", {}) } let(:normalized_attributes) { header.send(:normalized_attributes) } - it 'returns a sorted-key, quoted-value and comma-separated list' do - allow(header).to receive(:signed_attributes).and_return(:d => 1, :c => 2, :b => 3, :a => 4) + it "returns a sorted-key, quoted-value and comma-separated list" do + allow(header).to receive(:signed_attributes).and_return(d: 1, c: 2, b: 3, a: 4) expect(normalized_attributes).to eq 'a="4", b="3", c="2", d="1"' end - it 'URI encodes its values' do - allow(header).to receive(:signed_attributes).and_return(1 => '!', 2 => '@', 3 => '#', 4 => '$') + it "URI encodes its values" do + allow(header).to receive(:signed_attributes).and_return(1 => "!", 2 => "@", 3 => "#", 4 => "$") expect(normalized_attributes).to eq '1="%21", 2="%40", 3="%23", 4="%24"' end end - describe '#signed_attributes' do - it 'includes the OAuth signature' do - header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}) + describe "#signed_attributes" do + it "includes the OAuth signature" do + header = described_class.new(:get, "https://api.twitter.com/1/statuses/friends.json", {}) expect(header.send(:signed_attributes)).to have_key(:oauth_signature) end end - describe '#attributes' do + describe "#attributes" do let(:header) do options = {} SimpleOAuth::Header::ATTRIBUTE_KEYS.each { |k| options[k] = k.to_s.upcase } - options[:other] = 'OTHER' - SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json', {}, options) + options[:other] = "OTHER" + described_class.new(:get, "https://api.twitter.com/1/statuses/friendships.json", {}, options) end it "prepends keys with 'oauth_'" do header.options[:ignore_extra_keys] = true - expect(header.send(:attributes).keys).to be_all { |k| k.to_s =~ /^oauth_/ } + expect(header.send(:attributes).keys).to(be_all { |k| k.to_s =~ /^oauth_/ }) end - it 'excludes keys not included in the list of valid attributes' do + it "excludes keys not included in the list of valid attributes" do header.options[:ignore_extra_keys] = true - expect(header.send(:attributes).keys).to be_all { |k| k.is_a?(Symbol) } + expect(header.send(:attributes).keys).to(be_all { |k| k.is_a?(Symbol) }) expect(header.send(:attributes)).not_to have_key(:oauth_other) end - it 'preserves values for valid keys' do + it "preserves values for valid keys" do header.options[:ignore_extra_keys] = true expect(header.send(:attributes).size).to eq SimpleOAuth::Header::ATTRIBUTE_KEYS.size - expect(header.send(:attributes)).to be_all { |k, v| k.to_s == "oauth_#{v.downcase}" } + expect(header.send(:attributes)).to(be_all { |k, v| k.to_s == "oauth_#{v.downcase}" }) end - it 'raises exception for extra keys' do - expect { header.send(:attributes) }.to raise_error(RuntimeError, "SimpleOAuth: Found extra option keys not matching ATTRIBUTE_KEYS:\n [:other]") + it "raises exception for extra keys" do + expect do + header.send(:attributes) + end.to raise_error(RuntimeError, + "SimpleOAuth: Found extra option keys not matching ATTRIBUTE_KEYS:\n [:other]") end end - describe '#signature' do - context 'calls the appropriate signature method' do - specify 'when using HMAC-SHA1' do - header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, :signature_method => 'HMAC-SHA1') - expect(header).to receive(:hmac_sha1_signature).once.and_return('HMAC_SHA1_SIGNATURE') - expect(header.send(:signature)).to eq 'HMAC_SHA1_SIGNATURE' - end + describe "#signature" do + specify "when using HMAC-SHA1" do + header = described_class.new(:get, "https://api.twitter.com/1/statuses/friends.json", {}, signature_method: "HMAC-SHA1") + expect(header).to receive(:hmac_sha1_signature).once.and_return("HMAC_SHA1_SIGNATURE") + expect(header.send(:signature)).to eq "HMAC_SHA1_SIGNATURE" + end - specify 'when using RSA-SHA1' do - header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, :signature_method => 'RSA-SHA1') - expect(header).to receive(:rsa_sha1_signature).once.and_return('RSA_SHA1_SIGNATURE') - expect(header.send(:signature)).to eq 'RSA_SHA1_SIGNATURE' - end + specify "when using RSA-SHA1" do + header = described_class.new(:get, "https://api.twitter.com/1/statuses/friends.json", {}, signature_method: "RSA-SHA1") + expect(header).to receive(:rsa_sha1_signature).once.and_return("RSA_SHA1_SIGNATURE") + expect(header.send(:signature)).to eq "RSA_SHA1_SIGNATURE" + end - specify 'when using PLAINTEXT' do - header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, :signature_method => 'PLAINTEXT') - expect(header).to receive(:plaintext_signature).once.and_return('PLAINTEXT_SIGNATURE') - expect(header.send(:signature)).to eq 'PLAINTEXT_SIGNATURE' - end + specify "when using PLAINTEXT" do + header = described_class.new(:get, "https://api.twitter.com/1/statuses/friends.json", {}, signature_method: "PLAINTEXT") + expect(header).to receive(:plaintext_signature).once.and_return("PLAINTEXT_SIGNATURE") + expect(header.send(:signature)).to eq "PLAINTEXT_SIGNATURE" end end - describe '#hmac_sha1_signature' do - it 'reproduces a successful Twitter GET' do + describe "#hmac_sha1_signature" do + it "reproduces a successful Twitter GET" do options = { - :consumer_key => '8karQBlMg6gFOwcf8kcoYw', - :consumer_secret => '3d0vcHyUiiqADpWxolW8nlDIpSWMlyK7YNgc5Qna2M', - :nonce => '547fed103e122eecf84c080843eedfe6', - :signature_method => 'HMAC-SHA1', - :timestamp => '1286830180', - :token => '201425800-Sv4sTcgoffmHGkTCue0JnURT8vrm4DiFAkeFNDkh', - :token_secret => 'T5qa1tF57tfDzKmpM89DHsNuhgOY4NT6DlNLsTFcuQ', + consumer_key: "8karQBlMg6gFOwcf8kcoYw", + consumer_secret: "3d0vcHyUiiqADpWxolW8nlDIpSWMlyK7YNgc5Qna2M", + nonce: "547fed103e122eecf84c080843eedfe6", + signature_method: "HMAC-SHA1", + timestamp: "1286830180", + token: "201425800-Sv4sTcgoffmHGkTCue0JnURT8vrm4DiFAkeFNDkh", + token_secret: "T5qa1tF57tfDzKmpM89DHsNuhgOY4NT6DlNLsTFcuQ" } - header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friends.json', {}, options) + header = described_class.new(:get, "https://api.twitter.com/1/statuses/friends.json", {}, options) expect(header.to_s).to eq 'OAuth oauth_consumer_key="8karQBlMg6gFOwcf8kcoYw", oauth_nonce="547fed103e122eecf84c080843eedfe6", oauth_signature="i9CT6ahDRAlfGX3hKYf78QzXsaw%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1286830180", oauth_token="201425800-Sv4sTcgoffmHGkTCue0JnURT8vrm4DiFAkeFNDkh", oauth_version="1.0"' end - it 'reproduces a successful Twitter POST' do + it "reproduces a successful Twitter POST" do options = { - :consumer_key => '8karQBlMg6gFOwcf8kcoYw', - :consumer_secret => '3d0vcHyUiiqADpWxolW8nlDIpSWMlyK7YNgc5Qna2M', - :nonce => 'b40a3e0f18590ecdcc0e273f7d7c82f8', - :signature_method => 'HMAC-SHA1', - :timestamp => '1286830181', - :token => '201425800-Sv4sTcgoffmHGkTCue0JnURT8vrm4DiFAkeFNDkh', - :token_secret => 'T5qa1tF57tfDzKmpM89DHsNuhgOY4NT6DlNLsTFcuQ', + consumer_key: "8karQBlMg6gFOwcf8kcoYw", + consumer_secret: "3d0vcHyUiiqADpWxolW8nlDIpSWMlyK7YNgc5Qna2M", + nonce: "b40a3e0f18590ecdcc0e273f7d7c82f8", + signature_method: "HMAC-SHA1", + timestamp: "1286830181", + token: "201425800-Sv4sTcgoffmHGkTCue0JnURT8vrm4DiFAkeFNDkh", + token_secret: "T5qa1tF57tfDzKmpM89DHsNuhgOY4NT6DlNLsTFcuQ" } - header = SimpleOAuth::Header.new(:post, 'https://api.twitter.com/1/statuses/update.json', {:status => 'hi, again'}, options) + header = described_class.new(:post, "https://api.twitter.com/1/statuses/update.json", + {status: "hi, again"}, options) expect(header.to_s).to eq 'OAuth oauth_consumer_key="8karQBlMg6gFOwcf8kcoYw", oauth_nonce="b40a3e0f18590ecdcc0e273f7d7c82f8", oauth_signature="mPqSFKejrWWk3ZT9bTQjhO5b2xI%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1286830181", oauth_token="201425800-Sv4sTcgoffmHGkTCue0JnURT8vrm4DiFAkeFNDkh", oauth_version="1.0"' end end - describe '#secret' do - let(:header) { SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json', {}) } + describe "#secret" do + let(:header) { described_class.new(:get, "https://api.twitter.com/1/statuses/friendships.json", {}) } let(:secret) { header.send(:secret) } - it 'combines the consumer and token secrets with an ampersand' do - allow(header).to receive(:options).and_return(:consumer_secret => 'CONSUMER_SECRET', :token_secret => 'TOKEN_SECRET') - expect(secret).to eq 'CONSUMER_SECRET&TOKEN_SECRET' + it "combines the consumer and token secrets with an ampersand" do + allow(header).to receive(:options).and_return(consumer_secret: "CONSUMER_SECRET", + token_secret: "TOKEN_SECRET") + expect(secret).to eq "CONSUMER_SECRET&TOKEN_SECRET" end - it 'URI encodes each secret value before combination' do - allow(header).to receive(:options).and_return(:consumer_secret => 'CONSUM#R_SECRET', :token_secret => 'TOKEN_S#CRET') - expect(secret).to eq 'CONSUM%23R_SECRET&TOKEN_S%23CRET' + it "URI encodes each secret value before combination" do + allow(header).to receive(:options).and_return(consumer_secret: "CONSUM#R_SECRET", + token_secret: "TOKEN_S#CRET") + expect(secret).to eq "CONSUM%23R_SECRET&TOKEN_S%23CRET" end end - describe '#signature_base' do - let(:header) { SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json', {}) } + describe "#signature_base" do + let(:header) { described_class.new(:get, "https://api.twitter.com/1/statuses/friendships.json", {}) } let(:signature_base) { header.send(:signature_base) } - it 'combines the request method, URL and normalized parameters using ampersands' do - allow(header).to receive(:method).and_return('METHOD') - allow(header).to receive(:url).and_return('URL') - allow(header).to receive(:normalized_params).and_return('NORMALIZED_PARAMS') - expect(signature_base).to eq 'METHOD&URL&NORMALIZED_PARAMS' + it "combines the request method, URL and normalized parameters using ampersands" do + allow(header).to receive_messages(method: "METHOD", url: "URL", normalized_params: "NORMALIZED_PARAMS") + expect(signature_base).to eq "METHOD&URL&NORMALIZED_PARAMS" end - it 'URI encodes each value before combination' do - allow(header).to receive(:method).and_return('ME#HOD') - allow(header).to receive(:url).and_return('U#L') - allow(header).to receive(:normalized_params).and_return('NORMAL#ZED_PARAMS') - expect(signature_base).to eq 'ME%23HOD&U%23L&NORMAL%23ZED_PARAMS' + it "URI encodes each value before combination" do + allow(header).to receive_messages(method: "ME#HOD", url: "U#L", normalized_params: "NORMAL#ZED_PARAMS") + expect(signature_base).to eq "ME%23HOD&U%23L&NORMAL%23ZED_PARAMS" end end - describe '#normalized_params' do + describe "#normalized_params" do let(:header) do - header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json', {}) - allow(header).to receive(:signature_params).and_return([%w(A 4), %w(B 3), %w(B 2), %w(C 1), ['D[]', '0 ']]) + header = described_class.new(:get, "https://api.twitter.com/1/statuses/friendships.json", {}) + allow(header).to receive(:signature_params).and_return([%w[A 4], %w[B 3], %w[B 2], %w[C 1], ["D[]", "0 "]]) header end let(:signature_params) { header.send(:signature_params) } let(:normalized_params) { header.send(:normalized_params) } - it 'joins key/value pairs with equal signs and ampersands' do + it "joins key/value pairs with equal signs and ampersands" do expect(normalized_params).to be_a(String) - parts = normalized_params.split('&') + parts = normalized_params.split("&") expect(parts.size).to eq signature_params.size - pairs = parts.collect { |p| p.split('=') } - expect(pairs).to be_all { |p| p.size == 2 } + pairs = parts.collect { |p| p.split("=") } + expect(pairs).to(be_all { |p| p.size == 2 }) end end - describe '#signature_params' do - let(:header) { SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json', {}) } + describe "#signature_params" do + let(:header) { described_class.new(:get, "https://api.twitter.com/1/statuses/friendships.json", {}) } let(:signature_params) { header.send(:signature_params) } - it 'combines OAuth header attributes, body parameters and URL parameters into an flattened array of key/value pairs' do - allow(header).to receive(:attributes).and_return(:attribute => 'ATTRIBUTE') - allow(header).to receive(:params).and_return('param' => 'PARAM') - allow(header).to receive(:url_params).and_return([%w(url_param 1), %w(url_param 2)]) + it "combines OAuth header attributes, body parameters and URL parameters into an flattened array of key/value pairs" do + allow(header).to receive_messages(attributes: {attribute: "ATTRIBUTE"}, params: {"param" => "PARAM"}, + url_params: [%w[url_param 1], %w[url_param 2]]) expect(signature_params).to eq [ - [:attribute, 'ATTRIBUTE'], - %w(param PARAM), - %w(url_param 1), - %w(url_param 2), + [:attribute, "ATTRIBUTE"], + %w[param PARAM], + %w[url_param 1], + %w[url_param 2] ] end end - describe '#url_params' do - it 'returns an empty array when the URL has no query parameters' do - header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json', {}) + describe "#url_params" do + it "returns an empty array when the URL has no query parameters" do + header = described_class.new(:get, "https://api.twitter.com/1/statuses/friendships.json", {}) expect(header.send(:url_params)).to eq [] end - it 'returns an array of key/value pairs for each query parameter' do - header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json?test=TEST', {}) - expect(header.send(:url_params)).to eq [%w(test TEST)] + it "returns an array of key/value pairs for each query parameter" do + header = described_class.new(:get, "https://api.twitter.com/1/statuses/friendships.json?test=TEST", {}) + expect(header.send(:url_params)).to eq [%w[test TEST]] end - it 'sorts values for repeated keys' do - header = SimpleOAuth::Header.new(:get, 'https://api.twitter.com/1/statuses/friendships.json?test=3&test=1&test=2', {}) - expect(header.send(:url_params)).to eq [%w(test 1), %w(test 2), %w(test 3)] + it "sorts values for repeated keys" do + header = described_class.new(:get, + "https://api.twitter.com/1/statuses/friendships.json?test=3&test=1&test=2", {}) + expect(header.send(:url_params)).to eq [%w[test 1], %w[test 2], %w[test 3]] end end - describe '#rsa_sha1_signature' do - it 'reproduces a successful OAuth example GET' do + describe "#rsa_sha1_signature" do + it "reproduces a successful OAuth example GET" do options = { - :consumer_key => 'dpf43f3p2l4k3l03', - :consumer_secret => rsa_private_key, - :nonce => '13917289812797014437', - :signature_method => 'RSA-SHA1', - :timestamp => '1196666512', + consumer_key: "dpf43f3p2l4k3l03", + consumer_secret: rsa_private_key, + nonce: "13917289812797014437", + signature_method: "RSA-SHA1", + timestamp: "1196666512" } - header = SimpleOAuth::Header.new(:get, 'http://photos.example.net/photos', {:file => 'vacaction.jpg', :size => 'original'}, options) + header = described_class.new(:get, "http://photos.example.net/photos", + {file: "vacaction.jpg", size: "original"}, options) expect(header.to_s).to eq 'OAuth oauth_consumer_key="dpf43f3p2l4k3l03", oauth_nonce="13917289812797014437", oauth_signature="jvTp%2FwX1TYtByB1m%2BPbyo0lnCOLIsyGCH7wke8AUs3BpnwZJtAuEJkvQL2%2F9n4s5wUmUl4aCI4BwpraNx4RtEXMe5qg5T1LVTGliMRpKasKsW%2F%2Fe%2BRinhejgCuzoH26dyF8iY2ZZ%2F5D1ilgeijhV%2FvBka5twt399mXwaYdCwFYE%3D", oauth_signature_method="RSA-SHA1", oauth_timestamp="1196666512", oauth_version="1.0"' end end - describe '#private_key' do + describe "#private_key" do pending end - describe '#plaintext_signature' do - it 'reproduces a successful OAuth example GET' do + describe "#plaintext_signature" do + it "reproduces a successful OAuth example GET" do options = { - :consumer_key => 'abcd', - :consumer_secret => 'efgh', - :nonce => 'oLKtec51GQy', - :signature_method => 'PLAINTEXT', - :timestamp => '1286977095', - :token => 'ijkl', - :token_secret => 'mnop', + consumer_key: "abcd", + consumer_secret: "efgh", + nonce: "oLKtec51GQy", + signature_method: "PLAINTEXT", + timestamp: "1286977095", + token: "ijkl", + token_secret: "mnop" } - header = SimpleOAuth::Header.new(:get, 'http://host.net/resource?name=value', {:name => 'value'}, options) + header = described_class.new(:get, "http://host.net/resource?name=value", {name: "value"}, options) expect(header.to_s).to eq 'OAuth oauth_consumer_key="abcd", oauth_nonce="oLKtec51GQy", oauth_signature="efgh%26mnop", oauth_signature_method="PLAINTEXT", oauth_timestamp="1286977095", oauth_token="ijkl", oauth_version="1.0"' end end diff --git a/spec/support/rsa.rb b/spec/support/rsa.rb index 0d3f116..9bdf388 100644 --- a/spec/support/rsa.rb +++ b/spec/support/rsa.rb @@ -1,5 +1,5 @@ module RSAHelpers - PRIVATE_KEY_PATH = File.expand_path('../fixtures/rsa-private-key', __FILE__) + PRIVATE_KEY_PATH = File.expand_path("fixtures/rsa-private-key", __dir__) def rsa_private_key @rsa_private_key ||= File.read(PRIVATE_KEY_PATH)