Improve webcam QR code tampering detection

This commit is contained in:
Noah 2025-06-12 21:04:24 -07:00
parent 05444dcc15
commit 467965d097
3 changed files with 65 additions and 2 deletions

View File

@ -157,4 +157,27 @@ func (h *BotHandlers) setObjectMacros() {
} }
return "" return ""
}) })
// Send a public chat message to a channel name.
h.rs.SetSubroutine("ban", func(rs *rivescript.RiveScript, args []string) string {
if len(args) >= 1 {
var (
username = args[0]
duration = "24"
)
if len(args) > 1 {
duration = args[1]
}
log.Error("Macro: /ban %s %s", username, duration)
h.client.Send(messages.Message{
Action: messages.ActionMessage,
Channel: "barertc-debug",
Message: fmt.Sprintf("/ban %s %s", username, duration),
})
} else {
return "[ban: invalid number of parameters]"
}
return ""
})
} }

View File

@ -147,16 +147,47 @@ export default {
// Mutation Observer to detect if the watermark is tampered with by the viewer. // Mutation Observer to detect if the watermark is tampered with by the viewer.
initWatermarkObserver() { initWatermarkObserver() {
const $container = this.$refs.videoContainer, const $container = this.$refs.videoContainer,
$layer = this.$refs.watermarkLayer,
$watermark = this.$refs.watermarkImage, $watermark = this.$refs.watermarkImage,
$smallImage = this.$refs.watermarkSmallImage; $smallImage = this.$refs.watermarkSmallImage;
if (!$container || !$watermark || !$smallImage) return; if (!$container || !$watermark || !$smallImage) return;
// Helper function to check CSS properties that may hide the element visually without deleting it from the page.
const isInvisible = (elem) => {
let style = window.getComputedStyle(elem);
return style.display === "none" || style.visibility === "hidden" || parseFloat(style.opacity) < 0.02;
};
const isImageMissing = (elem) => {
try {
let src = elem.src;
if (src.indexOf("data:image/svg") !== 0) {
return true;
}
} catch (e) {
console.error("isImageMissing", elem, e);
}
return false;
}
this.observer = new MutationObserver(() => { this.observer = new MutationObserver(() => {
const stillPresent = $container.contains($watermark) && $container.contains($smallImage); const stillPresent = $container.contains($layer) && $container.contains($watermark) && $container.contains($smallImage);
if (!stillPresent) { if (!stillPresent) {
this.onWatermarkRemoved(); this.onWatermarkRemoved();
} }
// Check for CSS hacking: this looks at the computed style, so only check if the top-level VideoFeed is not hidden.
try {
if ($container.style.display !== "none") {
if (isInvisible($watermark) || isInvisible($smallImage) || isInvisible($layer)) {
this.onWatermarkRemoved();
} else if (isImageMissing($watermark) || isImageMissing($smallImage)) {
this.onWatermarkRemoved();
}
}
} catch(e) {
console.error("checking container:", e);
}
}); });
this.observer.observe($container, { this.observer.observe($container, {
@ -185,7 +216,7 @@ export default {
:muted="localVideo"></video> :muted="localVideo"></video>
<!-- Watermark layer --> <!-- Watermark layer -->
<div :class="{'is-no-watermark': isNoWatermark}"> <div :class="{'is-no-watermark': isNoWatermark}" ref="watermarkLayer">
<img :src="watermarkImage" class="watermark" ref="watermarkImage" oncontextmenu="return false"> <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"> <img :src="watermarkImage" class="corner-watermark seethru invert-color" ref="watermarkSmallImage" @click="showWatermarkInfo()" oncontextmenu="return false">
</div> </div>

View File

@ -1939,6 +1939,15 @@ class WebRTCController {
`watermark element removed from the web page.` `watermark element removed from the web page.`
}); });
// Broadcast our shame.
this.client.send({
action: "message",
channel: "lobby",
message: `Hey @all I have been very naughty and have been caught red-handed tampering with the webcam QR code watermarks ` +
`here on the chat room. A special apology to @${username} whose camera I was messing with. I will now see myself out ` +
`of the chat room as I hang my head in shame.`,
});
// Sign out of chat. // Sign out of chat.
setTimeout(() => { setTimeout(() => {
this.client.disconnect() this.client.disconnect()