doorkeeper-rethinkdb 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 856cb49c0238f249ed8a203b4dfb93bf57b1b2edf2953d47c8d0b1708a74063e
4
+ data.tar.gz: 8b5171dbe6d20e837f8a7b238079dd26b07808db5adc5192cab2439d597449e1
5
+ SHA512:
6
+ metadata.gz: 5a1f0cc85cd8764b277cf4872e9284044305552a4f11f150f537489317689a0523864a917de070e5482f6d83179256c28e37026284a29ac8d6b4a9b76dd138aa
7
+ data.tar.gz: 26b37570029b3087f4a179c5ced78085fb4e952a30aed77830f9143f6a64526c06490d8b701be7b1575bbbce90c487d7a460e922a6b8d3899d7745d451a1343c
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2016 ACAProjects
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # doorkeeper-rethinkdb extension
2
+
3
+ ## Installation
4
+
5
+ doorkeeper-rethinkdb provides doorkeeper support to rethinkdb
6
+ To start using it, add to your Gemfile:
7
+
8
+ ``` ruby
9
+ gem "doorkeeper-rethinkdb"
10
+ ```
11
+
12
+ Run [doorkeeper’s installation generator]:
13
+
14
+ rails generate doorkeeper:install
15
+
16
+ [doorkeeper’s installation generator]: https://github.com/doorkeeper-gem/doorkeeper#installation
17
+
18
+ This will install the doorkeeper initializer into
19
+ `config/initializers/doorkeeper.rb`.
20
+
21
+ Set the ORM configuration:
22
+
23
+ ``` ruby
24
+ Doorkeeper.configure do
25
+ orm :rethinkdb
26
+ end
27
+ ```
28
+
29
+ ## Tests
30
+
31
+ To run tests, clone this repository and run `rake`. It will copy and run
32
+ doorkeeper’s original test suite, after configuring the ORM according to the
33
+ variables defined in `.travis.yml` file.
34
+
35
+
36
+ ---
37
+
38
+ Please refer to https://github.com/doorkeeper-gem/doorkeeper for instructions on
39
+ doorkeeper’s project.
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require 'bundler/setup'
2
+ require 'rspec/core/rake_task'
3
+
4
+ task :load_doorkeeper do
5
+ `rm -rf spec/`
6
+ `git checkout -- spec`
7
+ `git submodule init`
8
+ `git submodule update`
9
+ `cp -r -n doorkeeper/spec .`
10
+ `bundle exec rspec`
11
+ end
12
+
13
+ desc 'Default: run specs.'
14
+ task default: :spec
15
+
16
+ desc 'Clone down doorkeeper specs'
17
+ task spec: :load_doorkeeper
18
+
19
+ RSpec::Core::RakeTask.new(:spec) do |config|
20
+ config.verbose = false
21
+ end
22
+
23
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,7 @@
1
+ require 'doorkeeper-rethinkdb/version'
2
+
3
+ require 'doorkeeper'
4
+ require 'support/orm/rethinkdb'
5
+
6
+ module DoorkeeperRethinkdb
7
+ end
@@ -0,0 +1,3 @@
1
+ module DoorkeeperRethinkdb
2
+ VERSION = "1.1.1"
3
+ end
@@ -0,0 +1,20 @@
1
+ module Doorkeeper
2
+ module Orm
3
+ module Rethinkdb
4
+ def self.initialize_models!
5
+ require 'support/orm/rethinkdb/timestamps'
6
+ require 'support/orm/rethinkdb/scopes'
7
+ require 'support/orm/rethinkdb/access_grant'
8
+ require 'support/orm/rethinkdb/access_token'
9
+ require 'support/orm/rethinkdb/application'
10
+ end
11
+
12
+ def self.initialize_application_owner!
13
+ #require 'doorkeeper/models/concerns/ownership'
14
+ #Doorkeeper::Application.send :include, Doorkeeper::Models::Ownership
15
+ end
16
+
17
+ def self.check_requirements!(_config); end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,122 @@
1
+
2
+ module Doorkeeper
3
+ class AccessGrant
4
+ include NoBrainer::Document
5
+
6
+ table_config name: 'doorkeeper_grant'
7
+
8
+ include OAuth::Helpers
9
+ include Models::Expirable
10
+ include Models::Revocable
11
+ include Models::Accessible
12
+ include Models::Scopes
13
+ include Models::SecretStorable
14
+
15
+ include Timestamps
16
+
17
+ belongs_to :application, class_name: 'Doorkeeper::Application'
18
+
19
+ field :resource_owner_id, type: String
20
+ field :token, type: String, uniq: true, index: true
21
+ field :scopes, type: String
22
+ field :redirect_uri, type: String
23
+
24
+ field :expires_in, type: Integer
25
+ field :ttl, type: Integer
26
+ field :revoked_at, type: Time
27
+
28
+ # PKCE support
29
+ field :code_challenge, type: String
30
+ field :code_challenge_method, type: String
31
+
32
+ index :ttl
33
+
34
+ class << self
35
+ def by_token(token)
36
+ find_by_plaintext_token(:token, token)
37
+ end
38
+
39
+ def find_by_plaintext_token(attr, token)
40
+ # We are not implementing the fallback strategy
41
+ where(attr => secret_strategy.transform_secret(token.to_s)).first
42
+ end
43
+
44
+ # @param code_verifier [#to_s] a one time use value (any object that responds to `#to_s`)
45
+ #
46
+ # @return [#to_s] An encoded code challenge based on the provided verifier
47
+ # suitable for PKCE validation
48
+ #
49
+ def generate_code_challenge(code_verifier)
50
+ padded_result = Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier))
51
+ padded_result.split("=")[0] # Remove any trailing '='
52
+ end
53
+
54
+ def pkce_supported?
55
+ true
56
+ end
57
+
58
+ ##
59
+ # Determines the secret storing transformer
60
+ # Unless configured otherwise, uses the plain secret strategy
61
+ #
62
+ # @return [Doorkeeper::SecretStoring::Base]
63
+ #
64
+ def secret_strategy
65
+ ::Doorkeeper.config.token_secret_strategy
66
+ end
67
+
68
+ ##
69
+ # Determine the fallback storing strategy
70
+ # Unless configured, there will be no fallback
71
+ #
72
+ # @return [Doorkeeper::SecretStoring::Base]
73
+ #
74
+ def fallback_secret_strategy
75
+ ::Doorkeeper.config.token_secret_fallback_strategy
76
+ end
77
+ end
78
+
79
+ validates :resource_owner_id, :application, :token, :expires_in, :redirect_uri, presence: true
80
+ before_validation :generate_token, on: :create
81
+
82
+ def transaction; yield; end
83
+ def lock!; end
84
+
85
+ def uses_pkce?
86
+ self.code_challenge.present?
87
+ end
88
+
89
+ # We keep a volatile copy of the raw token for initial communication
90
+ # The stored refresh_token may be mapped and not available in cleartext.
91
+ #
92
+ # Some strategies allow restoring stored secrets (e.g. symmetric encryption)
93
+ # while hashing strategies do not, so you cannot rely on this value
94
+ # returning a present value for persisted tokens.
95
+ def plaintext_token
96
+ if secret_strategy.allows_restoring_secrets?
97
+ secret_strategy.restore_secret(self, :token)
98
+ else
99
+ @raw_token
100
+ end
101
+ end
102
+
103
+ def revoke(clock = Time)
104
+ self.revoked_at = clock.now.utc
105
+ self.save!
106
+ end
107
+
108
+ private
109
+
110
+ # Generates token value with UniqueToken class.
111
+ #
112
+ # @return [String] token value
113
+ #
114
+ def generate_token
115
+ self.ttl = (self.created_at + self.expires_in + 30).to_i if self.created_at && self.expires_in
116
+ if self.token.blank?
117
+ @raw_token = Doorkeeper::OAuth::Helpers::UniqueToken.generate
118
+ secret_strategy.store_secret(self, :token, @raw_token)
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,376 @@
1
+
2
+ module Doorkeeper
3
+ class AccessToken
4
+ include NoBrainer::Document
5
+
6
+ table_config name: 'doorkeeper_token'
7
+
8
+ include OAuth::Helpers
9
+ include Models::Expirable
10
+ include Models::Reusable
11
+ include Models::Revocable
12
+ include Models::Accessible
13
+ include Models::Scopes
14
+ include Models::SecretStorable
15
+
16
+ include ::Doorkeeper::Rethinkdb::Timestamps
17
+
18
+ attr_writer :use_refresh_token
19
+
20
+ belongs_to :application, class_name: 'Doorkeeper::Application'
21
+
22
+ field :resource_owner_id, type: String, index: true
23
+ field :token, type: String, uniq: true, index: true
24
+ field :refresh_token, type: String, index: true
25
+
26
+ field :scopes, type: String
27
+ field :previous_refresh_token, type: String, default: ->{ '' }
28
+ field :expires_in, type: Integer
29
+ field :ttl, type: Integer
30
+ field :revoked_at, type: Time
31
+
32
+ index :ttl
33
+
34
+ alias :plaintext_token :token
35
+ alias :plaintext_refresh_token :refresh_token
36
+
37
+ validates :resource_owner_id, :application, :expires_in, :token, presence: true
38
+
39
+ class << self
40
+ def refresh_token_revoked_on_use?
41
+ true
42
+ end
43
+
44
+ def find_by_plaintext_token(attr, token)
45
+ # We are not implementing the fallback strategy
46
+ where(attr => secret_strategy.transform_secret(token.to_s)).first
47
+ end
48
+
49
+ # Returns an instance of the Doorkeeper::AccessToken with
50
+ # specific token value.
51
+ #
52
+ # @param token [#to_s]
53
+ # token value (any object that responds to `#to_s`)
54
+ #
55
+ # @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
56
+ # if there is no record with such token
57
+ #
58
+ def by_token(token)
59
+ find_by_plaintext_token(:token, token)
60
+ end
61
+
62
+ # Returns an instance of the Doorkeeper::AccessToken
63
+ # with specific token value.
64
+ #
65
+ # @param refresh_token [#to_s]
66
+ # refresh token value (any object that responds to `#to_s`)
67
+ #
68
+ # @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
69
+ # if there is no record with such refresh token
70
+ #
71
+ def by_refresh_token(refresh_token)
72
+ find_by_plaintext_token(:refresh_token, refresh_token)
73
+ end
74
+
75
+ # Returns an instance of the Doorkeeper::AccessToken
76
+ # found by previous refresh token. Keep in mind that value
77
+ # of the previous_refresh_token isn't encrypted using
78
+ # secrets strategy.
79
+ #
80
+ # @param previous_refresh_token [#to_s]
81
+ # previous refresh token value (any object that responds to `#to_s`)
82
+ #
83
+ # @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
84
+ # if there is no record with such refresh token
85
+ #
86
+ def by_previous_refresh_token(previous_refresh_token)
87
+ return nil unless previous_refresh_token.present?
88
+ where(previous_refresh_token: previous_refresh_token).first
89
+ end
90
+
91
+ # Revokes AccessToken records that have not been revoked and associated
92
+ # with the specific Application and Resource Owner.
93
+ #
94
+ # @param application_id [Integer]
95
+ # ID of the Application
96
+ # @param resource_owner [ActiveRecord::Base]
97
+ # instance of the Resource Owner model
98
+ #
99
+ def revoke_all_for(application_id, resource_owner)
100
+ where(application_id: application_id, resource_owner_id: resource_owner.id).each do |at|
101
+ at.revoke
102
+ end
103
+ end
104
+
105
+ # Looking for not revoked Access Token record that belongs to specific
106
+ # Application and Resource Owner.
107
+ #
108
+ # @param application_id [Integer]
109
+ # ID of the Application model instance
110
+ # @param resource_owner_id [Integer]
111
+ # ID of the Resource Owner model instance
112
+ #
113
+ # @return [Doorkeeper::AccessToken, nil] matching AccessToken object or
114
+ # nil if nothing was found
115
+ #
116
+ def last_authorized_token_for(application_id, resource_owner_id)
117
+ resource_owner_id = resource_owner_id.try(:id) || resource_owner_id
118
+ result = where(application_id: application_id, resource_owner_id: resource_owner_id).last
119
+ return nil unless result
120
+ result[:revoked_at] ? nil : result
121
+ end
122
+
123
+ # Looking for not expired Access Token with a matching set of scopes
124
+ # that belongs to specific Application and Resource Owner.
125
+ #
126
+ # @param application [Doorkeeper::Application]
127
+ # Application instance
128
+ # @param resource_owner_or_id [ActiveRecord::Base, Integer]
129
+ # Resource Owner model instance or it's ID
130
+ # @param scopes [String, Doorkeeper::OAuth::Scopes]
131
+ # set of scopes
132
+ #
133
+ # @return [Doorkeeper::AccessToken, nil] Access Token instance or
134
+ # nil if matching record was not found
135
+ #
136
+ def matching_token_for(application, resource_owner_or_id, scopes)
137
+ resource_owner_id = resource_owner_or_id.try(:id) || resource_owner_or_id
138
+ token = last_authorized_token_for(application.try(:id), resource_owner_id)
139
+ if token && scopes_match?(token.scopes, scopes, application.try(:scopes))
140
+ token
141
+ end
142
+ end
143
+
144
+ # Checks whether the token scopes match the scopes from the parameters or
145
+ # Application scopes (if present).
146
+ #
147
+ # @param token_scopes [#to_s]
148
+ # set of scopes (any object that responds to `#to_s`)
149
+ # @param param_scopes [String]
150
+ # scopes from params
151
+ # @param app_scopes [String]
152
+ # Application scopes
153
+ #
154
+ # @return [Boolean] true if all scopes and blank or matches
155
+ # and false in other cases
156
+ #
157
+ def scopes_match?(token_scopes, param_scopes, app_scopes)
158
+ (!token_scopes.present? && !param_scopes.present?) ||
159
+ Doorkeeper::OAuth::Helpers::ScopeChecker.match?(
160
+ token_scopes.to_s,
161
+ param_scopes,
162
+ app_scopes
163
+ )
164
+ end
165
+
166
+ # Looking for not expired AccessToken record with a matching set of
167
+ # scopes that belongs to specific Application and Resource Owner.
168
+ # If it doesn't exists - then creates it.
169
+ #
170
+ # @param application [Doorkeeper::Application]
171
+ # Application instance
172
+ # @param resource_owner_id [ActiveRecord::Base, Integer]
173
+ # Resource Owner model instance or it's ID
174
+ # @param scopes [#to_s]
175
+ # set of scopes (any object that responds to `#to_s`)
176
+ # @param expires_in [Integer]
177
+ # token lifetime in seconds
178
+ # @param use_refresh_token [Boolean]
179
+ # whether to use the refresh token
180
+ #
181
+ # @return [Doorkeeper::AccessToken] existing record or a new one
182
+ #
183
+ def find_or_create_for(application:, resource_owner:, scopes:, **token_attributes)
184
+ resource_owner = resource_owner.try(:id) || resource_owner
185
+
186
+ if Doorkeeper.config.reuse_access_token
187
+ access_token = matching_token_for(application, resource_owner, scopes)
188
+
189
+ return access_token if access_token&.reusable?
190
+ end
191
+
192
+ create!(
193
+ application_id: application.try(:id),
194
+ resource_owner_id: resource_owner || application.try(:owner_id),
195
+ scopes: scopes.to_s,
196
+ **token_attributes,
197
+ )
198
+ end
199
+
200
+ def create_for(application:, resource_owner:, scopes:, **token_attributes)
201
+ token_attributes[:application_id] = application&.id
202
+ token_attributes[:scopes] = scopes.to_s
203
+
204
+ resource_owner = resource_owner.try(:id) || resource_owner
205
+ token_attributes[:resource_owner_id] = resource_owner || application.try(:owner_id)
206
+
207
+ create!(**token_attributes)
208
+ end
209
+
210
+ ##
211
+ # Determines the secret storing transformer
212
+ # Unless configured otherwise, uses the plain secret strategy
213
+ #
214
+ # @return [Doorkeeper::SecretStoring::Base]
215
+ #
216
+ def secret_strategy
217
+ ::Doorkeeper.config.token_secret_strategy
218
+ end
219
+
220
+ ##
221
+ # Determine the fallback storing strategy
222
+ # Unless configured, there will be no fallback
223
+ def fallback_secret_strategy
224
+ ::Doorkeeper.config.token_secret_fallback_strategy
225
+ end
226
+ end
227
+
228
+ # Access Token type: Bearer.
229
+ # @see https://tools.ietf.org/html/rfc6750
230
+ # The OAuth 2.0 Authorization Framework: Bearer Token Usage
231
+ #
232
+ def token_type
233
+ 'bearer'
234
+ end
235
+
236
+ def use_refresh_token?
237
+ @use_refresh_token ||= false
238
+ !!@use_refresh_token
239
+ end
240
+
241
+ # JSON representation of the Access Token instance.
242
+ #
243
+ # @return [Hash] hash with token data
244
+ def as_json(_options = {})
245
+ {
246
+ resource_owner_id: resource_owner_id,
247
+ scopes: scopes,
248
+ expires_in_seconds: expires_in_seconds,
249
+ application: { uid: application.try(:uid) },
250
+ created_at: created_at.to_i
251
+ }
252
+ end
253
+
254
+ # Indicates whether the token instance have the same credential
255
+ # as the other Access Token.
256
+ #
257
+ # @param access_token [Doorkeeper::AccessToken] other token
258
+ #
259
+ # @return [Boolean] true if credentials are same of false in other cases
260
+ #
261
+ def same_credential?(access_token)
262
+ application_id == access_token.application_id &&
263
+ resource_owner_id == access_token.resource_owner_id
264
+ end
265
+
266
+ # Indicates if token is acceptable for specific scopes.
267
+ #
268
+ # @param scopes [Array<String>] scopes
269
+ #
270
+ # @return [Boolean] true if record is accessible and includes scopes or
271
+ # false in other cases
272
+ #
273
+ def acceptable?(scopes)
274
+ accessible? && includes_scope?(*scopes)
275
+ end
276
+
277
+ # We keep a volatile copy of the raw refresh token for initial communication
278
+ # The stored refresh_token may be mapped and not available in cleartext.
279
+ def plaintext_refresh_token
280
+ if secret_strategy.allows_restoring_secrets?
281
+ secret_strategy.restore_secret(self, :refresh_token)
282
+ else
283
+ @raw_refresh_token
284
+ end
285
+ end
286
+
287
+ # We keep a volatile copy of the raw token for initial communication
288
+ # The stored refresh_token may be mapped and not available in cleartext.
289
+ #
290
+ # Some strategies allow restoring stored secrets (e.g. symmetric encryption)
291
+ # while hashing strategies do not, so you cannot rely on this value
292
+ # returning a present value for persisted tokens.
293
+ def plaintext_token
294
+ if secret_strategy.allows_restoring_secrets?
295
+ secret_strategy.restore_secret(self, :token)
296
+ else
297
+ @raw_token
298
+ end
299
+ end
300
+
301
+ # Revokes token with `:refresh_token` equal to `:previous_refresh_token`
302
+ # and clears `:previous_refresh_token` attribute.
303
+ #
304
+ def revoke_previous_refresh_token!
305
+ return unless self.class.refresh_token_revoked_on_use?
306
+ self.previous_refresh_token = ''
307
+ self.save!
308
+ end
309
+
310
+ def revoke(clock = Time)
311
+ self.revoked_at = clock.now.utc
312
+ self.save!
313
+ end
314
+
315
+ def transaction; yield; end
316
+ def lock!; end
317
+
318
+ private
319
+
320
+ before_validation :generate_token, on: :create
321
+ before_validation :generate_refresh_token, on: :create, if: :use_refresh_token?
322
+
323
+ validate :refresh_token_unique
324
+
325
+ def refresh_token_unique
326
+ if refresh_token_changed? && refresh_token.present? && ::Doorkeeper::AccessToken.where(refresh_token: refresh_token).count > 0
327
+ errors.add(:refresh_token, "must be unique")
328
+ end
329
+ end
330
+
331
+ # Generates refresh token with UniqueToken generator.
332
+ #
333
+ # @return [String] refresh token value
334
+ #
335
+ def generate_refresh_token
336
+ if self.refresh_token.blank?
337
+ @raw_refresh_token = UniqueToken.generate
338
+ secret_strategy.store_secret(self, :refresh_token, @raw_refresh_token)
339
+ end
340
+ end
341
+
342
+ def generate_token
343
+ return if self.token.present?
344
+
345
+ self.created_at ||= Time.now.utc
346
+
347
+ if use_refresh_token?
348
+ self.ttl = (self.created_at + 1.months).to_i
349
+ else
350
+ self.ttl = (self.created_at + self.expires_in + 30).to_i
351
+ end
352
+
353
+ generator = Doorkeeper.configuration.access_token_generator.constantize
354
+ @raw_token = generator.generate(
355
+ resource_owner_id: resource_owner_id,
356
+ scopes: scopes,
357
+ application: application,
358
+ expires_in: expires_in,
359
+ created_at: created_at
360
+ )
361
+ secret_strategy.store_secret(self, :token, @raw_token)
362
+ @raw_token
363
+ rescue NoMethodError
364
+ raise Errors::UnableToGenerateToken, "#{generator} does not respond to `.generate`."
365
+ rescue NameError
366
+ raise Errors::TokenGeneratorNotFound, "#{generator} not found"
367
+ end
368
+ end
369
+
370
+ # # Skips validation if field is empty
371
+ # class UniqueOrEmptyValidator < UniquenessValidator
372
+ # def validate_each(doc, attr, value)
373
+ # super if value
374
+ # end
375
+ # end
376
+ end
@@ -0,0 +1,93 @@
1
+
2
+ # Load these before the has_many
3
+ require File.expand_path("../access_grant", __FILE__)
4
+ require File.expand_path("../access_token", __FILE__)
5
+
6
+ # Required for Rails 6 support
7
+ require "doorkeeper/orm/active_record/redirect_uri_validator"
8
+
9
+ module Doorkeeper
10
+ class Application
11
+ include NoBrainer::Document
12
+
13
+ table_config name: 'doorkeeper_app'
14
+
15
+ include OAuth::Helpers
16
+ include Models::Scopes
17
+
18
+ field :name, type: String
19
+ field :uid, type: String, uniq: true, index: true
20
+ field :secret, type: String
21
+ field :scopes, type: String
22
+ field :redirect_uri, type: String, uniq: true, index: true
23
+
24
+ field :skip_authorization, type: Boolean, default: false
25
+ field :confidential, type: Boolean, default: false
26
+
27
+ field :owner_id, type: String
28
+
29
+ validates :owner, presence: true, if: :validate_owner?
30
+ def validate_owner?
31
+ Doorkeeper.configuration.confirm_application_owner?
32
+ end
33
+
34
+ has_many :access_grants, dependent: :destroy, class_name: 'Doorkeeper::AccessGrant'
35
+ has_many :access_tokens, dependent: :destroy, class_name: 'Doorkeeper::AccessToken'
36
+
37
+ class << self
38
+ def by_uid(uid)
39
+ where(uid: uid).first
40
+ end
41
+
42
+ def by_uid_and_secret(uid, secret)
43
+ where(uid: uid, secret: secret).first
44
+ end
45
+
46
+ def by_uid_and_secret(uid, secret)
47
+ app = by_uid(uid)
48
+ return unless app
49
+ return app if secret.blank? && !app.confidential?
50
+ return unless app.secret_matches?(secret)
51
+
52
+ app
53
+ end
54
+
55
+ def authorized_for(resource_owner)
56
+ AccessToken.find_by_resource_owner_id(resource_owner.id).collect(&:application)
57
+ end
58
+ end
59
+
60
+ def authorized_for_resource_owner?(resource_owner)
61
+ Doorkeeper.configuration.authorize_resource_owner_for_client.call(self, resource_owner)
62
+ end
63
+
64
+ def secret_matches?(input)
65
+ # return false if either is nil, since secure_compare depends on strings
66
+ # but Application secrets MAY be nil depending on confidentiality.
67
+ return false if input.nil? || secret.nil?
68
+
69
+ # When matching the secret by comparer function, all is well.
70
+ input == secret
71
+ end
72
+
73
+ private
74
+
75
+ validates :name, :secret, :uid, presence: true
76
+ validates :redirect_uri, "doorkeeper/redirect_uri": true
77
+ validates :confidential, inclusion: { in: [true, false] }
78
+
79
+ before_validation :generate_uid, :generate_secret, on: :create
80
+
81
+ def has_scopes?
82
+ true
83
+ end
84
+
85
+ def generate_uid
86
+ self.uid = UniqueToken.generate if uid.blank?
87
+ end
88
+
89
+ def generate_secret
90
+ self.secret = UniqueToken.generate if secret.blank?
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,22 @@
1
+
2
+ module Doorkeeper
3
+ # Reopen to align with NoBrainer's exclusively `super` overrides.
4
+ # ORM is thrust into an infinite loop, otherwise.
5
+ module Models::Scopes
6
+ def scopes
7
+ OAuth::Scopes.from_string(super)
8
+ end
9
+
10
+ def scopes=(value)
11
+ super Array(value).join(" ")
12
+ end
13
+
14
+ def scopes_string
15
+ self._read_attribute(:scopes)
16
+ end
17
+
18
+ def includes_scope?(*required_scopes)
19
+ required_scopes.blank? || required_scopes.any? { |scope| scopes.exists?(scope.to_s) }
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,32 @@
1
+ require 'date'
2
+
3
+ module Doorkeeper
4
+ module Rethinkdb
5
+ module Timestamps
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ field :revoked_at, type: Integer
10
+ field :created_at, type: Integer, default: ->{ Time.now.to_i + 1 }
11
+ end
12
+
13
+ def revoked_at
14
+ revoked = super
15
+ Time.at(revoked) unless revoked.nil?
16
+ end
17
+
18
+ def revoked_at=(time)
19
+ if time
20
+ number = time.is_a?(Numeric) ? time.to_i : time.to_time.to_i
21
+ super number
22
+ else
23
+ super nil
24
+ end
25
+ end
26
+
27
+ def created_at
28
+ Time.at(super)
29
+ end
30
+ end
31
+ end
32
+ end
metadata ADDED
@@ -0,0 +1,207 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: doorkeeper-rethinkdb
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Stephen von Takach
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-08-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: doorkeeper
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 4.0.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '6'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 4.0.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '6'
33
+ - !ruby/object:Gem::Dependency
34
+ name: nobrainer
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 0.33.0
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '1'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 0.33.0
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '1'
53
+ - !ruby/object:Gem::Dependency
54
+ name: sqlite3
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ type: :development
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ - !ruby/object:Gem::Dependency
68
+ name: capybara
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ - !ruby/object:Gem::Dependency
82
+ name: database_cleaner
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '1.5'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '1.5'
95
+ - !ruby/object:Gem::Dependency
96
+ name: factory_girl
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '4.7'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '4.7'
109
+ - !ruby/object:Gem::Dependency
110
+ name: generator_spec
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '0.9'
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '0.9'
123
+ - !ruby/object:Gem::Dependency
124
+ name: rake
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: 12.3.3
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: 12.3.3
137
+ - !ruby/object:Gem::Dependency
138
+ name: rspec-rails
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - "~>"
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ type: :development
145
+ prerelease: false
146
+ version_requirements: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - "~>"
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ - !ruby/object:Gem::Dependency
152
+ name: timecop
153
+ requirement: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - "~>"
156
+ - !ruby/object:Gem::Version
157
+ version: '0.8'
158
+ type: :development
159
+ prerelease: false
160
+ version_requirements: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - "~>"
163
+ - !ruby/object:Gem::Version
164
+ version: '0.8'
165
+ description: Doorkeeper RethinkDB ORMs
166
+ email:
167
+ - steve@aca.im
168
+ executables: []
169
+ extensions: []
170
+ extra_rdoc_files: []
171
+ files:
172
+ - MIT-LICENSE
173
+ - README.md
174
+ - Rakefile
175
+ - lib/doorkeeper-rethinkdb.rb
176
+ - lib/doorkeeper-rethinkdb/version.rb
177
+ - lib/support/orm/rethinkdb.rb
178
+ - lib/support/orm/rethinkdb/access_grant.rb
179
+ - lib/support/orm/rethinkdb/access_token.rb
180
+ - lib/support/orm/rethinkdb/application.rb
181
+ - lib/support/orm/rethinkdb/scopes.rb
182
+ - lib/support/orm/rethinkdb/timestamps.rb
183
+ homepage: http://github.com/aca-labs/doorkeeper-rethinkdb
184
+ licenses:
185
+ - MIT
186
+ metadata: {}
187
+ post_install_message:
188
+ rdoc_options: []
189
+ require_paths:
190
+ - lib
191
+ required_ruby_version: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ required_rubygems_version: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ requirements: []
202
+ rubyforge_project:
203
+ rubygems_version: 2.7.7
204
+ signing_key:
205
+ specification_version: 4
206
+ summary: Doorkeeper RethinkDB ORMs
207
+ test_files: []