Add files via upload

more security patches
This commit is contained in:
Steve Seguin
2025-10-21 20:13:06 -04:00
committed by GitHub
parent 83c0ac753a
commit 20c815e607
6 changed files with 383 additions and 170 deletions

164
examples/chat.html Normal file
View File

@@ -0,0 +1,164 @@
<html>
<head>
<meta charset="utf8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>OBSN Chat Overlay</title>
<style>
@font-face {
font-family: 'Cousine';
src: url('fonts/Cousine-Bold.ttf') format('truetype');
}
body {
margin:0;
padding:0 10px;
height:100%;
border: 0;
display: flex;
flex-direction: column-reverse;
position:absolute;
bottom:0;
overflow:hidden;
max-width:100%;
}
div {
margin:0;
background-color: black;
padding: 8px 8px 0px 8px;
color: white;
font-family: Cousine, monospace;
font-size: 3.2em;
line-height: 1.1em;
letter-spacing: 0.0em;
text-transform: uppercase;
text-shadow: 0.05em 0.05em 0px rgba(0,0,0,1);
max-width:100%;
word-wrap: break-word;
overflow-wrap: break-word;
word-break: break-all;
hyphens: auto;
display:inline-block;
}
a {
color:white;
font-size:1.2em;
text-transform: none;
word-wrap: break-word;
overflow-wrap: break-word;
word-wrap: break-word;
word-break: break-all;
hyphens: auto;
}
</style>
<script>
(function (w) {
w.URLSearchParams =
w.URLSearchParams ||
function (searchString) {
var self = this;
self.searchString = searchString;
self.get = function (name) {
var results = new RegExp("[\?&]" + name + "=([^&#]*)").exec(
self.searchString
);
if (results == null) {
return null;
} else {
return decodeURI(results[1]) || 0;
}
};
};
})(window);
var urlParams = new URLSearchParams(window.location.search);
function loadIframe() {
var iframe = document.createElement("iframe");
var view= "";
if (urlParams.has("view")) {
view = "&view="+(urlParams.get("view") || "");
}
var room="";
if (urlParams.has("room")) {
room = "&room="+urlParams.get("room");
}
var password="";
if (urlParams.has("password")) {
password = "&password="+urlParams.get("password");
}
iframe.allow = "autoplay";
var srcString = "./?novideo&noaudio&label=chatOverlay&scene"+room+view+password;
iframe.src = srcString;
iframe.style.width="0";
iframe.style.height="0";
iframe.style.border="0";
document.body.appendChild(iframe);
//////////// LISTEN FOR EVENTS
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
/// If you have a routing system setup, you could have just one global listener for all iframes instead.
eventer(messageEvent, function (e) {
if (e.source != iframe.contentWindow){return} // reject messages send from other iframes
console.log(e);
if ("gotChat" in e.data){
logData(e.data.gotChat.label,e.data.gotChat.msg);
}
});
}
function printValues(obj) {
var out = "";
for (var key in obj) {
if (typeof obj[key] === "object") {
out += "<br />";
out += printValues(obj[key]);
} else {
if (key.startsWith("_")) {
} else {
out += "<b>" + key + "</b>: " + obj[key] + "<br />";
}
}
}
return out;
}
function logData(type, data) {
var span = document.createElement('span');
var entry = document.createElement('div');
if (type){
var typeElement = document.createElement('i');
typeElement.textContent = type.replace(/_/g, ' ');
entry.appendChild(typeElement);
entry.appendChild(document.createTextNode(" "));
}
var message = document.createElement('span');
message.textContent = data;
entry.appendChild(message);
span.appendChild(entry);
document.body.prepend(span);
}
</script>
</head>
<body onload="loadIframe();">
</body>
</html>

View File

@@ -166,16 +166,21 @@
window.location.href = newUrl; window.location.href = newUrl;
} }
function logData(type, data) { function logData(type, data) {
var entry = document.createElement('div'); var entry = document.createElement('div');
if (type) { if (type) {
type = "<i>" + type.replace(/_/g, ' ') + "</i>"; var typeElement = document.createElement('i');
} typeElement.textContent = type.replace(/_/g, ' ');
entry.innerHTML = type + data; entry.appendChild(typeElement);
document.getElementById('chat-overlay').prepend(entry); entry.appendChild(document.createTextNode(" "));
} }
var message = document.createElement('span');
message.textContent = data;
entry.appendChild(message);
document.getElementById('chat-overlay').prepend(entry);
}
window.onload = loadIframe; window.onload = loadIframe;
</script> </script>
</body> </body>
</html> </html>

View File

@@ -94,21 +94,39 @@ if (urlParams.has("api")){
var href = window.location.href; var href = window.location.href;
var arr = href.split('?'); var arr = href.split('?');
var newurl; var newurl;
if (arr.length > 1 && arr[1] !== '') { if (arr.length > 1 && arr[1] !== '') {
newurl = href + '&api=' + WID; newurl = href + '&api=' + encodeURIComponent(WID);
} else { } else {
newurl = href + '?api=' + WID; newurl = href + '?api=' + encodeURIComponent(WID);
} }
window.history.pushState({path: newurl.toString()}, '', newurl.toString()); window.history.pushState({path: newurl.toString()}, '', newurl.toString());
} }
var path = "vdo.ninja"; //window.location.host+window.location.pathname.split("/").slice(0,-1).join("/"); var path = "vdo.ninja"; //window.location.host+window.location.pathname.split("/").slice(0,-1).join("/");
var header = document.getElementById("header"); var header = document.getElementById("header");
header.innerHTML += "Your Ninja Link: <a href='https://"+path+"/?api="+WID+"' target='_blank'>https://"+path+"/?api="+WID+"</a><br /><br />"; var linkWrapper = document.createElement("div");
header.innerHTML += "<small>You can append your own VDO.Ninja parameters to this link, treating it like a normal VDO.Ninja link.</small>"; var linkLabel = document.createElement("span");
header.innerHTML += "<br /><br /><small>Code and documentation hosted at <a href='https://github.com/steveseguin/Companion-Ninja'>https://github.com/steveseguin/Companion-Ninja</a></small> <svg width='32' height='32' viewBox='0 0 1024 1024' fill='none' xmlns='http://www.w3.org/2000/svg'><path fill-rule='evenodd' clip-rule='evenodd' d='M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z' transform='scale(64)' fill='#1B1F23'/></svg>"; linkLabel.textContent = "Your Ninja Link: ";
var shareLink = document.createElement("a");
var shareURL = "https://" + path + "/?api=" + encodeURIComponent(WID);
shareLink.href = shareURL;
shareLink.target = "_blank";
shareLink.rel = "noopener";
shareLink.textContent = shareURL;
linkWrapper.appendChild(linkLabel);
linkWrapper.appendChild(shareLink);
header.appendChild(linkWrapper);
var info = document.createElement("small");
info.textContent = "You can append your own VDO.Ninja parameters to this link, treating it like a normal VDO.Ninja link.";
header.appendChild(info);
header.appendChild(document.createElement("br"));
header.appendChild(document.createElement("br"));
var repoInfo = document.createElement("small");
repoInfo.innerHTML = "Code and documentation hosted at <a href='https://github.com/steveseguin/Companion-Ninja'>https://github.com/steveseguin/Companion-Ninja</a>";
header.appendChild(repoInfo);
header.insertAdjacentHTML("beforeend", " <svg width='32' height='32' viewBox='0 0 1024 1024' fill='none' xmlns='http://www.w3.org/2000/svg'><path fill-rule='evenodd' clip-rule='evenodd' d='M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z' transform='scale(64)' fill='#1B1F23'/></svg>");
var socket = null; var socket = null;
var connecting = false; var connecting = false;
@@ -474,4 +492,4 @@ loadGuestCommands(3);
loadGuestCommands(4); loadGuestCommands(4);
</script> </script>
</body> </body>
</html> </html>

View File

@@ -99,8 +99,50 @@ function loadIframe(url=false){ // this is pretty important if you want to avoi
document.getElementById("container").appendChild(iframeContainer); document.getElementById("container").appendChild(iframeContainer);
var videos = iframe.contentWindow.document.querySelectorAll("video"); var videos = iframe.contentWindow.document.querySelectorAll("video");
var sensors = {}; var sensors = {};
function appendTextLine(container, text, indentLevel){
var line = document.createElement("div");
if (indentLevel){
line.style.marginLeft = (indentLevel * 12) + "px";
}
line.textContent = text;
container.appendChild(line);
}
function appendKeyValueList(container, obj, indentLevel){
indentLevel = indentLevel || 0;
for (var key in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
continue;
}
var value = obj[key];
if (typeof value === "object" && value !== null) {
appendTextLine(container, key + ":", indentLevel);
appendKeyValueList(container, value, indentLevel + 1);
} else {
appendTextLine(container, key + ": " + value, indentLevel);
}
}
}
function getOrCreateOutput(id, borderStyle){
var element = id ? document.getElementById(id) : null;
if (element){
element.textContent = "";
return element;
}
var div = document.createElement("div");
if (borderStyle){
div.style.border = borderStyle;
}
if (id){
div.id = id;
}
iframeContainer.appendChild(div);
return div;
}
function drawFrame(vid){ function drawFrame(vid){
try { try {
@@ -159,122 +201,99 @@ function loadIframe(url=false){ // this is pretty important if you want to avoi
eventer(messageEvent, function (e) { eventer(messageEvent, function (e) {
if (e.source != iframe.contentWindow){return} // reject messages send from other iframes if (e.source != iframe.contentWindow){return} // reject messages send from other iframes
if ("stats" in e.data){ if ("stats" in e.data){
var outputWindow = document.createElement("div"); var statsBox = document.createElement("div");
//console.log(e.data.stats); appendTextLine(statsBox, "total_inbound_connections: " + e.data.stats.total_inbound_connections);
appendTextLine(statsBox, "total_outbound_connections: " + e.data.stats.total_outbound_connections);
var out = "<br />total_inbound_connections:"+e.data.stats.total_inbound_connections; for (var streamID in e.data.stats.inbound){
out += "<br />total_outbound_connections:"+e.data.stats.total_outbound_connections; if (!Object.prototype.hasOwnProperty.call(e.data.stats.inbound, streamID)){
continue;
for (var streamID in e.data.stats.inbound){ }
out += "<br /><br /><b>streamID:</b> "+streamID+"<br />"; var streamHeader = document.createElement("div");
out += printValues(e.data.stats.inbound[streamID]); streamHeader.style.marginTop = "8px";
} var streamLabel = document.createElement("strong");
streamLabel.textContent = "streamID:";
outputWindow.innerHTML = out; streamHeader.appendChild(streamLabel);
iframeContainer.appendChild(outputWindow); streamHeader.appendChild(document.createTextNode(" " + streamID));
} statsBox.appendChild(streamHeader);
appendKeyValueList(statsBox, e.data.stats.inbound[streamID], 1);
if ("gotChat" in e.data){ }
var outputWindow = document.createElement("div");
outputWindow.innerHTML = e.data.gotChat.msg; iframeContainer.appendChild(statsBox);
outputWindow.style.border="1px dotted black"; }
iframeContainer.appendChild(outputWindow);
} if ("gotChat" in e.data){
var chatBox = document.createElement("div");
if ("action" in e.data){ chatBox.textContent = e.data.gotChat.msg;
var outputWindow = document.createElement("div"); chatBox.style.border="1px dotted black";
outputWindow.innerHTML = "child-page-action: "+e.data.action+"<br />"; iframeContainer.appendChild(chatBox);
outputWindow.style.border="1px dotted black"; }
iframeContainer.appendChild(outputWindow);
console.log(e.data.action); if ("action" in e.data){
var actionBox = document.createElement("div");
if (e.data.action == "new-view-connection"){ appendTextLine(actionBox, "child-page-action: " + e.data.action);
setTimeout(function(){ actionBox.style.border="1px dotted black";
videos = iframe.contentWindow.document.querySelectorAll("video"); iframeContainer.appendChild(actionBox);
console.log(videos); console.log(e.data.action);
},500);
} if (e.data.action == "new-view-connection"){
} setTimeout(function(){
videos = iframe.contentWindow.document.querySelectorAll("video");
console.log(videos);
if ("streamIDs" in e.data){ },500);
var outputWindow = document.createElement("div"); }
outputWindow.innerHTML = "child-page-action: streamIDs<br />"; }
for (var key in e.data.streamIDs) {
outputWindow.innerHTML += "streamID: " + key + ", label:"+e.data.streamIDs[key] + "\n";
} if ("streamIDs" in e.data){
outputWindow.style.border="1px dotted black"; var streamBox = document.createElement("div");
iframeContainer.appendChild(outputWindow); streamBox.style.border="1px dotted black";
} appendTextLine(streamBox, "child-page-action: streamIDs");
for (var key in e.data.streamIDs) {
if ("loudness" in e.data){ if (!Object.prototype.hasOwnProperty.call(e.data.streamIDs, key)){
//console.log(e.data); continue;
if (document.getElementById("loudness")){ }
outputWindow = document.getElementById("loudness"); appendTextLine(streamBox, "streamID: " + key + ", label: " + e.data.streamIDs[key], 1);
} else { }
var outputWindow = document.createElement("div"); iframeContainer.appendChild(streamBox);
outputWindow.style.border="1px dotted black"; }
iframeContainer.appendChild(outputWindow);
outputWindow.id = "loudness"; if ("loudness" in e.data){
} var loudnessBox = getOrCreateOutput("loudness", "1px dotted black");
outputWindow.innerHTML = "child-page-action: loudness<br />"; appendTextLine(loudnessBox, "child-page-action: loudness");
for (var key in e.data.loudness) { for (var key in e.data.loudness) {
outputWindow.innerHTML += key + " Loudness: " + e.data.loudness[key] + "\n"; if (!Object.prototype.hasOwnProperty.call(e.data.loudness, key)){
} continue;
outputWindow.style.border="1px black"; }
appendTextLine(loudnessBox, key + " Loudness: " + e.data.loudness[key], 1);
} }
loudnessBox.style.border="1px black";
if ("sensors" in e.data){
sensors = e.data.sensors; }
if (document.getElementById("sensors")){
outputWindow = document.getElementById("sensors"); if ("sensors" in e.data){
} else { sensors = e.data.sensors;
var outputWindow = document.createElement("div"); var sensorsBox = getOrCreateOutput("sensors", "1px dotted black");
outputWindow.style.border="1px dotted black"; appendTextLine(sensorsBox, "child-page-action: sensors");
iframeContainer.appendChild(outputWindow); for (var sensorKey in e.data.sensors) {
outputWindow.id = "sensors"; if (!Object.prototype.hasOwnProperty.call(e.data.sensors, sensorKey)){
console.log(sensors); continue;
} }
outputWindow.innerHTML = "child-page-action: sensors<br /><br />"; var sensorValue = e.data.sensors[sensorKey];
if (typeof sensorValue === "object" && sensorValue !== null){
for (var key in e.data.sensors.lin) { appendTextLine(sensorsBox, sensorKey + ":", 0);
outputWindow.innerHTML += key + " linear: " + e.data.sensors.lin[key] + "<br />"; appendKeyValueList(sensorsBox, sensorValue, 1);
} } else {
for (var key in e.data.sensors.acc) { appendTextLine(sensorsBox, sensorKey + ": " + sensorValue, 0);
outputWindow.innerHTML += key + " acceleration: " + e.data.sensors.acc[key] + "<br />"; }
} }
for (var key in e.data.sensors.gyro) { sensorsBox.style.border="1px black";
outputWindow.innerHTML += key + " gyro: " + e.data.sensors.gyro[key] + "<br />"; }
}
for (var key in e.data.sensors.mag) {
outputWindow.innerHTML += key + " magnet: " + e.data.sensors.mag[key] + "<br />";
}
for (var key in e.data.sensors.ori) {
outputWindow.innerHTML += key + " orientation: " + e.data.sensors.ori[key] + "<br />";
}
outputWindow.style.border="1px black";
}
}); });
} }
function printValues( obj) { </script>
var out = ""; </body>
for (var key in obj) { </html>
if (typeof obj[key] === "object") {
out +="<br />";
out += printValues(obj[key]);
} else {
out +="<b>"+key+"</b>: "+obj[key]+"<br />";
}
}
return out;
}
</script>
</body>
</html>

View File

@@ -147,21 +147,26 @@
return out; return out;
} }
function logData(type, data) { function logData(type, data) {
var log = document.body.getElementsByTagName("ul")[0]; var log = document.body.getElementsByTagName("ul")[0];
var entry = document.createElement('li'); var entry = document.createElement('li');
if (type){ if (type){
type = "<i>"+type+"</i>"; var typeElement = document.createElement("i");
} typeElement.textContent = type;
entry.innerHTML = type + data; entry.appendChild(typeElement);
entry.appendChild(document.createTextNode(" "));
//setTimeout(function(entry){ // hide message after 60 seconds }
// entry.innerHTML=""; var message = document.createElement("span");
// entry.remove(); message.textContent = data;
// },60000,entry); entry.appendChild(message);
log.appendChild(entry); //setTimeout(function(entry){ // hide message after 60 seconds
} // entry.innerHTML="";
// entry.remove();
// },60000,entry);
log.appendChild(entry);
}
</script> </script>
</head> </head>
<body onload="loadIframe();"> <body onload="loadIframe();">

View File

@@ -130,12 +130,13 @@ if (urlParams.get("a")){
} }
document.getElementById("viewlinka").value = "https://"+path+"/?push="+urlParams.get("a"); document.getElementById("viewlinka").value = "https://"+path+"/?push="+urlParams.get("a");
if (urlParams.get("la")){ if (urlParams.get("la")){
document.getElementById("viewlinka").value += "&label="+urlParams.get("la"); var labelA = urlParams.get("la");
document.getElementById("a").innerHTML = urlParams.get("la") document.getElementById("viewlinka").value += "&label="+encodeURIComponent(labelA);
} document.getElementById("a").textContent = labelA;
}
}
}
if (urlParams.get("b")){ if (urlParams.get("b")){
if (window.location.host){ if (window.location.host){
var path = window.location.host+window.location.pathname.replace("/examples/","/").split("/").slice(0,-1).join("/"); var path = window.location.host+window.location.pathname.replace("/examples/","/").split("/").slice(0,-1).join("/");
@@ -144,11 +145,12 @@ if (urlParams.get("b")){
} }
document.getElementById("viewlinkb").value = "https://"+path+"/?push="+urlParams.get("b"); document.getElementById("viewlinkb").value = "https://"+path+"/?push="+urlParams.get("b");
if (urlParams.get("lb")){ if (urlParams.get("lb")){
document.getElementById("viewlinkb").value += "&label="+urlParams.get("lb"); var labelB = urlParams.get("lb");
document.getElementById("b").innerHTML = urlParams.get("lb") document.getElementById("viewlinkb").value += "&label="+encodeURIComponent(labelB);
} document.getElementById("b").textContent = labelB;
} }
}
var iframeb = null; var iframeb = null;
var iframea = null; var iframea = null;
@@ -193,15 +195,15 @@ function loadIframes(){
if (iframeb && (e.source === iframeb.contentWindow)) { if (iframeb && (e.source === iframeb.contentWindow)) {
console.log(e.data); console.log(e.data);
if (e.data.action == "this-label"){ if (e.data.action == "this-label"){
document.getElementById("a").innerHTML = e.data.value; document.getElementById("a").textContent = e.data.value;
} }
} else if (iframea && (e.source === iframea.contentWindow)) { } else if (iframea && (e.source === iframea.contentWindow)) {
if (e.data.action == "this-label"){ if (e.data.action == "this-label"){
document.getElementById("b").innerHTML = e.data.value; document.getElementById("b").textContent = e.data.value;
} }
} }
}, false); }, false);
</script> </script>
</body> </body>
</html> </html>