diff --git a/src/lib/Hydra/Controller/Root.pm b/src/lib/Hydra/Controller/Root.pm index a9b0d558..4070184c 100644 --- a/src/lib/Hydra/Controller/Root.pm +++ b/src/lib/Hydra/Controller/Root.pm @@ -30,6 +30,8 @@ sub noLoginNeeded { return $whitelisted || $c->request->path eq "api/push-github" || $c->request->path eq "google-login" || + $c->request->path eq "github-redirect" || + $c->request->path eq "github-login" || $c->request->path eq "login" || $c->request->path eq "logo" || $c->request->path =~ /^static\//; diff --git a/src/lib/Hydra/Controller/User.pm b/src/lib/Hydra/Controller/User.pm index 656ce018..ce48dd44 100644 --- a/src/lib/Hydra/Controller/User.pm +++ b/src/lib/Hydra/Controller/User.pm @@ -4,6 +4,7 @@ use utf8; use strict; use warnings; use base 'Hydra::Base::Controller::REST'; +use File::Slurp; use Crypt::RandPasswd; use Digest::SHA1 qw(sha1_hex); use Hydra::Helper::Nix; @@ -154,6 +155,57 @@ sub google_login :Path('/google-login') Args(0) { doEmailLogin($self, $c, "google", $data->{email}, $data->{name} // undef); } +sub github_login :Path('/github-login') Args(0) { + my ($self, $c) = @_; + + error($c, "Logging in via GitHub is not enabled.") unless $c->config->{enable_github_login}; + my $client_id = $c->config->{github_client_id} or die "github_client_id not configured."; + my $client_secret = $c->config->{github_client_secret} // do { + my $client_secret_file = $c->config->{github_client_secret_file} or die "github_client_secret nor github_client_secret_file is configured."; + my $client_secret = read_file($client_secret_file); + $client_secret =~ s/\s+//; + $client_secret; + }; + die "No github secret configured" unless $client_secret; + + my $ua = new LWP::UserAgent; + my $response = $ua->post( + 'https://github.com/login/oauth/access_token', + { + client_id => $client_id, + client_secret => $client_secret, + code => ($c->req->params->{code} // die "No token."), + }, Accept => 'application/json'); + error($c, "Did not get a response from GitHub.") unless $response->is_success; + + my $data = decode_json($response->decoded_content) or die; + my $access_token = $data->{access_token} // die "No access_token in response from GitHub."; + + $response = $ua->get('https://api.github.com/user', Authorization => "token $access_token"); + error($c, "Did not get a response from GitHub for user info.") unless $response->is_success; + + $data = decode_json($response->decoded_content) or die; + doEmailLogin($self, $c, "github", $data->{email}, $data->{name} // undef); + + $c->res->redirect($c->uri_for($c->res->cookies->{'after_github'})); +} + +sub github_redirect :Path('/github-redirect') Args(0) { + my ($self, $c) = @_; + + error($c, "Logging in via GitHub is not enabled.") unless $c->config->{enable_github_login}; + my $client_id = $c->config->{github_client_id} or die "github_client_id not configured."; + + my $after = "/" . $c->req->params->{after}; + + $c->res->cookies->{'after_github'} = { + name => 'after_github', + value => $after, + }; + + $c->res->redirect("https://github.com/login/oauth/authorize?client_id=$client_id"); +} + sub captcha :Local Args(0) { my ($self, $c) = @_; diff --git a/src/root/topbar.tt b/src/root/topbar.tt index b9b839f9..e0156231 100644 --- a/src/root/topbar.tt +++ b/src/root/topbar.tt @@ -136,6 +136,10 @@