Base del merge a tres bandas: git 0.9.5 de epsylon, esta rama y el src de la
APK oficial 1.3.1 (la variante movil: OASIS_MOBILE, regex sin \p{}, audio y
video de Android). Corre en el mismo nodejs-mobile 18.20.4 que ya usabamos.
Se conserva de la rama: Karvan, identidades y multicuenta, topbar y barra
inferior, borrado de EXIF sin sharp, filtro hot del foro, RTC sin STUN y los
modulos apagados en movil (wallet, banking, torrents).
Se toma de upstream lo que ya hace de serie: respuesta citada en chats, ssb-lan
en movil, configuracion en ~/.ssb/oasis (sobrevive a reinstalar el backend).
El asistente de bienvenida deja elegir workflow tambien en movil.
62 lines
2.5 KiB
JavaScript
62 lines
2.5 KiB
JavaScript
"use strict";
|
|
|
|
const SAFE_SRC = /^\/(?:blob|image)\/[^\s"'<>]+$/i;
|
|
const SAFE_HREF = /^(?:https?:\/\/|\/(?!\/)|#|mailto:)/i;
|
|
const SAFE_CLASS = /^(?:rt-[a-z0-9-]+|styled-link|mention|tag-link|zoom-link|pm-quote|wiki-link(?:-missing)?|internal-link(?:-id|-kind)?|lightbox(?:-[a-z]+)?|post-(?:audio|image|pdf|video))$/;
|
|
let purifier = null;
|
|
const getPurify = () => {
|
|
if (purifier) return purifier;
|
|
const { JSDOM } = require('../server/node_modules/jsdom');
|
|
const DOMPurify = require('../server/node_modules/dompurify');
|
|
const purify = DOMPurify(new JSDOM('').window);
|
|
purify.addHook('uponSanitizeAttribute', (node, data) => {
|
|
const name = String(data.attrName || '').toLowerCase();
|
|
const value = String(data.attrValue || '').trim();
|
|
if (name === 'src' && !SAFE_SRC.test(value)) data.keepAttr = false;
|
|
if (name === 'href' && !SAFE_HREF.test(value)) data.keepAttr = false;
|
|
if (name === 'class') {
|
|
const kept = value.split(/\s+/).filter(c => SAFE_CLASS.test(c));
|
|
if (kept.length) data.attrValue = kept.join(' '); else data.keepAttr = false;
|
|
}
|
|
});
|
|
purifier = purify;
|
|
return purifier;
|
|
};
|
|
const dropControlChars = (html) => String(html).replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f]/g, '');
|
|
|
|
const stripDangerousTags = (input) => {
|
|
if (typeof input !== 'string') return '';
|
|
return dropControlChars(getPurify().sanitize(input, {
|
|
ALLOWED_TAGS: [
|
|
'p', 'br',
|
|
'b', 'strong', 'i', 'em', 'u',
|
|
'ul', 'ol', 'li',
|
|
'blockquote',
|
|
'code', 'pre'
|
|
],
|
|
ALLOWED_ATTR: [],
|
|
FORBID_TAGS: ['svg', 'math', 'iframe', 'object', 'embed', 'form', 'input', 'textarea', 'select', 'button', 'script'],
|
|
FORBID_ATTR: ['style']
|
|
}));
|
|
};
|
|
|
|
const sanitizeHtml = (input) => {
|
|
if (typeof input !== 'string') return '';
|
|
return dropControlChars(getPurify().sanitize(input, {
|
|
ALLOWED_TAGS: [
|
|
'p', 'br', 'hr',
|
|
'b', 'strong', 'i', 'em', 'u', 's', 'del',
|
|
'ul', 'ol', 'li',
|
|
'blockquote', 'code', 'pre',
|
|
'a', 'span', 'div',
|
|
'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
|
|
'img', 'video', 'audio',
|
|
'table', 'thead', 'tbody', 'tr', 'th', 'td'
|
|
],
|
|
ALLOWED_ATTR: ['href', 'class', 'target', 'rel', 'src', 'alt', 'title', 'controls'],
|
|
FORBID_TAGS: ['svg', 'math', 'iframe', 'object', 'embed', 'form', 'input', 'textarea', 'select', 'button', 'script', 'style', 'link', 'meta'],
|
|
FORBID_ATTR: ['onerror', 'onload', 'onclick', 'onmouseover', 'onfocus', 'onblur', 'onsubmit', 'onchange', 'style']
|
|
}));
|
|
};
|
|
|
|
module.exports = { stripDangerousTags, sanitizeHtml };
|