diff --git a/src/main.cr b/src/main.cr index 46d7619..3368198 100644 --- a/src/main.cr +++ b/src/main.cr @@ -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 diff --git a/src/requests/admin.cr b/src/requests/admin.cr index 6861996..65f46ea 100644 --- a/src/requests/admin.cr +++ b/src/requests/admin.cr @@ -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 diff --git a/src/requests/user.cr b/src/requests/user.cr index 5ce4041..13eefb7 100644 --- a/src/requests/user.cr +++ b/src/requests/user.cr @@ -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 diff --git a/src/requests/zone.cr b/src/requests/zone.cr index cef395e..004898e 100644 --- a/src/requests/zone.cr +++ b/src/requests/zone.cr @@ -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 diff --git a/src/storage.cr b/src/storage.cr index 6742a15..97b46d1 100644 --- a/src/storage.cr +++ b/src/storage.cr @@ -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