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:
Sat Mar 23 12:26:49 2019 +0000
Revision:
77:4689596a2f3f
Parent:
46:1822fdbe6c0c
Child:
94:d7226b2c14b6
Changed from using float to using flex for creating left and right aligned lines.

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