Skip to content

Commit 73e904c

Browse files
authored
Merge pull request #654 from code16/fix-vue-xss
Sanitize vue
2 parents 54fdf29 + 0b50890 commit 73e904c

File tree

3 files changed

+33
-33
lines changed

3 files changed

+33
-33
lines changed

resources/js/components/TemplateRenderer.vue

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,28 @@
1010
</script>
1111
<script lang="ts" setup>
1212
import { computed } from 'vue';
13+
import type { Component } from 'vue';
1314
1415
const props = defineProps<{
15-
templateData?: Record<string, any>,
16-
templateProps?: string[],
1716
template: string,
17+
components?: Record<string, Component>,
1818
}>();
1919
2020
const component = computed(() => ({
21-
components,
22-
template: `<div class="SharpTemplate">${props.template ?? ''}</div>`,
23-
props: [
24-
...(props.templateProps || []),
25-
...Object.keys(props.templateData ?? {}),
26-
],
21+
components: {
22+
...components,
23+
...props.components,
24+
},
25+
template: `<div data-sharp-template>${sanitizeForVue(props.template ?? '')}</div>`,
2726
}));
27+
28+
function sanitizeForVue(template: string) {
29+
return template.replaceAll('{{', '&lcub;&lcub;').replaceAll('}}', '&rcub;&rcub;');
30+
}
2831
</script>
2932

3033
<template>
31-
<component :is="component" v-bind="templateData ?? {}">
34+
<component :is="component">
3235
<slot />
3336
</component>
3437
</template>

resources/js/show/components/fields/text/TextRenderer.vue

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import Html from "@/show/components/fields/text/nodes/Html.vue";
55
import { ShowTextFieldData } from "@/types";
66
import Embed from "@/show/components/fields/text/nodes/Embed.vue";
7-
import { components } from '@/components/TemplateRenderer.vue';
7+
import TemplateRenderer from '@/components/TemplateRenderer.vue';
88
99
const props = defineProps<{
1010
field: ShowTextFieldData,
@@ -21,31 +21,26 @@
2121
dom.content.removeChild(htmlNode);
2222
});
2323
return dom.innerHTML;
24-
})
24+
});
2525
26-
const component = computed<Component>(() => ({
27-
template: `<div>${formattedContent.value}</div>`,
28-
components: {
29-
...components,
30-
'x-sharp-file': File,
31-
'x-sharp-image': File,
32-
'html-content': Html,
33-
...Object.fromEntries(
34-
Object.entries(props.field.embeds ?? {})
35-
.map(([embedKey, embed]) => [
36-
embed.tag,
37-
{
38-
template: '<Embed :embed="embed" v-bind="$attrs"></Embed>',
39-
components: { Embed },
40-
data: () => ({ embed }),
41-
}
42-
])
43-
),
44-
},
26+
const components = computed(() => ({
27+
'x-sharp-file': File,
28+
'x-sharp-image': File,
29+
'html-content': Html,
30+
...Object.fromEntries(
31+
Object.entries(props.field.embeds ?? {})
32+
.map(([embedKey, embed]) => [
33+
embed.tag,
34+
{
35+
template: '<Embed :embed="embed" v-bind="$attrs"></Embed>',
36+
components: { Embed },
37+
data: () => ({ embed }),
38+
}
39+
])
40+
),
4541
}));
4642
</script>
4743

4844
<template>
49-
<component :is="component" />
45+
<TemplateRenderer :template="formattedContent" :components="components" />
5046
</template>
51-

resources/js/utils/sanitize.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ export function sanitize(html: string | null) {
66
ADD_TAGS: ['iframe'],
77
CUSTOM_ELEMENT_HANDLING: {
88
tagNameCheck: () => true,
9-
attributeNameCheck: () => true,
9+
attributeNameCheck: (name) => {
10+
return !name.match(/^(v-)|:|@|#/); // remove vue related attributes
11+
},
1012
},
1113
})
1214
: html;

0 commit comments

Comments
 (0)