Safety feature to detect webcam watermark being removed

This commit is contained in:
Noah 2025-05-14 20:27:04 -07:00
parent 43993d5b01
commit c5e3ffe09b
3 changed files with 79 additions and 7 deletions

View File

@ -3409,7 +3409,8 @@ export default {
@popout="popoutVideo"
@open-profile="showProfileModal"
@set-volume="setVideoVolume"
@modal-alert="modalAlert">
@modal-alert="modalAlert"
@watermark-removed="onDeletedWatermark">
</VideoFeed>
<!-- Others' videos -->
@ -3430,7 +3431,8 @@ export default {
@close-video="expresslyCloseVideo"
@set-volume="setVideoVolume"
@open-profile="showProfileModal"
@modal-alert="modalAlert">
@modal-alert="modalAlert"
@watermark-removed="onDeletedWatermark">
</VideoFeed>
<!-- Debugging - copy a lot of these to simulate more videos -->

View File

@ -27,8 +27,17 @@ export default {
// Mouse over status
mouseOver: false,
// Mutation Observer, to detect if the user deletes the QR code via dev tools.
observer: null,
};
},
mounted() {
this.initWatermarkObserver();
},
beforeUnmount() {
this.observer?.disconnect();
},
computed: {
containerID() {
return this.videoID + '-container';
@ -132,13 +141,37 @@ export default {
"to everybody, and a second (subtle) copy of the code spans across the center/middle of the video and pulsates in " +
"transparency over time.",
});
}
},
// Mutation Observer to detect if the watermark is tampered with by the viewer.
initWatermarkObserver() {
const $container = this.$refs.videoContainer,
$watermark = this.$refs.watermarkImage,
$smallImage = this.$refs.watermarkSmallImage;
if (!$container || !$watermark || !$smallImage) return;
this.observer = new MutationObserver(() => {
const stillPresent = $container.contains($watermark) && $container.contains($smallImage);
if (!stillPresent) {
this.onWatermarkRemoved();
}
});
this.observer.observe($container, {
childList: true,
subtree: true,
});
},
onWatermarkRemoved() {
this.$emit('watermark-removed', this.username);
},
}
}
</script>
<template>
<div class="feed" :id="containerID" :class="{
<div class="feed" ref="videoContainer" :id="containerID" :class="{
'popped-out': poppedOut,
'popped-in': !poppedOut,
}" @mouseover="mouseOver = true" @mouseleave="mouseOver = false">
@ -151,9 +184,9 @@ export default {
:muted="localVideo"></video>
<!-- Watermark layer -->
<div v-if="watermarkImage">
<img :src="watermarkImage" class="watermark" oncontextmenu="return false">
<img :src="watermarkImage" class="corner-watermark seethru invert-color" @click="showWatermarkInfo()" oncontextmenu="return false">
<div>
<img :src="watermarkImage" class="watermark" ref="watermarkImage" oncontextmenu="return false">
<img :src="watermarkImage" class="corner-watermark seethru invert-color" ref="watermarkSmallImage" @click="showWatermarkInfo()" oncontextmenu="return false">
</div>
<!-- Caption -->

View File

@ -1888,6 +1888,43 @@ class WebRTCController {
// Set it.
this.webcam.videoScale = this.webcam.videoScaleOptions[currentSize][0];
},
// Safety feature: if the user deletes the QR code watermark in their browser's dev
// tools, this function is called.
onDeletedWatermark(username) {
// Stop ALL videos NOW.
window.requestAnimationFrame(() => {
this.closeOpenVideos();
this.stopVideo();
});
// Report this to your main website.
this.doCustomReport({
message: {
channel: 'n/a',
username: this.username,
at: new Date(),
message: 'User has deleted the webcam watermark QR code image!',
},
classification: 'Community Safety Violation',
comment: `The user ${this.username} is trying to circumvent the webcam watermarking system!\n\n` +
`It has been detected that the QR code overlay had been removed from the page, possibly via ${this.username} ` +
`using their browser's dev tools to do so.\n\nSpecifically, the webcam being broadcast by @${username} has had its ` +
`watermark element removed from the web page.`
});
// Sign out of chat.
setTimeout(() => {
this.client.disconnect()
}, 5000);
// Show the user an alert modal and reload the page.
this.modalAlert({
icon: "fa fa-skull-crossbones",
title: "Something has gone wrong",
message: "A critical error was detected. Please refresh the web page.",
});
},
}
}