Commit Diff
Diff:
5f6bf6e34fb7bae1f58e6fc28b662bc417b505b6
302b7e40ac6e03c59e1f6d061031a1221c0e39a0
Commit:
302b7e40ac6e03c59e1f6d061031a1221c0e39a0
Tree:
4cc9170d1200136eaf68aecf8f7aebdb12788999
Author:
jrmu <jrmu@ircnow.org>
Committer:
jrmu <jrmu@ircnow.org>
Date:
Sun Oct 11 12:43:37 2020 UTC
Message:
Refactored code to be modular
blob - /dev/null
blob + b89d29c80f39e12b5d224458a65349a3820e29b2 (mode 644)
--- /dev/null
+++ BNC.pm
@@ -0,0 +1,405 @@
+#!/usr/bin/perl
+
+package BNC;
+
+use strict;
+use warnings;
+use OpenBSD::Pledge;
+use OpenBSD::Unveil;
+use Data::Dumper;
+use MIME::Base64;
+use lib './';
+use SQLite;
+
+my $chans;
+my $teamchans;
+my @teamchans;
+my $staff;
+my $zncdir;
+my $znclog;
+my $captchaURL = "https://guava.ircnow.org/captcha.php?vhost=";
+my $hostname;
+my $terms;
+my @logs;
+
+sub init {
+ $chans = $main::conf{chans};
+ $teamchans = $main::conf{teamchans};
+ @teamchans = split /[,\s]+/m, $teamchans;
+ $staff = $main::conf{staff};
+ $zncdir = $main::conf{zncdir};
+ $znclog = $main::conf{znclog} || "$zncdir/.znc/moddata/adminlog/znc.log";
+ $hostname = $main::conf{hostname};
+ $terms = $main::conf{terms} || "IRCNow is a Christian network. Rules: no profanity, no porn, no illegal drugs, no gambling, no slander, no warez, no promoting violence, no spam, illegal cracking, or DDoS. Only one account per person. Don't share passwords. Religious or political content may be moderated. Full terms: https://ircnow.org/terms.php";
+ #dependencies for figlet
+ unveil("/usr/local/bin/figlet", "rx") or die "Unable to unveil $!";
+ unveil("/usr/lib/libc.so.95.1", "r") or die "Unable to unveil $!";
+ unveil("/usr/libexec/ld.so", "r") or die "Unable to unveil $!";
+ #znc.log file
+ unveil("$znclog", "r") or die "Unable to unveil $!";
+ main::cbind("pub", "-", "help", \&help);
+ main::cbind("msg", "-", "help", \&help);
+ main::cbind("pub", "-", "request", \&help);
+ main::cbind("pub", "-", "bnc", \&mbnc);
+ main::cbind("msg", "-", "bnc", \&mbnc);
+ main::cbind("msg", "-", "delete", \&mdelete);
+ main::cbind("msg", "-", "captcha", \&mcaptcha);
+ main::cbind("msg", "-", "regex", \&mregex);
+ main::cbind("msg", "-", "foreach", \&mforeach);
+}
+
+sub help {
+ my ($bot, $nick, $host, $hand, @args) = @_;
+ my ($chan, $text);
+ my $msg = <<"EOF";
+$terms
+To request a free bouncer, type !bnc <username> <email>. For example, !bnc john john\@example.com.
+To reset the password, type !set password <password>.
+To change email, type !set email <email>.
+EOF
+ if (@args == 2) {
+ ($chan, $text) = ($args[0], $args[1]);
+ if ($chans =~ $chan) {
+ main::putserv($bot, "PRIVMSG $chan :$nick: Please see private message.");
+ }
+ } else {
+ $text = $args[0];
+ }
+ main::putserv($bot, "PRIVMSG $nick :$msg");
+ foreach my $chan (@teamchans) {
+ main::putserv($bot, "PRIVMSG $chan :Help *$nick* on ".$bot->{name});
+ }
+}
+sub mcaptcha {
+ my ($bot, $nick, $host, $hand, @args) = @_;
+ my ($chan, $text);
+ if (@args == 2) {
+ ($chan, $text) = ($args[0], $args[1]);
+ } else { $text = $args[0]; }
+ my $hostmask = "$nick!$host";
+ my $captcha = SQLite::userget($hostmask, "captcha");
+ if ($text =~ /^$captcha$/i) {
+ my $pass = main::newpass();
+ chomp(my $encrypted = `encrypt $pass`);
+ my $username = SQLite::userget($hostmask, "username");
+ my $email = SQLite::userget($hostmask, "email");
+ my $version = SQLite::userget($hostmask, "version");
+ my $bindhost = "$username.$hostname";
+ SQLite::userset($hostmask, "password", $encrypted);
+ if (DNS::nextdns($username)) {
+ sleep(2);
+ createbnc($bot, $username, $pass, $bindhost);
+ main::putserv($bot, "PRIVMSG $nick :Check your email!");
+ Mail::mailverify($username, $email, $pass, "bouncer", $version);
+ SQLite::userset($hostmask, "date", main::date());
+ #www($newnick, $reply, $password, "bouncer");
+ } else {
+ foreach my $chan (@teamchans) {
+ main::putserv($bot, "PRIVMSG $chan :Assigning bindhost $bindhost failed");
+ }
+ }
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :Wrong captcha. To get a new captcha, type !bnc <username> <email>");
+ }
+}
+
+sub mbnc {
+ my ($bot, $nick, $host, $hand, @args) = @_;
+ my ($chan, $text);
+ if (@args == 2) {
+ ($chan, $text) = ($args[0], $args[1]);
+ } else { $text = $args[0]; }
+ my $hostmask = "$nick!$host";
+ if (defined($chan) && $chans =~ /$chan/) {
+ main::putserv($bot, "PRIVMSG $chan :$nick: Please check private message");
+ }
+ if (defined(SQLite::userget($hostmask, "date"))) {
+ main::putserv($bot, "PRIVMSG $nick :Sorry, only one account per person. Please contact staff if you need help.");
+ ### TODO: Check duplicate emails ###
+ } elsif ($text =~ /^$/) {
+ main::putserv($bot, "PRIVMSG $nick :Type !help for new instructions");
+ foreach my $chan (@teamchans) {
+ main::putserv($bot, "PRIVMSG $chan :Help *$nick* on ".$bot->{name});
+ }
+ } elsif ($text =~ /^([[:alnum:]]+)\s+([[:ascii:]]+)/) {
+ my ($username, $email) = ($1, $2);
+ my $captcha = join'', map +(0..9,'a'..'z','A'..'Z')[rand(10+26*2)], 1..4;
+ SQLite::userset($hostmask, "oldnick", $nick);
+ SQLite::userset($hostmask, "username", $username);
+ SQLite::userset($hostmask, "realname", $username);
+ SQLite::userset($hostmask, "email", $email);
+ SQLite::userset($hostmask, "captcha", $captcha);
+ main::whois($bot->{sock}, $nick);
+ main::putserv($bot, "PRIVMSG $nick :".`figlet $captcha`);
+ main::putserv($bot, "PRIVMSG $nick :$captchaURL".encode_base64($captcha));
+ main::putserv($bot, "PRIVMSG $nick :Type !captcha <text>");
+ foreach my $chan (@teamchans) {
+ main::putserv($bot, "PRIVMSG $chan :$nick\'s captcha is $captcha");
+ }
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :Invalid username or email. Type !bnc <username> <email> to try again.");
+ foreach my $chan (@teamchans) {
+ main::putserv($bot, "PRIVMSG $chan :Help *$nick* on ".$bot->{name});
+ }
+ }
+}
+
+sub mregex {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($staff !~ /$nick/) { return; }
+ if ($text =~ /^ips?\s+([-_()|0-9A-Za-z:\.?*\s]{3,})$/) {
+ my $ips = $1; # space-separated list of IPs
+ main::putserv($bot, "PRIVMSG $nick :".regexlist($ips));
+ } elsif ($text =~ /^users?\s+([-_()|0-9A-Za-z:\.?*\s]{3,})$/) {
+ my $users = $1; # space-separated list of usernames
+ main::putserv($bot, "PRIVMSG $nick :".regexlist($users));
+ } elsif ($text =~ /^[-_()|0-9A-Za-z:,\.?*\s]{3,}$/) {
+ my @lines = regex($text);
+ foreach my $l (@lines) { print "$l\n"; }
+ }
+}
+sub mforeach {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($main::conf{staff} !~ /$nick/) { return; }
+ if ($text =~ /^network\s+del\s+([[:graph:]]+)\s+(#[[:graph:]]+)$/) {
+ my ($user, $chan) = ($1, $2);
+ foreach my $n (@main::networks) {
+ main::putserv($bot, "PRIVMSG *controlpanel :delchan $user $n->{name} $chan");
+ }
+ }
+}
+sub mdelete {
+ my ($bot, $nick, $host, $hand, @args) = @_;
+ my ($chan, $text);
+ if (@args == 2) {
+ $chan = $args[0];
+ $text = $args[1];
+ } else {
+ $text = $args[0];
+ }
+ if ($main::conf{staff} !~ /$nick/) { return; }
+ if (SQLite::userdel($text)) {
+ main::putserv($bot, "PRIVMSG *controlpanel :deluser $text");
+ foreach my $chan (@teamchans) {
+ main::putserv($bot, "PRIVMSG $chan :$text deleted");
+ }
+ }
+}
+
+sub loadlog {
+ open(my $fh, '<', "$znclog") or die "Could not read file 'znc.log' $!";
+ chomp(@logs = <$fh>);
+ close $fh;
+}
+
+# return all lines matching a pattern
+sub regex {
+ my ($pattern) = @_;
+ if (!@logs) { loadlog(); }
+ return grep(/$pattern/, @logs);
+}
+
+# given a list of IPs, return matching users
+# or given a list of users, return matching IPs
+sub regexlist {
+ my ($items) = @_;
+ my @items = split /[,\s]+/m, $items;
+ my $pattern = "(".join('|', @items).")";
+ if (!@logs) { loadlog(); }
+ my @matches = grep(/$pattern/, @logs);
+ my @results;
+ foreach my $match (@matches) {
+ if ($match =~ /^\[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\] \[([^]\/]+)(\/[^]]+)?\] connected to ZNC from (.*)/) {
+ my ($user, $ip) = ($1, $3);
+ if ($items =~ /[.:]/) { # items are IP addresses
+ push(@results, $user);
+ } else { # items are users
+ push(@results, $ip);
+ }
+ }
+ }
+ my @sorted = sort @results;
+ @results = do { my %seen; grep { !$seen{$_}++ } @sorted }; # uniq
+ return join(' ', @results);
+}
+
+sub createclone {
+ my ($bot) = @_;
+ my $socket = $bot->{sock};
+ my $password = main::newpass();
+ my $msg = <<"EOF";
+adduser cloneuser $password
+set Nick cloneuser cloneuser
+set Altnick cloneuser cloneuser_
+set Ident cloneuser cloneuser
+set RealName cloneuser cloneuser
+set MaxNetworks cloneuser 1000
+set ChanBufferSize cloneuser 1000
+set MaxQueryBuffers cloneuser 1000
+set QueryBufferSize cloneuser 1000
+set NoTrafficTimeout cloneuser 600
+set QuitMsg cloneuser IRCNow and Forever!
+set RealName cloneuser cloneuser
+set DenySetBindHost cloneuser true
+set Timezone cloneuser US/Pacific
+LoadModule cloneuser controlpanel
+LoadModule cloneuser chansaver
+EOF
+#LoadModule cloneuser buffextras
+ main::putserv($bot, "PRIVMSG *controlpanel :$msg");
+ foreach my $n (@main::networks) {
+ my $net = $n->{name};
+ my $server = $n->{server};
+ my $port = $n->{port};
+ my $trustcerts = $n->{trustcerts};
+ $msg = <<"EOF";
+addnetwork cloneuser $net
+addserver cloneuser $net $server $port
+disconnect cloneuser $net
+EOF
+ if ($trustcerts) {
+ $msg .= "SetNetwork TrustAllCerts cloneuser $net True\r\n";
+ }
+ my @chans = split /[,\s]+/m, $chans;
+ foreach my $chan (@chans) {
+ $msg .= "addchan cloneuser $net $chan\r\n";
+ }
+ main::putserv($bot, "PRIVMSG *controlpanel :$msg");
+ }
+}
+
+sub createbnc {
+ my ($bot, $username, $password, $bindhost) = @_;
+ my $netname = $bot->{name};
+ my $msg = <<"EOF";
+cloneuser cloneuser $username
+set Nick $username $username
+set Altnick $username ${username}_
+set Ident $username $username
+set RealName $username $username
+set Password $username $password
+set MaxNetworks $username 1000
+set ChanBufferSize $username 1000
+set MaxQueryBuffers $username 1000
+set QueryBufferSize $username 1000
+set NoTrafficTimeout $username 600
+set QuitMsg $username IRCNow and Forever!
+set BindHost $username $bindhost
+set DCCBindHost $username $bindhost
+set DenySetBindHost $username true
+reconnect $username $netname
+EOF
+#set Language $username en-US
+ main::putserv($bot, "PRIVMSG *controlpanel :$msg");
+ return 1;
+}
+#if ($hostmask eq '*status!znc@znc.in' && $target =~ /^$nick.?$/) {
+# if ($reply eq "You are currently disconnected from IRC. Use 'connect' to reconnect.") {
+# if ($verbose >= 3) { print "not connected to $bot->{name}\n"; }
+# return;
+# } elsif ($reply =~ /Unable to load module (.*): Module (.*) already loaded./) {
+# if ($verbose >= 3) { print "Module $1 already loaded\n"; }
+# return;
+# } else {
+# print "Unexpected: $hostmask $target $reply\r\n";
+# }
+#} elsif($hostmask eq '*controlpanel!znc@znc.in') {
+# if ($reply =~ /^Error: User \[cloneuser\] does not exist/) {
+# createclone($bot);
+# sendteam($sender, "Cloneuser created!");
+# } elsif($reply =~ /^Nick = ([a-zA-Z][-_a-zA-Z0-9]+)$/) {
+## only one requestnick
+# my $requestnick = $1;
+# my $hostmask = firstval("requestnick", $requestnick);
+# if (!defined($hostmask)) { return; }
+# delkey($hostmask, "requestnick");
+# sendmsg($bot, nickfromhost($hostmask), "Username already taken. New username:");
+# } elsif($reply =~ /^Error: User \[(.*)\] does not exist/) {
+## delete requestnick after granted
+# my $newnick = $1;
+# my $hostmask = firstval("requestnick", $newnick);
+# if (!defined($hostmask)) { return; }
+# setkeyval($hostmask, "newnick", $newnick);
+# delkey($hostmask, "requestnick");
+# sendmsg($bot, nickfromhost($hostmask), "Email:");
+# } elsif ($reply =~ /^User (.*) added!$/) {
+# print "User $1 created!\r\n";
+# } elsif ($reply =~ /^Password has been changed!$/) {
+# print "Password changed\r\n";
+# } elsif ($reply =~ /^Queued network (.*) of user (.*) for a reconnect.$/) {
+# print "$2 now connecting to $1...\r\n";
+# } elsif ($reply =~ /^Admin = false/) {
+# sendteam("", "ERROR: $nick is not admin");
+# die "ERROR: $nick is not admin";
+# } elsif ($reply =~ /^Admin = true/) {
+# if ($verbose >= 3) { print "$nick is ZNC admin\n"; }
+# } elsif ($reply =~ /(.*) = (.*)/) {
+# my ($key, $val) = ($1, $2);
+# if ($verbose >= 3) { print "$key = $val\r\n"; }
+# } else {
+#print "Unexpected: $hostmask $target $reply\r\n";
+#}
+# if ($chans =~ $target) {
+# sendmsg($bot, $target, "$sender: Please check private message");
+# }
+# sendmsg($bot, $sender, $terms);
+# sendteam($bot->{name}, "Help *$sender* on ".$bot->{name});
+# }
+# } elsif(!defined(getkeyval($hostmask, "newnick"))) {
+# if ($reply =~ /^([a-zA-Z][-a-zA-Z0-9]+)/) {
+# setkeyval($hostmask, "requestnick", $reply);
+# sendmsg($bot, "*controlpanel", "get Nick $reply");
+# www($newnick, $reply, $password, "bouncer");
+ # } elsif ($reply =~ /^!rehash$/i) {
+ # if ($main::conf{staff} !~ /$sender/) {
+ # return;
+ # }
+ # print $socket "PRIVMSG *controlpanel :deluser cloneuser\r\n";
+ # sleep 5;
+ # print $socket "PRIVMSG *controlpanel :get Nick cloneuser\r\n";
+
+#sub resend {
+# my ($bot, $newnick, $email) = @_;
+# my $password = newpass();
+# sendmsg($bot, "*controlpanel", "set Password $newnick $password");
+# mailverify($newnick, $email, $password, "bouncer");
+# sendmsg($bot, "$newnick", "Email sent");
+#}
+
+# if ($reply =~ /^!resend ([-_0-9a-zA-Z]+) ([-_0-9a-zA-Z]+@[-_0-9a-zA-Z]+\.[-_0-9a-zA-Z]+)$/i) {
+# my ($newnick, $email) = ($1, $2);
+# my $password = newpass();
+# resend($bot, $newnick, $email);
+# }
+
+
+
+#sub resetznc {
+#
+#AnonIPLimit 10000
+#AuthOnlyViaModule false
+#ConnectDelay 0
+#HideVersion true
+#LoadModule
+#ServerThrottle
+#1337 209.141.38.137
+#31337 209.141.38.137
+#1337 2605:6400:20:5cc::
+#31337 2605:6400:20:5cc::
+#1337 127.0.0.1
+#1338 127.0.0.1
+#}
+#
+#alias Provides bouncer-side command alias support.
+#autoreply Reply to queries when you are away
+#block_motd Block the MOTD from IRC so it's not sent to your client(s).
+#bouncedcc Bounces DCC transfers through ZNC instead of sending them directly to the user.
+#clientnotify Notifies you when another IRC client logs into or out of your account. Configurable.
+#ctcpflood Don't forward CTCP floods to clients
+#dcc This module allows you to transfer files to and from ZNC
+#perform Keeps a list of commands to be executed when ZNC connects to IRC.
+#webadmin Web based administration module.
+
+
+#main::putserv($bot, "PRIVMSG $teamchan :nick: $nick, host: $host, hand: $hand, chan: $chan, text: $text");
+1; # MUST BE LAST STATEMENT IN FILE
blob - 9691f8fff3868e2fc8cd602fe98809f2bf119a07
blob + f3719a4f4c4bdff09ade56ae521a742e9893e7be
--- README
+++ README
@@ -50,6 +50,7 @@ $ doas make -i
### Changelog ###
+Version 0.06: Refactored code to be modular
Version 0.05: Refactored conf file out of the script and supplied sensible defaults
Version 0.04: Switched from flatfiles to sqlite for user metadata
Version 0.03: Added new DNS commands
blob - /dev/null
blob + 695e6108e0ec9152e0ba991b667f553a8f5cec7e (mode 644)
--- /dev/null
+++ DNS.pm
@@ -0,0 +1,219 @@
+#!/usr/bin/perl
+
+package DNS;
+
+use strict;
+use warnings;
+use OpenBSD::Pledge;
+use OpenBSD::Unveil;
+use File::Copy qw(copy);
+
+my $staff;
+my $chans;
+my $key;
+my $hash;
+my $zonedir = '/var/nsd/zones/master/';
+my $hostname;
+my $verbose;
+my $ipv4;
+my @ipv6s;
+my $ipv6path;
+my $hostnameif;
+
+sub init {
+ $chans = $main::conf{chans};
+ $staff = $main::conf{staff};
+ $key = $main::conf{key};
+ $hash = $main::conf{hash};
+ $hostname = $main::conf{hostname};
+ $verbose = $main::conf{verbose};
+ $ipv4 = $main::conf{ipv4};
+ $ipv6path = "ipv6s";
+ $hostnameif = $main::conf{hostnameif};
+ unveil("$ipv6path", "rwc") or die "Unable to unveil $!";
+ unveil("$zonedir", "rwc") or die "Unable to unveil $!";
+ #dependencies for doas
+ unveil("/usr/bin/doas", "rx") or die "Unable to unveil $!";
+ #dependencies for host
+ unveil("/usr/bin/host", "rx") or die "Unable to unveil $!";
+ main::cbind("msg", "-", "setrdns", \&msetrdns);
+ main::cbind("msg", "-", "delrdns", \&mdelrdns);
+ main::cbind("msg", "-", "setdns", \&msetdns);
+ main::cbind("msg", "-", "deldns", \&mdeldns);
+ main::cbind("msg", "-", "host", \&mhost);
+ main::cbind("msg", "-", "nextdns", \&mnextdns);
+ # Validate ipv6s if it exists, otherwise load addresses from /etc/hostname.if
+ if (!(-s "$ipv6path")) {
+ print "No IPv6 addresses in $ipv6path, loading from $hostnameif...\n";
+ @ipv6s = readipv6s($hostnameif);
+ } else {
+ @ipv6s = readipv6s($ipv6path);
+ }
+ if (!@ipv6s) { die "No IPv6 addresses in $ipv6path or $hostnameif!"; }
+ if (host($hostname) =~ /(\d+\.){3,}\d+/) {
+ $ipv4 = $&;
+ }
+}
+
+sub msetrdns {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($staff !~ /$nick/) { return; }
+ if ($text =~ /^([0-9A-Fa-f:\.]{3,})\s+([-0-9A-Za-z\.]+)/) {
+ my ($ip, $hostname) = ($1, $2);
+ if (setrdns($ip, $hostname)) {
+ main::putserv($bot, "PRIVMSG $nick :$hostname set to $ip");
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :ERROR: failed to set rDNS");
+ }
+ }
+}
+sub mdelrdns {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($staff !~ /$nick/) { return; }
+ if ($text =~ /^([0-9A-Fa-f:\.]{3,})$/) {
+ my $ip = $1;
+ my $hostname = "notset";
+ if (setrdns($ip, $hostname)) {
+ main::putserv($bot, "PRIVMSG $nick :$ip rDNS deleted");
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :ERROR: failed to set rDNS");
+ }
+ }
+}
+sub msetdns {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($staff !~ /$nick/) { return; }
+ if ($text =~ /^([-0-9A-Za-z\.]+)\s+([0-9A-Fa-f:\.]+)/) {
+ my ($hostname, $ip) = ($1, $2);
+ if (setdns($hostname, $ip)) {
+ main::putserv($bot, "PRIVMSG $nick :$hostname set to $ip");
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :ERROR: failed to set DNS");
+ }
+ }
+}
+sub mdeldns {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($staff !~ /$nick/) { return; }
+ if ($text =~ /^([-0-9A-Za-z\.]+)/) {
+ if (setdns($text)) {
+ main::putserv($bot, "PRIVMSG $nick :$text deleted");
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :ERROR: failed to delete DNS records");
+ }
+ }
+}
+sub mhost {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($staff !~ /$nick/) { return; }
+ if ($text =~ /^([-0-9A-Za-z:\.]{3,})/) {
+ my ($hostname, $version) = ($1, $2);
+ main::putserv($bot, "PRIVMSG $nick :".host($hostname));
+ }
+}
+
+sub mnextdns {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($staff !~ /$nick/) { return; }
+ if ($text =~ /^([-0-9a-zA-Z]+)/) {
+ main::putserv($bot, "PRIVMSG $nick :$text set to ".nextdns($text));
+ }
+}
+
+# Given filename, return a list of ipv6 addresses
+sub readipv6s {
+ my ($filename) = @_;
+ my @lines = main::readarray($filename);
+ my @ipv6s;
+ foreach my $line (@lines) {
+ if ($line =~ /^\s*inet6 (alias )?([0-9a-f:]{4,}) [0-9]+\s*$/i) {
+ push(@ipv6s, $2);
+ } elsif ($line =~ /^\s*([0-9a-f:]{4,})\s*$/i) {
+ push(@ipv6s, $1);
+ }
+ }
+ return @ipv6s;
+}
+
+# returns true upon success, false upon failure
+sub setrdns {
+ my ($ip, $hostname) = @_;
+ my $stdout = `curl -d \"key=$key&hash=$hash&action=rdns&ip=$ip&rdns=$hostname\" https://manage.buyvm.net/api/client/command.php`;
+ if ($stdout !~ /success/) {
+ return 0;
+ }
+ return 1;
+}
+# set $domain to $ip if provided; otherwise, delete $domain
+# returns true upon success, false upon failure
+sub setdns {
+ my ($domain, $ip) = @_;
+ my $filename = "$zonedir/$hostname";
+ my $subdomain;
+ if ($domain =~ /^([a-zA-Z][-\.a-zA-Z0-9]+)\.$hostname$/) {
+ $subdomain = $1;
+ } else {
+ return 0;
+ }
+ my @lines = main::readarray($filename);
+ foreach my $line (@lines) {
+ # increment the zone's serial number
+ if ($line =~ /(\d{8})(\d{2})((\s+\d+){4}\s*\))/) {
+ my $date = main::date();
+ my $serial = 0;
+ if ($date <= $1) { $serial = $2+1; }
+ $line = $`.$date.sprintf("%02d",$serial).$3.$';
+ }
+ }
+ if ($ip =~ /^([0-9\.]+)$/) { # if IPv4
+ push(@lines, "$subdomain 3600 IN A $ip");
+ } elsif ($ip =~ /:/) { # if IPv6
+ push(@lines, "$subdomain 3600 IN AAAA $ip");
+ } elsif (!defined($ip)) { # delete records
+ @lines = grep !/\b$subdomain\s*3600\s*IN/, @lines;
+ }
+ # trailing newline necessary
+ main::writefile("$filename.bak", join("\n", @lines)."\n");
+ copy "$filename.bak", $filename;
+ if (system("doas -u _nsd nsd-control reload")) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+# given hostname, return IP addresses; or given IP address, return hostname
+sub host {
+ my ($name) = @_;
+ my @matches;
+ my @lines = split /\n/m, `host $name`;
+ if ($name =~ /^[0-9\.]+$/ or $name =~ /:/) { # IP address
+ foreach my $line (@lines) {
+ if ($line =~ /([\d\.]+).(in-addr|ip6).arpa domain name pointer (.*)/) {
+ push(@matches, $3);
+ }
+ }
+ } else { # hostname
+ foreach my $line (@lines) {
+ if ($line =~ /$name has (IPv6 )?address ([0-9a-fA-F\.:]+)/) {
+ push(@matches, $2);
+ }
+ }
+ }
+ return join(' ', @matches);
+}
+
+# create A and AAAA records for subdomain, set the rDNS,
+# and return the new ipv6 address
+sub nextdns {
+ my ($subdomain) = @_;
+ my $ipv6 = shift(@ipv6s);
+ my $fqdn = "$subdomain.$hostname";
+ main::writefile($main::ipv6path, join("\n", @ipv6s));
+ if (setdns($fqdn, $ipv4) && setdns($fqdn, $ipv6) && setrdns($ipv6, $fqdn)) {
+ return "$ipv6";
+ }
+ return "false";
+}
+
+1; # MUST BE LAST STATEMENT IN FILE
blob - 46aaeb27daabec467458141cee65c66fac477bdb
blob + 79c3525909504abecf65b117c26098c3d0177a2f
--- botnow.conf
+++ botnow.conf
@@ -1,30 +1,30 @@
# For all options, see botnow.conf.full
# Name of local network; default ircnow
-# localnet = ircnow
+#localnet = ircnow
# Internal IPv4 address and plaintext port; default 127.0.0.1@1337
-# host = 127.0.0.1
-# port = 1337
+#host = 127.0.0.1
+#port = 1337
# Bouncer hostname; default uses return of `hostname`
-# hostname = example.ircnow.org
+#hostname = example.ircnow.org
# External IPv4 address, plaintext and ssl port
-# ip4 = 192.168.0.1
-# plainport = 1337
-# sslport = 31337
+#ip4 = 192.168.0.1
+#plainport = 1337
+#sslport = 31337
# Nick and password of bot -- make sure to add to oper block
nick = botnow
pass = password
-# Comma-separated list of channels for requesting bouncers
-# chans = #ircnow,#testing
+# List of channels for requesting bouncers
+chans = #ircnow #testing
-# Comma-separated list of staff nicks; comment out to avoid highlights
-staff = jrmu,test
+# List of staff nicks; comment out to avoid highlights
+staff = jrmu test
-# Comma-separated list of team channels on localnet; comment out to disable
+# List of team channels on localnet; comment out to disable
teamchans = #ircnow-team
# Mail from address
@@ -35,7 +35,7 @@ key = ABCDE-FGHIJ-KLMNO
hash = ABCDEFGHIJKLMNOPQRST
# ZNC install directory
-# zncdir = /home/znc/home/znc/
+#zncdir = /home/znc/home/znc/
# Comment out the line below
die = You did not configure botnow.conf!
blob - /dev/null
blob + 6cfdf34c056fb604d0fd5e688277553ac3511ac3 (mode 644)
--- /dev/null
+++ Login.pm
@@ -0,0 +1,23 @@
+#!/usr/bin/perl
+
+package Login;
+
+use strict;
+use warnings;
+use OpenBSD::Pledge;
+use OpenBSD::Unveil;
+
+sub init {
+}
+#dependencies for blowfish
+#unveil("./blowfish.o", "rx") or die "Unable to unveil $!";
+# } elsif ($reply =~ /^!identify\s*(.*)?\s+(.*)$/i) {
+# my $hash = getkeyval($hostmask, "password");
+# #print "result = ".`./blowfish.o $2 '$hash'`;
+# if(system("./blowfish.o $2 '$hash' > /dev/null")) {
+# print "login failed\r\n";
+# } else {
+# print "logged in\r\n";
+# }
+
+1; # MUST BE LAST STATEMENT IN FILE
blob - e355a40adddacd77f32a22fff7d7bed731f76225
blob + e8879c59cb55d5d4dfd64f46fdd831a1abed34cd
--- botnow.pl
+++ botnow.pl
@@ -6,16 +6,24 @@ use IO::Socket;
use IO::Select;
use OpenBSD::Pledge;
use OpenBSD::Unveil;
-use File::Copy qw(copy);
use Digest::SHA qw(sha256_hex);
-use MIME::Base64;
-use Time::HiRes qw ( setitimer ITIMER_VIRTUAL time );
-use DBI;
-use DBD::SQLite;
+use Data::Dumper;
+use lib './';
+use BNC;
+use DNS;
+use Login;
+use Mail;
+use Shell;
+use SQLite;
+use VPN;
+use WWW;
my $confpath = "botnow.conf";
-my %conf;
-foreach my $line (readfile($confpath)) {
+my $netpath = "networks"; # networks file path
+our $ipv6path = "ipv6s"; # ipv6 file path
+
+our %conf;
+foreach my $line (readarray($confpath)) {
if ($line =~ /^#/ or $line =~ /^\s*$/) { # skip comments and whitespace
next;
} elsif ($line =~ /^([-_a-zA-Z0-9]+)\s*=\s*([[:print:]]+)$/) {
@@ -26,106 +34,77 @@ foreach my $line (readfile($confpath)) {
}
# Name of local network
-my $localnet = $conf{localnet} || "ircnow";
+$conf{localnet} = $conf{localnet} || "ircnow";
# Internal IPv4 address and plaintext port
-my $host = $conf{host} || "127.0.0.1";
-my $port = $conf{port} || 1337;
+$conf{host} = $conf{host} || "127.0.0.1";
+$conf{port} = $conf{port} || 1337;
# Bouncer hostname
-chomp(my $hostname = $conf{hostname} || `hostname`);
+chomp($conf{hostname} = $conf{hostname} || `hostname`);
# External IPv4 address, plaintext and ssl port
-my $ip4 = $conf{ip4} || host($hostname,4);
-my $plainport = $conf{plainport} || 1337;
-my $sslport = $conf{sslport} || 31337;
+$conf{ip4} = $conf{ip4} || DNS::host($conf{hostname},4);
+$conf{plainport} = $conf{plainport} || 1337;
+$conf{sslport} = $conf{sslport} || 31337;
# Nick and password of bot -- Make sure to add to oper block
-my $nick = $conf{nick} || "botnow";
-my $pass = $conf{pass} or die "ERROR: botnow.conf: pass";
+$conf{nick} = $conf{nick} || "botnow";
+$conf{pass} = $conf{pass} or die "ERROR: botnow.conf: pass";
# Comma-separated list of channels for requesting bouncers
-my $chans = $conf{chans} || "#ircnow";
+$conf{chans} = $conf{chans} || "#ircnow";
# Number of words in password
-my $passlength = $conf{passlength} || 3;
+$conf{passlength} = $conf{passlength} || 3;
-# Comma-separated list of staff nicks; comment out to avoid highlights
-my $staff = $conf{staff};
-
-# Comma-separated list of team channels on localnet; comment out to disable
-my $teamchans = $conf{teamchans};
-
# Mail from address
-my $mailfrom = $conf{mailfrom} or die "ERROR: botnow.conf: mailfrom";
-my $mailname = $conf{mailname};
-if (!defined($mailname)) {
- if ($mailfrom =~ /^([^@]+)@/) {
- $mailname = $1;
+if (!defined($conf{mailname})) {
+ if ($conf{mailfrom} =~ /^([^@]+)@/) {
+ $conf{mailname} = $1;
} else {
die "ERROR: botnow.conf mailname";
}
}
-# DNS zone directory
-my $zonedir = $conf{zonedir} || "/var/nsd/zones/master/";
-
# rDNS keys from Stallion in BuyVM
-my $key = $conf{key} or die "ERROR: botnow.conf: key";
-my $hash = $conf{hash} or die "ERROR: botnow.conf: hash";
+$conf{key} = $conf{key} or die "ERROR: botnow.conf: key";
+$conf{hash} = $conf{hash} or die "ERROR: botnow.conf: hash";
# ZNC install directory
-my $zncdir = $conf{zncdir} || "/home/znc/home/znc";
+$conf{zncdir} = $conf{zncdir} || "/home/znc/home/znc";
# Network Interface Config File
-my $hostnameif = $conf{hostnameif} || "/etc/hostname.vio0";
+$conf{hostnameif} = $conf{hostnameif} || "/etc/hostname.vio0";
# Verbosity: 0 (no errors), 1 (errors), 2 (warnings), 3 (diagnostic)
-my $verbose = $conf{verbose} || 1;
+use constant {
+ NONE => 0,
+ ERRORS => 1,
+ WARNINGS => 2,
+ ALL => 3,
+};
+$conf{verbose} = $conf{verbose} || ERRORS;
# Terms of Service; don't edit lines with the word EOF
-my $terms = $conf{terms} || "IRCNow is a Christian network. Rules: no profanity, no porn, no illegal drugs, no gambling, no slander, no warez, no promoting violence, no spam, illegal cracking, or DDoS. Only one account per person. Don't share passwords. Religious or political content may be moderated. Full terms: https://ircnow.org/terms.php . Do you agree? (yes/no)";
+$conf{terms} = $conf{terms} || "IRCNow is a Christian network. Rules: no profanity, no porn, no illegal drugs, no gambling, no slander, no warez, no promoting violence, no spam, illegal cracking, or DDoS. Only one account per person. Don't share passwords. Religious or political content may be moderated. Full terms: https://ircnow.org/terms.php . Do you agree? (yes/no)";
if(defined($conf{die})) { die $conf{die}; }
-my $wwwpath = "/var/www/htdocs/botnow"; # Web folder path
-my $ipv6path = "ipv6s"; # ipv6 file path
-my $netpath = "networks"; # networks file path
-my $database = "/var/www/botnow/"; # database path
-my $znclog = "$zncdir/.znc/moddata/adminlog/znc.log"; # znc.log path
-my $dbpath = "/var/www/botnow/users.db";
+# Initiate modules
+BNC::init();
+DNS::init();
+SQLite::init();
+Mail::init();
+Shell::init();
+VPN::init();
+Login::init();
+
unveil("./", "r") or die "Unable to unveil $!";
unveil("$confpath", "r") or die "Unable to unveil $!";
unveil("$netpath", "r") or die "Unable to unveil $!";
unveil("$ipv6path", "rwc") or die "Unable to unveil $!";
-unveil("$database", "rwxc") or die "Unable to unveil $!";
-unveil("$zonedir", "rwc") or die "Unable to unveil $!";
-unveil("$dbpath", "rwc") or die "Unable to unveil $!";
-unveil("$dbpath-journal", "rwc") or die "Unable to unveil $!";
-
-#dependencies for figlet
-unveil("/usr/local/bin/figlet", "rx") or die "Unable to unveil $!";
-unveil("/usr/lib/libc.so.95.1", "r") or die "Unable to unveil $!";
-unveil("/usr/libexec/ld.so", "r") or die "Unable to unveil $!";
-
-#dependencies for mail
-unveil("/usr/sbin/sendmail", "rx") or die "Unable to unveil $!";
-unveil("/usr/lib/libutil.so.13.1", "r") or die "Unable to unveil $!";
-unveil("/bin/sh", "rx") or die "Unable to unveil $!";
-
-#dependencies for doas
-unveil("/usr/bin/doas", "rx") or die "Unable to unveil $!";
-
-#dependencies for encrypt
-unveil("/usr/bin/encrypt", "rx") or die "Unable to unveil $!";
-
-#znc.log file
-unveil("$znclog", "r") or die "Unable to unveil $!";
-
-#dependencies for host
-unveil("/usr/bin/host", "rx") or die "Unable to unveil $!";
-
unveil() or die "Unable to lock unveil $!";
#dns and inet for sockets, proc and exec for figlet
@@ -133,21 +112,18 @@ unveil() or die "Unable to lock unveil $!";
#flock, fattr for sqlite
pledge( qw(stdio rpath wpath cpath inet dns proc exec flock fattr) ) or die "Unable to pledge: $!";
-my @networks;
+our @networks;
my @bots;
my @words;
-my $records;
my @months = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );
my @days = qw(Sun Mon Tue Wed Thu Fri Sat Sun);
-my @chans = split /,/m, $chans;
+my @chans = split /[,\s]+/m, $conf{chans};
my @teamchans;
-my @logs;
-my $dbh;
-my $fh;
-if (defined($teamchans)) { @teamchans = split /,/m, $teamchans; }
+my $call;
+if (defined($conf{teamchans})) { @teamchans = split /[,\s]+/m, $conf{teamchans}; }
-# Read from filename and return all lines without trailing newlines
-sub readfile {
+# Read from filename and return array of lines without trailing newlines
+sub readarray {
my ($filename) = @_;
my (@lines, $fh);
open($fh, '<', "$filename") or die "Could not read file '$filename' $!";
@@ -155,6 +131,15 @@ sub readfile {
close $fh;
return @lines;
}
+
+# Read from filename and return as string
+sub readstr {
+ my ($filename) = @_;
+ open my $fh, '<', $filename or die "Could not read file '$filename' $!";
+ my $str = do { local $/; <$fh> };
+ return $str;
+}
+
# Write str to filename
sub writefile {
my ($filename, $str) = @_;
@@ -169,7 +154,7 @@ sub writefile {
# the same net name; znc ignores addnetwork commands when a network already exists
sub readnetworks {
my ($filename) = @_;
- my @lines = readfile($filename);
+ my @lines = readarray($filename);
my @networks;
foreach my $line (@lines) {
if ($line =~ /^#/ or $line =~ /^\s*$/) { # skip comments and whitespace
@@ -200,35 +185,8 @@ sub readnetworks {
@networks = sort @networks;
# dictionary words for passwords
-@words = readfile("words");
+@words = readarray("words");
-# Validate ipv6s if it exists, otherwise load addresses from /etc/hostname.if
-my @lines;
-
-# Given filename, return a list of ipv6 addresses
-sub readipv6s {
- my ($filename) = @_;
- my @lines = readfile($filename);
- my @ipv6s;
- foreach my $line (@lines) {
- if ($line =~ /^\s*inet6 (alias )?([0-9a-f:]{4,}) [0-9]+\s*$/i) {
- push(@ipv6s, $2);
- } elsif ($line =~ /^\s*([0-9a-f:]{4,})\s*$/i) {
- push(@ipv6s, $1);
- }
- }
- return @ipv6s;
-}
-my @ipv6s;
-
-if (!(-s "$ipv6path")) {
- print "No IPv6 addresses in $ipv6path, loading from $hostnameif...\n";
- @ipv6s = readipv6s($hostnameif);
- if (!@ipv6s) { die "No IPv6 addresses in $hostnameif!"; }
-} else {
- @ipv6s = readipv6s($ipv6path);
-}
-
# create sockets
my $sel = IO::Select->new( );
my $lastnet = "";
@@ -236,16 +194,17 @@ foreach my $network (@networks) {
# avoid duplicate connections
if ($lastnet eq $network->{name}) { next; }
$lastnet = $network->{name};
- my $socket = IO::Socket::INET->new(PeerAddr=>$host, PeerPort=>$port, Proto=>'tcp', Timeout=>'300') || print "Failed to establish connection\n";
+ my $socket = IO::Socket::INET->new(PeerAddr=>$conf{host}, PeerPort=>$conf{port}, Proto=>'tcp', Timeout=>'300') || print "Failed to establish connection\n";
$sel->add($socket);
- my $tmp = {"sock" => $socket};
- push(@bots, {%$tmp, %$network});
- print $socket "NICK $nick\r\n";
- print $socket "USER $nick * * :$nick\r\n";
+ my $bot = {("sock" => $socket), %$network};
+ push(@bots, $bot);
+ putserv($bot, "NICK $conf{nick}");
+ putserv($bot, "USER $conf{nick} * * :$conf{nick}");
}
while(my @ready = $sel->can_read) {
my ($bot, $response);
+ my ($sender, $val);
foreach my $socket (@ready) {
foreach my $b (@bots) {
if($socket == $b->{sock}) {
@@ -254,400 +213,264 @@ while(my @ready = $sel->can_read) {
}
}
if (!defined($response = <$socket>)) {
+ debug(ERRORS, "ERROR bot has no response:");
+ warn Dumper \$bot;
next;
}
- if ($response =~ /^PING :(ZNC)\r\n$/i) {
- my $reply = $1;
- parseping($bot, $reply, $localnet);
+ if ($response =~ /^PING :(.*)\r\n$/i) {
+ putserv($bot, "PONG :$1");
} elsif ($response =~ /^:irc.znc.in (.*) (.*) :(.*)\r\n$/) {
- my ($type, $target, $reply) = ($1, $2, $3);
- parseznc($bot, $type, $target, $reply);
- } elsif($response =~ /^:([^!]+![^@]+@[^@ ]+) PRIVMSG ([^ ]+) :(.*)\r\n$/i) {
- my ($hostmask, $target, $reply) = ($1, $2, $3);
- parsemsg($bot, $hostmask, $target, $reply);
- } elsif($response =~ /^:([^!]+![^@]+@[^@ ]+) NOTICE ([^ ]+) :(.*)\r\n$/i) {
- my ($hostmask, $target, $reply) = ($1, $2, $3);
- parsenotice($bot, $hostmask, $target, $reply);
- } elsif($response =~ /^:([^!]+![^@]+@[^@ ]+) MODE ([^ ]+) :(.*)\r\n$/i) {
- my ($hostmask, $target, $reply) = ($1, $2, $3);
- parsemode($bot, $hostmask, $target, $reply);
- } elsif($response =~ /^:([^!]+![^@]+@[^@ ]+) JOIN :?(.*)\r\n$/i) {
- my ($hostmask, $chan) = ($1, $2);
- parsejoin($bot, $hostmask, $chan);
- } elsif($response =~ /^:([^!]+![^@]+@[^@ ]+) PART ([^ ]+) :(.*)\r\n$/i) {
- my ($hostmask, $chan, $msg) = ($1, $2, $3);
- parsepart($bot, $hostmask, $chan, $msg);
- } elsif($response =~ /^:([^!]+![^@]+@[^@ ]+) NICK :(.*)\r\n$/i) {
- my ($hostmask, $nick) = ($1, $2);
- parsenick($bot, $hostmask, $nick);
- } elsif ($response =~ /^:([[:graph:]]+) (\d\d\d) $nick.? :?(.*)\r?\n?\r$/i) {
- my ($server, $code, $reply) = ($1, $2, $3);
- parseserver($bot, $server, $code, $reply);
- } else {
- if ($verbose >= 2) { print "Unexpected: $response\r\n"; }
- }
- }
-}
-
-sub parseping {
- my ($bot, $reply, $localnet) = @_;
- my $socket = $bot->{sock};
- print $socket "PONG :ZNC\r\n";
- if ($bot->{name} =~ /$localnet/i) {
- updaterecords();
- }
-}
-
-sub parseznc {
- my ($bot, $type, $target, $reply) = @_;
- my $socket = $bot->{sock};
- if ($type eq "001" && $target =~ /^$nick.?$/ && $reply eq "Welcome to ZNC") {
- } elsif ($type eq "NOTICE" && $target =~ /^$nick.?$/ && $reply eq "*** To connect now, you can use /quote PASS <username>:<password>, or /quote PASS <username>/<network>:<password> to connect to a specific network.") {
- } elsif ($type eq "NOTICE" && $target =~ /^$nick.?$/ && $reply eq "*** You need to send your password. Configure your client to send a server password.") {
- } elsif ($type eq "464" && $target =~ /^$nick.?$/ && $reply eq "Password required") {
- print $socket "PASS $nick/$bot->{name}:$pass\r\n";
- foreach my $chan (@chans) {
- print $socket "JOIN ".$chan."\r\n";
- }
- if ($bot->{name} =~ /$localnet/i) {
- print $socket "OPER $nick $pass\r\n";
- print $socket "PRIVMSG *status :LoadMod --type=user controlpanel\r\n";
- print $socket "PRIVMSG *controlpanel :get Admin $nick\r\n";
- print $socket "PRIVMSG *controlpanel :get Nick cloneuser\r\n";
- foreach my $chan (@teamchans) {
- print $socket "JOIN ".$chan."\r\n";
+ my ($type, $target, $text) = ($1, $2, $3);
+ if ($type eq "001" && $target =~ /^$conf{nick}.?$/ && $text eq "Welcome to ZNC") {
+ } elsif ($type eq "NOTICE" && $target =~ /^$conf{nick}.?$/ && $text eq "*** To connect now, you can use /quote PASS <username>:<password>, or /quote PASS <username>/<network>:<password> to connect to a specific network.") {
+ } elsif ($type eq "NOTICE" && $target =~ /^$conf{nick}.?$/ && $text eq "*** You need to send your password. Configure your client to send a server password.") {
+ } elsif ($type eq "464" && $target =~ /^$conf{nick}.?$/ && $text eq "Password required") {
+ putserv($bot, "PASS $conf{nick}/$bot->{name}:$conf{pass}");
+ foreach my $chan (@chans) {
+ putserv($bot, "JOIN $chan");
+ }
+ if ($bot->{name} =~ /$conf{localnet}/i) {
+ putserv($bot, "OPER $conf{nick} $conf{pass}");
+ putserv($bot, "PRIVMSG *status :LoadMod --type=user controlpanel");
+ putserv($bot, "PRIVMSG *controlpanel :get Admin $conf{nick}");
+ putserv($bot, "PRIVMSG *controlpanel :get Nick cloneuser");
+ foreach my $chan (@teamchans) {
+ putserv($bot, "JOIN $chan");
+ }
+ }
+ } elsif ($type eq "464" && $target =~ /^$conf{nick}.?$/ && $text eq "Invalid Password") {
+ debug(ERRORS, "ERROR: Wrong Username/Password: $bot->{name}");
+ } else {
+ debug(ERRORS, "Unexpected: type: $type, target: $target, text: $text");
}
- }
- } elsif ($type eq "464" && $target =~ /^$nick.?$/ && $reply eq "Invalid Password") {
- print "ERROR: Wrong Username/Password: $bot->{name}\r\n";
- } else {
- print "Unexpected: type: $type, target: $target, reply: $reply\r\n";
- }
-}
-
-sub parseserver {
- my ($bot, $server, $code, $reply) = @_;
- my ($sender, $val, $key);
- my $socket = $bot->{sock};
- if ($code =~ /^001$/) { # Server Info
- if ($verbose >= 3) { print "botnow successfully connected to $bot->{name}\r\n"; }
- } elsif ($code =~ /^00\d$/) { # Server Info
-# print "$server $reply\r\n";
- } elsif ($code =~ /^2\d\d$/) { # Server Stats
-# print "$server $reply\r\n";
- } elsif ($code == 301 && $reply =~ /^([-_\|`a-zA-Z0-9]+) :([[:graph:]]+)/) {
- if ($verbose >= 3) { print "$reply\r\n"; }
- } elsif ($code == 307 && $reply =~ /^([-_\|`a-zA-Z0-9]+) (.*)/) {
- ($sender, $key) = ($1, "registered");
- $val = $2 eq ":is a registered nick" ? "True" : "$2";
- my $hostmask = firstval("oldnick", $sender);
- setkeyval($hostmask, "identified", $val);
- if ($verbose >= 3) { print "$key: $val\r\n"; }
- } elsif ($code == 311 && $reply =~ /^([-_\|`a-zA-Z0-9]+) ([^:]+)\s+([^:]+) \* :([^:]*)/) {
- ($sender, $key, $val) = ($1, "vhost", "$1\!$2\@$3");
- my $hostmask = firstval("oldnick", $sender);
- setkeyval($hostmask, $key, $val);
- if ($verbose >= 3) { print "$key: $val\r\n"; }
- } elsif ($code == 312 && $reply =~ /^([-_\|`a-zA-Z0-9]+) ([^:]+) :([^:]+)/) {
- ($sender, $key, $val) = ($1, "server", $2);
- my $hostmask = firstval("oldnick", $sender);
- setkeyval($hostmask, $key, $val);
- if ($verbose >= 3) { print "$key: $val\r\n"; }
- } elsif ($code == 313 && $reply =~ /^([-_\|`a-zA-Z0-9]+) :?(.*)/) {
- ($sender, $key, $val) = ($1, "oper", ($2 eq "is an IRC operator" ? "True" : "$2"));
- my $hostmask = firstval("oldnick", $sender);
- setkeyval($hostmask, $key, $val);
- if ($verbose >= 3) { print "$key: $val\r\n"; }
- } elsif ($code == 315 && $reply =~ /^([-_\|`a-zA-Z0-9]+) :End of \/?WHOIS list/) {
- if ($verbose >= 3) { print "End of WHOIS\r\n"; }
- } elsif ($code == 317 && $reply =~ /^([-_\|`a-zA-Z0-9]+) (\d+) (\d+) :?(.*)/) {
- ($sender, my $idle, my $epochtime) = ($1, $2, $3);
- my $hostmask = firstval("oldnick", $sender);
- setkeyval($hostmask, "idle", $idle);
- setkeyval($hostmask, "epochtime", $epochtime);
- if ($verbose >= 3) { print "idle: $idle, epochtime: $epochtime\r\n"; }
- } elsif ($code == 318 && $reply =~ /^([-_\|`a-zA-Z0-9]+) :End of \/?WHOIS list/) {
- if ($verbose >= 3) { print "End of WHOIS\r\n"; }
- } elsif ($code == 319 && $reply =~ /^([-_\|`a-zA-Z0-9]+) :(.*)/) {
- ($sender, $key, $val) = ($1, "chans", $2);
- my $hostmask = firstval("oldnick", $sender);
- setkeyval($hostmask, $key, $val);
- if ($verbose >= 3) { print "$key: $val\r\n"; }
- } elsif ($code == 330 && $reply =~ /^([-_\|`a-zA-Z0-9]+) ([-_\|`a-zA-Z0-9]+) :?(.*)/) {
- ($sender, $key, $val) = ($1, "loggedin", ($3 eq "is logged in as" ? "True" : $2));
- my $hostmask = firstval("oldnick", $sender);
- setkeyval($hostmask, $key, $val);
- if ($verbose >= 3) { print "$key: $val\r\n"; }
- } elsif ($code == 338 && $reply =~ /^([-_\|`a-zA-Z0-9]+) ([0-9a-fA-F:.]+) :actually using host/) {
- ($sender, $key, $val) = ($1, "ip", $2);
- my $hostmask = firstval("oldnick", $sender);
- setkeyval($hostmask, $key, $val);
- if ($verbose >= 3) { print "$key: $val\r\n"; }
- print "$key: $val\r\n";
-#Unexpected: efnet.port80.se 338 jrmu 206.253.167.44 :actually using host
- } elsif ($code == 378 && $reply =~ /^([-_\|`a-zA-Z0-9]+) :is connecting from ([^ ]+)\s*([0-9a-fA-F:.]+)?/) {
- ($sender, $key, $val) = ($1, "ip", $3);
- my $hostmask = firstval("oldnick", $sender);
- setkeyval($hostmask, $key, $val);
- if ($verbose >= 3) { print "$key: $val\r\n"; }
- } elsif ($code == 671 && $reply =~ /^([-_\|`a-zA-Z0-9]+) :is using a secure connection/) {
- ($sender, $key, $val) = ($1, "ssl", "True");
- my $hostmask = firstval("oldnick", $sender);
- setkeyval($hostmask, $key, $val);
- if ($verbose >= 3) { print "$key: $val\r\n"; }
- print "$key: $val\r\n";
- } elsif ($code =~ /^332$/) { # Topic
-# print "$reply\r\n";
- } elsif ($code =~ /^333$/) { # Topic
-# print "$server $reply\r\n";
-#karatkievich.freenode.net 333 #ircnow jrmu!znc@206.253.167.44 1579277253
- } elsif ($code =~ /^353$/) { # Names
-# print "$server $code $reply\r\n";
- } elsif ($code =~ /^366$/) { # End of names
-# print "$server $code $reply\r\n";
- } elsif ($code =~ /^37\d$/) { # MOTD
-# print "$server $code $reply\r\n";
- } elsif ($code =~ /^381$/) { # IRC Operator Verified
-# print "IRC Oper Verified\r\n";
- } elsif ($code =~ /^401$/) { # IRC Operator Verified
-# print "IRC Oper Verified\r\n";
- } elsif ($code =~ /^422$/) { # MOTD missing
-# print "$server $code $reply\r\n";
- } elsif ($code =~ /^464$/) { # Invalid password for oper
- foreach my $chan (@teamchans) {
- sendmsg($bot, $chan, "ERROR: $nick oper password failed; the bot will be unable to view uncloaked IP addresses\r\n");
- }
- } elsif ($code =~ /^477$/) { # Can't join channel
- foreach my $chan (@teamchans) {
- sendmsg($bot, $chan, "ERROR: $nick on $server: $reply\r\n");
- }
- } elsif ($code == 716 && $reply =~ /^([-_\|`a-zA-Z0-9]+) :is in \+g mode \(server-side ignore.\)/) {
- if ($verbose >= 3) { print "$reply\r\n"; }
- } else {
- print "Unexpected: $server $code $reply\r\n";
- }
-}
-
-sub parsemode {
- my ($bot, $hostmask, $target, $reply) = @_;
- if ($verbose >= 3) { print "$hostmask MODE $target $reply\r\n"; }
+ } elsif($response =~ /^:(([^!]+)!([^@]+@[^@ ]+)) PRIVMSG ([^ ]+) :(.*)\r\n$/i) {
+ my ($hostmask, $nick, $host, $target, $text) = ($1, $2, $3, $4, $5);
+ if ($hostmask eq '*status!znc@znc.in' && $target =~ /$conf{nick}.?/ && $text =~ /Network ([[:ascii:]]+) doesn't exist./) {
+ debug(ERRORS, "$1 is not connected");
+ } elsif ($text =~ /!([[:graph:]]+)\s*(.*)/) {
+ my ($cmd, $text) = ($1, $2);
+ my $hand = $conf{staff}; # TODO fix later
+
+ if ($target =~ /^#/) {
+ foreach my $c (@{$call->{pub}}) {
+ if ($cmd eq $c->{cmd}) {
+ my $proc = $c->{proc};
+ $proc->($bot, $nick, $host, $hand, $target, $text);
+ }
+ }
+ } else {
+ foreach my $c (@{$call->{msg}}) {
+ if ($cmd eq $c->{cmd}) {
+ my $proc = $c->{proc};
+ $proc->($bot, $nick, $host, $hand, $text);
+ }
+ }
+ }
+ }
+ debug(ALL, "$hostmask $target $text");
+ } elsif($response =~ /^:(([^!]+)!([^@]+@[^@ ]+)) NOTICE ([^ ]+) :(.*)\r\n$/i) {
+ my ($hostmask, $nick, $host, $target, $text) = ($1, $2, $3, $4, $5);
+ my $hand = $conf{staff}; # TODO fix later
+ foreach my $c (@{$call->{notc}}) {
+ # if ($text eq $c->{mask}) { # TODO fix later
+ my $proc = $c->{proc};
+ $proc->($bot, $nick, $host, $hand, $text, $target);
+ # }
+ }
+ # TODO use CTCR
+ # CTCP replies
+ if ($hostmask ne '*status!znc@znc.in') {
+ if ($text =~ /^(PING|VERSION|TIME|USERINFO) (.*)$/i) {
+ my ($key, $val) = ($1, $2);
+ SQLite::userset($hostmask, lc($key), $val);
+ SQLite::userset($hostmask, "localtime", gettime());
+ }
+ }
+ debug(ALL, "$nick!$host NOTICE $target $text");
+ } elsif($response =~ /^:(([^!]+)!([^@]+@[^@ ]+)) MODE ([^ ]+) ([^ ]+)\s*([^ ]*)\r\n$/i) {
+ my ($hostmask, $nick, $host, $chan, $change, $target) = ($1, $2, $3, $4, $5, $6);
+ my $hand = $conf{staff}; # TODO fix later
+ foreach my $c (@{$call->{mode}}) {
+ # TODO filter by mask
+ my $proc = $c->{proc};
+ $proc->($bot, $nick, $host, $hand, $chan, $change, $target);
+ }
+ debug(ALL, "$hostmask MODE $chan $change $target");
#:guava!guava@guava.guava.ircnow.org MODE guava :+Ci
#:ChanServ!services@services.irc.ircnow.org MODE #testing +q jrmu
#:jrmu!jrmu@jrmu.staff.ircnow.org MODE #testing +o jrmu
-}
-sub parsejoin {
- my ($bot, $hostmask, $chan) = @_;
- if ($verbose >= 3) { print "$hostmask JOIN $chan\r\n"; }
+ } elsif($response =~ /^:(([^!]+)!([^@]+@[^@ ]+)) JOIN :?(.*)\r\n$/i) {
+ my ($hostmask, $nick, $host, $chan) = ($1, $2, $3, $4);
+ my $hand = $conf{staff}; # TODO fix later
+ foreach my $c (@{$call->{join}}) {
+ my $proc = $c->{proc};
+ $proc->($bot, $nick, $host, $hand, $chan);
+ }
+ debug(ALL, "$hostmask JOIN $chan");
#:jrmu!jrmu@jrmu.staff.ircnow.org JOIN :#testing
-}
-sub parsepart {
- my ($bot, $hostmask, $chan, $msg) = @_;
- print "$hostmask PART $chan :$msg\r\n";
+ } elsif($response =~ /^:(([^!]+)!([^@]+@[^@ ]+)) PART ([^ ]+) :(.*)\r\n$/i) {
+ my ($hostmask, $nick, $host, $chan, $text) = ($1, $2, $3, $4, $5);
+ my $hand = $conf{staff}; # TODO fix later
+ foreach my $c (@{$call->{part}}) {
+ # if ($text eq $c->{mask}) { # TODO fix later
+ my $proc = $c->{proc};
+ $proc->($bot, $nick, $host, $hand, $chan, $text);
+ # }
+ }
+ debug(ALL, "$hostmask PART $chan :$text");
#:jrmu!jrmu@jrmu.staff.ircnow.org PART #testing :
-}
-sub parsenick {
- my ($bot, $hostmask, $nick) = @_;
- print "$hostmask NICK $nick\r\n";
+ } elsif($response =~ /^:(([^!]+)!([^@]+@[^@ ]+)) NICK :?(.*)\r\n$/i) {
+ my ($hostmask, $nick, $host, $text) = ($1, $2, $3, $4);
+ debug(ALL, "$hostmask NICK $text");
#:Fly0nDaWaLL|dal!psybnc@do.not.h4ck.me NICK :nec|dal
-}
-
-sub sendmsg {
- my( $bot, $target, $msg )=@_;
- my $socket = $bot->{sock};
- my @lines = split /\r?\n\r?/m, $msg;
- foreach my $l (@lines) {
- print $socket "PRIVMSG $target :$l\r\n";
- # if not sending to znc
- if ($bot->{name} =~ /^$localnet$/i and $target !~ /^\*/) {
- sleep(1);
- }
- }
-}
-
-sub mailverify {
- my( $username, $email, $password, $service, $version )=@_;
- my $passhash = sha256_hex("$username");
- if ($version =~ /mIRC/) {
- $version = "mIRC";
- }
-my $versionhash = encode_base64($version);
-
-my $msg = <<"EOF";
-From: $mailname \<$mailfrom\>
-To: $email
-Subject: Verify IRCNow Account
-MIME-Version: 1.0
-Content-Type: text/plain; charset=us-ascii
-Content-Disposition: inline
-
-You created a bouncer!
-
-Username: $username
-Password: $password
-Server: $hostname
-Port: $sslport for SSL (secure connection)
-Port: $plainport for plaintext
-
-*IMPORTANT*: Verify your email address:
-
-https://www.$hostname/register.php?id=$hash&version=$versionhash
-
-You *MUST* click on the link or your account will be deleted.
-
-IRCNow
-EOF
-open(my $fh, "| /usr/sbin/sendmail -tv -F support -f $mailfrom") or die "Could not send mail $!";
-print $fh $msg;
-close $fh;
-}
-
-sub getrecords {
- if (!defined($records)) {
- my @rows = selectall();
- if (@rows) {
- foreach my $row (@rows) {
- my $hostmask = $row->{vhost};
- $records->{$hostmask} = ();
- foreach $key (keys %$row) {
- my $val = $row->{$key} || "";
- $records->{$hostmask}->{$key} = $val;
+ } elsif ($response =~ /^:([[:graph:]]+) (\d\d\d) $conf{nick}.? :?(.*)\r?\n?\r$/i) {
+ my ($server, $code, $text) = ($1, $2, $3);
+ if ($code =~ /^001$/) { # Server Info
+ debug(ERRORS, "botnow successfully connected to $bot->{name}");
+ } elsif ($code =~ /^0\d\d$/) { # Server Info
+ debug(ALL, "$server $code $text");
+ } elsif ($code =~ /^2\d\d$/) { # Server Stats
+ debug(ALL, "$server $code $text");
+ } elsif ($code == 301 && $text =~ /^([-_\|`a-zA-Z0-9]+) :([[:graph:]]+)/) {
+ debug(ALL, "$text");
+ } elsif ($code == 307 && $text =~ /^([-_\|`a-zA-Z0-9]+) (.*)/) {
+ my ($sender, $key) = ($1, "registered");
+ $val = $2 eq ":is a registered nick" ? "True" : "$2";
+ my $hostmask = SQLite::firstval("oldnick", $sender);
+ SQLite::userset($hostmask, "identified", $val);
+ debug(ALL, "$key: $val");
+ } elsif ($code == 311 && $text =~ /^([-_\|`a-zA-Z0-9]+) ([^:]+)\s+([^:]+) \* :([^:]*)/) {
+ my ($sender, $key, $val) = ($1, "vhost", "$1\!$2\@$3");
+ my $hostmask = SQLite::firstval("oldnick", $sender);
+ SQLite::userset($hostmask, $key, $val);
+ debug(ALL, "$key: $val");
+ } elsif ($code == 312 && $text =~ /^([-_\|`a-zA-Z0-9]+) ([^:]+) :([^:]+)/) {
+ my ($sender, $key, $val) = ($1, "server", $2);
+ my $hostmask = SQLite::firstval("oldnick", $sender);
+ SQLite::userset($hostmask, $key, $val);
+ debug(ALL, "$key: $val");
+ } elsif ($code == 313 && $text =~ /^([-_\|`a-zA-Z0-9]+) :?(.*)/) {
+ my ($sender, $key, $val) = ($1, "oper", ($2 eq "is an IRC operator" ? "True" : "$2"));
+ my $hostmask = SQLite::firstval("oldnick", $sender);
+ SQLite::userset($hostmask, $key, $val);
+ debug(ALL, "$key: $val");
+ } elsif ($code == 315 && $text =~ /^([-_\|`a-zA-Z0-9]+) :End of \/?WHOIS list/) {
+ debug(ALL, "End of WHOIS");
+ } elsif ($code == 317 && $text =~ /^([-_\|`a-zA-Z0-9]+) (\d+) (\d+) :?(.*)/) {
+ ($sender, my $idle, my $epochtime) = ($1, $2, $3);
+ my $hostmask = SQLite::firstval("oldnick", $sender);
+ SQLite::userset($hostmask, "idle", $idle);
+ SQLite::userset($hostmask, "epochtime", $epochtime);
+ debug(ALL, "idle: $idle, epochtime: $epochtime");
+ } elsif ($code == 318 && $text =~ /^([-_\|`a-zA-Z0-9]+) :End of \/?WHOIS list/) {
+ debug(ALL, "End of WHOIS");
+ } elsif ($code == 319 && $text =~ /^([-_\|`a-zA-Z0-9]+) :(.*)/) {
+ my ($sender, $key, $val) = ($1, "chans", $2);
+ my $hostmask = SQLite::firstval("oldnick", $sender);
+ SQLite::userset($hostmask, $key, $val);
+ debug(ALL, "$key: $val");
+ } elsif ($code == 330 && $text =~ /^([-_\|`a-zA-Z0-9]+) ([-_\|`a-zA-Z0-9]+) :?(.*)/) {
+ my ($sender, $key, $val) = ($1, "identified", ($3 eq "is logged in as" ? "True" : $2));
+ my $hostmask = SQLite::firstval("oldnick", $sender);
+ SQLite::userset($hostmask, $key, $val);
+ debug(ALL, "$key: $val");
+ } elsif ($code == 338 && $text =~ /^([-_\|`a-zA-Z0-9]+) ([0-9a-fA-F:.]+) :actually using host/) {
+ my ($sender, $key, $val) = ($1, "ip", $2);
+ my $hostmask = SQLite::firstval("oldnick", $sender);
+ SQLite::userset($hostmask, $key, $val);
+ debug(ALL, "$key: $val");
+ #Unexpected: efnet.port80.se 338 jrmu 206.253.167.44 :actually using host
+ } elsif ($code == 378 && $text =~ /^([-_\|`a-zA-Z0-9]+) :is connecting from ([^ ]+)\s*([0-9a-fA-F:.]+)?/) {
+ my ($sender, $key, $val) = ($1, "ip", $3);
+ my $hostmask = SQLite::firstval("oldnick", $sender);
+ SQLite::userset($hostmask, $key, $val);
+ debug(ALL, "$key: $val");
+ } elsif ($code == 671 && $text =~ /^([-_\|`a-zA-Z0-9]+) :is using a secure connection/) {
+ my ($sender, $key, $val) = ($1, "ssl", "True");
+ my $hostmask = SQLite::firstval("oldnick", $sender);
+ SQLite::userset($hostmask, $key, $val);
+ debug(ALL, "$key: $val");
+ } elsif ($code =~ /^332$/) { # Topic
+ # print "$text\r\n";
+ } elsif ($code =~ /^333$/) { # Topic
+ # print "$server $text\r\n";
+ #karatkievich.freenode.net 333 #ircnow jrmu!znc@206.253.167.44 1579277253
+ } elsif ($code =~ /^353$/) { # Names
+ # print "$server $code $text\r\n";
+ } elsif ($code =~ /^366$/) { # End of names
+ # print "$server $code $text\r\n";
+ } elsif ($code =~ /^37\d$/) { # MOTD
+ # print "$server $code $text\r\n";
+ } elsif ($code =~ /^381$/) { # IRC Operator Verified
+ # print "IRC Oper Verified\r\n";
+ } elsif ($code =~ /^401$/) { # IRC Operator Verified
+ # print "IRC Oper Verified\r\n";
+ } elsif ($code =~ /^422$/) { # MOTD missing
+ # print "$server $code $text\r\n";
+ } elsif ($code =~ /^464$/) { # Invalid password for oper
+ foreach my $chan (@teamchans) {
+ putserv($bot, "PRIVMSG $chan :$conf{nick} oper password failed; the bot will be unable to view uncloaked IP addresses");
}
+ } elsif ($code =~ /^477$/) { # Can't join channel
+ foreach my $chan (@teamchans) {
+ putserv($bot, "PRIVMSG $chan :ERROR: $conf{nick} on $server: $text");
+ }
+ } elsif ($code == 716 && $text =~ /^([-_\|`a-zA-Z0-9]+) :is in \+g mode \(server-side ignore.\)/) {
+ debug(ALL, "$text");
+ } else {
+ debug(ERRORS, "Unexpected: $server $code $text");
}
+ # } elsif($response =~ /^:\*status!znc\@znc\.in $conf{nick} (.*)/i) {
+ #my ($text) = ($1);
+ #debug(ERRORS, "$text");
} else {
- print "Error getting records\n";
+ debug(ERRORS, "Unexpected: $response");
}
}
}
-sub getkeyval {
- my ($hostmask, $key) = @_;
- my $val;
- if (!defined($records)) { getrecords(); }
- $val = $records->{$hostmask}->{$key};
- if ($verbose >= 3) { print "getkeyval $hostmask: $key => ".($val or "undefined")."\r\n"; }
- return $val;
-}
-sub setkeyval {
- my ($hostmask, $key, $val) = @_;
- if (!defined($records)) { getrecords(); }
- if (!defined($records->{$hostmask})) {
- insert("vhost", $hostmask);
- }
- $records->{$hostmask}->{$key} = $val; # autovivifies
- if ($verbose >= 3) { print "setkeyval $hostmask: $key => $val\r\n"; }
-}
-sub delkey {
- my ($hostmask, $key) = @_;
- if (!defined($records)) { getrecords(); }
- delete($records->{$hostmask}->{$key});
- if ($verbose >= 3) { print "delkey $hostmask: $key\r\n"; }
-}
-sub delhost {
- my ($hostmask) = @_;
- if (!defined($records)) { getrecords(); }
- deleterow($hostmask);
- delete($records->{$hostmask});
-}
-sub firstval {
- my ($key, $val) = @_;
- if (!defined($records)) { getrecords(); }
- foreach my $hostmask (keys %$records) {
- if (exists($records->{$hostmask}->{$key}) && $records->{$hostmask}->{$key} eq $val) {
- return $hostmask;
+#Unexpected: *status!znc@znc.in guava Disconnected from IRC. Reconnecting...
+#Unexpected: *status!znc@znc.in guava Connected!
+#Unexpected: *status!znc@znc.in guava Error from server: Closing Link: guava.guava.ircnow.org (Ping timeout: 493 seconds)
+#Unexpected: irc.us10.ircnow.org 396 guava.guava.ircnow.org :is your displayed hostname now
+#Unexpected: irc.us10.ircnow.org 352 * guava guava.guava.ircnow.org irc.us10.ircnow.org guava H :0 guava
+#Unexpected: irc.us10.ircnow.org 315 guava :End of WHO list
+
+sub putserv {
+ my( $bot, $text )=@_;
+ my $socket = $bot->{sock};
+ if ($text =~ /^([^:]+):([[:ascii:]]*)$/m) {
+ my ($cmd, $line) = ($1, $2);
+ my @lines = split /\r?\n/m, $line;
+ foreach my $l (@lines) {
+ print $socket "$cmd:$l\r\n";
}
+ } else {
+ print $socket "$text\r\n";
}
- return;
}
-sub createrecord {
- my ($hostmask) = @_;
- if (!defined($records)) { getrecords(); }
- insert("vhost", $hostmask);
- return 1;
-}
-sub updaterecords {
- if (!defined($records)) { getrecords(); }
- while (my ($hostmask, $record) = each (%$records)) {
- foreach my $key (keys %$record) {
- print "key: $key, val: ".$record->{$key}.", hostmask: $hostmask\n";
- update($key, $record->{$key}, $hostmask);
- }
- }
- if ($verbose >= 3) { print "records saved\n"; }
- return 1;
-}
+
sub date {
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
my $localtime = sprintf("%04d%02d%02d", $year+1900, $mon+1, $mday);
return $localtime;
}
-sub mytime {
+sub gettime {
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
my $localtime = sprintf("%s %s %d %02d:%02d:%02d", $days[$wday], $months[$mon], $mday, $hour, $min, $sec);
return $localtime;
}
-sub www {
- my( $username, $email, $password, $service )=@_;
- my $hash = sha256_hex("$username");
- my $filename = "$database/www";
- my $lines = "";
- if (open($fh, '+<', $filename)) {
- while (my $line = <$fh>) {
- $lines .= $line;
- }
- close $fh;
- }
- open($fh, '>', "$filename") or die "Could not write to '$database/www' $!";
- print $fh $lines;
- print $fh "Hash: $hash, Username: $username, Email: $email, Password: $password\n";
- close $fh;
-}
-
sub newpass {
my $len = scalar @words;
my $pass;
- for (my $i=0; $i < $passlength; $i++) {
+ for (my $i=0; $i < $conf{passlength}; $i++) {
my $word = $words[int(rand($len))];
$word =~ s/(\w+)/\u$1/g;
$pass .= $word;
}
return $pass;
}
-sub nickfromhost {
- my ($hostmask) = @_;
- if ($hostmask =~ /([^!]+)!/i) {
- return $1;
- }
- return;
-}
-# Send $msg to every nick in $staff on the team channel
-sub sendteam {
- my( $sender, $msg )=@_;
- my @nicks = split /,/m, $staff;
- my $bot;
-
- if (!defined($teamchans)) { return; }
-
- #prevent duplicates on other networks
- if ($sender =~ /\|/) {
- return;
- }
-
- foreach my $b (@bots) {
- if($b->{name} =~ /$localnet/i) {
- $bot = $b;
- last;
- }
- }
- foreach my $chan (@teamchans) {
- if (defined($staff)) {
- sendmsg($bot, $chan, join(" ", split /,/m, $staff).": $msg");
- } else {
- sendmsg($bot, $chan, $msg);
- }
- }
-}
-
sub whois {
my( $socket, $target )=@_;
print $socket "WHOIS $target $target\r\n";
@@ -664,726 +487,24 @@ sub ctcp {
# print $socket "PRIVMSG $target :".chr(01)."PING".chr(01)."\r\n";
}
-sub parsemsg {
- my ($bot, $hostmask, $target, $reply) = @_;
- my $socket = $bot->{sock};
- my $sender = nickfromhost($hostmask);
- my $help = sub {
- my $msg = <<"EOF";
-To request a free bouncer, type !bnc . To reset the password, type !resetpass <nick> <email>. To change email, type !set email <email>.
-EOF
- sendmsg($bot, $sender, $msg);
- sendteam($sender, "Help *$sender* on network ".$bot->{name}." $chans");
- };
- my $captcha = sub {
- my $num = int(rand(999));
- setkeyval($hostmask, "num", $num);
- my $figlet = `figlet $num`;
- sendmsg($bot, $sender, $figlet);
- sendteam($sender, "$sender\'s captcha is $num");
- };
- if ($hostmask eq '*status!znc@znc.in' && $target =~ /^$nick.?$/) {
- if ($reply eq "You are currently disconnected from IRC. Use 'connect' to reconnect.") {
- if ($verbose >= 3) { print "not connected to $bot->{name}\n"; }
- return;
- } elsif ($reply =~ /Unable to load module (.*): Module (.*) already loaded./) {
- if ($verbose >= 3) { print "Module $1 already loaded\n"; }
- return;
- } else {
- print "Unexpected: $hostmask $target $reply\r\n";
- }
- } elsif($hostmask eq '*controlpanel!znc@znc.in') {
- if ($reply =~ /^Error: User \[cloneuser\] does not exist/) {
- createclone($bot);
- sendteam($sender, "Cloneuser created!");
- } elsif($reply =~ /^Nick = ([a-zA-Z][-_a-zA-Z0-9]+)$/) {
-# only one requestnick
- my $requestnick = $1;
- my $hostmask = firstval("requestnick", $requestnick);
- if (!defined($hostmask)) { return; }
- delkey($hostmask, "requestnick");
- sendmsg($bot, nickfromhost($hostmask), "Username already taken. New username:");
- } elsif($reply =~ /^Error: User \[(.*)\] does not exist/) {
-# delete requestnick after granted
- my $newnick = $1;
- my $hostmask = firstval("requestnick", $newnick);
- if (!defined($hostmask)) { return; }
- setkeyval($hostmask, "newnick", $newnick);
- delkey($hostmask, "requestnick");
- sendmsg($bot, nickfromhost($hostmask), "Email:");
- } elsif ($reply =~ /^User (.*) added!$/) {
- print "User $1 created!\r\n";
- } elsif ($reply =~ /^Password has been changed!$/) {
- print "Password changed\r\n";
- } elsif ($reply =~ /^Queued network (.*) of user (.*) for a reconnect.$/) {
- print "$2 now connecting to $1...\r\n";
- } elsif ($reply =~ /^Admin = false/) {
- sendteam("", "ERROR: $nick is not admin");
- die "ERROR: $nick is not admin";
- } elsif ($reply =~ /^Admin = true/) {
- if ($verbose >= 3) { print "$nick is ZNC admin\n"; }
- } elsif ($reply =~ /(.*) = (.*)/) {
- my ($key, $val) = ($1, $2);
- if ($verbose >= 3) { print "$key = $val\r\n"; }
- } else {
- print "Unexpected: $hostmask $target $reply\r\n";
- }
- } elsif ($reply =~ /^!(help|request)/i) {
- if ($chans =~ $target) {
- sendmsg($bot, $target, "$sender: Please check private message");
- }
- $help->();
- } elsif ($reply =~ /^!bnc/i) {
- if (defined(getkeyval($hostmask, "services"))) {
- sendmsg($bot, $sender, "Sorry, only one account per person. Please contact staff if you need help.");
- } else {
- delhost($hostmask);
- setkeyval($hostmask, "oldnick", $sender);
- whois($socket, $sender);
- if ($chans =~ $target) {
- sendmsg($bot, $target, "$sender: Please check private message");
- }
- sendmsg($bot, $sender, $terms);
- sendteam($bot->{name}, "Help *$sender* on ".$bot->{name});
- }
- } elsif ($reply =~ /^!linesmatching ([-_()|0-9A-Za-z:\.?*]{3,})/) {
- my $pattern = $1; # arbitrary pattern
- if ($staff !~ /$sender/) { return; }
- my @lines = linesmatching($pattern);
- foreach my $l (@lines) { print "$l\n"; }
- } elsif ($reply =~ /^!usersmatching ([0-9A-Fa-f:\.,]{3,})/) {
- my $ips = $1; # comma-separated list of IPs
- if ($staff !~ /$sender/) { return; }
- sendmsg($bot, $sender, usersmatching($ips));
- } elsif ($reply =~ /^!ipsmatching ([0-9A-Za-z_-]{3,})/) {
- my $usernames = $1; # comma-separated list of usernames
- if ($staff !~ /$sender/) { return; }
- sendmsg($bot, $sender, ipsmatching($usernames));
- } elsif ($reply =~ /^!host ([-0-9A-Za-z:\.]{3,})/) {
- my $name = $1;
- if ($staff !~ /$sender/) { return; }
- sendmsg($bot, $sender, host($name));
- } elsif ($reply =~ /^!setrdns\s+([0-9A-Fa-f:\.]{3,})\s+([-0-9A-Za-z\.]+)/) {
- my ($ip, $hostname) = ($1, $2);
- if ($staff !~ /$sender/) { return; }
- if (setrdns($ip, $hostname)) {
- sendteam("", "$hostname set to $ip");
- } else {
- sendteam("", "Error: failed to set rDNS");
- }
- } elsif ($reply =~ /^!delrdns\s+([0-9A-Fa-f:\.]{3,})/) {
- my $ip = $1;
- if ($staff !~ /$sender/) { return; }
- my $hostname = "notset";
- if (setrdns($ip, $hostname)) {
- sendteam("", "$ip rDNS deleted");
- } else {
- sendteam("", "Error: failed to set rDNS");
- }
- } elsif ($reply =~ /^!setdns\s+([-0-9A-Za-z\.]+)\s+([0-9A-Fa-f:\.]+)/) {
- my ($hostname, $ip) = ($1, $2);
- if ($staff !~ /$sender/) { return; }
- if (setdns($hostname, $ip)) {
- sendteam("", "$hostname set to $ip");
- } else {
- sendteam("", "ERROR: failed to set DNS");
- }
- } elsif ($reply =~ /^!deldns\s+([-0-9A-Za-z\.]+)/) {
- my $hostname = $1;
- if ($staff !~ /$sender/) { return; }
- if (deldns($hostname)) {
- sendteam("", "$hostname deleted");
- } else {
- sendteam("", "ERROR: failed to delete DNS records");
- }
- } elsif ($reply =~ /^!connectdb/) {
- if ($staff !~ /$sender/) { return; }
- if (connectdb()) {
- sendteam("", "connectdb succeeded");
- } else {
- sendteam("", "ERROR: connectdb failed");
- }
- } elsif ($reply =~ /^!updaterecords/) {
- if ($staff !~ /$sender/) { return; }
- if (updaterecords()) {
- sendteam("", "updaterecords succeeded");
- } else {
- sendteam("", "ERROR: updaterecords failed");
- }
- } elsif ($reply =~ /^!insert ([-_0-9A-Za-z]+) ([[:graph:]]+)/) {
- my ($key, $val) = ($1, $2);
- if ($staff !~ /$sender/) { return; }
- my $rows = insert($key, $val);
- if (!defined($rows)) {
- sendteam("", "ERROR: insert failed");
- } else {
- sendteam("", "insert: $key => $val");
- }
- } elsif ($reply =~ /^!update ([-_0-9A-Za-z]+) ([[:graph:]]+) ([-_0-9A-Za-z]+)/) {
- my ($key, $val, $id) = ($1, $2, $3);
- if ($staff !~ /$sender/) { return; }
- my $rows = update($key, $val, $id);
- if (!defined($rows)) {
- sendteam("", "ERROR: update failed");
- } else {
- sendteam("", "update $rows rows: $key $val");
- }
- } elsif ($reply =~ /^!select ([-=_0-9A-Za-z\s]+) ([-~=_0-9A-Za-z\s]+)/) {
- my ($key, $val) = ($1, $2);
- if ($staff !~ /$sender/) { return; }
- my @rows = selectdb($key, $val);
- if (@rows) {
- foreach my $row (@rows) {
- foreach $key (keys %$row) {
- my $val = $row->{$key} || "";
- print "$key => $val\n";
- }
- }
- } else {
- sendteam("", "ERROR: select failed");
- }
- } elsif ($target !~ /^$nick.?/) {
-# print "$hostmask: $target $reply\r\n";
- } elsif (!defined(getkeyval($hostmask, "num"))) {
- if ($reply =~ /^(y|yes)/i) {
- setkeyval($hostmask, "terms", "yes");
- ctcp($socket, $sender);
- sendmsg($bot, $sender, "What number is this?");
- $captcha->();
- } elsif (defined(getkeyval($hostmask, "terms")) && !getkeyval($hostmask, "terms")) {
-# already asked, so repeat help message
- $help->();
- return;
- } else {
- setkeyval($hostmask, "terms", "no");
- sendmsg($bot, $sender, "Sorry, command not understood. Type !help or contact staff.");
- }
- } elsif (!defined(getkeyval($hostmask, "captcha"))) {
- if ($reply =~ /^([0-9]+)$/ && $reply == getkeyval($hostmask, "num")) {
- setkeyval($hostmask, "captcha", $reply);
- sendmsg($bot, $sender, "New username:");
- } else {
- sendmsg($bot, $sender, "Wrong. What number is this?");
- $captcha->();
- }
- } elsif(!defined(getkeyval($hostmask, "newnick"))) {
- if ($reply =~ /^([a-zA-Z][-a-zA-Z0-9]+)/) {
- setkeyval($hostmask, "requestnick", $reply);
- sendmsg($bot, "*controlpanel", "get Nick $reply");
- } else {
- sendmsg($bot, $sender, "Invalid username. New username:");
- }
- } elsif(!defined(getkeyval($hostmask, "email"))) {
- if ($reply =~ /^(([-_.0-9a-zA-Z]+)\@([-_.0-9a-zA-Z]+))$/) {
- my $otheracct = firstval("email", $reply);
- if (defined($otheracct)) {
- setkeyval($hostmask, "terms", "no");
- sendmsg($bot, $sender, "Sorry, only one account per person. Please contact staff if you need help.");
- return;
- }
- my $newnick = getkeyval($hostmask, "newnick");
- my $version = getkeyval($hostmask, "VERSION");
- setkeyval($hostmask, "email", $reply);
- my $password = newpass();
- my $encrypted = `encrypt $password`;
- chomp($encrypted);
- setkeyval($hostmask, "password", $encrypted);
- my $bindhost = nextdns($newnick);
- mailverify($newnick, $reply, $password, "bouncer", $version);
- my $msg = <<"EOF";
-Check your email.
-EOF
- sendmsg($bot, $sender, $msg);
- sleep(5);
- createbnc($bot, $newnick, $password, $bindhost);
- setkeyval($hostmask, "services", "znc");
- www($newnick, $reply, $password, "bouncer");
- } else {
- sendmsg($bot, $sender, "Invalid email. New email:");
- }
-
-### Hidden functionality ###
-
- } elsif ($reply =~ /^!deluser (.*)$/i) {
- my $user = $1;
- if ($staff !~ /$sender/) {
- return;
- }
- print $socket "PRIVMSG *controlpanel :deluser $user\r\n";
- } elsif ($reply =~ /^!rehash$/i) {
- if ($staff !~ /$sender/) {
- return;
- }
- print $socket "PRIVMSG *controlpanel :deluser cloneuser\r\n";
- sleep 5;
- print $socket "PRIVMSG *controlpanel :get Nick cloneuser\r\n";
- } elsif ($reply =~ /^!dns\s+([-.0-9a-z]+)\s+([:0-9a-f]+)/i) {
- my ($fqdn, $ip6) = ($1, $2);
- if ($staff !~ /$sender/) {
- return;
- }
- dns($fqdn, $ip6);
- } elsif ($reply =~ /^!nextdns ([-0-9a-zA-Z]+)/i) {
- my $username = $1;
- if ($staff !~ /$sender/) {
- return;
- }
- nextdns($username);
- sendmsg($bot, $sender, "nextdns called");
- } elsif ($reply =~ /^!getkeyval ([-_0-9a-zA-Z]+) ([-_0-9a-zA-Z]+)/) {
- if ($staff !~ /$sender/) {
- return;
- }
- sendmsg($bot, $sender, getkeyval($1, $2));
- } elsif ($reply =~ /^!setkeyval ([-_0-9a-zA-Z]+) ([-_0-9a-zA-Z]+) ([-_0-9a-zA-Z]+)/) {
- if ($staff !~ /$sender/) {
- return;
- }
- sendmsg($bot, $sender, setkeyval($1, $2, $3));
- } elsif ($reply =~ /^!delkey ([-_0-9a-zA-Z]+) ([-_0-9a-zA-Z]+)/) {
- if ($staff !~ /$sender/) {
- return;
- }
- sendmsg($bot, $sender, delkey($1, $2));
- } elsif ($reply =~ /^!updaterecords/) {
- if ($staff !~ /$sender/) {
- return;
- }
- if (updaterecords()) {
- sendmsg($bot, $sender, "Records saved.");
- }
- } else {
- print "exception $hostmask targe: $target reply: $reply\r\n";
+sub cbind {
+ my ($type, $flags, $cmd, $proc) = @_;
+ if ($type eq "pub") {
+ push(@{$call->{pub}}, {cmd => $cmd, proc => $proc});
+ } elsif ($type eq "msg") {
+ push(@{$call->{msg}}, {cmd => $cmd, proc => $proc});
+ } elsif ($type eq "notc") {
+ push(@{$call->{notc}}, {mask => $cmd, proc => $proc});
+ } elsif ($type eq "mode") {
+ push(@{$call->{mode}}, {mask => $cmd, proc => $proc});
+ } elsif ($type eq "join") {
+ push(@{$call->{join}}, {mask => $cmd, proc => $proc});
+ } elsif ($type eq "partcall") {
+ push(@{$call->{part}}, {mask => $cmd, proc => $proc});
}
}
-sub parsenotice {
- my ($bot, $hostmask, $target, $reply) = @_;
- my $socket = $bot->{sock};
- my $sender = nickfromhost($hostmask);
-
- # CTCP replies
- if ($hostmask ne '*status!znc@znc.in') {
- if ($reply =~ /^(PING|VERSION|TIME|USERINFO) (.*)$/i) {
- my ($key, $val) = ($1, $2);
- $key = lc $key;
- setkeyval($hostmask, $key, $val);
- setkeyval($hostmask, "localtime", mytime());
- }
- }
-}
-
-#sub resetznc {
-#
-#AnonIPLimit 10000
-#AuthOnlyViaModule false
-#ConnectDelay 0
-#HideVersion true
-#LoadModule
-#ServerThrottle
-#1337 209.141.38.137
-#31337 209.141.38.137
-#1337 2605:6400:20:5cc::
-#31337 2605:6400:20:5cc::
-#1337 127.0.0.1
-#1338 127.0.0.1
-#}
-#
-#alias Provides bouncer-side command alias support.
-#autoreply Reply to queries when you are away
-#block_motd Block the MOTD from IRC so it's not sent to your client(s).
-#bouncedcc Bounces DCC transfers through ZNC instead of sending them directly to the user.
-#clientnotify Notifies you when another IRC client logs into or out of your account. Configurable.
-#ctcpflood Don't forward CTCP floods to clients
-#dcc This module allows you to transfer files to and from ZNC
-#perform Keeps a list of commands to be executed when ZNC connects to IRC.
-#webadmin Web based administration module.
-
-sub createclone {
- my ($bot) = @_;
- my $socket = $bot->{sock};
- my $password = newpass();
- my $msg = <<"EOF";
-adduser cloneuser $password
-set Nick cloneuser cloneuser
-set Altnick cloneuser cloneuser_
-set Ident cloneuser cloneuser
-set RealName cloneuser cloneuser
-set MaxNetworks cloneuser 1000
-set ChanBufferSize cloneuser 1000
-set MaxQueryBuffers cloneuser 1000
-set QueryBufferSize cloneuser 1000
-set NoTrafficTimeout cloneuser 600
-set QuitMsg cloneuser IRCNow and Forever!
-set RealName cloneuser cloneuser
-set DenySetBindHost cloneuser true
-set Timezone cloneuser US/Pacific
-LoadModule cloneuser controlpanel
-LoadModule cloneuser chansaver
-EOF
-#LoadModule cloneuser buffextras
- sendmsg($bot, "*controlpanel", $msg);
- foreach my $n (@networks) {
- my $net = $n->{name};
- my $server = $n->{server};
- my $port = $n->{port};
- my $trustcerts = $n->{trustcerts};
- $msg = <<"EOF";
-addnetwork cloneuser $net
-addserver cloneuser $net $server $port
-disconnect cloneuser $net
-EOF
- if ($trustcerts) {
- $msg .= "SetNetwork TrustAllCerts cloneuser $net True\r\n";
- }
- foreach my $chan (@chans) {
- $msg .= "addchan cloneuser $net $chan\r\n";
- }
- sendmsg($bot, "*controlpanel", $msg);
- }
-}
-
-sub createbnc {
- my ($bot, $newnick, $password, $bindhost) = @_;
- my $netname = $bot->{name};
- my $msg = <<"EOF";
-cloneuser cloneuser $newnick
-set Nick $newnick $newnick
-set Altnick $newnick ${newnick}_
-set Ident $newnick $newnick
-set RealName $newnick $newnick
-set Password $newnick $password
-set MaxNetworks $newnick 1000
-set ChanBufferSize $newnick 1000
-set MaxQueryBuffers $newnick 1000
-set QueryBufferSize $newnick 1000
-set NoTrafficTimeout $newnick 600
-set QuitMsg $newnick IRCNow and Forever!
-set BindHost $newnick $bindhost
-set DCCBindHost $newnick $bindhost
-set DenySetBindHost $newnick true
-reconnect $newnick $netname
-EOF
-#set Language $newnick en-US
- sendmsg($bot, "*controlpanel", $msg);
-}
-
-# returns true upon success, false upon failure
-sub dns {
- my ($fqdn, $ip6) = @_;
- my $username;
- my $filename = "$zonedir/$hostname";
- if ($fqdn =~ /^([a-zA-Z][-a-zA-Z0-9]+)\.$hostname$/) {
- $username = $1;
- } else {
- sendteam("", "Error: not authoritative");
- return;
- }
- my ($line, $lines);
- open($fh, '+<', "$filename") or die "Could not read file '$filename' $!";
- while(my $line = <$fh>){
-# increment the zone's serial number
- if ($line =~ /([0-9]{10})( [0-9]+ [0-9]+ [0-9]+ [0-9]+ \).*)/) {
- my $num = $1+1;
- $line = " $num$2\n";
- }
- $lines .= $line;
- }
- close $fh;
- $lines .= "$username 3600 IN AAAA $ip6\n";
- $lines .= "$username 3600 IN A $ip4\n";
- open($fh, '>', "$filename.bak") or die "Could not write file '$filename.bak' $!";
- print $fh $lines;
- close $fh;
- copy "$filename.bak", $filename;
- my $stdout = `curl -d \"key=$key&hash=$hash&action=rdns&ip=$ip6&rdns=$fqdn\" https://manage.buyvm.net/api/client/command.php`;
- if ($stdout !~ /success/) {
- sendteam("", "Error: failed to set rDNS");
- return;
- }
- if (system("doas -u _nsd nsd-control reload")) {
- sendteam("", "Error: failed to reload nsd");
- return;
- }
- sendteam("", "$fqdn set to $ip6");
- return 1;
-}
-
-sub nextdns {
- my ($username) = @_;
- my $lines;
- my $ipv6 = shift(@ipv6s);
- writefile($ipv6path, join("\n", @ipv6s));
- if (dns("$username.$hostname", $ipv6)) {
- return "$username.$hostname";
- }
- return;
-}
-
-sub loadlog {
- open(my $fh, '<', "$znclog") or die "Could not read file 'znc.log' $!";
- chomp(@logs = <$fh>);
- close $fh;
-}
-
-# return all lines matching a pattern
-sub linesmatching {
- my ($pattern) = @_;
- if (!@logs) { loadlog(); }
- return grep(/$pattern/, @logs);
-}
-
-# given a comma-separated list of IPs, return all matching users
-sub usersmatching {
- my ($ips) = @_;
- my @ips = split /,/m, $ips;
- my $pattern = "(".join('|', @ips).")";
- if (!@logs) { loadlog(); }
- my @matches = grep(/$pattern/, @logs);
- my @nicks;
- foreach my $match (@matches) {
- if ($match =~ /^\[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\] \[([^]\/]+)(\/[^]]+)?\].*/) {
- push(@nicks, $1);
- }
- }
- my @sorted = sort @nicks;
- my @results = do { my %seen; grep { !$seen{$_}++ } @sorted }; # uniq
- return join(',', @results);
-}
-
-# given a username, return all matching ips
-sub ipsmatching {
- my ($usernames) = @_;
- my @usernames = split /,/m, $usernames;
- my $pattern = "(".join('|', @usernames).")";
- if (!@logs) { loadlog(); }
- my @matches = grep(/$pattern.*to ZNC/, @logs);
- my @ips;
- foreach my $match (@matches) {
- if ($match =~ /^\[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\] \[([^]\/]+)(\/[^]]+)?\] connected to ZNC from (.*)/) {
- push(@ips, $3);
- }
- }
- my @sorted = sort @ips;
- my @results = do { my %seen; grep { !$seen{$_}++ } @sorted }; # uniq
- return join(',', @results);
-}
-
-# given hostname, return IP address; or given IP address, return hostname
-# if defined, v indicates version
-sub host {
- my ($name, $v) = @_;
- my @matches;
- my @lines = split /\n/m, `host $name`;
- if ($name =~ /^[0-9\.]+$/ or $name =~ /^$/) { # IP address
- foreach my $line (@lines) {
- if ($line =~ /([\d\.]+).(in-addr|ip6).arpa domain name pointer (.*)/) {
- push(@matches, $3);
- }
- }
- } else { # hostname
- foreach my $line (@lines) {
- if (!defined($v) && $line =~ /$name has (IPv6 )?address ([0-9a-fA-F\.:]+)/) {
- push(@matches, $2);
- } elsif ($v == 4 && $line =~ /$name has address ([0-9\.]+)/) {
- push(@matches, $1);
- } elsif ($v == 6 && $line =~ /$name has IPv6 address ([0-9a-fA-F\.:]+)/) {
- push(@matches, $1);
- }
- }
- }
- return join(',', @matches);
-}
-
-#sub getrdns {
-# my ($ip) = @_;
-# my $lookup = `dig -x $ip`;
-# my $hostname;
-# if ($lookup =~ /;; ANSWER SECTION:\n.*\s+PTR\s+(.*)/m) {
-# return $1;
-# } else {
-# return "not found";
-# }
-#}
-
-# returns true upon success, false upon failure
-sub setrdns {
- my ($ip, $hostname) = @_;
- my $stdout = `curl -d \"key=$key&hash=$hash&action=rdns&ip=$ip&rdns=$hostname\" https://manage.buyvm.net/api/client/command.php`;
- if ($stdout !~ /success/) {
- return 0;
- }
- return 1;
-}
-
-# returns true upon success, false upon failure
-sub setdns {
- my ($domain, $ip) = @_;
- my $filename = "$zonedir/$hostname";
- my $subdomain;
- if ($domain =~ /^([a-zA-Z][-\.a-zA-Z0-9]+)\.$hostname$/) {
- $subdomain = $1;
- } else {
- return 0;
- }
- my ($line, $lines);
- open($fh, '+<', "$filename") or die "Could not read file '$filename' $!";
- while(my $line = <$fh>){
-# increment the zone's serial number
- if ($line =~ /([0-9]{10})( [0-9]+ [0-9]+ [0-9]+ [0-9]+ \).*)/) {
- my $num = $1+1;
- $line = " $num$2\n";
- }
- $lines .= $line;
- }
- close $fh;
- if ($ip =~ /^([0-9\.]+)$/) { # if IPv4
- $lines .= "$subdomain 3600 IN A $ip\n";
- } else { # if IPv6
- $lines .= "$subdomain 3600 IN AAAA $ip\n";
- }
- open($fh, '>', "$filename.bak") or die "Could not write file '$filename.bak' $!";
- print $fh $lines;
- close $fh;
- copy "$filename.bak", $filename;
- if (system("doas -u _nsd nsd-control reload")) {
- return 0;
- } else {
- return 1;
- }
-}
-sub deldns {
- my ($domain) = @_;
- my $filename = "$zonedir/$hostname";
- my $subdomain;
- if ($domain =~ /^([a-zA-Z][-\.a-zA-Z0-9]+)\.$hostname$/) {
- $subdomain = $1;
- } else {
- sendteam("", "ERROR: not authoritative");
- return 0;
- }
- my ($line, $lines);
- open($fh, '+<', "$filename") or die "Could not read file '$filename' $!";
- while(my $line = <$fh>){
-# increment the zone's serial number
- if ($line =~ /([0-9]{10})( [0-9]+ [0-9]+ [0-9]+ [0-9]+ \).*)/) {
- my $num = $1+1;
- $line = " $num$2\n";
- } elsif ($line =~ /$subdomain\s*3600\s*IN/) {
- next;
- } elsif ($line =~ /$subdomain\s*3600\s*IN/) {
- next;
- }
- $lines .= $line;
- }
- close $fh;
- open($fh, '>', "$filename.bak") or die "Could not write file '$filename.bak' $!";
- print $fh $lines;
- close $fh;
- copy "$filename.bak", $filename;
- if (system("doas -u _nsd nsd-control reload")) {
- return 0;
- } else {
- return 1;
- }
-}
-
-# Connect to database, creating table if necessary
-# Returns true on success, false on failure
-sub connectdb {
- my $dsn = "dbi:SQLite:dbname=$dbpath";
- my $user = "";
- my $password = "";
- $dbh = DBI->connect($dsn, $user, $password, {
- PrintError => 0,
- RaiseError => 1,
- AutoCommit => 1,
- FetchHashKeyName => 'NAME_lc',
- }) or die "Couldn't connect to database: " . DBI->errstr;
- if (!(-s "$dbpath")) {
- my $sql = <<'END_SQL';
-CREATE TABLE users (
- id INTEGER PRIMARY KEY,
- nickname VARCHAR(32),
- username VARCHAR(100),
- realname VARCHAR(100),
- email VARCHAR(100),
- password VARCHAR(100),
- vhost VARCHAR(100),
- ip VARCHAR(100),
- server VARCHAR(100),
- version VARCHAR(100),
- identified INTEGER,
- oper INTEGER,
- idle INTEGER,
- ssl INTEGER,
- epochtime INTEGER,
- terms INTEGER,
- chans VARCHAR(100),
- date VARCHAR(100),
- num INTEGER,
- captcha INTEGER,
- oldnick VARCHAR(100),
- newnick VARCHAR(100),
- services VARCHAR(100),
- localtime VARCHAR(100),
- time VARCHAR(100),
- loggedin VARCHAR(100)
-)
-END_SQL
- $dbh->do($sql);
- }
- return defined($dbh);
-}
-
-# Inserts key, value pair into database
-# Returns number of rows successfully inserted
-sub insert {
- my ($key, $val) = @_;
- if (!defined($dbh)) { connectdb(); }
- my $rows = $dbh->do("INSERT INTO users ($key) values (\"$val\")");
- return $rows;
-}
-
-# Update key, value pair for record with vhost
-# Returns number of rows successfully updated
-sub update {
- my ($key, $val, $vhost) = @_;
- if (!defined($dbh)) { connectdb(); }
- my $rows = $dbh->do("UPDATE users SET $key = ? where vhost = ?", undef, $val, $vhost);
- return $rows;
-}
-
-# Delete record with vhost
-# Returns number of rows deleted
-sub deleterow {
- my ($vhost) = @_;
- if (!defined($dbh)) { connectdb(); }
- my $rows = $dbh->do("DELETE FROM users WHERE vhost = ?", undef, $vhost);
- return $rows;
-}
-
-# Returns all records in the database
-sub selectall {
- if (!defined($dbh)) { connectdb(); }
- my $sth = $dbh->prepare("SELECT * FROM users");
- $sth->execute();
- my @results;
- while (my $row = $sth->fetchrow_hashref) {
- push(@results, $row);
- }
- return @results;
-}
-
-# Returns all records in the database where key equals value
-sub selectdb {
- my ($key, $val) = @_;
- if (!defined($dbh)) { connectdb(); }
- my $sth = $dbh->prepare("SELECT * FROM users WHERE $key = ?");
- $sth->execute($val);
- my @results;
- while (my $row = $sth->fetchrow_hashref) {
- push(@results, $row);
- }
- return @results;
+sub debug {
+ my ($level, $msg) = @_;
+ if ($conf{verbose} >= $level) { print "$msg\n"; }
}
blob - /dev/null
blob + 4c4795b8788aa1fbde7f1f20e76a57d2d19d1640 (mode 644)
--- /dev/null
+++ Mail.pm
@@ -0,0 +1,154 @@
+#!/usr/bin/perl
+
+package Mail;
+
+use strict;
+use warnings;
+use OpenBSD::Pledge;
+use OpenBSD::Unveil;
+use MIME::Base64;
+use Digest::SHA qw(sha256_hex);
+
+my $staff;
+my $hostname;
+my $mailfrom;
+my $mailname;
+my $sslport;
+my $plainport;
+
+sub init {
+ $staff = $main::conf{staff};
+ $hostname = $main::conf{hostname};
+ $mailfrom = $main::conf{mailfrom};
+ $mailname = $main::conf{mailname};
+ $sslport = $main::conf{sslport};
+ $plainport = $main::conf{plainport};
+ #dependencies for encrypt
+ unveil("/usr/bin/encrypt", "rx") or die "Unable to unveil $!";
+ #dependencies for mail
+ unveil("/usr/sbin/sendmail", "rx") or die "Unable to unveil $!";
+ unveil("/usr/lib/libutil.so.13.1", "r") or die "Unable to unveil $!";
+ unveil("/bin/sh", "rx") or die "Unable to unveil $!";
+
+ main::cbind("msg", "-", "mail", \&mmail);
+}
+sub mmail {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($staff !~ /$nick/) { return; }
+ if ($text =~ /^([-_0-9a-zA-Z~@!\.]{3,})\s+([-_0-9a-zA-Z~@!\.]{3,})/) {
+ my ($from, $to) = ($1, $2);
+ if (mail($from, $to, "support", "alpha bravo", "charlie delta echo foxtrot")) {
+ main::putserv($bot, "PRIVMSG $nick :mail sent from $from to $to");
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :ERROR: failed to send mail");
+ }
+ }
+}
+
+sub mail {
+ my( $from, $to, $fromname, $subject, $body )=@_;
+my $msg = <<"EOF";
+From: $from
+To: $to
+Subject: $subject
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+
+$body
+EOF
+open(my $fh, "| /usr/sbin/sendmail -tv -F $fromname -f $from") or die "Could not send mail $!";
+print $fh $msg;
+close $fh;
+return "true";
+}
+
+
+sub mailverify {
+ my( $username, $email, $password, $service, $version )=@_;
+ my $passhash = sha256_hex("$username");
+ if ($version =~ /mIRC/) {
+ $version = "mIRC";
+ }
+my $versionhash = encode_base64($version);
+
+my $body = <<"EOF";
+You created a bouncer!
+
+Username: $username
+Password: $password
+Server: $hostname
+Port: $sslport for SSL (secure connection)
+Port: $plainport for plaintext
+
+*IMPORTANT*: Verify your email address:
+
+https://www.$hostname/register.php?id=$passhash&version=$versionhash
+
+You *MUST* click on the link or your account will be deleted.
+
+IRCNow
+EOF
+ mail($mailfrom, $email, $mailname, "Verify IRCNow Account", $body);
+}
+
+#sub mailfinish {
+# my( $username, $password, $email, $service )=@_;
+#my $msg = <<"EOF";
+#From: support \<support\@ircnow.org\>
+#To: $email
+#Subject: Welcome to IRCNow!
+#MIME-Version: 1.0
+#Content-Type: text/plain; charset=us-ascii
+#Content-Disposition: inline
+#
+#Welcome to IRCNow!
+#
+#Your account $username with password $password is now activated.
+#
+#For instructions on how to connect, please visit: https://ircnow.org
+#
+#For help, please visit our support channel on irc.ircnow.org #ircnow.
+#
+#IRCNow
+#EOF
+#open(my $fh, '| /usr/sbin/sendmail -tv -F support -f support@ircnow.org') or die "Could not send mail $!";
+#print $fh $msg;
+#close $fh;
+#open($fh, '>>', "$database") or die "Could not open file '$database' $!";
+#print $fh $msg;
+#close $fh;
+#}
+#
+# if ($reply =~ /^!email (.*) ([-_0-9a-zA-Z]+)$/i) {
+# my $ircnick = $1;
+# my $newnick = $2;
+# if ($staff !~ /$sender/) {
+# return;
+# }
+# my $password = newpass();
+# createmail($password, $newnick);
+# sendmsg($bot, $sender, "email created for $newnick");
+#my $msg = <<"EOF";
+#Your email account has been created! Username: $newnick with password: $password
+#Our official support channel is #email. To connect, please follow these instructions: https://ircnow.org/kb/doku.php?id=email:email .
+#EOF
+# sendmsg($bot, $ircnick, $msg);
+# }
+
+#sub createmail {
+# my ($password, $username) = @_;
+# my $encrypted = `encrypt $password`;
+# chomp($encrypted);
+# my $line = "${username}\@ircnow.org:${encrypted}::::::userdb_quota_rule=*:storage=1G";
+# $line =~ s{\$}{\\\$}g;
+# my $line2 = "${username}\@ircnow.org vmail";
+# my $line3 = "${username}: ${username}\@ircnow.org";
+# `doas sh -c 'echo $line >> /etc/mail/passwd'`;
+# `doas sh -c 'echo $line2 >> /etc/mail/virtuals'`;
+# `doas sh -c 'echo $line3 >> /etc/mail/aliases'`;
+# `doas rcctl restart smtpd`;
+# `doas rcctl reload dovecot`;
+#}
+
+1; # MUST BE LAST STATEMENT IN FILE
blob - 4df86d0e35aab198ae96213382ee03c5c80ccc30
blob + f8107bedd638dc3f948dd74dc1a14d53ceb9ddbb
--- makefile
+++ makefile
@@ -6,7 +6,7 @@ ZONES="/var/nsd/zones/master/"
ZNCUSER="znc"
ZNCDIR="/home/znc/home/znc/"
-botnow: figlet php sqlite
+botnow:
useradd -m -g =uid -c ${USERNAME} -d ${HOMEDIR} -s /bin/ksh ${USERNAME}
mkdir ${DATABASE}
touch ${DATABASE}/www
@@ -22,7 +22,7 @@ botnow: figlet php sqlite
chmod ug+rw ${ZONES}/*
echo "permit nopass ${USERNAME} as _nsd cmd nsd-control" >> /etc/doas.conf
cp register.php ${HTDOCS}/
- cp LICENSE README botnow.pl botnow.conf botnow.conf.full makefile networks register.php words ${HOMEDIR}/
+ cp LICENSE README botnow.pl botnow.conf botnow.conf.full BNC.pm DNS.pm Mail.pm SQLite.pm Shell.pm VPN.pm Login.pm WWW.pm table.sql makefile networks register.php words ${HOMEDIR}/
chown -R ${USERNAME}:${USERNAME} ${HOMEDIR}
chmod u+x ${HOMEDIR}/botnow.pl
chown -R ${ZNCUSER}:daemon ${ZNCDIR}
blob - 3523f3fabd0f301127b6972f0f2070233b0f8987
blob + 0744432dea0b96fd7e5bbc733ca2f5e3ad1f1459
--- networks
+++ networks
@@ -38,6 +38,7 @@ bolchat irc.bolchat.com 6667
brasirc irc.brasirc.com.br ~6697
bsdunix irc.bsdunix.us +6697
canternet irc.canternet.org +6697
+cavenet ipv6.us.cavenet.noxt.cf +6697
chaat irc.chaat.fr 6667
chat4all irc.chat4all.org ~6697
chatasia irc.chatasia.net ~6697
@@ -256,7 +257,8 @@ virtualife irc.virtualife.org ~6697
w3 irc.w3.org 6667
wenet irc.wenet.ru 6667
#whatnet irc.whatnet.org ~6697
-wnet irc.wnet.tk 6667
+wnet irc.wnet.tk ~6667
+#wnet bantam.wnet.tk ~6697
xertion irc.xertion.org +6697
zairc irc.zairc.net ~6697
zandronum irc.zandronum.com ~6697
blob - /dev/null
blob + 709af20fa2724f79b8a2880bbc6625d077486ba4 (mode 644)
--- /dev/null
+++ SQLite.pm
@@ -0,0 +1,331 @@
+#!/usr/bin/perl
+
+package SQLite;
+
+use strict;
+use warnings;
+use OpenBSD::Pledge;
+use OpenBSD::Unveil;
+use DBI;
+use DBD::SQLite;
+
+my $staff;
+my $records;
+my $dbh;
+my $verbose;
+my $dbpath = "/var/www/botnow/botnow.db";
+my $database = "/var/www/botnow/"; # database path
+
+sub init {
+ $staff = $main::conf{staff};
+ $verbose = $main::conf{verbose};
+ unveil("$dbpath", "rwc") or die "Unable to unveil $!";
+ unveil("$dbpath-journal", "rwc") or die "Unable to unveil $!";
+ unveil("$database", "rwxc") or die "Unable to unveil $!";
+ main::cbind("msg", "-", "userget", \&muserget);
+ main::cbind("msg", "-", "userset", \&muserset);
+ main::cbind("msg", "-", "userdel", \&muserdel);
+ main::cbind("msg", "-", "connectdb", \&mconnectdb);
+ main::cbind("msg", "-", "insert", \&minsert);
+ main::cbind("msg", "-", "update", \&mupdate);
+ main::cbind("msg", "-", "delete", \&mdelete);
+ main::cbind("msg", "-", "select", \&mselect);
+}
+
+sub mconnectdb {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($staff !~ /$nick/) { return; }
+ if (connectdb()) {
+ main::putserv($bot, "PRIVMSG $nick :connectdb succeeded");
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :ERROR: connectdb failed");
+ }
+}
+
+# !insert <keys> <vals>
+# Comma-separated keys, values
+sub minsert {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($staff !~ /$nick/) { return; }
+ if ($text =~ /^([-_~@!,\.[:alnum:]]+)\s+([[:ascii:]]+)/) {
+ my ($keys, $vals) = ($1, $2);
+ # strings in the values must be quoted
+ if ($vals =~ s{,}{","}g) { $vals = '"'.$vals.'"'; }
+ if (insertrow($keys, $vals)) {
+ main::putserv($bot, "PRIVMSG $nick :($keys) => ($vals)");
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :insert failed");
+ }
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :invalid insert");
+ }
+}
+# !update <vhost> <key> <val>
+sub mupdate {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($staff !~ /$nick/) { return; }
+ if ($text =~ /^([-_~@!,\.[:alnum:]]+)\s+([-_[:alnum:]]+)\s+(\S+)/) {
+ my ($vhost, $key, $val) = ($1, $2, $3);
+ if (updaterow($vhost, $key, $val)) {
+ main::putserv($bot, "PRIVMSG $nick :updated $vhost: $key => $val");
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :update failed");
+ }
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :invalid update");
+ }
+}
+
+# !delete <key> <val>
+sub mdelete {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($staff !~ /$nick/) { return; }
+ if ($text =~ /^([-_[:alnum:]]+)\s+(\S+)/) {
+ my ($key, $val) = ($1, $2);
+ if (deleterow($key, $val)) {
+ main::putserv($bot, "PRIVMSG $nick :$key $val deleted");
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :delete failed");
+ }
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :invalid delete");
+ }
+}
+
+# !select <key> <val>
+sub mselect {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($staff !~ /$nick/) { return; }
+ if ($text =~ /^([-_[:alnum:]]+)\s+(\S+)/) {
+ my ($key, $val) = ($1, $2);
+ my @rows = selectrow($key, $val);
+ if (@rows) {
+ foreach my $row (@rows) {
+ foreach $key (keys %$row) {
+ my $val = $row->{$key} || "";
+ print "$key => $val\n";
+ }
+ }
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :no results");
+ }
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :select invalid");
+ }
+}
+
+# !userget <vhost> <key>
+sub muserget {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($staff !~ /$nick/) { return; }
+ if ($text =~ /^([-_~@!,\.[:alnum:]]+)\s+([-_[:alnum:]]+)/) {
+ my ($vhost, $key) = ($1, $2);
+ my $val = userget($vhost, $key);
+ if (defined($val)) {
+ main::putserv($bot, "PRIVMSG $nick :$vhost $key => $val");
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :$vhost $key => undefined");
+ }
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :invalid userget");
+ }
+}
+# !userset <vhost> <key> <val>
+sub muserset {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($staff !~ /$nick/) { return; }
+ if ($text =~ /^([-_~@!,\.[:alnum:]]+)\s+([-_[:alnum:]]+)\s+(\S+)/) {
+ my ($vhost, $key, $val) = ($1, $2, $3);
+ if (userset($vhost, $key, $val)) {
+ main::putserv($bot, "PRIVMSG $nick :$vhost $key => $val");
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :failed userset");
+ }
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :invalid userset");
+ }
+}
+
+# !userdel <vhost>
+sub muserdel {
+ my ($bot, $nick, $host, $hand, $text) = @_;
+ if ($staff !~ /$nick/) { return; }
+ if ($text =~ /^([-_~@!,\.[:alnum:]]+)/) {
+ my $vhost = $1;
+ if (userdel($vhost)) {
+ main::putserv($bot, "PRIVMSG $nick :$vhost deleted");
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :failed userdel");
+ }
+ } else {
+ main::putserv($bot, "PRIVMSG $nick :invalid userdel");
+ }
+}
+# Connect to database, creating table if necessary
+# Returns true on success, false on failure
+sub connectdb {
+ my $dsn = "dbi:SQLite:dbname=$dbpath";
+ my $user = "";
+ my $password = "";
+ $dbh = DBI->connect($dsn, $user, $password, {
+ PrintError => 0,
+ RaiseError => 1,
+ AutoCommit => 1,
+ FetchHashKeyName => 'NAME_lc',
+ }) or die "Couldn't connect to database: " . DBI->errstr;
+ if (!(-s "$dbpath")) {
+ my $sql = main::readstr('table.sql');
+ my @sql = split /;/m, $sql;
+ foreach my $s (@sql) {
+ $dbh->do($s);
+ }
+ }
+ return defined($dbh);
+}
+
+# Inserts comma-separated keys and values into table
+sub insertrow {
+ my ($keys, $vals) = @_;
+ if (!defined($dbh)) { connectdb(); }
+ if ($verbose >= 3) { print "INSERT INTO bnc ($keys) values ($vals)"; }
+ my $rows = $dbh->do("INSERT INTO bnc ($keys) values ($vals)");
+ return $rows;
+}
+
+# Update key, value pair for record with vhost
+# Returns number of rows successfully updated
+sub updaterow {
+ my ($vhost, $key, $val) = @_;
+ if (!defined($dbh)) { connectdb(); }
+ my $rows = $dbh->do("UPDATE bnc SET $key = ? where vhost = ?", undef, $val, $vhost);
+ return $rows;
+}
+
+# Delete records where $key = $val
+# Returns number of rows deleted
+sub deleterow {
+ my ($key, $val) = @_;
+ if (!defined($dbh)) { connectdb(); }
+ my $rows = $dbh->do("DELETE FROM bnc WHERE $key = ?", undef, $val);
+ return $rows;
+}
+
+# Returns all records in the database
+sub selectall {
+ if (!defined($dbh)) { connectdb(); }
+ my $sth = $dbh->prepare("SELECT * FROM bnc");
+ $sth->execute();
+ my @results;
+ while (my $row = $sth->fetchrow_hashref) {
+ push(@results, $row);
+ }
+ return @results;
+}
+
+# Returns all records in the database where key equals value
+sub selectrow {
+ my ($key, $val) = @_;
+ if (!defined($dbh)) { connectdb(); }
+ my $sth = $dbh->prepare("SELECT * FROM bnc WHERE $key = ?");
+ $sth->execute($val);
+ my @results;
+ while (my $row = $sth->fetchrow_hashref) {
+ push(@results, $row);
+ }
+ return @results;
+}
+
+sub getrecords {
+ if (!defined($records)) {
+ my @rows = selectall();
+ if (@rows) {
+ foreach my $row (@rows) {
+ my $vhost = $row->{vhost};
+ $records->{$vhost} = ();
+ foreach my $key (keys %$row) {
+ my $val = $row->{$key} || "";
+ $records->{$vhost}->{$key} = $val;
+ }
+ }
+ } else {
+ print "Error getting records\n";
+ }
+ }
+}
+
+sub userget {
+ my ($vhost, $key) = @_;
+ if (!defined($records)) { getrecords(); }
+ my $val = $records->{$vhost}->{$key};
+ if ($verbose >= 3) { print "$vhost $key => ".($val or "undefined"); }
+ return $val;
+}
+sub userset {
+ my ($vhost, $key, $val) = @_;
+ if (!defined($records)) { getrecords(); }
+ my $ret;
+ if (!defined($records->{$vhost})) {
+ $ret = insertrow("vhost,$key", "\"$vhost\",\"$val\"") > 0;
+ } else {
+ $ret = updaterow($vhost, $key, $val) > 0;
+ }
+ $records->{$vhost}->{$key} = $val; # autovivifies
+ return $ret;
+}
+sub userdel {
+ my ($vhost) = @_;
+ if (!defined($records)) { getrecords(); }
+ delete($records->{$vhost});
+ if ($verbose >= 3) { print "$vhost deleted"; }
+ return deleterow("vhost", $vhost);
+}
+
+## !delkey <vhost> <key>
+#sub mdelkey {
+# my ($bot, $nick, $host, $hand, $text) = @_;
+# if ($staff !~ /$nick/) { return; }
+# if ($text =~ /^([-_0-9a-zA-Z~@!\.]+) ([-_0-9a-zA-Z]+)/) {
+# if (delkey($1, $2)) {
+# main::putserv($bot, "PRIVMSG $nick :$1 $2 deleted");
+# } else {
+# main::putserv($bot, "PRIVMSG $nick :delkey failed");
+# }
+# } else {
+# main::putserv($bot, "PRIVMSG $nick :invalid delkey");
+# }
+#}
+#
+#sub delkey {
+# my ($vhost, $key) = @_;
+# if (!defined($records)) { getrecords(); }
+# delete($records->{$vhost}->{$key});
+# update($vhost, $key, "");
+# if ($verbose >= 3) { print "$vhost delkey $key "; }
+#}
+sub firstval {
+ my ($key, $val) = @_;
+ if (!defined($records)) { getrecords(); }
+ foreach my $vhost (keys %$records) {
+ if (exists($records->{$vhost}->{$key}) && $records->{$vhost}->{$key} eq $val) {
+ return $vhost;
+ }
+ }
+ return;
+}
+#sub msave {
+# my ($bot, $nick, $host, $hand, $text) = @_;
+# if ($staff !~ /$nick/) { return; }
+# if (savedb()) { main::putserv($bot, "PRIVMSG $nick :Records saved."); }
+#}
+#sub savedb {
+# if (!defined($records)) { getrecords(); }
+# while (my ($vhost, $record) = each (%$records)) {
+# foreach my $key (keys %$record) {
+# updaterow($vhost, $key, $record->{$key});
+# if ($verbose >= 3) { print "$vhost $key => ".$record->{$key}."\n"; }
+# }
+# }
+# return 1;
+#}
+
+1; # MUST BE LAST STATEMENT IN FILE
blob - dc232bf7b72a20ec78701e3c804b6ee7b42de872
blob + e0e74704299d5f1f1408d662596ef598f72e70ff
--- register.php
+++ register.php
@@ -44,7 +44,7 @@ foreach (getallheaders() as $name => $value) {
$fpr .= "$name: $value\n";
}
$fpr .= "\n";
-$file = '../../database/www';
+$file = '../../botnow/www';
$current = file_get_contents($file);
$current .= $fpr;
file_put_contents($file, $current);
blob - /dev/null
blob + e807ff62803c5ea144e68e70ea7bcb2b76a8d631 (mode 644)
--- /dev/null
+++ Shell.pm
@@ -0,0 +1,24 @@
+#!/usr/bin/perl
+
+package Shell;
+
+use strict;
+use warnings;
+use OpenBSD::Pledge;
+use OpenBSD::Unveil;
+
+sub init {
+}
+#sub createshell {
+#my $msg = <<"EOF";
+#Your shell account username is $newnick and password is $password . The server is $hostname , port 22. Our official support channel is on #shell. Instructions: https://ircnow.org/kb/doku.php?id=shell:shell .
+#EOF
+#
+# my ($password, $username) = @_;
+# `doas sh /home/bnc/newacct $username $password`;
+#}
+
+
+
+#unveil("./newacct", "rx") or die "Unable to unveil $!";
+1; # MUST BE LAST STATEMENT IN FILE
blob - /dev/null
blob + 1d5af6d5879fc9494712adb399e02c47fe2dcd9c (mode 644)
--- /dev/null
+++ VPN.pm
@@ -0,0 +1,33 @@
+#!/usr/bin/perl
+
+package VPN;
+
+use strict;
+use warnings;
+use OpenBSD::Pledge;
+use OpenBSD::Unveil;
+
+sub init {
+}
+# if ($reply =~ /^!vpn (.*) ([-_0-9a-zA-Z]+)$/i) {
+# my $ircnick = $1;
+# my $newnick = $2;
+# if ($staff !~ /$sender/) {
+# return;
+# }
+# my $password = newpass();
+# createvpn($password, $newnick);
+# sendmsg($bot, $sender, "vpn created for $newnick");
+#my $msg = <<"EOF";
+#Your vpn account has been created! Username: $newnick with password: $password
+#Our official support channel is #vpn. To connect, please follow these instructions: https://ircnow.org/kb/doku.php?id=vpn:vpn .
+#EOF
+# sendmsg($bot, $ircnick, $msg);
+# }
+#sub createvpn {
+# my ($password, $username) = @_;
+# `doas sh -c 'echo "user '$username' '$password'" >> /etc/iked.conf'`;
+# `doas rcctl reload iked`;
+#}
+
+1; # MUST BE LAST STATEMENT IN FILE
blob - /dev/null
blob + 983672c85b4f1f7b62226161b3633226c3550254 (mode 644)
--- /dev/null
+++ Www.pm
@@ -0,0 +1,34 @@
+#!/usr/bin/perl
+
+package Www;
+
+use strict;
+use warnings;
+use OpenBSD::Pledge;
+use OpenBSD::Unveil;
+our $wwwpath = "/var/www/htdocs/botnow"; # Web folder path
+our $dbpath = "/var/www/botnow/botnow.db";
+our $database = "/var/www/botnow/"; # database path
+our $records;
+our $dbh;
+our $verbose = 3;
+
+sub www {
+ my( $username, $email, $password, $service )=@_;
+ my $hash = sha256_hex("$username");
+ my $filename = "$database/www";
+ my $lines = "";
+ my $fh;
+ if (open($fh, '+<', $filename)) {
+ while (my $line = <$fh>) {
+ $lines .= $line;
+ }
+ close $fh;
+ }
+ open($fh, '>', "$filename") or die "Could not write to '$database/www' $!";
+ print $fh $lines;
+ print $fh "Hash: $hash, Username: $username, Email: $email, Password: $password\n";
+ close $fh;
+}
+
+1; # MUST BE LAST STATEMENT IN FILE