super-smart-kit 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/doorkeeper-5.9.3/CHANGELOG.md +1208 -0
- data/doorkeeper-5.9.3/MIT-LICENSE +20 -0
- data/doorkeeper-5.9.3/README.md +186 -0
- data/doorkeeper-5.9.3/app/assets/stylesheets/doorkeeper/admin/application.css +10 -0
- data/doorkeeper-5.9.3/app/assets/stylesheets/doorkeeper/application.css +64 -0
- data/doorkeeper-5.9.3/app/controllers/doorkeeper/application_controller.rb +14 -0
- data/doorkeeper-5.9.3/app/controllers/doorkeeper/application_metal_controller.rb +13 -0
- data/doorkeeper-5.9.3/app/controllers/doorkeeper/applications_controller.rb +99 -0
- data/doorkeeper-5.9.3/app/controllers/doorkeeper/authorizations_controller.rb +164 -0
- data/doorkeeper-5.9.3/app/controllers/doorkeeper/authorized_applications_controller.rb +33 -0
- data/doorkeeper-5.9.3/app/controllers/doorkeeper/token_info_controller.rb +25 -0
- data/doorkeeper-5.9.3/app/controllers/doorkeeper/tokens_controller.rb +180 -0
- data/doorkeeper-5.9.3/app/helpers/doorkeeper/dashboard_helper.rb +21 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/applications/_delete_form.html.erb +6 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/applications/_form.html.erb +59 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/applications/edit.html.erb +5 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/applications/index.html.erb +38 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/applications/new.html.erb +5 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/applications/show.html.erb +63 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/authorizations/error.html.erb +9 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/authorizations/new.html.erb +46 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/authorizations/show.html.erb +7 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +4 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/authorized_applications/index.html.erb +24 -0
- data/doorkeeper-5.9.3/app/views/layouts/doorkeeper/admin.html.erb +39 -0
- data/doorkeeper-5.9.3/app/views/layouts/doorkeeper/application.html.erb +23 -0
- data/doorkeeper-5.9.3/config/locales/en.yml +155 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/config/abstract_builder.rb +28 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/config/option.rb +82 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/config/validations.rb +65 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/config.rb +721 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/engine.rb +38 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/errors.rb +85 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/grant_flow/flow.rb +44 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/grant_flow/registry.rb +50 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/grant_flow.rb +45 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/grape/authorization_decorator.rb +19 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/grape/helpers.rb +58 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/helpers/controller.rb +91 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/access_grant_mixin.rb +124 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/access_token_mixin.rb +526 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/application_mixin.rb +96 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/accessible.rb +15 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/expirable.rb +36 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/expiration_time_sql_math.rb +96 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/orderable.rb +15 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/ownership.rb +18 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/polymorphic_resource_owner.rb +29 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/reusable.rb +19 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/revocable.rb +31 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/scopes.rb +27 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/write_to_primary.rb +57 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/authorization/code.rb +76 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/authorization/context.rb +17 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/authorization/token.rb +100 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/authorization/uri_builder.rb +33 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/authorization_code_request.rb +125 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/base_request.rb +68 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/base_response.rb +31 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client/credentials.rb +34 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client.rb +28 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client_credentials/creator.rb +57 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client_credentials/issuer.rb +48 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client_credentials/validator.rb +55 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client_credentials_request.rb +46 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/code_request.rb +25 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/code_response.rb +51 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/error.rb +16 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/error_response.rb +121 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/forbidden_token_response.rb +31 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/helpers/scope_checker.rb +50 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/helpers/unique_token.rb +30 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/helpers/uri_checker.rb +83 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/hooks/context.rb +21 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/invalid_request_response.rb +47 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/invalid_token_response.rb +54 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/nonstandard.rb +39 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/password_access_token_request.rb +75 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/pre_authorization.rb +187 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/refresh_token_request.rb +144 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/scopes.rb +134 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/token.rb +66 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/token_introspection.rb +220 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/token_request.rb +25 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/token_response.rb +38 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth.rb +13 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/access_grant.rb +9 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/access_token.rb +9 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/application.rb +10 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +64 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/mixins/access_token.rb +95 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/mixins/application.rb +223 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +44 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record.rb +41 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rails/helpers.rb +82 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rails/routes/mapper.rb +30 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rails/routes/mapping.rb +40 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rails/routes/registry.rb +45 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rails/routes.rb +110 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rake/db.rake +40 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rake/setup.rake +6 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rake.rb +14 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/request/authorization_code.rb +26 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/request/client_credentials.rb +17 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/request/code.rb +17 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/request/password.rb +19 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/request/refresh_token.rb +22 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/request/strategy.rb +19 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/request/token.rb +17 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/request.rb +73 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/revocable_tokens/revocable_access_token.rb +21 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/revocable_tokens/revocable_refresh_token.rb +21 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/secret_storing/base.rb +64 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/secret_storing/plain.rb +33 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/server.rb +44 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/stale_records_cleaner.rb +24 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/validations.rb +33 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/version.rb +14 -0
- data/doorkeeper-5.9.3/lib/doorkeeper.rb +209 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/application_owner_generator.rb +33 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/install_generator.rb +22 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/migration_generator.rb +32 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/pkce_generator.rb +33 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/previous_refresh_token_generator.rb +41 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/remove_applications_secret_not_null_constraint_generator.rb +33 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/README +24 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +9 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +13 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/initializer.rb +544 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/migration.rb.erb +99 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/remove_applications_secret_not_null_constraint.rb.erb +7 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/views_generator.rb +18 -0
- data/doorkeeper-5.9.3/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +6 -0
- data/super-smart-kit.gemspec +12 -0
- metadata +188 -0
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
module AccessTokenMixin
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
include OAuth::Helpers
|
|
8
|
+
include Models::Expirable
|
|
9
|
+
include Models::Reusable
|
|
10
|
+
include Models::Revocable
|
|
11
|
+
include Models::Accessible
|
|
12
|
+
include Models::Orderable
|
|
13
|
+
include Models::SecretStorable
|
|
14
|
+
include Models::Scopes
|
|
15
|
+
include Models::ResourceOwnerable
|
|
16
|
+
include Models::ExpirationTimeSqlMath
|
|
17
|
+
include Models::Concerns::WriteToPrimary
|
|
18
|
+
|
|
19
|
+
module ClassMethods
|
|
20
|
+
# Returns an instance of the Doorkeeper::AccessToken with
|
|
21
|
+
# specific plain text token value.
|
|
22
|
+
#
|
|
23
|
+
# @param token [#to_s]
|
|
24
|
+
# Plain text token value (any object that responds to `#to_s`)
|
|
25
|
+
#
|
|
26
|
+
# @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
|
|
27
|
+
# if there is no record with such token
|
|
28
|
+
#
|
|
29
|
+
def by_token(token)
|
|
30
|
+
find_by_plaintext_token(:token, token)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns an instance of the Doorkeeper::AccessToken
|
|
34
|
+
# with specific token value.
|
|
35
|
+
#
|
|
36
|
+
# @param refresh_token [#to_s]
|
|
37
|
+
# refresh token value (any object that responds to `#to_s`)
|
|
38
|
+
#
|
|
39
|
+
# @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
|
|
40
|
+
# if there is no record with such refresh token
|
|
41
|
+
#
|
|
42
|
+
def by_refresh_token(refresh_token)
|
|
43
|
+
find_by_plaintext_token(:refresh_token, refresh_token)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns an instance of the Doorkeeper::AccessToken
|
|
47
|
+
# found by previous refresh token. Keep in mind that value
|
|
48
|
+
# of the previous_refresh_token isn't encrypted using
|
|
49
|
+
# secrets strategy.
|
|
50
|
+
#
|
|
51
|
+
# @param previous_refresh_token [#to_s]
|
|
52
|
+
# previous refresh token value (any object that responds to `#to_s`)
|
|
53
|
+
#
|
|
54
|
+
# @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
|
|
55
|
+
# if there is no record with such refresh token
|
|
56
|
+
#
|
|
57
|
+
def by_previous_refresh_token(previous_refresh_token)
|
|
58
|
+
find_by(refresh_token: previous_refresh_token)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Revokes AccessToken records that have not been revoked and associated
|
|
62
|
+
# with the specific Application and Resource Owner.
|
|
63
|
+
#
|
|
64
|
+
# @param application_id [Integer]
|
|
65
|
+
# ID of the Application
|
|
66
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
|
67
|
+
# instance of the Resource Owner model or it's ID
|
|
68
|
+
#
|
|
69
|
+
def revoke_all_for(application_id, resource_owner, clock = Time)
|
|
70
|
+
with_primary_role do
|
|
71
|
+
by_resource_owner(resource_owner)
|
|
72
|
+
.where(
|
|
73
|
+
application_id: application_id,
|
|
74
|
+
revoked_at: nil,
|
|
75
|
+
)
|
|
76
|
+
.update_all(revoked_at: clock.now.utc)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Looking for not revoked Access Token with a matching set of scopes
|
|
81
|
+
# that belongs to specific Application and Resource Owner.
|
|
82
|
+
#
|
|
83
|
+
# @param application [Doorkeeper::Application]
|
|
84
|
+
# Application instance
|
|
85
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
|
86
|
+
# Resource Owner model instance or it's ID
|
|
87
|
+
# @param scopes [String, Doorkeeper::OAuth::Scopes]
|
|
88
|
+
# set of scopes
|
|
89
|
+
# @param custom_attributes [Nilable Hash]
|
|
90
|
+
# A nil value, or hash with keys corresponding to the custom attributes
|
|
91
|
+
# configured with the `custom_access_token_attributes` config option.
|
|
92
|
+
# A nil value will ignore custom attributes.
|
|
93
|
+
#
|
|
94
|
+
# @return [Doorkeeper::AccessToken, nil] Access Token instance or
|
|
95
|
+
# nil if matching record was not found
|
|
96
|
+
#
|
|
97
|
+
def matching_token_for(application, resource_owner, scopes, custom_attributes: nil, include_expired: true)
|
|
98
|
+
tokens = authorized_tokens_for(application&.id, resource_owner)
|
|
99
|
+
tokens = tokens.not_expired unless include_expired
|
|
100
|
+
find_matching_token(tokens, application, custom_attributes, scopes)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Interface to enumerate access token records in batches in order not
|
|
104
|
+
# to bloat the memory. Could be overloaded in any ORM extension.
|
|
105
|
+
#
|
|
106
|
+
def find_access_token_in_batches(relation, **args, &block)
|
|
107
|
+
relation.find_in_batches(**args, &block)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Enumerates AccessToken records in batches to find a matching token.
|
|
111
|
+
# Batching is required in order not to pollute the memory if Application
|
|
112
|
+
# has huge amount of associated records.
|
|
113
|
+
#
|
|
114
|
+
# ActiveRecord 5.x - 6.x ignores custom ordering so we can't perform a
|
|
115
|
+
# database sort by created_at, so we need to load all the matching records,
|
|
116
|
+
# sort them and find latest one.
|
|
117
|
+
#
|
|
118
|
+
# @param relation [ActiveRecord::Relation]
|
|
119
|
+
# Access tokens relation
|
|
120
|
+
# @param application [Doorkeeper::Application]
|
|
121
|
+
# Application instance
|
|
122
|
+
# @param scopes [String, Doorkeeper::OAuth::Scopes]
|
|
123
|
+
# set of scopes
|
|
124
|
+
# @param custom_attributes [Nilable Hash]
|
|
125
|
+
# A nil value, or hash with keys corresponding to the custom attributes
|
|
126
|
+
# configured with the `custom_access_token_attributes` config option.
|
|
127
|
+
# A nil value will ignore custom attributes.
|
|
128
|
+
#
|
|
129
|
+
# @return [Doorkeeper::AccessToken, nil] Access Token instance or
|
|
130
|
+
# nil if matching record was not found
|
|
131
|
+
#
|
|
132
|
+
def find_matching_token(relation, application, custom_attributes, scopes)
|
|
133
|
+
return nil unless relation
|
|
134
|
+
|
|
135
|
+
matching_tokens = []
|
|
136
|
+
batch_size = Doorkeeper.configuration.token_lookup_batch_size
|
|
137
|
+
|
|
138
|
+
find_access_token_in_batches(relation, batch_size: batch_size) do |batch|
|
|
139
|
+
tokens = batch.select do |token|
|
|
140
|
+
scopes_match?(token.scopes, scopes, application&.scopes) &&
|
|
141
|
+
custom_attributes_match?(token, custom_attributes)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
matching_tokens.concat(tokens)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
matching_tokens.max_by(&:created_at)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Checks whether the token scopes match the scopes from the parameters
|
|
151
|
+
#
|
|
152
|
+
# @param token_scopes [#to_s]
|
|
153
|
+
# set of scopes (any object that responds to `#to_s`)
|
|
154
|
+
# @param param_scopes [Doorkeeper::OAuth::Scopes]
|
|
155
|
+
# scopes from params
|
|
156
|
+
# @param app_scopes [Doorkeeper::OAuth::Scopes]
|
|
157
|
+
# Application scopes
|
|
158
|
+
#
|
|
159
|
+
# @return [Boolean] true if the param scopes match the token scopes,
|
|
160
|
+
# and all the param scopes are defined in the application (or in the
|
|
161
|
+
# server configuration if the application doesn't define any scopes),
|
|
162
|
+
# and false in other cases
|
|
163
|
+
#
|
|
164
|
+
def scopes_match?(token_scopes, param_scopes, app_scopes)
|
|
165
|
+
return true if token_scopes.empty? && param_scopes.empty?
|
|
166
|
+
|
|
167
|
+
(token_scopes.sort == param_scopes.sort) &&
|
|
168
|
+
Doorkeeper::OAuth::Helpers::ScopeChecker.valid?(
|
|
169
|
+
scope_str: param_scopes.to_s,
|
|
170
|
+
server_scopes: Doorkeeper.config.scopes,
|
|
171
|
+
app_scopes: app_scopes,
|
|
172
|
+
)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Checks whether the token custom attribute values match the custom
|
|
176
|
+
# attributes from the parameters.
|
|
177
|
+
#
|
|
178
|
+
# @param token [Doorkeeper::AccessToken]
|
|
179
|
+
# The access token whose custom attributes are being compared
|
|
180
|
+
# to the custom_attributes.
|
|
181
|
+
#
|
|
182
|
+
# @param custom_attributes [Hash]
|
|
183
|
+
# A hash of the attributes for which we want to determine whether
|
|
184
|
+
# the token's custom attributes match.
|
|
185
|
+
#
|
|
186
|
+
# @return [Boolean] true if the token's custom attribute values
|
|
187
|
+
# match those in the custom_attributes, or if both are empty/blank.
|
|
188
|
+
# False otherwise.
|
|
189
|
+
def custom_attributes_match?(token, custom_attributes)
|
|
190
|
+
return true if custom_attributes.nil?
|
|
191
|
+
|
|
192
|
+
token_attribs = token.custom_attributes
|
|
193
|
+
return true if token_attribs.blank? && custom_attributes.blank?
|
|
194
|
+
|
|
195
|
+
Doorkeeper.config.custom_access_token_attributes.all? do |attribute|
|
|
196
|
+
token_attribs[attribute] == custom_attributes[attribute]
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Looking for not expired AccessToken record with a matching set of
|
|
201
|
+
# scopes that belongs to specific Application and Resource Owner.
|
|
202
|
+
# If it doesn't exists - then creates it.
|
|
203
|
+
#
|
|
204
|
+
# @param application [Doorkeeper::Application]
|
|
205
|
+
# Application instance
|
|
206
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
|
207
|
+
# Resource Owner model instance or it's ID
|
|
208
|
+
# @param scopes [#to_s]
|
|
209
|
+
# set of scopes (any object that responds to `#to_s`)
|
|
210
|
+
# @param token_attributes [Hash]
|
|
211
|
+
# Additional attributes to use when creating a token
|
|
212
|
+
# @option token_attributes [Integer] :expires_in
|
|
213
|
+
# token lifetime in seconds
|
|
214
|
+
# @option token_attributes [Boolean] :use_refresh_token
|
|
215
|
+
# whether to use the refresh token
|
|
216
|
+
#
|
|
217
|
+
# @return [Doorkeeper::AccessToken] existing record or a new one
|
|
218
|
+
#
|
|
219
|
+
def find_or_create_for(application:, resource_owner:, scopes:, **token_attributes)
|
|
220
|
+
scopes = Doorkeeper::OAuth::Scopes.from_string(scopes) if scopes.is_a?(String)
|
|
221
|
+
|
|
222
|
+
if Doorkeeper.config.reuse_access_token
|
|
223
|
+
custom_attributes = extract_custom_attributes(token_attributes).presence
|
|
224
|
+
access_token = matching_token_for(
|
|
225
|
+
application, resource_owner, scopes, custom_attributes: custom_attributes, include_expired: false,
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
return access_token if access_token&.reusable?
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
create_for(
|
|
232
|
+
application: application,
|
|
233
|
+
resource_owner: resource_owner,
|
|
234
|
+
scopes: scopes,
|
|
235
|
+
**token_attributes,
|
|
236
|
+
)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Creates a not expired AccessToken record with a matching set of
|
|
240
|
+
# scopes that belongs to specific Application and Resource Owner.
|
|
241
|
+
#
|
|
242
|
+
# @param application [Doorkeeper::Application]
|
|
243
|
+
# Application instance
|
|
244
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
|
245
|
+
# Resource Owner model instance or it's ID
|
|
246
|
+
# @param scopes [#to_s]
|
|
247
|
+
# set of scopes (any object that responds to `#to_s`)
|
|
248
|
+
# @param token_attributes [Hash]
|
|
249
|
+
# Additional attributes to use when creating a token
|
|
250
|
+
# @option token_attributes [Integer] :expires_in
|
|
251
|
+
# token lifetime in seconds
|
|
252
|
+
# @option token_attributes [Boolean] :use_refresh_token
|
|
253
|
+
# whether to use the refresh token
|
|
254
|
+
#
|
|
255
|
+
# @return [Doorkeeper::AccessToken] new access token
|
|
256
|
+
#
|
|
257
|
+
def create_for(application:, resource_owner:, scopes:, **token_attributes)
|
|
258
|
+
token_attributes[:application] = application
|
|
259
|
+
token_attributes[:scopes] = scopes.to_s
|
|
260
|
+
|
|
261
|
+
if Doorkeeper.config.polymorphic_resource_owner?
|
|
262
|
+
token_attributes[:resource_owner] = resource_owner
|
|
263
|
+
else
|
|
264
|
+
token_attributes[:resource_owner_id] = resource_owner_id_for(resource_owner)
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
with_primary_role do
|
|
268
|
+
create!(token_attributes)
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Looking for not revoked Access Token records that belongs to specific
|
|
273
|
+
# Application and Resource Owner.
|
|
274
|
+
#
|
|
275
|
+
# @param application_id [Integer]
|
|
276
|
+
# ID of the Application model instance
|
|
277
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
|
278
|
+
# Resource Owner model instance or it's ID
|
|
279
|
+
#
|
|
280
|
+
# @return [ActiveRecord::Relation]
|
|
281
|
+
# collection of matching AccessToken objects
|
|
282
|
+
#
|
|
283
|
+
def authorized_tokens_for(application_id, resource_owner)
|
|
284
|
+
by_resource_owner(resource_owner).where(
|
|
285
|
+
application_id: application_id,
|
|
286
|
+
revoked_at: nil,
|
|
287
|
+
)
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# Convenience method for backwards-compatibility, return the last
|
|
291
|
+
# matching token for the given Application and Resource Owner.
|
|
292
|
+
#
|
|
293
|
+
# @param application_id [Integer]
|
|
294
|
+
# ID of the Application model instance
|
|
295
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
|
296
|
+
# ID of the Resource Owner model instance
|
|
297
|
+
#
|
|
298
|
+
# @return [Doorkeeper::AccessToken, nil] matching AccessToken object or
|
|
299
|
+
# nil if nothing was found
|
|
300
|
+
#
|
|
301
|
+
def last_authorized_token_for(application_id, resource_owner)
|
|
302
|
+
authorized_tokens_for(application_id, resource_owner)
|
|
303
|
+
.ordered_by(:created_at, :desc)
|
|
304
|
+
.first
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
##
|
|
308
|
+
# Determines the secret storing transformer
|
|
309
|
+
# Unless configured otherwise, uses the plain secret strategy
|
|
310
|
+
#
|
|
311
|
+
# @return [Doorkeeper::SecretStoring::Base]
|
|
312
|
+
#
|
|
313
|
+
def secret_strategy
|
|
314
|
+
::Doorkeeper.config.token_secret_strategy
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
##
|
|
318
|
+
# Determine the fallback storing strategy
|
|
319
|
+
# Unless configured, there will be no fallback
|
|
320
|
+
def fallback_secret_strategy
|
|
321
|
+
::Doorkeeper.config.token_secret_fallback_strategy
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# Extracts the token's custom attributes (defined by the
|
|
325
|
+
# custom_access_token_attributes config option) from the token's attributes.
|
|
326
|
+
#
|
|
327
|
+
# @param attributes [Hash]
|
|
328
|
+
# A hash of the access token's attributes.
|
|
329
|
+
# @return [Hash]
|
|
330
|
+
# A hash containing only the custom access token attributes.
|
|
331
|
+
def extract_custom_attributes(attributes)
|
|
332
|
+
attributes.with_indifferent_access.slice(
|
|
333
|
+
*Doorkeeper.configuration.custom_access_token_attributes,
|
|
334
|
+
)
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# Access Token type: Bearer.
|
|
339
|
+
# @see https://datatracker.ietf.org/doc/html/rfc6750
|
|
340
|
+
# The OAuth 2.0 Authorization Framework: Bearer Token Usage
|
|
341
|
+
#
|
|
342
|
+
def token_type
|
|
343
|
+
"Bearer"
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def use_refresh_token?
|
|
347
|
+
@use_refresh_token ||= false
|
|
348
|
+
!!@use_refresh_token
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
# JSON representation of the Access Token instance.
|
|
352
|
+
#
|
|
353
|
+
# @return [Hash] hash with token data
|
|
354
|
+
def as_json(_options = {})
|
|
355
|
+
{
|
|
356
|
+
resource_owner_id: resource_owner_id,
|
|
357
|
+
scope: scopes,
|
|
358
|
+
expires_in: expires_in_seconds,
|
|
359
|
+
application: { uid: application.try(:uid) },
|
|
360
|
+
created_at: created_at.to_i,
|
|
361
|
+
}.tap do |json|
|
|
362
|
+
if Doorkeeper.configuration.polymorphic_resource_owner?
|
|
363
|
+
json[:resource_owner_type] = resource_owner_type
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# The token's custom attributes, as defined by
|
|
369
|
+
# the custom_access_token_attributes config option.
|
|
370
|
+
#
|
|
371
|
+
# @return [Hash] hash of custom access token attributes.
|
|
372
|
+
def custom_attributes
|
|
373
|
+
self.class.extract_custom_attributes(attributes)
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
# Indicates whether the token instance have the same credential
|
|
377
|
+
# as the other Access Token.
|
|
378
|
+
#
|
|
379
|
+
# @param access_token [Doorkeeper::AccessToken] other token
|
|
380
|
+
#
|
|
381
|
+
# @return [Boolean] true if credentials are same of false in other cases
|
|
382
|
+
#
|
|
383
|
+
def same_credential?(access_token)
|
|
384
|
+
application_id == access_token.application_id &&
|
|
385
|
+
same_resource_owner?(access_token)
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# Indicates whether the token instance have the same credential
|
|
389
|
+
# as the other Access Token.
|
|
390
|
+
#
|
|
391
|
+
# @param access_token [Doorkeeper::AccessToken] other token
|
|
392
|
+
#
|
|
393
|
+
# @return [Boolean] true if credentials are same of false in other cases
|
|
394
|
+
#
|
|
395
|
+
def same_resource_owner?(access_token)
|
|
396
|
+
if Doorkeeper.configuration.polymorphic_resource_owner?
|
|
397
|
+
resource_owner == access_token.resource_owner
|
|
398
|
+
else
|
|
399
|
+
resource_owner_id == access_token.resource_owner_id
|
|
400
|
+
end
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
# Indicates if token is acceptable for specific scopes.
|
|
404
|
+
#
|
|
405
|
+
# @param scopes [Array<String>] scopes
|
|
406
|
+
#
|
|
407
|
+
# @return [Boolean] true if record is accessible and includes scopes or
|
|
408
|
+
# false in other cases
|
|
409
|
+
#
|
|
410
|
+
def acceptable?(scopes)
|
|
411
|
+
accessible? && includes_scope?(*scopes)
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
# We keep a volatile copy of the raw refresh token for initial communication
|
|
415
|
+
# The stored refresh_token may be mapped and not available in cleartext.
|
|
416
|
+
def plaintext_refresh_token
|
|
417
|
+
if secret_strategy.allows_restoring_secrets?
|
|
418
|
+
secret_strategy.restore_secret(self, :refresh_token)
|
|
419
|
+
else
|
|
420
|
+
@raw_refresh_token
|
|
421
|
+
end
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
# We keep a volatile copy of the raw token for initial communication
|
|
425
|
+
# The stored refresh_token may be mapped and not available in cleartext.
|
|
426
|
+
#
|
|
427
|
+
# Some strategies allow restoring stored secrets (e.g. symmetric encryption)
|
|
428
|
+
# while hashing strategies do not, so you cannot rely on this value
|
|
429
|
+
# returning a present value for persisted tokens.
|
|
430
|
+
def plaintext_token
|
|
431
|
+
if secret_strategy.allows_restoring_secrets?
|
|
432
|
+
secret_strategy.restore_secret(self, :token)
|
|
433
|
+
else
|
|
434
|
+
@raw_token
|
|
435
|
+
end
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
# Revokes token with `:refresh_token` equal to `:previous_refresh_token`
|
|
439
|
+
# and clears `:previous_refresh_token` attribute.
|
|
440
|
+
#
|
|
441
|
+
def revoke_previous_refresh_token!
|
|
442
|
+
return if !self.class.refresh_token_revoked_on_use? || previous_refresh_token.blank?
|
|
443
|
+
|
|
444
|
+
old_refresh_token&.revoke
|
|
445
|
+
|
|
446
|
+
if self.class.respond_to?(:with_primary_role)
|
|
447
|
+
self.class.with_primary_role { update_attribute(:previous_refresh_token, "") }
|
|
448
|
+
else
|
|
449
|
+
update_attribute(:previous_refresh_token, "")
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
private
|
|
454
|
+
|
|
455
|
+
# Searches for Access Token record with `:refresh_token` equal to
|
|
456
|
+
# `:previous_refresh_token` value.
|
|
457
|
+
#
|
|
458
|
+
# @return [Doorkeeper::AccessToken, nil]
|
|
459
|
+
# Access Token record or nil if nothing found
|
|
460
|
+
#
|
|
461
|
+
def old_refresh_token
|
|
462
|
+
@old_refresh_token ||= self.class.by_previous_refresh_token(previous_refresh_token)
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
# Generates refresh token with UniqueToken generator.
|
|
466
|
+
#
|
|
467
|
+
# @return [String] refresh token value
|
|
468
|
+
#
|
|
469
|
+
def generate_refresh_token
|
|
470
|
+
@raw_refresh_token = UniqueToken.generate
|
|
471
|
+
secret_strategy.store_secret(self, :refresh_token, @raw_refresh_token)
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
# Generates and sets the token value with the
|
|
475
|
+
# configured Generator class (see Doorkeeper.config).
|
|
476
|
+
#
|
|
477
|
+
# @return [String] generated token value
|
|
478
|
+
#
|
|
479
|
+
# @raise [Doorkeeper::Errors::UnableToGenerateToken]
|
|
480
|
+
# custom class doesn't implement .generate method
|
|
481
|
+
# @raise [Doorkeeper::Errors::TokenGeneratorNotFound]
|
|
482
|
+
# custom class doesn't exist
|
|
483
|
+
#
|
|
484
|
+
def generate_token
|
|
485
|
+
self.created_at ||= Time.now.utc
|
|
486
|
+
|
|
487
|
+
@raw_token = token_generator.generate(attributes_for_token_generator)
|
|
488
|
+
secret_strategy.store_secret(self, :token, @raw_token)
|
|
489
|
+
@raw_token
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
# Set of attributes that would be passed to token generator to
|
|
493
|
+
# generate unique token based on them.
|
|
494
|
+
#
|
|
495
|
+
# @return [Hash] set of attributes
|
|
496
|
+
#
|
|
497
|
+
def attributes_for_token_generator
|
|
498
|
+
{
|
|
499
|
+
resource_owner_id: resource_owner_id,
|
|
500
|
+
scopes: scopes,
|
|
501
|
+
application: application,
|
|
502
|
+
expires_in: expires_in,
|
|
503
|
+
created_at: created_at,
|
|
504
|
+
}.tap do |attributes|
|
|
505
|
+
if Doorkeeper.config.polymorphic_resource_owner?
|
|
506
|
+
attributes[:resource_owner] = resource_owner
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
Doorkeeper.config.custom_access_token_attributes.each do |attribute_name|
|
|
510
|
+
attributes[attribute_name] = public_send(attribute_name)
|
|
511
|
+
end
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
def token_generator
|
|
516
|
+
generator_name = Doorkeeper.config.access_token_generator
|
|
517
|
+
generator = generator_name.constantize
|
|
518
|
+
|
|
519
|
+
return generator if generator.respond_to?(:generate)
|
|
520
|
+
|
|
521
|
+
raise Errors::UnableToGenerateToken, "#{generator} does not respond to `.generate`."
|
|
522
|
+
rescue NameError
|
|
523
|
+
raise Errors::TokenGeneratorNotFound, "#{generator_name} not found"
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
module ApplicationMixin
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
include OAuth::Helpers
|
|
8
|
+
include Models::Orderable
|
|
9
|
+
include Models::SecretStorable
|
|
10
|
+
include Models::Scopes
|
|
11
|
+
|
|
12
|
+
# :nodoc
|
|
13
|
+
module ClassMethods
|
|
14
|
+
# Returns an instance of the Doorkeeper::Application with
|
|
15
|
+
# specific UID and secret.
|
|
16
|
+
#
|
|
17
|
+
# Public/Non-confidential applications will only find by uid if secret is
|
|
18
|
+
# blank.
|
|
19
|
+
#
|
|
20
|
+
# @param uid [#to_s] UID (any object that responds to `#to_s`)
|
|
21
|
+
# @param secret [#to_s] secret (any object that responds to `#to_s`)
|
|
22
|
+
#
|
|
23
|
+
# @return [Doorkeeper::Application, nil]
|
|
24
|
+
# Application instance or nil if there is no record with such credentials
|
|
25
|
+
#
|
|
26
|
+
def by_uid_and_secret(uid, secret)
|
|
27
|
+
app = by_uid(uid)
|
|
28
|
+
return unless app
|
|
29
|
+
return app if secret.blank? && !app.confidential?
|
|
30
|
+
return unless app.secret_matches?(secret)
|
|
31
|
+
|
|
32
|
+
app
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Returns an instance of the Doorkeeper::Application with specific UID.
|
|
36
|
+
#
|
|
37
|
+
# @param uid [#to_s] UID (any object that responds to `#to_s`)
|
|
38
|
+
#
|
|
39
|
+
# @return [Doorkeeper::Application, nil] Application instance or nil
|
|
40
|
+
# if there is no record with such UID
|
|
41
|
+
#
|
|
42
|
+
def by_uid(uid)
|
|
43
|
+
find_by(uid: uid.to_s)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
##
|
|
47
|
+
# Determines the secret storing transformer
|
|
48
|
+
# Unless configured otherwise, uses the plain secret strategy
|
|
49
|
+
def secret_strategy
|
|
50
|
+
::Doorkeeper.config.application_secret_strategy
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
##
|
|
54
|
+
# Determine the fallback storing strategy
|
|
55
|
+
# Unless configured, there will be no fallback
|
|
56
|
+
def fallback_secret_strategy
|
|
57
|
+
::Doorkeeper.config.application_secret_fallback_strategy
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Set an application's valid redirect URIs.
|
|
62
|
+
#
|
|
63
|
+
# @param uris [String, Array<String>] Newline-separated string or array the URI(s)
|
|
64
|
+
#
|
|
65
|
+
# @return [String] The redirect URI(s) separated by newlines.
|
|
66
|
+
#
|
|
67
|
+
def redirect_uri=(uris)
|
|
68
|
+
super(uris.is_a?(Array) ? uris.join("\n") : uris)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Check whether the given plain text secret matches our stored secret
|
|
72
|
+
#
|
|
73
|
+
# @param input [#to_s] Plain secret provided by user
|
|
74
|
+
# (any object that responds to `#to_s`)
|
|
75
|
+
#
|
|
76
|
+
# @return [Boolean] Whether the given secret matches the stored secret
|
|
77
|
+
# of this application.
|
|
78
|
+
#
|
|
79
|
+
def secret_matches?(input)
|
|
80
|
+
# return false if either is nil, since secure_compare depends on strings
|
|
81
|
+
# but Application secrets MAY be nil depending on confidentiality.
|
|
82
|
+
return false if input.nil? || secret.nil?
|
|
83
|
+
|
|
84
|
+
# When matching the secret by comparer function, all is well.
|
|
85
|
+
return true if secret_strategy.secret_matches?(input, secret)
|
|
86
|
+
|
|
87
|
+
# When fallback lookup is enabled, ensure applications
|
|
88
|
+
# with plain secrets can still be found
|
|
89
|
+
if fallback_secret_strategy
|
|
90
|
+
fallback_secret_strategy.secret_matches?(input, secret)
|
|
91
|
+
else
|
|
92
|
+
false
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
module Models
|
|
5
|
+
module Accessible
|
|
6
|
+
# Indicates whether the object is accessible (not expired and not revoked).
|
|
7
|
+
#
|
|
8
|
+
# @return [Boolean] true if object accessible or false in other case
|
|
9
|
+
#
|
|
10
|
+
def accessible?
|
|
11
|
+
!expired? && !revoked?
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
module Models
|
|
5
|
+
module Expirable
|
|
6
|
+
# Indicates whether the object is expired (`#expires_in` present and
|
|
7
|
+
# expiration time has come).
|
|
8
|
+
#
|
|
9
|
+
# @return [Boolean] true if object expired and false in other case
|
|
10
|
+
def expired?
|
|
11
|
+
!!(expires_in && Time.now.utc > expires_at)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Calculates expiration time in seconds.
|
|
15
|
+
#
|
|
16
|
+
# @return [Integer, nil] number of seconds if object has expiration time
|
|
17
|
+
# or nil if object never expires.
|
|
18
|
+
def expires_in_seconds
|
|
19
|
+
return nil if expires_in.nil?
|
|
20
|
+
|
|
21
|
+
expires = expires_at - Time.now.utc
|
|
22
|
+
expires_sec = expires.seconds.round(0)
|
|
23
|
+
expires_sec > 0 ? expires_sec : 0
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Expiration time (date time of creation + TTL).
|
|
27
|
+
#
|
|
28
|
+
# @return [Time, nil] expiration time in UTC
|
|
29
|
+
# or nil if the object never expires.
|
|
30
|
+
#
|
|
31
|
+
def expires_at
|
|
32
|
+
expires_in && created_at + expires_in.seconds
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|