fix: block usr_ signups and improve runtime portability
This commit is contained in:
1 parent
8d42548c54
commit
7cc965ce52
1 file changed
+135
-36
+135
-36
@@ -4,6 +4,7 @@ import argparse
|
|||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import pwd
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@@ -17,7 +18,7 @@ from pathlib import Path
|
|||||||
import dns.resolver
|
import dns.resolver
|
||||||
|
|
||||||
|
|
||||||
VERSION = "6.1"
|
VERSION = "6.5"
|
||||||
|
|
||||||
SOURCES = [
|
SOURCES = [
|
||||||
"https://raw.githubusercontent.com/mehrtat/disposable-email-domain/main/domains.txt",
|
"https://raw.githubusercontent.com/mehrtat/disposable-email-domain/main/domains.txt",
|
||||||
@@ -25,8 +26,6 @@ SOURCES = [
|
|||||||
"https://disposable.github.io/disposable-email-domains/domains.txt",
|
"https://disposable.github.io/disposable-email-domains/domains.txt",
|
||||||
]
|
]
|
||||||
|
|
||||||
RUBY_BIN = "/home/mastodon/.rbenv/versions/3.4.7/bin"
|
|
||||||
|
|
||||||
DOMAIN_RE = re.compile(
|
DOMAIN_RE = re.compile(
|
||||||
r"^(?=.{1,253}$)"
|
r"^(?=.{1,253}$)"
|
||||||
r"(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+"
|
r"(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+"
|
||||||
@@ -169,28 +168,82 @@ def save_json_atomic(filename, value):
|
|||||||
os.unlink(temporary)
|
os.unlink(temporary)
|
||||||
|
|
||||||
|
|
||||||
def command_environment():
|
def mastodon_owner(cwd):
|
||||||
|
path = Path(cwd).resolve()
|
||||||
|
stat = path.stat()
|
||||||
|
account = pwd.getpwuid(stat.st_uid)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"uid": stat.st_uid,
|
||||||
|
"gid": stat.st_gid,
|
||||||
|
"name": account.pw_name,
|
||||||
|
"home": Path(account.pw_dir),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def command_environment(cwd):
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
|
owner = mastodon_owner(cwd)
|
||||||
|
home = owner["home"]
|
||||||
|
|
||||||
env["PATH"] = (
|
candidates = [
|
||||||
f"{RUBY_BIN}:"
|
home / ".rbenv" / "shims",
|
||||||
"/usr/local/bin:"
|
home / ".rbenv" / "bin",
|
||||||
"/usr/bin:"
|
home / ".asdf" / "shims",
|
||||||
"/bin"
|
home / ".asdf" / "bin",
|
||||||
)
|
home / ".local" / "share" / "mise" / "shims",
|
||||||
|
home / ".local" / "bin",
|
||||||
|
]
|
||||||
|
|
||||||
|
path_parts = []
|
||||||
|
|
||||||
|
for candidate in candidates:
|
||||||
|
if candidate.is_dir():
|
||||||
|
path_parts.append(str(candidate))
|
||||||
|
|
||||||
|
current_path = env.get("PATH", "")
|
||||||
|
|
||||||
|
if current_path:
|
||||||
|
path_parts.append(current_path)
|
||||||
|
|
||||||
|
env["PATH"] = os.pathsep.join(path_parts)
|
||||||
|
env["HOME"] = str(home)
|
||||||
|
env["USER"] = owner["name"]
|
||||||
|
env["LOGNAME"] = owner["name"]
|
||||||
env["RAILS_ENV"] = "production"
|
env["RAILS_ENV"] = "production"
|
||||||
|
|
||||||
|
rbenv_root = home / ".rbenv"
|
||||||
|
|
||||||
|
if rbenv_root.is_dir():
|
||||||
|
env["RBENV_ROOT"] = str(rbenv_root)
|
||||||
|
|
||||||
return env
|
return env
|
||||||
|
|
||||||
|
|
||||||
|
def demote_to_mastodon_owner(cwd):
|
||||||
|
owner = mastodon_owner(cwd)
|
||||||
|
|
||||||
|
if os.geteuid() != 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if owner["uid"] == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def demote():
|
||||||
|
os.initgroups(owner["name"], owner["gid"])
|
||||||
|
os.setgid(owner["gid"])
|
||||||
|
os.setuid(owner["uid"])
|
||||||
|
|
||||||
|
return demote
|
||||||
|
|
||||||
|
|
||||||
def run_command(
|
def run_command(
|
||||||
command,
|
command,
|
||||||
cwd,
|
cwd,
|
||||||
check=True,
|
check=True,
|
||||||
extra_env=None,
|
extra_env=None,
|
||||||
):
|
):
|
||||||
env = command_environment()
|
env = command_environment(cwd)
|
||||||
|
|
||||||
if extra_env:
|
if extra_env:
|
||||||
env.update(extra_env)
|
env.update(extra_env)
|
||||||
@@ -202,6 +255,7 @@ def run_command(
|
|||||||
text=True,
|
text=True,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
|
preexec_fn=demote_to_mastodon_owner(cwd),
|
||||||
)
|
)
|
||||||
|
|
||||||
if check and process.returncode != 0:
|
if check and process.returncode != 0:
|
||||||
@@ -225,7 +279,6 @@ def run_command(
|
|||||||
|
|
||||||
return process
|
return process
|
||||||
|
|
||||||
|
|
||||||
def get_mastodon_blocks(mastodon_dir):
|
def get_mastodon_blocks(mastodon_dir):
|
||||||
ruby = r'''
|
ruby = r'''
|
||||||
rows = EmailDomainBlock
|
rows = EmailDomainBlock
|
||||||
@@ -356,30 +409,40 @@ def cleanup_blocked_pending(
|
|||||||
dry_run=False,
|
dry_run=False,
|
||||||
):
|
):
|
||||||
|
|
||||||
ruby = r'''
|
ruby = r'''dry_run = ENV["BLOCKER_DRY_RUN"] == "1"
|
||||||
dry_run = ENV["BLOCKER_DRY_RUN"] == "1"
|
|
||||||
|
|
||||||
checked = 0
|
checked = 0
|
||||||
matched = 0
|
matched = 0
|
||||||
|
matched_email = 0
|
||||||
|
matched_username = 0
|
||||||
deleted = 0
|
deleted = 0
|
||||||
errors = []
|
errors = []
|
||||||
|
|
||||||
User
|
User.pending.find_each(batch_size: 100) do |user|
|
||||||
.where(approved: false)
|
|
||||||
.find_each(batch_size: 100) do |user|
|
|
||||||
|
|
||||||
next if user.email.blank?
|
|
||||||
next if user.account.nil?
|
next if user.account.nil?
|
||||||
|
|
||||||
checked += 1
|
checked += 1
|
||||||
|
|
||||||
begin
|
begin
|
||||||
next unless EmailDomainBlock.block?(user.email)
|
blocked_email =
|
||||||
|
user.email.present? &&
|
||||||
|
EmailDomainBlock.block?(user.email)
|
||||||
|
|
||||||
|
blocked_username =
|
||||||
|
user.account.username.to_s.match?(/\\Ausr_/i)
|
||||||
|
|
||||||
|
next unless blocked_email || blocked_username
|
||||||
|
|
||||||
matched += 1
|
matched += 1
|
||||||
|
matched_email += 1 if blocked_email
|
||||||
|
matched_username += 1 if blocked_username
|
||||||
|
|
||||||
|
reasons = []
|
||||||
|
reasons << "email" if blocked_email
|
||||||
|
reasons << "username" if blocked_username
|
||||||
|
|
||||||
if dry_run
|
if dry_run
|
||||||
puts "__PENDING__#{user.id}\t#{user.email}"
|
puts "__PENDING__#{user.id}\\t#{user.account.username}\\t#{reasons.join(",")}"
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -394,7 +457,7 @@ User
|
|||||||
rescue => e
|
rescue => e
|
||||||
errors << {
|
errors << {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
email: user.email,
|
username: user.account&.username,
|
||||||
error: "#{e.class}: #{e.message}"
|
error: "#{e.class}: #{e.message}"
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@@ -404,6 +467,8 @@ STDOUT.write(
|
|||||||
"__CLEANUP__" + JSON.generate({
|
"__CLEANUP__" + JSON.generate({
|
||||||
checked: checked,
|
checked: checked,
|
||||||
matched: matched,
|
matched: matched,
|
||||||
|
matched_email: matched_email,
|
||||||
|
matched_username: matched_username,
|
||||||
deleted: deleted,
|
deleted: deleted,
|
||||||
errors: errors
|
errors: errors
|
||||||
})
|
})
|
||||||
@@ -457,7 +522,6 @@ STDOUT.write(
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def resolve_mx(
|
def resolve_mx(
|
||||||
domain,
|
domain,
|
||||||
timeout,
|
timeout,
|
||||||
@@ -498,7 +562,7 @@ def main():
|
|||||||
"Disposable domains are hard-blocked; "
|
"Disposable domains are hard-blocked; "
|
||||||
"MX records are report-only; "
|
"MX records are report-only; "
|
||||||
"pending registrations using blocked "
|
"pending registrations using blocked "
|
||||||
"email domains are removed."
|
"email domains or usr_ usernames are removed."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -573,7 +637,7 @@ def main():
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help=(
|
help=(
|
||||||
"Do not remove pending registrations "
|
"Do not remove pending registrations "
|
||||||
"whose email is hard-blocked"
|
"matched by email block or usr_ username"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -583,15 +647,6 @@ def main():
|
|||||||
args.mastodon_dir
|
args.mastodon_dir
|
||||||
)
|
)
|
||||||
|
|
||||||
ruby = Path(
|
|
||||||
RUBY_BIN
|
|
||||||
) / "ruby"
|
|
||||||
|
|
||||||
if not ruby.exists():
|
|
||||||
raise SystemExit(
|
|
||||||
f"Ruby non trovato: {ruby}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if not (
|
if not (
|
||||||
mastodon_dir / "bin/rails"
|
mastodon_dir / "bin/rails"
|
||||||
).exists():
|
).exists():
|
||||||
@@ -629,8 +684,23 @@ def main():
|
|||||||
f"{mastodon_dir}"
|
f"{mastodon_dir}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
owner = mastodon_owner(
|
||||||
|
mastodon_dir
|
||||||
|
)
|
||||||
|
|
||||||
log(
|
log(
|
||||||
f"[config] Ruby: {ruby}"
|
f"[config] Utente Mastodon: "
|
||||||
|
f"{owner['name']} "
|
||||||
|
f"(uid={owner['uid']})"
|
||||||
|
)
|
||||||
|
|
||||||
|
ruby_version = run_command(
|
||||||
|
["ruby", "-v"],
|
||||||
|
cwd=mastodon_dir,
|
||||||
|
).stdout.strip()
|
||||||
|
|
||||||
|
log(
|
||||||
|
f"[config] Ruby: {ruby_version}"
|
||||||
)
|
)
|
||||||
|
|
||||||
log(
|
log(
|
||||||
@@ -822,6 +892,8 @@ def main():
|
|||||||
cleanup = {
|
cleanup = {
|
||||||
"checked": 0,
|
"checked": 0,
|
||||||
"matched": 0,
|
"matched": 0,
|
||||||
|
"matched_email": 0,
|
||||||
|
"matched_username": 0,
|
||||||
"deleted": 0,
|
"deleted": 0,
|
||||||
"errors": [],
|
"errors": [],
|
||||||
}
|
}
|
||||||
@@ -848,6 +920,16 @@ def main():
|
|||||||
f"{cleanup['matched']:,}"
|
f"{cleanup['matched']:,}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
log(
|
||||||
|
f"[pending] per email : "
|
||||||
|
f"{cleanup['matched_email']:,}"
|
||||||
|
)
|
||||||
|
|
||||||
|
log(
|
||||||
|
f"[pending] per usr_ : "
|
||||||
|
f"{cleanup['matched_username']:,}"
|
||||||
|
)
|
||||||
|
|
||||||
if args.dry_run:
|
if args.dry_run:
|
||||||
log(
|
log(
|
||||||
f"[pending] da eliminare: "
|
f"[pending] da eliminare: "
|
||||||
@@ -873,7 +955,7 @@ def main():
|
|||||||
log(
|
log(
|
||||||
" "
|
" "
|
||||||
f"user={error['id']} "
|
f"user={error['id']} "
|
||||||
f"{error['email']} "
|
f"{error.get('username', '')} "
|
||||||
f"{error['error']}"
|
f"{error['error']}"
|
||||||
)
|
)
|
||||||
mx_to_domains = defaultdict(set)
|
mx_to_domains = defaultdict(set)
|
||||||
@@ -1069,6 +1151,12 @@ def main():
|
|||||||
"pending_blocked":
|
"pending_blocked":
|
||||||
cleanup["matched"],
|
cleanup["matched"],
|
||||||
|
|
||||||
|
"pending_matched_email":
|
||||||
|
cleanup["matched_email"],
|
||||||
|
|
||||||
|
"pending_matched_username":
|
||||||
|
cleanup["matched_username"],
|
||||||
|
|
||||||
"pending_deleted":
|
"pending_deleted":
|
||||||
cleanup["deleted"],
|
cleanup["deleted"],
|
||||||
|
|
||||||
@@ -1180,6 +1268,16 @@ def main():
|
|||||||
f"{cleanup['matched']:,}"
|
f"{cleanup['matched']:,}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
log(
|
||||||
|
f" per email : "
|
||||||
|
f"{cleanup['matched_email']:,}"
|
||||||
|
)
|
||||||
|
|
||||||
|
log(
|
||||||
|
f" per usr_ : "
|
||||||
|
f"{cleanup['matched_username']:,}"
|
||||||
|
)
|
||||||
|
|
||||||
log(
|
log(
|
||||||
f"Pending eliminati : "
|
f"Pending eliminati : "
|
||||||
f"{cleanup['deleted']:,}"
|
f"{cleanup['deleted']:,}"
|
||||||
@@ -1232,3 +1330,4 @@ if __name__ == "__main__":
|
|||||||
log("ERRORE FATALE:")
|
log("ERRORE FATALE:")
|
||||||
log(str(exc))
|
log(str(exc))
|
||||||
raise
|
raise
|
||||||
|
|
||||||
Reference in new issue
Block a user