Added license text and bug from last commit
[CGIscriptor.git] / JavaScript / CGIscriptorSession.js
blob13c9098569761957537fa1b1f888bf81c0c529b1
1 /*
2  *  LICENSE
3  *  
4  *  This program is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU General Public License
6  *  as published by the Free Software Foundation; either version 2
7  *  of the License, or (at your option) any later version.
8  *  
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *  
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330,
17  *  Boston, MA  02111-1307, USA.
18  * 
19  *  Copyright 2012-2013 Rob van Son 
20  *  email: R.J.J.H.vanSon@gmail.com 
21  *  NKI-AVL Amsterdam
22  */
23 // Global variables, set by the server as CGI parameter values
24 var CGIscriptorSessionType="<SCRIPT TYPE="text/ssperl" CGI='$SESSIONTYPE=""'>
25         $SESSIONTYPE;</SCRIPT>";
26 var CGIscriptorChallengeTicket="<SCRIPT TYPE="text/ssperl" CGI='$CHALLENGETICKET=""'>
27         $CHALLENGETICKET;</SCRIPT>";
29 var CGIscriptorLoginticket="<SCRIPT TYPE='text/ssperl' CGI='$LOGINTICKET=""'>
30         $LOGINTICKET</SCRIPT>";
31 var CGIscriptorServerSalt="<SCRIPT TYPE='text/ssperl' CGI='$SERVERSALT=""'>
32         $SERVERSALT</SCRIPT>";
33 var CGIscriptorRandomSalt="<SCRIPT TYPE='text/ssperl' CGI='$RANDOMSALT=""'>
34         $RANDOMSALT</SCRIPT>";
36 // OnSubmit functions
37 function LoginSubmit () {
38         var success=check_username_password();
39         // Set the LOGINTICKET value in FORM
40         var formID = document.getElementById("LOGINTICKET");
41         if(formID) {
42                 formID.value = CGIscriptorLoginticket;
43         };
44         
45         SetSessionCookie();
46         HashPassword(CGIscriptorRandomSalt);
47         hidePasswords();
48         return success;
51 function ChangePasswordSubmit () {
52         if(! check_password_fields())return false;
53         // Set the LOGINTICKET value in FORM
54         var formID = document.getElementById("LOGINTICKET");
55         if(formID) {
56                 formID.value = CGIscriptorLoginticket;
57         };
58         
59         EncryptNewPassword("CGIUSERNAME");
60         HashPassword(CGIscriptorRandomSalt);
61         hidePasswords();
62         return true;
65 function CreateUserSubmit () {
66         if(! check_password_fields())return false;
67         // Set the LOGINTICKET value in FORM
68         var formID = document.getElementById("LOGINTICKET");
69         if(formID) {
70                 formID.value = CGIscriptorLoginticket;
71         };
72         
73         EncryptNewPassword("NEWUSERNAME");
74         HashPassword(CGIscriptorRandomSalt);
75         hidePasswords();
76         return true;
79 // Function definitions
80 function hex_sha1 (plaintext) {
81         var shaObj = new jsSHA(plaintext, "ASCII");
82         return shaObj.getHash("SHA-1", "HEX");
84 function hex_sha256 (plaintext) {
85         var shaObj = new jsSHA(plaintext, "ASCII");
86         return shaObj.getHash("SHA-256", "HEX");
88 function hex_sha512 (plaintext) {
89         var shaObj = new jsSHA(plaintext, "ASCII");
90         return shaObj.getHash("SHA-256", "HEX");
92 function chained_sha (plaintext) {
93         return hex_sha256( hex_sha256( hex_sha512(plaintext) ) );
96 function loadSessionData (SessionType, ChallengeTicket) {
97         if(SessionType == 'CHALLENGE') 
98                 setChallengeParameters(ChallengeTicket);
99         else if(SessionType == 'SESSION')
100                 setSessionParameters();
101         return SessionType;
104 function createCookie(name,value,days,path) {
105         if (days) {
106                 var date = new Date();
107                 date.setTime(date.getTime()+(days*24*60*60*1000));
108                 var expires = "; expires="+date.toGMTString();
109         }
110         else var expires = "";
111         var match = document.cookie.match('/('+name+'\=[^\;]*\);/');
112         if(match){
113                 while(match) {
114                         document.cookie = document.cookie.replace(match[1], name+"="+value);
115                         match = document.cookie.match('/('+name+'\=[^\;]*\);/');
116                 };
117         } else {
118                 document.cookie = name+"=-";
119                 document.cookie = name+"="+value+expires+"; path=/"+path;
120         };
124 function readCookie(name) {
125         var nameEQ = name + "=";
126         var ca = document.cookie.split(';');
127         for(var i=0;i < ca.length;i++) {
128                 var c = ca[i];
129                 while (c.charAt(0)==' ') c = c.substring(1,c.length);
130                 if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
131         }
132         return null;
135 function eraseCookie(name) {
136         createCookie(name,"",-1);
139 // Combine the PASSWORD with the site SERVERSALT and hash it
140 // Combine this Hash iwth the extra SERVERSALT, and hash them
141 function HashPassword(extsalt) {
142         var hash = HashSessionSeed(extsalt);
143         var password = document.getElementById('PASSWORD');
144         if(password){
145                 password.value = hash;
146         } else {
147                 alert("NO PASSWORD IN FORM");
148                 return 0;
149         };
150         return hash;
153 // REMEMBER: Set the session cookie BEFORE you hash the password!!!
154 function SetSessionCookie() {
155         var loginticket = CGIscriptorLoginticket;
156         var randomsalt = CGIscriptorRandomSalt;
157         var hash = HashSessionSeed(loginticket);
158         // Dom.storage.enabled must be set!
159         if (!sessionStorage || typeof(sessionStorage) == 'undefined' ) {
160                 alert('Your browser does not support HTML5 sessionStorage. Set Dom.storage.enabled or try upgrading.');
161                 return 0;
162         } 
163         else sessionStorage.setItem("CGIscriptorPRIVATE", hash);
164         
165         // Store a secret key, if one is given
166         SetSecretKey();
167         
168         return hash;
171 function SetSecretKey() {
172         var loginticket = CGIscriptorLoginticket;
173         var randomsalt = CGIscriptorRandomSalt;
174         var secretkey = ""; 
175         if (!sessionStorage || typeof(sessionStorage) == 'undefined' ) {
176                 alert('Your browser does not support HTML5 sessionStorage. Set Dom.storage.enabled or try upgrading.');
177                 return "";
178         } 
179         else if (loginticket && randomsalt) {
180                 secretkey = HashSessionSeed(loginticket+randomsalt);
181                 sessionStorage.setItem("CGIscriptorSECRET", secretkey);
182         };
183         
184         return secretkey;
187 // Hash(sessionseed+hash(password+username+salt.toLowerCase()))
188 function HashSessionSeed(sessionseed) {
189         var hash1 = "";
190         var hash2 = "";
191         var passwordvalue = document.getElementById('PASSWORD');
192         var saltvalue = CGIscriptorServerSalt;
193         var username = document.getElementById('CGIUSERNAME');
194         hash1 = hex_sha256(passwordvalue.value+username.value.toLowerCase()+saltvalue);
195         if(sessionseed != "")
196                 hash2 = hex_sha256(hash1+sessionseed);
197         else
198                 hash2 = hash1;
199         return hash2;
202 // Remember to hash the repeat too! Or else it will be send in the clear
203 function HashNewPassword(userid) {
204         var hash1 = "";
205         var newpassword = document.getElementById('NEWPASSWORD');
206         var newpasswordrep = document.getElementById('NEWPASSWORDREP');
207         var username = document.getElementById(userid);
208         if(newpassword.value == "" ) {
209                 newpassword.value = "";
210                 return 0;
211         };
212         if(newpasswordrep && (newpasswordrep.value == ""|| newpassword.value != newpasswordrep.value)) {
213                 newpassword.value = "";
214                 newpasswordrep.value = "";
215                 return 0;
216         };
217         var saltvalue = CGIscriptorServerSalt;
218         hash1 = hex_sha256(newpassword.value+username.value.toLowerCase()+saltvalue);
219         newpassword.value = hash1;
220         newpasswordrep.value = hash1;
221         return hash1;
224 function XOR_hex_strings(hex1, hex2) {
225         var resultHex = "";
226         var maxlength = Math.max(hex1.length, hex2.length);
228         for(var i=0; i < maxlength; ++i) {
229                 var h1 = hex1.charAt(i);
230                 if(! h1) h1='0';
231                 var h2 = hex2.charAt(i);
232                 if(! h2) h2 ='0';
233                 var d1 = parseInt(h1,16);
234                 var d2 = parseInt(h2,16);
235                 var resultD = d1^d2;
236                 resultHex = resultHex+resultD.toString(16);
237         };
238         return resultHex;
241 function EncryptNewPassword(userid) {
242         var newpassword = document.getElementById('NEWPASSWORD');
243         var newpasswordrep = document.getElementById('NEWPASSWORDREP');
244         var secretkey = SetSecretKey();
245         
246         // This hashes the newpassword field!
247         HashNewPassword(userid);
248         var encrypted = XOR_hex_strings(secretkey, newpassword.value);
249         newpassword.value = encrypted;
250         newpasswordrep.value = encrypted;
251         return encrypted;
254 function DecryptNewPassword(key, encrypted) {
255         decrypted = XOR_hex_strings(key, encrypted);
256         
257         return decrypted;
260 function add_cgiparam(elem, attr, param) {
261     var elems = document.getElementsByTagName(elem);
262     for (var i = 0; i < elems.length; i++)
263     {
264                 var n=elems[i][attr].indexOf("?");
265                 if(n<0)
266                         elems[i][attr] = elems[i][attr] + "?" + param;
267                 else
268                         elems[i][attr] = elems[i][attr] + "&" + param;
269     };
272 function setSessionParameters() {
273         var sessionset = readCookie("CGIscriptorSESSION");
274         if(!(sessionset &&sessionset.match(/[\S]/)))return false;
276         var sessionticket = "";
277         sessionticket = sessionStorage.getItem("CGIscriptorPRIVATE");
278         if(!sessionticket) return false;
279         createCookie("CGIscriptorSESSION",sessionticket, 0, "");
280         
281         // Without cookies, use this
282         // var sessionparm = document.getElementById('SESSIONTICKET');
283         // if(sessionparm) sessionparm.value = sessionticket;
284     // add_cgiparam('a', 'href', "SESSIONTICKET="+sessionticket);
285     // add_cgiparam('form', 'action', "SESSIONTICKET="+sessionticket);
286         return true;
288 function setChallengeParameters(sessionset) {
289         if(!(sessionset && sessionset.match(/[\S]/)))return false;
290         
291         var sessionticket = "";
292         var sessionkey = sessionStorage.getItem("CGIscriptorPRIVATE");
293         if(!sessionkey) return false;
294         sessionticket = hex_sha256(sessionkey+sessionset);
295         createCookie("CGIscriptorCHALLENGE",sessionticket, 0, "");
297         // Without cookies, use this
298         // var sessionparm = document.getElementById('CHALLENGETICKET');
299         // if(sessionparm) sessionparm.value = sessionticket;
300         
301         // add_cgiparam('a', 'href', "CHALLENGETICKET="+sessionticket);
302         // add_cgiparam('form', 'action', "CHALLENGETICKET="+sessionticket);
303         return true;
306 function clear_persistent_data () {
307         createCookie("CGIscriptorSESSION","", 0, "");
308         createCookie("CGIscriptorCHALLENGE","", 0, "");
309         sessionStorage.setItem("CGIscriptorPRIVATE", "");
310         return true;
313 function check_password_fields ( ) {
314         var newpassword = document.getElementById('NEWPASSWORD');
315         var newpasswordrep = document.getElementById('NEWPASSWORDREP');
316         if(newpassword.value == "" || newpasswordrep.value == "") {
317                 alert("No passwords");
318                 return false;
319         };
320         if(newpassword.value == newpasswordrep.value) {
321                 var submitbutton = document.getElementById('SUBMIT');
322                 submitbutton.style.color = "Black";
323                 return true;
324         };
325         alert("Passwords differ");
326         return false;
329 function check_username_password ( ) {
330         var username = document.getElementById('CGIUSERNAME');
331         var password = document.getElementById('PASSWORD');
332         if(username.value.match(/[a-zA-Z0-9]/) && password.value.match(/[a-zA-Z0-9]/))
333                 return true;
334         alert("Please enter a user name and password");
335         return false;
338 function revealPasswords () {
339         var inputs = document.getElementsByTagName("input");
340         for (i=(inputs.length-1); i>=0; i--) {
341                 var curr = inputs[i];
342                 if (curr.type.toLowerCase()=="password") {
343                         curr.type = "TEXT";
344                 };
345         };
346         
349 function hidePasswords () {
350         var inputs = document.getElementsByTagName("input");
351         for (i=(inputs.length-1); i>=0; i--) {
352                 var curr = inputs[i];
353                 if (curr.type.toLowerCase()=="text") {
354                         curr.type = "PASSWORD";
355                 };
356         };
357         
360 function togglePasswords (hide, show, value) {
361         if(value.match(hide)) {
362                 hidePasswords ();
363                 return value.replace(hide, show);
364         } else {
365                 revealPasswords ();
366                 return value.replace(show, hide);
367         };
370 // Get a loginticket, salt, and random salt from a hidden loginFrame
371 // For use in a local version of the Private/Login.html web page.
372 // UNFINISHED WORK only useful with IPADDRESS sessions
373 // Put the following line in your local version of the HTML page to activate
374 // Replace http://localhost:8080/Private/index.html with the correct URL of the login page
375 // <iFrame id="loginFrame" src="http://localhost:8080/Private/index.html" hidden>Login frame</iFrame>
377 function getLoginData(){
378         var frameID = document.getElementById("loginFrame");
379         var iFrameHeader;
380         if ( frameID.contentDocument ) 
381         { // FF
382           iFrameHeader = frameID.contentDocument.getElementsByTagName('head')[0];
383         }
384         else if ( frameID.contentWindow ) 
385         { // IE
386           iFrameHeader = frameID.contentWindow.document.getElementsByTagName('head')[0];
387         }
388         
389         // Login ticket
390         var myLoginexp = /CGIscriptorLoginticket="([a-f0-9]{64})"/;
391         var myLogin = iFrameHeader.innerHTML.match(myLoginexp);
392         CGIscriptorLoginticket = myLogin[1];
393         
394         // Server Salt
395         var mySaltexp = /CGIscriptorServerSalt="([a-f0-9]{64})"/;
396         var mySalt = iFrameHeader.innerHTML.match(mySaltexp);
397         CGIscriptorServerSalt = mySalt[1];
399         // Random Salt
400         var myRandomexp = /CGIscriptorRandomSalt="([a-f0-9]{64})"/;
401         var myRandom = iFrameHeader.innerHTML.match(myRandomexp);
402         CGIscriptorRandomSalt = myRandom[1];