67 lines
2.1 KiB
Crystal
67 lines
2.1 KiB
Crystal
class Acl < Jennifer::Model::Base
|
|
with_timestamps
|
|
|
|
mapping(
|
|
id: { type: UUID, primary: true, default: UUID.random },
|
|
role: String,
|
|
path: String,
|
|
permission: String,
|
|
created_at: { type: Time, default: Time.utc },
|
|
updated_at: { type: Time, default: Time.utc },
|
|
)
|
|
end
|
|
|
|
# Load permissions, ...
|
|
require "./acl/*"
|
|
|
|
class Acl
|
|
alias Role = String
|
|
alias PermissionTuple = NamedTuple(path: Acl::Path, permission: Permission)
|
|
@@permissions = Hash(Role, Array(PermissionTuple)).new
|
|
|
|
def self._permissions
|
|
@@permissions
|
|
end
|
|
|
|
after_save :reload_permissions!
|
|
|
|
private def reload_permissions!
|
|
Acl.reload_permissions!
|
|
end
|
|
|
|
def self.reload_permissions!
|
|
# clean up existing permissions
|
|
# TODO optimise with optional role argument to clean part of it
|
|
@@permissions = Hash(Role, Array(PermissionTuple)).new
|
|
Acl.all.each do |acl|
|
|
@@permissions[acl.role] = Array(PermissionTuple).new if !@@permissions.has_key?(acl.role)
|
|
@@permissions[acl.role] << {
|
|
path: Acl::Path.new(acl.path),
|
|
# TODO handle invalid string
|
|
permission: STRING_TO_PERMISSION[acl.permission],
|
|
}
|
|
end
|
|
end
|
|
|
|
# check if the database allow the role to perform an action on a path
|
|
# TODO: handle invalid string
|
|
def self.permitted?(role : String, path : String, permission : String) : Bool
|
|
permitted?(role: role, path: path, permission: STRING_TO_PERMiSSION[permission])
|
|
end
|
|
|
|
# check if the database allow the role to perform an action on a path
|
|
def self.permitted?(role : String, path : String, permission : Permission) : Bool
|
|
# role do not exists ? => false TODO use "default" configuration
|
|
return false if !@@permissions.has_key?(role)
|
|
matched_permissions = @@permissions[role].select { |pp_tuple| pp_tuple[:path].match?(path) }
|
|
|
|
# path not mapped at all ? => false TODO use "default" configuration
|
|
return false if matched_permissions.empty?
|
|
|
|
# keep the longuest path
|
|
match = matched_permissions.reduce { |l, r| l[:path].size >= r[:path].size ? l : r }
|
|
match[:permission].to_i >= permission.to_i
|
|
end
|
|
|
|
end
|