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:
Wed Jan 09 18:22:56 2019 +0000
Revision:
22:f45bbb468439
Parent:
21:048b7dbdf0aa
Child:
23:f340b48d0538
Tidied link to leap seconds

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewboyson 14:c3c43c8faf0e 1 'use strict';
andrewboyson 14:c3c43c8faf0e 2
andrewboyson 14:c3c43c8faf0e 3 var response = '';
andrewboyson 14:c3c43c8faf0e 4 var headers = '';
andrewboyson 14:c3c43c8faf0e 5 var msRtc = 0; //nibbles 0 to 3: 16 bits
andrewboyson 14:c3c43c8faf0e 6 var msCountAtRtcSet = 0;
andrewboyson 14:c3c43c8faf0e 7 var msDiff = 0;
andrewboyson 15:2cea2bbd5046 8 var rtcIsSet = false; //nibble 4: bit 0
andrewboyson 15:2cea2bbd5046 9 var clockIsSet = false; //nibble 4: bit 1
andrewboyson 15:2cea2bbd5046 10 var sourceIsOk = false; //nibble 4: bit 2
andrewboyson 15:2cea2bbd5046 11 var rateIsLocked = false; //nibble 4: bit 3
andrewboyson 15:2cea2bbd5046 12 var timeIsLocked = false; //nibble 5: bit 0
andrewboyson 15:2cea2bbd5046 13 var leapEnable = false; //nibble 5: bit 1
andrewboyson 15:2cea2bbd5046 14 var leapBackward = false; //nibble 5: bit 2
andrewboyson 14:c3c43c8faf0e 15 var leapmonths1970 = 0; //nibbles 6 to 8: 12 bits
andrewboyson 14:c3c43c8faf0e 16 var leapmonth = 0;
andrewboyson 14:c3c43c8faf0e 17 var leapyear = 0;
andrewboyson 14:c3c43c8faf0e 18 var leaps = 0; //nibbles 9 to 12: 16 bits
andrewboyson 14:c3c43c8faf0e 19 var msCount = 0;
andrewboyson 14:c3c43c8faf0e 20
andrewboyson 14:c3c43c8faf0e 21 const TICK_MS = 100;
andrewboyson 14:c3c43c8faf0e 22 const AJAX_REFRESH_MS = 10000;
andrewboyson 14:c3c43c8faf0e 23 const AJAX_QUIET_MS = 3000;
andrewboyson 14:c3c43c8faf0e 24
andrewboyson 14:c3c43c8faf0e 25 function hexToBit(iChar, iBit)
andrewboyson 14:c3c43c8faf0e 26 {
andrewboyson 14:c3c43c8faf0e 27 var value = parseInt(response.charAt(iChar), 16);
andrewboyson 14:c3c43c8faf0e 28 value >>= iBit;
andrewboyson 14:c3c43c8faf0e 29 return value & 1;
andrewboyson 14:c3c43c8faf0e 30 }
andrewboyson 14:c3c43c8faf0e 31 function parseAjax()
andrewboyson 14:c3c43c8faf0e 32 {
andrewboyson 14:c3c43c8faf0e 33 var iDateStart = headers.indexOf('Date:');
andrewboyson 14:c3c43c8faf0e 34 var iDateEnd = headers.indexOf('\r', iDateStart);
andrewboyson 14:c3c43c8faf0e 35 var rtcDate = new Date(headers.slice(iDateStart + 5, iDateEnd));
andrewboyson 14:c3c43c8faf0e 36 msRtc = parseInt(response.substr(0, 4), 16);
andrewboyson 14:c3c43c8faf0e 37 msRtc += rtcDate.getTime();
andrewboyson 14:c3c43c8faf0e 38 msDiff = msRtc - Date.now();
andrewboyson 14:c3c43c8faf0e 39 msCountAtRtcSet = msCount;
andrewboyson 22:f45bbb468439 40 rtcIsSet = hexToBit(4, 0);
andrewboyson 22:f45bbb468439 41 clockIsSet = hexToBit(4, 1);
andrewboyson 15:2cea2bbd5046 42 sourceIsOk = hexToBit(4, 2);
andrewboyson 15:2cea2bbd5046 43 rateIsLocked = hexToBit(4, 3);
andrewboyson 15:2cea2bbd5046 44 timeIsLocked = hexToBit(5, 0);
andrewboyson 15:2cea2bbd5046 45 leapEnable = hexToBit(5, 1);
andrewboyson 15:2cea2bbd5046 46 leapBackward = hexToBit(5, 2);
andrewboyson 14:c3c43c8faf0e 47 leapmonths1970 = parseInt(response.substr(6, 3), 16);
andrewboyson 14:c3c43c8faf0e 48 leapmonth = leapmonths1970 % 12;
andrewboyson 14:c3c43c8faf0e 49 leapyear = (leapmonths1970 - leapmonth) / 12;
andrewboyson 14:c3c43c8faf0e 50 leapmonth += 1;
andrewboyson 14:c3c43c8faf0e 51 leapyear += 1970;
andrewboyson 14:c3c43c8faf0e 52 leaps = parseInt(response.substr(9, 4), 16);
andrewboyson 14:c3c43c8faf0e 53 }
andrewboyson 14:c3c43c8faf0e 54 function displayGeneral()
andrewboyson 14:c3c43c8faf0e 55 {
andrewboyson 14:c3c43c8faf0e 56 var elem;
andrewboyson 15:2cea2bbd5046 57 elem = document.getElementById('ajax-rtc-set' ); if (elem) elem.setAttribute('dir', rtcIsSet ? 'rtl' : 'ltr');
andrewboyson 15:2cea2bbd5046 58 elem = document.getElementById('ajax-clock-set' ); if (elem) elem.setAttribute('dir', clockIsSet ? 'rtl' : 'ltr');
andrewboyson 15:2cea2bbd5046 59 elem = document.getElementById('ajax-source-ok' ); if (elem) elem.setAttribute('dir', sourceIsOk ? 'rtl' : 'ltr');
andrewboyson 14:c3c43c8faf0e 60 elem = document.getElementById('ajax-rate-locked' ); if (elem) elem.setAttribute('dir', rateIsLocked ? 'rtl' : 'ltr');
andrewboyson 14:c3c43c8faf0e 61 elem = document.getElementById('ajax-time-locked' ); if (elem) elem.setAttribute('dir', timeIsLocked ? 'rtl' : 'ltr');
andrewboyson 14:c3c43c8faf0e 62
andrewboyson 14:c3c43c8faf0e 63 elem = document.getElementById('ajax-leap-enable' ); if (elem) elem.setAttribute('dir', leapEnable ? 'rtl' : 'ltr');
andrewboyson 14:c3c43c8faf0e 64 elem = document.getElementById('ajax-leap-backward'); if (elem) elem.setAttribute('dir', leapBackward ? 'rtl' : 'ltr');
andrewboyson 14:c3c43c8faf0e 65
andrewboyson 14:c3c43c8faf0e 66 elem = document.getElementById('ajax-leap-year' ); if (elem) elem.value = leapmonths1970 ? leapyear : '';
andrewboyson 14:c3c43c8faf0e 67 elem = document.getElementById('ajax-leap-month' ); if (elem) elem.value = leapmonths1970 ? leapmonth : '';
andrewboyson 14:c3c43c8faf0e 68
andrewboyson 14:c3c43c8faf0e 69 elem = document.getElementById('ajax-leap-count' ); if (elem) elem.value = leaps;
andrewboyson 14:c3c43c8faf0e 70
andrewboyson 14:c3c43c8faf0e 71 elem = document.getElementById('ajax-response' ); if (elem) elem.innerHTML = response;
andrewboyson 14:c3c43c8faf0e 72 elem = document.getElementById('ajax-headers' ); if (elem) elem.innerHTML = headers;
andrewboyson 14:c3c43c8faf0e 73
andrewboyson 14:c3c43c8faf0e 74 elem = document.getElementById('date-diff' ); if (elem) elem.innerHTML = msDiff;
andrewboyson 14:c3c43c8faf0e 75 }
andrewboyson 14:c3c43c8faf0e 76
andrewboyson 14:c3c43c8faf0e 77 function formatNumbers00(i)
andrewboyson 14:c3c43c8faf0e 78 {
andrewboyson 14:c3c43c8faf0e 79 if (i<10) i='0' + i;
andrewboyson 14:c3c43c8faf0e 80 return i;
andrewboyson 14:c3c43c8faf0e 81 }
andrewboyson 14:c3c43c8faf0e 82 function formatDayOfWeek(wday)
andrewboyson 14:c3c43c8faf0e 83 {
andrewboyson 14:c3c43c8faf0e 84 switch(wday)
andrewboyson 14:c3c43c8faf0e 85 {
andrewboyson 14:c3c43c8faf0e 86 case 0: return 'Sun';
andrewboyson 14:c3c43c8faf0e 87 case 1: return 'Mon';
andrewboyson 14:c3c43c8faf0e 88 case 2: return 'Tue';
andrewboyson 14:c3c43c8faf0e 89 case 3: return 'Wed';
andrewboyson 14:c3c43c8faf0e 90 case 4: return 'Thu';
andrewboyson 14:c3c43c8faf0e 91 case 5: return 'Fri';
andrewboyson 14:c3c43c8faf0e 92 case 6: return 'Sat';
andrewboyson 14:c3c43c8faf0e 93 default: return '---';
andrewboyson 14:c3c43c8faf0e 94 }
andrewboyson 14:c3c43c8faf0e 95 }
andrewboyson 14:c3c43c8faf0e 96 function adjustLeap()
andrewboyson 14:c3c43c8faf0e 97 {
andrewboyson 14:c3c43c8faf0e 98 if (msRtc == 0) return; //Don't attempt to adjust an invalid time
andrewboyson 14:c3c43c8faf0e 99
andrewboyson 14:c3c43c8faf0e 100 if (!leapEnable) return; // Adjustment disabled
andrewboyson 14:c3c43c8faf0e 101
andrewboyson 14:c3c43c8faf0e 102 //Get the calander date and time from the ms
andrewboyson 21:048b7dbdf0aa 103 var now = new Date(msCount - msCountAtRtcSet + msRtc);
andrewboyson 21:048b7dbdf0aa 104 var leapStart = new Date(leapyear, leapmonth - 1, 1, 0, 0, leapBackward ? -1: 0);
andrewboyson 21:048b7dbdf0aa 105
andrewboyson 22:f45bbb468439 106 if (now.getTime() < leapStart.getTime()) return; //Do nothing until reached the leap start
andrewboyson 14:c3c43c8faf0e 107
andrewboyson 21:048b7dbdf0aa 108 if (leapBackward) { msRtc += 1000; leaps -= 1; } //skip 59
andrewboyson 21:048b7dbdf0aa 109 else { msRtc -= 1000; leaps += 1; } //repeat 59
andrewboyson 21:048b7dbdf0aa 110
andrewboyson 21:048b7dbdf0aa 111 leapEnable = false;
andrewboyson 14:c3c43c8faf0e 112 }
andrewboyson 14:c3c43c8faf0e 113 function displayTime()
andrewboyson 14:c3c43c8faf0e 114 {
andrewboyson 14:c3c43c8faf0e 115 if (msRtc == 0) return; //Don't attempt to display an invalid time
andrewboyson 14:c3c43c8faf0e 116
andrewboyson 14:c3c43c8faf0e 117 //Get the calander date and time from the ms
andrewboyson 14:c3c43c8faf0e 118 var now = new Date(msCount - msCountAtRtcSet + msRtc);
andrewboyson 14:c3c43c8faf0e 119 var y = now.getUTCFullYear();
andrewboyson 14:c3c43c8faf0e 120 var n = now.getUTCMonth () + 1;
andrewboyson 14:c3c43c8faf0e 121 var d = now.getUTCDate ();
andrewboyson 14:c3c43c8faf0e 122 var w = now.getUTCDay (); // 0 == Sunday
andrewboyson 14:c3c43c8faf0e 123 var h = now.getUTCHours ();
andrewboyson 14:c3c43c8faf0e 124 var m = now.getUTCMinutes ();
andrewboyson 14:c3c43c8faf0e 125 var s = now.getUTCSeconds ();
andrewboyson 14:c3c43c8faf0e 126
andrewboyson 14:c3c43c8faf0e 127 //Format time
andrewboyson 14:c3c43c8faf0e 128 n = formatNumbers00(n);
andrewboyson 14:c3c43c8faf0e 129 d = formatNumbers00(d);
andrewboyson 14:c3c43c8faf0e 130 h = formatNumbers00(h);
andrewboyson 14:c3c43c8faf0e 131 m = formatNumbers00(m);
andrewboyson 14:c3c43c8faf0e 132 s = formatNumbers00(s);
andrewboyson 14:c3c43c8faf0e 133 w = formatDayOfWeek(w);
andrewboyson 14:c3c43c8faf0e 134
andrewboyson 14:c3c43c8faf0e 135 //Display time
andrewboyson 14:c3c43c8faf0e 136 var elem;
andrewboyson 14:c3c43c8faf0e 137
andrewboyson 14:c3c43c8faf0e 138 elem = document.getElementById('date-utc');
andrewboyson 14:c3c43c8faf0e 139 if (elem) elem.innerHTML = y + '-' + n + '-' + d + ' ' + w + ' ' + h + ':' + m + ':' + s + ' TAI-UTC=' + leaps;
andrewboyson 14:c3c43c8faf0e 140
andrewboyson 14:c3c43c8faf0e 141 elem = document.getElementById('date-pc');
andrewboyson 14:c3c43c8faf0e 142 //if (elem) elem.innerHTML = now.toString();
andrewboyson 14:c3c43c8faf0e 143 var options =
andrewboyson 14:c3c43c8faf0e 144 {
andrewboyson 14:c3c43c8faf0e 145 year: 'numeric',
andrewboyson 14:c3c43c8faf0e 146 month: 'short',
andrewboyson 14:c3c43c8faf0e 147 day: '2-digit',
andrewboyson 14:c3c43c8faf0e 148 weekday: 'short',
andrewboyson 14:c3c43c8faf0e 149 hour: '2-digit',
andrewboyson 14:c3c43c8faf0e 150 minute: '2-digit',
andrewboyson 14:c3c43c8faf0e 151 second: '2-digit',
andrewboyson 14:c3c43c8faf0e 152 timeZoneName: 'short'
andrewboyson 14:c3c43c8faf0e 153 };
andrewboyson 14:c3c43c8faf0e 154 if (elem) elem.innerHTML = now.toLocaleString(undefined, options);
andrewboyson 14:c3c43c8faf0e 155 }
andrewboyson 14:c3c43c8faf0e 156
andrewboyson 14:c3c43c8faf0e 157 var ajax;
andrewboyson 14:c3c43c8faf0e 158 var msCountAtAjaxSend = 0;
andrewboyson 14:c3c43c8faf0e 159 function AjaxRequest(request) //Used by this script and from HTML page
andrewboyson 14:c3c43c8faf0e 160 {
andrewboyson 14:c3c43c8faf0e 161 ajax=new XMLHttpRequest();
andrewboyson 14:c3c43c8faf0e 162 ajax.onreadystatechange=handleAjaxResponse;
andrewboyson 14:c3c43c8faf0e 163 if (request) ajax.open('GET', '/ajax-clock' + '?' + request, true);
andrewboyson 14:c3c43c8faf0e 164 else ajax.open('GET', '/ajax-clock' , true);
andrewboyson 14:c3c43c8faf0e 165 ajax.send();
andrewboyson 14:c3c43c8faf0e 166 }
andrewboyson 14:c3c43c8faf0e 167 function requestAjax() //Used in this script
andrewboyson 14:c3c43c8faf0e 168 {
andrewboyson 14:c3c43c8faf0e 169
andrewboyson 14:c3c43c8faf0e 170 AjaxRequest('');
andrewboyson 14:c3c43c8faf0e 171 msCountAtAjaxSend = msCount;
andrewboyson 14:c3c43c8faf0e 172 }
andrewboyson 14:c3c43c8faf0e 173
andrewboyson 14:c3c43c8faf0e 174 function counter()
andrewboyson 14:c3c43c8faf0e 175 {
andrewboyson 14:c3c43c8faf0e 176 msCount += TICK_MS; //Don't use Date.now() as we don't know when its clock will be updated around a leap second
andrewboyson 14:c3c43c8faf0e 177 adjustLeap();
andrewboyson 14:c3c43c8faf0e 178 displayTime();
andrewboyson 14:c3c43c8faf0e 179 if (msCount >= msCountAtRtcSet + AJAX_REFRESH_MS && //Wait until time to refresh
andrewboyson 14:c3c43c8faf0e 180 msCount >= msCountAtAjaxSend + AJAX_QUIET_MS) //Don't repeat during quiet period
andrewboyson 14:c3c43c8faf0e 181 {
andrewboyson 14:c3c43c8faf0e 182 requestAjax(); //RequestAjax will set msRtc and reset msCount
andrewboyson 14:c3c43c8faf0e 183 }
andrewboyson 14:c3c43c8faf0e 184 }
andrewboyson 14:c3c43c8faf0e 185
andrewboyson 14:c3c43c8faf0e 186 function handleAjaxResponse()
andrewboyson 14:c3c43c8faf0e 187 {
andrewboyson 14:c3c43c8faf0e 188 if (ajax.readyState==4 && ajax.status==200)
andrewboyson 14:c3c43c8faf0e 189 {
andrewboyson 14:c3c43c8faf0e 190 response = ajax.responseText;
andrewboyson 14:c3c43c8faf0e 191 headers = ajax.getAllResponseHeaders();
andrewboyson 14:c3c43c8faf0e 192 parseAjax();
andrewboyson 14:c3c43c8faf0e 193 displayGeneral();
andrewboyson 14:c3c43c8faf0e 194 }
andrewboyson 14:c3c43c8faf0e 195 }
andrewboyson 14:c3c43c8faf0e 196
andrewboyson 14:c3c43c8faf0e 197 function DisplayLeap() //Called by display leap button in HTML
andrewboyson 14:c3c43c8faf0e 198 {
andrewboyson 14:c3c43c8faf0e 199 leapEnable = true;
andrewboyson 14:c3c43c8faf0e 200 msRtc = Date.UTC(leapyear, leapmonth - 1, 1) - AJAX_REFRESH_MS / 2; //displays the refresh period around the latest leap second
andrewboyson 14:c3c43c8faf0e 201 msCountAtRtcSet = msCount;
andrewboyson 14:c3c43c8faf0e 202 }
andrewboyson 14:c3c43c8faf0e 203
andrewboyson 14:c3c43c8faf0e 204 function init()
andrewboyson 14:c3c43c8faf0e 205 {
andrewboyson 14:c3c43c8faf0e 206 setInterval(counter, TICK_MS);
andrewboyson 14:c3c43c8faf0e 207 requestAjax();
andrewboyson 14:c3c43c8faf0e 208 }
andrewboyson 14:c3c43c8faf0e 209 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init ); // Loading hasn't finished yet
andrewboyson 14:c3c43c8faf0e 210 else init(); //`DOMContentLoaded` has already fired