mourningdove/cgi-bin/DW/Controller/Auth.pm

131 lines
3.9 KiB
Perl
Raw Permalink Normal View History

2026-05-24 01:03:05 +00:00
#!/usr/bin/perl
#
# DW::Controller::Auth
#
# This controller is for authentication endpoints. Login, logout, and other
# related functionality.
#
# Authors:
# Mark Smith <mark@dreamwidth.org>
#
# Copyright (c) 2017-2022 by Dreamwidth Studios, LLC.
#
# This program is free software; you may redistribute it and/or modify it under
# the same terms as Perl itself. For a copy of the license, please reference
# 'perldoc perlartistic' or 'perldoc perlgpl'.
#
package DW::Controller::Auth;
use strict;
use v5.10;
use Log::Log4perl;
my $log = Log::Log4perl->get_logger(__PACKAGE__);
use LWP::UserAgent;
use LJ::JSON;
use LJ::MemCache;
use LJ::Sysban;
use DW::Captcha;
use DW::Controller;
use DW::FormErrors;
use DW::Routing;
use DW::Template;
DW::Routing->register_string( "/captcha", \&captcha_handler, app => 1 );
DW::Routing->register_string( "/logout", \&logout_handler, app => 1 );
sub captcha_handler {
my ( $ok, $rv ) = controller( anonymous => 1, form_auth => 1, skip_captcha => 1 );
return $rv unless $ok;
my $r = DW::Request->get;
my $ip = $r->get_remote_ip;
my $get_args = $r->get_args;
# Renderer for GETs
my $render_captcha_form = sub {
return DW::Template->render_template( 'auth/captcha.tt',
{ sitekey => $LJ::CAPTCHA_HCAPTCHA_SITEKEY, returnto => $get_args->{returnto} } );
};
return $render_captcha_form->()
unless $r->did_post;
# If it was a POST and it had the reset get var, just wipe it and do
# absolutely nothing else
if ( $get_args->{reset} ) {
DW::Captcha->reset_captcha;
return $render_captcha_form->();
}
my $post_args = $r->post_args;
my $response = $post_args->{'h-captcha-response'}
or return $render_captcha_form->();
# Hit up hCaptcha and ask nicely if this is any good
my $ua = LWP::UserAgent->new;
$ua->agent('Dreamwidth Captcha API <accounts@dreamwidth.org>');
my $res = $ua->post(
qq{https://hcaptcha.com/siteverify},
Content =>
qq{response=$response&secret=$LJ::CAPTCHA_HCAPTCHA_SECRET&sitekey=$LJ::CAPTCHA_HCAPTCHA_SITEKEY&remoteip=$ip},
'Content-Type' => 'application/x-www-form-urlencoded',
);
return $render_captcha_form->()
unless $res->is_success;
my $obj = from_json( $res->decoded_content );
if ( $obj->{success} ) {
DW::Captcha->record_success( $rv->{remote} );
if ( DW::Controller::validate_redirect_url( $post_args->{returnto} ) ) {
return $r->redirect( $post_args->{returnto} );
}
}
# Something has gone wrong, just redirect back to the main page in
# basically a captcha loop (hopefully they can fix their stuff)
return $render_captcha_form->();
}
sub logout_handler {
# We have to allow anonymous viewers because that's how we render the page that
# tells the user they have successfully logged out
my ( $ok, $rv ) = controller( anonymous => 1, form_auth => 1 );
return $rv unless $ok;
my $r = DW::Request->get;
my $remote = $rv->{remote};
my $vars = { returnto => $r->get_args->{'returnto'} // '', };
if ( $remote && $r->did_post ) {
my $post_args = $r->post_args;
if ( exists $post_args->{logout_one} ) {
$remote->logout;
$vars->{success} = 'one';
}
elsif ( exists $post_args->{logout_all} ) {
$remote->logout_all;
$vars->{success} = 'all';
}
# If the logout form asked to be sent back to the original page (with a
# hidden 'ret=1' form input and a return url), do so (as long as the logout
# was successful).
if ( $vars->{success} && $post_args->{returnto} && $post_args->{ret} ) {
if ( LJ::check_referer( '', $post_args->{returnto} ) ) {
return $r->redirect( $post_args->{returnto} );
}
}
}
# GET case or the logout success case
return DW::Template->render_template( 'auth/logout.tt', $vars );
}
1;