initial commit
This commit is contained in:
commit
7430004adb
|
@ -0,0 +1,208 @@
|
||||||
|
Apache License
|
||||||
|
|
||||||
|
Version 2.0, January 2004
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION,
|
||||||
|
AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction, and distribution
|
||||||
|
as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
||||||
|
owner that is granting the License.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all other entities
|
||||||
|
that control, are controlled by, or are under common control with that entity.
|
||||||
|
For the purposes of this definition, "control" means (i) the power, direct
|
||||||
|
or indirect, to cause the direction or management of such entity, whether
|
||||||
|
by contract or otherwise, or (ii) ownership of fifty percent (50%) or more
|
||||||
|
of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions
|
||||||
|
granted by this License.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications, including
|
||||||
|
but not limited to software source code, documentation source, and configuration
|
||||||
|
files.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical transformation
|
||||||
|
or translation of a Source form, including but not limited to compiled object
|
||||||
|
code, generated documentation, and conversions to other media types.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or Object form,
|
||||||
|
made available under the License, as indicated by a copyright notice that
|
||||||
|
is included in or attached to the work (an example is provided in the Appendix
|
||||||
|
below).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object form,
|
||||||
|
that is based on (or derived from) the Work and for which the editorial revisions,
|
||||||
|
annotations, elaborations, or other modifications represent, as a whole, an
|
||||||
|
original work of authorship. For the purposes of this License, Derivative
|
||||||
|
Works shall not include works that remain separable from, or merely link (or
|
||||||
|
bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including the original version
|
||||||
|
of the Work and any modifications or additions to that Work or Derivative
|
||||||
|
Works thereof, that is intentionally submitted to Licensor for inclusion in
|
||||||
|
the Work by the copyright owner or by an individual or Legal Entity authorized
|
||||||
|
to submit on behalf of the copyright owner. For the purposes of this definition,
|
||||||
|
"submitted" means any form of electronic, verbal, or written communication
|
||||||
|
sent to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems, and
|
||||||
|
issue tracking systems that are managed by, or on behalf of, the Licensor
|
||||||
|
for the purpose of discussing and improving the Work, but excluding communication
|
||||||
|
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||||
|
owner as "Not a Contribution."
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
||||||
|
of whom a Contribution has been received by Licensor and subsequently incorporated
|
||||||
|
within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of this
|
||||||
|
License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable copyright license to reproduce, prepare
|
||||||
|
Derivative Works of, publicly display, publicly perform, sublicense, and distribute
|
||||||
|
the Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of this License,
|
||||||
|
each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable (except as stated in this section) patent
|
||||||
|
license to make, have made, use, offer to sell, sell, import, and otherwise
|
||||||
|
transfer the Work, where such license applies only to those patent claims
|
||||||
|
licensable by such Contributor that are necessarily infringed by their Contribution(s)
|
||||||
|
alone or by combination of their Contribution(s) with the Work to which such
|
||||||
|
Contribution(s) was submitted. If You institute patent litigation against
|
||||||
|
any entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that the Work or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses granted to You
|
||||||
|
under this License for that Work shall terminate as of the date such litigation
|
||||||
|
is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the Work or
|
||||||
|
Derivative Works thereof in any medium, with or without modifications, and
|
||||||
|
in Source or Object form, provided that You meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or Derivative Works a copy
|
||||||
|
of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices stating that
|
||||||
|
You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works that You distribute,
|
||||||
|
all copyright, patent, trademark, and attribution notices from the Source
|
||||||
|
form of the Work, excluding those notices that do not pertain to any part
|
||||||
|
of the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its distribution,
|
||||||
|
then any Derivative Works that You distribute must include a readable copy
|
||||||
|
of the attribution notices contained within such NOTICE file, excluding those
|
||||||
|
notices that do not pertain to any part of the Derivative Works, in at least
|
||||||
|
one of the following places: within a NOTICE text file distributed as part
|
||||||
|
of the Derivative Works; within the Source form or documentation, if provided
|
||||||
|
along with the Derivative Works; or, within a display generated by the Derivative
|
||||||
|
Works, if and wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and do not modify the
|
||||||
|
License. You may add Your own attribution notices within Derivative Works
|
||||||
|
that You distribute, alongside or as an addendum to the NOTICE text from the
|
||||||
|
Work, provided that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and may provide
|
||||||
|
additional or different license terms and conditions for use, reproduction,
|
||||||
|
or distribution of Your modifications, or for any such Derivative Works as
|
||||||
|
a whole, provided Your use, reproduction, and distribution of the Work otherwise
|
||||||
|
complies with the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise, any
|
||||||
|
Contribution intentionally submitted for inclusion in the Work by You to the
|
||||||
|
Licensor shall be under the terms and conditions of this License, without
|
||||||
|
any additional terms or conditions. Notwithstanding the above, nothing herein
|
||||||
|
shall supersede or modify the terms of any separate license agreement you
|
||||||
|
may have executed with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade names,
|
||||||
|
trademarks, service marks, or product names of the Licensor, except as required
|
||||||
|
for reasonable and customary use in describing the origin of the Work and
|
||||||
|
reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or agreed to
|
||||||
|
in writing, Licensor provides the Work (and each Contributor provides its
|
||||||
|
Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, either express or implied, including, without limitation, any warranties
|
||||||
|
or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness
|
||||||
|
of using or redistributing the Work and assume any risks associated with Your
|
||||||
|
exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory, whether
|
||||||
|
in tort (including negligence), contract, or otherwise, unless required by
|
||||||
|
applicable law (such as deliberate and grossly negligent acts) or agreed to
|
||||||
|
in writing, shall any Contributor be liable to You for damages, including
|
||||||
|
any direct, indirect, special, incidental, or consequential damages of any
|
||||||
|
character arising as a result of this License or out of the use or inability
|
||||||
|
to use the Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all other commercial
|
||||||
|
damages or losses), even if such Contributor has been advised of the possibility
|
||||||
|
of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing the Work
|
||||||
|
or Derivative Works thereof, You may choose to offer, and charge a fee for,
|
||||||
|
acceptance of support, warranty, indemnity, or other liability obligations
|
||||||
|
and/or rights consistent with this License. However, in accepting such obligations,
|
||||||
|
You may act only on Your own behalf and on Your sole responsibility, not on
|
||||||
|
behalf of any other Contributor, and only if You agree to indemnify, defend,
|
||||||
|
and hold each Contributor harmless for any liability incurred by, or claims
|
||||||
|
asserted against, such Contributor by reason of your accepting any such warranty
|
||||||
|
or additional liability. END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following boilerplate
|
||||||
|
notice, with the fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
information. (Don't include the brackets!) The text should be enclosed in
|
||||||
|
the appropriate comment syntax for the file format. We also recommend that
|
||||||
|
a file or class name and description of purpose be included on the same "printed
|
||||||
|
page" as the copyright notice for easier identification within third-party
|
||||||
|
archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
|
||||||
|
limitations under the License.
|
|
@ -0,0 +1,13 @@
|
||||||
|
# matrix-synapse-GDPR
|
||||||
|
|
||||||
|
GDPR 100% compilant matrix synapse user data deletion script in Python 3.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Clone the repo **wherever you** want and execute the scripts from the project root path
|
||||||
|
2. Install `psycopg2` either using pip or by package name `python3-psycopg2`
|
||||||
|
3. Configure `postgres.conf` to your own needs (see file)
|
||||||
|
|
||||||
|
The main script to delete a user is `python3 user_delete.py` (see --help)
|
||||||
|
|
||||||
|
ALWAYS make a **backup of your database** before deleting data!!
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"hostname": "127.0.0.1",
|
||||||
|
"port": 5432,
|
||||||
|
"username": "postgres",
|
||||||
|
"database": "synapse"
|
||||||
|
}
|
|
@ -0,0 +1,147 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
import psycopg2
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
|
||||||
|
# Note:
|
||||||
|
# Not all queries are safe for SQL injection,
|
||||||
|
# please dont use this as an API for user input,
|
||||||
|
# or at least secure it for system administrators!
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='GDPR 100% compilant matrix synapse user data deletion script in Python3.')
|
||||||
|
group = parser.add_mutually_exclusive_group(required=False)
|
||||||
|
group.add_argument('-t', '--dryrun', action='store_true', help='Dry run, just SELECT rows instead of DELETE')
|
||||||
|
group.add_argument('-y', '--yes', action='store_true', help='Do not ask confirmations to DELETE commands')
|
||||||
|
group2 = parser.add_argument_group('required arguments')
|
||||||
|
group2.add_argument('user_ids', metavar='UID', type=str, nargs='+', help='The user id/ids to delete')
|
||||||
|
args = parser.parse_args(sys.argv[1:])
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn = psql_connect()
|
||||||
|
tables = psql_showtables(conn)
|
||||||
|
for user in args.user_ids:
|
||||||
|
ushort = re.search(r'(?<=^@)\w+', user).group(0).strip()
|
||||||
|
print('UID {} NAME {}'.format(user, ushort))
|
||||||
|
for table in tables:
|
||||||
|
cols = psql_describe(conn, table)
|
||||||
|
for col in cols:
|
||||||
|
if col in ('user_id', 'name'):
|
||||||
|
_psql_deletesafe(args, conn, 'DELETE FROM {} WHERE {} = %s'.format(table, col), (user,))
|
||||||
|
|
||||||
|
_psql_deletesafe(args, conn, 'DELETE FROM device_inbox WHERE message_json LIKE \'%{}%\''.format(user))
|
||||||
|
_psql_deletesafe(args, conn, 'DELETE FROM current_state_delta_stream WHERE state_key LIKE \'%{}%\''.format(user))
|
||||||
|
_psql_deletesafe(args, conn, 'DELETE FROM cache_invalidation_stream WHERE %s = ANY(keys)', (user,))
|
||||||
|
_psql_deletesafe(args, conn, 'DELETE FROM current_state_events WHERE state_key = %s', (user,))
|
||||||
|
_psql_deletesafe(args, conn, 'DELETE FROM event_json WHERE json LIKE \'%{}%\''.format(user))
|
||||||
|
_psql_deletesafe(args, conn, 'DELETE FROM events WHERE sender = %s', (user,))
|
||||||
|
_psql_deletesafe(args, conn, 'DELETE FROM local_invites WHERE invitee = %s OR inviter = %s', (user,user,))
|
||||||
|
_psql_deletesafe(args, conn, 'DELETE FROM profiles WHERE user_id = %s', (ushort,))
|
||||||
|
_psql_deletesafe(args, conn, 'DELETE FROM rooms WHERE creator = %s', (user,))
|
||||||
|
_psql_deletesafe(args, conn, 'DELETE FROM state_events WHERE state_key LIKE \'%{}%\' OR prev_state LIKE \'%{}%\''.format(user, user))
|
||||||
|
_psql_deletesafe(args, conn, 'DELETE FROM state_groups_state WHERE state_key LIKE \'%{}%\''.format(user))
|
||||||
|
_psql_deletesafe(args, conn, 'DELETE FROM user_filters WHERE user_id = %s', (ushort,))
|
||||||
|
_psql_deletesafe(args, conn, 'DELETE FROM room_memberships WHERE user_id = %s OR sender = %s', (user,user,))
|
||||||
|
|
||||||
|
_custom__delete_account_relations(conn, user)
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\nAborted.")
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def _custom__delete_account_relations(conn, user):
|
||||||
|
print('*** [CUSTOM] UPDATE account_data "content" json')
|
||||||
|
md5s = psql_getall(conn, 'SELECT md5(content) FROM account_data WHERE content LIKE \'%{}%\''.format(user))
|
||||||
|
if len(md5s) == 0:
|
||||||
|
print('NOTHING TO UPDATE')
|
||||||
|
return False
|
||||||
|
for md5 in md5s:
|
||||||
|
print('MD5 content: {}'.format(md5))
|
||||||
|
content = psql_getone(conn, 'SELECT content FROM account_data WHERE md5(content) = %s', (md5,))
|
||||||
|
jscontent = json.loads(content); del jscontent[user]
|
||||||
|
content = json.dumps(jscontent)
|
||||||
|
rcnt = psql_update(conn, 'UPDATE account_data SET content = %s WHERE md5(content) = %s', (content, md5,))
|
||||||
|
print('UPDATED {}'.format(rcnt))
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Note: to myself
|
||||||
|
# i could do this using the conn.commit() function instead
|
||||||
|
# but i wanted to make it more human fail safe and call another function
|
||||||
|
# to keep things separated
|
||||||
|
def _psql_deletesafe(pargs, conn, sql, args=None):
|
||||||
|
sqls = re.sub(r'(?i)^delete from', 'SELECT COUNT(1) FROM', sql)
|
||||||
|
count = psql_getone(conn, sqls, args)
|
||||||
|
|
||||||
|
if not args is None:
|
||||||
|
print('*** [ARGS] >> {}'.format(', '.join(args)))
|
||||||
|
|
||||||
|
if pargs.dryrun:
|
||||||
|
print('*** [DRY_RUN] >> {}'.format(sql))
|
||||||
|
print('DELETE {}'.format(count))
|
||||||
|
print()
|
||||||
|
return -1
|
||||||
|
|
||||||
|
if not pargs.yes:
|
||||||
|
y = input('{} [Y/n]: '.format(sql)).strip().lower()
|
||||||
|
if y == 'n':
|
||||||
|
return -2
|
||||||
|
|
||||||
|
print('*** [EXECUTE] >> {}'.format(sql))
|
||||||
|
rcnt = psql_delete(conn, sql, args)
|
||||||
|
print('DELETE {}'.format(rcnt))
|
||||||
|
print()
|
||||||
|
return rcnt
|
||||||
|
|
||||||
|
def psql_describe(conn, table):
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute('SELECT * FROM {} LIMIT 0'.format(table))
|
||||||
|
cols = [desc[0] for desc in cur.description]
|
||||||
|
cur.close()
|
||||||
|
return cols
|
||||||
|
|
||||||
|
def psql_showtables(conn):
|
||||||
|
out = psql_getall(conn, "SELECT relname FROM pg_class WHERE relkind='r' AND relname !~ '^(pg_|sql_)'")
|
||||||
|
tables = []
|
||||||
|
for row in out:
|
||||||
|
tables.append(row[0])
|
||||||
|
return tables
|
||||||
|
|
||||||
|
def psql_connect():
|
||||||
|
conf = json.loads(fread('postgres.conf'))
|
||||||
|
conn = psycopg2.connect(host=conf['hostname'], port=conf['port'],\
|
||||||
|
user=conf['username'], database=conf['database'])
|
||||||
|
return conn
|
||||||
|
|
||||||
|
def psql_update(conn, sql, args=None):
|
||||||
|
return psql_delete(conn, sql, args)
|
||||||
|
|
||||||
|
def psql_delete(conn, sql, args=None):
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute(sql, args)
|
||||||
|
rowcount = cur.rowcount
|
||||||
|
conn.commit()
|
||||||
|
cur.close()
|
||||||
|
return rowcount
|
||||||
|
|
||||||
|
def psql_getone(conn, sql, args=None):
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute(sql, args)
|
||||||
|
row = cur.fetchone()
|
||||||
|
cur.close()
|
||||||
|
return row[0]
|
||||||
|
|
||||||
|
def psql_getall(conn, sql, args=None):
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute(sql, args)
|
||||||
|
rows = cur.fetchall()
|
||||||
|
cur.close()
|
||||||
|
return rows
|
||||||
|
|
||||||
|
def fread(f):
|
||||||
|
r=open(f,'r');c=r.read().strip();r.close();return c
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
Loading…
Reference in New Issue