127 lines
3.5 KiB
Crystal
127 lines
3.5 KiB
Crystal
require "json"
|
|
require "uuid"
|
|
require "uuid/json"
|
|
require "baguette-crystal-base"
|
|
|
|
require "dodb"
|
|
|
|
class DNSManager::Storage
|
|
getter user_data : DODB::CachedDataBase(UserData)
|
|
getter user_data_by_uid : DODB::Index(UserData)
|
|
|
|
getter zones : DODB::CachedDataBase(Zone)
|
|
getter zones_by_domain : DODB::Index(Zone)
|
|
|
|
def initialize(@root : String, reindex : Bool = false)
|
|
@user_data = DODB::CachedDataBase(UserData).new "#{@root}/user-data"
|
|
@user_data_by_uid = @user_data.new_index "uid", &.uid.to_s
|
|
@zones = DODB::CachedDataBase(Zone).new "#{@root}/zones"
|
|
@zones_by_domain = @zones.new_index "domain", &.domain
|
|
|
|
Baguette::Log.info "storage initialized"
|
|
|
|
if reindex
|
|
Baguette::Log.debug "Reindexing user data..."
|
|
@user_data.reindex_everything!
|
|
Baguette::Log.debug "Reindexing zones..."
|
|
@zones.reindex_everything!
|
|
Baguette::Log.debug "Reindexed!"
|
|
end
|
|
end
|
|
|
|
def get_user_data(uid : Int32)
|
|
user_data_by_uid.get uid.to_s
|
|
rescue e : DODB::MissingEntry
|
|
entry = UserData.new uid
|
|
entry
|
|
end
|
|
|
|
def get_user_data(user : ::AuthD::User::Public)
|
|
get_user_data user.uid
|
|
end
|
|
|
|
def update_user_data(user_data : UserData)
|
|
user_data_by_uid.update_or_create user_data.uid.to_s, user_data
|
|
end
|
|
|
|
def ensure_user_data(user_id : Int32)
|
|
user_data = user_data_by_uid.get? user_id.to_s
|
|
unless user_data
|
|
Baguette::Log.info "New user #{user_id}"
|
|
@user_data << Storage::UserData.new user_id
|
|
end
|
|
|
|
Response::Success.new
|
|
end
|
|
|
|
def add_or_update_zone(user_id : Int32, zone : Zone) : IPC::JSON
|
|
# 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
|
|
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 -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) : 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
|
|
Baguette::Log.warning "user #{user_id} tries to delete domain #{domain} but doesn't own it"
|
|
return Response::NoOwnership.new
|
|
end
|
|
|
|
# Remove this domain from the list of user's domains.
|
|
user_data.domains.delete domain
|
|
|
|
# Update on-disk user data.
|
|
update_user_data user_data
|
|
|
|
# Remove the related zone.
|
|
zones_by_domain.delete domain
|
|
|
|
Response::Success.new
|
|
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/*"
|