summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Wurst <ChristophWurst@users.noreply.github.com>2021-09-14 20:06:47 +0200
committerGitHub <noreply@github.com>2021-09-14 20:06:47 +0200
commitf8671718cdaae8d2edbf7c8ab74c301e010eac57 (patch)
tree3244a8f4956875ead2e26dcec84fbe29faf8e9a8
parent582ba59b4485f86e4e56bfdac3d0c30f041021a9 (diff)
parent255fd72be679eebd082c1d717e59cff28d02ce3e (diff)
Merge pull request #2437 from nextcloud/backport/2407/stable4.0
[stable4.0] Run SVGs through some sanitization
-rw-r--r--src/components/ContactDetails/ContactDetailsAvatar.vue27
-rw-r--r--src/components/ContactsList/ContactsListItem.vue33
-rw-r--r--src/models/contact.js18
3 files changed, 65 insertions, 13 deletions
diff --git a/src/components/ContactDetails/ContactDetailsAvatar.vue b/src/components/ContactDetails/ContactDetailsAvatar.vue
index 1700c8dd..9a1bd3f5 100644
--- a/src/components/ContactDetails/ContactDetailsAvatar.vue
+++ b/src/components/ContactDetails/ContactDetailsAvatar.vue
@@ -32,8 +32,8 @@
@change="processFile">
<!-- Avatar display -->
- <div v-if="contact.photo"
- :style="{ 'backgroundImage': `url(${contact.photoUrl})` }"
+ <div v-if="photoUrl"
+ :style="{ 'backgroundImage': `url(${photoUrl})` }"
class="contact-header-avatar__photo"
@click="toggleModal" />
<Avatar v-else
@@ -136,7 +136,7 @@
<div class="contact-header-modal__photo-wrapper"
@click.exact.self="toggleModal">
<img ref="img"
- :src="contact.photoUrl"
+ :src="photoUrl"
class="contact-header-modal__photo">
</div>
</Modal>
@@ -178,11 +178,18 @@ export default {
},
},
+ watch: {
+ contact() {
+ this.loadPhotoUrl()
+ },
+ },
+
data() {
return {
maximizeAvatar: false,
opened: false,
loading: false,
+ photoUrl: false,
root: generateRemoteUrl(`dav/files/${getCurrentUser().uid}`),
}
},
@@ -210,6 +217,10 @@ export default {
},
},
+ mounted() {
+ this.loadPhotoUrl()
+ },
+
methods: {
onLoad() {
console.debug(...arguments)
@@ -354,6 +365,16 @@ export default {
this.loading = false
},
+ async loadPhotoUrl() {
+ this.photoUrl = false
+ const photoUrl = await this.contact.getPhotoUrl()
+ if (!photoUrl) {
+ console.warn('contact has an invalid photo')
+ return
+ }
+ this.photoUrl = photoUrl
+ },
+
/**
* Toggle the full image preview
*/
diff --git a/src/components/ContactsList/ContactsListItem.vue b/src/components/ContactsList/ContactsListItem.vue
index 7441aa23..c5d1aee3 100644
--- a/src/components/ContactsList/ContactsListItem.vue
+++ b/src/components/ContactsList/ContactsListItem.vue
@@ -35,7 +35,16 @@ export default {
required: true,
},
},
-
+ data() {
+ return {
+ avatarUrl: undefined,
+ }
+ },
+ watch: {
+ source() {
+ this.loadAvatarUrl()
+ }
+ },
computed: {
selectedGroup() {
return this.$route.params.selectedGroup
@@ -48,18 +57,26 @@ export default {
id() {
return window.btoa(this.source.key).slice(0, -2)
},
-
- avatarUrl() {
+ },
+ mounted() {
+ this.loadAvatarUrl()
+ },
+ methods: {
+ async loadAvatarUrl() {
+ this.avatarUrl = undefined
if (this.source.photo) {
- return `${this.source.photoUrl}`
+ const photoUrl = await this.source.getPhotoUrl()
+ if (!photoUrl) {
+ console.warn('contact has an invalid photo')
+ // Invalid photo data
+ return
+ }
+ this.avatarUrl = photoUrl
}
if (this.source.url) {
- return `${this.source.url}?photo`
+ this.avatarUrl = `${this.source.url}?photo`
}
- return undefined
},
- },
- methods: {
/**
* Select this contact within the list
diff --git a/src/models/contact.js b/src/models/contact.js
index ef122d1c..b87e295d 100644
--- a/src/models/contact.js
+++ b/src/models/contact.js
@@ -26,6 +26,7 @@ import b64toBlob from 'b64-to-blob'
import store from '../store'
import updateDesignSet from '../services/updateDesignSet'
+import sanitizeSVG from '@mattkrick/sanitize-svg'
/**
* Check if the given value is an empty array or an empty string
@@ -229,11 +230,13 @@ export default class Contact {
* Return the photo usable url
* We cannot fetch external url because of csp policies
*
- * @readonly
* @memberof Contact
*/
- get photoUrl() {
+ async getPhotoUrl() {
const photo = this.vCard.getFirstProperty('photo')
+ if (!photo) {
+ return false
+ }
const encoding = photo.getFirstParameter('encoding')
let photoType = photo.getFirstParameter('type')
let photoB64 = this.photo
@@ -247,6 +250,17 @@ export default class Contact {
photoType = photoB64.split(';')[0].split('/')
}
+ // Verify if SVG is valid
+ if (photoType.startsWith('svg')) {
+ const imageSvg = atob(photoB64)
+ const cleanSvg = await sanitizeSVG(imageSvg)
+
+ if (!cleanSvg) {
+ console.error('Invalid SVG for the following contact. Ignoring...', this.contact, { photoB64, photoType })
+ return false
+ }
+ }
+
try {
// Create blob from url
const blob = b64toBlob(photoB64, `image/${photoType}`)