Adding a client (draft) and domain test.
This commit is contained in:
parent
c1ef4f6235
commit
7f5d162e91
13
src/client/lib/authd_api.cr
Normal file
13
src/client/lib/authd_api.cr
Normal 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
|
46
src/client/lib/dnsmanager-client.cr
Normal file
46
src/client/lib/dnsmanager-client.cr
Normal 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
|
15
src/client/lib/yaml_uuid.cr
Normal file
15
src/client/lib/yaml_uuid.cr
Normal 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
|
@ -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
151
src/lib.cr
Normal 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
|
@ -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
31
src/requests/zone.cr
Normal 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
11
src/responses/zone.cr
Normal 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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user