avoid use of dangerously

This commit is contained in:
Roland Osborne 2023-04-03 11:51:18 -07:00
parent 9f5647fa57
commit 37f6ec6f09
4 changed files with 26 additions and 17 deletions

View File

@ -162,8 +162,8 @@ export function TopicItem({ item, focused, focus, hosting, remove, update, block
<MatIcons name="weather-cloudy-alert" size={32} color={Colors.alert} /> <MatIcons name="weather-cloudy-alert" size={32} color={Colors.alert} />
</View> </View>
)} )}
{ state.message && !state.sealed && ( { state.clickable && !state.sealed && (
<Text style={{ ...styles.message, fontSize: state.fontSize, color: state.fontColor }}>{ state.message }</Text> <Text style={{ ...styles.message, fontSize: state.fontSize, color: state.fontColor }}>{ state.clickable }</Text>
)} )}
{ state.sealed && ( { state.sealed && (
<Text style={ styles.sealed }>sealed message</Text> <Text style={ styles.sealed }>sealed message</Text>

View File

@ -20,6 +20,7 @@ export function useTopicItem(item, hosting, remove, contentKey) {
logo: null, logo: null,
timestamp: null, timestamp: null,
message: null, message: null,
clickable: null,
carousel: false, carousel: false,
carouselIndex: 0, carouselIndex: 0,
width: null, width: null,
@ -92,12 +93,13 @@ export function useTopicItem(item, hosting, remove, contentKey) {
} }
} }
let parsed, sealed, message, assets, fontSize, fontColor; let parsed, sealed, message, clickable, assets, fontSize, fontColor;
if (dataType === 'superbasictopic') { if (dataType === 'superbasictopic') {
try { try {
sealed = false; sealed = false;
parsed = JSON.parse(data); parsed = JSON.parse(data);
message = clickableText(parsed.text); message = parsed?.text;
clickable = clickableText(parsed.text);
assets = parsed.assets; assets = parsed.assets;
if (parsed.textSize === 'small') { if (parsed.textSize === 'small') {
fontSize = 10; fontSize = 10;
@ -140,7 +142,8 @@ export function useTopicItem(item, hosting, remove, contentKey) {
if (unsealed) { if (unsealed) {
sealed = false; sealed = false;
parsed = unsealed.message; parsed = unsealed.message;
message = clickableText(parsed?.text); message = parsed?.text;
clickable = clickableText(parsed?.text);
if (parsed?.textSize === 'small') { if (parsed?.textSize === 'small') {
fontSize = 10; fontSize = 10;
} }
@ -179,7 +182,7 @@ export function useTopicItem(item, hosting, remove, contentKey) {
const editable = guid === identity?.guid && parsed; const editable = guid === identity?.guid && parsed;
const deletable = editable || hosting; const deletable = editable || hosting;
updateState({ logo, name, nameSet, known, sealed, message, fontSize, fontColor, timestamp, transform, status, assets, deletable, editable, editData: parsed, editMessage: message, editType: dataType }); updateState({ logo, name, nameSet, known, sealed, message, clickable, fontSize, fontColor, timestamp, transform, status, assets, deletable, editable, editData: parsed, editMessage: message, editType: dataType });
}, [conversation.state, card.state, account.state, item, contentKey]); }, [conversation.state, card.state, account.state, item, contentKey]);
const unsealTopic = async (topicId, revision, topicDetail) => { const unsealTopic = async (topicId, revision, topicDetail) => {
@ -206,7 +209,7 @@ export function useTopicItem(item, hosting, remove, contentKey) {
let clickable = []; let clickable = [];
let group = ''; let group = '';
const words = text == null ? '' : text.split(' '); const words = text == null ? [''] : text.split(' ');
words.forEach((word, index) => { words.forEach((word, index) => {
if (!!pattern.test(word)) { if (!!pattern.test(word)) {
clickable.push(<Text key={index}>{ group }</Text>); clickable.push(<Text key={index}>{ group }</Text>);

View File

@ -7,7 +7,6 @@ import { Space, Skeleton, Button, Modal, Input } from 'antd';
import { ExclamationCircleOutlined, DeleteOutlined, EditOutlined, FireOutlined, PictureOutlined } from '@ant-design/icons'; import { ExclamationCircleOutlined, DeleteOutlined, EditOutlined, FireOutlined, PictureOutlined } from '@ant-design/icons';
import { Carousel } from 'carousel/Carousel'; import { Carousel } from 'carousel/Carousel';
import { useTopicItem } from './useTopicItem.hook'; import { useTopicItem } from './useTopicItem.hook';
import * as DOMPurify from 'dompurify';
export function TopicItem({ host, sealed, topic, update, remove }) { export function TopicItem({ host, sealed, topic, update, remove }) {
@ -124,7 +123,7 @@ export function TopicItem({ host, sealed, topic, update, remove }) {
)} )}
{ !sealed && !state.editing && ( { !sealed && !state.editing && (
<div class="message"> <div class="message">
<div style={{ color: topic.textColor, fontSize: topic.textSize }} dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(topic.text, { ADD_ATTR: ['target'] })}} /> <div style={{ color: topic.textColor, fontSize: topic.textSize }}>{ topic.clickable }</div>
</div> </div>
)} )}
{ state.editing && ( { state.editing && (

View File

@ -9,6 +9,7 @@ import { ProfileContext } from 'context/ProfileContext';
import { isUnsealed, getChannelSeals, getContentKey, encryptTopicSubject } from 'context/sealUtil'; import { isUnsealed, getChannelSeals, getContentKey, encryptTopicSubject } from 'context/sealUtil';
import { decryptTopicSubject } from 'context/sealUtil'; import { decryptTopicSubject } from 'context/sealUtil';
import { getProfileByGuid } from 'context/cardUtil'; import { getProfileByGuid } from 'context/cardUtil';
import * as DOMPurify from 'dompurify';
export function useConversation(cardId, channelId) { export function useConversation(cardId, channelId) {
@ -140,17 +141,21 @@ export function useConversation(cardId, channelId) {
'(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
'(\\#[-a-z\\d_]*)?$','i'); // fragment locator '(\\#[-a-z\\d_]*)?$','i'); // fragment locator
let clickable = ''; let group = '';
const words = text == null ? '' : text.split(' '); let clickable = [];
words.forEach(word => { const words = text == null ? '' : DOMPurify.sanitize(text).split(' ');
words.forEach((word, index) => {
if (!!pattern.test(word)) { if (!!pattern.test(word)) {
clickable += `<a target="_blank" rel="noopener noreferrer" href="${word}">${word}</a> `; clickable.push(<span key={index}>{ group }</span>);
group = '';
clickable.push(<a key={'link-'+index} target="_blank" rel="noopener noreferrer" href={word}>{ `${word} ` }</a>);
} }
else { else {
clickable += `${word} `; group += `${word} `;
} }
}) })
return `<p>${clickable}</p>`; clickable.push(<span key={words.length}>{ group }</span>);
return <p>{ clickable }</p>;
}; };
const syncTopic = (item, value) => { const syncTopic = (item, value) => {
@ -210,14 +215,16 @@ export function useConversation(cardId, channelId) {
if (detail.dataType === 'superbasictopic') { if (detail.dataType === 'superbasictopic') {
const message = JSON.parse(detail.data); const message = JSON.parse(detail.data);
item.assets = message.assets; item.assets = message.assets;
item.text = clickableText(message.text); item.text = message.text;
item.clickable = clickableText(message.text);
item.textColor = message.textColor ? message.textColor : '#444444'; item.textColor = message.textColor ? message.textColor : '#444444';
item.textSize = message.textSize ? message.textSize : 14; item.textSize = message.textSize ? message.textSize : 14;
} }
if (detail.dataType === 'sealedtopic' && state.contentKey) { if (detail.dataType === 'sealedtopic' && state.contentKey) {
const subject = decryptTopicSubject(detail.data, state.contentKey); const subject = decryptTopicSubject(detail.data, state.contentKey);
item.assets = subject.message.assets; item.assets = subject.message.assets;
item.text = clickableText(subject.message.text); item.text = subject.message.text;
item.clickable = clickableText(subject.message.text);
item.textColor = subject.message.textColor ? subject.message.textColor : '#444444'; item.textColor = subject.message.textColor ? subject.message.textColor : '#444444';
item.textSize = subject.message.textSize ? subject.message.textSize : 14; item.textSize = subject.message.textSize ? subject.message.textSize : 14;
} }