Move bulk to react-sdk and reference it from riot-web land

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2020-02-13 16:58:27 +00:00
parent 627a4d4ea4
commit 4ed27a4ba6
3 changed files with 88 additions and 0 deletions

27
docs/usercontent.md Normal file
View file

@ -0,0 +1,27 @@
# Usercontent
While decryption itself is safe to be done without a sandbox,
letting the browser and user interact with the resulting data may be dangerous,
previously `usercontent.riot.im` was used to act as a sandbox on a different origin to close the attack surface,
it is now possible to do by using a combination of a sandboxed iframe and some code written into the app which consumes this SDK.
Usercontent is an iframe sandbox target for allowing a user to safely download a decrypted attachment from a sandboxed origin where it cannot be used to XSS your riot session out from under you.
Its function is to create an Object URL for the user/browser to use but bound to an origin different to that of the riot instance to protect against XSS.
It exposes a function over a postMessage API, when sent an object with the matching fields to render a download link with the Object URL:
```json5
{
"imgSrc": "", // the src of the image to display in the download link
"imgStyle": "", // the style to apply to the image
"style": "", // the style to apply to the download link
"download": "", // download attribute to pass to the <a/> tag
"textContent": "", // the text to put inside the download link
"blob": "", // the data blob to wrap in an object url and allow the user to download
}
```
If only imgSrc, imgStyle and style are passed then just update the existing link without overwriting other things about it.
It is expected that this target be available at `usercontent/` relative to the root of the app, this can be seen in riot-web's webpack config.

View file

@ -0,0 +1,12 @@
<html>
<head>
<!--
Hello! If you're reading this, perhaps you're wondering what this
file is doing and why your Riot is using it.
In short, this allows Riot to isolate potentially unsafe encrypted
attachments into their own origin, away from your Riot.
Stay curious!
-->
</head>
<body></body>
</html>

49
src/usercontent/index.js Normal file
View file

@ -0,0 +1,49 @@
var params = window.location.search.substring(1).split('&');
var lockOrigin;
for (var i = 0; i < params.length; ++i) {
var parts = params[i].split('=');
if (parts[0] === 'origin') lockOrigin = decodeURIComponent(parts[1]);
}
function remoteRender(event) {
const data = event.data;
const img = document.createElement("img");
img.id = "img";
img.src = data.imgSrc;
img.style = data.imgStyle;
const a = document.createElement("a");
a.id = "a";
a.rel = "noopener";
a.target = "_blank";
a.download = data.download;
a.style = data.style;
a.style.fontFamily = "Arial, Helvetica, Sans-Serif";
a.href = window.URL.createObjectURL(data.blob);
a.appendChild(img);
a.appendChild(document.createTextNode(data.textContent));
const body = document.body;
// Don't display scrollbars if the link takes more than one line to display.
body.style = "margin: 0px; overflow: hidden";
body.appendChild(a);
}
function remoteSetTint(event) {
const data = event.data;
const img = document.getElementById("img");
img.src = data.imgSrc;
img.style = data.imgStyle;
const a = document.getElementById("a");
a.style = data.style;
}
window.onmessage = function(e) {
if (lockOrigin === undefined || e.origin === lockOrigin) {
if (e.data.blob) remoteRender(e);
else remoteSetTint(e);
}
};