Commit Diff
Diff:
c54830adcfff9e7ec910825ace159fcabf5ed456
3a155d6064f7abfab12f1180241034ee90cee30b
Commit:
3a155d6064f7abfab12f1180241034ee90cee30b
Tree:
89906a1a8761152eae7cc8ab53f9fb738eab806d
Author:
jrmu <jrmu@ircnow.org>
Committer:
jrmu <jrmu@ircnow.org>
Date:
Sun Mar 5 23:51:05 2023 UTC
Message:
Adding Mail support
blob - 6df39f6f4e394386d6b4ef5fb28988e72d15246c
blob + 2c188f068502084d0c556c4cbe4d43ab62076987
--- Help.pm
+++ Help.pm
@@ -28,13 +28,14 @@ sub help {
$terms
To request a free bouncer, type !bnc <username> <email>. For example, !bnc john john\@example.com.
To request a free shell account, type !shell <username> <email>. For example, !shell john john\@example.com.
+To request a free email account, type !mail <username> <email>. For example, !mail john john\@example.com.
EOF
-#To request a free email account, type !email <username> <email>. For example, !email john john\@example.com.
#To request a free VPN account, type !vpn <username> <email>. For example, !vpn john john\@example.com.
if (main::isstaff($bot, $nick)) {
$msg .= <<"EOF";
To delete a bouncer, type !bnc delete <username>
To verify a captcha, type !bnc captcha <username>
+To approve a bouncer, type !bnc approve <username>
To recreate cloneuser, type !bnc cloneuser
To get a list of usernames that match IPs, type !regex ips <ips>
To get a list of IPs that match usernames, type !regex users <usernames>
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 <username> <email>");
+ 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 <text>");
+ 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 <username> <email> 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 \<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;
-#}
-#
+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),
IRCNow