[483] | 1 | dojo.provide("dojox.sql._base"); |
---|
| 2 | dojo.require("dojox.sql._crypto"); |
---|
| 3 | |
---|
| 4 | dojo.mixin(dojox.sql, { |
---|
| 5 | // summary: |
---|
| 6 | // Executes a SQL expression. |
---|
| 7 | // description: |
---|
| 8 | // There are four ways to call this: |
---|
| 9 | // |
---|
| 10 | // 1. Straight SQL: dojox.sql("SELECT * FROM FOOBAR"); |
---|
| 11 | // 2. SQL with parameters: dojox.sql("INSERT INTO FOOBAR VALUES (?)", someParam) |
---|
| 12 | // 3. Encrypting particular values: |
---|
| 13 | // dojox.sql("INSERT INTO FOOBAR VALUES (ENCRYPT(?))", someParam, "somePassword", callback) |
---|
| 14 | // 4. Decrypting particular values: |
---|
| 15 | // | dojox.sql("SELECT DECRYPT(SOMECOL1), DECRYPT(SOMECOL2) FROM |
---|
| 16 | // | FOOBAR WHERE SOMECOL3 = ?", someParam, |
---|
| 17 | // | "somePassword", callback) |
---|
| 18 | // |
---|
| 19 | // For encryption and decryption the last two values should be the the password for |
---|
| 20 | // encryption/decryption, and the callback function that gets the result set. |
---|
| 21 | // |
---|
| 22 | // Note: We only support ENCRYPT(?) statements, and |
---|
| 23 | // and DECRYPT(*) statements for now -- you can not have a literal string |
---|
| 24 | // inside of these, such as ENCRYPT('foobar') |
---|
| 25 | // |
---|
| 26 | // Note: If you have multiple columns to encrypt and decrypt, you can use the following |
---|
| 27 | // convenience form to not have to type ENCRYPT(?)/DECRYPT(*) many times: |
---|
| 28 | // |
---|
| 29 | // | dojox.sql("INSERT INTO FOOBAR VALUES (ENCRYPT(?, ?, ?))", |
---|
| 30 | // | someParam1, someParam2, someParam3, |
---|
| 31 | // | "somePassword", callback) |
---|
| 32 | // | |
---|
| 33 | // | dojox.sql("SELECT DECRYPT(SOMECOL1, SOMECOL2) FROM |
---|
| 34 | // | FOOBAR WHERE SOMECOL3 = ?", someParam, |
---|
| 35 | // | "somePassword", callback) |
---|
| 36 | |
---|
| 37 | dbName: null, |
---|
| 38 | |
---|
| 39 | // debug: Boolean |
---|
| 40 | // If true, then we print out any SQL that is executed |
---|
| 41 | // to the debug window |
---|
| 42 | debug: (dojo.exists("dojox.sql.debug") ? dojox.sql.debug:false), |
---|
| 43 | |
---|
| 44 | open: function(dbName){ |
---|
| 45 | if(this._dbOpen && (!dbName || dbName == this.dbName)){ |
---|
| 46 | return; |
---|
| 47 | } |
---|
| 48 | |
---|
| 49 | if(!this.dbName){ |
---|
| 50 | this.dbName = "dot_store_" |
---|
| 51 | + window.location.href.replace(/[^0-9A-Za-z_]/g, "_"); |
---|
| 52 | // database names in Gears are limited to 64 characters long |
---|
| 53 | if(this.dbName.length > 63){ |
---|
| 54 | this.dbName = this.dbName.substring(0, 63); |
---|
| 55 | } |
---|
| 56 | } |
---|
| 57 | |
---|
| 58 | if(!dbName){ |
---|
| 59 | dbName = this.dbName; |
---|
| 60 | } |
---|
| 61 | |
---|
| 62 | try{ |
---|
| 63 | this._initDb(); |
---|
| 64 | this.db.open(dbName); |
---|
| 65 | this._dbOpen = true; |
---|
| 66 | }catch(exp){ |
---|
| 67 | throw exp.message||exp; |
---|
| 68 | } |
---|
| 69 | }, |
---|
| 70 | |
---|
| 71 | close: function(dbName){ |
---|
| 72 | // on Internet Explorer, Google Gears throws an exception |
---|
| 73 | // "Object not a collection", when we try to close the |
---|
| 74 | // database -- just don't close it on this platform |
---|
| 75 | // since we are running into a Gears bug; the Gears team |
---|
| 76 | // said it's ok to not close a database connection |
---|
| 77 | if(dojo.isIE){ return; } |
---|
| 78 | |
---|
| 79 | if(!this._dbOpen && (!dbName || dbName == this.dbName)){ |
---|
| 80 | return; |
---|
| 81 | } |
---|
| 82 | |
---|
| 83 | if(!dbName){ |
---|
| 84 | dbName = this.dbName; |
---|
| 85 | } |
---|
| 86 | |
---|
| 87 | try{ |
---|
| 88 | this.db.close(dbName); |
---|
| 89 | this._dbOpen = false; |
---|
| 90 | }catch(exp){ |
---|
| 91 | throw exp.message||exp; |
---|
| 92 | } |
---|
| 93 | }, |
---|
| 94 | |
---|
| 95 | _exec: function(params){ |
---|
| 96 | try{ |
---|
| 97 | // get the Gears Database object |
---|
| 98 | this._initDb(); |
---|
| 99 | |
---|
| 100 | // see if we need to open the db; if programmer |
---|
| 101 | // manually called dojox.sql.open() let them handle |
---|
| 102 | // it; otherwise we open and close automatically on |
---|
| 103 | // each SQL execution |
---|
| 104 | if(!this._dbOpen){ |
---|
| 105 | this.open(); |
---|
| 106 | this._autoClose = true; |
---|
| 107 | } |
---|
| 108 | |
---|
| 109 | // determine our parameters |
---|
| 110 | var sql = null; |
---|
| 111 | var callback = null; |
---|
| 112 | var password = null; |
---|
| 113 | |
---|
| 114 | var args = dojo._toArray(params); |
---|
| 115 | |
---|
| 116 | sql = args.splice(0, 1)[0]; |
---|
| 117 | |
---|
| 118 | // does this SQL statement use the ENCRYPT or DECRYPT |
---|
| 119 | // keywords? if so, extract our callback and crypto |
---|
| 120 | // password |
---|
| 121 | if(this._needsEncrypt(sql) || this._needsDecrypt(sql)){ |
---|
| 122 | callback = args.splice(args.length - 1, 1)[0]; |
---|
| 123 | password = args.splice(args.length - 1, 1)[0]; |
---|
| 124 | } |
---|
| 125 | |
---|
| 126 | // 'args' now just has the SQL parameters |
---|
| 127 | |
---|
| 128 | // print out debug SQL output if the developer wants that |
---|
| 129 | if(this.debug){ |
---|
| 130 | this._printDebugSQL(sql, args); |
---|
| 131 | } |
---|
| 132 | |
---|
| 133 | // handle SQL that needs encryption/decryption differently |
---|
| 134 | // do we have an ENCRYPT SQL statement? if so, handle that first |
---|
| 135 | var crypto; |
---|
| 136 | if(this._needsEncrypt(sql)){ |
---|
| 137 | crypto = new dojox.sql._SQLCrypto("encrypt", sql, |
---|
| 138 | password, args, |
---|
| 139 | callback); |
---|
| 140 | return null; // encrypted results will arrive asynchronously |
---|
| 141 | }else if(this._needsDecrypt(sql)){ // otherwise we have a DECRYPT statement |
---|
| 142 | crypto = new dojox.sql._SQLCrypto("decrypt", sql, |
---|
| 143 | password, args, |
---|
| 144 | callback); |
---|
| 145 | return null; // decrypted results will arrive asynchronously |
---|
| 146 | } |
---|
| 147 | |
---|
| 148 | // execute the SQL and get the results |
---|
| 149 | var rs = this.db.execute(sql, args); |
---|
| 150 | |
---|
| 151 | // Gears ResultSet object's are ugly -- normalize |
---|
| 152 | // these into something JavaScript programmers know |
---|
| 153 | // how to work with, basically an array of |
---|
| 154 | // JavaScript objects where each property name is |
---|
| 155 | // simply the field name for a column of data |
---|
| 156 | rs = this._normalizeResults(rs); |
---|
| 157 | |
---|
| 158 | if(this._autoClose){ |
---|
| 159 | this.close(); |
---|
| 160 | } |
---|
| 161 | |
---|
| 162 | return rs; |
---|
| 163 | }catch(exp){ |
---|
| 164 | exp = exp.message||exp; |
---|
| 165 | |
---|
| 166 | console.debug("SQL Exception: " + exp); |
---|
| 167 | |
---|
| 168 | if(this._autoClose){ |
---|
| 169 | try{ |
---|
| 170 | this.close(); |
---|
| 171 | }catch(e){ |
---|
| 172 | console.debug("Error closing database: " |
---|
| 173 | + e.message||e); |
---|
| 174 | } |
---|
| 175 | } |
---|
| 176 | |
---|
| 177 | throw exp; |
---|
| 178 | } |
---|
| 179 | |
---|
| 180 | return null; |
---|
| 181 | }, |
---|
| 182 | |
---|
| 183 | _initDb: function(){ |
---|
| 184 | if(!this.db){ |
---|
| 185 | try{ |
---|
| 186 | this.db = google.gears.factory.create('beta.database', '1.0'); |
---|
| 187 | }catch(exp){ |
---|
| 188 | dojo.setObject("google.gears.denied", true); |
---|
| 189 | if(dojox.off){ |
---|
| 190 | dojox.off.onFrameworkEvent("coreOperationFailed"); |
---|
| 191 | } |
---|
| 192 | throw "Google Gears must be allowed to run"; |
---|
| 193 | } |
---|
| 194 | } |
---|
| 195 | }, |
---|
| 196 | |
---|
| 197 | _printDebugSQL: function(sql, args){ |
---|
| 198 | var msg = "dojox.sql(\"" + sql + "\""; |
---|
| 199 | for(var i = 0; i < args.length; i++){ |
---|
| 200 | if(typeof args[i] == "string"){ |
---|
| 201 | msg += ", \"" + args[i] + "\""; |
---|
| 202 | }else{ |
---|
| 203 | msg += ", " + args[i]; |
---|
| 204 | } |
---|
| 205 | } |
---|
| 206 | msg += ")"; |
---|
| 207 | |
---|
| 208 | console.debug(msg); |
---|
| 209 | }, |
---|
| 210 | |
---|
| 211 | _normalizeResults: function(rs){ |
---|
| 212 | var results = []; |
---|
| 213 | if(!rs){ return []; } |
---|
| 214 | |
---|
| 215 | while(rs.isValidRow()){ |
---|
| 216 | var row = {}; |
---|
| 217 | |
---|
| 218 | for(var i = 0; i < rs.fieldCount(); i++){ |
---|
| 219 | var fieldName = rs.fieldName(i); |
---|
| 220 | var fieldValue = rs.field(i); |
---|
| 221 | row[fieldName] = fieldValue; |
---|
| 222 | } |
---|
| 223 | |
---|
| 224 | results.push(row); |
---|
| 225 | |
---|
| 226 | rs.next(); |
---|
| 227 | } |
---|
| 228 | |
---|
| 229 | rs.close(); |
---|
| 230 | |
---|
| 231 | return results; |
---|
| 232 | }, |
---|
| 233 | |
---|
| 234 | _needsEncrypt: function(sql){ |
---|
| 235 | return /encrypt\([^\)]*\)/i.test(sql); |
---|
| 236 | }, |
---|
| 237 | |
---|
| 238 | _needsDecrypt: function(sql){ |
---|
| 239 | return /decrypt\([^\)]*\)/i.test(sql); |
---|
| 240 | } |
---|
| 241 | }); |
---|
| 242 | |
---|
| 243 | dojo.declare("dojox.sql._SQLCrypto", null, { |
---|
| 244 | // summary: |
---|
| 245 | // A private class encapsulating any cryptography that must be done |
---|
| 246 | // on a SQL statement. We instantiate this class and have it hold |
---|
| 247 | // it's state so that we can potentially have several encryption |
---|
| 248 | // operations happening at the same time by different SQL statements. |
---|
| 249 | constructor: function(action, sql, password, args, callback){ |
---|
| 250 | if(action == "encrypt"){ |
---|
| 251 | this._execEncryptSQL(sql, password, args, callback); |
---|
| 252 | }else{ |
---|
| 253 | this._execDecryptSQL(sql, password, args, callback); |
---|
| 254 | } |
---|
| 255 | }, |
---|
| 256 | |
---|
| 257 | _execEncryptSQL: function(sql, password, args, callback){ |
---|
| 258 | // strip the ENCRYPT/DECRYPT keywords from the SQL |
---|
| 259 | var strippedSQL = this._stripCryptoSQL(sql); |
---|
| 260 | |
---|
| 261 | // determine what arguments need encryption |
---|
| 262 | var encryptColumns = this._flagEncryptedArgs(sql, args); |
---|
| 263 | |
---|
| 264 | // asynchronously encrypt each argument that needs it |
---|
| 265 | var self = this; |
---|
| 266 | this._encrypt(strippedSQL, password, args, encryptColumns, function(finalArgs){ |
---|
| 267 | // execute the SQL |
---|
| 268 | var error = false; |
---|
| 269 | var resultSet = []; |
---|
| 270 | var exp = null; |
---|
| 271 | try{ |
---|
| 272 | resultSet = dojox.sql.db.execute(strippedSQL, finalArgs); |
---|
| 273 | }catch(execError){ |
---|
| 274 | error = true; |
---|
| 275 | exp = execError.message||execError; |
---|
| 276 | } |
---|
| 277 | |
---|
| 278 | // was there an error during SQL execution? |
---|
| 279 | if(exp != null){ |
---|
| 280 | if(dojox.sql._autoClose){ |
---|
| 281 | try{ dojox.sql.close(); }catch(e){} |
---|
| 282 | } |
---|
| 283 | |
---|
| 284 | callback(null, true, exp.toString()); |
---|
| 285 | return; |
---|
| 286 | } |
---|
| 287 | |
---|
| 288 | // normalize SQL results into a JavaScript object |
---|
| 289 | // we can work with |
---|
| 290 | resultSet = dojox.sql._normalizeResults(resultSet); |
---|
| 291 | |
---|
| 292 | if(dojox.sql._autoClose){ |
---|
| 293 | dojox.sql.close(); |
---|
| 294 | } |
---|
| 295 | |
---|
| 296 | // are any decryptions necessary on the result set? |
---|
| 297 | if(dojox.sql._needsDecrypt(sql)){ |
---|
| 298 | // determine which of the result set columns needs decryption |
---|
| 299 | var needsDecrypt = self._determineDecryptedColumns(sql); |
---|
| 300 | |
---|
| 301 | // now decrypt columns asynchronously |
---|
| 302 | // decrypt columns that need it |
---|
| 303 | self._decrypt(resultSet, needsDecrypt, password, function(finalResultSet){ |
---|
| 304 | callback(finalResultSet, false, null); |
---|
| 305 | }); |
---|
| 306 | }else{ |
---|
| 307 | callback(resultSet, false, null); |
---|
| 308 | } |
---|
| 309 | }); |
---|
| 310 | }, |
---|
| 311 | |
---|
| 312 | _execDecryptSQL: function(sql, password, args, callback){ |
---|
| 313 | // strip the ENCRYPT/DECRYPT keywords from the SQL |
---|
| 314 | var strippedSQL = this._stripCryptoSQL(sql); |
---|
| 315 | |
---|
| 316 | // determine which columns needs decryption; this either |
---|
| 317 | // returns the value *, which means all result set columns will |
---|
| 318 | // be decrypted, or it will return the column names that need |
---|
| 319 | // decryption set on a hashtable so we can quickly test a given |
---|
| 320 | // column name; the key is the column name that needs |
---|
| 321 | // decryption and the value is 'true' (i.e. needsDecrypt["someColumn"] |
---|
| 322 | // would return 'true' if it needs decryption, and would be 'undefined' |
---|
| 323 | // or false otherwise) |
---|
| 324 | var needsDecrypt = this._determineDecryptedColumns(sql); |
---|
| 325 | |
---|
| 326 | // execute the SQL |
---|
| 327 | var error = false; |
---|
| 328 | var resultSet = []; |
---|
| 329 | var exp = null; |
---|
| 330 | try{ |
---|
| 331 | resultSet = dojox.sql.db.execute(strippedSQL, args); |
---|
| 332 | }catch(execError){ |
---|
| 333 | error = true; |
---|
| 334 | exp = execError.message||execError; |
---|
| 335 | } |
---|
| 336 | |
---|
| 337 | // was there an error during SQL execution? |
---|
| 338 | if(exp != null){ |
---|
| 339 | if(dojox.sql._autoClose){ |
---|
| 340 | try{ dojox.sql.close(); }catch(e){} |
---|
| 341 | } |
---|
| 342 | |
---|
| 343 | callback(resultSet, true, exp.toString()); |
---|
| 344 | return; |
---|
| 345 | } |
---|
| 346 | |
---|
| 347 | // normalize SQL results into a JavaScript object |
---|
| 348 | // we can work with |
---|
| 349 | resultSet = dojox.sql._normalizeResults(resultSet); |
---|
| 350 | |
---|
| 351 | if(dojox.sql._autoClose){ |
---|
| 352 | dojox.sql.close(); |
---|
| 353 | } |
---|
| 354 | |
---|
| 355 | // decrypt columns that need it |
---|
| 356 | this._decrypt(resultSet, needsDecrypt, password, function(finalResultSet){ |
---|
| 357 | callback(finalResultSet, false, null); |
---|
| 358 | }); |
---|
| 359 | }, |
---|
| 360 | |
---|
| 361 | _encrypt: function(sql, password, args, encryptColumns, callback){ |
---|
| 362 | //console.debug("_encrypt, sql="+sql+", password="+password+", encryptColumns="+encryptColumns+", args="+args); |
---|
| 363 | |
---|
| 364 | this._totalCrypto = 0; |
---|
| 365 | this._finishedCrypto = 0; |
---|
| 366 | this._finishedSpawningCrypto = false; |
---|
| 367 | this._finalArgs = args; |
---|
| 368 | |
---|
| 369 | for(var i = 0; i < args.length; i++){ |
---|
| 370 | if(encryptColumns[i]){ |
---|
| 371 | // we have an encrypt() keyword -- get just the value inside |
---|
| 372 | // the encrypt() parantheses -- for now this must be a ? |
---|
| 373 | var sqlParam = args[i]; |
---|
| 374 | var paramIndex = i; |
---|
| 375 | |
---|
| 376 | // update the total number of encryptions we know must be done asynchronously |
---|
| 377 | this._totalCrypto++; |
---|
| 378 | |
---|
| 379 | // FIXME: This currently uses DES as a proof-of-concept since the |
---|
| 380 | // DES code used is quite fast and was easy to work with. Modify dojox.sql |
---|
| 381 | // to be able to specify a different encryption provider through a |
---|
| 382 | // a SQL-like syntax, such as dojox.sql("SET ENCRYPTION BLOWFISH"), |
---|
| 383 | // and modify the dojox.crypto.Blowfish code to be able to work using |
---|
| 384 | // a Google Gears Worker Pool |
---|
| 385 | |
---|
| 386 | // do the actual encryption now, asychronously on a Gears worker thread |
---|
| 387 | dojox.sql._crypto.encrypt(sqlParam, password, dojo.hitch(this, function(results){ |
---|
| 388 | // set the new encrypted value |
---|
| 389 | this._finalArgs[paramIndex] = results; |
---|
| 390 | this._finishedCrypto++; |
---|
| 391 | // are we done with all encryption? |
---|
| 392 | if(this._finishedCrypto >= this._totalCrypto |
---|
| 393 | && this._finishedSpawningCrypto){ |
---|
| 394 | callback(this._finalArgs); |
---|
| 395 | } |
---|
| 396 | })); |
---|
| 397 | } |
---|
| 398 | } |
---|
| 399 | |
---|
| 400 | this._finishedSpawningCrypto = true; |
---|
| 401 | }, |
---|
| 402 | |
---|
| 403 | _decrypt: function(resultSet, needsDecrypt, password, callback){ |
---|
| 404 | //console.debug("decrypt, resultSet="+resultSet+", needsDecrypt="+needsDecrypt+", password="+password); |
---|
| 405 | |
---|
| 406 | this._totalCrypto = 0; |
---|
| 407 | this._finishedCrypto = 0; |
---|
| 408 | this._finishedSpawningCrypto = false; |
---|
| 409 | this._finalResultSet = resultSet; |
---|
| 410 | |
---|
| 411 | for(var i = 0; i < resultSet.length; i++){ |
---|
| 412 | var row = resultSet[i]; |
---|
| 413 | |
---|
| 414 | // go through each of the column names in row, |
---|
| 415 | // seeing if they need decryption |
---|
| 416 | for(var columnName in row){ |
---|
| 417 | if(needsDecrypt == "*" || needsDecrypt[columnName]){ |
---|
| 418 | this._totalCrypto++; |
---|
| 419 | var columnValue = row[columnName]; |
---|
| 420 | |
---|
| 421 | // forming a closure here can cause issues, with values not cleanly |
---|
| 422 | // saved on Firefox/Mac OS X for some of the values above that |
---|
| 423 | // are needed in the callback below; call a subroutine that will form |
---|
| 424 | // a closure inside of itself instead |
---|
| 425 | this._decryptSingleColumn(columnName, columnValue, password, i, |
---|
| 426 | function(finalResultSet){ |
---|
| 427 | callback(finalResultSet); |
---|
| 428 | }); |
---|
| 429 | } |
---|
| 430 | } |
---|
| 431 | } |
---|
| 432 | |
---|
| 433 | this._finishedSpawningCrypto = true; |
---|
| 434 | }, |
---|
| 435 | |
---|
| 436 | _stripCryptoSQL: function(sql){ |
---|
| 437 | // replace all DECRYPT(*) occurrences with a * |
---|
| 438 | sql = sql.replace(/DECRYPT\(\*\)/ig, "*"); |
---|
| 439 | |
---|
| 440 | // match any ENCRYPT(?, ?, ?, etc) occurrences, |
---|
| 441 | // then replace with just the question marks in the |
---|
| 442 | // middle |
---|
| 443 | var matches = sql.match(/ENCRYPT\([^\)]*\)/ig); |
---|
| 444 | if(matches != null){ |
---|
| 445 | for(var i = 0; i < matches.length; i++){ |
---|
| 446 | var encryptStatement = matches[i]; |
---|
| 447 | var encryptValue = encryptStatement.match(/ENCRYPT\(([^\)]*)\)/i)[1]; |
---|
| 448 | sql = sql.replace(encryptStatement, encryptValue); |
---|
| 449 | } |
---|
| 450 | } |
---|
| 451 | |
---|
| 452 | // match any DECRYPT(COL1, COL2, etc) occurrences, |
---|
| 453 | // then replace with just the column names |
---|
| 454 | // in the middle |
---|
| 455 | matches = sql.match(/DECRYPT\([^\)]*\)/ig); |
---|
| 456 | if(matches != null){ |
---|
| 457 | for(i = 0; i < matches.length; i++){ |
---|
| 458 | var decryptStatement = matches[i]; |
---|
| 459 | var decryptValue = decryptStatement.match(/DECRYPT\(([^\)]*)\)/i)[1]; |
---|
| 460 | sql = sql.replace(decryptStatement, decryptValue); |
---|
| 461 | } |
---|
| 462 | } |
---|
| 463 | |
---|
| 464 | return sql; |
---|
| 465 | }, |
---|
| 466 | |
---|
| 467 | _flagEncryptedArgs: function(sql, args){ |
---|
| 468 | // capture literal strings that have question marks in them, |
---|
| 469 | // and also capture question marks that stand alone |
---|
| 470 | var tester = new RegExp(/([\"][^\"]*\?[^\"]*[\"])|([\'][^\']*\?[^\']*[\'])|(\?)/ig); |
---|
| 471 | var matches; |
---|
| 472 | var currentParam = 0; |
---|
| 473 | var results = []; |
---|
| 474 | while((matches = tester.exec(sql)) != null){ |
---|
| 475 | var currentMatch = RegExp.lastMatch+""; |
---|
| 476 | |
---|
| 477 | // are we a literal string? then ignore it |
---|
| 478 | if(/^[\"\']/.test(currentMatch)){ |
---|
| 479 | continue; |
---|
| 480 | } |
---|
| 481 | |
---|
| 482 | // do we have an encrypt keyword to our left? |
---|
| 483 | var needsEncrypt = false; |
---|
| 484 | if(/ENCRYPT\([^\)]*$/i.test(RegExp.leftContext)){ |
---|
| 485 | needsEncrypt = true; |
---|
| 486 | } |
---|
| 487 | |
---|
| 488 | // set the encrypted flag |
---|
| 489 | results[currentParam] = needsEncrypt; |
---|
| 490 | |
---|
| 491 | currentParam++; |
---|
| 492 | } |
---|
| 493 | |
---|
| 494 | return results; |
---|
| 495 | }, |
---|
| 496 | |
---|
| 497 | _determineDecryptedColumns: function(sql){ |
---|
| 498 | var results = {}; |
---|
| 499 | |
---|
| 500 | if(/DECRYPT\(\*\)/i.test(sql)){ |
---|
| 501 | results = "*"; |
---|
| 502 | }else{ |
---|
| 503 | var tester = /DECRYPT\((?:\s*\w*\s*\,?)*\)/ig; |
---|
| 504 | var matches = tester.exec(sql); |
---|
| 505 | while(matches){ |
---|
| 506 | var lastMatch = new String(RegExp.lastMatch); |
---|
| 507 | var columnNames = lastMatch.replace(/DECRYPT\(/i, ""); |
---|
| 508 | columnNames = columnNames.replace(/\)/, ""); |
---|
| 509 | columnNames = columnNames.split(/\s*,\s*/); |
---|
| 510 | dojo.forEach(columnNames, function(column){ |
---|
| 511 | if(/\s*\w* AS (\w*)/i.test(column)){ |
---|
| 512 | column = column.match(/\s*\w* AS (\w*)/i)[1]; |
---|
| 513 | } |
---|
| 514 | results[column] = true; |
---|
| 515 | }); |
---|
| 516 | |
---|
| 517 | matches = tester.exec(sql) |
---|
| 518 | } |
---|
| 519 | } |
---|
| 520 | |
---|
| 521 | return results; |
---|
| 522 | }, |
---|
| 523 | |
---|
| 524 | _decryptSingleColumn: function(columnName, columnValue, password, currentRowIndex, |
---|
| 525 | callback){ |
---|
| 526 | //console.debug("decryptSingleColumn, columnName="+columnName+", columnValue="+columnValue+", currentRowIndex="+currentRowIndex) |
---|
| 527 | dojox.sql._crypto.decrypt(columnValue, password, dojo.hitch(this, function(results){ |
---|
| 528 | // set the new decrypted value |
---|
| 529 | this._finalResultSet[currentRowIndex][columnName] = results; |
---|
| 530 | this._finishedCrypto++; |
---|
| 531 | |
---|
| 532 | // are we done with all encryption? |
---|
| 533 | if(this._finishedCrypto >= this._totalCrypto |
---|
| 534 | && this._finishedSpawningCrypto){ |
---|
| 535 | //console.debug("done with all decrypts"); |
---|
| 536 | callback(this._finalResultSet); |
---|
| 537 | } |
---|
| 538 | })); |
---|
| 539 | } |
---|
| 540 | }); |
---|
| 541 | |
---|
| 542 | (function(){ |
---|
| 543 | |
---|
| 544 | var orig_sql = dojox.sql; |
---|
| 545 | dojox.sql = new Function("return dojox.sql._exec(arguments);"); |
---|
| 546 | dojo.mixin(dojox.sql, orig_sql); |
---|
| 547 | |
---|
| 548 | })(); |
---|