1 84c190b6 2021-12-17 jrmu #!/usr/bin/perl
6 84c190b6 2021-12-17 jrmu use warnings;
7 84c190b6 2021-12-17 jrmu use OpenBSD::Pledge;
8 84c190b6 2021-12-17 jrmu use OpenBSD::Unveil;
9 84c190b6 2021-12-17 jrmu use MIME::Base64;
10 84c190b6 2021-12-17 jrmu use Digest::SHA qw(sha256_hex);
11 84c190b6 2021-12-17 jrmu use lib './';
12 84c190b6 2021-12-17 jrmu require "SQLite.pm";
13 84c190b6 2021-12-17 jrmu require "Hash.pm";
14 84c190b6 2021-12-17 jrmu require "DNS.pm";
15 84c190b6 2021-12-17 jrmu require "Mail.pm";
17 84c190b6 2021-12-17 jrmu my %conf = %main::conf;
18 84c190b6 2021-12-17 jrmu my $chans = $conf{chans};
19 84c190b6 2021-12-17 jrmu my $teamchans = $conf{teamchans};
20 84c190b6 2021-12-17 jrmu my @teamchans = split /[,\s]+/m, $teamchans;
21 84c190b6 2021-12-17 jrmu my $staff = $conf{staff};
22 84c190b6 2021-12-17 jrmu my $zncdir = $conf{zncdir};
23 84c190b6 2021-12-17 jrmu my $znclog = $conf{znclog} || "$zncdir/.znc/moddata/adminlog/znc.log";
24 84c190b6 2021-12-17 jrmu my $hostname = $conf{hostname};
25 84c190b6 2021-12-17 jrmu my $terms = $conf{terms};
27 84c190b6 2021-12-17 jrmu my $expires = $conf{expires};
28 84c190b6 2021-12-17 jrmu my $sslport = $conf{sslport};
29 84c190b6 2021-12-17 jrmu my $plainport = $conf{plainport};
30 84c190b6 2021-12-17 jrmu my $mailfrom = $conf{mailfrom};
31 84c190b6 2021-12-17 jrmu my $mailname = $conf{mailname};
32 84c190b6 2021-12-17 jrmu my $zncconfpath = $conf{zncconfpath} || "$zncdir/.znc/configs/znc.conf";
33 84c190b6 2021-12-17 jrmu my $znctree = { Node => "root" };
35 84c190b6 2021-12-17 jrmu use constant {
37 84c190b6 2021-12-17 jrmu ERRORS => 1,
38 84c190b6 2021-12-17 jrmu WARNINGS => 2,
42 84c190b6 2021-12-17 jrmu `doas chown znc:daemon /home/znc/home/znc/.znc/configs/znc.conf`;
43 84c190b6 2021-12-17 jrmu `doas chmod g+r /home/znc/home/znc/.znc/`;
44 84c190b6 2021-12-17 jrmu my @zncconf = main::readarray($zncconfpath);
47 84c190b6 2021-12-17 jrmu foreach my $line (@zncconf) {
48 84c190b6 2021-12-17 jrmu if ($line =~ /<User (.*)>/) {
49 84c190b6 2021-12-17 jrmu push(@users, $1);
52 84c190b6 2021-12-17 jrmu #$znctree = parseml($znctree, @zncconf);
53 84c190b6 2021-12-17 jrmu main::cbind("pub", "-", "bnc", \&mbnc);
54 84c190b6 2021-12-17 jrmu main::cbind("msg", "-", "bnc", \&mbnc);
55 84c190b6 2021-12-17 jrmu main::cbind("msg", "-", "regex", \&mregex);
56 84c190b6 2021-12-17 jrmu main::cbind("msg", "-", "foreach", \&mforeach);
57 84c190b6 2021-12-17 jrmu main::cbind("msgm", "-", "*", \&mcontrolpanel);
58 84c190b6 2021-12-17 jrmu main::cbind("msg", "-", "taillog", \&mtaillog);
59 84c190b6 2021-12-17 jrmu main::cbind("msg", "-", "lastseen", \&mlastseen);
62 84c190b6 2021-12-17 jrmu #znc.conf file
63 84c190b6 2021-12-17 jrmu unveil("$zncconfpath", "r") or die "Unable to unveil $!";
64 84c190b6 2021-12-17 jrmu #dependencies for figlet
65 84c190b6 2021-12-17 jrmu unveil("/usr/local/bin/figlet", "rx") or die "Unable to unveil $!";
66 84c190b6 2021-12-17 jrmu unveil("/usr/lib/libc.so.95.1", "r") or die "Unable to unveil $!";
67 84c190b6 2021-12-17 jrmu unveil("/usr/libexec/ld.so", "r") or die "Unable to unveil $!";
68 84c190b6 2021-12-17 jrmu unveil("/usr/bin/tail", "rx") or die "Unable to unveil $!";
69 84c190b6 2021-12-17 jrmu #znc.log file
70 84c190b6 2021-12-17 jrmu unveil("$znclog", "r") or die "Unable to unveil $!";
71 84c190b6 2021-12-17 jrmu #print treeget($znctree, "AnonIPLimit")."\n";
72 84c190b6 2021-12-17 jrmu #print treeget($znctree, "ServerThrottle")."\n";
73 84c190b6 2021-12-17 jrmu #print treeget($znctree, "ConnectDelay")."\n";
74 84c190b6 2021-12-17 jrmu #print "treeget\n";
75 84c190b6 2021-12-17 jrmu #print Dumper \treeget($znctree, "User", "Node");
76 84c190b6 2021-12-17 jrmu #print Dumper \treeget($znctree, "User", "Network", "Node");
79 84c190b6 2021-12-17 jrmu # parseml($tree, @lines)
80 84c190b6 2021-12-17 jrmu # tree is a reference to a hash
81 84c190b6 2021-12-17 jrmu # returns hash ref of tree
82 84c190b6 2021-12-17 jrmu sub parseml {
83 84c190b6 2021-12-17 jrmu my ($tree, @lines) = @_;
84 84c190b6 2021-12-17 jrmu #if (scalar(@lines) == 0) { return $tree; }
85 84c190b6 2021-12-17 jrmu while (scalar(@lines) > 0) {
86 84c190b6 2021-12-17 jrmu my $line = shift(@lines);
87 84c190b6 2021-12-17 jrmu if ($line =~ /^\s*([^=<>\s]+)\s*=\s*([^=<>]+)\s*$/) {
88 84c190b6 2021-12-17 jrmu my ($tag, $val) = ($1, $2);
89 84c190b6 2021-12-17 jrmu $tree->{$tag} = $val;
90 84c190b6 2021-12-17 jrmu } elsif ($line =~ /^\/\//) { # skip comments
91 84c190b6 2021-12-17 jrmu } elsif ($line =~ /^\s*$/) { # skip blank lines
92 84c190b6 2021-12-17 jrmu } elsif ($line =~ /^\s*<([^>\s\/]+)\s*([^>\/]*)>\s*$/) {
93 84c190b6 2021-12-17 jrmu my ($tag, $val) = ($1, $2);
94 84c190b6 2021-12-17 jrmu if (!defined($tree->{$tag})) { $tree->{$tag} = []; }
95 84c190b6 2021-12-17 jrmu my @newlines;
96 84c190b6 2021-12-17 jrmu while (scalar(@lines) > 0) {
97 84c190b6 2021-12-17 jrmu my $line = shift(@lines);
98 84c190b6 2021-12-17 jrmu if ($line =~ /^\s*<\/$tag>\s*$/) {
99 84c190b6 2021-12-17 jrmu my $subtree = parseml({ Node => $val }, @newlines);
100 84c190b6 2021-12-17 jrmu push(@{$tree->{$tag}}, $subtree);
101 84c190b6 2021-12-17 jrmu return parseml($tree, @lines);
103 84c190b6 2021-12-17 jrmu push(@newlines, $line);
105 84c190b6 2021-12-17 jrmu } else { print "ERROR: $line\n"; }
106 84c190b6 2021-12-17 jrmu #TODO ERRORS not defined??
107 84c190b6 2021-12-17 jrmu # } else { main::debug(ERRORS, "ERROR: $line"); }
109 84c190b6 2021-12-17 jrmu return $tree;
112 84c190b6 2021-12-17 jrmu #Returns array of all values
113 84c190b6 2021-12-17 jrmu #treeget($tree, "User");
114 84c190b6 2021-12-17 jrmu #treeget($tree, "MaFFia Network");
115 84c190b6 2021-12-17 jrmu sub treeget {
116 84c190b6 2021-12-17 jrmu my ($tree, @keys) = @_;
117 84c190b6 2021-12-17 jrmu my $subtree;
118 84c190b6 2021-12-17 jrmu my @rest = @keys;
119 84c190b6 2021-12-17 jrmu my $key = shift(@rest);
120 84c190b6 2021-12-17 jrmu $subtree = $tree->{$key};
121 84c190b6 2021-12-17 jrmu if (!defined($subtree)) {
122 84c190b6 2021-12-17 jrmu return ("Undefined");
123 84c190b6 2021-12-17 jrmu } elsif (ref($subtree) eq 'HASH') {
124 84c190b6 2021-12-17 jrmu return treeget($subtree, @rest);
125 84c190b6 2021-12-17 jrmu } elsif (ref($subtree) eq 'ARRAY') {
126 84c190b6 2021-12-17 jrmu my @array = @{$subtree};
128 84c190b6 2021-12-17 jrmu foreach my $hashref (@array) {
129 84c190b6 2021-12-17 jrmu push(@ret, treeget($hashref, @rest));
131 84c190b6 2021-12-17 jrmu return @ret;
132 84c190b6 2021-12-17 jrmu #my @array = @{$subtree};
133 84c190b6 2021-12-17 jrmu #print Dumper treeget($hashref, @rest);
134 84c190b6 2021-12-17 jrmu #print Dumper treeget({$key => $subtree}, @rest);
135 84c190b6 2021-12-17 jrmu #return (treeget($hashref, @rest), treeget({$key => $subtree}, @rest));
137 84c190b6 2021-12-17 jrmu return ($subtree);
142 84c190b6 2021-12-17 jrmu my ($bot, $nick, $host, $hand, @args) = @_;
143 84c190b6 2021-12-17 jrmu my ($chan, $text);
144 84c190b6 2021-12-17 jrmu if (@args == 2) {
145 84c190b6 2021-12-17 jrmu ($chan, $text) = ($args[0], $args[1]);
146 84c190b6 2021-12-17 jrmu } else { $text = $args[0]; }
147 84c190b6 2021-12-17 jrmu my $hostmask = "$nick!$host";
148 84c190b6 2021-12-17 jrmu if (defined($chan) && $chans =~ /$chan/) {
149 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $chan :$nick: Please check private message");
151 84c190b6 2021-12-17 jrmu if ($text =~ /^$/) {
152 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :Type !help for new instructions");
153 84c190b6 2021-12-17 jrmu foreach my $chan (@teamchans) {
154 84c190b6 2021-12-17 jrmu main::putservlocalnet($bot, "PRIVMSG $chan :Help *$nick* on ".$bot->{name});
157 84c190b6 2021-12-17 jrmu } elsif (main::isstaff($bot, $nick) && $text =~ /^delete\s+([[:ascii:]]+)/) {
158 84c190b6 2021-12-17 jrmu my $username = $1;
159 84c190b6 2021-12-17 jrmu if (SQLite::deleterows("bnc", "username", $username)) {
160 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG *controlpanel :deluser $username");
161 84c190b6 2021-12-17 jrmu foreach my $chan (@teamchans) {
162 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $chan :$username deleted");
166 84c190b6 2021-12-17 jrmu } elsif ($staff =~ /$nick/ && $text =~ /^cloneuser$/i) {
167 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG *controlpanel :deluser cloneuser");
169 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG *controlpanel :get Nick cloneuser");
171 84c190b6 2021-12-17 jrmu ### TODO: Check duplicate emails ###
172 84c190b6 2021-12-17 jrmu my @rows = SQLite::selectrows("irc", "hostmask", $hostmask);
173 84c190b6 2021-12-17 jrmu foreach my $row (@rows) {
174 84c190b6 2021-12-17 jrmu my $password = SQLite::get("bnc", "ircid", $row->{id}, "password");
175 84c190b6 2021-12-17 jrmu if (defined($password)) {
176 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :Sorry, only one account per person. Please contact staff if you need help.");
180 84c190b6 2021-12-17 jrmu if ($text =~ /^captcha\s+([[:alnum:]]+)/) {
181 84c190b6 2021-12-17 jrmu my $text = $1;
182 84c190b6 2021-12-17 jrmu # TODO avoid using host mask because cloaking can cause problems
183 84c190b6 2021-12-17 jrmu my $ircid = SQLite::id("irc", "nick", $nick, $expires);
184 84c190b6 2021-12-17 jrmu my $captcha = SQLite::get("bnc", "ircid", $ircid, "captcha");
185 84c190b6 2021-12-17 jrmu if ($text ne $captcha) {
186 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :Wrong captcha. To get a new captcha, type !bnc <username> <email>");
189 84c190b6 2021-12-17 jrmu my $pass = Hash::newpass();
190 84c190b6 2021-12-17 jrmu chomp(my $encrypted = `encrypt $pass`);
191 84c190b6 2021-12-17 jrmu my $username = SQLite::get("bnc", "ircid", $ircid, "username");
192 84c190b6 2021-12-17 jrmu my $email = SQLite::get("bnc", "ircid", $ircid, "email");
193 84c190b6 2021-12-17 jrmu my $hashirc = SQLite::get("irc", "id", $ircid, "hashid");
194 84c190b6 2021-12-17 jrmu my $bindhost = "$username.$hostname";
195 84c190b6 2021-12-17 jrmu SQLite::set("bnc", "ircid", $ircid, "password", $encrypted);
196 84c190b6 2021-12-17 jrmu if (DNS::nextdns($username)) {
198 84c190b6 2021-12-17 jrmu createbnc($bot, $username, $pass, $bindhost);
199 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :Check your email!");
200 84c190b6 2021-12-17 jrmu mailbnc($username, $email, $pass, "bouncer", $hashirc);
201 84c190b6 2021-12-17 jrmu #www($newnick, $reply, $password, "bouncer");
203 84c190b6 2021-12-17 jrmu foreach my $chan (@teamchans) {
204 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $chan :Assigning bindhost $bindhost failed");
208 84c190b6 2021-12-17 jrmu } elsif ($text =~ /^([[:alnum:]]+)\s+([[:ascii:]]+)/) {
209 84c190b6 2021-12-17 jrmu my ($username, $email) = ($1, $2);
210 84c190b6 2021-12-17 jrmu # my @users = treeget($znctree, "User", "Node");
211 84c190b6 2021-12-17 jrmu foreach my $user (@users) {
212 84c190b6 2021-12-17 jrmu if ($user eq $username) {
213 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :Sorry, username taken. Please contact staff if you need help.");
217 84c190b6 2021-12-17 jrmu #my $captcha = join'', map +(0..9,'a'..'z','A'..'Z')[rand(10+26*2)], 1..4;
218 84c190b6 2021-12-17 jrmu my $captcha = int(rand(999));
219 84c190b6 2021-12-17 jrmu my $ircid = int(rand(9223372036854775807));
220 84c190b6 2021-12-17 jrmu my $hashid = sha256_hex("$ircid");
221 84c190b6 2021-12-17 jrmu SQLite::set("irc", "id", $ircid, "localtime", time());
222 84c190b6 2021-12-17 jrmu SQLite::set("irc", "id", $ircid, "hashid", sha256_hex($ircid));
223 84c190b6 2021-12-17 jrmu SQLite::set("irc", "id", $ircid, "date", main::date());
224 84c190b6 2021-12-17 jrmu SQLite::set("irc", "id", $ircid, "hostmask", $hostmask);
225 84c190b6 2021-12-17 jrmu SQLite::set("irc", "id", $ircid, "nick", $nick);
226 84c190b6 2021-12-17 jrmu SQLite::set("bnc", "ircid", $ircid, "username", $username);
227 84c190b6 2021-12-17 jrmu SQLite::set("bnc", "ircid", $ircid, "email", $email);
228 84c190b6 2021-12-17 jrmu SQLite::set("bnc", "ircid", $ircid, "captcha", $captcha);
229 84c190b6 2021-12-17 jrmu SQLite::set("bnc", "ircid", $ircid, "hashid", $hashid);
230 84c190b6 2021-12-17 jrmu main::whois($bot->{sock}, $nick);
231 84c190b6 2021-12-17 jrmu main::ctcp($bot->{sock}, $nick);
232 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :".`figlet $captcha`);
233 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :https://$hostname/$hashid/captcha.png");
234 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :https://$hostname/register.php?hashirc=$hashid");
235 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :Type !bnc captcha <text>");
236 84c190b6 2021-12-17 jrmu foreach my $chan (@teamchans) {
237 84c190b6 2021-12-17 jrmu main::putservlocalnet($bot, "PRIVMSG $chan :$nick\'s on $bot->{name} bnc captcha is $captcha");
240 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :Invalid username or email. Type !bnc <username> <email> to try again.");
241 84c190b6 2021-12-17 jrmu foreach my $chan (@teamchans) {
242 84c190b6 2021-12-17 jrmu main::putservlocalnet($bot, "PRIVMSG $chan :Help *$nick* on ".$bot->{name});
247 84c190b6 2021-12-17 jrmu sub mregex {
248 84c190b6 2021-12-17 jrmu my ($bot, $nick, $host, $hand, $text) = @_;
249 84c190b6 2021-12-17 jrmu if (!main::isstaff($bot, $nick)) { return; }
250 84c190b6 2021-12-17 jrmu if ($text =~ /^ips?\s+([-_()|0-9A-Za-z:\.?*\s]{3,})$/) {
251 84c190b6 2021-12-17 jrmu my $ips = $1; # space-separated list of IPs
252 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :".regexlist($ips));
253 84c190b6 2021-12-17 jrmu } elsif ($text =~ /^users?\s+([-_()|0-9A-Za-z:\.?*\s]{3,})$/) {
254 84c190b6 2021-12-17 jrmu my $users = $1; # space-separated list of usernames
255 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $nick :".regexlist($users));
256 84c190b6 2021-12-17 jrmu } elsif ($text =~ /^[-_()|0-9A-Za-z:,\.?*\s]{3,}$/) {
257 84c190b6 2021-12-17 jrmu my @lines = regex($text);
258 84c190b6 2021-12-17 jrmu foreach my $l (@lines) { print "$l\n"; }
261 84c190b6 2021-12-17 jrmu sub mforeach {
262 84c190b6 2021-12-17 jrmu my ($bot, $nick, $host, $hand, $text) = @_;
263 84c190b6 2021-12-17 jrmu if ($staff !~ /$nick/) { return; }
264 84c190b6 2021-12-17 jrmu if ($text =~ /^network\s+del\s+([[:graph:]]+)\s+(#[[:graph:]]+)$/) {
265 84c190b6 2021-12-17 jrmu my ($user, $chan) = ($1, $2);
266 84c190b6 2021-12-17 jrmu foreach my $n (@main::networks) {
267 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG *controlpanel :delchan $user $n->{name} $chan");
272 84c190b6 2021-12-17 jrmu sub mcontrolpanel {
273 84c190b6 2021-12-17 jrmu my ($bot, $nick, $host, $hand, @args) = @_;
274 84c190b6 2021-12-17 jrmu my ($chan, $text);
275 84c190b6 2021-12-17 jrmu if (@args == 2) {
276 84c190b6 2021-12-17 jrmu ($chan, $text) = ($args[0], $args[1]);
277 84c190b6 2021-12-17 jrmu } else { $text = $args[0]; }
278 84c190b6 2021-12-17 jrmu my $hostmask = "$nick!$host";
279 84c190b6 2021-12-17 jrmu if($hostmask eq '*controlpanel!znc@znc.in') {
280 84c190b6 2021-12-17 jrmu if ($text =~ /^Error: User \[cloneuser\] does not exist/) {
281 84c190b6 2021-12-17 jrmu createclone($bot);
282 84c190b6 2021-12-17 jrmu foreach my $chan (@teamchans) {
283 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $chan :Cloneuser created");
285 84c190b6 2021-12-17 jrmu } elsif ($text =~ /^User (.*) added!$/) {
286 84c190b6 2021-12-17 jrmu main::debug(ALL, "User $1 created");
287 84c190b6 2021-12-17 jrmu } elsif ($text =~ /^Password has been changed!$/) {
288 84c190b6 2021-12-17 jrmu main::debug(ALL, "Password changed");
289 84c190b6 2021-12-17 jrmu } elsif ($text =~ /^Queued network (.*) of user (.*) for a reconnect.$/) {
290 84c190b6 2021-12-17 jrmu main::debug(ALL, "$2 now connecting to $1...");
291 84c190b6 2021-12-17 jrmu } elsif ($text =~ /^Admin = false/) {
292 84c190b6 2021-12-17 jrmu foreach my $chan (@teamchans) {
293 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $chan :ERROR: $nick is not admin");
295 84c190b6 2021-12-17 jrmu die "ERROR: $nick is not admin";
296 84c190b6 2021-12-17 jrmu } elsif ($text =~ /^Admin = true/) {
297 84c190b6 2021-12-17 jrmu main::debug(ALL, "$nick is ZNC admin");
298 84c190b6 2021-12-17 jrmu } elsif ($text =~ /(.*) = (.*)/) {
299 84c190b6 2021-12-17 jrmu my ($key, $val) = ($1, $2);
300 84c190b6 2021-12-17 jrmu main::debug(ALL, "ZNC: $key => $val");
302 84c190b6 2021-12-17 jrmu main::debug(ERRORS, "Unexpected 290 BNC.pm: $hostmask $text");
306 84c190b6 2021-12-17 jrmu sub loadlog {
307 84c190b6 2021-12-17 jrmu open(my $fh, '<', "$znclog") or die "Could not read file 'znc.log' $!";
308 84c190b6 2021-12-17 jrmu chomp(@logs = <$fh>);
312 84c190b6 2021-12-17 jrmu # return all lines matching a pattern
313 84c190b6 2021-12-17 jrmu sub regex {
314 84c190b6 2021-12-17 jrmu my ($pattern) = @_;
315 84c190b6 2021-12-17 jrmu if (!@logs) { loadlog(); }
316 84c190b6 2021-12-17 jrmu return grep(/$pattern/, @logs);
319 84c190b6 2021-12-17 jrmu # given a list of IPs, return matching users
320 84c190b6 2021-12-17 jrmu # or given a list of users, return matching IPs
321 84c190b6 2021-12-17 jrmu sub regexlist {
322 84c190b6 2021-12-17 jrmu my ($items) = @_;
323 84c190b6 2021-12-17 jrmu my @items = split /[,\s]+/m, $items;
324 84c190b6 2021-12-17 jrmu my $pattern = "(".join('|', @items).")";
325 84c190b6 2021-12-17 jrmu if (!@logs) { loadlog(); }
326 84c190b6 2021-12-17 jrmu my @matches = grep(/$pattern/, @logs);
327 84c190b6 2021-12-17 jrmu my @results;
328 84c190b6 2021-12-17 jrmu foreach my $match (@matches) {
329 84c190b6 2021-12-17 jrmu if ($match =~ /^\[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\] \[([^]\/]+)(\/[^]]+)?\] connected to ZNC from (.*)/) {
330 84c190b6 2021-12-17 jrmu my ($user, $ip) = ($1, $3);
331 84c190b6 2021-12-17 jrmu if ($items =~ /[.:]/) { # items are IP addresses
332 84c190b6 2021-12-17 jrmu push(@results, $user);
333 84c190b6 2021-12-17 jrmu } else { # items are users
334 84c190b6 2021-12-17 jrmu push(@results, $ip);
338 84c190b6 2021-12-17 jrmu my @sorted = sort @results;
339 84c190b6 2021-12-17 jrmu @results = do { my %seen; grep { !$seen{$_}++ } @sorted }; # uniq
340 84c190b6 2021-12-17 jrmu return join(' ', @results);
343 84c190b6 2021-12-17 jrmu sub createclone {
344 84c190b6 2021-12-17 jrmu my ($bot) = @_;
345 84c190b6 2021-12-17 jrmu my $socket = $bot->{sock};
346 84c190b6 2021-12-17 jrmu my $password = Hash::newpass();
347 84c190b6 2021-12-17 jrmu my $msg = <<"EOF";
348 84c190b6 2021-12-17 jrmu adduser cloneuser $password
349 84c190b6 2021-12-17 jrmu set Nick cloneuser cloneuser
350 84c190b6 2021-12-17 jrmu set Altnick cloneuser cloneuser_
351 84c190b6 2021-12-17 jrmu set Ident cloneuser cloneuser
352 84c190b6 2021-12-17 jrmu set RealName cloneuser cloneuser
353 84c190b6 2021-12-17 jrmu set MaxNetworks cloneuser 1000
354 84c190b6 2021-12-17 jrmu set ChanBufferSize cloneuser 1000
355 84c190b6 2021-12-17 jrmu set MaxQueryBuffers cloneuser 1000
356 84c190b6 2021-12-17 jrmu set QueryBufferSize cloneuser 1000
357 84c190b6 2021-12-17 jrmu set NoTrafficTimeout cloneuser 600
358 84c190b6 2021-12-17 jrmu set QuitMsg cloneuser IRCNow and Forever!
359 84c190b6 2021-12-17 jrmu set RealName cloneuser cloneuser
360 84c190b6 2021-12-17 jrmu set DenySetBindHost cloneuser true
361 84c190b6 2021-12-17 jrmu set Timezone cloneuser US/Pacific
362 84c190b6 2021-12-17 jrmu LoadModule cloneuser controlpanel
363 84c190b6 2021-12-17 jrmu LoadModule cloneuser chansaver
365 84c190b6 2021-12-17 jrmu #LoadModule cloneuser buffextras
366 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG *controlpanel :$msg");
367 84c190b6 2021-12-17 jrmu foreach my $n (@main::networks) {
368 84c190b6 2021-12-17 jrmu my $net = $n->{name};
369 84c190b6 2021-12-17 jrmu my $server = $n->{server};
370 84c190b6 2021-12-17 jrmu my $port = $n->{port};
371 84c190b6 2021-12-17 jrmu my $trustcerts = $n->{trustcerts};
372 84c190b6 2021-12-17 jrmu $msg = <<"EOF";
373 84c190b6 2021-12-17 jrmu addnetwork cloneuser $net
374 84c190b6 2021-12-17 jrmu addserver cloneuser $net $server $port
375 84c190b6 2021-12-17 jrmu disconnect cloneuser $net
377 84c190b6 2021-12-17 jrmu if ($trustcerts) {
378 84c190b6 2021-12-17 jrmu $msg .= "SetNetwork TrustAllCerts cloneuser $net True\r\n";
380 84c190b6 2021-12-17 jrmu my @chans = split /[,\s]+/m, $chans;
381 84c190b6 2021-12-17 jrmu foreach my $chan (@chans) {
382 84c190b6 2021-12-17 jrmu $msg .= "addchan cloneuser $net $chan\r\n";
384 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG *controlpanel :$msg");
388 84c190b6 2021-12-17 jrmu sub createbnc {
389 84c190b6 2021-12-17 jrmu my ($bot, $username, $password, $bindhost) = @_;
390 84c190b6 2021-12-17 jrmu my $netname = $bot->{name};
391 84c190b6 2021-12-17 jrmu my $msg = <<"EOF";
392 84c190b6 2021-12-17 jrmu cloneuser cloneuser $username
393 84c190b6 2021-12-17 jrmu set Nick $username $username
394 84c190b6 2021-12-17 jrmu set Altnick $username ${username}_
395 84c190b6 2021-12-17 jrmu set Ident $username $username
396 84c190b6 2021-12-17 jrmu set RealName $username $username
397 84c190b6 2021-12-17 jrmu set Password $username $password
398 84c190b6 2021-12-17 jrmu set MaxNetworks $username 1000
399 84c190b6 2021-12-17 jrmu set ChanBufferSize $username 1000
400 84c190b6 2021-12-17 jrmu set MaxQueryBuffers $username 1000
401 84c190b6 2021-12-17 jrmu set QueryBufferSize $username 1000
402 84c190b6 2021-12-17 jrmu set NoTrafficTimeout $username 600
403 84c190b6 2021-12-17 jrmu set QuitMsg $username IRCNow and Forever!
404 84c190b6 2021-12-17 jrmu set BindHost $username $bindhost
405 84c190b6 2021-12-17 jrmu set DCCBindHost $username $bindhost
406 84c190b6 2021-12-17 jrmu set DenySetBindHost $username true
407 84c190b6 2021-12-17 jrmu reconnect $username $netname
409 84c190b6 2021-12-17 jrmu #set Language $username en-US
410 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG *controlpanel :$msg");
413 84c190b6 2021-12-17 jrmu sub mailbnc {
414 84c190b6 2021-12-17 jrmu my( $username, $email, $password, $service, $hashirc )=@_;
415 84c190b6 2021-12-17 jrmu my $passhash = sha256_hex("$username");
417 84c190b6 2021-12-17 jrmu my $body = <<"EOF";
418 84c190b6 2021-12-17 jrmu You created a bouncer!
420 84c190b6 2021-12-17 jrmu Username: $username
421 84c190b6 2021-12-17 jrmu Password: $password
422 84c190b6 2021-12-17 jrmu Server: $hostname
423 84c190b6 2021-12-17 jrmu Port: $sslport for SSL (secure connection)
424 84c190b6 2021-12-17 jrmu Port: $plainport for plaintext
426 84c190b6 2021-12-17 jrmu *IMPORTANT*: Verify your email address:
428 84c190b6 2021-12-17 jrmu https://$hostname/register.php?hashirc=$hashirc
430 84c190b6 2021-12-17 jrmu You *MUST* click on the link or your account will be deleted.
434 84c190b6 2021-12-17 jrmu Mail::mail($mailfrom, $email, $mailname, "Verify IRCNow Account", $body);
437 84c190b6 2021-12-17 jrmu sub mtaillog {
438 84c190b6 2021-12-17 jrmu my ($bot, $nick, $host, $hand, @args) = @_;
439 84c190b6 2021-12-17 jrmu my ($chan, $text);
440 84c190b6 2021-12-17 jrmu if (@args == 2) {
441 84c190b6 2021-12-17 jrmu ($chan, $text) = ($args[0], $args[1]);
442 84c190b6 2021-12-17 jrmu } else { $text = $args[0]; }
443 84c190b6 2021-12-17 jrmu my $hostmask = "$nick!$host";
444 84c190b6 2021-12-17 jrmu open(my $fh, "-|", "/usr/bin/tail", "-f", $znclog) or die "could not start tail: $!";
445 84c190b6 2021-12-17 jrmu while (my $line = <$fh>) {
446 84c190b6 2021-12-17 jrmu foreach my $chan (@teamchans) {
447 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $chan :$line");
452 84c190b6 2021-12-17 jrmu sub mlastseen {
453 84c190b6 2021-12-17 jrmu my ($bot, $nick, $host, $hand, @args) = @_;
454 84c190b6 2021-12-17 jrmu my ($chan, $text);
455 84c190b6 2021-12-17 jrmu if (@args == 2) {
456 84c190b6 2021-12-17 jrmu ($chan, $text) = ($args[0], $args[1]);
457 84c190b6 2021-12-17 jrmu } else { $text = $args[0]; }
458 84c190b6 2021-12-17 jrmu my $hostmask = "$nick!$host";
459 84c190b6 2021-12-17 jrmu if (!@logs) { loadlog(); }
460 84c190b6 2021-12-17 jrmu my @users = treeget($znctree, "User", "Node");
461 84c190b6 2021-12-17 jrmu foreach my $user (@users) {
462 84c190b6 2021-12-17 jrmu my @lines = grep(/^\[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\] \[$user\] connected to ZNC from [.0-9a-fA-F:]+/, @logs);
463 84c190b6 2021-12-17 jrmu if (scalar(@lines) == 0) {
464 84c190b6 2021-12-17 jrmu foreach my $chan (@teamchans) {
465 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $chan :$user never logged in");
469 84c190b6 2021-12-17 jrmu my $recent = pop(@lines);
470 84c190b6 2021-12-17 jrmu if ($recent =~ /^\[(\d{4}-\d\d-\d\d) \d\d:\d\d:\d\d\] \[$user\] connected to ZNC from [.0-9a-fA-F:]+/) {
471 84c190b6 2021-12-17 jrmu my $date = $1;
472 84c190b6 2021-12-17 jrmu foreach my $chan (@teamchans) {
473 84c190b6 2021-12-17 jrmu main::putserv($bot, "PRIVMSG $chan :$user $date");
478 84c190b6 2021-12-17 jrmu #sub resend {
479 84c190b6 2021-12-17 jrmu # my ($bot, $newnick, $email) = @_;
480 84c190b6 2021-12-17 jrmu # my $password = newpass();
481 84c190b6 2021-12-17 jrmu # sendmsg($bot, "*controlpanel", "set Password $newnick $password");
482 84c190b6 2021-12-17 jrmu # mailverify($newnick, $email, $password, "bouncer");
483 84c190b6 2021-12-17 jrmu # sendmsg($bot, "$newnick", "Email sent");
486 84c190b6 2021-12-17 jrmu # if ($reply =~ /^!resend ([-_0-9a-zA-Z]+) ([-_0-9a-zA-Z]+@[-_0-9a-zA-Z]+\.[-_0-9a-zA-Z]+)$/i) {
487 84c190b6 2021-12-17 jrmu # my ($newnick, $email) = ($1, $2);
488 84c190b6 2021-12-17 jrmu # my $password = newpass();
489 84c190b6 2021-12-17 jrmu # resend($bot, $newnick, $email);
492 84c190b6 2021-12-17 jrmu #sub resetznc {
494 84c190b6 2021-12-17 jrmu #AnonIPLimit 10000
495 84c190b6 2021-12-17 jrmu #AuthOnlyViaModule false
496 84c190b6 2021-12-17 jrmu #ConnectDelay 0
497 84c190b6 2021-12-17 jrmu #HideVersion true
498 84c190b6 2021-12-17 jrmu #LoadModule
499 84c190b6 2021-12-17 jrmu #ServerThrottle
500 84c190b6 2021-12-17 jrmu #1337 209.141.38.137
501 84c190b6 2021-12-17 jrmu #31337 209.141.38.137
502 84c190b6 2021-12-17 jrmu #1337 2605:6400:20:5cc::
503 84c190b6 2021-12-17 jrmu #31337 2605:6400:20:5cc::
504 84c190b6 2021-12-17 jrmu #1337 127.0.0.1
505 84c190b6 2021-12-17 jrmu #1338 127.0.0.1
508 84c190b6 2021-12-17 jrmu #alias Provides bouncer-side command alias support.
509 84c190b6 2021-12-17 jrmu #autoreply Reply to queries when you are away
510 84c190b6 2021-12-17 jrmu #block_motd Block the MOTD from IRC so it's not sent to your client(s).
511 84c190b6 2021-12-17 jrmu #bouncedcc Bounces DCC transfers through ZNC instead of sending them directly to the user.
512 84c190b6 2021-12-17 jrmu #clientnotify Notifies you when another IRC client logs into or out of your account. Configurable.
513 84c190b6 2021-12-17 jrmu #ctcpflood Don't forward CTCP floods to clients
514 84c190b6 2021-12-17 jrmu #dcc This module allows you to transfer files to and from ZNC
515 84c190b6 2021-12-17 jrmu #perform Keeps a list of commands to be executed when ZNC connects to IRC.
516 84c190b6 2021-12-17 jrmu #webadmin Web based administration module.
519 84c190b6 2021-12-17 jrmu 1; # MUST BE LAST STATEMENT IN FILE