Added ability to download account data.
This commit is contained in:
parent
d8cb913892
commit
9da4b6a123
10 changed files with 166 additions and 3 deletions
16
assets/less/settings/data.less
Normal file
16
assets/less/settings/data.less
Normal file
|
@ -0,0 +1,16 @@
|
|||
.settings__data {
|
||||
|
||||
&__content {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
&__password {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
margin-top: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
|
@ -3,4 +3,9 @@
|
|||
&__pagination {
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
&__none {
|
||||
padding: 2px 5px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
@import "account-logs";
|
||||
@import "account";
|
||||
@import "container";
|
||||
@import "data";
|
||||
@import "description";
|
||||
@import "login-attempt";
|
||||
@import "login-attempts";
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
&__menu {
|
||||
width: 280px;
|
||||
margin-right: 2px;
|
||||
|
|
81
public/settings/data.php
Normal file
81
public/settings/data.php
Normal file
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
require_once '../../misuzu.php';
|
||||
|
||||
if(!user_session_active()) {
|
||||
echo render_error(401);
|
||||
return;
|
||||
}
|
||||
|
||||
function db_to_zip(ZipArchive $archive, int $userId, string $filename, string $query, int $params = 1): void {
|
||||
$prepare = db_prepare($query);
|
||||
|
||||
if($params < 2) {
|
||||
$prepare->bindValue('user_id', $userId);
|
||||
} else {
|
||||
for($i = 1; $i <= $params; $i++) {
|
||||
$prepare->bindValue('user_id_' . $i, $userId);
|
||||
}
|
||||
}
|
||||
|
||||
$archive->addFromString($filename, json_encode(db_fetch_all($prepare), JSON_PRETTY_PRINT));
|
||||
}
|
||||
|
||||
$errors = [];
|
||||
$currentUserId = user_session_current('user_id');
|
||||
|
||||
if(isset($_POST['action']) && is_string($_POST['action'])) {
|
||||
if(isset($_POST['password']) && is_string($_POST['password'])
|
||||
&& user_password_verify_db($currentUserId, $_POST['password'])) {
|
||||
switch($_POST['action']) {
|
||||
case 'data':
|
||||
audit_log(MSZ_AUDIT_PERSONAL_DATA_DOWNLOAD, $currentUserId);
|
||||
|
||||
$filename = tempnam(sys_get_temp_dir(), 'msz');
|
||||
$archive = new ZipArchive;
|
||||
$archive->open($filename, ZipArchive::CREATE);
|
||||
|
||||
db_to_zip($archive, $currentUserId, 'audit_log.json', 'SELECT *, INET6_NTOA(`log_ip`) AS `log_ip` FROM `msz_audit_log` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'auth_tfa.json', 'SELECT * FROM `msz_auth_tfa` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'changelog_changes.json', 'SELECT * FROM `msz_changelog_changes` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'comments_posts.json', 'SELECT * FROM `msz_comments_posts` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'comments_votes.json', 'SELECT * FROM `msz_comments_votes` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'forum_permissions.json', 'SELECT * FROM `msz_forum_permissions` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'forum_polls_answers.json', 'SELECT * FROM `msz_forum_polls_answers` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'forum_posts.json', 'SELECT *, INET6_NTOA(`post_ip`) AS `post_ip` FROM `msz_forum_posts` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'forum_posts_reactions.json', 'SELECT * FROM `msz_forum_posts_reactions` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'forum_topics.json', 'SELECT * FROM `msz_forum_topics` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'forum_topics_priority.json', 'SELECT * FROM `msz_forum_topics_priority` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'forum_topics_track.json', 'SELECT * FROM `msz_forum_topics_track` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'login_attempts.json', 'SELECT *, INET6_NTOA(`attempt_ip`) AS `attempt_ip` FROM `msz_login_attempts` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'news_posts.json', 'SELECT * FROM `msz_news_posts` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'permissions.json', 'SELECT * FROM `msz_permissions` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'sessions.json', 'SELECT *, INET6_NTOA(`session_ip`) AS `session_ip`, INET6_NTOA(`session_ip_last`) AS `session_ip_last` FROM `msz_sessions` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'users.json', 'SELECT *, NULL AS `password`, NULL AS `user_totp_key`, INET6_NTOA(`register_ip`) AS `register_ip`, INET6_NTOA(`last_ip`) AS `last_ip` FROM `msz_users` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'users_password_resets.json', 'SELECT *, INET6_NTOA(`reset_ip`) AS `reset_ip` FROM `msz_users_password_resets` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'user_relations.json', 'SELECT * FROM `msz_user_relations` WHERE `user_id` = :user_id_1 OR `subject_id` = :user_id_2', 2);
|
||||
db_to_zip($archive, $currentUserId, 'user_roles.json', 'SELECT * FROM `msz_user_roles` WHERE `user_id` = :user_id');
|
||||
db_to_zip($archive, $currentUserId, 'user_warnings.json', 'SELECT *, INET6_NTOA(`user_ip`) AS `user_ip`, NULL AS `issuer_id`, NULL AS `issuer_ip`, NULL AS `warning_note_private` FROM `msz_user_warnings` WHERE `user_id` = :user_id');
|
||||
|
||||
$archive->close();
|
||||
|
||||
header('Content-Type: application/zip');
|
||||
header(sprintf(
|
||||
'Content-Disposition: inline; filename="misuzu-user-data-%d-%d.zip"',
|
||||
$currentUserId,
|
||||
time()
|
||||
));
|
||||
echo file_get_contents($filename);
|
||||
return;
|
||||
|
||||
case 'deactivate':
|
||||
// deactivation
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$errors[] = 'Incorrect password.';
|
||||
}
|
||||
}
|
||||
|
||||
echo tpl_render('settings.data', [
|
||||
'errors' => $errors,
|
||||
]);
|
|
@ -3,6 +3,7 @@ audit_log_define('PERSONAL_EMAIL_CHANGE');
|
|||
audit_log_define('PERSONAL_PASSWORD_CHANGE');
|
||||
audit_log_define('PERSONAL_SESSION_DESTROY');
|
||||
audit_log_define('PERSONAL_SESSION_DESTROY_ALL');
|
||||
audit_log_define('PERSONAL_DATA_DOWNLOAD');
|
||||
audit_log_define('PASSWORD_RESET');
|
||||
audit_log_define('CHANGELOG_ENTRY_CREATE');
|
||||
audit_log_define('CHANGELOG_ENTRY_EDIT');
|
||||
|
@ -62,6 +63,7 @@ define('MSZ_AUDIT_LOG_STRINGS', [
|
|||
MSZ_AUDIT_FORUM_TOPIC_BUMP => 'Manually bumped forum topic #%d.',
|
||||
MSZ_AUDIT_FORUM_TOPIC_LOCK => 'Locked forum topic #%d.',
|
||||
MSZ_AUDIT_FORUM_TOPIC_UNLOCK => 'Unlocked forum topic #%d.',
|
||||
MSZ_AUDIT_PERSONAL_DATA_DOWNLOAD => 'Downloaded archive of account data.',
|
||||
]);
|
||||
|
||||
function audit_log_define(string $name): void {
|
||||
|
|
|
@ -84,6 +84,7 @@ define('MSZ_URLS', [
|
|||
'settings-account' => ['/settings/account.php'],
|
||||
'settings-sessions' => ['/settings/sessions.php'],
|
||||
'settings-logs' => ['/settings/logs.php'],
|
||||
'settings-data' => ['/settings/data.php'],
|
||||
|
||||
'comment-create' => ['/comments.php', ['m' => 'create']],
|
||||
'comment-vote' => ['/comments.php', ['c' => '<comment>', 'csrf' => '{csrf}', 'm' => 'vote', 'v' => '<vote>']],
|
||||
|
|
42
templates/settings/data.twig
Normal file
42
templates/settings/data.twig
Normal file
|
@ -0,0 +1,42 @@
|
|||
{% extends 'settings/master.twig' %}
|
||||
{% from 'macros.twig' import container_title %}
|
||||
{% from '_layout/input.twig' import input_hidden, input_csrf, input_text, input_select %}
|
||||
|
||||
{% set title = 'Settings / Data' %}
|
||||
|
||||
{% block settings_content %}
|
||||
<form action="{{ url('settings-data') }}" method="post" class="container settings__container">
|
||||
{{ container_title('<i class="fas fa-database fa-fw"></i> Download account data') }}
|
||||
{{ input_csrf() }}
|
||||
|
||||
<div class="settings__description">
|
||||
<p>Here you can request raw json files containing pretty much all data relating to your account. Moderator identities are concealed and password hashes are removed from the output.</p>
|
||||
</div>
|
||||
|
||||
<div class="settings__data__content">
|
||||
{{ input_text('password', 'settings__data__password', '', 'password', 'Password', true) }}
|
||||
|
||||
<div class="settings__data__actions">
|
||||
<button class="input__button" name="action" value="data">Download</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{#<form action="{{ url('settings-data') }}" method="post" class="container settings__container">
|
||||
{{ container_title('<i class="fas fa-trash-alt fa-fw"></i> Deactivate account') }}
|
||||
{{ input_csrf() }}
|
||||
|
||||
<div class="settings__description">
|
||||
<p>Deactivation will mark your account for deletion after 7 days unless you log in again. All content associated with your account EXCEPT forum topics and posts will be irrecoverably removed after these 7 days. Forum topics and posts will become associated with a default user effectively removing your identity from them. If you wish to have your forum posts removed please contact staff.</p>
|
||||
<p><b>Temporarily deactivating as a means to gain attention of some kind is frowned upon and you will likely be banned after returning. Use this feature cautiously.</b></p>
|
||||
</div>
|
||||
|
||||
<div class="settings__data__content">
|
||||
{{ input_text('password', 'settings__data__password', '', 'password', 'Password', true) }}
|
||||
|
||||
<div class="settings__data__actions">
|
||||
<button class="input__button" name="action" value="deactivate" onclick="return confirm('Are you absolutely sure?');">Deactivate</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>#}
|
||||
{% endblock %}
|
|
@ -20,9 +20,15 @@
|
|||
{{ lhpagination }}
|
||||
</div>
|
||||
|
||||
{% if login_history_list|length < 1 %}
|
||||
<div class="settings__login-attempts__none">
|
||||
There are no recent log in attempts to display.
|
||||
</div>
|
||||
{% else %}
|
||||
{% for attempt in login_history_list %}
|
||||
{{ user_login_attempt(attempt) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<div class="settings__login-attempts__pagination">
|
||||
{{ lhpagination }}
|
||||
|
|
|
@ -17,6 +17,11 @@
|
|||
'title': 'Logs',
|
||||
'url': url('settings-logs'),
|
||||
},
|
||||
{
|
||||
'icon': 'fas fa-database fa-fw',
|
||||
'title': 'Data',
|
||||
'url': url('settings-data'),
|
||||
},
|
||||
] %}
|
||||
|
||||
{% block content %}
|
||||
|
|
Loading…
Add table
Reference in a new issue