my $cache = $class->request_cache;
my $cgi = $class->cgi;
- $cache->{github_secret} //= $cgi->cookie('github_secret') // generate_random_password(16);
+ $cache->{github_secret} //= $cgi->cookie('github_secret') // generate_random_password(256);
return $cache->{github_secret};
}
$action = 'ignore';
}
my $limit = join("/", @$limit);
- Bugzilla->audit("[rate_limit] action=$action, ip=$ip, limit=$limit");
+ Bugzilla->audit("[rate_limit] action=$action, ip=$ip, limit=$limit, name=$name");
ThrowUserError("rate_limit") if $action eq 'block';
}
}
$param->{$name} = $item->{'default'};
}
}
+ else {
+ my $checker = $item->{'checker'};
+ my $updater = $item->{'updater'};
+ if ($checker) {
+ my $error = $checker->($param->{$name}, $item);
+ if ($error && $updater) {
+ my $new_val = $updater->( $param->{$name} );
+ $param->{$name} = $new_val unless $checker->($new_val, $item);
+ }
+ elsif ($error) {
+ warn "Invalid parameter: $name\n";
+ }
+ }
+ }
}
# Generate unique Duo integration secret key
use warnings;
use Bugzilla::Config::Common;
-use JSON::XS qw(decode_json);
+use JSON::XS qw(decode_json encode_json);
use List::MoreUtils qw(all);
use Scalar::Util qw(looks_like_number);
{
name => 'rate_limit_rules',
type => 'l',
- default => '{"get_bug": [75, 60], "show_bug": [75, 60]}',
+ default => '{"get_bug": [75, 60], "show_bug": [75, 60], "github": [10, 60]}',
checker => \&check_rate_limit_rules,
+ updater => \&update_rate_limit_rules,
},
{
ref($_) eq 'ARRAY' && looks_like_number( $_->[0] ) && looks_like_number( $_->[1] )
} values %$val;
- foreach my $required (qw( show_bug get_bug )) {
+ foreach my $required (qw( show_bug get_bug github )) {
return "missing $required" unless exists $val->{$required};
}
return "";
}
+sub update_rate_limit_rules {
+ my ($rules) = @_;
+ my $val = decode_json($rules);
+ $val->{github} = [10, 60];
+ return encode_json($val);
+}
+
1;
use lib qw(. lib local/lib/perl5);
use Bugzilla;
-use Bugzilla::Util ();
+use Bugzilla::Util qw(remote_ip);
use Bugzilla::Error;
use Bugzilla::Constants;
use Bugzilla::Token qw( issue_short_lived_session_token
my $github_secret = $cgi->param('github_secret') or ThrowCodeError("github_invalid_request", { reason => 'invalid secret' });
my $github_secret2 = Bugzilla->github_secret or ThrowCodeError("github_invalid_request", { reason => 'invalid secret' });
- ThrowCodeError("github_invalid_request", { reason => 'invalid secret' })
- unless $github_secret eq $github_secret2;
+ if ($github_secret ne $github_secret2) {
+ Bugzilla->check_rate_limit('github', remote_ip());
+ ThrowCodeError("github_invalid_request", { reason => 'invalid secret' });
+ }
ThrowCodeError("github_invalid_target", { target_uri => $target_uri })
unless $target_uri =~ /^\Q$urlbase\E/;
exit;
}
- ThrowCodeError("github_invalid_request", { reason => 'invalid state param' })
- unless $state_param eq $state_cookie;
+ my $invalid_request = $state_param ne $state_cookie;
- my $state_data = get_token_extra_data($state_param);
- ThrowCodeError("github_invalid_request", { reason => 'invalid state param' } )
- unless $state_data && $state_data->{type};
+ my $state_data;
+ unless ($invalid_request) {
+ $state_data = get_token_extra_data($state_param);
+ $invalid_request = !( $state_data && $state_data->{type} && $state_data->{type} =~ /^github_(?:login|email)$/ );
+ }
+ if ($invalid_request) {
+ Bugzilla->check_rate_limit('github', remote_ip());
+ ThrowCodeError("github_invalid_request", { reason => 'invalid state param' } )
+ }
$cgi->remove_cookie('github_state');
delete_token($state_param);
Bugzilla->request_cache->{github_action} = 'email';
Bugzilla->request_cache->{github_emails} = $state_data->{emails};
}
- else {
- ThrowCodeError("github_invalid_request", { reason => "invalid state param" })
- }
my $user = Bugzilla->login(LOGIN_REQUIRED);
my $target_uri = URI->new($state_data->{target_uri});