hotspotlogin 0.1.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +34 -13
- data/examples/etc/lighttpd/lighttpd.conf +31 -0
- data/examples/hotspotlogin.conf.yaml +6 -0
- data/lib/hotspotlogin/app.rb +74 -50
- data/lib/hotspotlogin/app/helpers.rb +17 -0
- data/lib/hotspotlogin/config.rb +25 -1
- data/lib/hotspotlogin/constants.rb +32 -2
- data/public/hotspotlogin/css/default.css +77 -0
- data/public/hotspotlogin/js/ChilliLibrary.js +844 -0
- data/public/hotspotlogin/js/UserStatus.js +229 -0
- data/views/_login_form.erb +5 -3
- data/views/hotspotlogin.erb +78 -18
- data/views/layout.erb +31 -43
- metadata +16 -11
@@ -0,0 +1,844 @@
|
|
1
|
+
/**
|
2
|
+
* ChilliLibrary.js
|
3
|
+
* V2.0
|
4
|
+
*
|
5
|
+
* This Javascript library can be used to create HTML/JS browser
|
6
|
+
* based smart clients (BBSM) for the CoovaChilli access controller
|
7
|
+
* Coova Chilli rev 81 or higher is required
|
8
|
+
*
|
9
|
+
* This library creates four global objects :
|
10
|
+
*
|
11
|
+
* - chilliController Expose session/client state and
|
12
|
+
* connect()/disconnect() methods the to BBSM.
|
13
|
+
*
|
14
|
+
* - chilliJSON INTERNAL (should not be called from the BBSM).
|
15
|
+
* Issues a command to the chilli daemon by adding a new <SCRIPT>
|
16
|
+
* tag to the HTML DOM (this hack enables cross server requests).
|
17
|
+
*
|
18
|
+
* - chilliClock Can be used by BBSMs to display a count down.
|
19
|
+
* Will sync with chilliController for smooth UI display (not yet implemented)
|
20
|
+
*
|
21
|
+
* - chilliLibrary Expose API and library versions
|
22
|
+
*
|
23
|
+
* For more information http://www.coova.org/CoovaChilli/JSON
|
24
|
+
*
|
25
|
+
* TODO :
|
26
|
+
* - Fine tune level of debug messages
|
27
|
+
* - Define error code when invoking onError
|
28
|
+
* - Retry mechanism after a JSON request fails
|
29
|
+
* - Delay clock tick when there is already an ongoing request
|
30
|
+
* - Use a true JSON parser to validate what we received
|
31
|
+
* - Use idleTime and idleTimeout to re-schedule autofresh after
|
32
|
+
* a likely idle termination by chilli
|
33
|
+
* - check that the library can be compiled as a Flash swf library
|
34
|
+
* and used from Flash BBSMs with the same API.
|
35
|
+
*
|
36
|
+
* Copyright (C) Y.Deltroo 2007
|
37
|
+
* Distributed under the BSD License
|
38
|
+
*
|
39
|
+
* This file also contains third party code :
|
40
|
+
* - MD5, distributed under the BSD license
|
41
|
+
* http://pajhome.org.uk/crypt/md5
|
42
|
+
*
|
43
|
+
*/
|
44
|
+
|
45
|
+
var chilliLibrary = { revision:'85' , apiVersion:'2.0' } ;
|
46
|
+
|
47
|
+
|
48
|
+
/**
|
49
|
+
* Global chilliController object
|
50
|
+
*
|
51
|
+
* CONFIGUARION PROPERTIES
|
52
|
+
* -----------------------
|
53
|
+
* ident (String)
|
54
|
+
* Hex encoded string (used for client side CHAP-Password calculations)
|
55
|
+
*
|
56
|
+
* interval (Number)
|
57
|
+
* Poll the gateway every interval, in seconds
|
58
|
+
*
|
59
|
+
* host (String)
|
60
|
+
* IP address of the controller (String)
|
61
|
+
*
|
62
|
+
* port (Number)
|
63
|
+
* UAM port to direct request to on the gateway
|
64
|
+
*
|
65
|
+
* ssl (Boolean)
|
66
|
+
* Shall we use HTTP or HTTPS to communicate with the chilli controller
|
67
|
+
*
|
68
|
+
* uamService : String
|
69
|
+
* !!! EXPERIMENTAL FEATURE !!!
|
70
|
+
* URL to external uamService script (used for external MD5 calculation when portal/chilli trust is required)
|
71
|
+
* This remote script runs on a SSL enable web server, and knows UAM SECRET.
|
72
|
+
* The chilliController javascript object will send the password over SSL (and challenge for CHAP)
|
73
|
+
* UAM SERVICE should reply with a JSON response containing
|
74
|
+
* - CHAP logon : CHAP-Password X0Red with UAM SECRET
|
75
|
+
* - PAP logon : Password XORed with UAM SECRET
|
76
|
+
*
|
77
|
+
* For more information http://www.coova.org/CoovaChilli/JSON
|
78
|
+
*
|
79
|
+
*/
|
80
|
+
|
81
|
+
if (!chilliController || !chilliController.host)
|
82
|
+
var chilliController = { interval:30 , host:"1.0.0.1" , port:false , ident:'00' , ssl:false , uamService: false };
|
83
|
+
|
84
|
+
/* Define clientState numerical code constants */
|
85
|
+
chilliController.stateCodes = { UNKNOWN:-1 , NOT_AUTH:0 , AUTH:1 , AUTH_PENDING:2 , AUTH_SPLASH:3 } ;
|
86
|
+
|
87
|
+
/* Initializing session and accounting members, objet properties */
|
88
|
+
chilliController.session = {} ;
|
89
|
+
chilliController.accounting = {} ;
|
90
|
+
chilliController.redir = {} ;
|
91
|
+
|
92
|
+
chilliController.location = { name: '' } ;
|
93
|
+
chilliController.challenge = '' ;
|
94
|
+
chilliController.message = '' ;
|
95
|
+
chilliController.clientState = chilliController.stateCodes.UNKNOWN ;
|
96
|
+
chilliController.command = '' ;
|
97
|
+
chilliController.autorefreshTimer = 0 ;
|
98
|
+
|
99
|
+
/* This method returns the root URL for commands */
|
100
|
+
chilliController.urlRoot = function () {
|
101
|
+
var protocol = ( chilliController.ssl ) ? "https" : "http" ;
|
102
|
+
var urlRoot = protocol + "://" + chilliController.host + (chilliController.port ? ":" + chilliController.port.toString() : "") + "/json/" ;
|
103
|
+
return urlRoot;
|
104
|
+
};
|
105
|
+
|
106
|
+
/* Default event handlers */
|
107
|
+
chilliController.onUpdate = function ( cmd ) {
|
108
|
+
log('>> Default onUpdate handler. <<\n>> You should write your own. <<\n>> cmd = ' + cmd + ' <<' );
|
109
|
+
};
|
110
|
+
|
111
|
+
chilliController.onError = function ( str ) {
|
112
|
+
log ( '>> Default Error Handler<<\n>> You should write your own <<\n>> ' + str + ' <<' );
|
113
|
+
};
|
114
|
+
|
115
|
+
|
116
|
+
chilliController.formatTime = function ( t , zeroReturn ) {
|
117
|
+
|
118
|
+
if ( typeof(t) == 'undefined' ) {
|
119
|
+
return "Not available";
|
120
|
+
}
|
121
|
+
|
122
|
+
t = parseInt ( t , 10 ) ;
|
123
|
+
if ( (typeof (zeroReturn) !='undefined') && ( t === 0 ) ) {
|
124
|
+
return zeroReturn;
|
125
|
+
}
|
126
|
+
|
127
|
+
var h = Math.floor( t/3600 ) ;
|
128
|
+
var m = Math.floor( (t - 3600*h)/60 ) ;
|
129
|
+
var s = t % 60 ;
|
130
|
+
|
131
|
+
var s_str = s.toString();
|
132
|
+
if (s < 10 ) { s_str = '0' + s_str; }
|
133
|
+
|
134
|
+
var m_str = m.toString();
|
135
|
+
if (m < 10 ) { m_str= '0' + m_str; }
|
136
|
+
|
137
|
+
var h_str = h.toString();
|
138
|
+
if (h < 10 ) { h_str= '0' + h_str; }
|
139
|
+
|
140
|
+
|
141
|
+
if ( t < 60 ) { return s_str + 's' ; }
|
142
|
+
else if ( t < 3600 ) { return m_str + 'm' + s_str + 's' ; }
|
143
|
+
else { return h_str + 'h' + m_str + 'm' + s_str + 's'; }
|
144
|
+
|
145
|
+
};
|
146
|
+
|
147
|
+
chilliController.formatBytes = function ( b , zeroReturn ) {
|
148
|
+
|
149
|
+
if ( typeof(b) == 'undefined' ) {
|
150
|
+
b = 0;
|
151
|
+
} else {
|
152
|
+
b = parseInt ( b , 10 ) ;
|
153
|
+
}
|
154
|
+
|
155
|
+
if ( (typeof (zeroReturn) !='undefined') && ( b === 0 ) ) {
|
156
|
+
return zeroReturn;
|
157
|
+
}
|
158
|
+
|
159
|
+
var kb = Math.round(b / 10) / 100;
|
160
|
+
if (kb < 1) return b + ' Bytes';
|
161
|
+
|
162
|
+
var mb = Math.round(kb / 10) / 100;
|
163
|
+
if (mb < 1) return kb + ' Kilobytes';
|
164
|
+
|
165
|
+
var gb = Math.round(mb / 10) / 100;
|
166
|
+
if (gb < 1) return mb + ' Megabytes';
|
167
|
+
|
168
|
+
return gb + ' Gigabytes';
|
169
|
+
};
|
170
|
+
|
171
|
+
|
172
|
+
/**
|
173
|
+
* Global chilliController object
|
174
|
+
*
|
175
|
+
* PUBLIC METHODS
|
176
|
+
* --------------
|
177
|
+
* logon ( username, password ) :
|
178
|
+
* Attempt a CHAP logon with username/password
|
179
|
+
* issues a /logon command to chilli daemon
|
180
|
+
*
|
181
|
+
* logon2 ( username, response ) :
|
182
|
+
* Attempt a CHAP logon with username/response
|
183
|
+
* issues a /logon command to chilli daemon
|
184
|
+
*
|
185
|
+
* logoff () :
|
186
|
+
* Disconnect the current user by issuing a
|
187
|
+
* /logoff command to the chilli daemon
|
188
|
+
*
|
189
|
+
* refresh () :
|
190
|
+
* Issues a /status command to chilli daemon to refresh
|
191
|
+
* the local chilliController object state/session data
|
192
|
+
*
|
193
|
+
*/
|
194
|
+
|
195
|
+
chilliController.logon = function ( username , password ) {
|
196
|
+
|
197
|
+
if ( typeof(username) !== 'string') {
|
198
|
+
chilliController.onError( 1 , "username missing (or incorrect type)" ) ;
|
199
|
+
}
|
200
|
+
|
201
|
+
if ( typeof(password) !== 'string') {
|
202
|
+
chilliController.onError( 2 , "password missing (or incorrect type)" ) ;
|
203
|
+
}
|
204
|
+
|
205
|
+
log ( 'chilliController.logon( "' + username + '" , "' + password + ' " )' );
|
206
|
+
|
207
|
+
chilliController.temp = { 'username': username , 'password': password };
|
208
|
+
chilliController.command = 'logon';
|
209
|
+
|
210
|
+
log ('chilliController.logon: asking for a new challenge ' );
|
211
|
+
chilliJSON.onError = chilliController.onError ;
|
212
|
+
chilliJSON.onJSONReady = chilliController.logonStep2 ;
|
213
|
+
chilliController.clientState = chilliController.AUTH_PENDING ;
|
214
|
+
chilliJSON.get( chilliController.urlRoot() + 'status' ) ;
|
215
|
+
};
|
216
|
+
|
217
|
+
chilliController.logon2 = function ( username , response ) {
|
218
|
+
|
219
|
+
if ( typeof(username) !== 'string') {
|
220
|
+
chilliController.onError( 1 , "username missing (or incorrect type)" ) ;
|
221
|
+
}
|
222
|
+
|
223
|
+
if ( typeof(response) !== 'string') {
|
224
|
+
chilliController.onError( 2 , "response missing (or incorrect type)" ) ;
|
225
|
+
}
|
226
|
+
|
227
|
+
log ( 'chilliController.logon2( "' + username + '" , "' + response + ' " )' );
|
228
|
+
|
229
|
+
chilliController.temp = { 'username': username , 'response': response };
|
230
|
+
chilliController.command = 'logon2';
|
231
|
+
|
232
|
+
log ('chilliController.logon2: asking for a new challenge ' );
|
233
|
+
chilliJSON.onError = chilliController.onError ;
|
234
|
+
chilliJSON.onJSONReady = chilliController.logonStep2 ;
|
235
|
+
chilliController.clientState = chilliController.AUTH_PENDING ;
|
236
|
+
chilliJSON.get( chilliController.urlRoot() + 'status' ) ;
|
237
|
+
};
|
238
|
+
|
239
|
+
|
240
|
+
/**
|
241
|
+
* Second part of the logon process invoked after
|
242
|
+
* the just requested challenge has been received
|
243
|
+
*/
|
244
|
+
chilliController.logonStep2 = function ( resp ) {
|
245
|
+
|
246
|
+
log('Entering logonStep 2');
|
247
|
+
|
248
|
+
if ( typeof (resp.challenge) != 'string' ) {
|
249
|
+
log('logonStep2: cannot find a challenge. Aborting.');
|
250
|
+
return chilliController.onError('Cannot get challenge');
|
251
|
+
}
|
252
|
+
|
253
|
+
if ( resp.clientSate === chilliController.stateCodes.AUTH ) {
|
254
|
+
log('logonStep2: Already connected. Aborting.');
|
255
|
+
return chilliController.onError('Already connected.');
|
256
|
+
}
|
257
|
+
|
258
|
+
var challenge = resp.challenge;
|
259
|
+
|
260
|
+
var username = chilliController.temp.username ;
|
261
|
+
var password = chilliController.temp.password ;
|
262
|
+
var response = chilliController.temp.response ;
|
263
|
+
|
264
|
+
log ('chilliController.logonStep2: Got challenge = ' + challenge );
|
265
|
+
|
266
|
+
if ( chilliController.uamService ) { /* MD5 CHAP will be calculated by uamService */
|
267
|
+
|
268
|
+
log ('chilliController.logonStep2: Logon using uamService (external MD5 CHAP)');
|
269
|
+
|
270
|
+
var c ;
|
271
|
+
if ( chilliController.uamService.indexOf('?') === -1 ) {
|
272
|
+
c = '?' ;
|
273
|
+
}
|
274
|
+
else {
|
275
|
+
c = '&' ;
|
276
|
+
}
|
277
|
+
|
278
|
+
// Build command URL
|
279
|
+
var url = chilliController.uamService + c + 'username=' + escape(username) +'&password=' + escape(password) +'&challenge=' + challenge ;
|
280
|
+
|
281
|
+
if (chilliController.queryObj && chilliController.queryObj['userurl'] ) {
|
282
|
+
url += '&userurl='+chilliController.queryObj['userurl'] ;
|
283
|
+
}
|
284
|
+
|
285
|
+
// Make uamService request
|
286
|
+
chilliJSON.onError = chilliController.onError ;
|
287
|
+
chilliJSON.onJSONReady = chilliController.logonStep3 ;
|
288
|
+
|
289
|
+
chilliController.clientState = chilliController.AUTH_PENDING ;
|
290
|
+
chilliJSON.get( url ) ;
|
291
|
+
}
|
292
|
+
else {
|
293
|
+
/* TODO: Should check if challenge has expired and possibly get a new one */
|
294
|
+
/* OR always call status first to get a fresh challenge */
|
295
|
+
|
296
|
+
if (!response || response == '') {
|
297
|
+
/* Calculate MD5 CHAP at the client side */
|
298
|
+
var myMD5 = new ChilliMD5();
|
299
|
+
response = myMD5.chap ( chilliController.ident , password , challenge );
|
300
|
+
log ( 'chilliController.logonStep2: Calculating CHAP-Password = ' + response );
|
301
|
+
}
|
302
|
+
|
303
|
+
/* Prepare chilliJSON for logon request */
|
304
|
+
chilliJSON.onError = chilliController.onError ;
|
305
|
+
chilliJSON.onJSONReady = chilliController.processReply ;
|
306
|
+
chilliController.clientState = chilliController.stateCodes.AUTH_PENDING ;
|
307
|
+
|
308
|
+
/* Build /logon command URL */
|
309
|
+
var logonUrl = chilliController.urlRoot() + 'logon?username=' + escape(username) + '&response=' + response;
|
310
|
+
if (chilliController.queryObj && chilliController.queryObj['userurl'] ) {
|
311
|
+
logonUrl += '&userurl='+chilliController.queryObj['userurl'] ;
|
312
|
+
}
|
313
|
+
chilliJSON.get ( logonUrl ) ;
|
314
|
+
}
|
315
|
+
|
316
|
+
};
|
317
|
+
|
318
|
+
/**
|
319
|
+
* Third part of the logon process invoked after
|
320
|
+
* getting a uamService response
|
321
|
+
*/
|
322
|
+
chilliController.logonStep3 = function ( resp ) {
|
323
|
+
log('Entering logonStep 3');
|
324
|
+
|
325
|
+
var username = chilliController.temp.username ;
|
326
|
+
|
327
|
+
if ( typeof (resp.response) == 'string' ) {
|
328
|
+
chilliJSON.onError = chilliController.onError ;
|
329
|
+
chilliJSON.onJSONReady = chilliController.processReply ;
|
330
|
+
chilliController.clientState = chilliController.stateCodes.AUTH_PENDING ;
|
331
|
+
|
332
|
+
/* Build /logon command URL */
|
333
|
+
var logonUrl = chilliController.urlRoot() + 'logon?username=' + escape(username) + '&response=' + resp.response;
|
334
|
+
if (chilliController.queryObj && chilliController.queryObj['userurl'] ) {
|
335
|
+
logonUrl += '&userurl='+chilliController.queryObj['userurl'] ;
|
336
|
+
}
|
337
|
+
chilliJSON.get ( logonUrl ) ;
|
338
|
+
}
|
339
|
+
}
|
340
|
+
|
341
|
+
chilliController.refresh = function ( ) {
|
342
|
+
|
343
|
+
if ( chilliController.autorefreshTimer ) {
|
344
|
+
chilliController.command = 'autorefresh' ;
|
345
|
+
}
|
346
|
+
else {
|
347
|
+
chilliController.command = 'refresh' ;
|
348
|
+
}
|
349
|
+
|
350
|
+
chilliJSON.onError = chilliController.onError ;
|
351
|
+
chilliJSON.onJSONReady = chilliController.processReply ;
|
352
|
+
chilliJSON.get( chilliController.urlRoot() + 'status' ) ;
|
353
|
+
};
|
354
|
+
|
355
|
+
chilliController.logoff = function () {
|
356
|
+
|
357
|
+
chilliController.command = 'logoff' ;
|
358
|
+
chilliJSON.onError = chilliController.onError ;
|
359
|
+
chilliJSON.onJSONReady = chilliController.processReply ;
|
360
|
+
chilliJSON.get( chilliController.urlRoot() + 'logoff' );
|
361
|
+
};
|
362
|
+
|
363
|
+
/* *
|
364
|
+
*
|
365
|
+
* This functions does some check/type processing on the JSON resp
|
366
|
+
* and updates the corresponding chilliController members
|
367
|
+
*
|
368
|
+
*/
|
369
|
+
chilliController.processReply = function ( resp ) {
|
370
|
+
|
371
|
+
if ( typeof (resp.message) == 'string' ) {
|
372
|
+
|
373
|
+
/* The following trick will replace HTML entities with the corresponding
|
374
|
+
* character. This will not work in Flash (no innerHTML)
|
375
|
+
*/
|
376
|
+
|
377
|
+
var fakediv = document.createElement('div');
|
378
|
+
fakediv.innerHTML = resp.message ;
|
379
|
+
chilliController.message = fakediv.innerHTML ;
|
380
|
+
}
|
381
|
+
|
382
|
+
if ( typeof (resp.challenge) == 'string' ) {
|
383
|
+
chilliController.challenge = resp.challenge ;
|
384
|
+
}
|
385
|
+
|
386
|
+
if ( typeof ( resp.location ) == 'object' ) {
|
387
|
+
chilliController.location = resp.location ;
|
388
|
+
}
|
389
|
+
|
390
|
+
if ( typeof ( resp.accounting ) == 'object' ) {
|
391
|
+
chilliController.accounting = resp.accounting ;
|
392
|
+
}
|
393
|
+
|
394
|
+
if ( (typeof ( resp.redir ) == 'object') ) {
|
395
|
+
chilliController.redir = resp.redir ;
|
396
|
+
}
|
397
|
+
|
398
|
+
/* Update the session member only the first time after AUTH */
|
399
|
+
if ( (typeof ( resp.session ) == 'object') &&
|
400
|
+
( chilliController.session==null || (
|
401
|
+
( chilliController.clientState !== chilliController.stateCodes.AUTH ) &&
|
402
|
+
( resp.clientState === chilliController.stateCodes.AUTH )))) {
|
403
|
+
|
404
|
+
chilliController.session = resp.session ;
|
405
|
+
|
406
|
+
if ( resp.session.startTime ) {
|
407
|
+
chilliController.session.startTime = new Date();
|
408
|
+
chilliController.session.startTime.setTime(resp.session.startTime);
|
409
|
+
}
|
410
|
+
}
|
411
|
+
|
412
|
+
/* Update clientState */
|
413
|
+
if ( ( resp.clientState === chilliController.stateCodes.NOT_AUTH ) ||
|
414
|
+
( resp.clientState === chilliController.stateCodes.AUTH ) ||
|
415
|
+
( resp.clientState === chilliController.stateCodes.AUTH_SPLASH ) ||
|
416
|
+
( resp.clientState === chilliController.stateCodes.AUTH_PENDING ) ) {
|
417
|
+
|
418
|
+
chilliController.clientState = resp.clientState ;
|
419
|
+
}
|
420
|
+
else {
|
421
|
+
chilliController.onError("Unknown clientState found in JSON reply");
|
422
|
+
}
|
423
|
+
|
424
|
+
|
425
|
+
/* Launch or stop the autorefresh timer if required */
|
426
|
+
if ( chilliController.clientState === chilliController.stateCodes.AUTH ) {
|
427
|
+
|
428
|
+
if ( !chilliController.autorefreshTimer ) {
|
429
|
+
chilliController.autorefreshTimer = setInterval ('chilliController.refresh()' , 1000*chilliController.interval);
|
430
|
+
}
|
431
|
+
}
|
432
|
+
else if ( chilliController.clientState === chilliController.stateCodes.NOT_AUTH ) {
|
433
|
+
clearInterval ( chilliController.autorefreshTimer ) ;
|
434
|
+
chilliController.autorefreshTimer = 0 ;
|
435
|
+
}
|
436
|
+
|
437
|
+
/* Lastly... call the event handler */
|
438
|
+
log ('chilliController.processReply: Calling onUpdate. clienState = ' + chilliController.clientState);
|
439
|
+
chilliController.onUpdate( chilliController.command );
|
440
|
+
};
|
441
|
+
|
442
|
+
|
443
|
+
|
444
|
+
/**
|
445
|
+
* chilliJSON object
|
446
|
+
*
|
447
|
+
* This private objet implements the cross domain hack
|
448
|
+
* If no answer is received before timeout, then an error is raised.
|
449
|
+
*
|
450
|
+
*/
|
451
|
+
|
452
|
+
var chilliJSON = { timeout:25000 , timer:0 , node:0 , timestamp:0 };
|
453
|
+
|
454
|
+
chilliJSON.expired = function () {
|
455
|
+
|
456
|
+
if ( chilliJSON.node.text ) {
|
457
|
+
log ('chilliJSON: reply content \n' + chilliJSON.node.text );
|
458
|
+
}
|
459
|
+
else {
|
460
|
+
log ('chilliJSON: request timed out (or reply is not valid JS)');
|
461
|
+
}
|
462
|
+
|
463
|
+
clearInterval ( chilliJSON.timer ) ;
|
464
|
+
chilliJSON.timer = 0 ;
|
465
|
+
|
466
|
+
/* remove the <SCRIPT> tag node that we have created */
|
467
|
+
if ( typeof (chilliJSON.node) !== 'number' ) {
|
468
|
+
document.getElementsByTagName('head')[0].removeChild ( chilliJSON.node );
|
469
|
+
}
|
470
|
+
chilliJSON.node = 0;
|
471
|
+
|
472
|
+
/* TODO: Implement some kind of retry mechanism here ... */
|
473
|
+
|
474
|
+
chilliJSON.onError('JSON request timed out (or reply is not valid)');
|
475
|
+
};
|
476
|
+
|
477
|
+
chilliJSON.reply = function ( raw ) {
|
478
|
+
|
479
|
+
clearInterval ( chilliJSON.timer ) ;
|
480
|
+
chilliJSON.timer = 0 ;
|
481
|
+
|
482
|
+
var now = new Date() ;
|
483
|
+
var end = now.getTime() ;
|
484
|
+
|
485
|
+
if ( chilliJSON.timestamp ) {
|
486
|
+
log ( 'chilliJSON: JSON reply received in ' + ( end - chilliJSON.timestamp ) + ' ms\n' + dumpObject(raw) );
|
487
|
+
}
|
488
|
+
|
489
|
+
if ( typeof (chilliJSON.node) !== 'number' ) {
|
490
|
+
document.getElementsByTagName('head')[0].removeChild ( chilliJSON.node );
|
491
|
+
}
|
492
|
+
chilliJSON.node = 0;
|
493
|
+
|
494
|
+
/* TODO: We should parse raw JSON as an extra security measure */
|
495
|
+
|
496
|
+
chilliJSON.onJSONReady( raw ) ;
|
497
|
+
} ;
|
498
|
+
|
499
|
+
chilliJSON.get = function ( gUrl ) {
|
500
|
+
|
501
|
+
if ( typeof(gUrl) == "string" ) {
|
502
|
+
chilliJSON.url = gUrl ;
|
503
|
+
}
|
504
|
+
else {
|
505
|
+
log ( "chilliJSON:error:Incorrect url passed to chilliJSON.get():" + gUrl );
|
506
|
+
chilliJSON.onError ( "Incorrect url passed to chilliJSON.get() " );
|
507
|
+
return ;
|
508
|
+
}
|
509
|
+
|
510
|
+
if ( chilliJSON.timer ) {
|
511
|
+
log('logon: There is already a request running. Return without launching a new request.');
|
512
|
+
return ;
|
513
|
+
}
|
514
|
+
|
515
|
+
|
516
|
+
var scriptElement = document.createElement('script');
|
517
|
+
scriptElement.type = 'text/javascript';
|
518
|
+
|
519
|
+
var c ;
|
520
|
+
if ( this.url.indexOf('?') === -1 ) {
|
521
|
+
c = '?' ;
|
522
|
+
}
|
523
|
+
else {
|
524
|
+
c = '&' ;
|
525
|
+
}
|
526
|
+
|
527
|
+
scriptElement.src = chilliJSON.url + c + 'callback=chilliJSON.reply' ;
|
528
|
+
scriptElement.src += '&'+Math.random(); // prevent caching in Safari
|
529
|
+
|
530
|
+
/* Adding the node that will trigger the HTTP request to the DOM tree */
|
531
|
+
chilliJSON.node = document.getElementsByTagName('head')[0].appendChild(scriptElement);
|
532
|
+
|
533
|
+
/* Using interval instead of timeout to support Flash 5,6,7 */
|
534
|
+
chilliJSON.timer = setInterval ( 'chilliJSON.expired()' , chilliJSON.timeout ) ;
|
535
|
+
var now = new Date();
|
536
|
+
chilliJSON.timestamp = now.getTime() ;
|
537
|
+
|
538
|
+
log ('chilliJSON: getting ' + chilliJSON.url + ' . Waiting for reply ...');
|
539
|
+
|
540
|
+
}; // end chilliJSON.get = function ( url )
|
541
|
+
|
542
|
+
|
543
|
+
/**
|
544
|
+
* chilliClock object
|
545
|
+
*
|
546
|
+
* Can be used by BBSMs to display a count down.
|
547
|
+
*
|
548
|
+
* Will sync with chilliController and modulate the delay to call onTick
|
549
|
+
* This will avoid ugly sequence of short updates in the IO
|
550
|
+
* (not yet implemented)
|
551
|
+
*
|
552
|
+
*/
|
553
|
+
|
554
|
+
var chilliClock = { isStarted : 0 };
|
555
|
+
|
556
|
+
chilliClock.onTick = function () {
|
557
|
+
log ("You should define your own onTick() handler on this clock object. Clock value = " + this.value );
|
558
|
+
};
|
559
|
+
|
560
|
+
chilliClock.increment = function () {
|
561
|
+
|
562
|
+
chilliClock.value = chilliClock.value + 1 ;
|
563
|
+
chilliClock.onTick( chilliClock.value ) ;
|
564
|
+
};
|
565
|
+
|
566
|
+
chilliClock.resync = function ( newval ) {
|
567
|
+
clearInterval ( chilliClock.isStarted ) ;
|
568
|
+
chilliClock.value = parseInt( newval , 10 ) ;
|
569
|
+
chilliClock.isStarted = setInterval ( 'chilliClock.increment()' , 1000 );
|
570
|
+
};
|
571
|
+
|
572
|
+
chilliClock.start = function ( newval ) {
|
573
|
+
|
574
|
+
if ( typeof (newval) !== 'Number' ) {
|
575
|
+
chilliClock.resync ( 0 ) ;
|
576
|
+
}
|
577
|
+
else {
|
578
|
+
chilliClock.resync ( newval ) ;
|
579
|
+
}
|
580
|
+
};
|
581
|
+
|
582
|
+
chilliClock.stop = function () {
|
583
|
+
clearInterval ( chilliClock.isStarted ) ;
|
584
|
+
chilliClock.isStarted = 0 ;
|
585
|
+
};
|
586
|
+
|
587
|
+
|
588
|
+
function getel(e) {
|
589
|
+
if (document.getElementById) {
|
590
|
+
return document.getElementById(e);
|
591
|
+
} else if (document.all){
|
592
|
+
return document.all[e];
|
593
|
+
}
|
594
|
+
}
|
595
|
+
|
596
|
+
function log( msg , messageLevel ) {
|
597
|
+
if (!chilliController.debug) return;
|
598
|
+
if ( typeof(trace)=="function") {
|
599
|
+
// ActionScript trace
|
600
|
+
trace ( msg );
|
601
|
+
}
|
602
|
+
else if ( typeof(console)=="object") {
|
603
|
+
// FireBug console
|
604
|
+
console.debug ( msg );
|
605
|
+
}
|
606
|
+
|
607
|
+
if ( getel('debugarea') ) {
|
608
|
+
var e = getel('debugarea') ;
|
609
|
+
e.value = e.value + '\n' + msg;
|
610
|
+
e.scrollTop = e.scrollHeight - e.clientHeight;
|
611
|
+
}
|
612
|
+
}
|
613
|
+
|
614
|
+
/* Transform an object to a text representation */
|
615
|
+
function dumpObject ( obj ) {
|
616
|
+
|
617
|
+
var str = '' ;
|
618
|
+
|
619
|
+
for (var key in obj ) {
|
620
|
+
str = str + " " + key + " = " + obj[key] + "\n" ;
|
621
|
+
if ( typeof ( obj[key] ) == "object" ) {
|
622
|
+
for ( var key2 in obj[key] ) {
|
623
|
+
str = str + " " + key2 + " = " + obj[key][key2] + "\n" ;
|
624
|
+
}
|
625
|
+
}
|
626
|
+
}
|
627
|
+
|
628
|
+
return str;
|
629
|
+
}
|
630
|
+
|
631
|
+
/*
|
632
|
+
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
|
633
|
+
* Digest Algorithm, as defined in RFC 1321.
|
634
|
+
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
|
635
|
+
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
636
|
+
* Distributed under the BSD License
|
637
|
+
* See http://pajhome.org.uk/crypt/md5 for more info.
|
638
|
+
*
|
639
|
+
* added by Y.DELTROO
|
640
|
+
* - new functions: chap(), hex2binl() and str2hex()
|
641
|
+
* - modifications to comply with the jslint test, http://www.jslint.com/
|
642
|
+
*
|
643
|
+
* Copyright (c) 2007
|
644
|
+
* Distributed under the BSD License
|
645
|
+
*
|
646
|
+
*/
|
647
|
+
|
648
|
+
|
649
|
+
function ChilliMD5() {
|
650
|
+
|
651
|
+
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
|
652
|
+
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
|
653
|
+
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
|
654
|
+
|
655
|
+
this.hex_md5 = function (s){
|
656
|
+
return binl2hex(core_md5(str2binl(s), s.length * chrsz));
|
657
|
+
};
|
658
|
+
|
659
|
+
this.chap = function ( hex_ident , str_password , hex_chal ) {
|
660
|
+
|
661
|
+
// Convert everything to hex encoded strings
|
662
|
+
var hex_password = str2hex ( str_password );
|
663
|
+
|
664
|
+
// concatenate hex encoded strings
|
665
|
+
var hex = hex_ident + hex_password + hex_chal;
|
666
|
+
|
667
|
+
// Convert concatenated hex encoded string to its binary representation
|
668
|
+
var bin = hex2binl ( hex ) ;
|
669
|
+
|
670
|
+
// Calculate MD5 on binary representation
|
671
|
+
var md5 = core_md5( bin , hex.length * 4 ) ;
|
672
|
+
|
673
|
+
return binl2hex( md5 );
|
674
|
+
};
|
675
|
+
|
676
|
+
function core_md5(x, len) {
|
677
|
+
x[len >> 5] |= 0x80 << ((len) % 32);
|
678
|
+
x[(((len + 64) >>> 9) << 4) + 14] = len;
|
679
|
+
|
680
|
+
var a = 1732584193;
|
681
|
+
var b = -271733879;
|
682
|
+
var c = -1732584194;
|
683
|
+
var d = 271733878;
|
684
|
+
|
685
|
+
for(var i = 0; i < x.length; i += 16) {
|
686
|
+
var olda = a;
|
687
|
+
var oldb = b;
|
688
|
+
var oldc = c;
|
689
|
+
var oldd = d;
|
690
|
+
|
691
|
+
a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
|
692
|
+
d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
|
693
|
+
c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
|
694
|
+
b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
|
695
|
+
a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
|
696
|
+
d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
|
697
|
+
c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
|
698
|
+
b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
|
699
|
+
a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
|
700
|
+
d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
|
701
|
+
c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
|
702
|
+
b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
|
703
|
+
a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
|
704
|
+
d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
|
705
|
+
c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
|
706
|
+
b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
|
707
|
+
|
708
|
+
a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
|
709
|
+
d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
|
710
|
+
c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
|
711
|
+
b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
|
712
|
+
a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
|
713
|
+
d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
|
714
|
+
c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
|
715
|
+
b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
|
716
|
+
a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
|
717
|
+
d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
|
718
|
+
c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
|
719
|
+
b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
|
720
|
+
a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
|
721
|
+
d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
|
722
|
+
c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
|
723
|
+
b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
|
724
|
+
|
725
|
+
a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
|
726
|
+
d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
|
727
|
+
c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
|
728
|
+
b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
|
729
|
+
a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
|
730
|
+
d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
|
731
|
+
c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
|
732
|
+
b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
|
733
|
+
a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
|
734
|
+
d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
|
735
|
+
c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
|
736
|
+
b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
|
737
|
+
a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
|
738
|
+
d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
|
739
|
+
c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
|
740
|
+
b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
|
741
|
+
|
742
|
+
a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
|
743
|
+
d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
|
744
|
+
c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
|
745
|
+
b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
|
746
|
+
a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
|
747
|
+
d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
|
748
|
+
c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
|
749
|
+
b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
|
750
|
+
a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
|
751
|
+
d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
|
752
|
+
c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
|
753
|
+
b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
|
754
|
+
a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
|
755
|
+
d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
|
756
|
+
c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
|
757
|
+
b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
|
758
|
+
|
759
|
+
a = safe_add(a, olda);
|
760
|
+
b = safe_add(b, oldb);
|
761
|
+
c = safe_add(c, oldc);
|
762
|
+
d = safe_add(d, oldd);
|
763
|
+
}
|
764
|
+
return [ a, b, c, d ];
|
765
|
+
|
766
|
+
}
|
767
|
+
|
768
|
+
function md5_cmn(q, a, b, x, s, t) {
|
769
|
+
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
|
770
|
+
}
|
771
|
+
|
772
|
+
function md5_ff(a, b, c, d, x, s, t) {
|
773
|
+
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
|
774
|
+
}
|
775
|
+
|
776
|
+
function md5_gg(a, b, c, d, x, s, t) {
|
777
|
+
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
|
778
|
+
}
|
779
|
+
|
780
|
+
function md5_hh(a, b, c, d, x, s, t) {
|
781
|
+
return md5_cmn(b ^ c ^ d, a, b, x, s, t);
|
782
|
+
}
|
783
|
+
|
784
|
+
function md5_ii(a, b, c, d, x, s, t) {
|
785
|
+
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
|
786
|
+
}
|
787
|
+
|
788
|
+
function safe_add(x, y) {
|
789
|
+
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
|
790
|
+
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
791
|
+
return (msw << 16) | (lsw & 0xFFFF);
|
792
|
+
}
|
793
|
+
function bit_rol(num, cnt) {
|
794
|
+
return (num << cnt) | (num >>> (32 - cnt));
|
795
|
+
}
|
796
|
+
|
797
|
+
function str2binl(str) {
|
798
|
+
var bin = [] ;
|
799
|
+
var mask = (1 << chrsz) - 1;
|
800
|
+
for (var i = 0; i < str.length * chrsz; i += chrsz) {
|
801
|
+
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
|
802
|
+
}
|
803
|
+
return bin;
|
804
|
+
}
|
805
|
+
|
806
|
+
function binl2hex(binarray) {
|
807
|
+
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
|
808
|
+
var str = "";
|
809
|
+
for (var i = 0; i < binarray.length * 4; i++) {
|
810
|
+
str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
|
811
|
+
hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);
|
812
|
+
}
|
813
|
+
return str;
|
814
|
+
}
|
815
|
+
|
816
|
+
function str2hex ( str ) {
|
817
|
+
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
|
818
|
+
var hex = '';
|
819
|
+
var val ;
|
820
|
+
for ( var i=0 ; i<str.length ; i++) {
|
821
|
+
/* TODO: adapt this if chrz=16 */
|
822
|
+
val = str.charCodeAt(i);
|
823
|
+
hex = hex + hex_tab.charAt( val/16 );
|
824
|
+
hex = hex + hex_tab.charAt( val%16 );
|
825
|
+
}
|
826
|
+
return hex;
|
827
|
+
}
|
828
|
+
|
829
|
+
function hex2binl ( hex ) {
|
830
|
+
/* Clean-up hex encoded input string */
|
831
|
+
hex = hex.toLowerCase() ;
|
832
|
+
hex = hex.replace( / /g , "");
|
833
|
+
|
834
|
+
var bin =[] ;
|
835
|
+
|
836
|
+
/* Transfrom to array of integers (binary representation) */
|
837
|
+
for ( i=0 ; i < hex.length*4 ; i=i+8 ) {
|
838
|
+
octet = parseInt( hex.substr( i/4 , 2) , 16) ;
|
839
|
+
bin[i>>5] |= ( octet & 255 ) << (i%32);
|
840
|
+
}
|
841
|
+
return bin;
|
842
|
+
}
|
843
|
+
|
844
|
+
} // end of ChilliMD5 constructor
|