Adding a client (draft) and domain test.

master
Karchnu 2020-12-12 05:38:16 +01:00
parent c1ef4f6235
commit 7f5d162e91
9 changed files with 320 additions and 6 deletions

View File

@ -0,0 +1,13 @@
def authd_get_token(key_file : String? = nil, login : String? = nil, pass : String? = nil)
authd = AuthD::Client.new
key_file.try do |file| # FIXME: fail if missing?
authd.key = File.read(file).chomp
end
token = authd.get_token? login, pass
raise "cannot get a token" if token.nil?
authd.close
token
end

View File

@ -0,0 +1,46 @@
require "../../requests/*"
class DNSManager::Client < IPC::Client
def initialize
initialize "dnsmanager"
end
# TODO: parse_message should raise exception if response not anticipated
def parse_message(expected_messages, message)
em = Array(IPC::JSON.class).new
expected_messages.each do |e|
em << e
end
em << DNSManager::Response::Error
em.parse_ipc_json message
end
end
# Simple users.
class DNSManager::Client < IPC::Client
def login(token : String)
request = DNSManager::Request::Login.new token
send_now @server_fd.not_nil!, request
parse_message [ DNSManager::Response::Success ], read
end
# Adding a full zone.
def user_zone_add(zone : DNSManager::Storage::Zone)
request = DNSManager::Request::AddZone.new zone
send_now @server_fd.not_nil!, request
parse_message [ DNSManager::Response::Success ], read
end
end
# Admin stuff.
class DNSManager::Client < IPC::Client
def admin_maintainance(key : String, subject : DNSManager::Request::Maintainance::Subject, value : Int32? = nil)
request = DNSManager::Request::Maintainance.new(key,subject)
if value
request.value = value
end
send_now @server_fd.not_nil!, request
parse_message [ DNSManager::Response::Success ], read
end
end

View File

@ -0,0 +1,15 @@
# YAML UUID parser
def UUID.new(ctx : YAML::ParseContext, node : YAML::Nodes::Node)
ctx.read_alias(node, UUID) do |obj|
return UUID.new obj
end
if node.is_a?(YAML::Nodes::Scalar)
value = node.value
ctx.record_anchor(node, value)
UUID.new value
else
node.raise "Expected UUID, not #{node.class.name}"
end
end

View File

@ -17,9 +17,9 @@ end
require "./parser.cr"
#def read_searches
# Array(DNSManager::Request::BLAH).from_json_files Context.args.not_nil!
#end
def read_zones
Array(DNSManager::Storage::Zone).from_json_files Context.args.not_nil!
end
class Actions
property the_call = {} of String => Proc(Nil)
@ -34,7 +34,8 @@ class Actions
#
# Maintainance
@the_call["admin-maintainance"] = ->admin_maintainance
@the_call["admin-maintainance"] = ->admin_maintainance
@the_call["user-zone-add"] = ->user_zone_add
end
def admin_maintainance
@ -66,6 +67,18 @@ class Actions
end
end
end
def user_zone_add
zones = read_zones
zones.each do |zone|
begin
pp! zone
pp! @dnsmanagerd.user_zone_add zone
rescue e
puts "error for admin_maintainance #{subject}: #{e.message}"
end
end
end
end
def main

151
src/lib.cr Normal file
View File

@ -0,0 +1,151 @@
require "uuid"
# YAML UUID parser
def UUID.new(ctx : YAML::ParseContext, node : YAML::Nodes::Node)
ctx.read_alias(node, UUID) do |obj|
return UUID.new obj
end
if node.is_a?(YAML::Nodes::Scalar)
value = node.value
ctx.record_anchor(node, value)
UUID.new value
else
node.raise "Expected UUID, not #{node.class.name}"
end
end
module YAML
# change dates in YAML formated content
def self.human_dates(content : String)
new_lines = Array(String).new
content.each_line do |line|
case line
when /(?<date>.*date):[ \t]+NOW[ \t]*(?<op>[-+])[ \t]*(?<rand>rand)?[ \t]*(?<delta>[0-9]+) *(?<scale>[a-z]+)?/
date = $~["date"]
op = $~["op"]
delta = $~["delta"].to_i
rand = $~["rand"] rescue nil
scale = $~["scale"] rescue nil # days, hours
unless rand.nil?
old = delta
delta = Random.rand(delta)
end
vdelta = delta.days
case scale
when /day/
# default one
when /hour/
vdelta = delta.hours
else
# puts "scale infered: days"
end
yaml_date = Time::Format::YAML_DATE.format(Time.local + vdelta)
case op
when /-/
yaml_date = Time::Format::YAML_DATE.format(Time.local - vdelta)
# puts "-"
when /\+/
# default one
# puts "+"
else
# puts "date operation not understood: #{op}, + infered"
end
new_lines << "#{date}: #{yaml_date}"
next
when /(?<date>.+date):[ \t]+NOW[ \t]*$/
date = $~["date"]
yaml_date = Time::Format::YAML_DATE.format(Time.local)
new_lines << "#{date}: #{yaml_date}"
next
when /(?<date>[a-z]+_date):[ \t]+NOW[ \t]*$/
date = $~["date"]
yaml_date = Time::Format::YAML_DATE.format(Time.local)
new_lines << "#{date}: #{yaml_date}"
next
# when /(?<date>[a-z]+_date):/
# puts "date that does not compute: #{line}"
end
new_lines << line
end
new_lines.join "\n"
end
end
class Array(T)
def self.from_yaml_files(files)
values = Array(T).new
files.each do |file|
raise "File doesn't exist #{file}" unless File.exists? file
from_yaml_file(file).each do |v|
values << v
end
end
values
end
def self.from_yaml_file(file)
from_yaml_content File.read file
end
def self.from_yaml_content(input_content)
content = YAML.human_dates input_content
values = Array(T).new
begin
values << T.from_yaml content
rescue e
Baguette::Log.warning "reading the input #{e}"
begin
Array(T).from_yaml(content).each do |b|
values << b
end
rescue e
raise "wrong YAML content: #{e}"
end
end
values
end
def self.from_json_files(files)
values = Array(T).new
files.each do |file|
raise "File doesn't exist #{file}" unless File.exists? file
from_json_file(file).each do |v|
values << v
end
end
values
end
def self.from_json_file(file)
from_json_content File.read file
end
def self.from_json_content(content)
values = Array(T).new
begin
values << T.from_json content
rescue e
begin
Array(T).from_json(content).each do |b|
values << b
end
rescue e
raise "wrong JSON content: #{e}"
end
end
values
end
end

View File

@ -40,7 +40,7 @@ class DNSManager::Service < IPC::Server
end
def get_logged_user(event : IPC::Event::Events)
fd = event.connection.fd
fd = event.fd
@logged_users[fd]?
end

31
src/requests/zone.cr Normal file
View File

@ -0,0 +1,31 @@
require "grok"
class DNSManager::Request
IPC::JSON.message AddOrUpdateZone, 10 do
property zone : DNSManager::Storage::Zone
def initialize(@zone)
end
def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event::Events)
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
end
end
DNSManager.requests << AddOrUpdateZone
end

11
src/responses/zone.cr Normal file
View File

@ -0,0 +1,11 @@
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)
def initialize(@errors)
end
end
DNSManager.responses << InvalidZone
end

View File

@ -9,6 +9,7 @@ class DNSManager::Storage::Zone
def initialize(@domain)
end
alias Error = String
# Store a Resource Record: A, AAAA, TXT, PTR, CNAME…
abstract class ResourceRecord
@ -27,7 +28,7 @@ class DNSManager::Storage::Zone
}
# Used to discriminate between classes.
property rrtype : String = ""
property rrtype : String = ""
property name : String
property ttl : UInt32
@ -37,6 +38,10 @@ class DNSManager::Storage::Zone
def initialize(@name, @ttl, @target)
@rrtype = self.class.name.downcase.gsub /dnsmanager::storage::zone::/, ""
end
def get_error : Error?
nil
end
end
class SOA < ResourceRecord
@ -88,4 +93,33 @@ class DNSManager::Storage::Zone
def to_s(io : IO)
io << "TEST"
end
def get_errors? : Array(Error)
errors = [] of Error
unless Zone.is_domain_valid? @domain
errors << "invalid domain"
end
@resources.each do |r|
if error = r.get_error
errors << error
end
end
errors
end
# This regex only is "good enough for now".
def self.is_domain_valid?(domain) : Bool
if domain =~ /^(((?!-))(xn--|_{1,1})?[a-z0-9-]{0,61}[a-z0-9]{1,1}\.)*((xn--)?[a-z0-9][a-z0-9\-]{0,60}[a-z0-9]|(xn--)?[a-z0-9]{1,60})\.[a-z]{2,}$/
true
else
false
end
rescue e
Baguette::Log.error "invalid zone domain #{domain}: #{e}"
false
end
end