fix(front): fix XSS because of bad operations when setting the group's summary
Group summary (HTML) is properly sanitized by the backend, but for groups we did a special operation before setting the HTML in the Vue app. This is now removed Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
935799f123
commit
ded59bec27
|
@ -40,7 +40,7 @@
|
||||||
<div
|
<div
|
||||||
class="mb-2 line-clamp-3"
|
class="mb-2 line-clamp-3"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
v-html="saneSummary"
|
v-html="group.summary"
|
||||||
v-if="showSummary"
|
v-if="showSummary"
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
|
@ -91,7 +91,6 @@ import { addressFullName } from "@/types/address.model";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import AccountGroup from "vue-material-design-icons/AccountGroup.vue";
|
import AccountGroup from "vue-material-design-icons/AccountGroup.vue";
|
||||||
import Account from "vue-material-design-icons/Account.vue";
|
import Account from "vue-material-design-icons/Account.vue";
|
||||||
import { htmlToText } from "@/utils/html";
|
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import LinkOrRouterLink from "../core/LinkOrRouterLink.vue";
|
import LinkOrRouterLink from "../core/LinkOrRouterLink.vue";
|
||||||
|
|
||||||
|
@ -108,8 +107,6 @@ const props = withDefaults(
|
||||||
|
|
||||||
const { t } = useI18n({ useScope: "global" });
|
const { t } = useI18n({ useScope: "global" });
|
||||||
|
|
||||||
const saneSummary = computed(() => htmlToText(props.group.summary ?? ""));
|
|
||||||
|
|
||||||
const isInternal = computed(() => {
|
const isInternal = computed(() => {
|
||||||
return props.isRemoteGroup && props.isLoggedIn === false;
|
return props.isRemoteGroup && props.isLoggedIn === false;
|
||||||
});
|
});
|
||||||
|
|
|
@ -60,9 +60,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="mt-3 prose dark:prose-invert lg:prose-xl line-clamp-2"
|
class="mt-3 prose dark:prose-invert lg:prose-xl prose-p:m-0 line-clamp-2"
|
||||||
v-if="member.parent.summary"
|
v-if="member.parent.summary"
|
||||||
v-html="htmlToText(member.parent.summary)"
|
v-html="member.parent.summary"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -95,7 +95,6 @@ import DotsHorizontal from "vue-material-design-icons/DotsHorizontal.vue";
|
||||||
import AccountGroup from "vue-material-design-icons/AccountGroup.vue";
|
import AccountGroup from "vue-material-design-icons/AccountGroup.vue";
|
||||||
import AccountCircle from "vue-material-design-icons/AccountCircle.vue";
|
import AccountCircle from "vue-material-design-icons/AccountCircle.vue";
|
||||||
import Tag from "@/components/TagElement.vue";
|
import Tag from "@/components/TagElement.vue";
|
||||||
import { htmlToText } from "@/utils/html";
|
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
|
|
@ -2,15 +2,6 @@ export function nl2br(text: string): string {
|
||||||
return text.replace(/(?:\r\n|\r|\n)/g, "<br>");
|
return text.replace(/(?:\r\n|\r|\n)/g, "<br>");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function htmlToText(html: string) {
|
|
||||||
const template = document.createElement("template");
|
|
||||||
const trimmedHTML = html.trim();
|
|
||||||
template.innerHTML = trimmedHTML;
|
|
||||||
const text = template.content.textContent;
|
|
||||||
template.remove();
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getValueFromMeta = (name: string): string | null => {
|
export const getValueFromMeta = (name: string): string | null => {
|
||||||
const element = document.querySelector(`meta[name="${name}"]`);
|
const element = document.querySelector(`meta[name="${name}"]`);
|
||||||
if (element && element.getAttribute("content")) {
|
if (element && element.getAttribute("content")) {
|
||||||
|
|
Loading…
Reference in a new issue