436
+ − 1
/*
+ − 2
* AJAX-based intelligent login interface
+ − 3
*/
+ − 4
+ − 5
/*
+ − 6
* FRONTEND
+ − 7
*/
+ − 8
+ − 9
/**
+ − 10
* Performs a logon as a regular member.
+ − 11
*/
+ − 12
+ − 13
function ajaxLogonToMember()
+ − 14
{
+ − 15
// IE <6 pseudo-compatibility
+ − 16
if ( KILL_SWITCH )
+ − 17
return true;
+ − 18
if ( auth_level >= USER_LEVEL_MEMBER )
+ − 19
return true;
+ − 20
ajaxLoginInit(function(k)
+ − 21
{
+ − 22
window.location.reload();
+ − 23
}, USER_LEVEL_MEMBER);
+ − 24
}
+ − 25
+ − 26
/**
+ − 27
* Authenticates to the highest level the current user is allowed to go to.
+ − 28
*/
+ − 29
+ − 30
function ajaxLogonToElev()
+ − 31
{
+ − 32
if ( auth_level == user_level )
+ − 33
return true;
+ − 34
+ − 35
ajaxLoginInit(function(k)
+ − 36
{
+ − 37
ENANO_SID = k;
+ − 38
var url = String(' ' + window.location).substr(1);
+ − 39
url = append_sid(url);
+ − 40
window.location = url;
+ − 41
}, user_level);
+ − 42
}
+ − 43
+ − 44
/*
+ − 45
* BACKEND
+ − 46
*/
+ − 47
+ − 48
/**
+ − 49
* Holding object for various AJAX authentication information.
+ − 50
* @var object
+ − 51
*/
+ − 52
+ − 53
var logindata = {};
+ − 54
+ − 55
/**
+ − 56
* Path to the image used to indicate loading progress
+ − 57
* @var string
+ − 58
*/
+ − 59
+ − 60
if ( !ajax_login_loadimg_path )
+ − 61
var ajax_login_loadimg_path = false;
+ − 62
+ − 63
if ( !ajax_login_successimg_path )
+ − 64
var ajax_login_successimg_path = false;
+ − 65
+ − 66
/**
+ − 67
* Status variables
+ − 68
* @var int
+ − 69
*/
+ − 70
+ − 71
var AJAX_STATUS_LOADING_KEY = 1;
+ − 72
var AJAX_STATUS_GENERATING_KEY = 2;
+ − 73
var AJAX_STATUS_LOGGING_IN = 3;
+ − 74
var AJAX_STATUS_SUCCESS = 4;
+ − 75
var AJAX_STATUS_DESTROY = 65535;
+ − 76
+ − 77
/**
+ − 78
* State constants
+ − 79
* @var int
+ − 80
*/
+ − 81
+ − 82
var AJAX_STATE_EARLY_INIT = 1;
+ − 83
var AJAX_STATE_LOADING_KEY = 2;
+ − 84
+ − 85
/**
+ − 86
* Performs the AJAX request to get an encryption key and from there spawns the login form.
+ − 87
* @param function The function that will be called once authentication completes successfully.
+ − 88
* @param int The security level to authenticate at - see http://docs.enanocms.org/Help:Appendix_B
+ − 89
*/
+ − 90
+ − 91
function ajaxLoginInit(call_on_finish, user_level)
+ − 92
{
+ − 93
logindata = {};
+ − 94
+ − 95
var title = ( user_level > USER_LEVEL_MEMBER ) ? $lang.get('user_login_ajax_prompt_title_elev') : $lang.get('user_login_ajax_prompt_title');
+ − 96
logindata.mb_object = new messagebox(MB_OKCANCEL | MB_ICONLOCK, title, '');
+ − 97
+ − 98
logindata.mb_object.onclick['Cancel'] = function()
+ − 99
{
+ − 100
// Hide the error message and captcha
+ − 101
if ( document.getElementById('ajax_login_error_box') )
+ − 102
{
+ − 103
document.getElementById('ajax_login_error_box').parentNode.removeChild(document.getElementById('ajax_login_error_box'));
+ − 104
}
+ − 105
if ( document.getElementById('autoCaptcha') )
+ − 106
{
+ − 107
var to = fly_out_top(document.getElementById('autoCaptcha'), false, true);
+ − 108
setTimeout(function() {
+ − 109
var d = document.getElementById('autoCaptcha');
+ − 110
d.parentNode.removeChild(d);
+ − 111
}, to);
+ − 112
}
471
7906fb190fc1
Implemented all security features on theme disabling and ACLs; added clean_key mode to login API to clean unused encryption keys
Dan
diff
changeset
+ − 113
// Ask the server to clean our key
7906fb190fc1
Implemented all security features on theme disabling and ACLs; added clean_key mode to login API to clean unused encryption keys
Dan
diff
changeset
+ − 114
ajaxLoginPerformRequest({
7906fb190fc1
Implemented all security features on theme disabling and ACLs; added clean_key mode to login API to clean unused encryption keys
Dan
diff
changeset
+ − 115
mode: 'clean_key',
7906fb190fc1
Implemented all security features on theme disabling and ACLs; added clean_key mode to login API to clean unused encryption keys
Dan
diff
changeset
+ − 116
key_aes: logindata.key_aes,
7906fb190fc1
Implemented all security features on theme disabling and ACLs; added clean_key mode to login API to clean unused encryption keys
Dan
diff
changeset
+ − 117
key_dh: logindata.key_dh
7906fb190fc1
Implemented all security features on theme disabling and ACLs; added clean_key mode to login API to clean unused encryption keys
Dan
diff
changeset
+ − 118
});
436
+ − 119
};
+ − 120
+ − 121
logindata.mb_object.onbeforeclick['OK'] = function()
+ − 122
{
+ − 123
ajaxLoginSubmitForm();
+ − 124
return true;
+ − 125
}
+ − 126
+ − 127
// Fetch the inner content area
+ − 128
logindata.mb_inner = document.getElementById('messageBox').getElementsByTagName('div')[0];
+ − 129
+ − 130
// Initialize state
+ − 131
logindata.showing_status = false;
+ − 132
logindata.user_level = user_level;
+ − 133
logindata.successfunc = call_on_finish;
+ − 134
+ − 135
// Build the "loading" window
+ − 136
ajaxLoginSetStatus(AJAX_STATUS_LOADING_KEY);
+ − 137
+ − 138
// Request the key
+ − 139
ajaxLoginPerformRequest({ mode: 'getkey' });
+ − 140
}
+ − 141
+ − 142
/**
+ − 143
* Sets the contents of the AJAX login window to the appropriate status message.
+ − 144
* @param int One of AJAX_STATUS_*
+ − 145
*/
+ − 146
+ − 147
function ajaxLoginSetStatus(status)
+ − 148
{
+ − 149
if ( !logindata.mb_inner )
+ − 150
return false;
+ − 151
if ( logindata.showing_status )
+ − 152
{
+ − 153
var div = document.getElementById('ajax_login_status');
+ − 154
if ( div )
+ − 155
logindata.mb_inner.removeChild(div);
+ − 156
}
+ − 157
switch(status)
+ − 158
{
+ − 159
case AJAX_STATUS_LOADING_KEY:
+ − 160
+ − 161
// Create the status div
+ − 162
var div = document.createElement('div');
+ − 163
div.id = 'ajax_login_status';
+ − 164
div.style.marginTop = '10px';
+ − 165
div.style.textAlign = 'center';
+ − 166
+ − 167
// The circly ball ajaxy image + status message
+ − 168
var status_msg = $lang.get('user_login_ajax_fetching_key');
+ − 169
+ − 170
// Insert the status message
+ − 171
div.appendChild(document.createTextNode(status_msg));
+ − 172
+ − 173
// Append a br or two to space things properly
+ − 174
div.appendChild(document.createElement('br'));
+ − 175
div.appendChild(document.createElement('br'));
+ − 176
+ − 177
var img = document.createElement('img');
+ − 178
img.src = ( ajax_login_loadimg_path ) ? ajax_login_loadimg_path : scriptPath + '/images/loading-big.gif';
+ − 179
div.appendChild(img);
+ − 180
+ − 181
// Another coupla brs
+ − 182
div.appendChild(document.createElement('br'));
+ − 183
div.appendChild(document.createElement('br'));
+ − 184
+ − 185
// The link to the full login form
+ − 186
var small = document.createElement('small');
+ − 187
small.innerHTML = $lang.get('user_login_ajax_link_fullform', { link_full_form: makeUrlNS('Special', 'Login/' + title) });
+ − 188
div.appendChild(small);
+ − 189
+ − 190
// Insert the entire message into the login window
+ − 191
logindata.mb_inner.innerHTML = '';
+ − 192
logindata.mb_inner.appendChild(div);
+ − 193
+ − 194
break;
+ − 195
case AJAX_STATUS_GENERATING_KEY:
+ − 196
+ − 197
// Create the status div
+ − 198
var div = document.createElement('div');
+ − 199
div.id = 'ajax_login_status';
+ − 200
div.style.marginTop = '10px';
+ − 201
div.style.textAlign = 'center';
+ − 202
+ − 203
// The circly ball ajaxy image + status message
+ − 204
var status_msg = $lang.get('user_login_ajax_generating_key');
+ − 205
+ − 206
// Insert the status message
+ − 207
div.appendChild(document.createTextNode(status_msg));
+ − 208
+ − 209
// Append a br or two to space things properly
+ − 210
div.appendChild(document.createElement('br'));
+ − 211
div.appendChild(document.createElement('br'));
+ − 212
+ − 213
var img = document.createElement('img');
+ − 214
img.src = ( ajax_login_loadimg_path ) ? ajax_login_loadimg_path : scriptPath + '/images/loading-big.gif';
+ − 215
div.appendChild(img);
+ − 216
+ − 217
// Another coupla brs
+ − 218
div.appendChild(document.createElement('br'));
+ − 219
div.appendChild(document.createElement('br'));
+ − 220
+ − 221
// The link to the full login form
+ − 222
var small = document.createElement('small');
+ − 223
small.innerHTML = $lang.get('user_login_ajax_link_fullform_dh', { link_full_form: makeUrlNS('Special', 'Login/' + title) });
+ − 224
div.appendChild(small);
+ − 225
+ − 226
// Insert the entire message into the login window
+ − 227
logindata.mb_inner.innerHTML = '';
+ − 228
logindata.mb_inner.appendChild(div);
+ − 229
+ − 230
break;
+ − 231
case AJAX_STATUS_LOGGING_IN:
+ − 232
+ − 233
// Create the status div
+ − 234
var div = document.createElement('div');
+ − 235
div.id = 'ajax_login_status';
+ − 236
div.style.marginTop = '10px';
+ − 237
div.style.textAlign = 'center';
+ − 238
+ − 239
// The circly ball ajaxy image + status message
+ − 240
var status_msg = $lang.get('user_login_ajax_loggingin');
+ − 241
+ − 242
// Insert the status message
+ − 243
div.appendChild(document.createTextNode(status_msg));
+ − 244
+ − 245
// Append a br or two to space things properly
+ − 246
div.appendChild(document.createElement('br'));
+ − 247
div.appendChild(document.createElement('br'));
+ − 248
+ − 249
var img = document.createElement('img');
+ − 250
img.src = ( ajax_login_loadimg_path ) ? ajax_login_loadimg_path : scriptPath + '/images/loading-big.gif';
+ − 251
div.appendChild(img);
+ − 252
+ − 253
// Insert the entire message into the login window
+ − 254
logindata.mb_inner.innerHTML = '';
+ − 255
logindata.mb_inner.appendChild(div);
+ − 256
+ − 257
break;
+ − 258
case AJAX_STATUS_SUCCESS:
+ − 259
+ − 260
// Create the status div
+ − 261
var div = document.createElement('div');
+ − 262
div.id = 'ajax_login_status';
+ − 263
div.style.marginTop = '10px';
+ − 264
div.style.textAlign = 'center';
+ − 265
+ − 266
// The circly ball ajaxy image + status message
+ − 267
var status_msg = $lang.get('user_login_success_short');
+ − 268
+ − 269
// Insert the status message
+ − 270
div.appendChild(document.createTextNode(status_msg));
+ − 271
+ − 272
// Append a br or two to space things properly
+ − 273
div.appendChild(document.createElement('br'));
+ − 274
div.appendChild(document.createElement('br'));
+ − 275
+ − 276
var img = document.createElement('img');
+ − 277
img.src = ( ajax_login_successimg_path ) ? ajax_login_successimg_path : scriptPath + '/images/check.png';
+ − 278
div.appendChild(img);
+ − 279
+ − 280
// Insert the entire message into the login window
+ − 281
logindata.mb_inner.innerHTML = '';
+ − 282
logindata.mb_inner.appendChild(div);
+ − 283
+ − 284
case AJAX_STATUS_DESTROY:
+ − 285
case null:
+ − 286
case undefined:
+ − 287
logindata.showing_status = false;
+ − 288
return null;
+ − 289
break;
+ − 290
}
+ − 291
logindata.showing_status = true;
+ − 292
}
+ − 293
+ − 294
/**
+ − 295
* Performs an AJAX logon request to the server and calls ajaxLoginProcessResponse() on the result.
+ − 296
* @param object JSON packet to send
+ − 297
*/
+ − 298
+ − 299
function ajaxLoginPerformRequest(json)
+ − 300
{
+ − 301
json = toJSONString(json);
+ − 302
json = ajaxEscape(json);
+ − 303
ajaxPost(makeUrlNS('Special', 'Login/action.json'), 'r=' + json, function()
+ − 304
{
+ − 305
if ( ajax.readyState == 4 && ajax.status == 200 )
+ − 306
{
+ − 307
// parse response
+ − 308
var response = String(ajax.responseText + '');
+ − 309
if ( response.substr(0, 1) != '{' )
+ − 310
{
+ − 311
handle_invalid_json(response);
+ − 312
return false;
+ − 313
}
+ − 314
response = parseJSON(response);
+ − 315
ajaxLoginProcessResponse(response);
+ − 316
}
+ − 317
}, true);
+ − 318
}
+ − 319
+ − 320
/**
+ − 321
* Processes a response from the login server
+ − 322
* @param object JSON response
+ − 323
*/
+ − 324
+ − 325
function ajaxLoginProcessResponse(response)
+ − 326
{
+ − 327
// Did the server send a plaintext error?
+ − 328
if ( response.mode == 'error' )
+ − 329
{
+ − 330
logindata.mb_object.destroy();
+ − 331
new messagebox(MB_ICONSTOP | MB_OK, 'FIXME L10N: There was an error in the login process', 'The following error code came from the server:<br />' + response.error);
+ − 332
return false;
+ − 333
}
+ − 334
// Main mode switch
+ − 335
switch ( response.mode )
+ − 336
{
+ − 337
case 'build_box':
471
7906fb190fc1
Implemented all security features on theme disabling and ACLs; added clean_key mode to login API to clean unused encryption keys
Dan
diff
changeset
+ − 338
// Rid ourselves of any loading windows
7906fb190fc1
Implemented all security features on theme disabling and ACLs; added clean_key mode to login API to clean unused encryption keys
Dan
diff
changeset
+ − 339
ajaxLoginSetStatus(AJAX_STATUS_DESTROY);
436
+ − 340
// The server wants us to build the login form, all the information is there
+ − 341
ajaxLoginBuildForm(response);
+ − 342
break;
+ − 343
case 'login_success':
+ − 344
ajaxLoginSetStatus(AJAX_STATUS_SUCCESS);
+ − 345
logindata.successfunc(response.key);
+ − 346
break;
+ − 347
case 'login_failure':
471
7906fb190fc1
Implemented all security features on theme disabling and ACLs; added clean_key mode to login API to clean unused encryption keys
Dan
diff
changeset
+ − 348
// Rid ourselves of any loading windows
7906fb190fc1
Implemented all security features on theme disabling and ACLs; added clean_key mode to login API to clean unused encryption keys
Dan
diff
changeset
+ − 349
ajaxLoginSetStatus(AJAX_STATUS_DESTROY);
436
+ − 350
document.getElementById('messageBox').style.backgroundColor = '#C0C0C0';
+ − 351
var mb_parent = document.getElementById('messageBox').parentNode;
+ − 352
new Spry.Effect.Shake(mb_parent, {duration: 1500}).start();
+ − 353
setTimeout(function()
+ − 354
{
+ − 355
document.getElementById('messageBox').style.backgroundColor = '#FFF';
+ − 356
ajaxLoginBuildForm(response.respawn_info);
+ − 357
ajaxLoginShowFriendlyError(response);
+ − 358
}, 2500);
+ − 359
break;
472
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 360
case 'login_success_reset':
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 361
var conf = confirm($lang.get('user_login_ajax_msg_used_temp_pass'));
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 362
if ( conf )
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 363
{
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 364
var url = makeUrlNS('Special', 'PasswordReset/stage2/' + response.user_id + '/' + response.temp_password);
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 365
window.location = url;
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 366
}
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 367
else
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 368
{
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 369
// treat as a failure
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 370
ajaxLoginSetStatus(AJAX_STATUS_DESTROY);
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 371
document.getElementById('messageBox').style.backgroundColor = '#C0C0C0';
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 372
var mb_parent = document.getElementById('messageBox').parentNode;
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 373
new Spry.Effect.Shake(mb_parent, {duration: 1500}).start();
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 374
setTimeout(function()
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 375
{
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 376
document.getElementById('messageBox').style.backgroundColor = '#FFF';
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 377
ajaxLoginBuildForm(response.respawn_info);
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 378
// don't show an error here, just silently respawn
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 379
}, 2500);
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 380
}
bc4b58034f4d
Implemented password reset (albeit hackishly) into the new login API; added dummy window.console object to hopefully reduce errors when Firebug isn't around; fixed the longstanding ACL dismiss/close button bug; fixed a couple undefined variables in mailer; fixed PHP error on attempted opening of /dev/(u)random in rijndael.php; clarified documentation for PageProcessor::update_page(); fixed some logic problems in theme ACL code; disabled CAPTCHA debug
Dan
diff
changeset
+ − 381
break;
471
7906fb190fc1
Implemented all security features on theme disabling and ACLs; added clean_key mode to login API to clean unused encryption keys
Dan
diff
changeset
+ − 382
case 'noop':
7906fb190fc1
Implemented all security features on theme disabling and ACLs; added clean_key mode to login API to clean unused encryption keys
Dan
diff
changeset
+ − 383
break;
436
+ − 384
}
+ − 385
}
+ − 386
+ − 387
/*
+ − 388
* RESPONSE HANDLERS
+ − 389
*/
+ − 390
+ − 391
/**
+ − 392
* Builds the login form.
+ − 393
* @param object Metadata to build off of
+ − 394
*/
+ − 395
+ − 396
function ajaxLoginBuildForm(data)
+ − 397
{
+ − 398
// let's hope this effectively preloads the image...
+ − 399
var _ = document.createElement('img');
+ − 400
_.src = ( ajax_login_successimg_path ) ? ajax_login_successimg_path : scriptPath + '/images/check.png';
+ − 401
+ − 402
var div = document.createElement('div');
+ − 403
div.id = 'ajax_login_form';
+ − 404
+ − 405
var show_captcha = ( data.locked_out && data.lockout_info.lockout_policy == 'captcha' ) ? data.lockout_info.captcha : false;
+ − 406
+ − 407
// text displayed on re-auth
+ − 408
if ( logindata.user_level > USER_LEVEL_MEMBER )
+ − 409
{
+ − 410
div.innerHTML += $lang.get('user_login_ajax_prompt_body_elev') + '<br /><br />';
+ − 411
}
+ − 412
+ − 413
// Create the form
+ − 414
var form = document.createElement('form');
+ − 415
form.action = 'javascript:void(ajaxLoginSubmitForm());';
+ − 416
form.onsubmit = function()
+ − 417
{
+ − 418
ajaxLoginSubmitForm();
+ − 419
return false;
+ − 420
}
460
+ − 421
if ( IE )
+ − 422
{
+ − 423
form.style.marginTop = '-20px';
+ − 424
}
436
+ − 425
+ − 426
// Using tables to wrap form elements because it results in a
+ − 427
// more visually appealing form. Yes, tables suck. I don't really
+ − 428
// care - they make forms look good.
+ − 429
+ − 430
var table = document.createElement('table');
+ − 431
table.style.margin = '0 auto';
+ − 432
+ − 433
// Field - username
+ − 434
var tr1 = document.createElement('tr');
+ − 435
var td1_1 = document.createElement('td');
+ − 436
td1_1.appendChild(document.createTextNode($lang.get('user_login_field_username') + ':'));
+ − 437
tr1.appendChild(td1_1);
+ − 438
var td1_2 = document.createElement('td');
+ − 439
var f_username = document.createElement('input');
+ − 440
f_username.id = 'ajax_login_field_username';
+ − 441
f_username.name = 'ajax_login_field_username';
+ − 442
f_username.type = 'text';
+ − 443
f_username.size = '25';
+ − 444
if ( data.username )
+ − 445
f_username.value = data.username;
+ − 446
td1_2.appendChild(f_username);
+ − 447
tr1.appendChild(td1_2);
+ − 448
table.appendChild(tr1);
+ − 449
+ − 450
// Field - password
+ − 451
var tr2 = document.createElement('tr');
+ − 452
var td2_1 = document.createElement('td');
+ − 453
td2_1.appendChild(document.createTextNode($lang.get('user_login_field_password') + ':'));
+ − 454
tr2.appendChild(td2_1);
+ − 455
var td2_2 = document.createElement('td');
+ − 456
var f_password = document.createElement('input');
+ − 457
f_password.id = 'ajax_login_field_password';
+ − 458
f_password.name = 'ajax_login_field_username';
+ − 459
f_password.type = 'password';
+ − 460
f_password.size = '25';
+ − 461
if ( !show_captcha )
+ − 462
{
+ − 463
f_password.onkeyup = function(e)
+ − 464
{
461
+ − 465
if ( !e )
436
+ − 466
e = window.event;
461
+ − 467
if ( !e && IE )
436
+ − 468
return true;
+ − 469
if ( e.keyCode == 13 )
+ − 470
{
+ − 471
ajaxLoginSubmitForm();
+ − 472
}
+ − 473
}
+ − 474
}
+ − 475
td2_2.appendChild(f_password);
+ − 476
tr2.appendChild(td2_2);
+ − 477
table.appendChild(tr2);
+ − 478
+ − 479
// Field - captcha
+ − 480
if ( show_captcha )
+ − 481
{
+ − 482
var tr3 = document.createElement('tr');
+ − 483
var td3_1 = document.createElement('td');
+ − 484
td3_1.appendChild(document.createTextNode($lang.get('user_login_field_captcha') + ':'));
+ − 485
tr3.appendChild(td3_1);
+ − 486
var td3_2 = document.createElement('td');
+ − 487
var f_captcha = document.createElement('input');
+ − 488
f_captcha.id = 'ajax_login_field_captcha';
+ − 489
f_captcha.name = 'ajax_login_field_username';
+ − 490
f_captcha.type = 'text';
+ − 491
f_captcha.size = '25';
+ − 492
f_captcha.onkeyup = function(e)
+ − 493
{
+ − 494
if ( !e )
+ − 495
e = window.event;
+ − 496
if ( !e.keyCode )
+ − 497
return true;
+ − 498
if ( e.keyCode == 13 )
+ − 499
{
+ − 500
ajaxLoginSubmitForm();
+ − 501
}
+ − 502
}
+ − 503
td3_2.appendChild(f_captcha);
+ − 504
tr3.appendChild(td3_2);
+ − 505
table.appendChild(tr3);
+ − 506
}
+ − 507
+ − 508
// Done building the main part of the form
+ − 509
form.appendChild(table);
+ − 510
+ − 511
// Field: enable Diffie Hellman
460
+ − 512
if ( IE )
+ − 513
{
+ − 514
var lbl_dh = document.createElement('span');
+ − 515
lbl_dh.style.fontSize = 'smaller';
+ − 516
lbl_dh.style.display = 'block';
+ − 517
lbl_dh.style.textAlign = 'center';
+ − 518
lbl_dh.innerHTML = $lang.get('user_login_ajax_check_dh_ie');
+ − 519
form.appendChild(lbl_dh);
+ − 520
}
+ − 521
else
+ − 522
{
+ − 523
var lbl_dh = document.createElement('label');
+ − 524
lbl_dh.style.fontSize = 'smaller';
+ − 525
lbl_dh.style.display = 'block';
+ − 526
lbl_dh.style.textAlign = 'center';
+ − 527
var check_dh = document.createElement('input');
+ − 528
check_dh.type = 'checkbox';
+ − 529
// this onclick attribute changes the cookie whenever the checkbox or label is clicked
+ − 530
check_dh.setAttribute('onclick', 'var ck = ( this.checked ) ? "enable" : "disable"; createCookie("diffiehellman_login", ck, 3650);');
+ − 531
if ( readCookie('diffiehellman_login') != 'disable' )
+ − 532
check_dh.setAttribute('checked', 'checked');
+ − 533
check_dh.id = 'ajax_login_field_dh';
+ − 534
lbl_dh.appendChild(check_dh);
+ − 535
lbl_dh.innerHTML += $lang.get('user_login_ajax_check_dh');
+ − 536
form.appendChild(lbl_dh);
+ − 537
}
436
+ − 538
460
+ − 539
if ( IE )
+ − 540
{
+ − 541
div.innerHTML += form.outerHTML;
+ − 542
}
+ − 543
else
+ − 544
{
+ − 545
div.appendChild(form);
+ − 546
}
436
+ − 547
+ − 548
// Diagnostic / help links
+ − 549
// (only displayed in login, not in re-auth)
+ − 550
if ( logindata.user_level == USER_LEVEL_MEMBER )
+ − 551
{
+ − 552
form.style.marginBottom = '10px';
+ − 553
var links = document.createElement('small');
+ − 554
links.style.display = 'block';
+ − 555
links.style.textAlign = 'center';
+ − 556
links.innerHTML = '';
+ − 557
if ( !show_captcha )
+ − 558
links.innerHTML += $lang.get('user_login_ajax_link_fullform', { link_full_form: makeUrlNS('Special', 'Login/' + title) }) + '<br />';
+ − 559
// Always shown
+ − 560
links.innerHTML += $lang.get('user_login_ajax_link_forgotpass', { forgotpass_link: makeUrlNS('Special', 'PasswordReset') }) + '<br />';
+ − 561
if ( !show_captcha )
+ − 562
links.innerHTML += $lang.get('user_login_createaccount_blurb', { reg_link: makeUrlNS('Special', 'Register') });
+ − 563
div.appendChild(links);
+ − 564
}
+ − 565
+ − 566
// Insert the entire form into the login window
+ − 567
logindata.mb_inner.innerHTML = '';
+ − 568
logindata.mb_inner.appendChild(div);
+ − 569
+ − 570
// Post operations: field focus
460
+ − 571
if ( IE )
+ − 572
{
+ − 573
setTimeout(
+ − 574
function()
+ − 575
{
+ − 576
if ( logindata.loggedin_username )
+ − 577
document.getElementById('ajax_login_field_password').focus();
+ − 578
else
+ − 579
document.getElementById('ajax_login_field_username').focus();
+ − 580
}, 200);
+ − 581
}
436
+ − 582
else
460
+ − 583
{
+ − 584
if ( data.username )
+ − 585
f_password.focus();
+ − 586
else
+ − 587
f_username.focus();
+ − 588
}
436
+ − 589
+ − 590
// Post operations: show captcha window
+ − 591
if ( show_captcha )
+ − 592
ajaxShowCaptcha(show_captcha);
+ − 593
+ − 594
// Post operations: stash encryption keys and All That Jazz(TM)
+ − 595
logindata.key_aes = data.aes_key;
+ − 596
logindata.key_dh = data.dh_public_key;
+ − 597
logindata.captcha_hash = show_captcha;
460
+ − 598
logindata.loggedin_username = data.username
436
+ − 599
+ − 600
// Are we locked out? If so simulate an error and disable the controls
+ − 601
if ( data.lockout_info.lockout_policy == 'lockout' && data.locked_out )
+ − 602
{
+ − 603
f_username.setAttribute('disabled', 'disabled');
+ − 604
f_password.setAttribute('disabled', 'disabled');
+ − 605
var fake_packet = {
+ − 606
error_code: 'locked_out',
+ − 607
respawn_info: data
+ − 608
};
+ − 609
ajaxLoginShowFriendlyError(fake_packet);
+ − 610
}
+ − 611
}
+ − 612
+ − 613
function ajaxLoginSubmitForm(real, username, password, captcha)
+ − 614
{
+ − 615
// Perform AES test to make sure it's all working
+ − 616
if ( !aes_self_test() )
+ − 617
{
+ − 618
alert('BUG: AES self-test failed');
+ − 619
login_cache.mb_object.destroy();
+ − 620
return false;
+ − 621
}
+ − 622
// Hide the error message and captcha
+ − 623
if ( document.getElementById('ajax_login_error_box') )
+ − 624
{
+ − 625
document.getElementById('ajax_login_error_box').parentNode.removeChild(document.getElementById('ajax_login_error_box'));
+ − 626
}
+ − 627
if ( document.getElementById('autoCaptcha') )
+ − 628
{
+ − 629
var to = fly_out_top(document.getElementById('autoCaptcha'), false, true);
+ − 630
setTimeout(function() {
+ − 631
var d = document.getElementById('autoCaptcha');
+ − 632
d.parentNode.removeChild(d);
+ − 633
}, to);
+ − 634
}
+ − 635
// Encryption: preprocessor
+ − 636
if ( real )
+ − 637
{
+ − 638
var do_dh = true;
+ − 639
}
+ − 640
else if ( document.getElementById('ajax_login_field_dh') )
+ − 641
{
+ − 642
var do_dh = document.getElementById('ajax_login_field_dh').checked;
+ − 643
}
+ − 644
else
+ − 645
{
460
+ − 646
if ( IE )
+ − 647
{
+ − 648
// IE doesn't have this control, continue silently IF the rest
+ − 649
// of the login form is there
+ − 650
if ( !document.getElementById('ajax_login_field_username') )
+ − 651
{
+ − 652
return false;
+ − 653
}
+ − 654
}
+ − 655
else
+ − 656
{
+ − 657
// The user probably clicked ok when the form wasn't in there.
+ − 658
return false;
+ − 659
}
436
+ − 660
}
+ − 661
if ( !username )
+ − 662
{
+ − 663
var username = document.getElementById('ajax_login_field_username').value;
+ − 664
}
+ − 665
if ( !password )
+ − 666
{
+ − 667
var password = document.getElementById('ajax_login_field_password').value;
+ − 668
}
+ − 669
if ( !captcha && document.getElementById('ajax_login_field_captcha') )
+ − 670
{
+ − 671
var captcha = document.getElementById('ajax_login_field_captcha').value;
+ − 672
}
+ − 673
+ − 674
if ( do_dh )
+ − 675
{
+ − 676
ajaxLoginSetStatus(AJAX_STATUS_GENERATING_KEY);
+ − 677
if ( !real )
+ − 678
{
+ − 679
// Wait while the browser updates the login window
+ − 680
setTimeout(function()
+ − 681
{
+ − 682
ajaxLoginSubmitForm(true, username, password, captcha);
+ − 683
}, 200);
+ − 684
return true;
+ − 685
}
+ − 686
// Perform Diffie Hellman stuff
+ − 687
var dh_priv = dh_gen_private();
+ − 688
var dh_pub = dh_gen_public(dh_priv);
+ − 689
var secret = dh_gen_shared_secret(dh_priv, logindata.key_dh);
+ − 690
// secret_hash is used to verify that the server guesses the correct secret
+ − 691
var secret_hash = hex_sha1(secret);
+ − 692
// crypt_key is the actual AES key
+ − 693
var crypt_key = (hex_sha256(secret)).substr(0, (keySizeInBits / 4));
+ − 694
}
+ − 695
else
+ − 696
{
+ − 697
var crypt_key = logindata.key_aes;
+ − 698
}
+ − 699
+ − 700
ajaxLoginSetStatus(AJAX_STATUS_LOGGING_IN);
+ − 701
+ − 702
// Encrypt the password and username
+ − 703
var userinfo = toJSONString({
+ − 704
username: username,
+ − 705
password: password
+ − 706
});
+ − 707
var crypt_key_ba = hexToByteArray(crypt_key);
+ − 708
userinfo = stringToByteArray(userinfo);
+ − 709
+ − 710
userinfo = rijndaelEncrypt(userinfo, crypt_key_ba, 'ECB');
+ − 711
userinfo = byteArrayToHex(userinfo);
+ − 712
// Encrypted username and password (serialized with JSON) are now in the userinfo string
+ − 713
+ − 714
// Collect other needed information
+ − 715
if ( logindata.captcha_hash )
+ − 716
{
+ − 717
var captcha_hash = logindata.captcha_hash;
+ − 718
var captcha_code = captcha;
+ − 719
}
+ − 720
else
+ − 721
{
+ − 722
var captcha_hash = false;
+ − 723
var captcha_code = false;
+ − 724
}
+ − 725
+ − 726
// Ship it across the 'net
+ − 727
if ( do_dh )
+ − 728
{
+ − 729
var json_packet = {
+ − 730
mode: 'login_dh',
+ − 731
userinfo: userinfo,
+ − 732
captcha_code: captcha_code,
+ − 733
captcha_hash: captcha_hash,
+ − 734
dh_public_key: logindata.key_dh,
+ − 735
dh_client_key: dh_pub,
+ − 736
dh_secret_hash: secret_hash,
+ − 737
level: logindata.user_level
+ − 738
}
+ − 739
}
+ − 740
else
+ − 741
{
+ − 742
var json_packet = {
+ − 743
mode: 'login_aes',
+ − 744
userinfo: userinfo,
+ − 745
captcha_code: captcha_code,
+ − 746
captcha_hash: captcha_hash,
+ − 747
key_aes: hex_md5(crypt_key),
+ − 748
level: logindata.user_level
+ − 749
}
+ − 750
}
+ − 751
ajaxLoginPerformRequest(json_packet);
+ − 752
}
+ − 753
+ − 754
function ajaxLoginShowFriendlyError(response)
+ − 755
{
+ − 756
if ( !response.respawn_info )
+ − 757
return false;
+ − 758
if ( !response.error_code )
+ − 759
return false;
+ − 760
var text = ajaxLoginGetErrorText(response);
+ − 761
if ( document.getElementById('ajax_login_error_box') )
+ − 762
{
+ − 763
// console.info('Reusing existing error-box');
+ − 764
document.getElementById('ajax_login_error_box').innerHTML = text;
+ − 765
return true;
+ − 766
}
+ − 767
+ − 768
// console.info('Drawing new error-box');
+ − 769
+ − 770
// calculate position for the top of the box
+ − 771
var mb_bottom = $('messageBoxButtons').Top() + $('messageBoxButtons').Height();
+ − 772
// if the box isn't done flying in yet, just estimate
+ − 773
if ( mb_bottom < ( getHeight() / 2 ) )
+ − 774
{
+ − 775
mb_bottom = ( getHeight() / 2 ) + 120;
+ − 776
}
+ − 777
var win_bottom = getHeight() + getScrollOffset();
+ − 778
var top = mb_bottom + ( ( win_bottom - mb_bottom ) / 2 ) - 32;
+ − 779
// left position = 0.2 * window_width, seeing as the box is 60% width this works hackishly but nice and quick
+ − 780
var left = getWidth() * 0.2;
+ − 781
+ − 782
// create the div
+ − 783
var errbox = document.createElement('div');
+ − 784
errbox.className = 'error-box-mini';
+ − 785
errbox.style.position = 'absolute';
+ − 786
errbox.style.width = '60%';
+ − 787
errbox.style.top = top + 'px';
+ − 788
errbox.style.left = left + 'px';
+ − 789
errbox.innerHTML = text;
+ − 790
errbox.id = 'ajax_login_error_box';
+ − 791
+ − 792
var body = document.getElementsByTagName('body')[0];
+ − 793
body.appendChild(errbox);
+ − 794
}
+ − 795
+ − 796
function ajaxLoginGetErrorText(response)
+ − 797
{
+ − 798
switch ( response.error_code )
+ − 799
{
+ − 800
default:
+ − 801
return $lang.get('user_err_' + response.error_code);
+ − 802
break;
+ − 803
case 'locked_out':
+ − 804
if ( response.respawn_info.lockout_info.lockout_policy == 'lockout' )
+ − 805
{
+ − 806
return $lang.get('user_err_locked_out', {
+ − 807
lockout_threshold: response.respawn_info.lockout_info.lockout_threshold,
+ − 808
lockout_duration: response.respawn_info.lockout_info.lockout_duration,
+ − 809
time_rem: response.respawn_info.lockout_info.time_rem,
+ − 810
plural: ( response.respawn_info.lockout_info.time_rem == 1 ) ? '' : $lang.get('meta_plural'),
+ − 811
captcha_blurb: ''
+ − 812
});
+ − 813
break;
+ − 814
}
+ − 815
case 'invalid_credentials':
+ − 816
var base = $lang.get('user_err_invalid_credentials');
+ − 817
if ( response.respawn_info.locked_out )
+ − 818
{
+ − 819
base += ' ';
+ − 820
var captcha_blurb = '';
+ − 821
switch(response.respawn_info.lockout_info.lockout_policy)
+ − 822
{
+ − 823
case 'captcha':
+ − 824
captcha_blurb = $lang.get('user_err_locked_out_captcha_blurb');
+ − 825
break;
+ − 826
case 'lockout':
+ − 827
break;
+ − 828
default:
+ − 829
base += 'WTF? Shouldn\'t be locked out with lockout policy set to disable.';
+ − 830
break;
+ − 831
}
+ − 832
base += $lang.get('user_err_locked_out', {
+ − 833
captcha_blurb: captcha_blurb,
+ − 834
lockout_threshold: response.respawn_info.lockout_info.lockout_threshold,
+ − 835
lockout_duration: response.respawn_info.lockout_info.lockout_duration,
+ − 836
time_rem: response.respawn_info.lockout_info.time_rem,
+ − 837
plural: ( response.respawn_info.lockout_info.time_rem == 1 ) ? '' : $lang.get('meta_plural')
+ − 838
});
+ − 839
}
+ − 840
else if ( response.respawn_info.lockout_info.lockout_policy == 'lockout' || response.respawn_info.lockout_info.lockout_policy == 'captcha' )
+ − 841
{
+ − 842
// if we have a lockout policy of captcha or lockout, then warn the user
+ − 843
switch ( response.respawn_info.lockout_info.lockout_policy )
+ − 844
{
+ − 845
case 'captcha':
+ − 846
base += $lang.get('user_err_invalid_credentials_lockout', {
+ − 847
fails: response.respawn_info.lockout_info.lockout_fails,
+ − 848
lockout_threshold: response.respawn_info.lockout_info.lockout_threshold,
+ − 849
lockout_duration: response.respawn_info.lockout_info.lockout_duration
+ − 850
});
+ − 851
break;
+ − 852
case 'lockout':
+ − 853
break;
+ − 854
}
+ − 855
}
+ − 856
return base;
+ − 857
break;
+ − 858
}
+ − 859
}
+ − 860