Complete overhaul of ownership management: add a domain db, remove user data db.

dev
Karchnu 2024-04-27 17:32:22 +02:00
parent 61bace491c
commit 40fcc9c66e
5 changed files with 68 additions and 57 deletions

View File

@ -53,7 +53,7 @@ class DNSManager::Service < IPC
def initialize(@configuration)
super()
@storage = DNSManager::Storage.new self, @configuration.storage_directory, @configuration.recreate_indexes
@storage = DNSManager::Storage.new @configuration.storage_directory, @configuration.recreate_indexes
@logged_users = Hash(Int32, AuthD::User::Public).new
@ -71,6 +71,7 @@ class DNSManager::Service < IPC
raise "Cannot authenticate to authd with login #{@configuration.login}: #{response}."
end
@storage.dnsmanagerd = self
self.timer @configuration.ipc_timer
self.service_init @configuration.service_name
end

View File

@ -7,7 +7,7 @@ class DNSManager::Request
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
user = dnsmanagerd.get_logged_user event
return Response::ErrorUserNotLogged.new unless user
dnsmanagerd.storage.get_orphan_domains dnsmanagerd, user.uid
dnsmanagerd.storage.get_orphan_domains user.uid
end
end
DNSManager.requests << GetOrphanDomains
@ -59,8 +59,7 @@ class DNSManager::Request
user = dnsmanagerd.get_logged_user event
return Response::ErrorUserNotLogged.new unless user
udata = dnsmanagerd.storage.get_user_data user
return Response::InsufficientRights.new unless udata.admin
dnsmanagerd.storage.user_must_be_admin! user.uid
dnsmanagerd.storage.generate_all_zonefiles
end
end
@ -77,10 +76,8 @@ class DNSManager::Request
user = dnsmanagerd.get_logged_user event
return Response::ErrorUserNotLogged.new unless user
# TODO: verify user must be admin.
#udata = dnsmanagerd.storage.get_user_data user
#return Response::InsufficientRights.new unless udata.admin
#dnsmanagerd.storage.generate_zonefile @domain
dnsmanagerd.storage.user_must_be_admin! user.uid
dnsmanagerd.storage.generate_zonefile @domain
end
end
DNSManager.requests << GenerateZoneFile

View File

@ -14,12 +14,12 @@ class DNSManager::Request
#dnsmanagerd.auth.edit_profile_content user.uid, {
# "dnsmanager-last-connection" => JSON::Any.new Time.utc.to_s
#}
user_data = dnsmanagerd.storage.ensure_user_data response.user.uid
return Response::Error.new "invalid user" unless user_data
user_id = response.user.uid
dnsmanagerd.storage.user_must_exist! user_id
accepted_domains = dnsmanagerd.configuration.accepted_domains.not_nil!
user_domains = user_data.domains
perms = dnsmanagerd.check_permissions response.user.uid, "*"
user_domains = dnsmanagerd.storage.user_domains user_id
perms = dnsmanagerd.check_permissions user_id, "*"
Response::Logged.new (perms == AuthD::User::PermissionLevel::Admin), accepted_domains, user_domains
else
Response::ErrorInvalidToken.new
@ -42,7 +42,7 @@ class DNSManager::Request
user = dnsmanagerd.get_logged_user event
return Response::ErrorUserNotLogged.new unless user
dnsmanagerd.storage.delete_user_data dnsmanagerd, user.uid, user_id
dnsmanagerd.storage.delete_user_data user.uid, user_id
end
end
DNSManager.requests << DeleteUser

View File

@ -69,7 +69,7 @@ class DNSManager::Request
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) : IPC::JSON
user = dnsmanagerd.get_logged_user event
return Response::ErrorUserNotLogged.new unless user
dnsmanagerd.storage.user_domains user.uid
Response::DomainList.new dnsmanagerd.storage.user_domains user.uid
end
end
DNSManager.requests << UserDomains

View File

@ -24,9 +24,15 @@ class DNSManager::Storage
getter root : String
getter zonefiledir : String
getter dnsmanagerd : DNSManager::Service
property dnsmanagerd : DNSManager::Service? = nil
def initialize(@dnsmanagerd, @root : String, reindex : Bool = false)
def dnsmanagerd() : DNSManager::Service
@dnsmanagerd.not_nil!
rescue
raise Exception.new "dnsmanagerd not defined"
end
def initialize(@root : String, reindex : Bool = false)
@domains = DODB::CachedDataBase(Domain).new "#{@root}/domains"
@domains_by_name = @domains.new_index "name", &.name
@domains_by_share_key = @domains.new_nilable_index "share-key", do |d|
@ -139,7 +145,7 @@ class DNSManager::Storage
#
# Add the new domain.
@domains << DomainInfo.new domain, owners: [user_id]
@domains << Domain.new domain, owners: [user_id]
# Add the new zone in the database.
zones_by_domain.update_or_create domain, default_zone
@ -161,7 +167,7 @@ class DNSManager::Storage
user_should_own! user_id, z.domain
else
# Add the domain to the user's domain.
domains << DomainInfo.new zone.domain
domains << Domain.new zone.domain
end
# Add -or replace- the zone.
@ -256,73 +262,80 @@ class DNSManager::Storage
def get_orphan_domains(user_id : UserDataID) : IPC::JSON
user_must_be_admin! user_id
Baguette::Log.debug "list all orphan domains (long computation)"
orphans = [] of String
user_data.each do |user|
begin
@dnsmanagerd.authd.get_user? user.uid
rescue e
Baguette::Log.warning "no authd info on user #{user.uid}: #{e} (removing this user)"
Baguette::Log.debug "user #{user.uid} had #{user.domains.size} domains"
user.domains.each do |domain|
orphans << domain
end
wipe_user_data user
end
end
Baguette::Log.debug "total: #{orphans.size} orphans"
Response::OrphanDomainList.new orphans
# Baguette::Log.debug "list all orphan domains (long computation)"
# orphans = [] of String
# user_data.each do |user|
# begin
# dnsmanagerd().authd.get_user? user.uid
# rescue e
# Baguette::Log.warning "no authd info on user #{user.uid}: #{e} (removing this user)"
# Baguette::Log.debug "user #{user.uid} had #{user.domains.size} domains"
# user.domains.each do |domain|
# orphans << domain
# end
# wipe_user_data user
# end
# end
# Baguette::Log.debug "total: #{orphans.size} orphans"
#
# Response::OrphanDomainList.new orphans
Response::Error.new "Not implemented."
end
def get_zone(user_id : UserDataID, domain : String) : IPC::JSON
user_data = user_must_exist! user_id
user_must_exist! user_id
zone = zone_must_exist! domain
user_should_own! user_id, domain
Response::Zone.new zone
end
def wipe_user_data(user_data : UserData)
domains_by_owners.get(user_id.to_s).each do |d|
end
# Remove the user's domains.
user_data.domains.each do |domain|
tokens_by_domain.delete domain
zones_by_domain.delete domain
rescue e
Baguette::Log.error "while removing a domain: #{e}"
def wipe_user_data(user_id : UserDataID)
domains_by_owners.get(user_id.to_s).each do |domain|
domain.owners.delete user_id
# Remove the user's domain when he is the only owner.
if domain.owners.empty?
@domains_by_name.delete domain.name
@tokens_by_domain.delete domain.name
@zones_by_domain.delete domain.name
else
@domains_by_name.update_or_create domain.name, domain
end
end
rescue e
Baguette::Log.error "while removing a domain: #{e}"
end
def delete_user_data(user_id : UserDataID, user_to_delete : UserDataID?) : IPC::JSON
user_data = user_must_exist! user_id
user_data_to_delete = if u = user_to_delete
user_must_exist! user_id
user_id_to_delete = if u = user_to_delete
user_must_be_admin! user_id
Baguette::Log.info "Admin #{user_id} removes data of user #{u}."
user_must_exist! u
u
else
Baguette::Log.info "User #{user_data.uid} terminates his account."
user_data
Baguette::Log.info "User #{user_id} terminates his account."
user_id
end
wipe_user_data user_data_to_delete
wipe_user_data user_id_to_delete
Response::Success.new
end
def user_domains(user_id : UserDataID) : IPC::JSON
user_data = user_must_exist! user_id
Response::DomainList.new user_data.domains
def user_domains(user_id : UserDataID) : Array(String)
user_must_exist! user_id
domains_by_owners.get(user_id.to_s).map &.name
end
# TODO: is the user known from authd?
def user_must_exist!(user_id : UserDataID)
@dnsmanagerd.authd.get_user? user.uid
dnsmanagerd().authd.get_user? user_id
end
def user_must_be_admin!(user_id : UserDataID) : Nil
@dnsmanagerd.assert_permissions! user_id, "*", AuthD::User::PermissionLevel::Admin
dnsmanagerd().assert_permissions! user_id, "*", AuthD::User::PermissionLevel::Admin
end
def zone_must_exist!(domain : String) : Zone
@ -335,13 +348,13 @@ class DNSManager::Storage
# TODO: accept admin users to override this test.
def user_should_own!(user_id : UserDataID, domain : String)
d = domains_by_name.get domain
unless d.includes? user_id
unless d.owners.includes? user_id
raise NoOwnershipException.new
end
end
def new_token(user_id : UserDataID, domain : String, rrid : UInt32) : IPC::JSON
user_data = user_must_exist! user_id
user_must_exist! user_id
zone = zone_must_exist! domain
user_should_own! user_id, domain