#!/usr/bin/env python3 # coding: utf-8 # -*- coding: utf-8 -*- # A Fediverse (decentralized social network, for instance using Mastodon) bot from mastodon import StreamListener from logging.handlers import RotatingFileHandler from pprint import pprint from utils.config import get_parameter, init_log, init_mastodon from datetime import datetime, timezone, timedelta import requests, os, sys, time, json, logging, argparse, re, smtplib, array config_file = "config.txt" secrets_filepath = get_parameter("secrets_filepath", config_file) log_filepath = get_parameter("log_filepath", config_file) log = init_log(log_filepath) mastodon = init_mastodon(config_file, secrets_filepath) email = { 'host': get_parameter('email_host', config_file), 'port': get_parameter('email_port', config_file), 'from': get_parameter('email_from', config_file), 'fromname': get_parameter('email_fromname', config_file), 'username': get_parameter('email_username', config_file), 'password': get_parameter('email_password', config_file), 'encryption': get_parameter('email_encryption', config_file) } class bcolors: HEADER = '\033[95m' OKBLUE = '\033[94m' OKGREEN = '\033[92m' WARNING = '\033[93m' FAIL = '\033[91m' ENDC = '\033[0m' BOLD = '\033[1m' UNDERLINE = '\033[4m' def list_accounts(days): users_count = mastodon.instance()['stats']['user_count'] mastodon_accounts = mastodon.admin_accounts(remote=False, status='active', limit=users_count) for account in mastodon_accounts: uid = account['id'] username = account['username'] email = account['email'] if account['account']['last_status_at'] == None: last_activity = account['account']['created_at'] else: last_activity = account['account']['last_status_at'] today = datetime.now(timezone.utc) if today - last_activity > timedelta(int(days)): log.info("User "+username+" https://miaou.drycat.fr/admin/accounts/"+str(uid)+" will be delete") def alert_accounts(days): users_count = mastodon.instance()['stats']['user_count'] mastodon_accounts = mastodon.admin_accounts(remote=False, status='active', limit=users_count) for account in mastodon_accounts: uid = account['id'] username = account['username'] mail = account['email'] if account['account']['last_status_at'] == None: last_activity = account['account']['created_at'] else: last_activity = account['account']['last_status_at'] today = datetime.now(timezone.utc) if today - last_activity > timedelta(int(days)): log.info("User "+username+" https://miaou.drycat.fr/admin/accounts/"+str(uid)+" will be delete") sender = email['from'] receivers = [''+mail+''] message = """From: """+email['fromname']+""" <"""+email['from']+"""> To: """+username+""" <"""+mail+"""> Subject: Your account has been inactive for more than """+days+""" days ---- English message bellow. ---- Bonjour Votre compte est inactif depuis plus de """+days+""" jours. Si vous ne souhaitez pas conserver ce compte sur l'instance Mastodon miaou.drycat.fr, oubliez ce mail. Sinon, connectez vous et par messure de sécurité, envoyez un message privée à vous même. Sans action de votre part, votre compte sera clôturé sous 7 jours. Cordialement L'équipe d'administration de """+email['fromname']+""". -------- Hello Your account has been inactive for more than """+days+""" days. If you do not wish to keep this account on the instance Mastodon miaou.drycat.fr, forget this mail. Otherwise, log in and by security measure, send a private message to yourself. Without action on your part, your account will be closed within 7 days. Cordially The """+email['fromname']+"""'s administration team. """ try: smtpObj = smtplib.SMTP(email['host'], email['port']) smtpObj.ehlo() if email['encryption'] == "SSL": smtpObj.ssl() elif email['encryption'] == "STARTTLS": smtpObj.starttls() else: log.warning("No encryption select. It's dangerous") smtpObj.login(email['username'], email['password']) smtpObj.sendmail(sender, receivers, message.replace("\xe9", "").encode("ascii", errors="ignore")) log.info("Successfully sent email") except smtplib.SMTPException as e: log.debug(e) log.error("Error: unable to send email") def drop_accounts(days): users_count = mastodon.instance()['stats']['user_count'] mastodon_accounts = mastodon.admin_accounts(remote=False, status='active', limit=users_count) for account in mastodon_accounts: uid = account['id'] username = account['username'] mail = account['email'] if account['account']['last_status_at'] == None: last_activity = account['account']['created_at'] else: last_activity = account['account']['last_status_at'] today = datetime.now(timezone.utc) if today - last_activity > timedelta(int(days)): log.info("User "+username+" https://miaou.drycat.fr/admin/accounts/"+str(uid)+" is deleted") mastodon.admin_account_moderate(uid, action="suspend", report_id=None, warning_preset_id=None, text="Autodeleting old account", send_email_notification=False) sender = email['from'] receivers = [''+mail+''] message = """From: """+email['fromname']+""" <"""+email['from']+"""> To: """+username+""" <"""+mail+"""> Subject: Your account has been deleted ---- English message bellow. ---- Bonjour Votre compte est inactif depuis plus de """+days+""" jours. Vous n'avez pas donné suite à notre mail d'hier. Nous avons donc clôturé votre compte. Cordialement L'équipe d'administration de """+email['fromname']+""". -------- Hello Your account has been inactive for more than """+days+""" days. You did not respond to our email yesterday. We have therefore closed your account. Without action on your part, your account will be closed within 7 days. Cordially The """+email['fromname']+"""'s administration team. """ try: smtpObj = smtplib.SMTP(email['host'], email['port']) smtpObj.ehlo() if email['encryption'] == "SSL": smtpObj.ssl() elif email['encryption'] == "STARTTLS": smtpObj.starttls() else: log.warning("No encryption select. It's dangerous") smtpObj.login(email['username'], email['password']) smtpObj.sendmail(sender, receivers, message.replace("\xe9", "").encode("ascii", errors="ignore")) log.info("Successfully sent email") except smtplib.SMTPException as e: log.debug(e) log.error("Error: unable to send email") def main(): parser = argparse.ArgumentParser(description='Choose between alert, list or drop old accounts') parser.add_argument("-a", "--alert", action='store_true', help="Alert account by email") parser.add_argument("-l", "--list", action='store_true', help="Only list old accounts (dry run mode)") parser.add_argument("-d", "--drop", action='store_true', help="Drop old accounts") parser.add_argument("--forceyes", action='store_true', help="Accept dropping old accounts") parser.add_argument("--days", help="Number of days to keep account") args = parser.parse_args() if args.list: list_accounts(args.days) elif args.alert: alert_accounts(args.days) elif args.drop: if args.forceyes: drop_accounts else: print("Please use --forceyes to confirm dropping accounts") else: print("Require an argument. Use --help to display help") main()