#!perl
use strict;
use warnings;
use Net::Eboks;
use IO::Lambda qw(:all);
use IO::Lambda::HTTP::Client qw(http_request);
use IO::Lambda::HTTP::Server;
use URI;
use URI::QueryParam;
use HTTP::Request;
use HTTP::Response;

my $port = 9999;
my ($server, $error, $e);

sub html($)
{
	my $html = $_[0];
	$html = "<html><body>$html</body></html>";
	HTTP::Response->new( 200, "OK", [
		'Content-Type'   => 'text/html',
		'Content-Length' => length($html),
	], $html)
}

my %routes = (
	'/' => sub { html <<'INIT'
<h2>Welcome to the Eboks/Nemid authenticator</h2>
<p>
This step is needed to bind a device, usually a mobile phone, to
Eboks.<br> You can see a list of those devices in your E-boks personal page.<br>
Here we register a fake device "Net-Eboks" that establishes access for
the module.
<p>
First, you will need to provide your CPR and mobile login:
<form action="/step1" method="POST">
<table><tr>
<td>CPR:</td><td><input name="cpr"></td></tr><tr>
<td>Mobile login:</td><td><input type="password" name="login"></td></tr>
</table><p>
<input type="submit" value="Next">
</form>
INIT
	},

	'/step1' => sub {
		my $req = shift;
		return (undef, "bad response") unless 
			$req->method eq 'POST' and
			$req->header('Content-Type') eq 'application/x-www-form-urlencoded';
		my $uri = URI->new;
		$uri->query($req->content);
		$e = Net::Eboks->new(
			cpr        => $uri->query_param('cpr') // '',
			password   => $uri->query_param('login') // ''
		);
		my ($uname, $error) = $e->fetch_request($e->login)->wait;
		return (undef, "Error logging to E-Boks:$error") if defined $error;
		return html <<SUCCESS;
<h2>Welcome, $uname!</h2>
<p>
The login to E-Boks was successful.<br>
Now, it requires you to perform a NemID login, to get a confirmation
that the device is, indeed yours.<br> On the next page you will be presented
the standard NemID dialog, that you need to login as you usually do.<br>
If you are going to authorize the login with your NemID app, make sure that
the requestor is "E-Boks login".
<form action="/step2" method="POST">
<input type="submit" value="Next">
</form>
SUCCESS
	},

	'/step2' => sub {
		IO::Lambda::HTTP::Client->new( HTTP::Request->new(
			GET => 'https://m.e-boks.dk/app/logon.aspx?logontype=nemid'
		), keep_alive => 1)
	},

	'/nemid/Logon/LogonPrivate' => sub {
		my $req = shift;
		$req->uri("https://logon.e-boks.dk/".$req->uri);
		$req->header( Host => 'logon.e-boks.dk');
		$req->header( 'Accept-Encoding' => 'identity');
		my $resp = IO::Lambda::HTTP::Client->new( $req)->wait;
		return $resp unless $resp->is_success;
		return (undef, "Cannot get NemID ticket") unless $resp->content =~ /name="Ticket" value="(.*?)"/;
		my ( undef, $error) = $e->fetch_request($e->session_activate($1))->wait;
		return "Cannot activate device: $error" if defined $error;
		$server->shutdown;
		return html '<h2>Device is activated!</h2><p>Now you can use the module with your credentials';
	},
);

($server, $error) = http_server {
	my $req = shift;
	if ( my $cb = $routes{$req->uri}) {
		return $cb->($req);
	} else {
		my $msg = "Something wrong happened, ".$req->uri. " is not supposed to be accessed";
		return HTTP::Response->new( 404, "Not Found", ['Content-Length' => length($msg)], $msg);
	}
} "localhost:$port", timeout => 10;
die $error unless $server;
print "Open a browser and go to this address:\n";
print "\n   http://localhost:$port/\n\n";
$server->wait;
