Skip to content

Commit

Permalink
Interception of screen capture.
Browse files Browse the repository at this point in the history
  • Loading branch information
PoneyClairDeLune committed Jul 4, 2022
1 parent 0e3cb42 commit 426049c
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 4 deletions.
98 changes: 94 additions & 4 deletions svc/minuette.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
"use strict";
import {ics} from "./ics.js";
import {fakeNative} from "./minuette/fakeNative.js";
import {getCSSSelector} from "./minuette/cssSelector.js"
import {getCSSSelector} from "./minuette/cssSelector.js";
import {getRandom} from "./minuette/getRandom.js";
import {getEventFamily, getEventData} from "./minuette/eventData.js"
import {getEventFamily, getEventData} from "./minuette/eventData.js";
import {fakeScreen, fakeCamera} from "./minuette/fakeStream.js";
self.blacklistEvent = ["visibilitychange"];
self.fakeScreenVideo = undefined;
{
// Constants
const selectorSkip = ["id", "class"],
Expand Down Expand Up @@ -52,8 +54,39 @@ self.blacklistEvent = ["visibilitychange"];
fakeNative(HTMLElement.prototype.addEventListener);
HTMLElement.prototype.addEventListener = fakeAddEl;
document.addEventListener = fakeAddEl;
// Hijack several document APIs
let realDocument = self.document;
// Hijack screen reading
let realScreen = self.screen, fakeScreenWidth, fakeScreenHeight;
self.screen = new Proxy(self.screen, {get: function (obj, prop) {
switch (prop) {
case "availHeight":
case "height": {
return fakeScreenHeight;
break;
};
case "availWidth":
case "width": {
return fakeScreenWidth;
break;
};
case "orientation": {
return new Proxy(realScreen.orientation, {get: function (obj, prop) {
if (prop == "type") {
return (screen.width / screen.height < 1 ? "portrait" : "landscape");
} else {
return obj[prop];
};
}});
break;
};
default: {
return obj[prop];
};
};
}});
/*screen.orientation = */
let navMedDev = navigator.mediaDevices,
getDispMed = navMedDev.getDisplayMedia,
getUserMed = navMedDev.getUserMedia;
// Extension channel message
let extChannel = new BroadcastChannel("-ReplaceMeWithSomethingUnique-");
extChannel.onmessage = function (msg) {
Expand All @@ -72,5 +105,62 @@ self.blacklistEvent = ["visibilitychange"];
};
};
};
// Hijack display capture
navigator.mediaDevices.getDisplayMedia = async function () {
let stream;
try {
stream = await getDispMed.apply(navMedDev, arguments);
} catch (err) {
extChannel.postMessage({e: "getDisplay", success: false});
throw(err);
};
// Hijack stream
let inFocus = true, captureExhaust = 0;
let fakeVideoSource = document.createElement("video");
fakeVideoSource.srcObject = stream;
fakeVideoSource.muted = true;
fakeVideoSource.autoplay = true;
fakeVideoSource.style = "display: none";
addEL.apply(document, ["blur", function () {
inFocus = false;
captureExhaust = 2;
fakeVideoSource.pause();
ics.debug("Window lost focus.");
}]);
addEL.apply(document, ["focus", function () {
inFocus = true;
fakeVideoSource.play();
captureExhaust = 5;
ics.debug("Window regain focus.");
}]);
document.body.appendChild(fakeVideoSource);
let fakeVideoCanvas = document.createElement("canvas");
fakeVideoCanvas.width = screen.width;
fakeVideoCanvas.height = screen.height;
fakeVideoCanvas.style = "display: none";
document.body.appendChild(fakeVideoCanvas);
let fakeCanvasContext = fakeVideoCanvas.getContext("2d");
fakeCanvasContext.fillStyle = "#777";
fakeCanvasContext.fillRect(0, 0, screen.width, screen.height);
addEL.apply(fakeVideoSource, ["playing", function () {
fakeScreenWidth = fakeVideoSource.videoWidth,
fakeScreenHeight = fakeVideoSource.videoHeight;
fakeVideoCanvas.width = fakeVideoSource.videoWidth;
fakeVideoCanvas.height = fakeVideoSource.videoHeight;
fakeCanvasContext.drawImage(fakeVideoSource, 0, 0);
}]);
let proxyScreen = setInterval(function () {
if (!document.hidden && inFocus && !fakeVideoSource.paused) {
if (captureExhaust < 1) {
fakeCanvasContext.drawImage(fakeVideoSource, 0, 0);
} else {
captureExhaust --;
};
};
}, 50);
let newStream = fakeVideoCanvas.captureStream(60);
extChannel.postMessage({e: "getDisplay", success: true, stream: stream.id, task: proxyScreen});
return newStream;
};
};
ics.debug("Minuette launched.");
21 changes: 21 additions & 0 deletions svc/minuette/fakeStream.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"use strict";
let fakeScreenGetter = function (obj, prop) {
if (prop != "label") {
return obj[prop];
} else {
return "Primary Monitor"; // This may change due to language or browser. This is on Firefox.
};
};
// I'm a bummer
let fakeScreen = function (stream) {
stream.forEach(function (e, i, a) {
a[i] = new Proxy(e, fakeScreenGetter);
});
return stream;
};
let fakeCamera = function (stream) {};

export {
fakeScreen,
fakeCamera
};

0 comments on commit 426049c

Please sign in to comment.