includes/clientside/static/login.js
changeset 1132 05fe0039d952
parent 1125 367768040a61
child 1136 8c664c96fccd
equal deleted inserted replaced
1131:adfbe522c95f 1132:05fe0039d952
   113   logindata = {};
   113   logindata = {};
   114   
   114   
   115   var title = ( user_level > USER_LEVEL_MEMBER ) ? $lang.get('user_login_ajax_prompt_title_elev') : $lang.get('user_login_ajax_prompt_title');
   115   var title = ( user_level > USER_LEVEL_MEMBER ) ? $lang.get('user_login_ajax_prompt_title_elev') : $lang.get('user_login_ajax_prompt_title');
   116   logindata.mb_object = new MessageBox(MB_OKCANCEL | MB_ICONLOCK, title, '');
   116   logindata.mb_object = new MessageBox(MB_OKCANCEL | MB_ICONLOCK, title, '');
   117   
   117   
       
   118   //
       
   119   // Cancel function: called when the "Cancel" button is clicked
       
   120   //
   118   logindata.mb_object.onclick['Cancel'] = function()
   121   logindata.mb_object.onclick['Cancel'] = function()
   119   {
   122   {
   120     // Hide the error message and captcha
   123     // Hide the error message, if any
   121     if ( document.getElementById('ajax_login_error_box') )
   124     $('ajax_login_error_box').remove();
   122     {
   125     // Hide the captcha, if any
   123       document.getElementById('ajax_login_error_box').parentNode.removeChild(document.getElementById('ajax_login_error_box'));
       
   124     }
       
   125     if ( document.getElementById('autoCaptcha') )
   126     if ( document.getElementById('autoCaptcha') )
   126     {
   127     {
   127       var to = fly_out_top(document.getElementById('autoCaptcha'), false, true);
   128       var to = fly_out_top(document.getElementById('autoCaptcha'), false, true);
   128       setTimeout(function() {
   129       setTimeout(function() {
   129           var d = document.getElementById('autoCaptcha');
   130           var d = document.getElementById('autoCaptcha');
   130           d.parentNode.removeChild(d);
   131           d.parentNode.removeChild(d);
   131         }, to);
   132         }, to);
   132     }
   133     }
   133     // Ask the server to clean our key
   134     // Ask the server to delete the encryption key we're using
   134     ajaxLoginPerformRequest({
   135     ajaxLoginPerformRequest({
   135         mode: 'clean_key',
   136         mode: 'clean_key',
   136         key_aes: logindata.key_aes,
   137         key_aes: logindata.key_aes,
   137         key_dh: logindata.key_dh
   138         key_dh: logindata.key_dh
   138     });
   139     });
   139   };
   140   };
   140   
   141   
       
   142   // Clicking OK will not cause the box to destroy, as this function returns true.
   141   logindata.mb_object.onbeforeclick['OK'] = function()
   143   logindata.mb_object.onbeforeclick['OK'] = function()
   142   {
   144   {
       
   145     // Just call the submitter and let it take care of everything
   143     ajaxLoginSubmitForm();
   146     ajaxLoginSubmitForm();
   144     return true;
   147     return true;
   145   }
   148   }
   146   
   149   
   147   // Fetch the inner content area
   150   // Fetch the inner content area
   158   // Request the key
   161   // Request the key
   159   ajaxLoginPerformRequest({ mode: 'getkey' });
   162   ajaxLoginPerformRequest({ mode: 'getkey' });
   160 }
   163 }
   161 
   164 
   162 /**
   165 /**
   163  * For compatibility only.
   166  * For compatibility only. Really, folks, it's ajaxLoginInit. If you need a
       
   167  * mnemonic device, use "two 'in's."
   164  */
   168  */
   165 
   169 
   166 window.ajaxLogonInit = function(call_on_finish, user_level)
   170 window.ajaxLogonInit = function(call_on_finish, user_level)
   167 {
   171 {
   168   return ajaxLoginInit(call_on_finish, user_level);
   172   return ajaxLoginInit(call_on_finish, user_level);
   169 }
   173 }
   170 
   174 
   171 /**
   175 /**
   172  * Sets the contents of the AJAX login window to the appropriate status message.
   176  * Sets the contents of the AJAX login window to the appropriate status message.
   173  * @param int One of AJAX_STATUS_*
   177  * @param int One of AJAX_STATUS_* constants
   174  */
   178  */
   175 
   179 
   176 window.ajaxLoginSetStatus = function(status)
   180 window.ajaxLoginSetStatus = function(status)
   177 {
   181 {
   178   if ( !logindata.mb_inner )
   182   if ( !logindata.mb_inner )
   363       
   367       
   364     case AJAX_STATUS_DESTROY:
   368     case AJAX_STATUS_DESTROY:
   365     case null:
   369     case null:
   366     case undefined:
   370     case undefined:
   367       logindata.showing_status = false;
   371       logindata.showing_status = false;
   368       return null;
   372       return;
   369       break;
   373       break;
   370   }
   374   }
   371   logindata.showing_status = true;
   375   logindata.showing_status = true;
   372 }
   376 }
   373 
   377 
   374 /**
   378 /**
   375  * Performs an AJAX logon request to the server and calls ajaxLoginProcessResponse() on the result.
   379  * Performs an AJAX logon request to the server and calls ajaxLoginProcessResponse() on the result.
   376  * @param object JSON packet to send
   380  * @param object JSON packet to send
       
   381  * @param function Optional function to call on the response as well.
   377  */
   382  */
   378 
   383 
   379 window.ajaxLoginPerformRequest = function(json, _hookfunc)
   384 window.ajaxLoginPerformRequest = function(json, _hookfunc)
   380 {
   385 {
   381   json = toJSONString(json);
   386   json = toJSONString(json);
   418     {
   423     {
   419       alert(response.error);
   424       alert(response.error);
   420     }
   425     }
   421     return false;
   426     return false;
   422   }
   427   }
       
   428   
   423   // Main mode switch
   429   // Main mode switch
   424   switch ( response.mode )
   430   switch ( response.mode )
   425   {
   431   {
   426     case 'build_box':
   432     case 'initial':
   427       // Rid ourselves of any loading windows
   433       // Rid ourselves of any loading windows
   428       ajaxLoginSetStatus(AJAX_STATUS_DESTROY);
   434       ajaxLoginSetStatus(AJAX_STATUS_DESTROY);
       
   435       // show any errors
       
   436       ajaxLoginShowFriendlyError(response);
   429       // The server wants us to build the login form, all the information is there
   437       // The server wants us to build the login form, all the information is there
   430       ajaxLoginBuildForm(response);
   438       ajaxLoginBuildForm(response);
   431       break;
   439       break;
   432     case 'login_success':
   440     case 'login_success':
   433       ajaxLoginSetStatus(AJAX_STATUS_SUCCESS);
   441       ajaxLoginSetStatus(AJAX_STATUS_SUCCESS);
   434       logindata.successfunc(response.key, response);
   442       logindata.successfunc(response.key, response);
   435       break;
   443       break;
   436     case 'login_failure':
   444     case 'reset_pass_used':
       
   445       // We logged in with a temporary password. Prompt the user to go to the temp password page and
       
   446       // reset their real password. If they click no, treat it as a login failure, as no session key
       
   447       // is actually issued when this type of login is performed.
       
   448       
       
   449       var conf = confirm($lang.get('user_login_ajax_msg_used_temp_pass'));
       
   450       if ( conf )
       
   451       {
       
   452         var url = makeUrlNS('Special', 'PasswordReset/stage2/' + response.user_id + '/' + response.temp_password);
       
   453         window.location = url;
       
   454         break;
       
   455       }
       
   456       // else, treat as a failure
       
   457     default:
   437       // Rid ourselves of any loading windows
   458       // Rid ourselves of any loading windows
   438       ajaxLoginSetStatus(AJAX_STATUS_DESTROY);
   459       ajaxLoginSetStatus(AJAX_STATUS_DESTROY);
   439       document.getElementById('messageBox').style.backgroundColor = '#C0C0C0';
   460       document.getElementById('messageBox').style.backgroundColor = '#C0C0C0';
   440       var mb_parent = document.getElementById('messageBox').parentNode;
   461       var mb_parent = document.getElementById('messageBox').parentNode;
   441       var do_respawn = ( typeof(response.respawn) == 'boolean' && response.respawn == true ) || typeof(response.respawn) != 'boolean';
   462       $(mb_parent).effect("shake", {}, 200);
   442       if ( do_respawn )
   463       setTimeout(function()
   443       {
   464         {
   444         $(mb_parent).effect("shake", {}, 200);
   465           document.getElementById('messageBox').style.backgroundColor = '#FFF';
   445         setTimeout(function()
   466           console.debug(response);
   446           {
   467           ajaxLoginShowFriendlyError(response);
   447             document.getElementById('messageBox').style.backgroundColor = '#FFF';
   468           ajaxLoginBuildForm(response);
   448             
   469         }, 2500);
   449             ajaxLoginBuildForm(response.respawn_info);
   470       
   450             ajaxLoginShowFriendlyError(response);
       
   451           }, 2500);
       
   452       }
       
   453       else
       
   454       {
       
   455         ajaxLoginShowFriendlyError(response);
       
   456       }
       
   457       break;
       
   458     case 'login_success_reset':
       
   459       var conf = confirm($lang.get('user_login_ajax_msg_used_temp_pass'));
       
   460       if ( conf )
       
   461       {
       
   462         var url = makeUrlNS('Special', 'PasswordReset/stage2/' + response.user_id + '/' + response.temp_password);
       
   463         window.location = url;
       
   464       }
       
   465       else
       
   466       {
       
   467         // treat as a failure
       
   468         ajaxLoginSetStatus(AJAX_STATUS_DESTROY);
       
   469         document.getElementById('messageBox').style.backgroundColor = '#C0C0C0';
       
   470         var mb_parent = document.getElementById('messageBox').parentNode;
       
   471         $(mb_parent).effect("shake", {}, 1500);
       
   472         setTimeout(function()
       
   473           {
       
   474             document.getElementById('messageBox').style.backgroundColor = '#FFF';
       
   475             ajaxLoginBuildForm(response.respawn_info);
       
   476             // don't show an error here, just silently respawn
       
   477           }, 2500);
       
   478       }
       
   479       break;
   471       break;
   480     case 'logout_success':
   472     case 'logout_success':
   481       if ( ENANO_SID )
   473       if ( ENANO_SID )
   482       {
   474       {
   483         ajaxLoginReplaceSIDInline(false, ENANO_SID, USER_LEVEL_MEMBER);
   475         ajaxLoginReplaceSIDInline(false, ENANO_SID, USER_LEVEL_MEMBER);
   510   _2.src = ( ajax_login_lockimg_path ) ? ajax_login_lockimg_path : scriptPath + '/images/lock48.png';
   502   _2.src = ( ajax_login_lockimg_path ) ? ajax_login_lockimg_path : scriptPath + '/images/lock48.png';
   511   
   503   
   512   var div = document.createElement('div');
   504   var div = document.createElement('div');
   513   div.id = 'ajax_login_form';
   505   div.id = 'ajax_login_form';
   514   
   506   
   515   var show_captcha = ( data.locked_out.locked_out && data.locked_out.lockout_policy == 'captcha' ) ? data.locked_out.captcha : false;
   507   var show_captcha = ( data.lockout.active && data.lockout.policy == 'captcha' ) ? data.lockout.captcha : false;
   516   
   508   
   517   // text displayed on re-auth
   509   // text displayed on re-auth
   518   if ( logindata.user_level > USER_LEVEL_MEMBER )
   510   if ( logindata.user_level > USER_LEVEL_MEMBER )
   519   {
   511   {
   520     div.innerHTML += $lang.get('user_login_ajax_prompt_body_elev') + '<br /><br />';
   512     div.innerHTML += $lang.get('user_login_ajax_prompt_body_elev') + '<br /><br />';
   584   }
   576   }
   585   td2_2.appendChild(f_password);
   577   td2_2.appendChild(f_password);
   586   tr2.appendChild(td2_2);
   578   tr2.appendChild(td2_2);
   587   table.appendChild(tr2);
   579   table.appendChild(tr2);
   588   
   580   
   589   eval(setHook('login_build_form'));
       
   590   
       
   591   // Field - captcha
   581   // Field - captcha
   592   if ( show_captcha )
   582   if ( show_captcha )
   593   {
   583   {
   594     var tr3 = document.createElement('tr');
   584     var tr3 = document.createElement('tr');
   595     var td3_1 = document.createElement('td');
   585     var td3_1 = document.createElement('td');
   615     td3_2.appendChild(f_captcha);
   605     td3_2.appendChild(f_captcha);
   616     tr3.appendChild(td3_2);
   606     tr3.appendChild(td3_2);
   617     table.appendChild(tr3);
   607     table.appendChild(tr3);
   618   }
   608   }
   619   
   609   
       
   610   // ok, this is a compatibility hack
       
   611   data.locked_out = { locked_out: data.lockout.active };
       
   612   
       
   613   // hook for the login form
       
   614   eval(setHook('login_build_form'));
       
   615   
       
   616   delete(data.locked_out);
       
   617   
   620   // Done building the main part of the form
   618   // Done building the main part of the form
   621   form.appendChild(table);
   619   form.appendChild(table);
   622   
   620   
   623   // Checkbox container
   621   // Checkbox container
   624   var boxen = document.createElement('div');
   622   var boxen = document.createElement('div');
   694     lbl_dh.style.fontSize = 'smaller';
   692     lbl_dh.style.fontSize = 'smaller';
   695     lbl_dh.style.textAlign = 'center';
   693     lbl_dh.style.textAlign = 'center';
   696     lbl_dh.innerHTML = $lang.get('user_login_ajax_check_dh_ie');
   694     lbl_dh.innerHTML = $lang.get('user_login_ajax_check_dh_ie');
   697     boxen.appendChild(lbl_dh);
   695     boxen.appendChild(lbl_dh);
   698   }
   696   }
   699   else if ( !data.allow_diffiehellman )
   697   else if ( !data.crypto.dh_enable )
   700   {
   698   {
   701     // create hidden control - server requested that DiffieHellman be disabled (usually means not supported)
   699     // create hidden control - server requested that DiffieHellman be disabled (usually means not supported)
   702     var check_dh = document.createElement('input');
   700     var check_dh = document.createElement('input');
   703     check_dh.type = 'hidden';
   701     check_dh.type = 'hidden';
   704     check_dh.id = 'ajax_login_field_dh';
   702     check_dh.id = 'ajax_login_field_dh';
   767         document.getElementById('ajax_login_field_username').focus();
   765         document.getElementById('ajax_login_field_username').focus();
   768     }, 750);        
   766     }, 750);        
   769   
   767   
   770   // Post operations: show captcha window
   768   // Post operations: show captcha window
   771   if ( show_captcha )
   769   if ( show_captcha )
       
   770   {
   772     ajaxShowCaptcha(show_captcha);
   771     ajaxShowCaptcha(show_captcha);
       
   772   }
   773   
   773   
   774   // Post operations: stash encryption keys and All That Jazz(TM)
   774   // Post operations: stash encryption keys and All That Jazz(TM)
   775   logindata.key_aes = data.aes_key;
   775   logindata.key_aes = data.crypto_aes_key;
   776   logindata.key_dh = data.dh_public_key;
   776   logindata.key_dh = data.crypto.dh_public_key;
   777   logindata.captcha_hash = show_captcha;
   777   logindata.captcha_hash = show_captcha;
   778   logindata.loggedin_username = data.username
   778   logindata.loggedin_username = data.username;
   779   
   779   
   780   // Are we locked out? If so simulate an error and disable the controls
   780   // If policy is lockout, also disable controls
   781   if ( data.lockout_info.lockout_policy == 'lockout' && data.locked_out.locked_out )
   781   if ( data.lockout.policy == 'lockout' && data.lockout.active )
   782   {
   782   {
   783     f_username.setAttribute('disabled', 'disabled');
   783     f_username.setAttribute('disabled', 'disabled');
   784     f_password.setAttribute('disabled', 'disabled');
   784     f_password.setAttribute('disabled', 'disabled');
   785     var fake_packet = {
       
   786       error_code: 'locked_out',
       
   787       respawn_info: data
       
   788     };
       
   789     ajaxLoginShowFriendlyError(fake_packet);
       
   790   }
   785   }
   791 }
   786 }
   792 
   787 
   793 window.ajaxLoginSubmitForm = function(real, username, password, captcha, remember)
   788 window.ajaxLoginSubmitForm = function(real, username, password, captcha, remember)
   794 {
   789 {
   976   ajaxLoginPerformRequest(json_packet);
   971   ajaxLoginPerformRequest(json_packet);
   977 }
   972 }
   978 
   973 
   979 window.ajaxLoginShowFriendlyError = function(response)
   974 window.ajaxLoginShowFriendlyError = function(response)
   980 {
   975 {
   981   if ( !response.respawn_info )
       
   982     return false;
       
   983   if ( !response.error_code )
       
   984     return false;
       
   985   var text = ajaxLoginGetErrorText(response);
   976   var text = ajaxLoginGetErrorText(response);
       
   977   if ( text == false )
       
   978     return true;
       
   979     
   986   if ( document.getElementById('ajax_login_error_box') )
   980   if ( document.getElementById('ajax_login_error_box') )
   987   {
   981   {
   988     // console.info('Reusing existing error-box');
   982     // console.info('Reusing existing error-box');
   989     document.getElementById('ajax_login_error_box').innerHTML = text;
   983     document.getElementById('ajax_login_error_box').innerHTML = text;
   990     return true;
   984     return true;
  1019   body.appendChild(errbox);
  1013   body.appendChild(errbox);
  1020 }
  1014 }
  1021 
  1015 
  1022 window.ajaxLoginGetErrorText = function(response)
  1016 window.ajaxLoginGetErrorText = function(response)
  1023 {
  1017 {
  1024   if ( !response.error_code.match(/^[a-z0-9]+_[a-z0-9_]+$/) )
  1018   if ( response.lockout )
  1025   {
  1019   {
  1026     return response.error_code;
  1020     // set this pluralality thing
  1027   }
  1021     response.lockout.plural = response.lockout.time_rem == 1 ? '' : $lang.get('meta_plural');
  1028   switch ( response.error_code )
  1022   }
  1029   {
  1023   
  1030     default:
  1024   if ( response.mode == 'initial' )
  1031       eval(setHook('ajax_login_process_error'));
  1025   {
  1032       if ( !ls )
  1026     // Just showing the box for the first time. If there's an error now, it's based on a preexisting lockout.
  1033       {
  1027     if ( response.lockout.active )
  1034         var ls = $lang.get('user_err_' + response.error_code);
  1028     {
  1035         if ( ls == 'user_err_' + response.error_code )
  1029       return $lang.get('user_err_locked_out_initial_' + response.lockout.policy, response.lockout);
  1036           // Adding response here allows language strings to utilize additional information passed from the error packet
  1030     }
  1037           ls = $lang.get(response.error_code, response);
  1031     return false;
  1038       }
  1032   }
  1039       
  1033   else
  1040       return ls;
  1034   {
  1041       break;
  1035     // An attempt was made.
  1042     case 'locked_out':
  1036     switch(response.mode)
  1043       if ( response.respawn_info.lockout_info.lockout_policy == 'lockout' )
  1037     {
  1044       {
  1038       case 'login_failure':
  1045         return $lang.get('user_err_locked_out', { 
  1039         // Generic login user error.
  1046                   lockout_threshold: response.respawn_info.lockout_info.lockout_threshold,
  1040         var error = '', x;
  1047                   lockout_duration: response.respawn_info.lockout_info.lockout_duration,
  1041         if ( (x = $lang.get(response.error)) != response.error )
  1048                   time_rem: response.respawn_info.lockout_info.time_rem,
  1042           error = x;
  1049                   plural: ( response.respawn_info.lockout_info.time_rem == 1 ) ? '' : $lang.get('meta_plural'),
  1043         else
  1050                   captcha_blurb: ''
  1044           error = $lang.get('user_err_' + response.error);
  1051                 });
  1045         if ( response.lockout.active && response.lockout.policy == 'lockout' )
       
  1046         {
       
  1047           // Lockout enforcement was just activated.
       
  1048           return $lang.get('user_err_locked_out_initial_' + response.lockout.policy, response.lockout);
       
  1049         }
       
  1050         else if ( response.lockout.policy != 'disable' && !response.lockout.active && response.lockout.fails > 0 )
       
  1051         {
       
  1052           // Lockout is in a warning state.
       
  1053           error += ' ' + $lang.get('user_err_invalid_credentials_' + response.lockout.policy, response.lockout);
       
  1054         }
       
  1055         return error;
  1052         break;
  1056         break;
  1053       }
  1057       case 'api_error':
  1054     case 'invalid_credentials':
  1058         // Error in the API.
  1055       var base = $lang.get('user_err_invalid_credentials');
  1059         return $lang.get('user_err_login_generic_title') + ': ' + $lang.get('user_' + response.error.toLowerCase());
  1056       if ( response.respawn_info.locked_out.locked_out )
  1060         break;
  1057       {
  1061     }
  1058         base += ' ';
  1062   }
  1059         var captcha_blurb = '';
  1063   
  1060         switch(response.respawn_info.lockout_info.lockout_policy)
  1064   return typeof(response.error) == 'string' ? response.error : false;
  1061         {
       
  1062           case 'captcha':
       
  1063             captcha_blurb = $lang.get('user_err_locked_out_captcha_blurb');
       
  1064             break;
       
  1065           case 'lockout':
       
  1066             break;
       
  1067           default:
       
  1068             base += 'WTF? Shouldn\'t be locked out with lockout policy set to disable. ';
       
  1069             break;
       
  1070         }
       
  1071         base += $lang.get('user_err_locked_out', { 
       
  1072                   captcha_blurb: captcha_blurb,
       
  1073                   lockout_threshold: response.respawn_info.lockout_info.lockout_threshold,
       
  1074                   lockout_duration: response.respawn_info.lockout_info.lockout_duration,
       
  1075                   time_rem: response.respawn_info.lockout_info.time_rem,
       
  1076                   plural: ( response.respawn_info.lockout_info.time_rem == 1 ) ? '' : $lang.get('meta_plural')
       
  1077                 });
       
  1078       }
       
  1079       else if ( response.respawn_info.lockout_info.lockout_policy == 'lockout' || response.respawn_info.lockout_info.lockout_policy == 'captcha' )
       
  1080       {
       
  1081         // if we have a lockout policy of captcha or lockout, then warn the user
       
  1082         switch ( response.respawn_info.lockout_info.lockout_policy )
       
  1083         {
       
  1084           case 'captcha':
       
  1085             base += $lang.get('user_err_invalid_credentials_lockout_captcha', { 
       
  1086                 fails: response.respawn_info.lockout_info.lockout_fails,
       
  1087                 lockout_threshold: response.respawn_info.lockout_info.lockout_threshold,
       
  1088                 lockout_duration: response.respawn_info.lockout_info.lockout_duration
       
  1089               });
       
  1090             break;
       
  1091           case 'lockout':
       
  1092             base += $lang.get('user_err_invalid_credentials_lockout', { 
       
  1093                 fails: response.respawn_info.lockout_info.lockout_fails,
       
  1094                 lockout_threshold: response.respawn_info.lockout_info.lockout_threshold,
       
  1095                 lockout_duration: response.respawn_info.lockout_info.lockout_duration
       
  1096               });
       
  1097             break;
       
  1098         }
       
  1099       }
       
  1100       return base;
       
  1101       break;
       
  1102   }
       
  1103 }
  1065 }
  1104 
  1066 
  1105 window.ajaxShowCaptcha = function(code)
  1067 window.ajaxShowCaptcha = function(code)
  1106 {
  1068 {
  1107   var mydiv = document.createElement('div');
  1069   var mydiv = document.createElement('div');
  1300   var targetpage = adminpage;
  1262   var targetpage = adminpage;
  1301   if ( !level )
  1263   if ( !level )
  1302   {
  1264   {
  1303     level = USER_LEVEL_ADMIN;
  1265     level = USER_LEVEL_ADMIN;
  1304   }
  1266   }
       
  1267   
  1305   ajaxLogonInit(function(k, response)
  1268   ajaxLogonInit(function(k, response)
  1306     {
  1269     {
  1307       ajaxLoginReplaceSIDInline(k, old_sid, level);
  1270       ajaxLoginReplaceSIDInline(k, old_sid, level);
  1308       window.user_id = response.user_id;
  1271       window.user_id = response.user_id;
  1309       window.user_level = response.user_level;
  1272       window.user_level = response.user_level;