Common stuff for all my devices' web server pages: css, login, log, ipv4, ipv6, firmware update, clock, reset info etc.

Dependents:   oldheating gps motorhome heating

Security

A password has to be set whenever there has been a software reset. Resets following faults or power on do not require a new password as the hash is restored from the RTC GPREG register.

The password is not saved on the device; instead a 32 bit hash of the password is saved. It would take 2^31 attempts to brute force the password: this could be done in under a month if an attempt were possible every millisecond. To prevent this a 200 ms delay is introduced in the reply to the login form, that gives a more reasonable 13 years to brute force the password.

Once the password is accepted a random session id is created. This is 36 bit to give six base 64 characters but without an extra delay. If an attempt could be made every ms then this would still take over a year to brute force.

The most likely attack would to use a dictionary with, say, 10 million entries against the password which would still take 20 days to do.

Committer:
andrewboyson
Date:
Thu Apr 18 15:26:29 2019 +0000
Revision:
95:8c9dda8a0caf
Used class to encapsulate ajax part of js in base.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewboyson 95:8c9dda8a0caf 1 "//Ajax script\n"
andrewboyson 95:8c9dda8a0caf 2 "'use strict';\n"
andrewboyson 95:8c9dda8a0caf 3 "\n"
andrewboyson 95:8c9dda8a0caf 4 "//Exposed properties\n"
andrewboyson 95:8c9dda8a0caf 5 "let ajaxResponse_ = '';\n"
andrewboyson 95:8c9dda8a0caf 6 "let ajaxHeaders_ = '';\n"
andrewboyson 95:8c9dda8a0caf 7 "let ajaxMs_ = 0;\n"
andrewboyson 95:8c9dda8a0caf 8 "let ajaxOnResponse_ = null;\n"
andrewboyson 95:8c9dda8a0caf 9 "let ajaxOnTick_ = null;\n"
andrewboyson 95:8c9dda8a0caf 10 "let ajaxServer_ = '';\n"
andrewboyson 95:8c9dda8a0caf 11 "\n"
andrewboyson 95:8c9dda8a0caf 12 "//Private variables\n"
andrewboyson 95:8c9dda8a0caf 13 "let ajaxOverrideBlockUpdateOnFocus_ = false;\n"
andrewboyson 95:8c9dda8a0caf 14 "let ajaxXhr_ = null;\n"
andrewboyson 95:8c9dda8a0caf 15 "let ajaxMsCountAtAjaxSend_ = 0;\n"
andrewboyson 95:8c9dda8a0caf 16 "const ajaxTickMs_ = 100;\n"
andrewboyson 95:8c9dda8a0caf 17 "const ajaxUpdateMs_ = 10000;\n"
andrewboyson 95:8c9dda8a0caf 18 "\n"
andrewboyson 95:8c9dda8a0caf 19 "//Private utilities\n"
andrewboyson 95:8c9dda8a0caf 20 "function ajaxGetElementOrNull_(elementName) //Returns the element if it: exists; block is overidden; does not have focus\n"
andrewboyson 95:8c9dda8a0caf 21 "{\n"
andrewboyson 95:8c9dda8a0caf 22 " let elem = document.getElementById(elementName);\n"
andrewboyson 95:8c9dda8a0caf 23 " if (!elem) return null;\n"
andrewboyson 95:8c9dda8a0caf 24 " if (ajaxOverrideBlockUpdateOnFocus_) return elem;\n"
andrewboyson 95:8c9dda8a0caf 25 " if (elem !== document.activeElement) return elem;\n"
andrewboyson 95:8c9dda8a0caf 26 " return null;\n"
andrewboyson 95:8c9dda8a0caf 27 "}\n"
andrewboyson 95:8c9dda8a0caf 28 "function ajaxHexToBit_(text, iBit)\n"
andrewboyson 95:8c9dda8a0caf 29 "{\n"
andrewboyson 95:8c9dda8a0caf 30 " let value = parseInt(text, 16);\n"
andrewboyson 95:8c9dda8a0caf 31 " value >>= iBit;\n"
andrewboyson 95:8c9dda8a0caf 32 " return value & 1;\n"
andrewboyson 95:8c9dda8a0caf 33 "}\n"
andrewboyson 95:8c9dda8a0caf 34 "\n"
andrewboyson 95:8c9dda8a0caf 35 "//Private ajax functions\n"
andrewboyson 95:8c9dda8a0caf 36 "function ajaxHandleAjaxResponse_()\n"
andrewboyson 95:8c9dda8a0caf 37 "{\n"
andrewboyson 95:8c9dda8a0caf 38 " if (ajaxXhr_.readyState == 4 && ajaxXhr_.status == 200)\n"
andrewboyson 95:8c9dda8a0caf 39 " {\n"
andrewboyson 95:8c9dda8a0caf 40 " ajaxResponse_ = ajaxXhr_.responseText;\n"
andrewboyson 95:8c9dda8a0caf 41 " ajaxHeaders_ = ajaxXhr_.getAllResponseHeaders();\n"
andrewboyson 95:8c9dda8a0caf 42 " let elem;\n"
andrewboyson 95:8c9dda8a0caf 43 " elem = ajaxGetElementOrNull_('ajax-response'); if (elem) elem.textContent = ajaxResponse_;\n"
andrewboyson 95:8c9dda8a0caf 44 " elem = ajaxGetElementOrNull_('ajax-headers' ); if (elem) elem.textContent = ajaxHeaders_;\n"
andrewboyson 95:8c9dda8a0caf 45 " if (ajaxOnResponse_) ajaxOnResponse_();\n"
andrewboyson 95:8c9dda8a0caf 46 " ajaxOverrideBlockUpdateOnFocus_ = false; //Received response so reset override after display\n"
andrewboyson 95:8c9dda8a0caf 47 " }\n"
andrewboyson 95:8c9dda8a0caf 48 "}\n"
andrewboyson 95:8c9dda8a0caf 49 "function ajaxSendAjaxRequest_(request) //Used by this script and from HTML page\n"
andrewboyson 95:8c9dda8a0caf 50 "{\n"
andrewboyson 95:8c9dda8a0caf 51 " ajaxXhr_ = new XMLHttpRequest();\n"
andrewboyson 95:8c9dda8a0caf 52 " ajaxXhr_.onreadystatechange = ajaxHandleAjaxResponse_;\n"
andrewboyson 95:8c9dda8a0caf 53 " if (request) ajaxXhr_.open('GET', ajaxServer_ + '?' + request, true);\n"
andrewboyson 95:8c9dda8a0caf 54 " else ajaxXhr_.open('GET', ajaxServer_ , true);\n"
andrewboyson 95:8c9dda8a0caf 55 " ajaxXhr_.send();\n"
andrewboyson 95:8c9dda8a0caf 56 " ajaxMsCountAtAjaxSend_ = ajaxMs_;\n"
andrewboyson 95:8c9dda8a0caf 57 "}\n"
andrewboyson 95:8c9dda8a0caf 58 "function AjaxRequest(request) //From html\n"
andrewboyson 95:8c9dda8a0caf 59 "{\n"
andrewboyson 95:8c9dda8a0caf 60 " ajaxOverrideBlockUpdateOnFocus_ = true; //Request has come from an update\n"
andrewboyson 95:8c9dda8a0caf 61 " ajaxSendAjaxRequest_(request);\n"
andrewboyson 95:8c9dda8a0caf 62 "}\n"
andrewboyson 95:8c9dda8a0caf 63 "\n"
andrewboyson 95:8c9dda8a0caf 64 "//Private functions\n"
andrewboyson 95:8c9dda8a0caf 65 "function ajaxTick_() //Called about every 100ms\n"
andrewboyson 95:8c9dda8a0caf 66 "{\n"
andrewboyson 95:8c9dda8a0caf 67 " ajaxMs_ += ajaxTickMs_; //Don't use Date.now() as we don't know when the PC's clock will be updated around a leap second\n"
andrewboyson 95:8c9dda8a0caf 68 " if (ajaxMs_ >= ajaxMsCountAtAjaxSend_ + ajaxUpdateMs_) ajaxSendAjaxRequest_('');\n"
andrewboyson 95:8c9dda8a0caf 69 " if (ajaxOnTick_) ajaxOnTick_();\n"
andrewboyson 95:8c9dda8a0caf 70 "}\n"
andrewboyson 95:8c9dda8a0caf 71 "function ajaxInit_()\n"
andrewboyson 95:8c9dda8a0caf 72 "{\n"
andrewboyson 95:8c9dda8a0caf 73 " setInterval(ajaxTick_, ajaxTickMs_);\n"
andrewboyson 95:8c9dda8a0caf 74 " ajaxSendAjaxRequest_('');\n"
andrewboyson 95:8c9dda8a0caf 75 "}\n"
andrewboyson 95:8c9dda8a0caf 76 "\n"
andrewboyson 95:8c9dda8a0caf 77 "//Exposed public\n"
andrewboyson 95:8c9dda8a0caf 78 "class Ajax\n"
andrewboyson 95:8c9dda8a0caf 79 "{\n"
andrewboyson 95:8c9dda8a0caf 80 " static get ms () { return ajaxMs_ ; }\n"
andrewboyson 95:8c9dda8a0caf 81 " static get response () { return ajaxResponse_ ; }\n"
andrewboyson 95:8c9dda8a0caf 82 " static get headers () { return ajaxHeaders_ ; }\n"
andrewboyson 95:8c9dda8a0caf 83 " static set tickMs (v) { ajaxTickMs_ = v ; }\n"
andrewboyson 95:8c9dda8a0caf 84 " static set updateMs (v) { ajaxUpdateMs_ = v ; }\n"
andrewboyson 95:8c9dda8a0caf 85 " static set server (v) { ajaxServer_ = v ; }\n"
andrewboyson 95:8c9dda8a0caf 86 " static set onResponse(v) { ajaxOnResponse_ = v ; }\n"
andrewboyson 95:8c9dda8a0caf 87 " static set onTick (v) { ajaxOnTick_ = v ; }\n"
andrewboyson 95:8c9dda8a0caf 88 "\n"
andrewboyson 95:8c9dda8a0caf 89 " static getElementOrNull(elementName) { return ajaxGetElementOrNull_(elementName) ; }\n"
andrewboyson 95:8c9dda8a0caf 90 " static hexToBit (text, iBit ) { return ajaxHexToBit_ (text, iBit ) ; }\n"
andrewboyson 95:8c9dda8a0caf 91 " \n"
andrewboyson 95:8c9dda8a0caf 92 " static init()\n"
andrewboyson 95:8c9dda8a0caf 93 " {\n"
andrewboyson 95:8c9dda8a0caf 94 " if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', ajaxInit_ ); // Loading hasn't finished yet\n"
andrewboyson 95:8c9dda8a0caf 95 " else ajaxInit_(); //`DOMContentLoaded` has already fired\n"
andrewboyson 95:8c9dda8a0caf 96 " }\n"
andrewboyson 95:8c9dda8a0caf 97 "}"