Use exceptions extensively.
parent
8824835975
commit
8534dcb246
29
src/main.cr
29
src/main.cr
|
@ -11,10 +11,24 @@ require "./config"
|
|||
module DNSManager
|
||||
class Exception < ::Exception
|
||||
end
|
||||
class DomainNotFoundException < ::Exception
|
||||
end
|
||||
class UnknownUserException < ::Exception
|
||||
end
|
||||
class RRReadOnlyException < ::Exception
|
||||
property domain : String
|
||||
property rr : DNSManager::Storage::Zone::ResourceRecord
|
||||
def initialize(@domain, @rr)
|
||||
end
|
||||
end
|
||||
class AuthorizationException < ::Exception
|
||||
end
|
||||
class NoOwnershipException < ::Exception
|
||||
end
|
||||
class NotLoggedException < ::Exception
|
||||
end
|
||||
class RRNotFoundException < ::Exception
|
||||
end
|
||||
class AdminAuthorizationException < ::Exception
|
||||
end
|
||||
end
|
||||
|
@ -85,12 +99,27 @@ class DNSManager::Service < IPC
|
|||
rescue e : AuthorizationException
|
||||
Baguette::Log.error "#{reqname} authorization error"
|
||||
Response::Error.new "authorization error"
|
||||
rescue e : DomainNotFoundException
|
||||
Baguette::Log.error "#{reqname} domain not found"
|
||||
Response::DomainNotFound.new
|
||||
rescue e : UnknownUserException
|
||||
Baguette::Log.error "#{reqname} unknown user"
|
||||
Response::UnknownUser.new
|
||||
rescue e : NoOwnershipException
|
||||
Baguette::Log.error "#{reqname} no ownership error"
|
||||
Response::NoOwnership.new
|
||||
rescue e : AdminAuthorizationException
|
||||
Baguette::Log.error "#{reqname} no admin authorization"
|
||||
Response::Error.new "admin authorization error"
|
||||
rescue e : NotLoggedException
|
||||
Baguette::Log.error "#{reqname} user not logged"
|
||||
Response::Error.new "user not logged"
|
||||
rescue e : RRNotFoundException
|
||||
Baguette::Log.error "#{reqname} RR not found"
|
||||
Response::RRNotFound.new
|
||||
rescue e : RRReadOnlyException
|
||||
Baguette::Log.error "#{reqname} RR is read only"
|
||||
Response::RRReadOnly.new e.domain, e.rr
|
||||
rescue e # Generic case
|
||||
Baguette::Log.error "#{reqname} generic error #{e}"
|
||||
DNSManager::Response::Error.new "generic error"
|
||||
|
|
218
src/storage.cr
218
src/storage.cr
|
@ -97,20 +97,10 @@ class DNSManager::Storage
|
|||
end
|
||||
|
||||
def get_generated_zonefile(user_id : Int32, domain : String) : IPC::JSON
|
||||
zone = zones_by_domain.get? domain
|
||||
return Response::DomainNotFound.new unless zone
|
||||
|
||||
# User must own the zone.
|
||||
user_data = user_data_by_uid.get? user_id.to_s
|
||||
unless user_data
|
||||
Baguette::Log.warning "unknown user #{user_id} asked a zonefile for domain #{domain}"
|
||||
return Response::UnknownUser.new
|
||||
end
|
||||
|
||||
unless user_data.domains.includes?(zone.domain) || user_data.admin
|
||||
Baguette::Log.warning "user #{user_id} doesn't own domain #{zone.domain}"
|
||||
return Response::NoOwnership.new
|
||||
end
|
||||
user_data = user_must_exist! user_id
|
||||
zone = zone_must_exist! domain
|
||||
user_should_own! user_data, zone.domain
|
||||
|
||||
io = IO::Memory.new
|
||||
zone.to_bind9 io
|
||||
|
@ -122,12 +112,7 @@ class DNSManager::Storage
|
|||
user_id : Int32,
|
||||
domain : String) : IPC::JSON
|
||||
|
||||
# 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 domain #{domain}"
|
||||
return Response::UnknownUser.new
|
||||
end
|
||||
user_data = user_must_exist! user_id
|
||||
|
||||
return Response::DomainAlreadyExists.new if zones_by_domain.get? domain
|
||||
|
||||
|
@ -167,26 +152,17 @@ class DNSManager::Storage
|
|||
end
|
||||
|
||||
def add_or_update_zone(user_id : Int32, zone : Zone) : IPC::JSON
|
||||
user_data = user_must_exist! user_id
|
||||
|
||||
# Test zone validity.
|
||||
if errors = zone.get_errors?
|
||||
Baguette::Log.warning "zone #{zone.domain} update with errors: #{errors}"
|
||||
return 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) || user_data.admin
|
||||
Baguette::Log.warning "user #{user_id} doesn't own domain #{zone.domain}"
|
||||
return Response::NoOwnership.new
|
||||
end
|
||||
user_should_own! user_data, z.domain
|
||||
else
|
||||
# Add the domain to the user's domain.
|
||||
user_data.domains << zone.domain
|
||||
|
@ -199,28 +175,12 @@ class DNSManager::Storage
|
|||
zones_by_domain.update_or_create zone.domain, zone
|
||||
|
||||
Response::Success.new
|
||||
rescue e
|
||||
Baguette::Log.error "trying to add -or update- zone #{zone.domain}: #{e}"
|
||||
Response::Error.new "error while adding or updating the domain #{zone.domain}"
|
||||
end
|
||||
|
||||
def add_rr(user_id : Int32, domain : String, rr : Zone::ResourceRecord) : IPC::JSON
|
||||
# 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 a RR in domain #{domain}"
|
||||
return Response::UnknownUser.new
|
||||
end
|
||||
|
||||
# Zone must exist.
|
||||
zone = zones_by_domain.get? domain
|
||||
return Response::DomainNotFound.new unless zone
|
||||
|
||||
# User must own the zone.
|
||||
unless user_data.domains.includes?(domain) || user_data.admin
|
||||
Baguette::Log.warning "user #{user_id} doesn't own domain #{domain}"
|
||||
return Response::NoOwnership.new
|
||||
end
|
||||
user_data = user_must_exist! user_id
|
||||
zone = zone_must_exist! domain
|
||||
user_should_own! user_data, domain
|
||||
|
||||
# Test RR validity.
|
||||
rr.get_errors.tap do |errors|
|
||||
|
@ -235,9 +195,6 @@ class DNSManager::Storage
|
|||
update_zone zone
|
||||
|
||||
Response::RRAdded.new zone.domain, rr
|
||||
rescue e
|
||||
Baguette::Log.error "trying to add a resource record in domain #{domain}: #{e}"
|
||||
Response::Error.new "error while adding a resource record in domain #{domain}"
|
||||
end
|
||||
|
||||
# Any modification of the zone must be performed here.
|
||||
|
@ -248,29 +205,11 @@ class DNSManager::Storage
|
|||
end
|
||||
|
||||
def update_rr(user_id : Int32, domain : String, rr : Zone::ResourceRecord) : IPC::JSON
|
||||
# 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 update a RR in domain #{domain}"
|
||||
return Response::UnknownUser.new
|
||||
end
|
||||
user_data = user_must_exist! user_id
|
||||
zone = zone_must_exist! domain
|
||||
user_should_own! user_data, domain
|
||||
|
||||
# Zone must exist.
|
||||
zone = zones_by_domain.get? domain
|
||||
return Response::DomainNotFound.new unless zone
|
||||
|
||||
# User must own the zone.
|
||||
unless user_data.domains.includes?(domain) || user_data.admin
|
||||
Baguette::Log.warning "user #{user_id} doesn't own domain #{domain}"
|
||||
return Response::NoOwnership.new
|
||||
end
|
||||
|
||||
# Verify the RR exists.
|
||||
stored_rr = zone.get_rr rr.rrid
|
||||
return Response::RRNotFound.new unless stored_rr
|
||||
|
||||
# Verify the RR isn't read only.
|
||||
return Response::RRReadOnly.new domain, stored_rr if stored_rr.readonly
|
||||
zone.rr_not_readonly! rr.rrid
|
||||
|
||||
# Test RR validity.
|
||||
rr.get_errors.tap do |errors|
|
||||
|
@ -282,68 +221,33 @@ class DNSManager::Storage
|
|||
|
||||
zone.update_rr rr
|
||||
|
||||
zone.resources = zone.resources.map { |x| x.rrid == rr.rrid ? rr : x }
|
||||
|
||||
update_zone zone
|
||||
|
||||
Response::RRUpdated.new domain, rr
|
||||
rescue e
|
||||
Baguette::Log.error "trying to replace a resource record in domain #{domain}: #{e}"
|
||||
Response::Error.new "error while replacing a resource record in domain #{domain}"
|
||||
end
|
||||
|
||||
def delete_rr(user_id : Int32, domain : String, rrid : UInt32) : IPC::JSON
|
||||
# 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 a RR in domain #{domain}"
|
||||
return Response::UnknownUser.new
|
||||
end
|
||||
user_data = user_must_exist! user_id
|
||||
zone = zone_must_exist! domain
|
||||
user_should_own! user_data, domain
|
||||
|
||||
# Zone must exist.
|
||||
zone = zones_by_domain.get? domain
|
||||
return Response::DomainNotFound.new unless zone
|
||||
|
||||
# User must own the zone.
|
||||
unless user_data.domains.includes?(domain) || user_data.admin
|
||||
Baguette::Log.warning "user #{user_id} doesn't own domain #{domain}"
|
||||
return Response::NoOwnership.new
|
||||
end
|
||||
|
||||
# Verify the RR exists.
|
||||
rr = zone.get_rr rrid
|
||||
return Response::RRNotFound.new unless rr
|
||||
|
||||
# Verify the RR isn't read only.
|
||||
return Response::RRReadOnly.new domain, rr if rr.readonly
|
||||
rr = zone.rr_not_readonly! rrid
|
||||
|
||||
# Remove token from the db.
|
||||
if token_uuid = rr.token
|
||||
tokens_by_uuid.delete token_uuid
|
||||
end
|
||||
zone.resources.select! { |x| x.rrid != rrid }
|
||||
|
||||
zone.delete_rr rrid
|
||||
update_zone zone
|
||||
|
||||
Response::RRDeleted.new rrid
|
||||
rescue e
|
||||
Baguette::Log.error "trying to remove a resource record in domain #{domain}: #{e}"
|
||||
Response::Error.new "error while removing a resource record in domain #{domain}"
|
||||
end
|
||||
|
||||
def delete_domain(user_id : Int32, domain : String) : IPC::JSON
|
||||
# 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) || user_data.admin
|
||||
Baguette::Log.warning "user #{user_id} tries to delete domain #{domain} but doesn't own it"
|
||||
return Response::NoOwnership.new
|
||||
end
|
||||
user_data = user_must_exist! user_id
|
||||
zone_must_exist! domain
|
||||
user_should_own! user_data, domain
|
||||
|
||||
# Remove this domain from the list of user's domains.
|
||||
user_data.domains.delete domain
|
||||
|
@ -356,73 +260,45 @@ class DNSManager::Storage
|
|||
tokens_by_domain.delete domain
|
||||
|
||||
Response::DomainDeleted.new domain
|
||||
rescue e
|
||||
Baguette::Log.error "trying to delete a domain #{domain}: #{e}"
|
||||
Response::Error.new "error while deleting the domain #{domain}"
|
||||
end
|
||||
|
||||
def get_zone(user_id : Int32, domain : String) : IPC::JSON
|
||||
# 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 get zone #{domain}"
|
||||
return Response::UnknownUser.new
|
||||
end
|
||||
|
||||
# User must own the domain.
|
||||
unless user_data.domains.includes?(domain) || user_data.admin
|
||||
Baguette::Log.warning "user #{user_id} tries to get zone #{domain} but doesn't own it"
|
||||
return Response::NoOwnership.new
|
||||
end
|
||||
|
||||
zone = zones_by_domain.get? domain
|
||||
unless zone
|
||||
return Response::UnknownZone.new
|
||||
end
|
||||
user_data = user_must_exist! user_id
|
||||
zone = zone_must_exist! domain
|
||||
user_should_own! user_data, domain
|
||||
|
||||
Response::Zone.new zone
|
||||
rescue e
|
||||
Baguette::Log.error "trying to get a zone #{domain}: #{e}"
|
||||
Response::Error.new "error while accessing a zone #{domain}"
|
||||
end
|
||||
|
||||
def user_domains(user_id : Int32) : IPC::JSON
|
||||
# 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 list its domains"
|
||||
return Response::UnknownUser.new
|
||||
user_data = user_must_exist! user_id
|
||||
Response::DomainList.new user_data.domains
|
||||
end
|
||||
|
||||
Response::DomainList.new user_data.domains
|
||||
rescue e
|
||||
Baguette::Log.error "trying to list all user #{user_id} domains: #{e}"
|
||||
Response::Error.new "error while listing domains"
|
||||
def user_must_exist!(user_id : Int32) : UserData
|
||||
user_data = user_data_by_uid.get? user_id.to_s
|
||||
raise UnknownUserException.new unless user_data
|
||||
user_data
|
||||
end
|
||||
|
||||
def zone_must_exist!(domain : String) : Zone
|
||||
zone = zones_by_domain.get? domain
|
||||
raise DomainNotFoundException.new unless zone
|
||||
zone
|
||||
end
|
||||
|
||||
def user_should_own!(user_data : UserData, domain : String)
|
||||
unless user_data.domains.includes?(domain) || user_data.admin
|
||||
raise NoOwnershipException.new
|
||||
end
|
||||
end
|
||||
|
||||
def new_token(user_id : Int32, domain : String, rrid : UInt32) : IPC::JSON
|
||||
# 0. verifications: must exist: user, zone, RR. Zone must be owned by user.
|
||||
user_data = user_must_exist! user_id
|
||||
zone = zone_must_exist! domain
|
||||
user_should_own! user_data, domain
|
||||
|
||||
# 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 get a new token for a RR in domain #{domain}"
|
||||
return Response::UnknownUser.new
|
||||
end
|
||||
|
||||
# Zone must exist.
|
||||
zone = zones_by_domain.get? domain
|
||||
return Response::DomainNotFound.new unless zone
|
||||
|
||||
# User should own it.
|
||||
unless user_data.domains.includes?(domain) || user_data.admin
|
||||
Baguette::Log.warning "user #{user_id} doesn't own domain #{domain}"
|
||||
return Response::NoOwnership.new
|
||||
end
|
||||
|
||||
# RR must exist.
|
||||
rr = zone.get_rr rrid
|
||||
return Response::RRNotFound.new unless rr
|
||||
rr = zone.rr_must_exist! rrid
|
||||
|
||||
old_token = rr.token
|
||||
|
||||
|
|
|
@ -630,10 +630,26 @@ class DNSManager::Storage::Zone
|
|||
end
|
||||
end
|
||||
|
||||
def rr_must_exist!(rrid : UInt32) : ResourceRecord
|
||||
rr = get_rr rrid
|
||||
raise RRNotFoundException.new unless rr
|
||||
rr
|
||||
end
|
||||
|
||||
def rr_not_readonly!(rrid : UInt32) : ResourceRecord
|
||||
rr = rr_must_exist! rrid
|
||||
raise RRReadOnlyException.new @domain, rr if rr.readonly
|
||||
rr
|
||||
end
|
||||
|
||||
def update_rr(rr : ResourceRecord)
|
||||
@resources.map! { |x| x.rrid != rr.rrid ? x : rr }
|
||||
end
|
||||
|
||||
def delete_rr(rrid : UInt32)
|
||||
@resources.select! { |x| x.rrid != rrid }
|
||||
end
|
||||
|
||||
def to_s(io : IO)
|
||||
io << "DOMAIN #{@domain}.\n"
|
||||
@resources.each do |rr|
|
||||
|
|
Loading…
Reference in New Issue