fix(client): prevent data url render (#44658)
* fix: only render profile urls * feat: warn user when submitting data url * fix: prevent dataurls being saved to db * fix: tests and imports Not sure why jest didn't like the es imports, but they aren't necessary so I dropped them. * fix: check for url protocol
This commit is contained in:
committed by
GitHub
parent
418480782a
commit
a726dd381f
@ -1,5 +1,6 @@
|
|||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
import { check } from 'express-validator';
|
import { check } from 'express-validator';
|
||||||
|
import isURL from 'validator/lib/isURL';
|
||||||
|
|
||||||
import { isValidUsername } from '../../../../utils/validate';
|
import { isValidUsername } from '../../../../utils/validate';
|
||||||
import { alertTypes } from '../../common/utils/flash.js';
|
import { alertTypes } from '../../common/utils/flash.js';
|
||||||
@ -164,10 +165,11 @@ function updateMyAbout(req, res, next) {
|
|||||||
body: { name, location, about, picture }
|
body: { name, location, about, picture }
|
||||||
} = req;
|
} = req;
|
||||||
log(name, location, picture, about);
|
log(name, location, picture, about);
|
||||||
return user.updateAttributes(
|
// prevent dataurls from being stored
|
||||||
{ name, location, about, picture },
|
const update = isURL(picture, { require_protocol: true })
|
||||||
createStandardHandler(req, res, next)
|
? { name, location, about, picture }
|
||||||
);
|
: { name, location, about };
|
||||||
|
return user.updateAttributes(update, createStandardHandler(req, res, next));
|
||||||
}
|
}
|
||||||
|
|
||||||
function createUpdateMyUsername(app) {
|
function createUpdateMyUsername(app) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Image } from '@freecodecamp/react-bootstrap';
|
import { Image } from '@freecodecamp/react-bootstrap';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import isURL from 'validator/lib/isURL';
|
||||||
import { defaultUserImage } from '../../../../config/misc';
|
import { defaultUserImage } from '../../../../config/misc';
|
||||||
import DefaultAvatar from '../../assets/icons/default-avatar';
|
import DefaultAvatar from '../../assets/icons/default-avatar';
|
||||||
import { borderColorPicker } from '.';
|
import { borderColorPicker } from '.';
|
||||||
@ -26,9 +27,14 @@ function AvatarRenderer({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const validationImage = document.createElement('img');
|
const validationImage = document.createElement('img');
|
||||||
validationImage.src = picture;
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
validationImage.onload = onImageLoad;
|
if (isURL(picture, { require_protocol: true })) {
|
||||||
validationImage.onerror = onImageError;
|
validationImage.src = picture;
|
||||||
|
validationImage.onload = onImageLoad;
|
||||||
|
validationImage.onerror = onImageError;
|
||||||
|
} else {
|
||||||
|
setIsPictureValid(false);
|
||||||
|
}
|
||||||
}, [picture]);
|
}, [picture]);
|
||||||
|
|
||||||
const isPlaceHolderImage =
|
const isPlaceHolderImage =
|
||||||
|
@ -23,11 +23,145 @@ exports[`<Profile/> renders correctly 1`] = `
|
|||||||
<div
|
<div
|
||||||
class="avatar-container default-border"
|
class="avatar-container default-border"
|
||||||
>
|
>
|
||||||
<img
|
<svg
|
||||||
alt="profile.avatar"
|
class="avatar default-avatar"
|
||||||
class="avatar img-responsive"
|
height="500px"
|
||||||
src="string"
|
version="1.1"
|
||||||
/>
|
viewBox="0 0 500 500"
|
||||||
|
width="500px"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
>
|
||||||
|
<title>
|
||||||
|
icons.avatar
|
||||||
|
</title>
|
||||||
|
<desc>
|
||||||
|
icons.avatar-2
|
||||||
|
</desc>
|
||||||
|
<g
|
||||||
|
fill="none"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
id="g"
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
fill="#D0D0D5"
|
||||||
|
height="500"
|
||||||
|
width="500"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="m251.34 49c23.859 58.47 34.222 90.121 31.088 94.954-4.701 7.2493-15.381 32.924 0 50.968s77.487 6.439 92.029 23.897c14.542 17.458 12.196 68.184 14.542 135.56-22.154 0.54208-68.154 1.0837-138 1.6248l0.062-56h-0.124l0.062 56c-69.846-0.54109-115.85-1.0827-138-1.6248 2.3463-67.372 0-118.1 14.542-135.56 14.542-17.458 76.649-5.852 92.029-23.897s4.701-43.719 0-50.968c-3.134-4.8329 7.2285-36.484 31.088-94.954l0.13247 120h0.415z"
|
||||||
|
fill="#242440"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="m250.13 185c47.577 0 66.872-66.034 66.872-90.434 0-42.286-29.773-76.566-66.5-76.566s-66.5 34.28-66.5 76.566c0 24.7 18.552 90.434 66.128 90.434z"
|
||||||
|
fill="#242440"
|
||||||
|
id="c"
|
||||||
|
stroke="#D0D0D5"
|
||||||
|
stroke-width="17"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="m77.011 459c-19.341-119.95-29.011-183.79-29.011-191.53 0-11.605 6.2167-16.473 17.298-16.473h370.4c11.082 0 17.298 4.8681 17.298 16.473 0 7.7366-9.6704 71.579-29.011 191.53z"
|
||||||
|
fill="#5F5F8C"
|
||||||
|
stroke="#D0D0D5"
|
||||||
|
stroke-width="16"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
fill="#5F5F8C"
|
||||||
|
height="23"
|
||||||
|
stroke="#D0D0D5"
|
||||||
|
stroke-width="6"
|
||||||
|
width="339"
|
||||||
|
x="81"
|
||||||
|
y="459"
|
||||||
|
/>
|
||||||
|
<g
|
||||||
|
fill-rule="nonzero"
|
||||||
|
transform="translate(162 283)"
|
||||||
|
>
|
||||||
|
<ellipse
|
||||||
|
cx="88.5"
|
||||||
|
cy="79"
|
||||||
|
fill="#0A0A23"
|
||||||
|
rx="88.5"
|
||||||
|
ry="79"
|
||||||
|
/>
|
||||||
|
<g
|
||||||
|
transform="translate(20 40)"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
id="Group"
|
||||||
|
transform="translate(42.462 4)"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
fill="#fff"
|
||||||
|
id="e"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="m38.312 39.042c-3.9186-0.91476 12.174-18.263-16.43-39.034 0 0 3.7555 10.879-15.169 35.157-18.933 24.27 8.418 38.725 8.418 38.725s-12.834-6.24 2.0846-28.459c2.6734-4.0329 6.1663-7.6847 10.507-15.899 0 0 3.839 4.9441 1.834 15.671-2.9996 16.208 13.005 11.569 13.256 11.794 5.5895 6.0077-4.6307 16.564-5.2513 16.894-0.62061 0.32307 29.185-16.36 8.0083-41.469-1.4521 1.325-3.3338 7.5359-7.2564 6.6212z"
|
||||||
|
id="i"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
fill="#000"
|
||||||
|
fill-opacity="0"
|
||||||
|
stroke="#000"
|
||||||
|
stroke-opacity="0"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="m38.312 39.042c-3.9186-0.91476 12.174-18.263-16.43-39.034 0 0 3.7555 10.879-15.169 35.157-18.933 24.27 8.418 38.725 8.418 38.725s-12.834-6.24 2.0846-28.459c2.6734-4.0329 6.1663-7.6847 10.507-15.899 0 0 3.839 4.9441 1.834 15.671-2.9996 16.208 13.005 11.569 13.256 11.794 5.5895 6.0077-4.6307 16.564-5.2513 16.894-0.62061 0.32307 29.185-16.36 8.0083-41.469-1.4521 1.325-3.3338 7.5359-7.2564 6.6212z"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="b"
|
||||||
|
transform="translate(110.13)"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
fill="#fff"
|
||||||
|
id="d"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="m0.96996 0.62339c-0.47786 0.41439-0.95166 1.0162-0.95166 1.6215-0.0040664 1.045 1.3846 2.4611 3.9577 4.7889 10.713 9.1022 16.104 20.251 16.068 33.692-0.040843 14.875-5.7099 26.82-16.729 36.077-2.3158 1.8305-3.2674 3.2647-3.2715 4.4935 0 0.60537 0.4697 1.2324 0.94347 1.8341 0.44519 0.4216 1.3927 0.83962 2.0748 0.83962 2.5486 0.0071777 6.1183-2.6521 10.774-7.8266 9.0712-9.8085 13.172-20.64 13.401-35.4 0.21238-14.77-5.0319-24.784-15.308-35.126-3.6963-3.6935-6.7759-5.6141-8.8834-5.6177-0.68208 0-1.3927 0.20539-2.0748 0.62339z"
|
||||||
|
id="a"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
fill="#000"
|
||||||
|
fill-opacity="0"
|
||||||
|
stroke="#000"
|
||||||
|
stroke-opacity="0"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="m0.96996 0.62339c-0.47786 0.41439-0.95166 1.0162-0.95166 1.6215-0.0040664 1.045 1.3846 2.4611 3.9577 4.7889 10.713 9.1022 16.104 20.251 16.068 33.692-0.040843 14.875-5.7099 26.82-16.729 36.077-2.3158 1.8305-3.2674 3.2647-3.2715 4.4935 0 0.60537 0.4697 1.2324 0.94347 1.8341 0.44519 0.4216 1.3927 0.83962 2.0748 0.83962 2.5486 0.0071777 6.1183-2.6521 10.774-7.8266 9.0712-9.8085 13.172-20.64 13.401-35.4 0.21238-14.77-5.0319-24.784-15.308-35.126-3.6963-3.6935-6.7759-5.6141-8.8834-5.6177-0.68208 0-1.3927 0.20539-2.0748 0.62339z"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
fill="#fff"
|
||||||
|
id="h"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="m26.367 0.6342c0.47409 0.41439 0.9482 1.0162 0.9482 1.6215 0.004069 1.045-1.3855 2.4611-3.9603 4.7889-10.72 9.1022-16.111 20.251-16.078 33.692 0.04087 14.875 5.7136 26.82 16.74 36.077 2.3173 1.8305 3.2696 3.2647 3.2737 4.4935 0 0.60537-0.47001 1.2324-0.9441 1.8341-0.44548 0.4216-1.3896 0.83962-2.0762 0.83962-2.5503 0.0071777-6.1223-2.6521-10.782-7.8266-9.0773-9.8085-13.181-20.64-13.409-35.4-0.21252-14.77 5.0352-24.784 15.318-35.126 3.6987-3.6935 6.7844-5.6141 8.8892-5.6177 0.68253 0 1.3937 0.20539 2.0803 0.62339z"
|
||||||
|
id="f"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
fill="#000"
|
||||||
|
fill-opacity="0"
|
||||||
|
stroke="#000"
|
||||||
|
stroke-opacity="0"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="m26.367 0.6342c0.47409 0.41439 0.9482 1.0162 0.9482 1.6215 0.004069 1.045-1.3855 2.4611-3.9603 4.7889-10.72 9.1022-16.111 20.251-16.078 33.692 0.04087 14.875 5.7136 26.82 16.74 36.077 2.3173 1.8305 3.2696 3.2647 3.2737 4.4935 0 0.60537-0.47001 1.2324-0.9441 1.8341-0.44548 0.4216-1.3896 0.83962-2.0762 0.83962-2.5503 0.0071777-6.1223-2.6521-10.782-7.8266-9.0773-9.8085-13.181-20.64-13.409-35.4-0.21252-14.77 5.0352-24.784 15.318-35.126 3.6987-3.6935 6.7844-5.6141 8.8892-5.6177 0.68253 0 1.3937 0.20539 2.0803 0.62339z"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
import { TFunction, withTranslation } from 'react-i18next';
|
import { TFunction, withTranslation } from 'react-i18next';
|
||||||
|
import isURL from 'validator/lib/isURL';
|
||||||
import { FullWidthRow, Spacer } from '../helpers';
|
import { FullWidthRow, Spacer } from '../helpers';
|
||||||
import BlockSaveButton from '../helpers/form/block-save-button';
|
import BlockSaveButton from '../helpers/form/block-save-button';
|
||||||
import SoundSettings from './sound';
|
import SoundSettings from './sound';
|
||||||
@ -149,8 +150,15 @@ class AboutSettings extends Component<AboutProps, AboutState> {
|
|||||||
|
|
||||||
handlePictureChange = (e: React.FormEvent<HTMLInputElement>) => {
|
handlePictureChange = (e: React.FormEvent<HTMLInputElement>) => {
|
||||||
const value = (e.target as HTMLInputElement).value.slice(0);
|
const value = (e.target as HTMLInputElement).value.slice(0);
|
||||||
this.validationImage.src = value;
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
return this.setState(state => ({
|
if (isURL(value, { require_protocol: true })) {
|
||||||
|
this.validationImage.src = value;
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
isPictureUrlValid: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.setState(state => ({
|
||||||
formValues: {
|
formValues: {
|
||||||
...state.formValues,
|
...state.formValues,
|
||||||
picture: value
|
picture: value
|
||||||
|
Reference in New Issue
Block a user