From 6ae06ae8396b48ee6d58df3273cfeb7caccaaa1a Mon Sep 17 00:00:00 2001 From: Philippe Pittoli Date: Sun, 7 May 2023 16:45:09 +0200 Subject: [PATCH] WIP (cannot compile ATM): add, update and remove zones. --- src/requests/zone.cr | 29 +++++++++-------- src/responses/user.cr | 13 ++++++++ src/responses/zone.cr | 9 ++++- src/storage.cr | 76 ++++++++++++++++++++++++++++++++++++------- 4 files changed, 101 insertions(+), 26 deletions(-) create mode 100644 src/responses/user.cr diff --git a/src/requests/zone.cr b/src/requests/zone.cr index 2f9743a..0bff366 100644 --- a/src/requests/zone.cr +++ b/src/requests/zone.cr @@ -11,21 +11,22 @@ class DNSManager::Request def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) user = dnsmanagerd.get_logged_user event raise NotLoggedException.new if user.nil? - - # TODO: test for zone validity. - if errors = zone.get_errors? - return DNSManager::Response::InvalidZone.new errors - end - - # In case there is no error, retrieve the zone in the DB. - #z = dnsmanagerd.storage.zones_by_domain.get? zone.domain - #if z - #else - # dnsmanagerd.storage.zones << @zone - #end - - Response::Success.new + dnsmanagerd.storage.add_or_update_zone user.uid, zone end end DNSManager.requests << AddOrUpdateZone + + IPC::JSON.message DeleteZone, 11 do + property domain : String + + def initialize(@domain) + end + + def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event) + user = dnsmanagerd.get_logged_user event + raise NotLoggedException.new if user.nil? + dnsmanagerd.storage.delete_domain user.uid, @domain + end + end + DNSManager.requests << DeleteZone end diff --git a/src/responses/user.cr b/src/responses/user.cr new file mode 100644 index 0000000..c8ffab0 --- /dev/null +++ b/src/responses/user.cr @@ -0,0 +1,13 @@ +class DNSManager::Response + IPC::JSON.message UnknownUser, 50 do + def initialize + end + end + DNSManager.responses << UnknownUser + + IPC::JSON.message NoOwnership, 51 do + def initialize + end + end + DNSManager.responses << NoOwnership +end diff --git a/src/responses/zone.cr b/src/responses/zone.cr index b589002..927ca7a 100644 --- a/src/responses/zone.cr +++ b/src/responses/zone.cr @@ -2,10 +2,17 @@ class DNSManager::Response IPC::JSON.message InvalidZone, 10 do # For now, Error is just an alias on String. - property errors : Array(DNSManager::Storage::Zone::Error) + property errors : Array(Storage::Zone::Error) def initialize(@errors) end end DNSManager.responses << InvalidZone + + # Domain of a zone cannot change, for security reasons. + IPC::JSON.message DomainChanged, 11 do + def initialize + end + end + DNSManager.responses << DomainChanged end diff --git a/src/storage.cr b/src/storage.cr index 19c1621..8254fe1 100644 --- a/src/storage.cr +++ b/src/storage.cr @@ -44,21 +44,75 @@ class DNSManager::Storage user_data_by_uid.update_or_create user_data.uid.to_s, user_data end - def new_domain(user_id : Int32, zone : Zone) - user_data = user_data_by_uid.get? user_id.to_s - if user_data - # store the new zone - @zones << zone + def add_or_update_zone(user_id : Int32, zone : Zone) - # update user data only after ensuring this zone isn't already existing - user_data.domains << zone.domain - update_user_data user_data - else - Baguette::Log.error "trying to add zone #{zone.domain} to unknown user #{user_id}" + # Test zone validity. + if errors = zone.get_errors? + Baguette::Log.warning "zone #{zone.domain} update with errors: #{errors}" + return DNSManager::Response::InvalidZone.new errors end + + # User must exist. + user_data = user_data_by_uid.get? user_id.to_s + unless user_data + Baguette::Log.warning "unknown user #{user_id} tries to add -or update- zone #{zone.domain}" + return Response::UnknownUser.new + end + + # Does the zone already exist? + if z = zones_by_domain.get? zone.domain + # User must own the zone. + unless user_data.domains.includes? zone.domain + Baguette::Log.warning "user #{user_id} doesn't own domain #{zone.domain}" + return Response::NoOwnership.new + end + + # Domain cannot change (for security reasons). + unless z.domain == zone.domain + Baguette::Log.warning "user #{user_id} tries to change domain #{z.domain} by #{zone.domain}" + return Response::DomainChanged.new + end + else + # Add the domain to the user's domain. + user_data.domains << zone.domain + + # Actually write data on-disk. + update_user_data user_data + end + + # Add -or replace- the zone. + zones_by_domain.update_or_create zone.domain, zone + + Response::Success.new rescue e - Baguette::Log.error "trying to add zone #{zone.domain} #{e}" + Baguette::Log.error "trying to add -or update- zone #{zone.domain}: #{e}" + Response::Error.new "error while updating the domain #{zone.domain}" end + + def delete_domain(user_id : Int32, domain : String) + # User must exist. + user_data = user_data_by_uid.get? user_id.to_s + unless user_data + Baguette::Log.warning "unknown user #{user_id} tries to delete domain #{domain}" + return Response::UnknownUser.new + end + + # User must own the domain. + unless user_data.domains.includes? domain + Baguette::Log.warning "user #{user_id} tries to delete domain #{domain} doesn't own it" + return Response::NoOwnership.new + end + + # TODO: remove this domain from the list of user's domains. + # TODO: remove the related zone. + #unless errors = Storage::Zone.is_domain_valid? domain + # return Response::InvalidZone.new errors + #end + rescue e + Baguette::Log.error "trying to delete a domain #{domain}: #{e}" + Response::Error.new "error while deleting the domain #{domain}" + end + end require "./storage/*"