omniauth-myvr 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +9 -0
- data/example/Gemfile +4 -0
- data/example/auth.js +43 -0
- data/example/config.ru +45 -0
- data/example/omni_auth.rb +45 -0
- data/lib/omniauth/strategies/myvr.rb +213 -0
- data/lib/omniauth_myvr.rb +7 -0
- data/omniauth-myvr.gemspec +22 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5f392900cec4ada0165ca53f676df5a69790b042
|
4
|
+
data.tar.gz: c7d1cdd0150d4056511c459a8b106a260bd84056
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5ab804a5b6ca562c855c4d068b119548041a711780d111f79956a0d36c2eb499aee14521875bc4c5e96b36727497cff0100f94f17d4e30a5b8347194a862c5ef
|
7
|
+
data.tar.gz: 252748d816f1168d377f60d7734ed8e73ec1f77c4f35563dea9e2062fa59deaa8751342b33f5fdab21d7a38ad93c52191c5a5bf47f700ed7e0a9c1b8b572d1f1
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
.ruby-gemset
|
7
|
+
.ruby-version
|
8
|
+
.rvmrc
|
9
|
+
Gemfile.lock
|
10
|
+
InstalledFiles
|
11
|
+
_yardoc
|
12
|
+
coverage
|
13
|
+
doc/
|
14
|
+
lib/bundler/man
|
15
|
+
pkg
|
16
|
+
rdoc
|
17
|
+
spec/reports
|
18
|
+
test/tmp
|
19
|
+
test/version_tmp
|
20
|
+
tmp
|
21
|
+
.powenv
|
22
|
+
.idea/
|
data/Gemfile
ADDED
data/example/Gemfile
ADDED
data/example/auth.js
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
// Basic hybrid auth example following the pattern at:
|
2
|
+
// https://developers.google.com/api-client-library/javascript/features/authentication#Authexample
|
3
|
+
jQuery(function() {
|
4
|
+
return $.ajax({
|
5
|
+
url: 'https://apis.google.com/js/client:plus.js?onload=gpAsyncInit',
|
6
|
+
dataType: 'script',
|
7
|
+
cache: true
|
8
|
+
});
|
9
|
+
});
|
10
|
+
|
11
|
+
window.gpAsyncInit = function() {
|
12
|
+
gapi.auth.authorize({
|
13
|
+
immediate: true,
|
14
|
+
response_type: 'code',
|
15
|
+
cookie_policy: 'single_host_origin',
|
16
|
+
client_id: 'YOUR_CLIENT_ID',
|
17
|
+
scope: 'email profile'
|
18
|
+
}, function(response) {
|
19
|
+
return;
|
20
|
+
});
|
21
|
+
$('.googleplus-login').click(function(e) {
|
22
|
+
e.preventDefault();
|
23
|
+
gapi.auth.authorize({
|
24
|
+
immediate: false,
|
25
|
+
response_type: 'code',
|
26
|
+
cookie_policy: 'single_host_origin',
|
27
|
+
client_id: 'YOUR_CLIENT_ID',
|
28
|
+
scope: 'email profile'
|
29
|
+
}, function(response) {
|
30
|
+
if (response && !response.error) {
|
31
|
+
// google authentication succeed, now post data to server.
|
32
|
+
jQuery.ajax({type: 'POST', url: "/auth/google_oauth2/callback",
|
33
|
+
data: response,
|
34
|
+
success: function(data) {
|
35
|
+
// response from server
|
36
|
+
}
|
37
|
+
});
|
38
|
+
} else {
|
39
|
+
// google authentication failed
|
40
|
+
}
|
41
|
+
});
|
42
|
+
});
|
43
|
+
};
|
data/example/config.ru
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# Sample app for MyVR OAuth Strategy
|
2
|
+
# Make sure to setup the ENV variables MYVR_KEY and MYVR_SECRET
|
3
|
+
# Run with "bundle exec rackup"
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'bundler'
|
7
|
+
require 'sinatra'
|
8
|
+
require 'omniauth'
|
9
|
+
require 'omniauth-myvr'
|
10
|
+
|
11
|
+
# Do not use for production code.
|
12
|
+
# This is only to make setup easier when running through the sample.
|
13
|
+
#
|
14
|
+
# If you do have issues with certs in production code, this could help:
|
15
|
+
# http://railsapps.github.io/openssl-certificate-verify-failed.html
|
16
|
+
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
|
17
|
+
|
18
|
+
class App < Sinatra::Base
|
19
|
+
get '/' do
|
20
|
+
<<-HTML
|
21
|
+
<ul>
|
22
|
+
<li><a href='/auth/myvr'>Sign in with MyVR</a></li>
|
23
|
+
</ul>
|
24
|
+
HTML
|
25
|
+
end
|
26
|
+
|
27
|
+
get '/auth/:provider/callback' do
|
28
|
+
content_type 'text/plain'
|
29
|
+
request.env['omniauth.auth'].to_hash.inspect rescue "No Data"
|
30
|
+
end
|
31
|
+
|
32
|
+
get '/auth/failure' do
|
33
|
+
content_type 'text/plain'
|
34
|
+
request.env['omniauth.auth'].to_hash.inspect rescue "No Data"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
use Rack::Session::Cookie, :secret => ENV['RACK_COOKIE_SECRET']
|
39
|
+
|
40
|
+
use OmniAuth::Builder do
|
41
|
+
# For additional provider examples please look at 'omni_auth.rb'
|
42
|
+
provider :myvr, ENV['MYVR_KEY'], ENV['MYVR_SECRET'], {}
|
43
|
+
end
|
44
|
+
|
45
|
+
run App.new
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# MyVR's OAuth2 docs. Make sure you are familiar with all the options
|
2
|
+
# before attempting to configure this gem.
|
3
|
+
# https://developers.MyVR.com/accounts/docs/OAuth2Login
|
4
|
+
|
5
|
+
Rails.application.config.middleware.use OmniAuth::Builder do
|
6
|
+
# Default usage, this will give you offline access and a refresh token
|
7
|
+
# using default scopes 'email' and 'profile'
|
8
|
+
#
|
9
|
+
provider :myvr, ENV['MYVR_KEY'], ENV['MYVR_SECRET'], {
|
10
|
+
:scope => 'email,profile'
|
11
|
+
}
|
12
|
+
|
13
|
+
# Manual setup for offline access with a refresh token.
|
14
|
+
#
|
15
|
+
# provider :MYVR_oauth2, ENV['MYVR_KEY'], ENV['MYVR_SECRET'], {
|
16
|
+
# :access_type => 'offline',
|
17
|
+
# }
|
18
|
+
|
19
|
+
# Custom scope supporting youtube. If you are customizing scopes, remember
|
20
|
+
# to include the default scopes 'email' and 'profile'
|
21
|
+
#
|
22
|
+
# provider :myvr, ENV['MYVR_KEY'], ENV['MYVR_SECRET'], {
|
23
|
+
# :scope => 'http://gdata.youtube.com,email,profile,plus.me'
|
24
|
+
# }
|
25
|
+
|
26
|
+
# Custom scope for users only using MyVR for account creation/auth and do not require a refresh token.
|
27
|
+
#
|
28
|
+
# provider :MYVR_oauth2, ENV['MYVR_KEY'], ENV['MYVR_SECRET'], {
|
29
|
+
# :access_type => 'online',
|
30
|
+
# :prompt => ''
|
31
|
+
# }
|
32
|
+
|
33
|
+
# To include information about people in your circles you must include the 'plus.login' scope.
|
34
|
+
#
|
35
|
+
# provider :MYVR_oauth2, ENV['MYVR_KEY'], ENV['MYVR_SECRET'], {
|
36
|
+
# :skip_friends => false,
|
37
|
+
# :scope => "email,profile,plus.login"
|
38
|
+
# }
|
39
|
+
|
40
|
+
# If you need to acquire whether user picture is a default one or uploaded by user.
|
41
|
+
#
|
42
|
+
# provider :MYVR_oauth2, ENV['MYVR_KEY'], ENV['MYVR_SECRET'], {
|
43
|
+
# :skip_image_info => false
|
44
|
+
# }
|
45
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
require 'jwt'
|
3
|
+
require 'omniauth/strategies/oauth2'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module OmniAuth
|
7
|
+
module Strategies
|
8
|
+
class MyVROAuth < OmniAuth::Strategies::OAuth2
|
9
|
+
BASE_SCOPE_URL = "https://api.myvr.com/auth/"
|
10
|
+
BASE_SCOPES = %w[profile email openid]
|
11
|
+
DEFAULT_SCOPE = "email,profile"
|
12
|
+
|
13
|
+
option :name, 'myvr'
|
14
|
+
option :skip_friends, true
|
15
|
+
option :skip_image_info, true
|
16
|
+
option :skip_jwt, false
|
17
|
+
option :jwt_leeway, 60
|
18
|
+
option :authorize_options, [
|
19
|
+
:access_type,
|
20
|
+
:hd,
|
21
|
+
:login_hint,
|
22
|
+
:prompt,
|
23
|
+
:request_visible_actions,
|
24
|
+
:scope,
|
25
|
+
:state,
|
26
|
+
:redirect_uri,
|
27
|
+
:include_granted_scopes,
|
28
|
+
:openid_realm
|
29
|
+
]
|
30
|
+
option :authorized_client_ids, []
|
31
|
+
|
32
|
+
option :client_options, {
|
33
|
+
:site => 'https://accounts.google.com',
|
34
|
+
:authorize_url => '/o/oauth2/auth',
|
35
|
+
:token_url => '/o/oauth2/token'
|
36
|
+
}
|
37
|
+
|
38
|
+
def authorize_params
|
39
|
+
super.tap do |params|
|
40
|
+
options[:authorize_options].each do |k|
|
41
|
+
params[k] = request.params[k.to_s] unless [nil, ''].include?(request.params[k.to_s])
|
42
|
+
end
|
43
|
+
|
44
|
+
raw_scope = params[:scope] || DEFAULT_SCOPE
|
45
|
+
scope_list = raw_scope.split(" ").map {|item| item.split(",")}.flatten
|
46
|
+
scope_list.map! { |s| s =~ /^https?:\/\// || BASE_SCOPES.include?(s) ? s : "#{BASE_SCOPE_URL}#{s}" }
|
47
|
+
params[:scope] = scope_list.join(" ")
|
48
|
+
params[:access_type] = 'offline' if params[:access_type].nil?
|
49
|
+
params['openid.realm'] = params.delete(:openid_realm) unless params[:openid_realm].nil?
|
50
|
+
|
51
|
+
session['omniauth.state'] = params[:state] if params['state']
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
uid { raw_info['sub'] || verified_email }
|
56
|
+
|
57
|
+
info do
|
58
|
+
prune!({
|
59
|
+
:name => raw_info['name'],
|
60
|
+
:email => verified_email,
|
61
|
+
:first_name => raw_info['given_name'],
|
62
|
+
:last_name => raw_info['family_name'],
|
63
|
+
:image => image_url,
|
64
|
+
:urls => {
|
65
|
+
'Google' => raw_info['profile']
|
66
|
+
}
|
67
|
+
})
|
68
|
+
end
|
69
|
+
|
70
|
+
extra do
|
71
|
+
hash = {}
|
72
|
+
hash[:id_token] = access_token['id_token']
|
73
|
+
if !options[:skip_jwt] && !access_token['id_token'].nil?
|
74
|
+
hash[:id_info] = JWT.decode(
|
75
|
+
access_token['id_token'], nil, false, {
|
76
|
+
:verify_iss => true,
|
77
|
+
'iss' => 'accounts.google.com',
|
78
|
+
:verify_aud => true,
|
79
|
+
'aud' => options.client_id,
|
80
|
+
:verify_sub => false,
|
81
|
+
:verify_expiration => true,
|
82
|
+
:verify_not_before => true,
|
83
|
+
:verify_iat => true,
|
84
|
+
:verify_jti => false,
|
85
|
+
:leeway => options[:jwt_leeway]
|
86
|
+
}).first
|
87
|
+
end
|
88
|
+
hash[:raw_info] = raw_info unless skip_info?
|
89
|
+
hash[:raw_friend_info] = raw_friend_info(raw_info['sub']) unless skip_info? || options[:skip_friends]
|
90
|
+
hash[:raw_image_info] = raw_image_info(raw_info['sub']) unless skip_info? || options[:skip_image_info]
|
91
|
+
prune! hash
|
92
|
+
end
|
93
|
+
|
94
|
+
def raw_info
|
95
|
+
@raw_info ||= access_token.get('https://www.googleapis.com/plus/v1/people/me/openIdConnect').parsed
|
96
|
+
end
|
97
|
+
|
98
|
+
def raw_friend_info(id)
|
99
|
+
@raw_friend_info ||= access_token.get("https://www.googleapis.com/plus/v1/people/#{id}/people/visible").parsed
|
100
|
+
end
|
101
|
+
|
102
|
+
def raw_image_info(id)
|
103
|
+
@raw_image_info ||= access_token.get("https://www.googleapis.com/plus/v1/people/#{id}?fields=image").parsed
|
104
|
+
end
|
105
|
+
|
106
|
+
def custom_build_access_token
|
107
|
+
access_token =
|
108
|
+
if request.xhr? && request.params['code']
|
109
|
+
verifier = request.params['code']
|
110
|
+
client.auth_code.get_token(verifier, get_token_options('postmessage'), deep_symbolize(options.auth_token_params || {}))
|
111
|
+
elsif request.params['code'] && request.params['redirect_uri']
|
112
|
+
verifier = request.params['code']
|
113
|
+
redirect_uri = request.params['redirect_uri']
|
114
|
+
client.auth_code.get_token(verifier, get_token_options(redirect_uri), deep_symbolize(options.auth_token_params || {}))
|
115
|
+
elsif verify_token(request.params['access_token'])
|
116
|
+
::OAuth2::AccessToken.from_hash(client, request.params.dup)
|
117
|
+
else
|
118
|
+
verifier = request.params["code"]
|
119
|
+
client.auth_code.get_token(verifier, get_token_options(callback_url), deep_symbolize(options.auth_token_params))
|
120
|
+
end
|
121
|
+
|
122
|
+
verify_hd(access_token)
|
123
|
+
access_token
|
124
|
+
end
|
125
|
+
alias_method :build_access_token, :custom_build_access_token
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def callback_url
|
130
|
+
options[:redirect_uri] || (full_host + script_name + callback_path)
|
131
|
+
end
|
132
|
+
|
133
|
+
def get_token_options(redirect_uri)
|
134
|
+
{ :redirect_uri => redirect_uri }.merge(token_params.to_hash(:symbolize_keys => true))
|
135
|
+
end
|
136
|
+
|
137
|
+
def prune!(hash)
|
138
|
+
hash.delete_if do |_, v|
|
139
|
+
prune!(v) if v.is_a?(Hash)
|
140
|
+
v.nil? || (v.respond_to?(:empty?) && v.empty?)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def verified_email
|
145
|
+
raw_info['email_verified'] ? raw_info['email'] : nil
|
146
|
+
end
|
147
|
+
|
148
|
+
def image_url
|
149
|
+
return nil unless raw_info['picture']
|
150
|
+
|
151
|
+
u = URI.parse(raw_info['picture'].gsub('https:https', 'https'))
|
152
|
+
|
153
|
+
path_index = u.path.to_s.index('/photo.jpg')
|
154
|
+
|
155
|
+
if path_index && image_size_opts_passed?
|
156
|
+
u.path.insert(path_index, image_params)
|
157
|
+
u.path = u.path.gsub('//', '/')
|
158
|
+
end
|
159
|
+
|
160
|
+
u.query = strip_unnecessary_query_parameters(u.query)
|
161
|
+
|
162
|
+
u.to_s
|
163
|
+
end
|
164
|
+
|
165
|
+
def image_size_opts_passed?
|
166
|
+
!!(options[:image_size] || options[:image_aspect_ratio])
|
167
|
+
end
|
168
|
+
|
169
|
+
def image_params
|
170
|
+
image_params = []
|
171
|
+
if options[:image_size].is_a?(Integer)
|
172
|
+
image_params << "s#{options[:image_size]}"
|
173
|
+
elsif options[:image_size].is_a?(Hash)
|
174
|
+
image_params << "w#{options[:image_size][:width]}" if options[:image_size][:width]
|
175
|
+
image_params << "h#{options[:image_size][:height]}" if options[:image_size][:height]
|
176
|
+
end
|
177
|
+
image_params << 'c' if options[:image_aspect_ratio] == 'square'
|
178
|
+
|
179
|
+
'/' + image_params.join('-')
|
180
|
+
end
|
181
|
+
|
182
|
+
def strip_unnecessary_query_parameters(query_parameters)
|
183
|
+
# strip `sz` parameter (defaults to sz=50) which overrides `image_size` options
|
184
|
+
return nil if query_parameters.nil?
|
185
|
+
|
186
|
+
params = CGI.parse(query_parameters)
|
187
|
+
stripped_params = params.delete_if { |key| key == "sz" }
|
188
|
+
|
189
|
+
# don't return an empty Hash since that would result
|
190
|
+
# in URLs with a trailing ? character: http://image.url?
|
191
|
+
return nil if stripped_params.empty?
|
192
|
+
|
193
|
+
URI.encode_www_form(stripped_params)
|
194
|
+
end
|
195
|
+
|
196
|
+
def verify_token(access_token)
|
197
|
+
return false unless access_token
|
198
|
+
raw_response = client.request(:get, 'https://www.googleapis.com/oauth2/v3/tokeninfo',
|
199
|
+
params: { access_token: access_token }).parsed
|
200
|
+
raw_response['aud'] == options.client_id || options.authorized_client_ids.include?(raw_response['aud'])
|
201
|
+
end
|
202
|
+
|
203
|
+
def verify_hd(access_token)
|
204
|
+
return true unless options.hd
|
205
|
+
@raw_info ||= access_token.get('https://www.googleapis.com/plus/v1/people/me/openIdConnect').parsed
|
206
|
+
allowed_hosted_domains = Array(options.hd)
|
207
|
+
|
208
|
+
raise CallbackError.new(:invalid_hd, "Invalid Hosted Domain") unless allowed_hosted_domains.include? @raw_info['hd']
|
209
|
+
true
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "omniauth-myvr"
|
6
|
+
s.version = "0.0.1"
|
7
|
+
s.authors = ["CJ Avilla"]
|
8
|
+
s.email = ["cjavilla@gmail.com"]
|
9
|
+
s.homepage = "https://github.com/w1zeman1p/omniauth-myvr"
|
10
|
+
s.description = %q{OmniAuth strategy for MyVR}
|
11
|
+
s.summary = s.description
|
12
|
+
s.license = "MIT"
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
|
19
|
+
s.add_dependency 'omniauth', '>= 1.1.1'
|
20
|
+
s.add_dependency 'omniauth-oauth2', '>= 1.3.1'
|
21
|
+
s.add_development_dependency 'bundler', '~> 1.0'
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: omniauth-myvr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- CJ Avilla
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: omniauth
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.1.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.1.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: omniauth-oauth2
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.3.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.3.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.0'
|
55
|
+
description: OmniAuth strategy for MyVR
|
56
|
+
email:
|
57
|
+
- cjavilla@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- Gemfile
|
64
|
+
- example/Gemfile
|
65
|
+
- example/auth.js
|
66
|
+
- example/config.ru
|
67
|
+
- example/omni_auth.rb
|
68
|
+
- lib/omniauth/strategies/myvr.rb
|
69
|
+
- lib/omniauth_myvr.rb
|
70
|
+
- omniauth-myvr.gemspec
|
71
|
+
homepage: https://github.com/w1zeman1p/omniauth-myvr
|
72
|
+
licenses:
|
73
|
+
- MIT
|
74
|
+
metadata: {}
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
requirements: []
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 2.4.5.1
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: OmniAuth strategy for MyVR
|
95
|
+
test_files: []
|