spf-dkim-dmarc-demo/console/web-api/lib/Email/SpoofingDemo/Web.pm

217 lines
6.0 KiB
Perl
Raw Normal View History

2023-10-25 15:50:25 +02:00
package Email::SpoofingDemo::Web;
use Dancer2;
use Dancer2::Plugin::Deferred;
2023-10-25 15:50:25 +02:00
use JSON;
use REST::Client;
our $VERSION = '0.1';
sub call_api {
my ($method, $target, $url, $body_parameters) = @_;
my $host = config->{'api'}{$target};
die "Invalid target: $target" unless defined $host;
my $client = REST::Client->new();
$client->setHost($host);
$client->setTimeout(5);
$client->addHeader('Accept' => 'application/json');
$client->addHeader('Content-Type' => 'application/json');
my $body_data;
$body_data = encode_json($body_parameters) if defined $body_parameters;
$client->request($method, $url, $body_data);
my $status = $client->responseCode();
if ($status =~ /^2\d\d$/) {
my $response;
if ($client->responseContent() ne '') {
$response = decode_json($client->responseContent());
}
return ($response, $status);
}
else {
warn "API request returned $status";
return ($client->responseContent(), $status);
}
}
2023-10-25 15:50:25 +02:00
get '/' => sub {
template 'index' => { 'title' => 'Accueil' };
};
get '/dns/zone-edit/:zone' => sub {
my $zone = route_parameters->get('zone');
if (not (grep { $_ eq $zone } @{config->{'editable_zones'}})) {
2023-10-25 15:50:25 +02:00
pass;
}
my $zone_contents = deferred 'zone_contents';
2023-10-25 15:50:25 +02:00
if (not defined $zone_contents) {
my ($response, $status) = call_api(GET => 'dns', "/zone/${zone}/file");
$zone_contents = $response->{contents};
2023-10-25 15:50:25 +02:00
}
template 'dns/zone-edit' => {
'title' => 'Éditeur de zone DNS',
'zone_to_edit' => $zone // '',
'zone_contents' => $zone_contents // '',
};
};
post '/dns/zone-edit/:zone' => sub {
my $zone = route_parameters->{'zone'};
unless (grep { $_ eq $zone } @{config->{'editable_zones'}}) {
pass;
}
my $contents = body_parameters->{'zone-contents'};
my ($data, $status) = call_api(PUT => 'dns', "/zone/${zone}/file", { contents => $contents });
2023-10-25 15:50:25 +02:00
if ($status ne '200') {
$data = decode_json($data);
}
deferred status => {
outcome => $data->{outcome},
messages => $data->{messages},
};
deferred zone_contents => $data->{contents};
redirect "/dns/zone-edit/$zone", 303;
};
get '/sender/dkim-keys' => sub {
my ($installed_keys, $status) = call_api(GET => 'sender', '/installed-keys');
($status eq '200') or die "API returned $status";
template 'sender/dkim-keys' => {
active_role => 'sender',
title => 'Gestion des clefs DKIM',
installed_keys => $installed_keys,
};
};
get '/dkim-generator/sender' => sub {
template 'dkim-generator/sender' => {
title => 'Générateur de clefs DKIM'
};
};
post '/dkim-generator/sender' => sub {
my $api_params = {
domain => body_parameters->get('domain'),
selector => body_parameters->get('selector'),
key_size => body_parameters->get('key-size')
};
my ($response, $status) = call_api(POST => 'sender', '/generate-dkim-key', $api_params);
($status eq 200) or die "API returned $status";
template 'dkim-generator/sender' => {
title => 'Générateur de clefs DKIM',
txt_record => $response->{'txt_record'}
};
};
get '/attacker/spoof' => sub {
my ($config, $status) = call_api(GET => 'attacker', '/config');
($status eq 200) or die "Could not get attackers configuration";
template 'attacker/spoof' => {
title => 'Usurpateur didentité de courriel',
default_helo => $config->{default_helo},
my_mail_from => $config->{my_mail_from},
scenarios => $config->{templates}
};
};
post '/attacker/spoof' => sub {
my $scenario = body_parameters->get('scenario');
my $replace_mail_from = (body_parameters->get('rfc5321-mailfrom') eq 'replace');
my $helo = body_parameters->get('helo');
my %api_params = (
scenario => $scenario,
replace_mail_from => ($replace_mail_from ? JSON::true : JSON::false),
helo => $helo
);
my ($logs, $status) = call_api(POST => 'attacker', '/spoof', \%api_params);
deferred 'logs' => $logs;
deferred 'selected_scenario' => $scenario;
deferred 'replace_mail_from' => $replace_mail_from;
redirect '/attacker/spoof', 303;
};
get '/sender/send-email' => sub {
my %template_params = (
title => 'Envoi de messages légitimes',
email_data => [
{
what => 'Confirmation de commande',
from => 'support@expediteur.example',
url => 'confirmation_email'
},
{
what => 'Newsletter',
from => 'info@newsletter.expediteur.example',
url => 'newsletter'
}
]
);
my $success = query_parameters->get('success');
if (defined $success) {
$template_params{success} = ($success eq 'success') ? 'success' : 'failure';
2023-10-25 15:50:25 +02:00
}
template 'sender/send-email' => \%template_params;
};
2023-10-25 15:50:25 +02:00
get '/recipient/settings' => sub {
my ($system_status, $http_code) = call_api(GET => 'recipient', '/status');
die if $http_code ne '200';
template 'recipient/settings' => {
title => 'Paramètres du système destinataire',
system_status => $system_status
};
};
post '/recipient/settings' => sub {
my %api_params = map {
$_ => body_parameters->{"$_-status"} ? 'enabled' : 'disabled'
} qw(spf dkim dmarc);
my (undef, $status) = call_api(PUT => 'recipient', '/status', \%api_params);
my $success = ($status eq 200) ? 'success' : 'failure';
redirect "/recipient/settings?success=$success", 303;
};
get '/sender/send-email/:email' => sub {
my $email = route_parameters->get('email');
my (undef, $response) = call_api(POST => 'sender', "/send-email/${email}");
my $success = ($response =~ /^2\d\d$/) ? 'success' : 'failure';
redirect "/sender/send-email?success=$success", 303;
2023-10-25 15:50:25 +02:00
};
get '/recipient/webmail' => sub {
template 'recipient/webmail' => {
title => 'Courriels'
};
};
2023-10-25 15:50:25 +02:00
any qr{.*} => sub {
template '404';
};
dance;
true;