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

This commit is contained in:
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) def initialize(@configuration)
super() 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 @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}." raise "Cannot authenticate to authd with login #{@configuration.login}: #{response}."
end end
@storage.dnsmanagerd = self
self.timer @configuration.ipc_timer self.timer @configuration.ipc_timer
self.service_init @configuration.service_name self.service_init @configuration.service_name
end end

View File

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

View File

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

View File

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

View File

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