commit 3a155d6064f7abfab12f1180241034ee90cee30b from: jrmu date: Sun Mar 05 23:51:05 2023 UTC Adding Mail support commit - c54830adcfff9e7ec910825ace159fcabf5ed456 commit + 3a155d6064f7abfab12f1180241034ee90cee30b blob - 6df39f6f4e394386d6b4ef5fb28988e72d15246c blob + 2c188f068502084d0c556c4cbe4d43ab62076987 --- Help.pm +++ Help.pm @@ -28,13 +28,14 @@ sub help { $terms To request a free bouncer, type !bnc . For example, !bnc john john\@example.com. To request a free shell account, type !shell . For example, !shell john john\@example.com. +To request a free email account, type !mail . For example, !mail john john\@example.com. EOF -#To request a free email account, type !email . For example, !email john john\@example.com. #To request a free VPN account, type !vpn . For example, !vpn john john\@example.com. if (main::isstaff($bot, $nick)) { $msg .= <<"EOF"; To delete a bouncer, type !bnc delete To verify a captcha, type !bnc captcha +To approve a bouncer, type !bnc approve To recreate cloneuser, type !bnc cloneuser To get a list of usernames that match IPs, type !regex ips To get a list of IPs that match usernames, type !regex users blob - 783bd370cc80eaccb3c1fbdaa6748c3e8abcf3a1 blob + 9c0569f1a8a5e9525edf63df0cf86f3691a208e4 --- Mail.pm +++ Mail.pm @@ -24,17 +24,137 @@ sub init { unveil("/usr/lib/libutil.so.13.1", "r") or die "Unable to unveil $!"; unveil("/bin/sh", "rx") or die "Unable to unveil $!"; } + 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"); + 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 ($text =~ /^$/) { + main::putserv($bot, "PRIVMSG $nick :Type !help for new instructions"); + foreach my $chan (@teamchans) { + main::putservlocalnet($bot, "PRIVMSG $chan :$staff: Help *$nick* on network ".$bot->{name}); } + return; + } elsif (main::isstaff($bot, $nick) && $text =~ /^delete\s+([[:ascii:]]+)/) { + my $username = $1; + if (SQLite::deleterows("mail", "username", $username)) { + deletemail($username); + foreach my $chan (@teamchans) { + main::putserv($bot, "PRIVMSG $chan :$username email deleted"); + } + } + return; + } elsif (main::isstaff($bot, $nick) && $text =~ /^approve\s+([[:ascii:]]+)/) { + my $username = $1; + ### TODO: Unblock account ### + foreach my $chan (@teamchans) { + main::putserv($bot, "PRIVMSG $chan :$username mail approved"); + } + return; } + ### Check duplicate hostmasks ### + my @rows = SQLite::selectrows("irc", "hostmask", $hostmask); + foreach my $row (@rows) { + my $password = SQLite::get("mail", "ircid", $row->{id}, "password"); + if (defined($password)) { + main::putserv($bot, "PRIVMSG $nick :Sorry, only one account per person. Please contact staff if you need help."); + return; + } + } + + if ($text =~ /^captcha\s+([[:alnum:]]+)/) { + my $text = $1; + # TODO avoid using host mask because cloaking can cause problems + my $ircid = SQLite::id("irc", "nick", $nick, $expires); + my $captcha = SQLite::get("mail", "ircid", $ircid, "captcha"); + if ($text ne $captcha) { + main::putserv($bot, "PRIVMSG $nick :Wrong captcha. To get a new captcha, type !mail "); + return; + } + my $pass = Hash::newpass(); + chomp(my $encrypted = `encrypt $pass`); + my $username = SQLite::get("mail", "ircid", $ircid, "username"); + my $email = SQLite::get("mail", "ircid", $ircid, "email"); + my $hashirc = SQLite::get("irc", "id", $ircid, "hashid"); + my $bindhost = "$username.$hostname"; + SQLite::set("mail", "ircid", $ircid, "password", $encrypted); + sleep(2); + createmail($pass, $username); + main::putserv($bot, "PRIVMSG $nick :Check your email!"); + mailmail($username, $pass, $email); + if ($approval eq "true") { + ### TODO: Block account ### + main::putserv($bot, "PRIVMSG $nick :Your account has been created but must be manually approved by your admins ($staff) before it can be used."); + foreach my $chan (@teamchans) { + main::putservlocalnet($bot, "PRIVMSG $chan :$staff: $nick\'s account $username must be manually unblocked before it can be used."); + } + } + foreach my $chan (@teamchans) { + main::putservlocalnet($bot, "PRIVMSG $chan :$nick\'s mail registration of $username@$hostname on $bot->{name} was successful, please help him connect"); + } + #www($newnick, $reply, $password, "bouncer"); + return; + } elsif ($text =~ /^([[:alnum:]]+)\s+([[:ascii:]]+)/) { + my ($username, $email) = ($1, $2); + my @userrows = SQLite::selectrows("mail", "username", $username); + foreach my $row (@userrows) { + my $password = SQLite::get("mail", "ircid", $row->{id}, "password"); + if (defined($password)) { + main::putserv($bot, "PRIVMSG $nick :Sorry, only one account per person. Please contact staff if you need help."); + return; + } + } + my @emailrows = SQLite::selectrows("mail", "email", $email); + foreach my $row (@userrows) { + my $password = SQLite::get("mail", "ircid", $row->{id}, "password"); + if (defined($password)) { + main::putserv($bot, "PRIVMSG $nick :Sorry, only one account per person. Please contact staff if you need help."); + return; + } + } + +# my @users = treeget($znctree, "User", "Node"); + foreach my $user (@users) { + if ($user eq $username) { + main::putserv($bot, "PRIVMSG $nick :Sorry, username taken. Please contact staff if you need help."); + return; + } + } + + #my $captcha = join'', map +(0..9,'a'..'z','A'..'Z')[rand(10+26*2)], 1..4; + my $captcha = int(rand(999)); + my $ircid = int(rand(9223372036854775807)); + my $hashid = sha256_hex("$ircid"); + SQLite::set("irc", "id", $ircid, "localtime", time()); + SQLite::set("irc", "id", $ircid, "hashid", sha256_hex($ircid)); + SQLite::set("irc", "id", $ircid, "date", main::date()); + SQLite::set("irc", "id", $ircid, "hostmask", $hostmask); + SQLite::set("irc", "id", $ircid, "nick", $nick); + SQLite::set("mail", "ircid", $ircid, "username", $username); + SQLite::set("mail", "ircid", $ircid, "email", $email); + SQLite::set("mail", "ircid", $ircid, "captcha", $captcha); + SQLite::set("mail", "ircid", $ircid, "hashid", $hashid); + main::whois($bot->{sock}, $nick); + main::ctcp($bot->{sock}, $nick); + main::putserv($bot, "PRIVMSG $nick :".`figlet $captcha`); +#main::putserv($bot, "PRIVMSG $nick :https://$hostname/$hashid/captcha.png"); +#main::putserv($bot, "PRIVMSG $nick :https://$hostname/register.php?hashirc=$hashid"); + main::putserv($bot, "PRIVMSG $nick :Type !mail captcha "); + foreach my $chan (@teamchans) { + main::putservlocalnet($bot, "PRIVMSG $chan :$nick\'s on $bot->{name} mail captcha is $captcha"); + } + } else { + main::putserv($bot, "PRIVMSG $nick :Invalid username or email. Type !mail to try again."); + foreach my $chan (@teamchans) { + main::putservlocalnet($bot, "PRIVMSG $chan :Help *$nick* on ".$bot->{name}); + } + } } sub mail { @@ -56,48 +176,58 @@ return "true"; } -#sub mailfinish { -# my( $username, $password, $email, $service )=@_; -#my $msg = <<"EOF"; -#From: support \ -#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; -#} -# +sub mailmail { + my( $username, $password, $email )=@_; +my $body = <<"EOF"; +Welcome to IRCNow! -#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`; -#} +You created an email account: +Username: $username@$hostname +Password: $password +Server: $hostname +IMAP Port: $imapport (STARTTLS) +SMTP Port: $smtpport (STARTTLS) +Webpanel: $mailwebpanel +$approvemsg +*IMPORTANT*: Verify your email address: + +Please reply to this email to indicate you have received the email. You must +reply in order to keep your account. + +Connection Instructions: https://wiki.ircnow.org/?n=Email.Email + +IRCNow +EOF + mail($mailfrom, $email, $mailname, "Verify IRCNow Account", $body); +} + + +sub createmail { + my ($password, $username) = @_; + chomp(my $encrypted = `encrypt $password`); + 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 rcctl restart smtpd`; + `doas rcctl reload dovecot`; +} + +sub deletemail { + my ($username) = @_; + my @passwd = readarray("/etc/mail/passwd"); + my @virtuals = readarray("/etc/mail/virtuals"); + @passwd = grep !/^${username}\@${hostname}/, @passwd; + @virtuals = grep !/^${username}\@${hostname}/, @virtuals; + + # trailing newline necessary + main::writefile("$filename.bak", join("\n", @lines)."\n"); + copy "$filename.bak", $filename; + + `doas rcctl restart smtpd`; + `doas rcctl reload dovecot`; +} 1; # MUST BE LAST STATEMENT IN FILE blob - 1005dddb4ee1f7faae95bea7f563897b62162853 blob + 967a11bd5552fb045109026b6e9bf75fc918c3ba --- botnow +++ botnow @@ -94,6 +94,8 @@ $conf{ip6subnet} = $conf{ip6subnet} or die "ERROR: bot $conf{ip6prefix} = $conf{ip6prefix} or die "ERROR: botnow.conf: ip6prefix"; $conf{plainport} = $conf{plainport} || 1337; $conf{sslport} = $conf{sslport} || 31337; +$conf{imapport} = $conf{imapport} || 143; +$conf{smtpport} = $conf{smtpport} || 587; # Nick and password of bot -- Make sure to add to oper block $conf{nick} = $conf{nick} or die "ERROR: botnow.conf: nick"; blob - a8861fb0055e97395b89f9ac4632664172841b57 blob + 371e609a7151c981ce2f1ee52973a49d336fb2ce --- botnow.conf.example +++ botnow.conf.example @@ -13,11 +13,16 @@ hostname = example.com #Webpanel URL webpanel = https://bnc.example.com +#Webpanel URL +mailwebpanel = https://mail.example.com + #External IP addresses, plaintext and ssl port ip4 = 192.168.0.1 ip6 = 2001:db8:: #plainport = 1337 #sslport = 31337 +#imapport = 143 +#smtpport = 587 #Your IPv6 subnet length ip6subnet = 64 blob - b57bfab705b26c3dc55ecb6a56980ccb275437c0 blob + 1b71f51716513895246584983f3f511ae6d299a2 --- table.sql +++ table.sql @@ -22,6 +22,18 @@ CREATE TABLE shell ( localtime VARCHAR(100), captcha INTEGER ); +CREATE TABLE mail ( + id INTEGER PRIMARY KEY, + hashid VARCHAR(100), + ircid INTEGER, + wwwid INTEGER, + smtpid INTEGER, + username VARCHAR(32), + email VARCHAR(100), + password VARCHAR(100), + localtime VARCHAR(100), + captcha INTEGER +); CREATE TABLE www ( id INTEGER PRIMARY KEY, hashid VARCHAR(100),