mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
FEATURE: user API now contains scopes so permission is granular
previously we supported blanket read and write for user API, this change amends it so we can define more limited scopes. A scope only covers a few routes. You can not grant access to part of the site and leave a large amount of the information hidden to API consumer.
This commit is contained in:
@@ -1,10 +1,63 @@
|
||||
class UserApiKey < ActiveRecord::Base
|
||||
|
||||
SCOPES = {
|
||||
read: [:get],
|
||||
write: [:get, :post, :patch],
|
||||
message_bus: [[:post, 'message_bus']],
|
||||
push: nil,
|
||||
notifications: [[:post, 'message_bus'], [:get, 'notifications#index'], [:put, 'notifications#mark_read']],
|
||||
session_info: [[:get, 'session#current'], [:get, 'users#topic_tracking_state']]
|
||||
}
|
||||
|
||||
belongs_to :user
|
||||
|
||||
def access
|
||||
has_push = push && push_url.present? && SiteSetting.allowed_user_api_push_urls.include?(push_url)
|
||||
"#{read ? "r" : ""}#{write ? "w" : ""}#{has_push ? "p" : ""}"
|
||||
def self.allowed_scopes
|
||||
Set.new(SiteSetting.allow_user_api_key_scopes.split("|"))
|
||||
end
|
||||
|
||||
def self.available_scopes
|
||||
@available_scopes ||= Set.new(SCOPES.keys.map(&:to_s))
|
||||
end
|
||||
|
||||
def self.allow_permission?(permission, env)
|
||||
verb, action = permission
|
||||
actual_verb = env["REQUEST_METHOD"] || ""
|
||||
|
||||
# safe in Ruby 2.3 which is only one supported
|
||||
return false unless actual_verb.downcase == verb.to_s
|
||||
return true unless action
|
||||
|
||||
# not a rails route, special handling
|
||||
return true if action == "message_bus" && env["PATH_INFO"] =~ /^\/message-bus\/.*\/poll/
|
||||
|
||||
params = env['action_dispatch.request.path_parameters']
|
||||
|
||||
return false unless params
|
||||
|
||||
actual_action = "#{params[:controller]}##{params[:action]}"
|
||||
actual_action == action
|
||||
end
|
||||
|
||||
def self.allow_scope?(name, env)
|
||||
if allowed = SCOPES[name.to_sym]
|
||||
good = allowed.any? do |permission|
|
||||
allow_permission?(permission, env)
|
||||
end
|
||||
|
||||
good || allow_permission?([:post, 'user_api_keys#revoke'], env)
|
||||
end
|
||||
end
|
||||
|
||||
def has_push?
|
||||
(scopes.include?("push") || scopes.include?("notifications")) && push_url.present? && SiteSetting.allowed_user_api_push_urls.include?(push_url)
|
||||
end
|
||||
|
||||
def allow?(env)
|
||||
scopes.any? do |name|
|
||||
UserApiKey.allow_scope?(name, env)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
|
||||
Reference in New Issue
Block a user