Record management

This commit is contained in:
Al Beano 2017-08-11 21:28:32 +01:00
parent 411280faa0
commit d87964893f
11 changed files with 350 additions and 28 deletions

View File

@ -16,7 +16,4 @@ plugins:
dbname: 'db.sqlite'
log_queries: 1
nsd:
enable: 1
zone_conf: /var/nsd/etc/zones.conf
zone_dir: /var/nsd/zones/master
tld: 'cyb'

View File

@ -9,7 +9,7 @@ requires "DBD::SQLite" => "0";
requires "HTML::Entities" => "0";
requires "Digest::Bcrypt" => "0";
requires "Math::Random::Secure" => "0";
requires "if" => "0";
requires "Switch" => "0";
requires "Plack::Middleware::Deflater" => "0";
requires "Plack::Middleware::Session" => "0";

View File

@ -1,10 +0,0 @@
package NSD::Interface;
use strict;
use warnings;
use Dancer2 appname => "cyberman";
use Exporter;
our @EXPORT = qw();
1;

View File

@ -8,6 +8,7 @@ use cyberman::Auth;
use cyberman::Account;
use cyberman::Helper;
use cyberman::API;
use cyberman::Records;
# Index route, hook and helper functions for authentication
@ -52,6 +53,7 @@ hook 'before' => sub {
var auth => $auth;
var email => $email;
var config => config();
};
get qr{^/(index)?$} => sub {

View File

@ -7,8 +7,6 @@ use cyberman::Helper;
get '/api/check_availability' => sub {
# No auth req'd
# returns 'y' or 'n'
# TODO: check name validity here
if (!param("name")) {
return "n";

View File

@ -4,7 +4,6 @@ use Dancer2 appname => "cyberman";
use Dancer2::Plugin::Database;
use cyberman::Helper;
use if config->{"use_nsd"}, "NSD::Interface";
get '/domains' => sub {
return auth_test() if auth_test();
@ -73,11 +72,11 @@ post '/domains/new' => sub {
};
};
get '/domains/:id/remove' => sub {
get '/domains/:name/remove' => sub {
my $domain = database->quick_select(
"domain",
{
"id" => param("id"),
"name" => param("name"),
},
);
@ -88,11 +87,11 @@ get '/domains/:id/remove' => sub {
};
};
post '/domains/:id/remove' => sub {
post '/domains/:name/remove' => sub {
my $domain = database->quick_select(
"domain",
{
"id" => param("id"),
"name" => param("name"),
},
);
@ -106,7 +105,7 @@ post '/domains/:id/remove' => sub {
database->quick_delete(
"domain",
{
"id" => param("id"),
"name" => param("name"),
},
);

174
lib/cyberman/Records.pm Normal file
View File

@ -0,0 +1,174 @@
package cyberman::Records;
use Dancer2 appname => "cyberman";
use Dancer2::Plugin::Database;
use Switch;
use cyberman::Helper;
get '/domains/:name/records' => sub {
my $domain = database->quick_select(
"domain",
{
"name" => param("name"),
},
);
if (!$domain) {
return "No such domain!";
}
return auth_test($domain->{"ownerid"}) if auth_test($domain->{"ownerid"});
my @records = database->quick_select(
"record",
{
"domainid" => $domain->{"id"},
},
);
template 'records' => {
domain => $domain,
records => \@records,
};
};
get '/domains/:name/records/add' => sub {
my $domain = database->quick_select(
"domain",
{
"name" => param("name"),
},
);
if (!$domain) {
return "No such domain!";
}
return auth_test($domain->{"ownerid"}) if auth_test($domain->{"ownerid"});
template 'records/add' => {
domain => $domain,
};
};
post '/domains/:name/records/add' => sub {
my $domain = database->quick_select(
"domain",
{
"name" => param("name"),
},
);
if (!$domain) {
return "No such domain!";
}
return auth_test($domain->{"ownerid"}) if auth_test($domain->{"ownerid"});
my %errs;
# tw overuse of regex
switch (param("type")) {
case "A" {
if (param("value") !~ m/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}$/) {
# here we go...
$errs{"e_bad_value"} = 1;
}
}
case "AAAA" {
if (param("value") !~ m/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/) {
# I am sorry
$errs{"e_bad_value"} = 1;
}
}
case "NS" {
if (param("value") !~ m/^([a-zA-Z0-9]([a-zA-Z0-9-_]*[a-zA-Z0-9])?\.)+$/) {
$errs{"e_bad_value"} = 1;
}
}
else {
$errs{"e_bad_type"} = 1;
}
}
if (param("rname") !~ m/^(@|([a-zA-Z0-9]([a-zA-Z0-9-_]*[a-zA-Z0-9])\.)*[a-zA-Z0-9]([a-zA-Z0-9-_]*[a-zA-Z0-9])?)$/) {
$errs{"e_bad_name"} = 1;
}
if (scalar(keys(%errs)) != 0) {
return template 'records/add' => {
domain => $domain,
%errs,
error => 1,
};
}
my $sid = $domain->{"lastsid"} + 1;
database->quick_update(
"domain",
{
"id" => $domain->{"id"},
},
{
"lastsid" => $sid,
},
);
database->quick_insert(
"record",
{
"sid" => $sid,
"domainid" => $domain->{"id"},
"type" => param("type"),
"name" => param("rname"),
"value" => param("value"),
},
);
template 'redir' => {
"redir" => "../records?added=1",
};
};
post '/domains/:name/records/:sid/remove' => sub {
my $domain = database->quick_select(
"domain",
{
"name" => param("name"),
},
);
if (!$domain) {
return "No such domain!";
}
return auth_test($domain->{"ownerid"}) if auth_test($domain->{"ownerid"});
my $record = database->quick_select(
"record",
{
"domainid" => $domain->{"id"},
"sid" => param("sid"),
},
);
if (!$record) {
return "No such record!";
}
database->quick_delete(
"record",
{
"domainid" => $domain->{"id"},
"sid" => param("sid"),
},
);
template 'redir' => {
"redir" => "../../records?removed=1",
};
};
true;

View File

@ -19,5 +19,16 @@ drop table if exists domain;
create table domain (
id integer primary key,
name string not null,
ownerid integer not null
)
ownerid integer not null,
lastsid integer not null default 0
);
drop table if exists record;
create table record (
id integer primary key,
sid integer not null,
domainid integer not null,
type string not null,
name string not null,
value string not null
);

View File

@ -19,7 +19,7 @@
<div class="body">
<center>
[&nbsp;<a class="bracketButton" href="domains/new">Register a domain</a>&nbsp;]
[&nbsp;<a class="bracketButton" href="domains/new">register a domain</a>&nbsp;]
</center>
<% IF domains.size > 0 %>
@ -49,8 +49,8 @@
<% d.name | html_entity %>.cyb
</td>
<td>
[&nbsp;<a class="bracketButton" href="domains/<% d.id %>/edit">edit</a>&nbsp;]
[&nbsp;<a class="bracketButton" href="domains/<% d.id %>/remove">remove</a>&nbsp;]
[&nbsp;<a class="bracketButton" href="domains/<% d.name %>/records">edit</a>&nbsp;]
[&nbsp;<a class="bracketButton" href="domains/<% d.name %>/remove">remove</a>&nbsp;]
</td>
</tr>
<% END %>

76
views/records.tt Normal file
View File

@ -0,0 +1,76 @@
<center>
<br />
<h1>Editing <% domain.name | html_entity %>.<% vars.config.tld %></h1>
<br />
<% IF params.added %>
<div class="msgBox">
The record was created successfully!
</div>
<br /><br />
<% END %>
<% IF params.removed %>
<div class="msgBox">
The record was removed successfully!
</div>
<br /><br />
<% END %>
</center>
<div class="body">
<center>
[&nbsp;<a class="bracketButton" href="records/add">add record</a>&nbsp;]
</center>
<% IF records.size > 0 %>
<em>
<% records.size %>
<% IF records.size == 1 %>
record
<% ELSE %>
records
<% END %>
</em>
<br />
<table class="domains">
<tr>
<td>
<strong>Name</strong>
</td>
<td>
<strong>Type</strong>
</td>
<td>
<strong>Value</strong>
</td>
<td>
<strong>Actions</strong>
</td>
</tr>
<% FOREACH r IN records %>
<tr>
<td>
<% r.name | html_entity %>
</td>
<td>
<% r.type | html_entity %>
</td>
<td>
<% r.value | html_entity %>
</td>
<td>
<form method="POST" action="records/<% r.sid %>/remove">
[&nbsp;<button class="textButton" action="submit">remove</button>&nbsp;]
</form>
</td>
</tr>
<% END %>
</table>
<% ELSE %>
This domain has no records.
<% END %>
</div>

75
views/records/add.tt Normal file
View File

@ -0,0 +1,75 @@
<center>
<br />
<h1>Add a record</h1>
<br />
</center>
<% IF error %>
<div style="text-align:center">
<div class="msgBox" style="text-align:left">
There were some problems with your submission:
<br />
<ul>
<% IF e_bad_value %>
<li>The value you entered was invalid.
<% IF params.type == 'NS' %>(Did you forget the trailing '.'?)<% END %></li>
<% END %>
<% IF e_bad_type %>
<li>You must choose a type for the record.</li>
<% END %>
<% IF e_bad_name %>
<li>The name of the record is invalid.</li>
<% END %>
</ul>
</div>
</div>
<br />
<% END %>
<div class="body">
<em>Adding a record for <% domain.name | html_entity %>.<% vars.config.tld %></em>
<form method="POST" class="login">
<table class="domains">
<tr>
<td>
<strong>
<label for="name">Record name:</label>
</strong>
</td>
<td>
<input type="text" style="width: 100px" name="rname" id="rname" placeholder="Use @ for root"
value="<% params.rname | html_entity %>" />.<% domain.name | html_entity %>.<% vars.config.tld %>
</td>
</tr>
<tr>
<td>
<strong>
<label for="type">Record type:</label>
</strong>
</td>
<td>
<select name="type" id="type">
<option value="">- Select -</option>
<option value="A">A</option>
<option value="AAAA">AAAA</option>
<option value="NS">NS</option>
</select>
</td>
</tr>
<tr>
<td>
<strong>
<label for="value">Value:</label>
</strong>
</td>
<td>
<input type="text" name="value" id="value" value="<% params.value | html_entity %>" />
</td>
</tr>
</table>
<br />
[&nbsp;<button action="submit" class="textButton">create&nbsp;record</button>&nbsp;]
[&nbsp;<a class="bracketButton" href="../records">go&nbsp;back</a>&nbsp;]
</form>
</div>