mirror of
				https://github.com/omniauth/omniauth.git
				synced 2022-11-09 12:31:49 -05:00 
			
		
		
		
	Merge branch 'master' of github.com:omniauth/omniauth into ensure-info-is-hash
This commit is contained in:
		
						commit
						40d8bd35bf
					
				
					 24 changed files with 305 additions and 153 deletions
				
			
		
							
								
								
									
										20
									
								
								.github/ISSUE_TEMPLATE.md
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								.github/ISSUE_TEMPLATE.md
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					Please complete all sections.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Configuration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Provider Gem: `omniauth-*`
 | 
				
			||||||
 | 
					- Ruby Version: ``
 | 
				
			||||||
 | 
					- Framework: ``
 | 
				
			||||||
 | 
					- Platform: ``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Expected Behavior
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tell us what should happen.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Actual Behavior
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tell us what happens instead.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Steps to Reproduce
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Please list all steps to reproduce the issue.
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,9 @@
 | 
				
			||||||
Lint/HandleExceptions:
 | 
					Lint/HandleExceptions:
 | 
				
			||||||
  Enabled: false
 | 
					  Enabled: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Metrics/BlockLength:
 | 
				
			||||||
 | 
					  Enabled: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Metrics/BlockNesting:
 | 
					Metrics/BlockNesting:
 | 
				
			||||||
  Max: 2
 | 
					  Max: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										22
									
								
								.travis.yml
									
										
									
									
									
								
							
							
						
						
									
										22
									
								
								.travis.yml
									
										
									
									
									
								
							| 
						 | 
					@ -1,33 +1,21 @@
 | 
				
			||||||
bundler_args: --without development
 | 
					bundler_args: --without development
 | 
				
			||||||
before_install: gem install bundler
 | 
					before_install: gem update bundler
 | 
				
			||||||
cache: bundler
 | 
					cache: bundler
 | 
				
			||||||
env:
 | 
					env:
 | 
				
			||||||
  global:
 | 
					  global:
 | 
				
			||||||
    - JRUBY_OPTS="$JRUBY_OPTS --debug"
 | 
					    - JRUBY_OPTS="$JRUBY_OPTS --debug"
 | 
				
			||||||
gemfile:
 | 
					 | 
				
			||||||
  - Gemfile
 | 
					 | 
				
			||||||
  - Gemfile.rack-1.3.x
 | 
					 | 
				
			||||||
language: ruby
 | 
					language: ruby
 | 
				
			||||||
rvm:
 | 
					rvm:
 | 
				
			||||||
  - jruby-18mode
 | 
					 | 
				
			||||||
  - jruby-19mode
 | 
					 | 
				
			||||||
  - jruby-9000
 | 
					  - jruby-9000
 | 
				
			||||||
  - 1.8.7
 | 
					  - 2.1.10 # EOL Soon
 | 
				
			||||||
  - 1.9.3
 | 
					  - 2.2.6
 | 
				
			||||||
  - 2.0.0
 | 
					  - 2.3.3
 | 
				
			||||||
  - 2.1
 | 
					  - 2.4.0
 | 
				
			||||||
  - 2.2
 | 
					 | 
				
			||||||
  - jruby-head
 | 
					  - jruby-head
 | 
				
			||||||
  - rbx-2
 | 
					 | 
				
			||||||
  - ruby-head
 | 
					  - ruby-head
 | 
				
			||||||
matrix:
 | 
					matrix:
 | 
				
			||||||
  include:
 | 
					 | 
				
			||||||
    - rvm: 2.2.2
 | 
					 | 
				
			||||||
      gemfile: Gemfile.rack-master
 | 
					 | 
				
			||||||
  allow_failures:
 | 
					  allow_failures:
 | 
				
			||||||
    - rvm: jruby-head
 | 
					    - rvm: jruby-head
 | 
				
			||||||
    - rvm: rbx-2
 | 
					 | 
				
			||||||
    - rvm: ruby-head
 | 
					    - rvm: ruby-head
 | 
				
			||||||
    - gemfile: Gemfile.rack-master
 | 
					 | 
				
			||||||
  fast_finish: true
 | 
					  fast_finish: true
 | 
				
			||||||
sudo: false
 | 
					sudo: false
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										25
									
								
								Gemfile
									
										
									
									
									
								
							
							
						
						
									
										25
									
								
								Gemfile
									
										
									
									
									
								
							| 
						 | 
					@ -1,24 +1,27 @@
 | 
				
			||||||
source 'https://rubygems.org'
 | 
					source 'https://rubygems.org'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
gem 'jruby-openssl', :platforms => :jruby
 | 
					gem 'jruby-openssl', '~> 0.9.19', :platforms => :jruby
 | 
				
			||||||
gem 'rake'
 | 
					gem 'rake', '>= 12.0'
 | 
				
			||||||
gem 'yard'
 | 
					gem 'yard', '>= 0.9'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
group :development do
 | 
					group :development do
 | 
				
			||||||
 | 
					  gem 'benchmark-ips'
 | 
				
			||||||
  gem 'kramdown'
 | 
					  gem 'kramdown'
 | 
				
			||||||
 | 
					  gem 'memory_profiler'
 | 
				
			||||||
  gem 'pry'
 | 
					  gem 'pry'
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
group :test do
 | 
					group :test do
 | 
				
			||||||
  gem 'coveralls'
 | 
					  gem 'hashie', '~> 3.5.0', :platforms => [:jruby_18]
 | 
				
			||||||
  gem 'hashie', '~> 2.0.5', :platforms => [:jruby_18, :ruby_18]
 | 
					  gem 'json', '~> 2.0.3', :platforms => [:jruby_18, :jruby_19, :ruby_19]
 | 
				
			||||||
  gem 'json', '>= 1.8.1', :platforms => [:jruby_18, :jruby_19, :ruby_18, :ruby_19]
 | 
					  gem 'mime-types', '~> 3.1', :platforms => [:jruby_18]
 | 
				
			||||||
  gem 'mime-types', '~> 1.25', :platforms => [:jruby_18, :ruby_18]
 | 
					  gem 'rack', '>= 1.6.2', :platforms => [:jruby_18, :jruby_19, :ruby_19, :ruby_20, :ruby_21]
 | 
				
			||||||
  gem 'rack-test'
 | 
					  gem 'rack-test'
 | 
				
			||||||
  gem 'rest-client', '~> 1.6.0', :platforms => [:jruby_18, :ruby_18]
 | 
					  gem 'rest-client', '~> 2.0.0', :platforms => [:jruby_18]
 | 
				
			||||||
  gem 'rspec', '~> 3.0'
 | 
					  gem 'rspec', '~> 3.5.0'
 | 
				
			||||||
  gem 'rubocop', '>= 0.25', :platforms => [:ruby_19, :ruby_20, :ruby_21, :ruby_22]
 | 
					  gem 'rubocop', '>= 0.47', :platforms => [:ruby_20, :ruby_21, :ruby_22, :ruby_23, :ruby_24]
 | 
				
			||||||
  gem 'simplecov', '>= 0.9'
 | 
					  gem 'simplecov', '>= 0.13'
 | 
				
			||||||
 | 
					  gem 'tins', '~> 1.13.0', :platforms => [:jruby_18, :jruby_19, :ruby_19]
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
gemspec
 | 
					gemspec
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,20 +0,0 @@
 | 
				
			||||||
source 'https://rubygems.org'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
gem 'jruby-openssl', :platforms => :jruby
 | 
					 | 
				
			||||||
gem 'rack', '~> 1.3.0'
 | 
					 | 
				
			||||||
gem 'rake'
 | 
					 | 
				
			||||||
gem 'yard'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
group :test do
 | 
					 | 
				
			||||||
  gem 'coveralls'
 | 
					 | 
				
			||||||
  gem 'hashie', '~> 2.0.5', :platforms => [:jruby_18, :ruby_18]
 | 
					 | 
				
			||||||
  gem 'json', '>= 1.8.1', :platforms => [:jruby_18, :jruby_18, :ruby_18, :ruby_19]
 | 
					 | 
				
			||||||
  gem 'mime-types', '~> 1.25', :platforms => [:jruby_18, :ruby_18]
 | 
					 | 
				
			||||||
  gem 'rack-test'
 | 
					 | 
				
			||||||
  gem 'rest-client', '~> 1.6.0', :platforms => [:jruby_18, :ruby_18]
 | 
					 | 
				
			||||||
  gem 'rspec', '~> 3.0'
 | 
					 | 
				
			||||||
  gem 'rubocop', '>= 0.25', :platforms => [:ruby_19, :ruby_20, :ruby_21]
 | 
					 | 
				
			||||||
  gem 'simplecov', '>= 0.9'
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
gemspec
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,16 +0,0 @@
 | 
				
			||||||
source 'https://rubygems.org'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
gem 'jruby-openssl', :platforms => :jruby
 | 
					 | 
				
			||||||
gem 'rack', :git => 'https://github.com/rack/rack.git'
 | 
					 | 
				
			||||||
gem 'rake'
 | 
					 | 
				
			||||||
gem 'yard'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
group :test do
 | 
					 | 
				
			||||||
  gem 'coveralls'
 | 
					 | 
				
			||||||
  gem 'rack-test'
 | 
					 | 
				
			||||||
  gem 'rspec', '~> 3.0'
 | 
					 | 
				
			||||||
  gem 'rubocop', '>= 0.25'
 | 
					 | 
				
			||||||
  gem 'simplecov', '>= 0.9'
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
gemspec
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
Copyright (c) 2010-2013 Michael Bleigh and Intridea, Inc.
 | 
					Copyright (c) 2010-2017 Michael Bleigh and Intridea, Inc.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
of this software and associated documentation files (the "Software"), to deal
 | 
					of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										35
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										35
									
								
								README.md
									
										
									
									
									
								
							| 
						 | 
					@ -1,22 +1,17 @@
 | 
				
			||||||
# OmniAuth: Standardized Multi-Provider Authentication
 | 
					# OmniAuth: Standardized Multi-Provider Authentication
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[][gem]
 | 
					[][gem]
 | 
				
			||||||
[][travis]
 | 
					[][travis]
 | 
				
			||||||
[][gemnasium]
 | 
					[][gemnasium]
 | 
				
			||||||
[][codeclimate]
 | 
					[][codeclimate]
 | 
				
			||||||
[][coveralls]
 | 
					[][coveralls]
 | 
				
			||||||
[](https://bitdeli.com/free "Bitdeli Badge")
 | 
					[](https://hakiri.io/github/omniauth/omniauth/master)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[gem]: https://rubygems.org/gems/omniauth
 | 
					[gem]: https://rubygems.org/gems/omniauth
 | 
				
			||||||
[travis]: http://travis-ci.org/intridea/omniauth
 | 
					[travis]: http://travis-ci.org/omniauth/omniauth
 | 
				
			||||||
[gemnasium]: https://gemnasium.com/intridea/omniauth
 | 
					[gemnasium]: https://gemnasium.com/omniauth/omniauth
 | 
				
			||||||
[codeclimate]: https://codeclimate.com/github/intridea/omniauth
 | 
					[codeclimate]: https://codeclimate.com/github/omniauth/omniauth
 | 
				
			||||||
[coveralls]: https://coveralls.io/r/intridea/omniauth
 | 
					[coveralls]: https://coveralls.io/r/omniauth/omniauth
 | 
				
			||||||
 | 
					 | 
				
			||||||
**OmniAuth 1.0 has several breaking changes from version 0.x. You can set
 | 
					 | 
				
			||||||
the dependency to `~> 0.3.2` if you do not wish to make the more difficult
 | 
					 | 
				
			||||||
upgrade. See [the wiki](https://github.com/intridea/omniauth/wiki/Upgrading-to-1.0)
 | 
					 | 
				
			||||||
for more information.**
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
## An Introduction
 | 
					## An Introduction
 | 
				
			||||||
OmniAuth is a library that standardizes multi-provider authentication for
 | 
					OmniAuth is a library that standardizes multi-provider authentication for
 | 
				
			||||||
| 
						 | 
					@ -27,7 +22,7 @@ have been created for everything from Facebook to LDAP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
In order to use OmniAuth in your applications, you will need to leverage
 | 
					In order to use OmniAuth in your applications, you will need to leverage
 | 
				
			||||||
one or more strategies. These strategies are generally released
 | 
					one or more strategies. These strategies are generally released
 | 
				
			||||||
individually as RubyGems, and you can see a [community maintained list](https://github.com/intridea/omniauth/wiki/List-of-Strategies)
 | 
					individually as RubyGems, and you can see a [community maintained list](https://github.com/omniauth/omniauth/wiki/List-of-Strategies)
 | 
				
			||||||
on the wiki for this project.
 | 
					on the wiki for this project.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
One strategy, called `Developer`, is included with OmniAuth and provides
 | 
					One strategy, called `Developer`, is included with OmniAuth and provides
 | 
				
			||||||
| 
						 | 
					@ -120,7 +115,7 @@ Authentication Hash which will contain information about the just
 | 
				
			||||||
authenticated user including a unique id, the strategy they just used
 | 
					authenticated user including a unique id, the strategy they just used
 | 
				
			||||||
for authentication, and personal details such as name and email address
 | 
					for authentication, and personal details such as name and email address
 | 
				
			||||||
as available. For an in-depth description of what the authentication
 | 
					as available. For an in-depth description of what the authentication
 | 
				
			||||||
hash might contain, see the [Auth Hash Schema wiki page](https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema).
 | 
					hash might contain, see the [Auth Hash Schema wiki page](https://github.com/omniauth/omniauth/wiki/Auth-Hash-Schema).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Note that OmniAuth does not perform any actions beyond setting some
 | 
					Note that OmniAuth does not perform any actions beyond setting some
 | 
				
			||||||
environment information on the callback request. It is entirely up to
 | 
					environment information on the callback request. It is entirely up to
 | 
				
			||||||
| 
						 | 
					@ -137,13 +132,13 @@ OmniAuth.config.logger = Rails.logger
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Resources
 | 
					## Resources
 | 
				
			||||||
The [OmniAuth Wiki](https://github.com/intridea/omniauth/wiki) has
 | 
					The [OmniAuth Wiki](https://github.com/omniauth/omniauth/wiki) has
 | 
				
			||||||
actively maintained in-depth documentation for OmniAuth. It should be
 | 
					actively maintained in-depth documentation for OmniAuth. It should be
 | 
				
			||||||
your first stop if you are wondering about a more in-depth look at
 | 
					your first stop if you are wondering about a more in-depth look at
 | 
				
			||||||
OmniAuth, how it works, and how to use it.
 | 
					OmniAuth, how it works, and how to use it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Supported Ruby Versions
 | 
					## Supported Ruby Versions
 | 
				
			||||||
OmniAuth is tested under 1.8.7, 1.9.3, 2.0.0, 2.1.0, JRuby, and Rubinius.
 | 
					OmniAuth is tested under 2.1.10, 2.2.6, 2.3.3, 2.4.0, and JRuby.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Versioning
 | 
					## Versioning
 | 
				
			||||||
This library aims to adhere to [Semantic Versioning 2.0.0][semver]. Violations
 | 
					This library aims to adhere to [Semantic Versioning 2.0.0][semver]. Violations
 | 
				
			||||||
| 
						 | 
					@ -158,10 +153,10 @@ Constraint][pvc] with two digits of precision. For example:
 | 
				
			||||||
    spec.add_dependency 'omniauth', '~> 1.0'
 | 
					    spec.add_dependency 'omniauth', '~> 1.0'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[semver]: http://semver.org/
 | 
					[semver]: http://semver.org/
 | 
				
			||||||
[pvc]: http://docs.rubygems.org/read/chapter/16#page74
 | 
					[pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## License
 | 
					## License
 | 
				
			||||||
Copyright (c) 2010-2013 Michael Bleigh and Intridea, Inc. See [LICENSE][] for
 | 
					Copyright (c) 2010-2017 Michael Bleigh and Intridea, Inc. See [LICENSE][] for
 | 
				
			||||||
details.
 | 
					details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[license]: LICENSE.md
 | 
					[license]: LICENSE.md
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										35
									
								
								Rakefile
									
										
									
									
									
								
							
							
						
						
									
										35
									
								
								Rakefile
									
										
									
									
									
								
							| 
						 | 
					@ -15,3 +15,38 @@ rescue LoadError
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
task :default => [:spec, :rubocop]
 | 
					task :default => [:spec, :rubocop]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace :perf do
 | 
				
			||||||
 | 
					  task :setup do
 | 
				
			||||||
 | 
					    require 'omniauth'
 | 
				
			||||||
 | 
					    require 'rack/test'
 | 
				
			||||||
 | 
					    app = Rack::Builder.new do |b|
 | 
				
			||||||
 | 
					      b.use Rack::Session::Cookie, :secret => 'abc123'
 | 
				
			||||||
 | 
					      b.use OmniAuth::Strategies::Developer
 | 
				
			||||||
 | 
					      b.run lambda { |_env| [200, {}, ['Not Found']] }
 | 
				
			||||||
 | 
					    end.to_app
 | 
				
			||||||
 | 
					    @app = Rack::MockRequest.new(app)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def call_app(path = ENV['GET_PATH'] || '/')
 | 
				
			||||||
 | 
					      result = @app.get(path)
 | 
				
			||||||
 | 
					      raise "Did not succeed #{result.body}" unless result.status == 200
 | 
				
			||||||
 | 
					      result
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  task :ips => :setup do
 | 
				
			||||||
 | 
					    require 'benchmark/ips'
 | 
				
			||||||
 | 
					    Benchmark.ips do |x|
 | 
				
			||||||
 | 
					      x.report('ips') { call_app }
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  task :mem => :setup do
 | 
				
			||||||
 | 
					    require 'memory_profiler'
 | 
				
			||||||
 | 
					    num = Integer(ENV['CNT'] || 1)
 | 
				
			||||||
 | 
					    report = MemoryProfiler.report do
 | 
				
			||||||
 | 
					      num.times { call_app }
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    report.pretty_print
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,11 @@
 | 
				
			||||||
require 'hashie/mash'
 | 
					require 'omniauth/key_store'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module OmniAuth
 | 
					module OmniAuth
 | 
				
			||||||
  # The AuthHash is a normalized schema returned by all OmniAuth
 | 
					  # The AuthHash is a normalized schema returned by all OmniAuth
 | 
				
			||||||
  # strategies. It maps as much user information as the provider
 | 
					  # strategies. It maps as much user information as the provider
 | 
				
			||||||
  # is able to provide into the InfoHash (stored as the `'info'`
 | 
					  # is able to provide into the InfoHash (stored as the `'info'`
 | 
				
			||||||
  # key).
 | 
					  # key).
 | 
				
			||||||
  class AuthHash < Hashie::Mash
 | 
					  class AuthHash < OmniAuth::KeyStore
 | 
				
			||||||
    def self.subkey_class
 | 
					    def self.subkey_class
 | 
				
			||||||
      Hashie::Mash
 | 
					      Hashie::Mash
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
| 
						 | 
					@ -26,7 +26,7 @@ module OmniAuth
 | 
				
			||||||
      super
 | 
					      super
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class InfoHash < Hashie::Mash
 | 
					    class InfoHash < OmniAuth::KeyStore
 | 
				
			||||||
      def self.subkey_class
 | 
					      def self.subkey_class
 | 
				
			||||||
        Hashie::Mash
 | 
					        Hashie::Mash
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,7 @@ module OmniAuth
 | 
				
			||||||
      def name?
 | 
					      def name?
 | 
				
			||||||
        !!name
 | 
					        !!name
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
      alias_method :valid?, :name?
 | 
					      alias valid? name?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      def to_hash
 | 
					      def to_hash
 | 
				
			||||||
        hash = super
 | 
					        hash = super
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,7 +49,7 @@ module OmniAuth
 | 
				
			||||||
        middleware = klass
 | 
					        middleware = klass
 | 
				
			||||||
      else
 | 
					      else
 | 
				
			||||||
        begin
 | 
					        begin
 | 
				
			||||||
          middleware = OmniAuth::Strategies.const_get("#{OmniAuth::Utils.camelize(klass.to_s)}")
 | 
					          middleware = OmniAuth::Strategies.const_get(OmniAuth::Utils.camelize(klass.to_s).to_s)
 | 
				
			||||||
        rescue NameError
 | 
					        rescue NameError
 | 
				
			||||||
          raise(LoadError.new("Could not find matching strategy for #{klass.inspect}. You may need to install an additional gem (such as omniauth-#{klass})."))
 | 
					          raise(LoadError.new("Could not find matching strategy for #{klass.inspect}. You may need to install an additional gem (such as omniauth-#{klass})."))
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,7 @@ module OmniAuth
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def raise_out!
 | 
					    def raise_out!
 | 
				
			||||||
      fail(env['omniauth.error'] || OmniAuth::Error.new(env['omniauth.error.type']))
 | 
					      raise(env['omniauth.error'] || OmniAuth::Error.new(env['omniauth.error.type']))
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def redirect_to_failure
 | 
					    def redirect_to_failure
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,7 +56,7 @@ input {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
input#identifier, input#openid_url {
 | 
					input#identifier, input#openid_url {
 | 
				
			||||||
  background: url(http://openid.net/login-bg.gif) no-repeat;
 | 
					  background: url(https://openid.net/images/login-bg.gif) no-repeat;
 | 
				
			||||||
  background-position: 0 50%;
 | 
					  background-position: 0 50%;
 | 
				
			||||||
  padding-left: 18px;
 | 
					  padding-left: 18px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										22
									
								
								lib/omniauth/key_store.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								lib/omniauth/key_store.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					require 'hashie/mash'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module OmniAuth
 | 
				
			||||||
 | 
					  # Generic helper hash that allows method access on deeply nested keys.
 | 
				
			||||||
 | 
					  class KeyStore < ::Hashie::Mash
 | 
				
			||||||
 | 
					    # Disables warnings on Hashie 3.5.0+ for overwritten keys
 | 
				
			||||||
 | 
					    def self.override_logging
 | 
				
			||||||
 | 
					      require 'hashie/version'
 | 
				
			||||||
 | 
					      return unless Gem::Version.new(Hashie::VERSION) >= Gem::Version.new('3.5.0')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if respond_to?(:disable_warnings)
 | 
				
			||||||
 | 
					        disable_warnings
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        define_method(:log_built_in_message) { |*| }
 | 
				
			||||||
 | 
					        private :log_built_in_message
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Disable on loading of the class
 | 
				
			||||||
 | 
					    override_logging
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
require 'hashie/mash'
 | 
					require 'omniauth/key_store'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module OmniAuth
 | 
					module OmniAuth
 | 
				
			||||||
  class NoSessionError < StandardError; end
 | 
					  class NoSessionError < StandardError; end
 | 
				
			||||||
| 
						 | 
					@ -21,9 +21,9 @@ module OmniAuth
 | 
				
			||||||
      # Returns an inherited set of default options set at the class-level
 | 
					      # Returns an inherited set of default options set at the class-level
 | 
				
			||||||
      # for each strategy.
 | 
					      # for each strategy.
 | 
				
			||||||
      def default_options
 | 
					      def default_options
 | 
				
			||||||
        return @default_options if instance_variable_defined?(:@default_options) && @default_options
 | 
					        # existing = superclass.default_options if superclass.respond_to?(:default_options)
 | 
				
			||||||
        existing = superclass.respond_to?(:default_options) ? superclass.default_options : {}
 | 
					        existing = superclass.respond_to?(:default_options) ? superclass.default_options : {}
 | 
				
			||||||
        @default_options = OmniAuth::Strategy::Options.new(existing)
 | 
					        @default_options ||= OmniAuth::Strategy::Options.new(existing)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # This allows for more declarative subclassing of strategies by allowing
 | 
					      # This allows for more declarative subclassing of strategies by allowing
 | 
				
			||||||
| 
						 | 
					@ -88,9 +88,12 @@ module OmniAuth
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      %w(uid info extra credentials).each do |fetcher|
 | 
					      %w(uid info extra credentials).each do |fetcher|
 | 
				
			||||||
        class_eval <<-RUBY
 | 
					        class_eval <<-RUBY, __FILE__, __LINE__ + 1
 | 
				
			||||||
 | 
					          attr_reader :#{fetcher}_proc
 | 
				
			||||||
 | 
					          private :#{fetcher}_proc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          def #{fetcher}(&block)
 | 
					          def #{fetcher}(&block)
 | 
				
			||||||
            return @#{fetcher}_proc unless block_given?
 | 
					            return #{fetcher}_proc unless block_given?
 | 
				
			||||||
            @#{fetcher}_proc = block
 | 
					            @#{fetcher}_proc = block
 | 
				
			||||||
          end
 | 
					          end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -132,7 +135,7 @@ module OmniAuth
 | 
				
			||||||
      @options = self.class.default_options.dup
 | 
					      @options = self.class.default_options.dup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      options.deep_merge!(args.pop) if args.last.is_a?(Hash)
 | 
					      options.deep_merge!(args.pop) if args.last.is_a?(Hash)
 | 
				
			||||||
      options.name ||= self.class.to_s.split('::').last.downcase
 | 
					      options[:name] ||= self.class.to_s.split('::').last.downcase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      self.class.args.each do |arg|
 | 
					      self.class.args.each do |arg|
 | 
				
			||||||
        break if args.empty?
 | 
					        break if args.empty?
 | 
				
			||||||
| 
						 | 
					@ -140,7 +143,7 @@ module OmniAuth
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # Make sure that all of the args have been dealt with, otherwise error out.
 | 
					      # Make sure that all of the args have been dealt with, otherwise error out.
 | 
				
			||||||
      fail(ArgumentError.new("Received wrong number of arguments. #{args.inspect}")) unless args.empty?
 | 
					      raise(ArgumentError.new("Received wrong number of arguments. #{args.inspect}")) unless args.empty?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      yield options if block_given?
 | 
					      yield options if block_given?
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
| 
						 | 
					@ -172,7 +175,7 @@ module OmniAuth
 | 
				
			||||||
    def call!(env) # rubocop:disable CyclomaticComplexity, PerceivedComplexity
 | 
					    def call!(env) # rubocop:disable CyclomaticComplexity, PerceivedComplexity
 | 
				
			||||||
      unless env['rack.session']
 | 
					      unless env['rack.session']
 | 
				
			||||||
        error = OmniAuth::NoSessionError.new('You must provide a session to use OmniAuth.')
 | 
					        error = OmniAuth::NoSessionError.new('You must provide a session to use OmniAuth.')
 | 
				
			||||||
        fail(error)
 | 
					        raise(error)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      @env = env
 | 
					      @env = env
 | 
				
			||||||
| 
						 | 
					@ -198,7 +201,9 @@ module OmniAuth
 | 
				
			||||||
      setup_phase
 | 
					      setup_phase
 | 
				
			||||||
      log :info, 'Request phase initiated.'
 | 
					      log :info, 'Request phase initiated.'
 | 
				
			||||||
      # store query params from the request url, extracted in the callback_phase
 | 
					      # store query params from the request url, extracted in the callback_phase
 | 
				
			||||||
      session['omniauth.params'] = request.params
 | 
					      session['omniauth.params'] = request.GET
 | 
				
			||||||
 | 
					      # store query headers from the request url, extracted in the callback_phase
 | 
				
			||||||
 | 
					      session['omniauth.headers'] = headers
 | 
				
			||||||
      OmniAuth.config.before_request_phase.call(env) if OmniAuth.config.before_request_phase
 | 
					      OmniAuth.config.before_request_phase.call(env) if OmniAuth.config.before_request_phase
 | 
				
			||||||
      if options.form.respond_to?(:call)
 | 
					      if options.form.respond_to?(:call)
 | 
				
			||||||
        log :info, 'Rendering form from supplied Rack endpoint.'
 | 
					        log :info, 'Rendering form from supplied Rack endpoint.'
 | 
				
			||||||
| 
						 | 
					@ -223,6 +228,7 @@ module OmniAuth
 | 
				
			||||||
      @env['omniauth.origin'] = session.delete('omniauth.origin')
 | 
					      @env['omniauth.origin'] = session.delete('omniauth.origin')
 | 
				
			||||||
      @env['omniauth.origin'] = nil if env['omniauth.origin'] == ''
 | 
					      @env['omniauth.origin'] = nil if env['omniauth.origin'] == ''
 | 
				
			||||||
      @env['omniauth.params'] = session.delete('omniauth.params') || {}
 | 
					      @env['omniauth.params'] = session.delete('omniauth.params') || {}
 | 
				
			||||||
 | 
					      @env['omniauth.headers'] = session.delete('omniauth.headers') || {}
 | 
				
			||||||
      OmniAuth.config.before_callback_phase.call(@env) if OmniAuth.config.before_callback_phase
 | 
					      OmniAuth.config.before_callback_phase.call(@env) if OmniAuth.config.before_callback_phase
 | 
				
			||||||
      callback_phase
 | 
					      callback_phase
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
| 
						 | 
					@ -234,8 +240,8 @@ module OmniAuth
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def on_request_path?
 | 
					    def on_request_path?
 | 
				
			||||||
      if options.request_path.respond_to?(:call)
 | 
					      if options[:request_path].respond_to?(:call)
 | 
				
			||||||
        options.request_path.call(env)
 | 
					        options[:request_path].call(env)
 | 
				
			||||||
      else
 | 
					      else
 | 
				
			||||||
        on_path?(request_path)
 | 
					        on_path?(request_path)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
| 
						 | 
					@ -246,7 +252,7 @@ module OmniAuth
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def on_path?(path)
 | 
					    def on_path?(path)
 | 
				
			||||||
      current_path.casecmp(path) == 0
 | 
					      current_path.casecmp(path).zero?
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def options_request?
 | 
					    def options_request?
 | 
				
			||||||
| 
						 | 
					@ -257,7 +263,7 @@ module OmniAuth
 | 
				
			||||||
    # in the event that OmniAuth has been configured to be
 | 
					    # in the event that OmniAuth has been configured to be
 | 
				
			||||||
    # in test mode.
 | 
					    # in test mode.
 | 
				
			||||||
    def mock_call!(*)
 | 
					    def mock_call!(*)
 | 
				
			||||||
      return mock_request_call if on_request_path?
 | 
					      return mock_request_call if on_request_path? && OmniAuth.config.allowed_request_methods.include?(request.request_method.downcase.to_sym)
 | 
				
			||||||
      return mock_callback_call if on_callback_path?
 | 
					      return mock_callback_call if on_callback_path?
 | 
				
			||||||
      call_app!
 | 
					      call_app!
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
| 
						 | 
					@ -265,7 +271,8 @@ module OmniAuth
 | 
				
			||||||
    def mock_request_call
 | 
					    def mock_request_call
 | 
				
			||||||
      setup_phase
 | 
					      setup_phase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      session['omniauth.params'] = request.params
 | 
					      session['omniauth.params'] = request.GET
 | 
				
			||||||
 | 
					      session['omniauth.headers'] = headers
 | 
				
			||||||
      OmniAuth.config.before_request_phase.call(env) if OmniAuth.config.before_request_phase
 | 
					      OmniAuth.config.before_request_phase.call(env) if OmniAuth.config.before_request_phase
 | 
				
			||||||
      if request.params['origin']
 | 
					      if request.params['origin']
 | 
				
			||||||
        @env['rack.session']['omniauth.origin'] = request.params['origin']
 | 
					        @env['rack.session']['omniauth.origin'] = request.params['origin']
 | 
				
			||||||
| 
						 | 
					@ -280,12 +287,14 @@ module OmniAuth
 | 
				
			||||||
      setup_phase
 | 
					      setup_phase
 | 
				
			||||||
      @env['omniauth.origin'] = session.delete('omniauth.origin')
 | 
					      @env['omniauth.origin'] = session.delete('omniauth.origin')
 | 
				
			||||||
      @env['omniauth.origin'] = nil if env['omniauth.origin'] == ''
 | 
					      @env['omniauth.origin'] = nil if env['omniauth.origin'] == ''
 | 
				
			||||||
 | 
					      @env['omniauth.params'] = session.delete('omniauth.params') || {}
 | 
				
			||||||
 | 
					      @env['omniauth.headers'] = session.delete('omniauth.headers') || {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      mocked_auth = OmniAuth.mock_auth_for(name.to_s)
 | 
					      mocked_auth = OmniAuth.mock_auth_for(name.to_s)
 | 
				
			||||||
      if mocked_auth.is_a?(Symbol)
 | 
					      if mocked_auth.is_a?(Symbol)
 | 
				
			||||||
        fail!(mocked_auth)
 | 
					        fail!(mocked_auth)
 | 
				
			||||||
      else
 | 
					      else
 | 
				
			||||||
        @env['omniauth.auth'] = mocked_auth
 | 
					        @env['omniauth.auth'] = mocked_auth
 | 
				
			||||||
        @env['omniauth.params'] = session.delete('omniauth.params') || {}
 | 
					 | 
				
			||||||
        OmniAuth.config.before_callback_phase.call(@env) if OmniAuth.config.before_callback_phase
 | 
					        OmniAuth.config.before_callback_phase.call(@env) if OmniAuth.config.before_callback_phase
 | 
				
			||||||
        call_app!
 | 
					        call_app!
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
| 
						 | 
					@ -299,7 +308,7 @@ module OmniAuth
 | 
				
			||||||
      if options[:setup].respond_to?(:call)
 | 
					      if options[:setup].respond_to?(:call)
 | 
				
			||||||
        log :info, 'Setup endpoint detected, running now.'
 | 
					        log :info, 'Setup endpoint detected, running now.'
 | 
				
			||||||
        options[:setup].call(env)
 | 
					        options[:setup].call(env)
 | 
				
			||||||
      elsif options.setup?
 | 
					      elsif options[:setup]
 | 
				
			||||||
        log :info, 'Calling through to underlying application for setup.'
 | 
					        log :info, 'Calling through to underlying application for setup.'
 | 
				
			||||||
        setup_env = env.merge('PATH_INFO' => setup_path, 'REQUEST_METHOD' => 'GET')
 | 
					        setup_env = env.merge('PATH_INFO' => setup_path, 'REQUEST_METHOD' => 'GET')
 | 
				
			||||||
        call_app!(setup_env)
 | 
					        call_app!(setup_env)
 | 
				
			||||||
| 
						 | 
					@ -310,7 +319,7 @@ module OmniAuth
 | 
				
			||||||
    # perform any information gathering you need to be able to authenticate
 | 
					    # perform any information gathering you need to be able to authenticate
 | 
				
			||||||
    # the user in this phase.
 | 
					    # the user in this phase.
 | 
				
			||||||
    def request_phase
 | 
					    def request_phase
 | 
				
			||||||
      fail(NotImplementedError)
 | 
					      raise(NotImplementedError)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def uid
 | 
					    def uid
 | 
				
			||||||
| 
						 | 
					@ -347,14 +356,9 @@ module OmniAuth
 | 
				
			||||||
    #
 | 
					    #
 | 
				
			||||||
    #   use MyStrategy, :skip_info => lambda{|uid| User.find_by_uid(uid)}
 | 
					    #   use MyStrategy, :skip_info => lambda{|uid| User.find_by_uid(uid)}
 | 
				
			||||||
    def skip_info?
 | 
					    def skip_info?
 | 
				
			||||||
      if options.skip_info?
 | 
					      return false unless options.skip_info?
 | 
				
			||||||
        if options.skip_info.respond_to?(:call)
 | 
					      return true unless options.skip_info.respond_to?(:call)
 | 
				
			||||||
          return options.skip_info.call(uid)
 | 
					      options.skip_info.call(uid)
 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
          return true
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
      false
 | 
					 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def callback_phase
 | 
					    def callback_phase
 | 
				
			||||||
| 
						 | 
					@ -445,7 +449,7 @@ module OmniAuth
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def name
 | 
					    def name
 | 
				
			||||||
      options.name
 | 
					      options[:name]
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def redirect(uri)
 | 
					    def redirect(uri)
 | 
				
			||||||
| 
						 | 
					@ -485,7 +489,7 @@ module OmniAuth
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Options < Hashie::Mash; end
 | 
					    class Options < OmniAuth::KeyStore; end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  protected
 | 
					  protected
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -503,5 +507,10 @@ module OmniAuth
 | 
				
			||||||
        (request.env['HTTP_X_FORWARDED_PROTO'] && request.env['HTTP_X_FORWARDED_PROTO'].split(',')[0] == 'https') ||
 | 
					        (request.env['HTTP_X_FORWARDED_PROTO'] && request.env['HTTP_X_FORWARDED_PROTO'].split(',')[0] == 'https') ||
 | 
				
			||||||
        request.env['rack.url_scheme'] == 'https'
 | 
					        request.env['rack.url_scheme'] == 'https'
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def headers
 | 
				
			||||||
 | 
					      headers = env.select { |key, _value| key.start_with? 'HTTP_' }
 | 
				
			||||||
 | 
					      Hash[headers.map { |key, value| [key.sub(/^HTTP_/, ''), value] }]
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@ module OmniAuth
 | 
				
			||||||
    #     include OmniAuth::Test::StrategyTestCase
 | 
					    #     include OmniAuth::Test::StrategyTestCase
 | 
				
			||||||
    #     def strategy
 | 
					    #     def strategy
 | 
				
			||||||
    #       # return the parameters to a Rack::Builder map call:
 | 
					    #       # return the parameters to a Rack::Builder map call:
 | 
				
			||||||
    #       [MyStrategy.new, :some, :configuration, :options => 'here']
 | 
					    #       [MyStrategy, :some, :configuration, :options => 'here']
 | 
				
			||||||
    #     end
 | 
					    #     end
 | 
				
			||||||
    #     setup do
 | 
					    #     setup do
 | 
				
			||||||
    #       post '/auth/my_strategy/callback', :user => { 'name' => 'Dylan', 'id' => '445' }
 | 
					    #       post '/auth/my_strategy/callback', :user => { 'name' => 'Dylan', 'id' => '445' }
 | 
				
			||||||
| 
						 | 
					@ -37,7 +37,7 @@ module OmniAuth
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      def strategy
 | 
					      def strategy
 | 
				
			||||||
        error = NotImplementedError.new('Including specs must define #strategy')
 | 
					        error = NotImplementedError.new('Including specs must define #strategy')
 | 
				
			||||||
        fail(error)
 | 
					        raise(error)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,3 @@
 | 
				
			||||||
module OmniAuth
 | 
					module OmniAuth
 | 
				
			||||||
  VERSION = '1.3.1'
 | 
					  VERSION = '1.5.0'.freeze
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,18 +4,20 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
 | 
				
			||||||
require 'omniauth/version'
 | 
					require 'omniauth/version'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Gem::Specification.new do |spec|
 | 
					Gem::Specification.new do |spec|
 | 
				
			||||||
  spec.add_dependency 'hashie', ['>= 1.2', '< 4']
 | 
					  spec.add_dependency 'hashie', ['~> 3.5.0', '< 4']
 | 
				
			||||||
  spec.add_dependency 'rack', ['>= 1.0', '< 3']
 | 
					  spec.add_dependency 'rack', ['>= 1.6.2', '< 3']
 | 
				
			||||||
  spec.add_development_dependency 'bundler', '~> 1.0'
 | 
					  spec.add_development_dependency 'bundler', '~> 1.14'
 | 
				
			||||||
 | 
					  spec.add_development_dependency 'rake', '~> 12.0'
 | 
				
			||||||
  spec.authors       = ['Michael Bleigh', 'Erik Michaels-Ober', 'Tom Milewski']
 | 
					  spec.authors       = ['Michael Bleigh', 'Erik Michaels-Ober', 'Tom Milewski']
 | 
				
			||||||
  spec.description   = 'A generalized Rack framework for multiple-provider authentication.'
 | 
					  spec.description   = 'A generalized Rack framework for multiple-provider authentication.'
 | 
				
			||||||
  spec.email         = ['michael@intridea.com', 'sferik@gmail.com', 'tmilewski@gmail.com']
 | 
					  spec.email         = ['michael@intridea.com', 'sferik@gmail.com', 'tmilewski@gmail.com']
 | 
				
			||||||
  spec.files         = `git ls-files -z`.split("\x0").reject { |f| f.start_with?('spec/') }
 | 
					  spec.files         = `git ls-files -z`.split("\x0").reject { |f| f.start_with?('spec/') }
 | 
				
			||||||
  spec.homepage      = 'http://github.com/intridea/omniauth'
 | 
					  spec.homepage      = 'https://github.com/omniauth/omniauth'
 | 
				
			||||||
  spec.licenses      = %w(MIT)
 | 
					  spec.licenses      = %w(MIT)
 | 
				
			||||||
  spec.name          = 'omniauth'
 | 
					  spec.name          = 'omniauth'
 | 
				
			||||||
  spec.require_paths = %w(lib)
 | 
					  spec.require_paths = %w(lib)
 | 
				
			||||||
  spec.required_rubygems_version = '>= 1.3.5'
 | 
					  spec.required_rubygems_version = '>= 1.3.5'
 | 
				
			||||||
 | 
					  spec.required_ruby_version = '>= 2.1.9'
 | 
				
			||||||
  spec.summary       = spec.description
 | 
					  spec.summary       = spec.description
 | 
				
			||||||
  spec.version       = OmniAuth::VERSION
 | 
					  spec.version       = OmniAuth::VERSION
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,10 @@
 | 
				
			||||||
if RUBY_VERSION >= '1.9'
 | 
					if RUBY_VERSION >= '1.9'
 | 
				
			||||||
  require 'simplecov'
 | 
					  require 'simplecov'
 | 
				
			||||||
  require 'coveralls'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  SimpleCov.formatters = [SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  SimpleCov.start do
 | 
					  SimpleCov.start do
 | 
				
			||||||
    add_filter '/spec/'
 | 
					    add_filter '/spec/'
 | 
				
			||||||
    add_filter '/vendor/'
 | 
					    add_filter '/vendor/'
 | 
				
			||||||
    minimum_coverage(92.93)
 | 
					    minimum_coverage(92.5)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,7 +29,7 @@ class ExampleStrategy
 | 
				
			||||||
  option :name, 'test'
 | 
					  option :name, 'test'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def call(env)
 | 
					  def call(env)
 | 
				
			||||||
    options[:dup] ? super : self.call!(env)
 | 
					    options[:dup] ? super : call!(env)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def initialize(*args, &block)
 | 
					  def initialize(*args, &block)
 | 
				
			||||||
| 
						 | 
					@ -45,7 +42,7 @@ class ExampleStrategy
 | 
				
			||||||
    @fail = fail!(options[:failure]) if options[:failure]
 | 
					    @fail = fail!(options[:failure]) if options[:failure]
 | 
				
			||||||
    @last_env = env
 | 
					    @last_env = env
 | 
				
			||||||
    return @fail if @fail
 | 
					    return @fail if @fail
 | 
				
			||||||
    fail('Request Phase')
 | 
					    raise('Request Phase')
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def callback_phase
 | 
					  def callback_phase
 | 
				
			||||||
| 
						 | 
					@ -53,6 +50,6 @@ class ExampleStrategy
 | 
				
			||||||
    @fail = fail!(options[:failure]) if options[:failure]
 | 
					    @fail = fail!(options[:failure]) if options[:failure]
 | 
				
			||||||
    @last_env = env
 | 
					    @last_env = env
 | 
				
			||||||
    return @fail if @fail
 | 
					    return @fail if @fail
 | 
				
			||||||
    fail('Callback Phase')
 | 
					    raise('Callback Phase')
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -110,5 +110,25 @@ describe OmniAuth::AuthHash do
 | 
				
			||||||
        expect(OmniAuth::AuthHash::InfoHash.new(:name => 'Awesome')).to be_valid
 | 
					        expect(OmniAuth::AuthHash::InfoHash.new(:name => 'Awesome')).to be_valid
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    require 'hashie/version'
 | 
				
			||||||
 | 
					    if Gem::Version.new(Hashie::VERSION) >= Gem::Version.new('3.5.1')
 | 
				
			||||||
 | 
					      context 'with Hashie 3.5.1+' do
 | 
				
			||||||
 | 
					        around(:each) do |example|
 | 
				
			||||||
 | 
					          original_logger = Hashie.logger
 | 
				
			||||||
 | 
					          example.run
 | 
				
			||||||
 | 
					          Hashie.logger = original_logger
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it 'does not log anything in Hashie 3.5.1+' do
 | 
				
			||||||
 | 
					          logger = double('Logger')
 | 
				
			||||||
 | 
					          expect(logger).not_to receive(:warn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          Hashie.logger = logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          subject.name = 'test'
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,7 +50,7 @@ describe OmniAuth::FailureEndpoint do
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it 'includes the origin (escaped) if one is provided' do
 | 
					    it 'includes the origin (escaped) if one is provided' do
 | 
				
			||||||
      env.merge! 'omniauth.origin' => '/origin-example'
 | 
					      env['omniauth.origin'] = '/origin-example'
 | 
				
			||||||
      _, head, = *subject.call(env)
 | 
					      _, head, = *subject.call(env)
 | 
				
			||||||
      expect(head['Location']).to be_include('&origin=%2Forigin-example')
 | 
					      expect(head['Location']).to be_include('&origin=%2Forigin-example')
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										79
									
								
								spec/omniauth/key_store_spec.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								spec/omniauth/key_store_spec.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,79 @@
 | 
				
			||||||
 | 
					require 'helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RSpec.describe OmniAuth::KeyStore do
 | 
				
			||||||
 | 
					  let(:logger) { double('Logger') }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  around(:each) do |example|
 | 
				
			||||||
 | 
					    patched = monkey_patch_logger
 | 
				
			||||||
 | 
					    example.run
 | 
				
			||||||
 | 
					    remove_logger(patched)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  context 'on Hashie < 3.5.0' do
 | 
				
			||||||
 | 
					    let(:version) { '3.4.0' }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'does not log anything to the console' do
 | 
				
			||||||
 | 
					      stub_const('Hashie::VERSION', version)
 | 
				
			||||||
 | 
					      OmniAuth::KeyStore.override_logging
 | 
				
			||||||
 | 
					      expect(logger).not_to receive(:info)
 | 
				
			||||||
 | 
					      OmniAuth::KeyStore.new(:id => 1234)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  context 'on Hashie 3.5.0 and 3.5.1' do
 | 
				
			||||||
 | 
					    let(:version) { '3.5.0' }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'does not log anything to the console' do
 | 
				
			||||||
 | 
					      stub_const('Hashie::VERSION', version)
 | 
				
			||||||
 | 
					      OmniAuth::KeyStore.override_logging
 | 
				
			||||||
 | 
					      expect(logger).not_to receive(:info)
 | 
				
			||||||
 | 
					      OmniAuth::KeyStore.new(:id => 1234)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  context 'on Hashie 3.5.2+' do
 | 
				
			||||||
 | 
					    let(:version) { '3.5.2' }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    around(:each) do |example|
 | 
				
			||||||
 | 
					      patching = monkey_patch_unreleased_interface
 | 
				
			||||||
 | 
					      example.run
 | 
				
			||||||
 | 
					      remove_monkey_patch(patching)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'does not log anything to the console' do
 | 
				
			||||||
 | 
					      stub_const('Hashie::VERSION', version)
 | 
				
			||||||
 | 
					      OmniAuth::KeyStore.override_logging
 | 
				
			||||||
 | 
					      expect(logger).not_to receive(:info)
 | 
				
			||||||
 | 
					      OmniAuth::KeyStore.new(:id => 1234)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def monkey_patch_unreleased_interface
 | 
				
			||||||
 | 
					    return false if OmniAuth::KeyStore.class.respond_to?(:disable_warnings, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    OmniAuth::KeyStore.define_singleton_method(:disable_warnings) {}
 | 
				
			||||||
 | 
					    OmniAuth::KeyStore.define_singleton_method(:log_built_in_message) { |*| }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    true
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def monkey_patch_logger
 | 
				
			||||||
 | 
					    return unless Hashie.respond_to?(:logger)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    original_logger = Hashie.logger
 | 
				
			||||||
 | 
					    Hashie.logger = logger
 | 
				
			||||||
 | 
					    original_logger
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def remove_logger(logger)
 | 
				
			||||||
 | 
					    return unless logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Hashie.logger = logger
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def remove_monkey_patch(perform)
 | 
				
			||||||
 | 
					    return unless perform
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    OmniAuth::KeyStore.singleton_class.__send__(:remove_method, :disable_warnings)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					@ -155,7 +155,7 @@ describe OmniAuth::Strategy do
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  %w(request_phase).each do |abstract_method|
 | 
					  %w(request_phase).each do |abstract_method|
 | 
				
			||||||
    context "#{abstract_method}" do
 | 
					    context abstract_method.to_s do
 | 
				
			||||||
      it 'raises a NotImplementedError' do
 | 
					      it 'raises a NotImplementedError' do
 | 
				
			||||||
        strat = Class.new
 | 
					        strat = Class.new
 | 
				
			||||||
        strat.send :include, OmniAuth::Strategy
 | 
					        strat.send :include, OmniAuth::Strategy
 | 
				
			||||||
| 
						 | 
					@ -550,19 +550,15 @@ describe OmniAuth::Strategy do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      context 'in request phase' do
 | 
					      context 'in request phase' do
 | 
				
			||||||
        it 'does not affect original options' do
 | 
					        it 'does not affect original options' do
 | 
				
			||||||
          @options.merge!(
 | 
					          @options[:test_option] = true
 | 
				
			||||||
            :test_option => true,
 | 
					          @options[:mutate_on_request] = proc { |options| options.delete(:test_option) }
 | 
				
			||||||
            :mutate_on_request => proc { |options| options.delete(:test_option) }
 | 
					 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
          expect { strategy.call(make_env) }.to raise_error('Request Phase')
 | 
					          expect { strategy.call(make_env) }.to raise_error('Request Phase')
 | 
				
			||||||
          expect(strategy.options).to have_key(:test_option)
 | 
					          expect(strategy.options).to have_key(:test_option)
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        it 'does not affect deep options' do
 | 
					        it 'does not affect deep options' do
 | 
				
			||||||
          @options.merge!(
 | 
					          @options[:deep_option] = {:test_option => true}
 | 
				
			||||||
            :deep_option => {:test_option => true},
 | 
					          @options[:mutate_on_request] = proc { |options| options[:deep_option].delete(:test_option) }
 | 
				
			||||||
            :mutate_on_request => proc { |options| options[:deep_option].delete(:test_option) }
 | 
					 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
          expect { strategy.call(make_env) }.to raise_error('Request Phase')
 | 
					          expect { strategy.call(make_env) }.to raise_error('Request Phase')
 | 
				
			||||||
          expect(strategy.options[:deep_option]).to have_key(:test_option)
 | 
					          expect(strategy.options[:deep_option]).to have_key(:test_option)
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
| 
						 | 
					@ -570,19 +566,15 @@ describe OmniAuth::Strategy do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      context 'in callback phase' do
 | 
					      context 'in callback phase' do
 | 
				
			||||||
        it 'does not affect original options' do
 | 
					        it 'does not affect original options' do
 | 
				
			||||||
          @options.merge!(
 | 
					          @options[:test_option] = true
 | 
				
			||||||
            :test_option => true,
 | 
					          @options[:mutate_on_callback] = proc { |options| options.delete(:test_option) }
 | 
				
			||||||
            :mutate_on_callback => proc { |options| options.delete(:test_option) }
 | 
					 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
          expect { strategy.call(make_env('/auth/test/callback', 'REQUEST_METHOD' => 'POST')) }.to raise_error('Callback Phase')
 | 
					          expect { strategy.call(make_env('/auth/test/callback', 'REQUEST_METHOD' => 'POST')) }.to raise_error('Callback Phase')
 | 
				
			||||||
          expect(strategy.options).to have_key(:test_option)
 | 
					          expect(strategy.options).to have_key(:test_option)
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        it 'does not affect deep options' do
 | 
					        it 'does not affect deep options' do
 | 
				
			||||||
          @options.merge!(
 | 
					          @options[:deep_option] = {:test_option => true}
 | 
				
			||||||
            :deep_option => {:test_option => true},
 | 
					          @options[:mutate_on_callback] = proc { |options| options[:deep_option].delete(:test_option) }
 | 
				
			||||||
            :mutate_on_callback => proc { |options| options[:deep_option].delete(:test_option) }
 | 
					 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
          expect { strategy.call(make_env('/auth/test/callback', 'REQUEST_METHOD' => 'POST')) }.to raise_error('Callback Phase')
 | 
					          expect { strategy.call(make_env('/auth/test/callback', 'REQUEST_METHOD' => 'POST')) }.to raise_error('Callback Phase')
 | 
				
			||||||
          expect(strategy.options[:deep_option]).to have_key(:test_option)
 | 
					          expect(strategy.options[:deep_option]).to have_key(:test_option)
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
| 
						 | 
					@ -605,6 +597,11 @@ describe OmniAuth::Strategy do
 | 
				
			||||||
        expect(response[1]['Location']).to eq('/auth/test/callback')
 | 
					        expect(response[1]['Location']).to eq('/auth/test/callback')
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it "doesn't short circuit the request if request method is not allowed" do
 | 
				
			||||||
 | 
					        response = strategy.call(make_env('/auth/test', 'REQUEST_METHOD' => 'DELETE'))
 | 
				
			||||||
 | 
					        expect(response[0]).to eq(404)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      it 'is case insensitive on request path' do
 | 
					      it 'is case insensitive on request path' do
 | 
				
			||||||
        expect(strategy.call(make_env('/AUTH/Test'))[0]).to eq(302)
 | 
					        expect(strategy.call(make_env('/AUTH/Test'))[0]).to eq(302)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
| 
						 | 
					@ -693,13 +690,31 @@ describe OmniAuth::Strategy do
 | 
				
			||||||
        expect(strategy.env['foobar']).to eq('baz')
 | 
					        expect(strategy.env['foobar']).to eq('baz')
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      it 'sets omniauth.params on the request phase' do
 | 
					      it 'sets omniauth.params with query params on the request phase' do
 | 
				
			||||||
        OmniAuth.config.mock_auth[:test] = {}
 | 
					        OmniAuth.config.mock_auth[:test] = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'foo=bar'))
 | 
					        strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'foo=bar'))
 | 
				
			||||||
        expect(strategy.env['rack.session']['omniauth.params']).to eq('foo' => 'bar')
 | 
					        expect(strategy.env['rack.session']['omniauth.params']).to eq('foo' => 'bar')
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it 'does not set body parameters of POST request on the request phase' do
 | 
				
			||||||
 | 
					        OmniAuth.config.mock_auth[:test] = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        props = {
 | 
				
			||||||
 | 
					          'REQUEST_METHOD' => 'POST',
 | 
				
			||||||
 | 
					          'rack.input' => StringIO.new('foo=bar')
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        strategy.call(make_env('/auth/test', props))
 | 
				
			||||||
 | 
					        expect(strategy.env['rack.session']['omniauth.params']).to eq({})
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it 'sets omniauth.headers on the request phase' do
 | 
				
			||||||
 | 
					        OmniAuth.config.mock_auth[:test] = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        strategy.call(make_env('/auth/test', 'HTTP_FOO' => 'bar'))
 | 
				
			||||||
 | 
					        expect(strategy.env['rack.session']['omniauth.headers']).to eq('FOO' => 'bar')
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      it 'executes request hook on the request phase' do
 | 
					      it 'executes request hook on the request phase' do
 | 
				
			||||||
        OmniAuth.config.mock_auth[:test] = {}
 | 
					        OmniAuth.config.mock_auth[:test] = {}
 | 
				
			||||||
        OmniAuth.config.before_request_phase do |env|
 | 
					        OmniAuth.config.before_request_phase do |env|
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -91,7 +91,7 @@ describe OmniAuth do
 | 
				
			||||||
    describe 'mock auth' do
 | 
					    describe 'mock auth' do
 | 
				
			||||||
      before do
 | 
					      before do
 | 
				
			||||||
        @auth_hash = {:uid => '12345', :info => {:name => 'Joe', :email => 'joe@example.com'}}
 | 
					        @auth_hash = {:uid => '12345', :info => {:name => 'Joe', :email => 'joe@example.com'}}
 | 
				
			||||||
        @original_auth_hash = Marshal.load(Marshal.dump(@auth_hash))
 | 
					        @original_auth_hash = @auth_hash.dup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        OmniAuth.config.add_mock(:facebook, @auth_hash)
 | 
					        OmniAuth.config.add_mock(:facebook, @auth_hash)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue