Module: Webhookdb::Service::Helpers
- Extended by:
- Grape::API::Helpers
- Includes:
- Collection::Helpers
- Defined in:
- lib/webhookdb/service/helpers.rb
Overview
A collection of helper functions that can be included
Instance Method Summary collapse
-
#_check_customer_deleted(user, potential_admin) ⇒ Object
Handle denying authentication if the given user cannot auth.
- #admin_customer ⇒ Object
- #admin_customer? ⇒ Boolean
- #authenticate! ⇒ Object
- #check_feature_access!(org, role) ⇒ Object
- #check_role!(customer, role_name) ⇒ Object
-
#current_customer ⇒ Object
Return the currently-authenticated user, or respond with a 401 if there is no authenticated user.
-
#current_customer? ⇒ Boolean
Return the currently-authenticated user, or respond nil if there is no authenticated user.
- #current_session_id ⇒ Object
- #declared_and_provided_params(params, exclude: []) ⇒ Object
- #delete_session_cookies ⇒ Object
- #endpoint_removed! ⇒ Object
- #forbidden! ⇒ Object
-
#invalid!(errors, message: nil) ⇒ Object
Raise a 400 error for unstructured validation.
-
#invalid_fields!(field_errors, message: nil) ⇒ Object
Raise a 400 error for structured validation.
- #logger ⇒ Object
- #merror!(status, message, code: nil, more: {}, headers: {}, rollback_db: nil, alert: false) ⇒ Object
- #not_found! ⇒ Object
- #order(dataset, params) ⇒ Object
- #paginate(dataset, params) ⇒ Object
- #permission_error!(message) ⇒ Object
-
#save_or_error!(object) ⇒ Object
If
object
is valid, save and return it. - #search_param_to_sql(params, column, param: :search) ⇒ Object
- #set_customer(customer) ⇒ Object
-
#set_declared(model, params, ignore: [:id]) ⇒ Object
Set the provided, declared/valid parameters in params on model.
- #unauthenticated! ⇒ Object
- #unauthenticated_with_message!(msg) ⇒ Object
- #use_http_expires_caching(expiration) ⇒ Object
Methods included from Collection::Helpers
Instance Method Details
#_check_customer_deleted(user, potential_admin) ⇒ Object
Handle denying authentication if the given user cannot auth. That is:
-
if we have an admin, but they should not be (deleted or missing role), throw unauthed error.
-
if current user is nil, return nil, since the caller can handle it.
-
if current user is deleted and there is no admin, throw unauthed error.
-
if current user is deleted and admin is deleted, throw unauthed error.
-
otherwise, return current user.
The scenarios this covers are:
-
Normal users cannot auth if deleted.
-
Admins can sudo deleted users, and current_customer still works.
-
Deleted admins cannot auth or get their sudo’ed user.
NOTE: It is safe to throw unauthed errors for deleted users- this does not expose whether a user exists or not, because the only way to call this is via cookies, and cookies are encrypted. So it is impossible to force requests trying to auth/check auth for a user without knowing the secret.
64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/webhookdb/service/helpers.rb', line 64 def _check_customer_deleted(user, potential_admin) return nil if user.nil? if potential_admin && (potential_admin.soft_deleted? || !potential_admin.roles.include?(Webhookdb::Role.admin_role)) unauthenticated! end if user.soft_deleted? && potential_admin.nil? unauthenticated! end return user end |
#admin_customer ⇒ Object
31 32 33 |
# File 'lib/webhookdb/service/helpers.rb', line 31 def admin_customer return _check_customer_deleted(env["warden"].authenticate!(scope: :admin), nil) end |
#admin_customer? ⇒ Boolean
35 36 37 |
# File 'lib/webhookdb/service/helpers.rb', line 35 def admin_customer? return _check_customer_deleted(env["warden"].authenticate(scope: :admin), nil) end |
#authenticate! ⇒ Object
39 40 41 42 43 44 |
# File 'lib/webhookdb/service/helpers.rb', line 39 def authenticate! warden = env["warden"] user = warden.authenticate!(scope: :customer) warden.set_user(user, scope: :admin) if user.admin? return user end |
#check_feature_access!(org, role) ⇒ Object
145 146 147 148 |
# File 'lib/webhookdb/service/helpers.rb', line 145 def check_feature_access!(org, role) return if org.feature_roles.include?(role) ("This feature is not enabled for your organization.") end |
#check_role!(customer, role_name) ⇒ Object
97 98 99 100 101 102 103 |
# File 'lib/webhookdb/service/helpers.rb', line 97 def check_role!(customer, role_name) has_role = customer.roles.find { |r| r.name == role_name } return if has_role role_exists = !Webhookdb::Role.where(name: role_name).empty? raise "The role '#{role_name}' does not exist so cannot be checked. You need to create it first." unless role_exists ("Sorry, this action is unavailable.") end |
#current_customer ⇒ Object
Return the currently-authenticated user, or respond with a 401 if there is no authenticated user.
21 22 23 |
# File 'lib/webhookdb/service/helpers.rb', line 21 def current_customer return _check_customer_deleted(env["warden"].authenticate!(scope: :customer), admin_customer?) end |
#current_customer? ⇒ Boolean
Return the currently-authenticated user, or respond nil if there is no authenticated user.
27 28 29 |
# File 'lib/webhookdb/service/helpers.rb', line 27 def current_customer? return _check_customer_deleted(env["warden"].user(scope: :customer), admin_customer?) end |
#current_session_id ⇒ Object
93 94 95 |
# File 'lib/webhookdb/service/helpers.rb', line 93 def current_session_id return env["rack.session"].id end |
#declared_and_provided_params(params, exclude: []) ⇒ Object
226 227 228 229 230 231 |
# File 'lib/webhookdb/service/helpers.rb', line 226 def declared_and_provided_params(params, exclude: []) decl = declared(params) exclude.each { |k| decl.delete(k) } decl.delete_if { |k| !params.key?(k) } return decl end |
#delete_session_cookies ⇒ Object
77 78 79 80 81 82 83 84 85 |
# File 'lib/webhookdb/service/helpers.rb', line 77 def # Nope, cannot do this through Warden easily. # And really we should have server-based sessions we can expire, # but in the meantime, stomp on the cookie hard. = env[Rack::RACK_SESSION_OPTIONS] [:drop] = true # Rack sends a cookie with an empty session, but let's tell the browser to actually delete the cookie. .delete(Webhookdb::Service::SESSION_COOKIE, domain: [:domain], path: [:path]) end |
#endpoint_removed! ⇒ Object
170 171 172 173 174 175 176 177 |
# File 'lib/webhookdb/service/helpers.rb', line 170 def endpoint_removed! merror!( 403, "Sorry, this endpoint has been removed. Run `webhookdb update` to upgrade your CLI, " \ "or file a ticket at #{Webhookdb.oss_repo_url} for help.", code: "endpoint_removed", ) end |
#forbidden! ⇒ Object
133 134 135 |
# File 'lib/webhookdb/service/helpers.rb', line 133 def forbidden! merror!(403, "Forbidden", code: "forbidden") end |
#invalid!(errors, message: nil) ⇒ Object
Raise a 400 error for unstructured validation.
153 154 155 156 157 |
# File 'lib/webhookdb/service/helpers.rb', line 153 def invalid!(errors, message: nil) errors = [errors] unless errors.respond_to?(:to_ary) ||= errors.join(", ").upcase_first merror!(400, , code: "validation_error", more: {errors:, field_errors: {}}) end |
#invalid_fields!(field_errors, message: nil) ⇒ Object
Raise a 400 error for structured validation.
164 165 166 167 168 |
# File 'lib/webhookdb/service/helpers.rb', line 164 def invalid_fields!(field_errors, message: nil) errors = field_errors.map { |field, field_errs| field_errs.map { |e| "#{field} #{e}" } }.flatten ||= errors.join(", ").upcase_first merror!(400, , code: "validation_error", more: {errors:, field_errors:}) end |
#logger ⇒ Object
15 16 17 |
# File 'lib/webhookdb/service/helpers.rb', line 15 def logger return Webhookdb::Service.logger end |
#merror!(status, message, code: nil, more: {}, headers: {}, rollback_db: nil, alert: false) ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/webhookdb/service/helpers.rb', line 105 def merror!(status, , code: nil, more: {}, headers: {}, rollback_db: nil, alert: false) header "Content-Type", "application/json" body = Webhookdb::Service.error_body(status, , code:, more:) if alert Sentry.with_scope do |scope| scope&.set_extras(**body) Sentry.() end end if rollback_db Webhookdb::Postgres.defer_after_rollback(rollback_db) do error!(body, status, headers) end raise Sequel::Rollback else error!(body, status, headers) end end |
#not_found! ⇒ Object
137 138 139 |
# File 'lib/webhookdb/service/helpers.rb', line 137 def not_found! merror!(404, "Not Found", code: "not_found") end |
#order(dataset, params) ⇒ Object
201 202 203 204 |
# File 'lib/webhookdb/service/helpers.rb', line 201 def order(dataset, params) expr = params[:order_direction] == :asc ? Sequel.asc(params[:order_by]) : Sequel.desc(params[:order_by]) return dataset.order(expr, Sequel.desc(:id)) end |
#paginate(dataset, params) ⇒ Object
197 198 199 |
# File 'lib/webhookdb/service/helpers.rb', line 197 def paginate(dataset, params) return dataset.paginate(params[:page], params[:per_page]) end |
#permission_error!(message) ⇒ Object
141 142 143 |
# File 'lib/webhookdb/service/helpers.rb', line 141 def () merror!(403, , code: "permission_check") end |
#save_or_error!(object) ⇒ Object
If object
is valid, save and return it. If not, call invalid! witht the validation errors.
188 189 190 191 192 193 194 195 |
# File 'lib/webhookdb/service/helpers.rb', line 188 def save_or_error!(object) if object.valid? object.save_changes return object else invalid_fields!(object.errors.to_h) end end |
#search_param_to_sql(params, column, param: :search) ⇒ Object
179 180 181 182 183 184 |
# File 'lib/webhookdb/service/helpers.rb', line 179 def search_param_to_sql(params, column, param: :search) search = params[param]&.strip return nil if search.blank? || search == "*" term = "%#{search.strip}%" return Sequel.ilike(column, term) end |
#set_customer(customer) ⇒ Object
87 88 89 90 91 |
# File 'lib/webhookdb/service/helpers.rb', line 87 def set_customer(customer) warden = env["warden"] warden.set_user(customer, scope: :customer) warden.set_user(customer, scope: :admin) if customer.admin? end |
#set_declared(model, params, ignore: [:id]) ⇒ Object
Set the provided, declared/valid parameters in params on model. Because Grape’s ‘declared()` function adds parameters that are declared-but-not-provided, and its `params` value includes provided-but-not-declared entries, the fields we set are the intersection of the two.
216 217 218 219 220 221 222 223 224 |
# File 'lib/webhookdb/service/helpers.rb', line 216 def set_declared(model, params, ignore: [:id]) # If .to_h is used (rather than Grape's 'params' which is HashWithIndifferentAccess), # the keys may be strings. We need to deep symbolize since nested hashes get to_h with 'symbolize_keys'. params = params.deep_symbolize_keys decl = declared_and_provided_params(params, exclude: ignore) ignore.each { |k| decl.delete(k) } decl.delete_if { |k| !params.key?(k) } model.set(decl) end |
#unauthenticated! ⇒ Object
124 125 126 |
# File 'lib/webhookdb/service/helpers.rb', line 124 def unauthenticated! merror!(401, "Unauthenticated", code: "unauthenticated") end |
#unauthenticated_with_message!(msg) ⇒ Object
128 129 130 131 |
# File 'lib/webhookdb/service/helpers.rb', line 128 def (msg) env["webhookdb.authfailuremessage"] = msg unauthenticated! end |