2022-09-13 08:39:47 -07:00
|
|
|
import xss, { friendlyAttrValue } from 'xss';
|
|
|
|
|
2022-08-01 13:43:50 -07:00
|
|
|
export const omit = (keyToOmit: string, { [keyToOmit]: _, ...remainder }) => remainder;
|
2022-08-22 08:46:22 -07:00
|
|
|
|
|
|
|
export function isObjectLiteral(maybeObject: unknown): maybeObject is { [key: string]: string } {
|
|
|
|
return typeof maybeObject === 'object' && maybeObject !== null && !Array.isArray(maybeObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isJsonKeyObject(item: unknown): item is {
|
|
|
|
json: unknown;
|
|
|
|
[otherKeys: string]: unknown;
|
|
|
|
} {
|
|
|
|
if (!isObjectLiteral(item)) return false;
|
|
|
|
|
|
|
|
return Object.keys(item).includes('json');
|
|
|
|
}
|
2022-09-13 08:39:47 -07:00
|
|
|
|
|
|
|
export function sanitizeHtml(dirtyHtml: string) {
|
|
|
|
const allowedAttributes = ['href','name', 'target', 'title', 'class', 'id'];
|
|
|
|
const allowedTags = ['p', 'strong', 'b', 'code', 'a', 'br', 'i', 'em', 'small' ];
|
|
|
|
|
|
|
|
const sanitizedHtml = xss(dirtyHtml, {
|
|
|
|
onTagAttr: (tag, name, value) => {
|
|
|
|
if (tag === 'img' && name === 'src') {
|
|
|
|
// Only allow http requests to supported image files from the `static` directory
|
|
|
|
const isImageFile = value.split('#')[0].match(/\.(jpeg|jpg|gif|png|webp)$/) !== null;
|
|
|
|
const isStaticImageFile = isImageFile && value.startsWith('/static/');
|
|
|
|
if (!value.startsWith('https://') && !isStaticImageFile) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allow `allowedAttributes` and all `data-*` attributes
|
|
|
|
if(allowedAttributes.includes(name) || name.startsWith('data-')) return `${name}="${friendlyAttrValue(value)}"`;
|
|
|
|
|
|
|
|
return;
|
|
|
|
// Return nothing, means keep the default handling measure
|
|
|
|
},
|
|
|
|
onTag: (tag) => {
|
|
|
|
if(!allowedTags.includes(tag)) return '';
|
|
|
|
return;
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
return sanitizedHtml;
|
|
|
|
}
|
2022-10-06 06:03:55 -07:00
|
|
|
|
|
|
|
export const isEmpty = (value?: unknown): boolean => {
|
|
|
|
if (!value && value !== 0) return true;
|
|
|
|
if(Array.isArray(value)){
|
|
|
|
if(!value.length) return true;
|
|
|
|
return value.every(isEmpty);
|
|
|
|
}
|
|
|
|
if (typeof value === 'object') {
|
|
|
|
return Object.values(value).every(isEmpty);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|