mirror of
https://github.com/tildeclub/makeuser.git
synced 2026-05-30 07:00:19 +00:00
improve data leaks
This commit is contained in:
4
Makefile
4
Makefile
@@ -6,8 +6,10 @@ install:
|
|||||||
@mkdir -p $(BINDIR)
|
@mkdir -p $(BINDIR)
|
||||||
@mkdir -p $(ZNCCONF)
|
@mkdir -p $(ZNCCONF)
|
||||||
@install -m 755 makeuser $(BINDIR)
|
@install -m 755 makeuser $(BINDIR)
|
||||||
|
@install -m 755 rmuser $(BINDIR)
|
||||||
@install -m 644 welcome-email.tmpl $(BINDIR)
|
@install -m 644 welcome-email.tmpl $(BINDIR)
|
||||||
@install -m 700 znccreate.py $(BINDIR)
|
@install -m 700 znccreate.py $(BINDIR)
|
||||||
|
@install -m 700 zncdelete.py $(BINDIR)
|
||||||
@install -m 600 znc-config-ex.json $(ZNCCONF)
|
@install -m 600 znc-config-ex.json $(ZNCCONF)
|
||||||
@echo Remember to edit znc-config with your ZNC details and rename $(ZNCCONF)/znc-config-ex.json to $(ZNCCONF)/znc-config.json
|
@echo Remember to edit znc-config with your ZNC details and rename $(ZNCCONF)/znc-config-ex.json to $(ZNCCONF)/znc-config.json
|
||||||
@echo ENJOY
|
@echo ENJOY
|
||||||
@@ -15,8 +17,10 @@ install:
|
|||||||
uninstall:
|
uninstall:
|
||||||
@echo removing the executables from $(BINDIR)
|
@echo removing the executables from $(BINDIR)
|
||||||
@rm -f $(BINDIR)/makeuser
|
@rm -f $(BINDIR)/makeuser
|
||||||
|
@rm -f $(BINDIR)/rmuser
|
||||||
@rm -f $(BINDIR)/welcome-email.tmpl
|
@rm -f $(BINDIR)/welcome-email.tmpl
|
||||||
@rm -f $(BINDIR)/znccreate.py
|
@rm -f $(BINDIR)/znccreate.py
|
||||||
|
@rm -f $(BINDIR)/zncdelete.py
|
||||||
@echo znc-config.json has not been touched. You will need to manually remove it from $(ZNCCONF)
|
@echo znc-config.json has not been touched. You will need to manually remove it from $(ZNCCONF)
|
||||||
.PHONY: install uninstall
|
.PHONY: install uninstall
|
||||||
|
|
||||||
|
|||||||
14
README.md
14
README.md
@@ -4,3 +4,17 @@ A script that allows admins to make user accounts easily.
|
|||||||
|
|
||||||
Run `make` to install the script to `/usr/local/bin`.
|
Run `make` to install the script to `/usr/local/bin`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## User removal
|
||||||
|
|
||||||
|
Use `rmuser <username>` to remove a user account and clean up related services:
|
||||||
|
|
||||||
|
- Removes user from Helpdesk (`helpdesk_admin.sh del`)
|
||||||
|
- Removes user from ZNC (`zncdelete.py`)
|
||||||
|
- Discovers user email from `/var/signups` for Helpdesk/list cleanup
|
||||||
|
- Comments out matching signup entries in `/var/signups`
|
||||||
|
- Sends mailing list unsubscribe request when an email is discovered
|
||||||
|
- Deletes the Unix account and home directory (`userdel -r`)
|
||||||
|
|
||||||
|
Run `make` to install `rmuser` and `zncdelete.py` to `/usr/local/bin`.
|
||||||
|
|||||||
134
makeuser
134
makeuser
@@ -5,7 +5,9 @@
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
PROGNAME=${0##*/}
|
PROGNAME=${0##*/}
|
||||||
VERSION="0.2"
|
VERSION="0.3"
|
||||||
|
CLUB_GROUP_ID="100"
|
||||||
|
WELCOME_EMAIL_TEMPLATE="/usr/local/bin/welcome-email.tmpl"
|
||||||
|
|
||||||
error_exit() {
|
error_exit() {
|
||||||
printf "%s: %s\n" "$PROGNAME" "${1:-"Unknown Error"}" >&2
|
printf "%s: %s\n" "$PROGNAME" "${1:-"Unknown Error"}" >&2
|
||||||
@@ -23,11 +25,97 @@ Subject: subscribe
|
|||||||
MAIL
|
MAIL
|
||||||
}
|
}
|
||||||
|
|
||||||
case $1 in
|
send_welcome_mail() {
|
||||||
|
welcome_username=$1
|
||||||
|
welcome_password=$2
|
||||||
|
welcome_email=$3
|
||||||
|
|
||||||
|
if [ ! -r "$WELCOME_EMAIL_TEMPLATE" ]; then
|
||||||
|
error_exit "welcome email template is not readable"
|
||||||
|
fi
|
||||||
|
|
||||||
|
{
|
||||||
|
printf "%s\n" "$welcome_username"
|
||||||
|
printf "%s\n" "$welcome_email"
|
||||||
|
printf "%s\n" "$welcome_password"
|
||||||
|
} | python3 -c '
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
template_path = "/usr/local/bin/welcome-email.tmpl"
|
||||||
|
|
||||||
|
username = sys.stdin.readline().rstrip("\r\n")
|
||||||
|
email = sys.stdin.readline().rstrip("\r\n")
|
||||||
|
password = sys.stdin.readline().rstrip("\r\n")
|
||||||
|
|
||||||
|
if not username or not email or not password:
|
||||||
|
sys.stderr.write("missing username, email, or password\n")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if "\n" in username or "\r" in username or "\n" in email or "\r" in email:
|
||||||
|
sys.stderr.write("unsafe username or email value\n")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with open(template_path, "r", encoding="utf-8", errors="replace") as handle:
|
||||||
|
text = handle.read()
|
||||||
|
|
||||||
|
text = text.replace("newusername", username)
|
||||||
|
text = text.replace("newpassword", password)
|
||||||
|
text = text.replace("newtoemail", email)
|
||||||
|
|
||||||
|
lines = text.splitlines(True)
|
||||||
|
|
||||||
|
has_header_block = bool(lines and re.match(r"^[A-Za-z0-9-]+:", lines[0]))
|
||||||
|
|
||||||
|
if has_header_block:
|
||||||
|
header_end = None
|
||||||
|
|
||||||
|
for index, line in enumerate(lines):
|
||||||
|
if line.rstrip("\r\n") == "":
|
||||||
|
header_end = index
|
||||||
|
break
|
||||||
|
|
||||||
|
if header_end is None:
|
||||||
|
header_end = len(lines)
|
||||||
|
header_lines = lines
|
||||||
|
body_lines = ["\n"]
|
||||||
|
else:
|
||||||
|
header_lines = lines[:header_end]
|
||||||
|
body_lines = lines[header_end:]
|
||||||
|
|
||||||
|
has_recipient_header = any(
|
||||||
|
re.match(r"^(to|cc|bcc):", header, re.IGNORECASE)
|
||||||
|
for header in header_lines
|
||||||
|
)
|
||||||
|
|
||||||
|
output = []
|
||||||
|
|
||||||
|
output.extend(header_lines)
|
||||||
|
|
||||||
|
if not has_recipient_header:
|
||||||
|
output.append(f"To: {email}\n")
|
||||||
|
|
||||||
|
output.append(f"Bcc: {username}, root@tilde.club\n")
|
||||||
|
output.extend(body_lines)
|
||||||
|
|
||||||
|
sys.stdout.write("".join(output))
|
||||||
|
else:
|
||||||
|
sys.stdout.write(f"To: {email}\n")
|
||||||
|
sys.stdout.write(f"Bcc: {username}, root@tilde.club\n")
|
||||||
|
sys.stdout.write("\n")
|
||||||
|
sys.stdout.write(text)
|
||||||
|
' | sendmail -oi -t
|
||||||
|
}
|
||||||
|
|
||||||
|
case ${1:-} in
|
||||||
-h | --help)
|
-h | --help)
|
||||||
usage; exit ;;
|
usage
|
||||||
|
exit
|
||||||
|
;;
|
||||||
-* | --*)
|
-* | --*)
|
||||||
usage; error_exit "unknown option $1" ;;
|
usage
|
||||||
|
error_exit "unknown option $1"
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
if [ $# -ne 3 ]; then
|
if [ $# -ne 3 ]; then
|
||||||
error_exit "not enough args"
|
error_exit "not enough args"
|
||||||
@@ -39,22 +127,28 @@ case $1 in
|
|||||||
|
|
||||||
printf "adding new user %s\n" "$1"
|
printf "adding new user %s\n" "$1"
|
||||||
newpw=$(pwgen -1B 20)
|
newpw=$(pwgen -1B 20)
|
||||||
sudo useradd -m -g 100 -s /bin/bash "$1" \
|
trap 'unset newpw' 0 HUP INT TERM
|
||||||
|
|
||||||
|
printf "creating matching primary group for %s\n" "$1"
|
||||||
|
if ! getent group "$1" > /dev/null 2>&1; then
|
||||||
|
sudo groupadd "$1" || error_exit "couldn't add group"
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo useradd -m -g "$1" -G "$CLUB_GROUP_ID" -s /bin/bash "$1" \
|
||||||
|| error_exit "couldn't add user"
|
|| error_exit "couldn't add user"
|
||||||
printf "%s:%s\n" "$1" "$newpw" | sudo chpasswd
|
|
||||||
|
printf "%s:%s\n" "$1" "$newpw" | sudo chpasswd \
|
||||||
|
|| error_exit "couldn't set user password"
|
||||||
|
|
||||||
printf "sending welcome mail\n"
|
printf "sending welcome mail\n"
|
||||||
sed -e "s/newusername/$1/g" \
|
send_welcome_mail "$1" "$newpw" "$2" \
|
||||||
-e "s/newpassword/$newpw/" \
|
|| error_exit "couldn't send welcome mail"
|
||||||
-e "s/newtoemail/$2/" \
|
|
||||||
/usr/local/bin/welcome-email.tmpl \
|
|
||||||
| sendmail "$1" "$2" root@tilde.club
|
|
||||||
|
|
||||||
printf "subscribing to mailing list\n"
|
printf "subscribing to mailing list\n"
|
||||||
sub_to_list "$1"
|
sub_to_list "$1"
|
||||||
|
|
||||||
printf "adding ssh pubkey\n"
|
printf "adding ssh pubkey\n"
|
||||||
printf "%s\n" "$3" | sudo tee "/home/$1/.ssh/authorized_keys"
|
printf "%s\n" "$3" | sudo tee "/home/$1/.ssh/authorized_keys" > /dev/null
|
||||||
|
|
||||||
printf "\nannouncing new user on mastodon\n"
|
printf "\nannouncing new user on mastodon\n"
|
||||||
/usr/local/bin/toot "welcome new user ~$1!"
|
/usr/local/bin/toot "welcome new user ~$1!"
|
||||||
@@ -63,10 +157,10 @@ case $1 in
|
|||||||
sudo sed -i"" "/\b$1\b/d" /var/signups_current
|
sudo sed -i"" "/\b$1\b/d" /var/signups_current
|
||||||
|
|
||||||
printf "removing .git from new homedir\n"
|
printf "removing .git from new homedir\n"
|
||||||
sudo rm -rf /home/$1/.git
|
sudo rm -rf "/home/$1/.git"
|
||||||
|
|
||||||
printf "removing skel git README.md\n"
|
printf "removing skel git README.md\n"
|
||||||
sudo rm /home/$1/README.md
|
sudo rm "/home/$1/README.md"
|
||||||
|
|
||||||
printf "fix sorting in /etc/passwd\n"
|
printf "fix sorting in /etc/passwd\n"
|
||||||
sudo pwck -s
|
sudo pwck -s
|
||||||
@@ -75,11 +169,15 @@ case $1 in
|
|||||||
sudo xfs_quota -x -c "limit -u bsoft=1G bhard=3G $1"
|
sudo xfs_quota -x -c "limit -u bsoft=1G bhard=3G $1"
|
||||||
|
|
||||||
printf "making znc user\n"
|
printf "making znc user\n"
|
||||||
/usr/local/bin/znccreate.py "$1" "$newpw" "MaxNetworks=3"
|
printf "%s\n" "$newpw" | /usr/local/bin/znccreate.py "$1" --password-stdin "MaxNetworks=3" \
|
||||||
|
|| error_exit "couldn't add znc user"
|
||||||
|
|
||||||
|
unset newpw
|
||||||
|
trap - 0 HUP INT TERM
|
||||||
|
|
||||||
printf "Adding user to Helpdesk\n"
|
printf "Adding user to Helpdesk\n"
|
||||||
/usr/local/bin/helpdesk_admin.sh "add" "$1" "$2"
|
printf "%s\n" "$2" | /usr/local/bin/helpdesk_admin.sh "add" "$1" --email-stdin \
|
||||||
|
|| error_exit "couldn't add user to Helpdesk"
|
||||||
|
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
160
rmuser
Executable file
160
rmuser
Executable file
@@ -0,0 +1,160 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# rmuser - tilde.club user removal helper
|
||||||
|
# Usage: rmuser [-h|--help] <username>
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
PROGNAME=${0##*/}
|
||||||
|
VERSION="0.2"
|
||||||
|
SIGNUPS_FILE="/var/signups"
|
||||||
|
|
||||||
|
error_exit() {
|
||||||
|
printf "%s: %s\n" "$PROGNAME" "${1:-"Unknown Error"}" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
printf "usage: %s %s [-h|--help] <username>\n" "$PROGNAME" "$VERSION"
|
||||||
|
}
|
||||||
|
|
||||||
|
lookup_email_from_signups() {
|
||||||
|
user="$1"
|
||||||
|
|
||||||
|
if [ ! -r "$SIGNUPS_FILE" ]; then
|
||||||
|
printf "warning: cannot read %s to discover email\n" "$SIGNUPS_FILE" >&2
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
awk -v u="$user" '
|
||||||
|
/^[[:space:]]*#/ { next }
|
||||||
|
{
|
||||||
|
n = split($0, fields, /[\t ,;:]+/)
|
||||||
|
found_user = 0
|
||||||
|
for (i = 1; i <= n; i++) {
|
||||||
|
if (fields[i] == u) {
|
||||||
|
found_user = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found_user) {
|
||||||
|
for (i = 1; i <= n; i++) {
|
||||||
|
if (fields[i] ~ /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/) {
|
||||||
|
print fields[i]
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' "$SIGNUPS_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
comment_out_signup() {
|
||||||
|
user="$1"
|
||||||
|
|
||||||
|
if [ ! -f "$SIGNUPS_FILE" ]; then
|
||||||
|
printf "warning: %s does not exist, skipping signup comment\n" "$SIGNUPS_FILE" >&2
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! sudo test -w "$SIGNUPS_FILE"; then
|
||||||
|
printf "warning: %s is not writable, skipping signup comment\n" "$SIGNUPS_FILE" >&2
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
tmpfile=$(mktemp) || return 1
|
||||||
|
|
||||||
|
awk -v u="$user" '
|
||||||
|
/^[[:space:]]*#/ {
|
||||||
|
print
|
||||||
|
next
|
||||||
|
}
|
||||||
|
{
|
||||||
|
line = $0
|
||||||
|
n = split($0, fields, /[\t ,;:]+/)
|
||||||
|
found_user = 0
|
||||||
|
for (i = 1; i <= n; i++) {
|
||||||
|
if (fields[i] == u) {
|
||||||
|
found_user = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found_user) {
|
||||||
|
print "# " line
|
||||||
|
} else {
|
||||||
|
print
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' "$SIGNUPS_FILE" > "$tmpfile" || {
|
||||||
|
rm -f "$tmpfile"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
sudo cp "$tmpfile" "$SIGNUPS_FILE" || {
|
||||||
|
rm -f "$tmpfile"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
rm -f "$tmpfile"
|
||||||
|
}
|
||||||
|
|
||||||
|
maybe_unsubscribe_list() {
|
||||||
|
email="$1"
|
||||||
|
|
||||||
|
if [ -z "$email" ]; then
|
||||||
|
printf "skipping mailing list unsubscribe (email not found)\n"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "sending mailing list unsubscribe request\n"
|
||||||
|
sendmail tildeclub-join@lists.tildeverse.org << MAIL || return 1
|
||||||
|
From: $email
|
||||||
|
Subject: unsubscribe
|
||||||
|
MAIL
|
||||||
|
}
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
-h | --help)
|
||||||
|
usage; exit 0 ;;
|
||||||
|
-* | --*)
|
||||||
|
usage; error_exit "unknown option $1" ;;
|
||||||
|
*)
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
usage
|
||||||
|
error_exit "invalid args"
|
||||||
|
fi
|
||||||
|
|
||||||
|
user="$1"
|
||||||
|
|
||||||
|
if ! id "$user" > /dev/null 2>&1; then
|
||||||
|
error_exit "user $user does not exist"
|
||||||
|
fi
|
||||||
|
|
||||||
|
email=$(lookup_email_from_signups "$user")
|
||||||
|
if [ -n "$email" ]; then
|
||||||
|
printf "found email for %s: %s\n" "$user" "$email"
|
||||||
|
else
|
||||||
|
printf "warning: email for %s not found in %s\n" "$user" "$SIGNUPS_FILE" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "commenting out %s from %s\n" "$user" "$SIGNUPS_FILE"
|
||||||
|
comment_out_signup "$user" \
|
||||||
|
|| printf "warning: failed to comment out %s in %s\n" "$user" "$SIGNUPS_FILE" >&2
|
||||||
|
|
||||||
|
printf "removing user from Helpdesk\n"
|
||||||
|
/usr/local/bin/helpdesk_admin.sh "del" "$user" \
|
||||||
|
|| printf "warning: failed to remove %s from Helpdesk\n" "$user" >&2
|
||||||
|
|
||||||
|
printf "removing user from ZNC\n"
|
||||||
|
/usr/local/bin/zncdelete.py "$user" \
|
||||||
|
|| printf "warning: failed to remove %s from ZNC\n" "$user" >&2
|
||||||
|
|
||||||
|
maybe_unsubscribe_list "$email" \
|
||||||
|
|| printf "warning: failed to send mailing list unsubscribe\n" >&2
|
||||||
|
|
||||||
|
printf "deleting unix account and home directory\n"
|
||||||
|
sudo userdel -r "$user" || error_exit "couldn't delete user"
|
||||||
|
|
||||||
|
printf "fix sorting in /etc/passwd\n"
|
||||||
|
sudo pwck -s || printf "warning: pwck -s reported an issue\n" >&2
|
||||||
|
|
||||||
|
printf "done removing %s\n" "$user"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
149
znccreate.py
149
znccreate.py
@@ -1,45 +1,120 @@
|
|||||||
#!/usr/bin/python3.8
|
#!/usr/bin/python3.8
|
||||||
# Script created/contributed by ~jmjl
|
# Script created/contributed by ~jmjl
|
||||||
|
|
||||||
import socket, ssl, json, time, sys
|
import json
|
||||||
|
import socket
|
||||||
|
import ssl
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_FILE = "/root/.znc-conf/znc-config.json"
|
||||||
|
|
||||||
|
|
||||||
|
def error_exit(message):
|
||||||
|
print(f"{sys.argv[0]}: {message}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
print(
|
||||||
|
"usage:\n"
|
||||||
|
f" {sys.argv[0]} <username> <password> [Key=Value ...]\n"
|
||||||
|
f" {sys.argv[0]} <username> --password-stdin [Key=Value ...]",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def loadconf(cfgfile):
|
def loadconf(cfgfile):
|
||||||
with open(cfgfile, 'r') as f:
|
with open(cfgfile, "r") as f:
|
||||||
return json.load(f)
|
return json.load(f)
|
||||||
|
|
||||||
def send(msg):
|
|
||||||
s.send(f"{msg}\n".encode('utf-8'))
|
|
||||||
|
|
||||||
cfg = loadconf("/root/.znc-conf/znc-config.json")
|
def read_password_from_stdin():
|
||||||
|
password = sys.stdin.readline()
|
||||||
|
|
||||||
readbuffer = ""
|
if password == "":
|
||||||
s = socket.socket()
|
error_exit("no password received on stdin")
|
||||||
if cfg.get('tls') == 'yes':
|
|
||||||
ctx = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
|
|
||||||
s = ctx.wrap_socket(s)
|
|
||||||
|
|
||||||
s.connect((cfg['srv'], int(cfg['port'])))
|
password = password.rstrip("\r\n")
|
||||||
send("NICK bot")
|
|
||||||
send("USER bot 0 * :A bot to make users")
|
if password == "":
|
||||||
|
error_exit("empty password received on stdin")
|
||||||
|
|
||||||
|
return password
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args(argv):
|
||||||
|
if len(argv) < 3:
|
||||||
|
usage()
|
||||||
|
error_exit("not enough arguments")
|
||||||
|
|
||||||
|
user = argv[1]
|
||||||
|
|
||||||
|
if not user:
|
||||||
|
error_exit("username cannot be empty")
|
||||||
|
|
||||||
|
if argv[2] == "--password-stdin":
|
||||||
|
password = read_password_from_stdin()
|
||||||
|
settings_args = argv[3:]
|
||||||
|
else:
|
||||||
|
password = argv[2]
|
||||||
|
settings_args = argv[3:]
|
||||||
|
|
||||||
|
if not password:
|
||||||
|
error_exit("password cannot be empty")
|
||||||
|
|
||||||
|
cli_settings = {}
|
||||||
|
|
||||||
# Parse optional key=value settings after username/password.
|
# Parse optional key=value settings after username/password.
|
||||||
# Example: MaxNetworks=3 MaxClients=5
|
# Example:
|
||||||
cli_settings = {}
|
# MaxNetworks=3 MaxClients=5
|
||||||
for arg in sys.argv[3:]:
|
for arg in settings_args:
|
||||||
if '=' in arg:
|
if "=" in arg:
|
||||||
k, v = arg.split('=', 1)
|
key, value = arg.split("=", 1)
|
||||||
k = k.strip()
|
key = key.strip()
|
||||||
v = v.strip()
|
value = value.strip()
|
||||||
if k:
|
|
||||||
cli_settings[k] = v
|
if key:
|
||||||
|
cli_settings[key] = value
|
||||||
|
|
||||||
|
return user, password, cli_settings
|
||||||
|
|
||||||
|
|
||||||
|
def send(sock, msg):
|
||||||
|
sock.send(f"{msg}\n".encode("utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
user, pswd, cli_settings = parse_args(sys.argv)
|
||||||
|
|
||||||
|
cfg = loadconf(CONFIG_FILE)
|
||||||
|
|
||||||
# Also allow defaults from config, but CLI wins.
|
# Also allow defaults from config, but CLI wins.
|
||||||
# In /root/.znc-conf/znc-config.json you may add:
|
# In /root/.znc-conf/znc-config.json you may add:
|
||||||
# { ..., "default_user_settings": { "MaxNetworks": "3" } }
|
# {
|
||||||
|
# ...,
|
||||||
|
# "default_user_settings": {
|
||||||
|
# "MaxNetworks": "3"
|
||||||
|
# }
|
||||||
|
# }
|
||||||
default_settings = cfg.get("default_user_settings", {}) or {}
|
default_settings = cfg.get("default_user_settings", {}) or {}
|
||||||
|
|
||||||
|
readbuffer = ""
|
||||||
|
|
||||||
|
sock = socket.socket()
|
||||||
|
|
||||||
|
if cfg.get("tls") == "yes":
|
||||||
|
ctx = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
|
||||||
|
sock = ctx.wrap_socket(sock)
|
||||||
|
|
||||||
|
sock.connect((cfg["srv"], int(cfg["port"])))
|
||||||
|
|
||||||
|
send(sock, "NICK bot")
|
||||||
|
send(sock, "USER bot 0 * :A bot to make users")
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
readbuffer += s.recv(2048).decode('utf-8', errors='ignore')
|
readbuffer += sock.recv(2048).decode("utf-8", errors="ignore")
|
||||||
temp = str.split(readbuffer, "\n")
|
temp = str.split(readbuffer, "\n")
|
||||||
readbuffer = temp.pop()
|
readbuffer = temp.pop()
|
||||||
|
|
||||||
@@ -51,25 +126,27 @@ while True:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Authenticate when ZNC asks for PASS (ERR_PASSWDMISMATCH 464).
|
# Authenticate when ZNC asks for PASS (ERR_PASSWDMISMATCH 464).
|
||||||
if parts[1] == '464':
|
if parts[1] == "464":
|
||||||
send(f"PASS {cfg['user']}:{cfg['password']}")
|
send(sock, f"PASS {cfg['user']}:{cfg['password']}")
|
||||||
|
|
||||||
# On welcome (001), create user and apply settings.
|
# On welcome (001), create user and apply settings.
|
||||||
# (Preserves your original hostname check.)
|
# Preserves your original hostname check.
|
||||||
if parts[0][1:] == 'irc.znc.in' and parts[1] == '001':
|
if parts[0][1:] == "irc.znc.in" and parts[1] == "001":
|
||||||
user = sys.argv[1]
|
# Create user.
|
||||||
pswd = sys.argv[2]
|
send(sock, f"PRIVMSG *controlpanel :AddUser {user} {pswd}")
|
||||||
|
|
||||||
# Create user (unchanged)
|
# Merge defaults + CLI, CLI overrides.
|
||||||
send(f"PRIVMSG *controlpanel :AddUser {user} {pswd}")
|
|
||||||
|
|
||||||
# Merge defaults + CLI, CLI overrides
|
|
||||||
effective = dict(default_settings)
|
effective = dict(default_settings)
|
||||||
effective.update(cli_settings)
|
effective.update(cli_settings)
|
||||||
|
|
||||||
# Apply settings like: set MaxNetworks <user> <val>
|
# Apply settings like:
|
||||||
|
# set MaxNetworks <user> <val>
|
||||||
for key, val in effective.items():
|
for key, val in effective.items():
|
||||||
send(f"PRIVMSG *controlpanel :set {key} {user} {val}")
|
send(sock, f"PRIVMSG *controlpanel :set {key} {user} {val}")
|
||||||
|
|
||||||
print(f"Maken znc user {user}")
|
print(f"Maken znc user {user}")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|||||||
55
zncdelete.py
Executable file
55
zncdelete.py
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/python3.8
|
||||||
|
# Script created/contributed by ~jmjl
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import ssl
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def loadconf(cfgfile):
|
||||||
|
with open(cfgfile, 'r') as f:
|
||||||
|
return json.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
def send(msg):
|
||||||
|
s.send(f"{msg}\n".encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
cfg = loadconf("/root/.znc-conf/znc-config.json")
|
||||||
|
|
||||||
|
readbuffer = ""
|
||||||
|
s = socket.socket()
|
||||||
|
if cfg.get('tls') == 'yes':
|
||||||
|
ctx = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
|
||||||
|
s = ctx.wrap_socket(s)
|
||||||
|
|
||||||
|
s.connect((cfg['srv'], int(cfg['port'])))
|
||||||
|
send("NICK bot")
|
||||||
|
send("USER bot 0 * :A bot to remove users")
|
||||||
|
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
print("usage: zncdelete.py <username>")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
user = sys.argv[1]
|
||||||
|
|
||||||
|
while True:
|
||||||
|
readbuffer += s.recv(2048).decode('utf-8', errors='ignore')
|
||||||
|
temp = str.split(readbuffer, "\n")
|
||||||
|
readbuffer = temp.pop()
|
||||||
|
|
||||||
|
for line in temp:
|
||||||
|
line = line.rstrip("\r")
|
||||||
|
parts = line.split()
|
||||||
|
|
||||||
|
if len(parts) < 2:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if parts[1] == '464':
|
||||||
|
send(f"PASS {cfg['user']}:{cfg['password']}")
|
||||||
|
|
||||||
|
if parts[0][1:] == 'irc.znc.in' and parts[1] == '001':
|
||||||
|
send(f"PRIVMSG *controlpanel :DelUser {user}")
|
||||||
|
print(f"Removed znc user {user}")
|
||||||
|
sys.exit(0)
|
||||||
Reference in New Issue
Block a user