| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- #!/usr/bin/env python3
- # Script for erasing all data about a user from the database.
- # Intended for GDPR erasure requests.
- #
- # NOTE: We recommend implementing a "GDPR Erasure Ban" on the user's last IP/HWID before erasing their data, to prevent abuse.
- # This is acceptable under the GDPR as a "legitimate interest" to prevent GDPR erasure being used to avoid moderation/bans.
- # You would need to do this *before* running this script, to avoid losing the IP/HWID of the user entirely.
- import argparse
- import os
- import psycopg2
- from uuid import UUID
- LATEST_DB_MIGRATION = "20230725193102_AdminNotesImprovementsForeignKeys"
- def main():
- parser = argparse.ArgumentParser()
- # Yes we need both to reliably pseudonymize the admin_log table.
- parser.add_argument("user_id", help="User ID to erase data for")
- parser.add_argument("user_name", help="User name to erase data for")
- parser.add_argument("--ignore-schema-mismatch", action="store_true")
- parser.add_argument("--connection-string", required=True, help="Database connection string to use. See https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING")
- args = parser.parse_args()
- conn = psycopg2.connect(args.connection_string)
- cur = conn.cursor()
- check_schema_version(cur, args.ignore_schema_mismatch)
- user_id = args.user_id
- user_name = args.user_name
- clear_admin(cur, user_id)
- pseudonymize_admin_log(cur, user_name, user_id)
- clear_assigned_user_id(cur, user_id)
- clear_connection_log(cur, user_id)
- clear_play_time(cur, user_id)
- clear_player(cur, user_id)
- clear_preference(cur, user_id)
- clear_server_ban(cur, user_id)
- clear_server_ban_exemption(cur, user_id)
- clear_server_role_ban(cur, user_id)
- clear_uploaded_resource_log(cur, user_id)
- clear_whitelist(cur, user_id)
- print("Committing...")
- conn.commit()
- def check_schema_version(cur: "psycopg2.cursor", ignore_mismatch: bool):
- cur.execute('SELECT "MigrationId" FROM "__EFMigrationsHistory" ORDER BY "__EFMigrationsHistory" DESC LIMIT 1')
- schema_version = cur.fetchone()
- if schema_version == None:
- print("Unable to read database schema version.")
- exit(1)
- if schema_version[0] != LATEST_DB_MIGRATION:
- print(f"Unsupport schema version of DB: '{schema_version[0]}'. Supported: {LATEST_DB_MIGRATION}")
- if ignore_mismatch:
- return
- exit(1)
- def clear_admin(cur: "psycopg2.cursor", user_id: str):
- print("Clearing admin...")
- cur.execute("""
- DELETE FROM
- admin
- WHERE
- user_id = %s
- """, (user_id,))
- def pseudonymize_admin_log(cur: "psycopg2.cursor", user_name: str, user_id: str):
- print("Pseudonymizing admin_log...")
- cur.execute("""
- UPDATE
- admin_log l
- SET
- message = replace(message, %s, %s)
- FROM
- admin_log_player lp
- WHERE
- lp.round_id = l.round_id AND lp.log_id = l.admin_log_id AND player_user_id = %s;
- """, (user_name, user_id, user_id,))
- def clear_assigned_user_id(cur: "psycopg2.cursor", user_id: str):
- print("Clearing assigned_user_id...")
- cur.execute("""
- DELETE FROM
- assigned_user_id
- WHERE
- user_id = %s
- """, (user_id,))
- def clear_connection_log(cur: "psycopg2.cursor", user_id: str):
- print("Clearing connection_log...")
- cur.execute("""
- DELETE FROM
- connection_log
- WHERE
- user_id = %s
- """, (user_id,))
- def clear_play_time(cur: "psycopg2.cursor", user_id: str):
- print("Clearing play_time...")
- cur.execute("""
- DELETE FROM
- play_time
- WHERE
- player_id = %s
- """, (user_id,))
- def clear_player(cur: "psycopg2.cursor", user_id: str):
- print("Clearing player...")
- cur.execute("""
- DELETE FROM
- player
- WHERE
- user_id = %s
- """, (user_id,))
- def clear_preference(cur: "psycopg2.cursor", user_id: str):
- print("Clearing preference...")
- cur.execute("""
- DELETE FROM
- preference
- WHERE
- user_id = %s
- """, (user_id,))
- def clear_server_ban(cur: "psycopg2.cursor", user_id: str):
- print("Clearing server_ban...")
- cur.execute("""
- DELETE FROM
- server_ban
- WHERE
- player_user_id = %s
- """, (user_id,))
- def clear_server_ban_exemption(cur: "psycopg2.cursor", user_id: str):
- print("Clearing server_ban_exemption...")
- cur.execute("""
- DELETE FROM
- server_ban_exemption
- WHERE
- user_id = %s
- """, (user_id,))
- def clear_server_role_ban(cur: "psycopg2.cursor", user_id: str):
- print("Clearing server_role_ban...")
- cur.execute("""
- DELETE FROM
- server_role_ban
- WHERE
- player_user_id = %s
- """, (user_id,))
- def clear_uploaded_resource_log(cur: "psycopg2.cursor", user_id: str):
- print("Clearing uploaded_resource_log...")
- cur.execute("""
- DELETE FROM
- uploaded_resource_log
- WHERE
- user_id = %s
- """, (user_id,))
- def clear_whitelist(cur: "psycopg2.cursor", user_id: str):
- print("Clearing whitelist...")
- cur.execute("""
- DELETE FROM
- whitelist
- WHERE
- user_id = %s
- """, (user_id,))
- main()
- # "I'm surprised you managed to write this entire Python file without spamming the word 'sus' everywhere." - Remie
|