Skip to content

Instantly share code, notes, and snippets.

@Cybso
Last active March 30, 2018 14:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Cybso/9bfa8929aa359c430312e049a358edff to your computer and use it in GitHub Desktop.
Save Cybso/9bfa8929aa359c430312e049a358edff to your computer and use it in GitHub Desktop.
Browser wrapper for ETS Inside
<!doctype html>
<html>
<head>
<!--
Wrapper for ETS Inside that allows to use the application in
a regular web browser and the native app.
Place this file as 'Default.htm' (NOT .html) in the ETS Inside's
Client directory, open http://ipadress:8081/ in a browser (e.g.
http://127.0.0.1:8081 on the same host) and follow this instructions.
Additionally, this wrapper adds a simple loader animation.
ETS Inside is a registered trademark of KNX Association. This wrapper is not endorsed
or approved by KNX Association. To uninstall it just remove or rename the file
Default.htm from the Client directory (normally "C:\Program Files\ETS Inside\Client").
-->
<title>Loader...</title>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<style>
.init-loader {
z-index: 100;
}
.init-loader > .init-loader-message {
font-size: 0.9;
color: #949494;
position: fixed;
left: 50%;
bottom: 0;
transform: translate(-50%, 0);
}
.init-loader > .init-ellipsis {
display: block;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 64px;
height: 64px;
}
.init-loader > .init-ellipsis div {
position: absolute;
top: 27px;
width: 11px;
height: 11px;
border-radius: 50%;
background: #489d3b;
animation-timing-function: cubic-bezier(0, 1, 1, 0);
}
.init-loader > .init-ellipsis div:nth-child(1) {
left: 6px;
animation: init-ellipsis1 0.6s infinite;
}
.init-loader > .init-ellipsis div:nth-child(2) {
left: 6px;
animation: init-ellipsis2 0.6s infinite;
}
.init-loader > .init-ellipsis div:nth-child(3) {
left: 26px;
animation: init-ellipsis2 0.6s infinite;
}
.init-loader > .init-ellipsis div:nth-child(4) {
left: 45px;
animation: init-ellipsis3 0.6s infinite;
}
@keyframes init-ellipsis1 {
0% {
transform: scale(0);
}
100% {
transform: scale(1);
}
}
@keyframes init-ellipsis3 {
0% {
transform: scale(1);
}
100% {
transform: scale(0);
}
}
@keyframes init-ellipsis2 {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(19px, 0);
}
}
</style>
</head>
<body>
<div class="init-loader"><div class="init-ellipsis"><div></div><div></div><div></div><div></div></div><br><div class="init-loader-message"></div></div>
<div id="disable-encryption" style="display: none">
<h1>WebService encryption enabled</h1>
<p>To use <i>ETS Inside</i> in a regular browser you have to disable the server's encryption.</p>
<ol>
<li>Open the <i>ETS Inside</i> installation directory (normally <tt>C:\Program Files\ETS Inside\Server</tt>)</li>
<li>Edit the file <tt>Web.config</tt> with Administrator permissions (e.g. using <a href="https://notepad-plus-plus.org/" target="_blank">Notepad++</a>)</li>
<li>Look for the following line:
<pre>&lt;add name="EncryptionModule" type="Knx.Ets.Osprey.Iis.<span style="color: red">EncryptionModule</span>, Knx.Ets.Osprey.Iis" /&gt;</pre></li>
<li>Replace it with the following line:
<pre>&lt;add name="EncryptionModule" type="Knx.Ets.Osprey.Iis.<span style="color: darkgreen">AspConcurrencyModule</span>, Knx.Ets.Osprey.Iis" /&gt;</pre></li>
<li><a href="javascript:location.reload()">Reload this page</a></li>
</ol>
<p><i>ETS Inside</i> is a registered trademark of KNX Association. This wrapper is not endorsed or approved by KNX Association.
To uninstall it just remove or rename the file <tt>Default.htm</tt> from the <i>ETS Inside</i>'s client directory
(normally <tt>C:\Program Files\ETS Inside\Client</tt>).</p>
</div>
</body>
<script>
(function() {
/**
* Monitor ajax requests in the loader
*/
var send = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function() {
var xhr = this;
var div = document.querySelector('.init-loader-message');
if (div) {
this.addEventListener("progress", function() {
div.innerText = xhr.responseURL;
});
} else {
// message div is not available anymore. Disable this hook.
XMLHttpRequest.prototype.send = send;
}
send.apply(this, arguments);
};
})();
(function() {
/**
* Evaluates <script>-Elements by cloning them
*/
var execScripts = function(scripts) {
for (var i = 0; i < scripts.length; i++) {
script = scripts[i];
var parentNode = script.parentNode;
var nextSibling = script.nextSibling;
if (parentNode) {
parentNode.removeChild(script);
var s = document.createElement('script');
for (var j = 0; j < script.attributes.length; j++){
s.setAttribute(script.attributes[j].nodeName, script.attributes[j].nodeValue);
}
s.innerText = script.innerText;
parentNode.insertBefore(s, nextSibling);
}
}
};
/**
* Inserts a loading animation into the document
*/
var insertLoadingAnimation = function(doc) {
if (doc === document) {
return;
}
// Add a document title for the browser's tab / title bar
if (!doc.title) {
doc.title = document.title;
}
// Copy styles
var head = doc.getElementsByTagName('head')[0];
var styles = document.getElementsByTagName('style');
for (var i = 0; i < styles.length; i++) {
if (styles[i].innerText) {
var style = doc.createElement('style');
style.innerText = styles[i].innerText;
head.appendChild(style);
}
}
// Copy body (will be overwritten when the application has been loaded)
var loader = document.querySelector('.init-loader');
doc.body.appendChild(loader);
};
/**
* Sends a "Still alive"-signal to the server every 60 seconds.
* This is normally done by the dedicated app to keep the session
* alive.
*/
var sendHeartbeat = function() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'WebServices/HeartBeatService.svc/rest/heart-beat');
window.setInterval(function() {
xhr.send(null);
}, 60000);
};
/**
* Loads 'index.html' and replaces the current document
*/
var initApplication = function() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'index.html');
xhr.send(null);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 /* done */) {
if (xhr.status === 200 /* OK */) {
var parser = new DOMParser();
var doc = parser.parseFromString(xhr.responseText, "text/html");
// Will be removed by the application
insertLoadingAnimation(doc);
// Replace site and load embedded scripts
document.replaceChild(doc.documentElement, document.documentElement);
execScripts(document.getElementsByTagName('script'));
} else {
alert('Error: ' + xhr.status);
}
}
}
}
// Checks if encryption has been enabled on the server.
// When ready, this executes the callback function with
// TRUE when encryption is enabled and FALSE when not.
var checkEncryptionState = function(callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'WebServices/StatusService.svc/rest/info');
xhr.send(null);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 /* done */) {
if (xhr.status === 200 /* OK */) {
try {
var info = JSON.parse(xhr.responseText);
if (info && info.InsideVersionDetail) {
// Update the document title, now we know who we are
document.title = info.InsideVersionDetail;
}
// Encryption is disabled
callback(false);
} catch (err) {
// Not what we expected... maybe the encryption is still enabled
callback(true);
}
} else if (xhr.status === 500) {
// Internal server error - guess encryption is enabled
callback(true);
} else {
alert('Error loading ' + xhr.responseURL + ':\n' + xhr.status + ' ' + xhr.statusText);
}
}
}
};
// Wait one second until 'dynamicSecret' should be initialized.
// Then reset it to undefined and load the original page ("index.html").
window.setTimeout(function() {
// Check if encryption is enabled or disabled
checkEncryptionState(function(enabled) {
if (enabled) {
if (typeof(window.dynamicSecret) === 'undefined') {
// Explain how to disable encryption
document.querySelector('.init-loader').style.display = 'none';
document.getElementById('disable-encryption').style.display = 'block';
return;
} else {
initApplication();
}
} else {
if (typeof(window.dynamicSecret) === 'undefined') {
// Initialize key exchange and heartbeat,
// that is normally done by the dedicated app
sendHeartbeat();
};
// Ensure that the client does not try to use encryption
window.dynamicSecret = undefined;
initApplication();
}
});
}, 1000);
})();
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment