cartodb-4.42/lib/carto/oauth_provider/scopes/scopes.rb
2024-04-06 05:25:13 +00:00

132 lines
4.9 KiB
Ruby

require_relative './category'
require_relative './scope'
require_relative './default_scope'
require_relative './apis_scope'
require_relative './dataservices_scope'
require_relative './datasets_scope'
require_relative './datasets_metadata_scope'
require_relative './schemas_scope'
require_relative './user_scope'
require_relative './scopes_validator'
module Carto
module OauthProvider
module Scopes
SCOPE_DEFAULT = '_default'.freeze
SCOPE_OFFLINE = 'offline'.freeze
CATEGORY_OFFLINE = Category.new('Offline access').freeze
CATEGORY_USER = Category.new('User and personal data').freeze
CATEGORY_MONEY = Category.new('Features that consume credits', 'money')
CATEGORY_DATASETS = Category.new('Access to your datasets')
CATEGORY_SCHEMA = Category.new('Create tables')
CATEGORY_DATASETS_METADATA = Category.new('List your datasets')
CATEGORY_APIS = Category.new('Access to CARTO APIs')
SCOPES = [
Scope.new(SCOPE_DEFAULT, CATEGORY_USER, 'Username and organization name').freeze,
Scope.new(SCOPE_OFFLINE, CATEGORY_OFFLINE, 'Access CARTO in the background').freeze,
DataservicesScope.new('geocoding', 'Geocoding').freeze,
DataservicesScope.new('isolines', 'Isolines').freeze,
DataservicesScope.new('routing', 'Routing').freeze,
DataservicesScope.new('observatory', 'Data Observatory').freeze,
ApisScope.new('do', 'Data Observatory API').freeze,
UserScope.new('profile', 'User profile (avatar, name, org. owner)').freeze,
DatasetsMetadataScope.new('Table names').freeze
].freeze
SCOPES_BY_NAME = SCOPES.map { |s| [s.name, s] }.to_h.freeze
# The default scope is always granted but cannot be explicitly requested
SUPPORTED_SCOPES = (SCOPES.map(&:name) - [SCOPE_DEFAULT]).freeze
def self.invalid_scopes(scopes)
scopes - SUPPORTED_SCOPES - DatasetsScope.valid_scopes(scopes) - SchemasScope.valid_scopes(scopes)
end
def self.invalid_scopes_and_tables(scopes, user)
scopes - SUPPORTED_SCOPES - DatasetsScope.valid_scopes_with_table(scopes, user) - SchemasScope.valid_scopes_with_schema(scopes, user)
end
def self.build(scope)
result = SCOPES_BY_NAME[scope]
if !result
if DatasetsScope.is_a?(scope)
result = DatasetsScope.new(scope)
elsif SchemasScope.is_a?(scope)
result = SchemasScope.new(scope)
end
end
result
end
def self.scopes_by_category(new_scopes, previous_scopes = [])
# If we had previous scopes, DEFAULT was already granted.
previous_scopes = previous_scopes.blank? ? [] : previous_scopes + [SCOPE_DEFAULT]
new_scopes_filtered = subtract_scopes(new_scopes, previous_scopes)
previous_scopes_filtered = subtract_scopes(previous_scopes, new_scopes_filtered)
all_scopes = ([SCOPE_DEFAULT] + new_scopes_filtered + previous_scopes_filtered).uniq
scopes_by_category = all_scopes.map { |s| build(s) }.group_by(&:category)
scopes_by_category.map do |category, scopes|
{
description: category.description,
icon: category.icon,
scopes: scopes.map do |scope|
{
description: scope.description,
new: !previous_scopes.include?(scope.name)
}
end
}
end
end
def self.subtract_scopes(scopes1, scopes2, user_schema = 'public')
return [] if scopes1.blank?
return scopes1 if scopes2.blank?
datasets1, non_datasets1 = split_dataset_scopes_for_subtract(scopes1, user_schema)
datasets2, non_datasets2 = split_dataset_scopes_for_subtract(scopes2, user_schema)
subtract_dataset_scopes!(datasets1, datasets2)
datasets_results = datasets1.map { |schema_table, permissions| "datasets:#{permissions}:#{schema_table}" }
datasets_results + (non_datasets1 - non_datasets2)
end
private_class_method def self.split_dataset_scopes_for_subtract(scopes, user_schema)
datasets = {}
non_datasets = []
scopes.each do |scope|
if DatasetsScope.is_a?(scope)
table, schema, permissions = DatasetsScope.table_schema_permission(scope)
schema ||= user_schema
schema_table = "#{schema}.#{table}"
datasets[schema_table] = permissions unless datasets[schema_table] == 'rw'
else
non_datasets << scope
end
end
[datasets, non_datasets]
end
private_class_method def self.subtract_dataset_scopes!(datasets1, datasets2)
return [] if datasets1.nil?
return datasets1 if datasets2.nil?
datasets2.each do |schema_table, permissions|
datasets1.delete(schema_table) unless datasets1[schema_table] == 'rw' && permissions == 'r'
end
end
end
end
end