mirror of
https://github.com/wassname/talk.git
synced 2026-07-01 00:35:55 +08:00
Merge branch 'gdpr-delete' of github.com:coralproject/talk into gdpr-delete
* 'gdpr-delete' of github.com:coralproject/talk: typo cleaned up config as js instead of json file added space added durations to configuration file Update copy to reflect ability to take action up until account is deleted added docs Added TALK_ prefix to constants RECAPTCHA_WINDOW and RECAPTCHA_INCORRECT_TRIGGER RECAPTCHA_WINDOW and RECAPTCHA_INCORRECT_TRIGGER now can be set with env vars
This commit is contained in:
@@ -212,6 +212,13 @@ const CONFIG = {
|
||||
RECAPTCHA_PUBLIC: process.env.TALK_RECAPTCHA_PUBLIC,
|
||||
RECAPTCHA_SECRET: process.env.TALK_RECAPTCHA_SECRET,
|
||||
|
||||
// RECAPTCHA_WINDOW is the rate limit's time interval
|
||||
RECAPTCHA_WINDOW: process.env.TALK_RECAPTCHA_WINDOW || '10m',
|
||||
|
||||
// After RECAPTCHA_INCORRECT_TRIGGER incorrect attempts, recaptcha will be required.
|
||||
RECAPTCHA_INCORRECT_TRIGGER:
|
||||
process.env.TALK_RECAPTCHA_INCORRECT_TRIGGER || 5,
|
||||
|
||||
// WEBSOCKET_LIVE_URI is the absolute url to the live endpoint.
|
||||
WEBSOCKET_LIVE_URI: process.env.TALK_WEBSOCKET_LIVE_URI || null,
|
||||
|
||||
|
||||
@@ -316,6 +316,18 @@ default to providing only a time based lockout. Refer to
|
||||
[reCAPTCHA](https://www.google.com/recaptcha/intro/index.html) for information
|
||||
on getting an account setup.
|
||||
|
||||
## TALK_RECAPTCHA_WINDOW
|
||||
|
||||
The rate limit time interval that there can be [TALK_RECAPTCHA_INCORRECT_TRIGGER](#talk_recaptcha_incorrect_trigger) incorrect attempts until the reCAPTCHA is
|
||||
marked as required, parsed by
|
||||
[ms](https://www.npmjs.com/package/ms). (Default `10m`)
|
||||
|
||||
## TALK_RECAPTCHA_INCORRECT_TRIGGER
|
||||
|
||||
The number of times that an incorrect login can be entered before within a time
|
||||
perioud indicated by [TALK_RECAPTCHA_WINDOW](#talk_recaptcha_window) until the
|
||||
reCAPTCHA is marked as required. (Default `5`)
|
||||
|
||||
## TALK_REDIS_CLIENT_CONFIGURATION
|
||||
|
||||
Configuration overrides for the redis client configuration in a JSON encoded
|
||||
@@ -531,4 +543,4 @@ Sets the logging level for the context logger (from [Bunyan](https://github.com/
|
||||
A JSON string representing the configuration passed to the
|
||||
[fetch](https://www.npmjs.com/package/node-fetch) call for the scraper. It
|
||||
can be used to set an authorization header, or change the user agent. (Default
|
||||
`{}`)
|
||||
`{}`)
|
||||
|
||||
@@ -6,6 +6,7 @@ import moment from 'moment';
|
||||
import { Button, Icon } from 'plugin-api/beta/client/components/ui';
|
||||
import styles from './AccountDeletionRequestedSign.css';
|
||||
import { getErrorMessages } from 'coral-framework/utils';
|
||||
import { scheduledDeletionDelayHours } from '../../config';
|
||||
|
||||
class AccountDeletionRequestedSign extends React.Component {
|
||||
cancelAccountDeletion = async () => {
|
||||
@@ -25,7 +26,7 @@ class AccountDeletionRequestedSign extends React.Component {
|
||||
'MMM Do YYYY, h:mm a'
|
||||
);
|
||||
const deletionScheduledOn = moment(scheduledDeletionDate)
|
||||
.subtract(24, 'hours')
|
||||
.subtract(scheduledDeletionDelayHours, 'hours')
|
||||
.format('MMM Do YYYY, h:mm a');
|
||||
|
||||
return (
|
||||
|
||||
@@ -33,7 +33,7 @@ const DeleteMyAccountFinalStep = props => (
|
||||
|
||||
<p className={styles.description}>
|
||||
<strong>{t('delete_request.tell_us_why')}.</strong>{' '}
|
||||
{t('delete_request.feedback_copy')}
|
||||
{t('delete_request.feedback_copy')}{' '}
|
||||
<a href={`mailto:${props.organizationContactEmail}`}>
|
||||
{props.organizationContactEmail}
|
||||
</a>.
|
||||
|
||||
@@ -4,16 +4,17 @@ import cn from 'classnames';
|
||||
import { Button } from 'plugin-api/beta/client/components/ui';
|
||||
import styles from './DeleteMyAccountStep.css';
|
||||
import { t } from 'plugin-api/beta/client/services';
|
||||
import { scheduledDeletionDelayHours } from '../../config';
|
||||
|
||||
const DeleteMyAccountStep1 = props => (
|
||||
<div className={styles.step}>
|
||||
<h4 className={styles.subTitle}>{t('delete_request.step_1.subtitle')}</h4>
|
||||
<p className={styles.description}>
|
||||
{t('delete_request.step_1.description')}
|
||||
{t('delete_request.step_1.description', scheduledDeletionDelayHours)}
|
||||
</p>
|
||||
<h4 className={styles.subTitle}>{t('delete_request.step_1.subtitle_2')}</h4>
|
||||
<p className={styles.description}>
|
||||
{t('delete_request.step_1.description_2')}
|
||||
{t('delete_request.step_1.description_2', scheduledDeletionDelayHours)}
|
||||
</p>
|
||||
<div className={cn(styles.actions)}>
|
||||
<Button
|
||||
|
||||
@@ -4,6 +4,7 @@ import { t } from 'plugin-api/beta/client/services';
|
||||
import { Button } from 'plugin-api/beta/client/components/ui';
|
||||
import styles from './DownloadCommentHistory.css';
|
||||
import { getErrorMessages } from 'coral-framework/utils';
|
||||
import { downloadRateLimitDays } from '../../config';
|
||||
|
||||
export const readableDuration = durAsHours => {
|
||||
const durAsDays = Math.ceil(durAsHours / 24);
|
||||
@@ -42,7 +43,8 @@ class DownloadCommentHistory extends Component {
|
||||
lastAccountDownload && new Date(lastAccountDownload);
|
||||
const hoursLeft = lastAccountDownloadDate
|
||||
? Math.ceil(
|
||||
7 * 24 - (now.getTime() - lastAccountDownloadDate.getTime()) / 3.6e6
|
||||
downloadRateLimitDays * 24 -
|
||||
(now.getTime() - lastAccountDownloadDate.getTime()) / 3.6e6
|
||||
)
|
||||
: 0;
|
||||
const canRequestDownload = !lastAccountDownloadDate || hoursLeft <= 0;
|
||||
@@ -52,7 +54,7 @@ class DownloadCommentHistory extends Component {
|
||||
<h3>{t('download_request.section_title')}</h3>
|
||||
<p>
|
||||
{t('download_request.you_will_get_a_copy')}{' '}
|
||||
<b>{t('download_request.download_rate')}</b>.
|
||||
<b>{t('download_request.download_rate', downloadRateLimitDays)}</b>.
|
||||
</p>
|
||||
{lastAccountDownloadDate && (
|
||||
<p className={styles.most_recent}>
|
||||
|
||||
@@ -2,7 +2,7 @@ en:
|
||||
download_request:
|
||||
section_title: "Download My Comment History"
|
||||
you_will_get_a_copy: "You will recieve an email with a link to download your comment history. You can make"
|
||||
download_rate: "one download request every 7 days"
|
||||
download_rate: "one download request every {0} days"
|
||||
most_recent_request: "Your most recent request"
|
||||
request: "Request Comment History"
|
||||
rate_limit: "You can submit another Comment History request in {0}"
|
||||
@@ -12,10 +12,10 @@ en:
|
||||
day: "{0} day"
|
||||
download_preparing: "Account Download Preparing - Check your email shortly for a download link"
|
||||
delete_request:
|
||||
account_deletion_cancelled: 'Account Deletion Request Cancelled - Your request to delete your account has been cancelled. You may now write comments, reply to comments, and select reactions.'
|
||||
account_deletion_cancelled: 'Account Deletion Request Cancelled - Your request to delete your account has been cancelled.'
|
||||
account_deletion_requested: 'Account Deletion Requested'
|
||||
received_on: "A request to delete your account was received on "
|
||||
cancel_request_description: "If you would like to continue leaving comments, replies or reactions, you may cancel your request to delete your account below"
|
||||
cancel_request_description: "If you would like to reactivate your account, you may cancel your request to delete your account below"
|
||||
before: "before"
|
||||
cancel_account_deletion_request: "Cancel Account Deletion Request"
|
||||
delete_my_account: "Delete My Account"
|
||||
@@ -38,9 +38,9 @@ en:
|
||||
item_3: "Your username and email address are removed from our system"
|
||||
step_1:
|
||||
subtitle: "When will my account be deleted?"
|
||||
description: "Your account will be deleted 24 hours after your request has been submitted."
|
||||
description: "Your account will be deleted {0} hours after your request has been submitted."
|
||||
subtitle_2: "Can I still write comments until my account is deleted?"
|
||||
description_2: "No. Once you have requested account deletion, you can no longer write comments, reply to comments, or select reactions."
|
||||
description_2: "Yes, you can still comment, reply, and react to comments until the {0} hours expires."
|
||||
step_2:
|
||||
description: "Before your account is deleted, we recommend you download your comment history for your records. After your account is deleted, you will be unable to request your comment history."
|
||||
to_download: "To download your comment history go to:"
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
scheduledDeletionDelayHours: 24,
|
||||
downloadRateLimitDays: 7,
|
||||
};
|
||||
@@ -8,6 +8,10 @@ const {
|
||||
} = require('./errors');
|
||||
const { ErrNotAuthorized, ErrMaxRateLimit } = require('errors');
|
||||
const { URL } = require('url');
|
||||
const {
|
||||
scheduledDeletionDelayHours,
|
||||
downloadRateLimitDays,
|
||||
} = require('../config');
|
||||
|
||||
// generateDownloadLinks will generate a signed set of links for a given user to
|
||||
// download an archive of their data.
|
||||
@@ -42,21 +46,26 @@ async function sendDownloadLink(ctx) {
|
||||
} = ctx;
|
||||
|
||||
// downloadLinkLimiter can be used to limit downloads for the user's data to
|
||||
// once every 7 days.
|
||||
const downloadLinkLimiter = new Limit('profileDataDownloadLimiter', 1, '7d');
|
||||
// once every ${downloadRateLimitDays} days.
|
||||
const downloadLinkLimiter = new Limit(
|
||||
'profileDataDownloadLimiter',
|
||||
1,
|
||||
`${downloadRateLimitDays}d`
|
||||
);
|
||||
|
||||
// Check that the user has not already requested a download within the last
|
||||
// 7 days.
|
||||
// ${downloadRateLimitDays} days.
|
||||
const attempts = await downloadLinkLimiter.get(user.id);
|
||||
if (attempts && attempts >= 1) {
|
||||
throw new ErrMaxRateLimit();
|
||||
}
|
||||
|
||||
// Check if the lastAccountDownload time is within 7 days.
|
||||
// Check if the lastAccountDownload time is within ${downloadRateLimitDays}
|
||||
// days.
|
||||
if (
|
||||
user.lastAccountDownload &&
|
||||
moment(user.lastAccountDownload)
|
||||
.add(7, 'days')
|
||||
.add(downloadRateLimitDays, 'days')
|
||||
.isAfter(moment())
|
||||
) {
|
||||
throw new ErrMaxRateLimit();
|
||||
@@ -93,16 +102,17 @@ async function sendDownloadLink(ctx) {
|
||||
}
|
||||
|
||||
// requestDeletion will schedule the current user to have their account deleted
|
||||
// by setting the `scheduledDeletionDate` on the user 24 hours from now.
|
||||
// by setting the `scheduledDeletionDate` on the user
|
||||
// ${scheduledDeletionDelayHours} hours from now.
|
||||
async function requestDeletion({ user, connectors: { models: { User } } }) {
|
||||
// Ensure the user doesn't already have a deletion scheduled.
|
||||
if (get(user, 'metadata.scheduledDeletionDate')) {
|
||||
throw new ErrDeletionAlreadyScheduled();
|
||||
}
|
||||
|
||||
// Get the date in the future 24 hours from now.
|
||||
// Get the date in the future ${scheduledDeletionDelayHours} hours from now.
|
||||
const scheduledDeletionDate = moment()
|
||||
.add(24, 'hours')
|
||||
.add(scheduledDeletionDelayHours, 'hours')
|
||||
.toDate();
|
||||
|
||||
// Amend the scheduledDeletionDate on the user.
|
||||
|
||||
+5
-3
@@ -18,12 +18,14 @@ const {
|
||||
ErrCannotIgnoreStaff,
|
||||
} = require('../errors');
|
||||
const { difference, sample, some, merge, random } = require('lodash');
|
||||
const { ROOT_URL } = require('../config');
|
||||
const {
|
||||
ROOT_URL,
|
||||
RECAPTCHA_WINDOW,
|
||||
RECAPTCHA_INCORRECT_TRIGGER,
|
||||
} = require('../config');
|
||||
const { jwt: JWT_SECRET } = require('../secrets');
|
||||
const debug = require('debug')('talk:services:users');
|
||||
const User = require('../models/user');
|
||||
const RECAPTCHA_WINDOW = '10m'; // 10 minutes.
|
||||
const RECAPTCHA_INCORRECT_TRIGGER = 5; // after 5 incorrect attempts, recaptcha will be required.
|
||||
const Actions = require('./actions');
|
||||
const mailer = require('./mailer');
|
||||
const i18n = require('./i18n');
|
||||
|
||||
Reference in New Issue
Block a user