Use cached indexes.

dev
Philippe PITTOLI 2024-05-07 01:32:37 +02:00
parent 158d772727
commit 4923fb34f9
5 changed files with 56 additions and 36 deletions

View File

@ -15,15 +15,14 @@ class DNSManager::Request
# "dnsmanager-last-connection" => JSON::Any.new Time.utc.to_s
#}
user_id = response.user.uid
dnsmanagerd.storage.user_must_exist! user_id
accepted_domains = dnsmanagerd.configuration.accepted_domains.not_nil!
# Limit the number of domains in this message.
# Pagination will be required beyond a hundred domains.
user_domains = dnsmanagerd.storage.user_domains(user_id).[0..100]
perms = dnsmanagerd.check_permissions user_id, "*"
Response::Logged.new (perms == AuthD::User::PermissionLevel::Admin), accepted_domains, user_domains
else
Response::ErrorInvalidToken.new

View File

@ -8,16 +8,16 @@ require "dodb"
class DNSManager::Storage
getter domains : DODB::CachedDataBase(Domain)
getter domains_by_name : DODB::Index(Domain)
getter domains_by_share_key : DODB::Index(Domain)
getter domains_by_transfer_key : DODB::Index(Domain)
getter domains_by_name : DODB::CachedIndex(Domain)
getter domains_by_share_key : DODB::CachedIndex(Domain)
getter domains_by_transfer_key : DODB::CachedIndex(Domain)
getter domains_by_owners : DODB::Tags(Domain)
getter zones : DODB::CachedDataBase(Zone)
getter zones_by_domain : DODB::Index(Zone)
getter zones_by_domain : DODB::CachedIndex(Zone)
getter tokens : DODB::CachedDataBase(Token)
getter tokens_by_uuid : DODB::Index(Token)
getter tokens_by_uuid : DODB::CachedIndex(Token)
getter tokens_by_domain : DODB::Partition(Token)
getter root : String
@ -103,8 +103,6 @@ class DNSManager::Storage
end
def get_generated_zonefile(user_id : UserDataID, domain : String) : IPC::JSON
user_must_exist! user_id
zone = zone_must_exist! domain
user_should_own! user_id, zone.domain
@ -118,8 +116,6 @@ class DNSManager::Storage
user_id : UserDataID,
domain : String) : IPC::JSON
user_must_exist! user_id
# Prevent future very confusing errors.
domain = domain.downcase
@ -164,7 +160,6 @@ class DNSManager::Storage
end
def ask_share_token(user_id : UserDataID, domain_name : String)
user_must_exist! user_id
user_should_own! user_id, domain_name
domain = @domains_by_name.get domain_name
@ -178,7 +173,6 @@ class DNSManager::Storage
end
def ask_transfer_token(user_id : UserDataID, domain_name : String)
user_must_exist! user_id
user_should_own! user_id, domain_name
domain = @domains_by_name.get domain_name
@ -194,13 +188,12 @@ class DNSManager::Storage
# Check the domain owners.
# In case there's only the requesting user, allow him to gain full control.
def ask_unshare_domain(user_id : UserDataID, domain_name : String)
user_must_exist! user_id
user_should_own! user_id, domain_name
domain = @domains_by_name.get domain_name
if domain.owners.size == 1 && domain.owners[0] == user_id
domain.share_key = nil
@domains_by_name.update_or_create domain_name, domain
@domains_by_name.update domain
Response::DomainChanged.new domain
else
Response::Error.new "You are not the only owner."
@ -208,14 +201,12 @@ class DNSManager::Storage
end
def gain_ownership(user_id : UserDataID, uuid : String)
user_must_exist! user_id
if domain = @domains_by_share_key.get? uuid
if domain.owners.includes? user_id
return Response::Error.new "You already own this domain."
end
domain.owners << user_id
@domains_by_name.update_or_create domain.name, domain
@domains_by_name.update domain
Response::DomainChanged.new domain
elsif domain = @domains_by_transfer_key.get? uuid
if domain.owners.includes? user_id
@ -223,7 +214,7 @@ class DNSManager::Storage
end
domain.transfer_key = nil
domain.owners = [user_id]
@domains_by_name.update_or_create domain.name, domain
@domains_by_name.update domain
Response::DomainChanged.new domain
else
Response::Error.new "There is no key with this UUID."
@ -231,8 +222,6 @@ class DNSManager::Storage
end
def add_or_update_zone(user_id : UserDataID, zone : Zone) : IPC::JSON
user_must_exist! user_id
# Test zone validity.
if errors = zone.get_errors?
Baguette::Log.warning "zone #{zone.domain} update with errors: #{errors}"
@ -254,7 +243,6 @@ class DNSManager::Storage
end
def add_rr(user_id : UserDataID, domain : String, rr : Zone::ResourceRecord) : IPC::JSON
user_must_exist! user_id
zone = zone_must_exist! domain
user_should_own! user_id, domain
@ -281,7 +269,6 @@ class DNSManager::Storage
end
def update_rr(user_id : UserDataID, domain : String, rr : Zone::ResourceRecord) : IPC::JSON
user_must_exist! user_id
zone = zone_must_exist! domain
user_should_own! user_id, domain
@ -303,8 +290,7 @@ class DNSManager::Storage
end
def delete_rr(user_id : UserDataID, domain : String, rrid : UInt32) : IPC::JSON
user_must_exist! user_id
zone = zone_must_exist! domain
zone = zone_must_exist! domain
user_should_own! user_id, domain
rr = zone.rr_not_readonly! rrid
@ -321,7 +307,6 @@ class DNSManager::Storage
end
def delete_domain(user_id : UserDataID, domain_name : String) : IPC::JSON
user_must_exist! user_id
zone_must_exist! domain_name
user_should_own! user_id, domain_name
@ -370,7 +355,6 @@ class DNSManager::Storage
end
def get_zone(user_id : UserDataID, domain : String) : IPC::JSON
user_must_exist! user_id
zone = zone_must_exist! domain
user_should_own! user_id, domain
@ -395,11 +379,9 @@ class DNSManager::Storage
end
def delete_user_data(user_id : UserDataID, user_to_delete : UserDataID?) : IPC::JSON
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_id} terminates his account."
@ -412,8 +394,11 @@ class DNSManager::Storage
end
def user_domains(user_id : UserDataID) : Array(Domain)
user_must_exist! user_id
domains_by_owners.get(user_id.to_s)
if doms = domains_by_owners.get? user_id.to_s
doms
else
Array(Domain).new
end
end
# TODO: is the user known from authd?
@ -434,14 +419,16 @@ class DNSManager::Storage
# Owning a domain means to be in the owners' list of the domain.
# TODO: accept admin users to override this test.
def user_should_own!(user_id : UserDataID, domain : String) : Nil
d = domains_by_name.get domain
unless d.owners.includes? user_id
raise NoOwnershipException.new
if d = domains_by_name.get? domain
unless d.owners.includes? user_id
raise NoOwnershipException.new
end
else
raise DomainNotFoundException.new
end
end
def new_token(user_id : UserDataID, domain : String, rrid : UInt32) : IPC::JSON
user_must_exist! user_id
zone = zone_must_exist! domain
user_should_own! user_id, domain

View File

@ -14,4 +14,6 @@ class DNSManager::Storage::Domain
def initialize(@name, share_key = nil, transfer_key = nil, owners = [] of UserDataID)
end
def_clone
end

View File

@ -7,6 +7,8 @@ class DNSManager::Storage::Token
property domain : String
property rrid : UInt32
def_clone
def initialize(@domain, @rrid)
@uuid = UUID.random.to_s
end

View File

@ -35,6 +35,8 @@ class DNSManager::Storage::Zone
def initialize(@domain)
end
def_clone
alias Error = String
# Store a Resource Record: A, AAAA, TXT, PTR, CNAME…
@ -96,6 +98,8 @@ class DNSManager::Storage::Zone
end
class SOA < ResourceRecord
def_clone
# Start of Authority
property mname : String # Master Name Server for the zone.
property rname : String # admin email address john.doe@example.com => john\.doe.example.com
@ -159,6 +163,8 @@ class DNSManager::Storage::Zone
end
class A < ResourceRecord
def_clone
def get_errors : Array(Error)
errors = [] of Error
@ -179,6 +185,8 @@ class DNSManager::Storage::Zone
end
class AAAA < ResourceRecord
def_clone
def get_errors : Array(Error)
errors = [] of Error
@ -199,6 +207,8 @@ class DNSManager::Storage::Zone
end
class TXT < ResourceRecord
def_clone
def get_errors : Array(Error)
errors = [] of Error
@ -224,6 +234,8 @@ class DNSManager::Storage::Zone
end
class PTR < ResourceRecord
def_clone
def get_errors : Array(Error)
errors = [] of Error
@ -252,6 +264,8 @@ class DNSManager::Storage::Zone
end
class NS < ResourceRecord
def_clone
def get_errors : Array(Error)
errors = [] of Error
@ -268,6 +282,8 @@ class DNSManager::Storage::Zone
end
class CNAME < ResourceRecord
def_clone
def get_errors : Array(Error)
errors = [] of Error
@ -289,7 +305,7 @@ class DNSManager::Storage::Zone
# TODO: verifications + print.
# baguette.netlib.re. 3600 IN TXT "v=spf1 a mx ip4:<IP> a:mail.baguette.netlib.re ~all"
class SPF < ResourceRecord
def_clone
# SPF mechanisms are about policy, which comes with the form of a single character:
# - '?' means no policy (neutral),
@ -332,6 +348,8 @@ class DNSManager::Storage::Zone
property t : Type # type of modifier
property v : String # value
def_clone
def initialize(@t, @v)
end
@ -362,6 +380,8 @@ class DNSManager::Storage::Zone
INCLUDE # include foreign SPF policy
end
def_clone
property q : Qualifier = Qualifier::Pass
property t : Type # type of mechanism
property v : String # value
@ -484,6 +504,7 @@ class DNSManager::Storage::Zone
# TODO
class DKIM < ResourceRecord
def_clone
enum Version
DKIM1
end
@ -508,6 +529,8 @@ class DNSManager::Storage::Zone
io << "v=#{v};h=#{h.to_s.downcase};k=#{k.to_s.downcase};p=#{p}"
io << ";n=#{n}" unless n == ""
end
def_clone
end
property dkim : DKIMProperties
@ -542,6 +565,7 @@ class DNSManager::Storage::Zone
# TODO
class DMARC < ResourceRecord
def_clone
enum Version
DMARC1
end
@ -551,6 +575,8 @@ class DNSManager::Storage::Zone
property mail : String
property limit : UInt32? = nil
def_clone
def to_s(io : IO)
io << "#{mail}"
if l = @limit
@ -596,6 +622,8 @@ class DNSManager::Storage::Zone
property rf : Array(ReportFormat)? = nil
property ri : UInt32
def_clone
def initialize(@p, @sp, @v, @adkim, @aspf, @pct, @fo, @rua, @ruf, @rf, @ri)
end
@ -694,6 +722,7 @@ class DNSManager::Storage::Zone
end
class MX < ResourceRecord
def_clone
property priority : UInt32 = 10
def initialize(@name, @ttl, @target, @priority = 10)
@rrtype = "MX"
@ -729,6 +758,7 @@ class DNSManager::Storage::Zone
end
class SRV < ResourceRecord
def_clone
property port : UInt16
property protocol : String = "tcp"
property priority : UInt32 = 10