mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-27 19:42:11 +10:00
Merge pull request #1023 from sharetribe/sanitize-entity-content
Sanitize example for listing and user entities
This commit is contained in:
commit
a3239dd1da
3 changed files with 123 additions and 1 deletions
|
|
@ -14,6 +14,9 @@ way to update this template, but currently, we follow a pattern:
|
|||
|
||||
## Upcoming version 2019-XX-XX
|
||||
|
||||
- [add] This adds an example how user-generated content could be sanitized. If you have extended
|
||||
data you should consider if sanitization is needed for that.
|
||||
[#1023](https://github.com/sharetribe/flex-template-web/pull/1023)
|
||||
- [change] A new component `UserDisplayName` is added for showing user display name and also
|
||||
handling the cases where a user is banned or deleted. When the user name must be a string instead
|
||||
of a component (e.g. in `Avatar` and in `ListingPage`) you can use a new function
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import isArray from 'lodash/isArray';
|
||||
import reduce from 'lodash/reduce';
|
||||
import { sanitizeEntity } from './sanitize';
|
||||
|
||||
/**
|
||||
* Combine the given relationships objects
|
||||
|
|
@ -42,9 +43,14 @@ export const updatedEntities = (oldEntities, apiResponse) => {
|
|||
|
||||
const newEntities = objects.reduce((entities, curr) => {
|
||||
const { id, type } = curr;
|
||||
|
||||
// Some entities (e.g. listing and user) might include extended data,
|
||||
// you should check if src/util/sanitize.js needs to be updated.
|
||||
const current = sanitizeEntity(curr);
|
||||
|
||||
entities[type] = entities[type] || {};
|
||||
const entity = entities[type][id.uuid];
|
||||
entities[type][id.uuid] = entity ? combinedResourceObjects(entity, curr) : curr;
|
||||
entities[type][id.uuid] = entity ? combinedResourceObjects(entity, current) : current;
|
||||
return entities;
|
||||
}, oldEntities);
|
||||
|
||||
|
|
|
|||
113
src/util/sanitize.js
Normal file
113
src/util/sanitize.js
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/**
|
||||
* By default, React DOM escapes any values embedded in JSX before rendering them,
|
||||
* but sometimes it is necessary to sanitize the user-generated content of received entities.
|
||||
* If you use this data in component props without any sanitization or encoding,
|
||||
* it might create XSS vulnerabilities.
|
||||
*
|
||||
* You should especially consider how you are using extended data inside the app.
|
||||
*/
|
||||
|
||||
const ESCAPE_TEXT_REGEXP = /[<>]/g;
|
||||
const ESCAPE_TEXT_REPLACEMENTS = {
|
||||
//fullwidth lesser-than character
|
||||
'<': '\uff1c',
|
||||
//fullwidth greater-than character
|
||||
'>': '\uff1e',
|
||||
};
|
||||
|
||||
// An example how you could sanitize text content.
|
||||
// This swaps some coding related characters to less dangerous ones
|
||||
const sanitizeText = str =>
|
||||
str == null
|
||||
? str
|
||||
: typeof str === 'string'
|
||||
? str.replace(ESCAPE_TEXT_REGEXP, ch => ESCAPE_TEXT_REPLACEMENTS[ch])
|
||||
: '';
|
||||
|
||||
/**
|
||||
* Sanitize user entity.
|
||||
* If you add public data, you should probably sanitize it here.
|
||||
* By default, React DOM escapes any values embedded in JSX before rendering them,
|
||||
* but if you use this data on props, it might create XSS vulnerabilities
|
||||
* E.g. you should sanitize and encode URI if you are creating links from public data.
|
||||
*/
|
||||
export const sanitizeUser = entity => {
|
||||
const { attributes, ...restEntity } = entity || {};
|
||||
const { profile, ...restAttributes } = attributes || {};
|
||||
const { bio, displayName, abbreviatedName, publicData } = profile || {};
|
||||
|
||||
const sanitizePublicData = publicData => {
|
||||
// TODO: If you add public data, you should probably sanitize it here.
|
||||
return publicData ? { publicData } : {};
|
||||
};
|
||||
|
||||
const profileMaybe = profile
|
||||
? {
|
||||
profile: {
|
||||
abbreviatedName: sanitizeText(abbreviatedName),
|
||||
displayName: sanitizeText(displayName),
|
||||
bio: sanitizeText(bio),
|
||||
...sanitizePublicData(publicData),
|
||||
},
|
||||
}
|
||||
: {};
|
||||
const attributesMaybe = attributes ? { attributes: { ...profileMaybe, ...restAttributes } } : {};
|
||||
|
||||
return { ...attributesMaybe, ...restEntity };
|
||||
};
|
||||
|
||||
/**
|
||||
* Sanitize listing entity.
|
||||
* If you add public data, you should probably sanitize it here.
|
||||
* By default, React DOM escapes any values embedded in JSX before rendering them,
|
||||
* but if you use this data on props, it might create XSS vulnerabilities
|
||||
* E.g. you should sanitize and encode URI if you are creating links from public data.
|
||||
*/
|
||||
export const sanitizeListing = entity => {
|
||||
const { attributes, ...restEntity } = entity;
|
||||
const { title, description, publicData, ...restAttributes } = attributes || {};
|
||||
|
||||
const sanitizeLocation = location => {
|
||||
const { address, building } = location || {};
|
||||
return { address: sanitizeText(address), building: sanitizeText(building) };
|
||||
};
|
||||
|
||||
const sanitizePublicData = publicData => {
|
||||
// Here's an example how you could sanitize location and rules from publicData:
|
||||
// TODO: If you add public data, you should probably sanitize it here.
|
||||
const { location, rules, ...restPublicData } = publicData || {};
|
||||
const locationMaybe = location ? { location: sanitizeLocation(location) } : {};
|
||||
const rulesMaybe = rules ? { rules: sanitizeText(rules) } : {};
|
||||
|
||||
return publicData ? { publicData: { ...locationMaybe, ...rulesMaybe, ...restPublicData } } : {};
|
||||
};
|
||||
|
||||
const attributesMaybe = attributes
|
||||
? {
|
||||
attributes: {
|
||||
title: sanitizeText(title),
|
||||
description: sanitizeText(description),
|
||||
...sanitizePublicData(publicData),
|
||||
...restAttributes,
|
||||
},
|
||||
}
|
||||
: {};
|
||||
|
||||
return { ...attributesMaybe, ...restEntity };
|
||||
};
|
||||
|
||||
/**
|
||||
* Sanitize entities if needed.
|
||||
* Remember to add your own sanitization rules for your extended data
|
||||
*/
|
||||
export const sanitizeEntity = entity => {
|
||||
const { type } = entity;
|
||||
switch (type) {
|
||||
case 'listing':
|
||||
return sanitizeListing(entity);
|
||||
case 'user':
|
||||
return sanitizeUser(entity);
|
||||
default:
|
||||
return entity;
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Reference in a new issue