201 lines
8.0 KiB
Python
Executable File
201 lines
8.0 KiB
Python
Executable File
#!/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()
|