Use cached indexes.
This commit is contained in:
		
							parent
							
								
									158d772727
								
							
						
					
					
						commit
						4923fb34f9
					
				
					 5 changed files with 56 additions and 36 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,4 +14,6 @@ class DNSManager::Storage::Domain
 | 
			
		|||
 | 
			
		||||
	def initialize(@name, share_key = nil, transfer_key = nil, owners = [] of UserDataID)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	def_clone
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue