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:
Mon Dec 31 18:49:36 2018 +0000
Revision:
15:2cea2bbd5046
Parent:
14:c3c43c8faf0e
Child:
21:048b7dbdf0aa
Added information to the clock page

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 15:2cea2bbd5046 40 rtcIsSet = hexToBit(4, 0)
andrewboyson 15:2cea2bbd5046 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 14:c3c43c8faf0e 103 var now = new Date(msCount - msCountAtRtcSet + msRtc);
andrewboyson 14:c3c43c8faf0e 104 var y = now.getUTCFullYear();
andrewboyson 14:c3c43c8faf0e 105 var n = now.getUTCMonth () + 1;
andrewboyson 14:c3c43c8faf0e 106 var d = now.getUTCDate ();
andrewboyson 14:c3c43c8faf0e 107 var h = now.getUTCHours ();
andrewboyson 14:c3c43c8faf0e 108 var m = now.getUTCMinutes ();
andrewboyson 14:c3c43c8faf0e 109 var s = now.getUTCSeconds ();
andrewboyson 14:c3c43c8faf0e 110
andrewboyson 14:c3c43c8faf0e 111 //Check for leap
andrewboyson 14:c3c43c8faf0e 112 if (y == leapyear && n == leapmonth && d == 1 && m == 0 && s == 0)
andrewboyson 14:c3c43c8faf0e 113 {
andrewboyson 14:c3c43c8faf0e 114 leapEnable = false;
andrewboyson 14:c3c43c8faf0e 115 if (leapBackward) { msRtc += 1000; leaps -= 1; }
andrewboyson 14:c3c43c8faf0e 116 else { msRtc -= 1000; leaps += 1; }
andrewboyson 14:c3c43c8faf0e 117 }
andrewboyson 14:c3c43c8faf0e 118 }
andrewboyson 14:c3c43c8faf0e 119 function displayTime()
andrewboyson 14:c3c43c8faf0e 120 {
andrewboyson 14:c3c43c8faf0e 121 if (msRtc == 0) return; //Don't attempt to display an invalid time
andrewboyson 14:c3c43c8faf0e 122
andrewboyson 14:c3c43c8faf0e 123 //Get the calander date and time from the ms
andrewboyson 14:c3c43c8faf0e 124 var now = new Date(msCount - msCountAtRtcSet + msRtc);
andrewboyson 14:c3c43c8faf0e 125 var y = now.getUTCFullYear();
andrewboyson 14:c3c43c8faf0e 126 var n = now.getUTCMonth () + 1;
andrewboyson 14:c3c43c8faf0e 127 var d = now.getUTCDate ();
andrewboyson 14:c3c43c8faf0e 128 var w = now.getUTCDay (); // 0 == Sunday
andrewboyson 14:c3c43c8faf0e 129 var h = now.getUTCHours ();
andrewboyson 14:c3c43c8faf0e 130 var m = now.getUTCMinutes ();
andrewboyson 14:c3c43c8faf0e 131 var s = now.getUTCSeconds ();
andrewboyson 14:c3c43c8faf0e 132
andrewboyson 14:c3c43c8faf0e 133 //Format time
andrewboyson 14:c3c43c8faf0e 134 n = formatNumbers00(n);
andrewboyson 14:c3c43c8faf0e 135 d = formatNumbers00(d);
andrewboyson 14:c3c43c8faf0e 136 h = formatNumbers00(h);
andrewboyson 14:c3c43c8faf0e 137 m = formatNumbers00(m);
andrewboyson 14:c3c43c8faf0e 138 s = formatNumbers00(s);
andrewboyson 14:c3c43c8faf0e 139 w = formatDayOfWeek(w);
andrewboyson 14:c3c43c8faf0e 140
andrewboyson 14:c3c43c8faf0e 141 //Display time
andrewboyson 14:c3c43c8faf0e 142 var elem;
andrewboyson 14:c3c43c8faf0e 143
andrewboyson 14:c3c43c8faf0e 144 elem = document.getElementById('date-utc');
andrewboyson 14:c3c43c8faf0e 145 if (elem) elem.innerHTML = y + '-' + n + '-' + d + ' ' + w + ' ' + h + ':' + m + ':' + s + ' TAI-UTC=' + leaps;
andrewboyson 14:c3c43c8faf0e 146
andrewboyson 14:c3c43c8faf0e 147 elem = document.getElementById('date-pc');
andrewboyson 14:c3c43c8faf0e 148 //if (elem) elem.innerHTML = now.toString();
andrewboyson 14:c3c43c8faf0e 149 var options =
andrewboyson 14:c3c43c8faf0e 150 {
andrewboyson 14:c3c43c8faf0e 151 year: 'numeric',
andrewboyson 14:c3c43c8faf0e 152 month: 'short',
andrewboyson 14:c3c43c8faf0e 153 day: '2-digit',
andrewboyson 14:c3c43c8faf0e 154 weekday: 'short',
andrewboyson 14:c3c43c8faf0e 155 hour: '2-digit',
andrewboyson 14:c3c43c8faf0e 156 minute: '2-digit',
andrewboyson 14:c3c43c8faf0e 157 second: '2-digit',
andrewboyson 14:c3c43c8faf0e 158 timeZoneName: 'short'
andrewboyson 14:c3c43c8faf0e 159 };
andrewboyson 14:c3c43c8faf0e 160 if (elem) elem.innerHTML = now.toLocaleString(undefined, options);
andrewboyson 14:c3c43c8faf0e 161 }
andrewboyson 14:c3c43c8faf0e 162
andrewboyson 14:c3c43c8faf0e 163 var ajax;
andrewboyson 14:c3c43c8faf0e 164 var msCountAtAjaxSend = 0;
andrewboyson 14:c3c43c8faf0e 165 function AjaxRequest(request) //Used by this script and from HTML page
andrewboyson 14:c3c43c8faf0e 166 {
andrewboyson 14:c3c43c8faf0e 167 ajax=new XMLHttpRequest();
andrewboyson 14:c3c43c8faf0e 168 ajax.onreadystatechange=handleAjaxResponse;
andrewboyson 14:c3c43c8faf0e 169 if (request) ajax.open('GET', '/ajax-clock' + '?' + request, true);
andrewboyson 14:c3c43c8faf0e 170 else ajax.open('GET', '/ajax-clock' , true);
andrewboyson 14:c3c43c8faf0e 171 ajax.send();
andrewboyson 14:c3c43c8faf0e 172 }
andrewboyson 14:c3c43c8faf0e 173 function requestAjax() //Used in this script
andrewboyson 14:c3c43c8faf0e 174 {
andrewboyson 14:c3c43c8faf0e 175
andrewboyson 14:c3c43c8faf0e 176 AjaxRequest('');
andrewboyson 14:c3c43c8faf0e 177 msCountAtAjaxSend = msCount;
andrewboyson 14:c3c43c8faf0e 178 }
andrewboyson 14:c3c43c8faf0e 179
andrewboyson 14:c3c43c8faf0e 180 function counter()
andrewboyson 14:c3c43c8faf0e 181 {
andrewboyson 14:c3c43c8faf0e 182 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 183 adjustLeap();
andrewboyson 14:c3c43c8faf0e 184 displayTime();
andrewboyson 14:c3c43c8faf0e 185 if (msCount >= msCountAtRtcSet + AJAX_REFRESH_MS && //Wait until time to refresh
andrewboyson 14:c3c43c8faf0e 186 msCount >= msCountAtAjaxSend + AJAX_QUIET_MS) //Don't repeat during quiet period
andrewboyson 14:c3c43c8faf0e 187 {
andrewboyson 14:c3c43c8faf0e 188 requestAjax(); //RequestAjax will set msRtc and reset msCount
andrewboyson 14:c3c43c8faf0e 189 }
andrewboyson 14:c3c43c8faf0e 190 }
andrewboyson 14:c3c43c8faf0e 191
andrewboyson 14:c3c43c8faf0e 192 function handleAjaxResponse()
andrewboyson 14:c3c43c8faf0e 193 {
andrewboyson 14:c3c43c8faf0e 194 if (ajax.readyState==4 && ajax.status==200)
andrewboyson 14:c3c43c8faf0e 195 {
andrewboyson 14:c3c43c8faf0e 196 response = ajax.responseText;
andrewboyson 14:c3c43c8faf0e 197 headers = ajax.getAllResponseHeaders();
andrewboyson 14:c3c43c8faf0e 198 parseAjax();
andrewboyson 14:c3c43c8faf0e 199 displayGeneral();
andrewboyson 14:c3c43c8faf0e 200 }
andrewboyson 14:c3c43c8faf0e 201 }
andrewboyson 14:c3c43c8faf0e 202
andrewboyson 14:c3c43c8faf0e 203 function DisplayLeap() //Called by display leap button in HTML
andrewboyson 14:c3c43c8faf0e 204 {
andrewboyson 14:c3c43c8faf0e 205 leapEnable = true;
andrewboyson 14:c3c43c8faf0e 206 msRtc = Date.UTC(leapyear, leapmonth - 1, 1) - AJAX_REFRESH_MS / 2; //displays the refresh period around the latest leap second
andrewboyson 14:c3c43c8faf0e 207 msCountAtRtcSet = msCount;
andrewboyson 14:c3c43c8faf0e 208 }
andrewboyson 14:c3c43c8faf0e 209
andrewboyson 14:c3c43c8faf0e 210 function init()
andrewboyson 14:c3c43c8faf0e 211 {
andrewboyson 14:c3c43c8faf0e 212 setInterval(counter, TICK_MS);
andrewboyson 14:c3c43c8faf0e 213 requestAjax();
andrewboyson 14:c3c43c8faf0e 214 }
andrewboyson 14:c3c43c8faf0e 215 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init ); // Loading hasn't finished yet
andrewboyson 14:c3c43c8faf0e 216 else init(); //`DOMContentLoaded` has already fired