mirror of
https://github.com/pragma-/pbot.git
synced 2024-12-23 19:22:40 +01:00
Refactor message account linking
Linking of message accounts is now significantly less likely to produce false-positives. Previously, any hostmasks with matching nick!*@* would be strongly linked together. This led to falsely-linking accounts, either inadvertently or intentionally. For example, Bob might also be known as Bob_ and Bobby, but primarily uses Bob as his main nick. Somebody else might join with Bobby and end up being linked to Bob. Now both Bob and the new Bobby are linked together as the same person, but likely with different *!user@host. Now if the new Bobby ever gets banned, then Bob will also end up being banned for evading Bobby's ban. This was a sore spot in the previous linking implementation. This new implementation has several adjustments to more intelligently link accounts only when they're proven beyond a reasonable doubt to be the same person (e.g. by matching nickserv accounts, etc). Consequently, rather than aggressively linking accounts and catching more ban-evaders at the risk of potentially falsely-linking accounts and falsely detecting innocent people as ban-evaders, this new implementation will instead link accounts more reliably at the risk of potential ban-evaders not yet being linked together and thus being able to evade a ban. This is a more preferable and reasonable risk. Active channel ops should be able to catch any obnoxious ban-evaders that slip through this net.
This commit is contained in:
parent
d77ea29b47
commit
857d1aa0d3
@ -48,6 +48,7 @@ sub initialize {
|
||||
$self->{channels} = {}; # per-channel statistics, e.g. for optimized tracking of last spoken nick for enter-abuse detection, etc
|
||||
$self->{nickflood} = {}; # statistics to track nickchange flooding
|
||||
$self->{whois_pending} = {}; # prevents multiple whois for nick joining multiple channels at once
|
||||
$self->{changinghost} = {}; # tracks nicks changing hosts/identifying to strongly link them
|
||||
|
||||
my $filename = delete $conf{whitelist_file} // $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/whitelist';
|
||||
$self->{whitelist} = PBot::DualIndexHashObject->new(name => 'Whitelist', filename => $filename);
|
||||
@ -128,8 +129,8 @@ sub whitelist {
|
||||
|
||||
return "Usage: whitelist <command>, where commands are: list/show, add, remove, set, unset" if not defined $command;
|
||||
|
||||
given($command) {
|
||||
when($_ eq "list" or $_ eq "show") {
|
||||
given ($command) {
|
||||
when ($_ eq "list" or $_ eq "show") {
|
||||
my $text = "Whitelist:\n";
|
||||
my $entries = 0;
|
||||
foreach my $channel (keys %{ $self->{whitelist}->hash }) {
|
||||
@ -147,7 +148,7 @@ sub whitelist {
|
||||
$text .= "none" if $entries == 0;
|
||||
return $text;
|
||||
}
|
||||
when("set") {
|
||||
when ("set") {
|
||||
my ($channel, $mask, $flag, $value) = split / /, $args, 4;
|
||||
return "Usage: whitelist set <channel> <mask> [flag] [value]" if not defined $channel or not defined $mask;
|
||||
|
||||
@ -188,7 +189,7 @@ sub whitelist {
|
||||
$self->{whitelist}->save;
|
||||
return "Flag set.";
|
||||
}
|
||||
when("unset") {
|
||||
when ("unset") {
|
||||
my ($channel, $mask, $flag) = split / /, $args, 3;
|
||||
return "Usage: whitelist unset <channel> <mask> <flag>" if not defined $channel or not defined $mask or not defined $flag;
|
||||
|
||||
@ -208,7 +209,7 @@ sub whitelist {
|
||||
$self->{whitelist}->save;
|
||||
return "Flag unset.";
|
||||
}
|
||||
when("add") {
|
||||
when ("add") {
|
||||
my ($channel, $mask, $mode) = split / /, $args, 3;
|
||||
return "Usage: whitelist add <channel> <mask> [mode (user or ban, default: user)]" if not defined $channel or not defined $mask;
|
||||
|
||||
@ -225,7 +226,7 @@ sub whitelist {
|
||||
$self->{whitelist}->save;
|
||||
return "$mask whitelisted in channel $channel";
|
||||
}
|
||||
when("remove") {
|
||||
when ("remove") {
|
||||
my ($channel, $mask) = split / /, $args, 2;
|
||||
return "Usage: whitelist remove <channel> <mask>" if not defined $channel or not defined $mask;
|
||||
|
||||
@ -287,8 +288,39 @@ sub check_flood {
|
||||
$channel = lc $channel;
|
||||
|
||||
my $mask = "$nick!$user\@$host";
|
||||
my $account = $self->{pbot}->{messagehistory}->get_message_account($nick, $user, $host);
|
||||
my $oldnick = $nick;
|
||||
my $account;
|
||||
|
||||
if ($mode == $self->{pbot}->{messagehistory}->{MSG_JOIN} and exists $self->{changinghost}->{$nick}) {
|
||||
$self->{pbot}->{logger}->log("Finalizing changinghost for $nick!\n");
|
||||
$account = delete $self->{changinghost}->{$nick};
|
||||
|
||||
my $id = $self->{pbot}->{messagehistory}->{database}->get_message_account_id($mask);
|
||||
if (defined $id) {
|
||||
if ($id != $account) {
|
||||
$self->{pbot}->{logger}->log("Linking $mask [$id] to account $account\n");
|
||||
$self->{pbot}->{messagehistory}->{database}->unlink_alias($account, $id);
|
||||
$self->{pbot}->{messagehistory}->{database}->link_alias($account, $id, $self->{pbot}->{messagehistory}->{database}->{alias_type}->{STRONG});
|
||||
} else {
|
||||
$self->{pbot}->{logger}->log("New hostmask already belongs to original account.\n");
|
||||
}
|
||||
$account = $id;
|
||||
} else {
|
||||
$self->{pbot}->{logger}->log("Adding $mask to account $account\n");
|
||||
$self->{pbot}->{messagehistory}->{database}->add_message_account($mask, $account, $self->{pbot}->{messagehistory}->{database}->{alias_type}->{STRONG});
|
||||
}
|
||||
|
||||
$self->{pbot}->{messagehistory}->{database}->devalidate_all_channels($account);
|
||||
my @nickserv_accounts = $self->{pbot}->{messagehistory}->{database}->get_nickserv_accounts($account);
|
||||
foreach my $nickserv_account (@nickserv_accounts) {
|
||||
$self->{pbot}->{logger}->log("$nick!$user\@$host [$account] seen with nickserv account [$nickserv_account]\n");
|
||||
$self->check_nickserv_accounts($nick, $nickserv_account, "$nick!$user\@$host");
|
||||
}
|
||||
} else {
|
||||
$account = $self->{pbot}->{messagehistory}->get_message_account($nick, $user, $host);
|
||||
}
|
||||
|
||||
$self->{pbot}->{messagehistory}->{database}->update_hostmask_data($mask, { last_seen => scalar gettimeofday });
|
||||
|
||||
if($mode == $self->{pbot}->{messagehistory}->{MSG_NICKCHANGE}) {
|
||||
$self->{pbot}->{logger}->log(sprintf("%-18s | %-65s | %s\n", "NICKCHANGE", $mask, $text));
|
||||
@ -319,6 +351,12 @@ sub check_flood {
|
||||
}
|
||||
|
||||
$self->{pbot}->{messagehistory}->{database}->devalidate_all_channels($account);
|
||||
|
||||
if ($text eq 'QUIT Changing host') {
|
||||
$self->{pbot}->{logger}->log("$mask [$account] changing host!\n");
|
||||
$self->{changinghost}->{$nick} = $account;
|
||||
}
|
||||
|
||||
# don't do flood processing for QUIT events
|
||||
return;
|
||||
}
|
||||
@ -591,6 +629,7 @@ sub unbanme {
|
||||
|
||||
foreach my $alias (keys %aliases) {
|
||||
next if $aliases{$alias}->{type} == $self->{pbot}->{messagehistory}->{database}->{alias_type}->{WEAK};
|
||||
next if $aliases{$alias}->{nickchange} == 1;
|
||||
|
||||
my ($anick, $auser, $ahost) = $alias =~ m/([^!]+)!([^@]+)@(.*)/;
|
||||
my $banmask = address_to_mask($ahost);
|
||||
@ -654,9 +693,9 @@ sub address_to_mask {
|
||||
|
||||
if($address =~ m/^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$/) {
|
||||
my ($a, $b, $c, $d) = ($1, $2, $3, $4);
|
||||
given($a) {
|
||||
when($_ <= 127) { $banmask = "$a.*"; }
|
||||
when($_ <= 191) { $banmask = "$a.$b.*"; }
|
||||
given ($a) {
|
||||
when ($_ <= 127) { $banmask = "$a.*"; }
|
||||
when ($_ <= 191) { $banmask = "$a.$b.*"; }
|
||||
default { $banmask = "$a.$b.$c.*"; }
|
||||
}
|
||||
} elsif($address =~ m{^gateway/([^/]+)/([^/]+)/}) {
|
||||
@ -709,7 +748,7 @@ sub check_bans {
|
||||
|
||||
my $current_nickserv_account = $self->{pbot}->{messagehistory}->{database}->get_current_nickserv_account($message_account);
|
||||
|
||||
if ($current_nickserv_account) {
|
||||
if (defined $current_nickserv_account and length $current_nickserv_account) {
|
||||
$self->{pbot}->{logger}->log("anti-flood: [check-bans] current nickserv [$current_nickserv_account] found for $mask\n") if $debug_checkban >= 2;
|
||||
my $channel_data = $self->{pbot}->{messagehistory}->{database}->get_channel_data($message_account, $channel, 'validated');
|
||||
if ($channel_data->{validated} & $self->{NEEDS_CHECKBAN}) {
|
||||
|
@ -344,7 +344,7 @@ sub on_nickchange {
|
||||
|
||||
my $newnick_account = $self->{pbot}->{messagehistory}->{database}->get_message_account($newnick, $user, $host, $nick);
|
||||
$self->{pbot}->{messagehistory}->{database}->devalidate_all_channels($newnick_account, $self->{pbot}->{antiflood}->{NEEDS_CHECKBAN});
|
||||
$self->{pbot}->{messagehistory}->{database}->update_hostmask_data($newnick_account, { last_seen => scalar gettimeofday });
|
||||
$self->{pbot}->{messagehistory}->{database}->update_hostmask_data("$newnick!$user\@$host", { last_seen => scalar gettimeofday });
|
||||
|
||||
$self->{pbot}->{antiflood}->check_flood("$nick!$user\@$host", $nick, $user, $host, "NICKCHANGE $newnick",
|
||||
$self->{pbot}->{registry}->get_value('antiflood', 'nick_flood_threshold'),
|
||||
|
@ -176,6 +176,8 @@ sub list_also_known_as {
|
||||
} else {
|
||||
$result .= "$sep$aka";
|
||||
}
|
||||
|
||||
$result .= "!" if $akas{$aka}->{nickchange} == 1;
|
||||
$result .= " ($akas{$aka}->{nickserv})" if $show_nickserv and exists $akas{$aka}->{nickserv};
|
||||
$result .= " {$akas{$aka}->{gecos}}" if $show_gecos and exists $akas{$aka}->{gecos};
|
||||
|
||||
|
@ -12,6 +12,7 @@ use DBI;
|
||||
use Carp qw(shortmess);
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
use Text::CSV;
|
||||
use Text::Levenshtein qw/fastdistance/;
|
||||
|
||||
sub new {
|
||||
if(ref($_[1]) eq 'HASH') {
|
||||
@ -82,7 +83,8 @@ sub begin {
|
||||
CREATE TABLE IF NOT EXISTS Hostmasks (
|
||||
hostmask TEXT PRIMARY KEY UNIQUE,
|
||||
id INTEGER,
|
||||
last_seen NUMERIC
|
||||
last_seen NUMERIC,
|
||||
nickchange INTEGER
|
||||
)
|
||||
SQL
|
||||
|
||||
@ -210,7 +212,12 @@ sub get_current_nickserv_account {
|
||||
my $sth = $self->{dbh}->prepare('SELECT nickserv FROM Accounts WHERE id = ?');
|
||||
$sth->bind_param(1, $id);
|
||||
$sth->execute();
|
||||
return $sth->fetchrow_hashref()->{'nickserv'};
|
||||
my $row = $sth->fetchrow_hashref();
|
||||
if (defined $row) {
|
||||
return $row->{'nickserv'};
|
||||
} else {
|
||||
return undef;
|
||||
}
|
||||
};
|
||||
$self->{pbot}->{logger}->log($@) if $@;
|
||||
return $nickserv;
|
||||
@ -281,33 +288,42 @@ sub update_gecos {
|
||||
}
|
||||
|
||||
sub add_message_account {
|
||||
my ($self, $mask, $link_id) = @_;
|
||||
my ($self, $mask, $link_id, $link_type) = @_;
|
||||
my $id;
|
||||
|
||||
if(defined $link_id) {
|
||||
if(defined $link_id and $link_type == $self->{alias_type}->{STRONG}) {
|
||||
$id = $link_id;
|
||||
} else {
|
||||
$id = $self->get_new_account_id();
|
||||
$self->{pbot}->{logger}->log("Got new account id $id\n");
|
||||
}
|
||||
|
||||
eval {
|
||||
my $sth = $self->{dbh}->prepare('INSERT INTO Hostmasks VALUES (?, ?, 0)');
|
||||
my $sth = $self->{dbh}->prepare('INSERT INTO Hostmasks VALUES (?, ?, 0, 0)');
|
||||
$sth->bind_param(1, $mask);
|
||||
$sth->bind_param(2, $id);
|
||||
$sth->execute();
|
||||
$self->{new_entries}++;
|
||||
|
||||
if(not defined $link_id) {
|
||||
if((not defined $link_id) || ((defined $link_id) && ($link_type == $self->{alias_type}->{WEAK}))) {
|
||||
$sth = $self->{dbh}->prepare('INSERT INTO Accounts VALUES (?, ?, ?)');
|
||||
$sth->bind_param(1, $id);
|
||||
$sth->bind_param(2, $mask);
|
||||
$sth->bind_param(3, "");
|
||||
$sth->execute();
|
||||
$self->{new_entries}++;
|
||||
|
||||
$self->{pbot}->{logger}->log("Added new account $id for mask $mask\n");
|
||||
}
|
||||
};
|
||||
|
||||
$self->{pbot}->{logger}->log($@) if $@;
|
||||
|
||||
if (defined $link_id && $link_type == $self->{alias_type}->{WEAK}) {
|
||||
$self->{pbot}->{logger}->log("Weakly linking $id to $link_id\n");
|
||||
$self->link_alias($id, $link_id, $link_type);
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
@ -361,54 +377,138 @@ sub find_message_accounts_by_mask {
|
||||
}
|
||||
|
||||
sub get_message_account {
|
||||
my ($self, $nick, $user, $host, $link_nick) = @_;
|
||||
my ($self, $nick, $user, $host, $orig_nick) = @_;
|
||||
|
||||
=cut
|
||||
use Devel::StackTrace;
|
||||
my $trace = Devel::StackTrace->new(indent => 1, ignore_class => ['PBot::PBot', 'PBot::IRC']);
|
||||
$self->{pbot}->{logger}->log("get_message_account stacktrace: " . $trace->as_string() . "\n");
|
||||
=cut
|
||||
|
||||
my $mask = "$nick!$user\@$host";
|
||||
my $id = $self->get_message_account_id($mask);
|
||||
return $id if defined $id;
|
||||
|
||||
my $rows = eval {
|
||||
my $sth = $self->{dbh}->prepare('SELECT id, hostmask FROM Hostmasks WHERE hostmask LIKE ? ESCAPE "\" ORDER BY last_seen DESC');
|
||||
my $do_nothing = 0;
|
||||
|
||||
my ($rows, $link_type) = eval {
|
||||
my $sth = $self->{dbh}->prepare('SELECT id, hostmask, last_seen FROM Hostmasks WHERE hostmask LIKE ? ESCAPE "\" ORDER BY last_seen DESC');
|
||||
|
||||
if (defined $orig_nick) {
|
||||
my $orig_id = $self->get_message_account_id("$orig_nick!$user\@$host");
|
||||
|
||||
my $qnick = quotemeta $nick;
|
||||
$qnick =~ s/_/\\_/g;
|
||||
$sth->bind_param(1, "$qnick!%");
|
||||
$sth->execute();
|
||||
my $rows = $sth->fetchall_arrayref({});
|
||||
|
||||
if (not defined $rows->[0]) {
|
||||
$rows->[0] = { id => $orig_id, hostmask => "$orig_nick!$user\@$host" };
|
||||
return ($rows, $self->{alias_type}->{STRONG});
|
||||
}
|
||||
|
||||
foreach my $row (@$rows) {
|
||||
$self->{pbot}->{logger}->log("Found matching nickchange account: [$row->{id}] $row->{hostmask}\n");
|
||||
|
||||
if ($row->{id} == $orig_id || $row->{hostmask} =~ m/^.*!\Q$nick\E\@\Q$host\E$/i) {
|
||||
$self->{pbot}->{logger}->log("Using this match.\n");
|
||||
$rows->[0] = { id => $orig_id, hostmask => $row->{hostmask} };
|
||||
return ($rows, $self->{alias_type}->{STRONG});
|
||||
}
|
||||
}
|
||||
|
||||
$self->{pbot}->{logger}->log("Creating new nickchange account!\n");
|
||||
|
||||
my $new_id = $self->add_message_account($mask);
|
||||
$self->link_alias($orig_id, $new_id, $self->{alias_type}->{WEAK});
|
||||
$self->update_hostmask_data($mask, { nickchange => 1 });
|
||||
|
||||
$do_nothing = 1;
|
||||
$rows->[0] = { id => $new_id };
|
||||
return ($rows, 0);
|
||||
}
|
||||
|
||||
if ($host =~ m{^gateway/web/irccloud.com}) {
|
||||
$sth->bind_param(1, "%!$user\@gateway/web/irccloud.com/%");
|
||||
$sth->execute();
|
||||
my $rows = $sth->fetchall_arrayref({});
|
||||
if (defined $rows->[0]) {
|
||||
return $rows;
|
||||
return ($rows, $self->{alias_type}->{STRONG});
|
||||
}
|
||||
}
|
||||
|
||||
my $qnick = quotemeta (defined $link_nick ? $link_nick : $nick);
|
||||
if ($host =~ m{^nat/([^/]+)/}) {
|
||||
$sth->bind_param(1, "$nick!$user\@nat/$1/%");
|
||||
$sth->execute();
|
||||
my $rows = $sth->fetchall_arrayref({});
|
||||
if (defined $rows->[0]) {
|
||||
return ($rows, $self->{alias_type}->{STRONG});
|
||||
}
|
||||
}
|
||||
|
||||
if ($host =~ m{^unaffiliated/}) {
|
||||
$sth->bind_param(1, "%\@$host");
|
||||
$sth->execute();
|
||||
my $rows = $sth->fetchall_arrayref({});
|
||||
if (defined $rows->[0]) {
|
||||
return ($rows, $self->{alias_type}->{STRONG});
|
||||
}
|
||||
}
|
||||
|
||||
my $link_type = $self->{alias_type}->{WEAK};
|
||||
my $qnick = quotemeta $nick;
|
||||
$qnick =~ s/_/\\_/g;
|
||||
$sth->bind_param(1, "$qnick!%");
|
||||
$sth->execute();
|
||||
my $rows = $sth->fetchall_arrayref({});
|
||||
|
||||
=cut
|
||||
foreach my $row (@$rows) {
|
||||
$self->{pbot}->{logger}->log("Found matching nick $row->{hostmask} with id $row->{id}\n");
|
||||
}
|
||||
=cut
|
||||
my ($thost) = $row->{hostmask} =~ m/@(.*)$/;
|
||||
|
||||
if(not defined $rows->[0]) {
|
||||
if ($thost =~ m{(^unaffiliated|/staff/|/member/)} and $host ne $thost) {
|
||||
$self->{pbot}->{logger}->log("Skipping non-matching cloaked hosts: $host vs $thost\n");
|
||||
next;
|
||||
}
|
||||
|
||||
my $distance = fastdistance($host, $thost);
|
||||
my $length = (length($host) > length($thost)) ? length $host : length $thost;
|
||||
|
||||
$self->{pbot}->{logger}->log("distance: " . ($distance / $length) . " -- $host vs $thost\n") if $length != 0;
|
||||
|
||||
if ($length != 0 && $distance / $length < 0.50) {
|
||||
$rows->[0] = $row;
|
||||
return ($rows, $self->{alias_type}->{STRONG});
|
||||
}
|
||||
}
|
||||
|
||||
if (not defined $rows->[0]) {
|
||||
$link_type = $self->{alias_type}->{STRONG};
|
||||
$sth->bind_param(1, "%!$user\@$host");
|
||||
$sth->execute();
|
||||
$rows = $sth->fetchall_arrayref({});
|
||||
|
||||
if (defined $rows->[0] and gettimeofday - $rows->[0]->{last_seen} > 60 * 60 * 48) {
|
||||
$link_type = $self->{alias_type}->{WEAK};
|
||||
$self->{pbot}->{logger}->log("Longer than 48 hours (" . (gettimeofday - $rows->[0]->{last_seen}) . ") for $rows->[0]->{hostmask} for $nick!$user\@$host, degrading to weak link\n");
|
||||
}
|
||||
|
||||
=cut
|
||||
foreach my $row (@$rows) {
|
||||
$self->{pbot}->{logger}->log("Found matching user\@host mask $row->{hostmask} with id $row->{id}\n");
|
||||
}
|
||||
=cut
|
||||
}
|
||||
return $rows;
|
||||
return ($rows, $link_type);
|
||||
};
|
||||
$self->{pbot}->{logger}->log($@) if $@;
|
||||
|
||||
if(defined $rows->[0]) {
|
||||
$self->{pbot}->{logger}->log("message-history: [get-account] $nick!$user\@$host linked to $rows->[0]->{hostmask} with id $rows->[0]->{id}\n");
|
||||
$self->add_message_account("$nick!$user\@$host", $rows->[0]->{id});
|
||||
return $rows->[0]->{id} if $do_nothing;
|
||||
|
||||
if (defined $rows->[0]) {
|
||||
$self->{pbot}->{logger}->log("message-history: [get-account] $nick!$user\@$host " . ($link_type == $self->{alias_type}->{WEAK} ? "weakly linked to" : "added to account") . " $rows->[0]->{hostmask} with id $rows->[0]->{id}\n");
|
||||
$self->add_message_account("$nick!$user\@$host", $rows->[0]->{id}, $link_type);
|
||||
$self->devalidate_all_channels($rows->[0]->{id});
|
||||
$self->update_hostmask_data("$nick!$user\@$host", { last_seen => scalar gettimeofday });
|
||||
my @nickserv_accounts = $self->get_nickserv_accounts($rows->[0]->{id});
|
||||
@ -906,9 +1006,9 @@ sub link_aliases {
|
||||
my %ids;
|
||||
|
||||
if ($hostmask) {
|
||||
my ($host) = $hostmask =~ /(\@.*)$/;
|
||||
my ($nick, $host) = $hostmask =~ /^([^!]+)![^@]+@(.*)$/;
|
||||
my $sth = $self->{dbh}->prepare('SELECT id, last_seen FROM Hostmasks WHERE hostmask LIKE ?');
|
||||
$sth->bind_param(1, "\%$host");
|
||||
$sth->bind_param(1, "\%\@$host");
|
||||
$sth->execute();
|
||||
my $rows = $sth->fetchall_arrayref({});
|
||||
|
||||
@ -916,27 +1016,41 @@ sub link_aliases {
|
||||
|
||||
foreach my $row (@$rows) {
|
||||
if ($now - $row->{last_seen} <= 60 * 60 * 48) {
|
||||
$ids{$row->{id}} = { id => $row->{id}, type => $self->{alias_type}->{STRONG} };
|
||||
$self->{pbot}->{logger}->log("found STRONG matching id $row->{id} for host [$host]\n") if $debug_link;
|
||||
$ids{$row->{id}} = { id => $row->{id}, type => $self->{alias_type}->{STRONG}, force => 1 };
|
||||
$self->{pbot}->{logger}->log("found STRONG matching id $row->{id} for host [$host]\n") if $debug_link && $row->{id} != $account;
|
||||
} else {
|
||||
$ids{$row->{id}} = { id => $row->{id}, type => $self->{alias_type}->{WEAK} };
|
||||
$self->{pbot}->{logger}->log("found WEAK matching id $row->{id} for host [$host]\n") if $debug_link;
|
||||
$self->{pbot}->{logger}->log("found WEAK matching id $row->{id} for host [$host]\n") if $debug_link && $row->{id} != $account;
|
||||
}
|
||||
}
|
||||
|
||||
my ($nick) = $hostmask =~ m/([^!]+)/;
|
||||
unless ($nick =~ m/^Guest\d+$/) {
|
||||
my $qnick = quotemeta $nick;
|
||||
$qnick =~ s/_/\\_/g;
|
||||
|
||||
my $sth = $self->{dbh}->prepare('SELECT id FROM Hostmasks WHERE hostmask LIKE ? ESCAPE "\"');
|
||||
my $sth = $self->{dbh}->prepare('SELECT id, hostmask FROM Hostmasks WHERE hostmask LIKE ? ESCAPE "\"');
|
||||
$sth->bind_param(1, "$qnick!%");
|
||||
$sth->execute();
|
||||
my $rows = $sth->fetchall_arrayref({});
|
||||
|
||||
foreach my $row (@$rows) {
|
||||
$ids{$row->{id}} = { id => $row->{id}, type => $self->{alias_type}->{STRONG} };
|
||||
$self->{pbot}->{logger}->log("found STRONG matching id $row->{id} for nick [$qnick]\n") if $debug_link;
|
||||
next if $row->{id} == $account;
|
||||
my ($thost) = $row->{hostmask} =~ m/@(.*)$/;
|
||||
|
||||
if ($thost =~ m{(^unaffiliated|/staff/|/member/)} and $host ne $thost) {
|
||||
$self->{pbot}->{logger}->log("Skipping non-matching cloaked hosts: $host vs $thost\n");
|
||||
next;
|
||||
}
|
||||
|
||||
my $distance = fastdistance($host, $thost);
|
||||
my $length = (length($host) > length($thost)) ? length $host : length $thost;
|
||||
|
||||
$self->{pbot}->{logger}->log("distance: " . ($distance / $length) . " -- $host vs $thost\n") if $length != 0;
|
||||
|
||||
if ($length != 0 && $distance / $length < 0.50) {
|
||||
$ids{$row->{id}} = { id => $row->{id}, type => $self->{alias_type}->{STRONG} }; # don't force linking
|
||||
$self->{pbot}->{logger}->log("found STRONG matching id $row->{id} for nick [$qnick]\n") if $debug_link;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -948,15 +1062,24 @@ sub link_aliases {
|
||||
my $rows = $sth->fetchall_arrayref({});
|
||||
|
||||
foreach my $row (@$rows) {
|
||||
$ids{$row->{id}} = { id => $row->{id}, type => $self->{alias_type}->{STRONG} };
|
||||
$self->{pbot}->{logger}->log("found STRONG matching id $row->{id} for nickserv [$nickserv]\n") if $debug_link;
|
||||
$ids{$row->{id}} = { id => $row->{id}, type => $self->{alias_type}->{STRONG}, force => 1 };
|
||||
$self->{pbot}->{logger}->log("found STRONG matching id $row->{id} for nickserv [$nickserv]\n") if $debug_link && $row->{id} != $account;
|
||||
}
|
||||
}
|
||||
|
||||
my $sth = $self->{dbh}->prepare('REPLACE INTO Aliases (id, alias, type) VALUES (?, ?, ?)');
|
||||
#my $sth = $self->{dbh}->prepare('REPLACE INTO Aliases (id, alias, type) VALUES (?, ?, ?)');
|
||||
|
||||
foreach my $id (sort keys %ids) {
|
||||
next if $account == $id;
|
||||
|
||||
if (exists $ids{$id}->{force}) {
|
||||
$self->{pbot}->{logger}->log("Forcing link of $account and $id!\n");
|
||||
$self->unlink_alias($account, $id);
|
||||
}
|
||||
|
||||
$self->link_alias($account, $id, $ids{$id}->{type});
|
||||
|
||||
=cut
|
||||
$sth->bind_param(1, $account);
|
||||
$sth->bind_param(2, $id);
|
||||
$sth->bind_param(3, $ids{$id}->{type});
|
||||
@ -974,6 +1097,7 @@ sub link_aliases {
|
||||
$self->{pbot}->{logger}->log("Linked $id to $account [$ids{$id}->{type}]\n") if $debug_link;
|
||||
$self->{new_entries}++;
|
||||
}
|
||||
=cut
|
||||
}
|
||||
};
|
||||
$self->{pbot}->{logger}->log($@) if $@;
|
||||
@ -982,55 +1106,32 @@ sub link_aliases {
|
||||
sub link_alias {
|
||||
my ($self, $id, $alias, $type) = @_;
|
||||
|
||||
my $ret = eval {
|
||||
my $ret = 0;
|
||||
$self->{pbot}->{logger}->log("Attempting to " . ($type == $self->{alias_type}->{STRONG} ? "strongly" : "weakly") . " link $id to $alias\n");
|
||||
|
||||
my $sth = $self->{dbh}->prepare('INSERT INTO Aliases SELECT ?, ?, ? WHERE NOT EXISTS (SELECT 1 FROM Aliases WHERE id = ? AND alias = ?)');
|
||||
my $ret = eval {
|
||||
my $sth = $self->{dbh}->prepare('SELECT * FROM Aliases WHERE id = ? AND alias = ? LIMIT 1');
|
||||
$sth->bind_param(1, $alias);
|
||||
$sth->bind_param(2, $id);
|
||||
$sth->execute();
|
||||
|
||||
my $row = $sth->fetchrow_hashref();
|
||||
if (defined $row) {
|
||||
$self->{pbot}->{logger}->log("$id already " . ($row->{'type'} == $self->{alias_type}->{STRONG} ? "strongly" : "weakly") . " linked to $alias, ignoring\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
$sth = $self->{dbh}->prepare('INSERT INTO Aliases VALUES (?, ?, ?)');
|
||||
$sth->bind_param(1, $alias);
|
||||
$sth->bind_param(2, $id);
|
||||
$sth->bind_param(3, $type);
|
||||
$sth->bind_param(4, $alias);
|
||||
$sth->bind_param(5, $id);
|
||||
$sth->execute();
|
||||
if ($sth->rows) {
|
||||
$self->{new_entries}++;
|
||||
$ret = 1;
|
||||
} else {
|
||||
$sth = $self->{dbh}->prepare('UPDATE Aliases SET type = ? WHERE id = ? AND alias = ?');
|
||||
$sth->bind_param(1, $type);
|
||||
$sth->bind_param(2, $id);
|
||||
$sth->bind_param(3, $alias);
|
||||
$sth->execute();
|
||||
if ($sth->rows) {
|
||||
$self->{new_entries}++;
|
||||
$ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
$sth = $self->{dbh}->prepare('INSERT INTO Aliases SELECT ?, ?, ? WHERE NOT EXISTS (SELECT 1 FROM Aliases WHERE id = ? AND alias = ?)');
|
||||
$sth->bind_param(1, $id);
|
||||
$sth->bind_param(2, $alias);
|
||||
$sth->bind_param(3, $type);
|
||||
$sth->bind_param(4, $id);
|
||||
$sth->bind_param(5, $alias);
|
||||
$sth->execute();
|
||||
if ($sth->rows) {
|
||||
$self->{new_entries}++;
|
||||
$ret = 1;
|
||||
} else {
|
||||
$sth = $self->{dbh}->prepare('UPDATE Aliases SET type = ? WHERE id = ? AND alias = ?');
|
||||
$sth->bind_param(1, $type);
|
||||
$sth->bind_param(2, $alias);
|
||||
$sth->bind_param(3, $id);
|
||||
$sth->execute();
|
||||
if ($sth->rows) {
|
||||
$self->{new_entries}++;
|
||||
$ret = 1;
|
||||
} else {
|
||||
$ret = 0;
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
|
||||
$self->{pbot}->{logger}->log("Linked.\n");
|
||||
return 1;
|
||||
};
|
||||
$self->{pbot}->{logger}->log($@) if $@;
|
||||
return $ret;
|
||||
@ -1166,7 +1267,7 @@ sub get_also_known_as {
|
||||
last if not $new_aliases;
|
||||
}
|
||||
|
||||
my $hostmask_sth = $self->{dbh}->prepare('SELECT hostmask FROM Hostmasks WHERE id = ?');
|
||||
my $hostmask_sth = $self->{dbh}->prepare('SELECT hostmask, nickchange FROM Hostmasks WHERE id = ?');
|
||||
my $nickserv_sth = $self->{dbh}->prepare('SELECT nickserv FROM Nickserv WHERE id = ?');
|
||||
my $gecos_sth = $self->{dbh}->prepare('SELECT gecos FROM Gecos WHERE id = ?');
|
||||
|
||||
@ -1178,7 +1279,7 @@ sub get_also_known_as {
|
||||
$rows = $hostmask_sth->fetchall_arrayref({});
|
||||
|
||||
foreach my $row (@$rows) {
|
||||
$akas{$row->{hostmask}} = { hostmask => $row->{hostmask}, id => $id, alias => $ids{$id}->{id}, type => $ids{$id}->{type} };
|
||||
$akas{$row->{hostmask}} = { hostmask => $row->{hostmask}, id => $id, alias => $ids{$id}->{id}, type => $ids{$id}->{type}, nickchange => $row->{nickchange} };
|
||||
$self->{pbot}->{logger}->log("[$id] Adding hostmask $row->{hostmask} -> $ids{$id}->{id} [type $ids{$id}->{type}]\n") if $debug;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user