Summary: Until now, launching flipper-server with TCP would accept any incoming connection as long as it comes from the same origin (localhost) using web socket host origin verification. This is not entirely secure as origin can be spoofed with tools like curl. Our team created a security review and a proposal was written: https://docs.google.com/document/d/16iXypCQibPiner061SoaQUFUY9tLVAEpkKfV_hUXI7c/ Effectively, Flipper can generate a token which is then used by the client to authenticate. This diff contains the changes required to generate, obtain, and validate authentication tokens from clients connecting to flipper over TCP connections. The token itself is a JWT token. JWT was chosen because it is a simple industry standard which offers three features which can immediately benefit us: - Expiration handling. No need for Flipper to store this information anywhere. - Payload. Payload can be used to push any data we deem relevant i.e. unix username. - Signing. Signed and verified using the same server key pair which is already in place for certificate exchange. Additionally, the token is stored in the Flipper static folder. This ensures that the browser and PWA clients have access to it. Reviewed By: mweststrate Differential Revision: D45179654 fbshipit-source-id: 6761bcb24f4ba30b67d1511cde8fe875158d78af
146 lines
3.8 KiB
HTML
146 lines
3.8 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<link rel="stylesheet" href="style.css">
|
|
<link rel="icon" href="icon.png">
|
|
<link id="flipper-theme-import" rel="stylesheet">
|
|
<title>Flipper</title>
|
|
<script>
|
|
window.flipperConfig = {
|
|
theme: 'light',
|
|
entryPoint: 'flipper-ui-browser/src/index-fast-refresh.bundle?platform=web&dev=true&minify=false',
|
|
debug: true,
|
|
}
|
|
</script>
|
|
<style>
|
|
#loading {
|
|
-webkit-app-region: drag;
|
|
z-index: 999999;
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
bottom: 0;
|
|
right: 0;
|
|
padding: 50px;
|
|
overflow: auto;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 20px;
|
|
color: #525252;
|
|
text-align: center;
|
|
}
|
|
|
|
.__infinity-dev-box-error {
|
|
background-color: red;
|
|
font-family: monospace;
|
|
font-size: 12px;
|
|
z-index: 10;
|
|
bottom: 0;
|
|
left: 0;
|
|
position: absolute;
|
|
}
|
|
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<div id="root">
|
|
<div id="loading">
|
|
Loading...
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="__infinity-dev-box __infinity-dev-box-error" hidden>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
(function () {
|
|
// FIXME: needed to make Metro work
|
|
window.global = window;
|
|
let suppressErrors = false;
|
|
|
|
const socket = new WebSocket(`ws://${location.host}${location.search}`);
|
|
window.devSocket = socket;
|
|
|
|
socket.addEventListener('message', ({ data: dataRaw }) => {
|
|
const message = JSON.parse(dataRaw.toString())
|
|
|
|
if (typeof message.event === 'string') {
|
|
switch (message.event) {
|
|
case 'hasErrors': {
|
|
openError(message.payload);
|
|
suppressErrors = true;
|
|
break;
|
|
}
|
|
case 'plugins-source-updated': {
|
|
window.postMessage({
|
|
type: 'plugins-source-updated',
|
|
data: message.payload
|
|
})
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
socket.addEventListener('error', () => {
|
|
openError('WebSocket -> error');
|
|
suppressErrors = true;
|
|
})
|
|
|
|
|
|
function openError(text) {
|
|
if (suppressErrors) {
|
|
return;
|
|
}
|
|
|
|
const box = document.querySelector('.__infinity-dev-box-error');
|
|
box.removeAttribute('hidden');
|
|
box.textContent = text;
|
|
box.appendChild(closeButton);
|
|
}
|
|
window.flipperShowError = openError;
|
|
window.flipperHideError = () => {
|
|
const box = document.querySelector('.__infinity-dev-box-error');
|
|
box.setAttribute('hidden', true);
|
|
}
|
|
|
|
const closeButton = document.createElement('button');
|
|
closeButton.addEventListener('click', window.flipperHideError);
|
|
closeButton.textContent = 'X';
|
|
|
|
// load correct theme (n.b. this doesn't handle system value specifically, will assume light in such cases)
|
|
try {
|
|
if (window.flipperConfig.theme === 'dark') {
|
|
document.getElementById('flipper-theme-import').href = "themes/dark.css";
|
|
} else {
|
|
document.getElementById('flipper-theme-import').href = "themes/light.css";
|
|
}
|
|
} catch (e) {
|
|
console.error("Failed to initialize theme", e);
|
|
document.getElementById('flipper-theme-import').href = "themes/light.css";
|
|
}
|
|
|
|
function init() {
|
|
const script = document.createElement('script');
|
|
script.src = window.flipperConfig.entryPoint;
|
|
|
|
script.onerror = (e) => {
|
|
openError('Script failure. Check Chrome console for more info.');
|
|
};
|
|
|
|
document.body.appendChild(script);
|
|
}
|
|
init();
|
|
})();
|
|
</script>
|
|
</body>
|
|
|
|
</html>
|