Mettre en place une interface Web
This commit is contained in:
parent
b42985d9a5
commit
a2ed2d18b8
|
@ -0,0 +1,84 @@
|
|||
FROM alpine:latest AS bootstrap-build
|
||||
|
||||
RUN mkdir /target
|
||||
|
||||
ADD https://github.com/twbs/bootstrap/archive/v5.3.0.zip /src/bootstrap-5.3.0.zip
|
||||
|
||||
RUN apk add sassc
|
||||
|
||||
RUN unzip -d /src /src/bootstrap-5.3.0.zip
|
||||
|
||||
RUN ln -nsf /src/bootstrap-5.3.0 /src/bootstrap
|
||||
|
||||
COPY scss /src
|
||||
|
||||
RUN /bin/sh -c "cd /src && sassc main.scss -t compressed /target/main.css"
|
||||
|
||||
FROM alpine:latest
|
||||
|
||||
RUN apk add \
|
||||
bash \
|
||||
bind \
|
||||
bind-tools \
|
||||
vim
|
||||
|
||||
# Dependencies for REST API
|
||||
RUN apk add \
|
||||
gcc \
|
||||
libc-dev \
|
||||
make \
|
||||
perl-app-cpanminus \
|
||||
perl-clone \
|
||||
perl-config-any \
|
||||
perl-data-optlist \
|
||||
perl-dev \
|
||||
perl-exporter-tiny \
|
||||
perl-extutils-config \
|
||||
perl-extutils-helpers \
|
||||
perl-extutils-installpaths \
|
||||
perl-file-sharedir \
|
||||
perl-file-sharedir-install \
|
||||
perl-file-slurp \
|
||||
perl-file-which \
|
||||
perl-hash-merge-simple \
|
||||
perl-hash-multivalue \
|
||||
perl-http-date \
|
||||
perl-http-headers-fast \
|
||||
perl-import-into \
|
||||
perl-json \
|
||||
perl-json-maybexs \
|
||||
perl-module-build \
|
||||
perl-module-build-tiny \
|
||||
perl-module-implementation \
|
||||
perl-module-runtime \
|
||||
perl-moo \
|
||||
perl-params-util \
|
||||
perl-params-validate \
|
||||
perl-path-tiny \
|
||||
perl-plack \
|
||||
perl-readonly \
|
||||
perl-ref-util \
|
||||
perl-role-tiny \
|
||||
perl-safe-isa \
|
||||
perl-sub-exporter \
|
||||
perl-sub-install \
|
||||
perl-sub-quote \
|
||||
perl-template-toolkit \
|
||||
perl-type-tiny \
|
||||
perl-yaml
|
||||
|
||||
RUN apk add perl-io-socket-ssl perl-lwp-protocol-https
|
||||
|
||||
RUN cpanm -n -v \
|
||||
Dancer2 \
|
||||
REST::Client \
|
||||
Module::Pluggable::Object
|
||||
|
||||
COPY web-api /src/web-ui
|
||||
RUN chmod +x /src/web-ui/bin/app.psgi
|
||||
|
||||
COPY --from=bootstrap-build /src/bootstrap/dist/js/bootstrap.bundle.min.js \
|
||||
/src/web-ui/public/javascripts/bootstrap.bundle.min.js
|
||||
COPY --from=bootstrap-build /target/main.css /src/web-ui/public/css/main.css
|
||||
|
||||
ENTRYPOINT ["/src/web-ui/bin/app.psgi"]
|
|
@ -0,0 +1,49 @@
|
|||
@import "bootstrap/scss/mixins/banner";
|
||||
@include bsBanner("");
|
||||
|
||||
// Configuration
|
||||
@import "bootstrap/scss/functions";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/variables-dark";
|
||||
@import "bootstrap/scss/maps";
|
||||
@import "bootstrap/scss/mixins";
|
||||
@import "bootstrap/scss/utilities";
|
||||
|
||||
// Layout & components
|
||||
@import "bootstrap/scss/root";
|
||||
@import "bootstrap/scss/reboot";
|
||||
@import "bootstrap/scss/type";
|
||||
@import "bootstrap/scss/images";
|
||||
@import "bootstrap/scss/containers";
|
||||
@import "bootstrap/scss/grid";
|
||||
@import "bootstrap/scss/tables";
|
||||
@import "bootstrap/scss/forms";
|
||||
@import "bootstrap/scss/buttons";
|
||||
@import "bootstrap/scss/transitions";
|
||||
@import "bootstrap/scss/dropdown";
|
||||
@import "bootstrap/scss/button-group";
|
||||
@import "bootstrap/scss/nav";
|
||||
@import "bootstrap/scss/navbar";
|
||||
@import "bootstrap/scss/card";
|
||||
@import "bootstrap/scss/accordion";
|
||||
@import "bootstrap/scss/breadcrumb";
|
||||
@import "bootstrap/scss/pagination";
|
||||
@import "bootstrap/scss/badge";
|
||||
@import "bootstrap/scss/alert";
|
||||
@import "bootstrap/scss/progress";
|
||||
@import "bootstrap/scss/list-group";
|
||||
@import "bootstrap/scss/close";
|
||||
@import "bootstrap/scss/toasts";
|
||||
@import "bootstrap/scss/modal";
|
||||
@import "bootstrap/scss/tooltip";
|
||||
@import "bootstrap/scss/popover";
|
||||
@import "bootstrap/scss/carousel";
|
||||
@import "bootstrap/scss/spinners";
|
||||
@import "bootstrap/scss/offcanvas";
|
||||
@import "bootstrap/scss/placeholders";
|
||||
|
||||
// Helpers
|
||||
@import "bootstrap/scss/helpers";
|
||||
|
||||
// Utilities
|
||||
@import "bootstrap/scss/utilities/api";
|
|
@ -0,0 +1,24 @@
|
|||
MANIFEST
|
||||
MANIFEST.SKIP
|
||||
.dancer
|
||||
Makefile.PL
|
||||
config.yml
|
||||
cpanfile
|
||||
views/index.tt
|
||||
views/layouts/main.tt
|
||||
lib/Email/SpoofingDemo/Web.pm
|
||||
t/002_index_route.t
|
||||
t/001_base.t
|
||||
environments/production.yml
|
||||
environments/development.yml
|
||||
bin/app.psgi
|
||||
public/500.html
|
||||
public/dispatch.cgi
|
||||
public/dispatch.fcgi
|
||||
public/favicon.ico
|
||||
public/404.html
|
||||
public/javascripts/jquery.js
|
||||
public/css/error.css
|
||||
public/css/style.css
|
||||
public/images/perldancer-bg.jpg
|
||||
public/images/perldancer.jpg
|
|
@ -0,0 +1,17 @@
|
|||
^\.git\/
|
||||
maint
|
||||
^tags$
|
||||
.last_cover_stats
|
||||
Makefile$
|
||||
^blib
|
||||
^pm_to_blib
|
||||
^.*.bak
|
||||
^.*.old
|
||||
^t.*sessions
|
||||
^cover_db
|
||||
^.*\.log
|
||||
^.*\.swp$
|
||||
MYMETA.*
|
||||
^.gitignore
|
||||
^.svn\/
|
||||
^Email-SpoofingDemo-Web-
|
|
@ -0,0 +1,26 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
use ExtUtils::MakeMaker;
|
||||
|
||||
# Normalize version strings like 6.30_02 to 6.3002,
|
||||
# so that we can do numerical comparisons on it.
|
||||
my $eumm_version = $ExtUtils::MakeMaker::VERSION;
|
||||
$eumm_version =~ s/_//;
|
||||
|
||||
WriteMakefile(
|
||||
NAME => 'Email::SpoofingDemo::Web',
|
||||
AUTHOR => q{Marc van der Wal <marc.vanderwal@afnic.fr>},
|
||||
VERSION_FROM => 'lib/Email/SpoofingDemo/Web.pm',
|
||||
ABSTRACT => 'Email spoofing demo: Web frontend',
|
||||
($eumm_version >= 6.3001
|
||||
? ('LICENSE'=> 'all-rights-reserved')
|
||||
: ()),
|
||||
PL_FILES => {},
|
||||
PREREQ_PM => {
|
||||
'Test::More' => 0,
|
||||
'YAML' => 0,
|
||||
'Dancer2' => 0.300000,
|
||||
},
|
||||
dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
|
||||
clean => { FILES => 'Email-SpoofingDemo-Web-*' },
|
||||
);
|
|
@ -0,0 +1,9 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
|
||||
use Email::SpoofingDemo::Web;
|
||||
Email::SpoofingDemo::Web->to_app;
|
|
@ -0,0 +1,17 @@
|
|||
appname: "Email::SpoofingDemo::Web"
|
||||
layout: "main"
|
||||
charset: "UTF-8"
|
||||
|
||||
template: "template_toolkit"
|
||||
|
||||
# Specify the addresses of the API endpoints for the other components of the
|
||||
# system
|
||||
api:
|
||||
dns: "ns.example:3000"
|
||||
|
||||
# Lists the DNS zones that can be edited by the user
|
||||
editable_zones:
|
||||
- example
|
||||
- expediteur.example
|
||||
- destinataire.example
|
||||
- attaquant.example
|
|
@ -0,0 +1,11 @@
|
|||
requires "Dancer2" => "0.300000";
|
||||
|
||||
recommends "YAML" => "0";
|
||||
recommends "URL::Encode::XS" => "0";
|
||||
recommends "CGI::Deurl::XS" => "0";
|
||||
recommends "HTTP::Parser::XS" => "0";
|
||||
|
||||
on "test" => sub {
|
||||
requires "Test::More" => "0";
|
||||
requires "HTTP::Request::Common" => "0";
|
||||
};
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
# configuration file for development environment
|
||||
logger: "console"
|
||||
log: "core"
|
||||
|
||||
# should Dancer2 consider warnings as critical errors?
|
||||
warnings: 1
|
||||
|
||||
# should Dancer2 show a stacktrace when an 5xx error is caught?
|
||||
# if set to yes, public/500.html will be ignored and either
|
||||
# views/500.tt, 'error_template' template, or a default error template will be used.
|
||||
show_errors: 1
|
||||
|
||||
# print the banner
|
||||
startup_info: 1
|
|
@ -0,0 +1,16 @@
|
|||
# configuration file for production environment
|
||||
|
||||
# only log warning and error messsages
|
||||
log: "warning"
|
||||
|
||||
# log message to a file in logs/
|
||||
logger: "file"
|
||||
|
||||
# don't consider warnings critical
|
||||
warnings: 0
|
||||
|
||||
# hide errors
|
||||
show_errors: 0
|
||||
|
||||
# disable server tokens in production environments
|
||||
no_server_tokens: 1
|
|
@ -0,0 +1,70 @@
|
|||
package Email::SpoofingDemo::Web;
|
||||
use Dancer2;
|
||||
|
||||
use JSON;
|
||||
use REST::Client;
|
||||
|
||||
our $VERSION = '0.1';
|
||||
|
||||
get '/' => sub {
|
||||
template 'index' => { 'title' => 'Accueil' };
|
||||
};
|
||||
|
||||
get '/dns/zone-edit/:zone' => sub {
|
||||
my $zone = route_parameters->get('zone');
|
||||
if (defined $zone and not (grep { $_ eq $zone } @{config->{'editable_zones'}})) {
|
||||
pass;
|
||||
}
|
||||
|
||||
my $zone_contents;
|
||||
|
||||
if (defined $zone) {
|
||||
my $client = REST::Client->new();
|
||||
$client->setHost(config->{'api'}{'dns'});
|
||||
$client->GET("/zone/${zone}/file");
|
||||
my $response = from_json($client->responseContent());
|
||||
$zone_contents = $response->{'contents'};
|
||||
}
|
||||
|
||||
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 $client = REST::Client->new();
|
||||
$client->setHost(config->{'api'}{'dns'});
|
||||
$client->PUT("/zone/${zone}/file",
|
||||
encode_json({ contents => $contents }),
|
||||
{
|
||||
"Content-Type" => "application/json",
|
||||
"Accept" => "application/json"
|
||||
});
|
||||
|
||||
my $success;
|
||||
if ($client->responseCode() eq '200') {
|
||||
$success = 'success';
|
||||
} else {
|
||||
warn "Got " . $client->responseCode() . " from upstream: " . $client->responseContent();
|
||||
$success = 'failure'
|
||||
}
|
||||
|
||||
redirect "/dns/zone-edit/$zone?success=$success", 303;
|
||||
};
|
||||
|
||||
any qr{.*} => sub {
|
||||
template '404';
|
||||
};
|
||||
|
||||
dance;
|
||||
|
||||
true;
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env perl
|
||||
BEGIN { $ENV{DANCER_APPHANDLER} = 'PSGI';}
|
||||
use Dancer2;
|
||||
use FindBin '$RealBin';
|
||||
use Plack::Runner;
|
||||
|
||||
# For some reason Apache SetEnv directives don't propagate
|
||||
# correctly to the dispatchers, so forcing PSGI and env here
|
||||
# is safer.
|
||||
set apphandler => 'PSGI';
|
||||
set environment => 'production';
|
||||
|
||||
my $psgi = path($RealBin, '..', 'bin', 'app.psgi');
|
||||
die "Unable to read startup script: $psgi" unless -r $psgi;
|
||||
|
||||
Plack::Runner->run($psgi);
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env perl
|
||||
BEGIN { $ENV{DANCER_APPHANDLER} = 'PSGI';}
|
||||
use Dancer2;
|
||||
use FindBin '$RealBin';
|
||||
use Plack::Handler::FCGI;
|
||||
|
||||
# For some reason Apache SetEnv directives don't propagate
|
||||
# correctly to the dispatchers, so forcing PSGI and env here
|
||||
# is safer.
|
||||
set apphandler => 'PSGI';
|
||||
set environment => 'production';
|
||||
|
||||
my $psgi = path($RealBin, '..', 'bin', 'app.psgi');
|
||||
my $app = do($psgi);
|
||||
die "Unable to read startup script: $@" if $@;
|
||||
my $server = Plack::Handler::FCGI->new(nproc => 5, detach => 1);
|
||||
|
||||
$server->run($app);
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,2 @@
|
|||
<h1>Erreur 404</h1>
|
||||
<h2>Page non trouvée</h2>
|
|
@ -0,0 +1,2 @@
|
|||
<h1>Erreur 500</h1>
|
||||
<h2>Erreur interne du serveur</h2>
|
|
@ -0,0 +1,19 @@
|
|||
<div class="container">
|
||||
<div class="row mt-3 mb-4">
|
||||
<main class="col-12">
|
||||
<form id="edit-form" method="POST">
|
||||
<div class="mb-3">
|
||||
<h1>Modification de la zone <span class="font-monospace">[% zone_to_edit %]</span> :</h1>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<textarea class="form-control font-monospace" cols="80" id="zone-contents" name="zone-contents" rows="25">
|
||||
[%- zone_contents -%]
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<button type="submit" class="btn btn-primary">Valider</button>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,42 @@
|
|||
[% BLOCK role %]
|
||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
[% label %]
|
||||
</a>
|
||||
[% END %]
|
||||
<nav class="navbar navbar-expand-md bg-light mb-3">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">Menu</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Afficher ou cacher la navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-md-0">
|
||||
<li class="nav-item dropdown">
|
||||
[% PROCESS role id="attacker" label="Attaquant" %]
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="[% request.uri_base %]/attacker/spoof">Envoyer des messages frauduleux</a></li>
|
||||
<li><a class="dropdown-item" href="[% request.uri_base %]/dns/zone-edit/attaquant.example">Éditer la zone DNS</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
[% PROCESS role id="sender" label="Expéditeur" %]
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="[% request.uri_base %]/sender/send-email">Envoyer un message légitime</a></li>
|
||||
<li><a class="dropdown-item" href="[% request.uri_base %]/sender/dkim-keys">Afficher des clefs DKIM</a></li>
|
||||
<li><a class="dropdown-item" href="[% request.uri_base %]/dkim-generator/sender">Générer des clefs DKIM</a></li>
|
||||
<li><a class="dropdown-item" href="[% request.uri_base %]/dns/zone-edit/expediteur.example">Éditer la zone DNS</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
[% PROCESS role id="recipient" label="Destinataire" %]
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="[% request.uri_base %]/dns/zone-edit/destinataire.example">Éditer la zone DNS</a></li>
|
||||
<li><a class="dropdown-item" href="[% request.uri_base %]/recipient/webmail">Relever les courriels</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="[% settings.charset %]">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>[% title %]</title>
|
||||
<link rel="stylesheet" href="[% request.uri_base %]/css/main.css">
|
||||
</head>
|
||||
<body>
|
||||
[% INCLUDE layouts/_nav.tt %]
|
||||
<script src="[% request.uri_base %]/jquery-3.6.4.min.js"></script>
|
||||
[% content %]
|
||||
<script src="[% request.uri_base %]/javascripts/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -2,6 +2,20 @@ version: '3.8'
|
|||
name: 'spf-dkim-dmarc-workshop'
|
||||
|
||||
services:
|
||||
console:
|
||||
image: spf-dkim-dmarc-workshop/console
|
||||
build: ./console
|
||||
hostname: console
|
||||
dns:
|
||||
- 172.31.0.53
|
||||
networks:
|
||||
internal:
|
||||
ipv4_address: 172.31.0.10
|
||||
ipv6_address: fd4a:8c4:c28b::10
|
||||
external:
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
||||
dns:
|
||||
image: spf-dkim-dmarc-workshop/dns
|
||||
build: ./dns
|
||||
|
|
Loading…
Reference in New Issue