Commit Diff


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 <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),