📄 offline.js.uncompressed.js
字号:
// determine our parameters var sql = null; var callback = null; var password = null; var args = dojo._toArray(params); sql = args.splice(0, 1)[0]; // does this SQL statement use the ENCRYPT or DECRYPT // keywords? if so, extract our callback and crypto // password if(this._needsEncrypt(sql) || this._needsDecrypt(sql)){ callback = args.splice(args.length - 1, 1)[0]; password = args.splice(args.length - 1, 1)[0]; } // 'args' now just has the SQL parameters // print out debug SQL output if the developer wants that if(this.debug){ this._printDebugSQL(sql, args); } // handle SQL that needs encryption/decryption differently // do we have an ENCRYPT SQL statement? if so, handle that first if(this._needsEncrypt(sql)){ var crypto = new dojox.sql._SQLCrypto("encrypt", sql, password, args, callback); return; // encrypted results will arrive asynchronously }else if(this._needsDecrypt(sql)){ // otherwise we have a DECRYPT statement var crypto = new dojox.sql._SQLCrypto("decrypt", sql, password, args, callback); return; // decrypted results will arrive asynchronously } // execute the SQL and get the results var rs = this.db.execute(sql, args); // Gears ResultSet object's are ugly -- normalize // these into something JavaScript programmers know // how to work with, basically an array of // JavaScript objects where each property name is // simply the field name for a column of data rs = this._normalizeResults(rs); if(this._autoClose){ this.close(); } return rs; }catch(exp){ exp = exp.message||exp; console.debug("SQL Exception: " + exp); if(this._autoClose){ try{ this.close(); }catch(e){ console.debug("Error closing database: " + e.message||e); } } throw exp; } }, _initDb: function(){ if(!this.db){ try{ this.db = google.gears.factory.create('beta.database', '1.0'); }catch(exp){ dojo.setObject("google.gears.denied", true); dojox.off.onFrameworkEvent("coreOperationFailed"); throw "Google Gears must be allowed to run"; } } }, _printDebugSQL: function(sql, args){ var msg = "dojox.sql(\"" + sql + "\""; for(var i = 0; i < args.length; i++){ if(typeof args[i] == "string"){ msg += ", \"" + args[i] + "\""; }else{ msg += ", " + args[i]; } } msg += ")"; console.debug(msg); }, _normalizeResults: function(rs){ var results = []; if(!rs){ return []; } while(rs.isValidRow()){ var row = {}; for(var i = 0; i < rs.fieldCount(); i++){ var fieldName = rs.fieldName(i); var fieldValue = rs.field(i); row[fieldName] = fieldValue; } results.push(row); rs.next(); } rs.close(); return results; }, _needsEncrypt: function(sql){ return /encrypt\([^\)]*\)/i.test(sql); }, _needsDecrypt: function(sql){ return /decrypt\([^\)]*\)/i.test(sql); }});// summary:// A private class encapsulating any cryptography that must be done// on a SQL statement. We instantiate this class and have it hold// it's state so that we can potentially have several encryption// operations happening at the same time by different SQL statements.dojo.declare("dojox.sql._SQLCrypto", null, { constructor: function(action, sql, password, args, callback){ if(action == "encrypt"){ this._execEncryptSQL(sql, password, args, callback); }else{ this._execDecryptSQL(sql, password, args, callback); } }, _execEncryptSQL: function(sql, password, args, callback){ // strip the ENCRYPT/DECRYPT keywords from the SQL var strippedSQL = this._stripCryptoSQL(sql); // determine what arguments need encryption var encryptColumns = this._flagEncryptedArgs(sql, args); // asynchronously encrypt each argument that needs it var self = this; this._encrypt(strippedSQL, password, args, encryptColumns, function(finalArgs){ // execute the SQL var error = false; var resultSet = []; var exp = null; try{ resultSet = dojox.sql.db.execute(strippedSQL, finalArgs); }catch(execError){ error = true; exp = execError.message||execError; } // was there an error during SQL execution? if(exp != null){ if(dojox.sql._autoClose){ try{ dojox.sql.close(); }catch(e){} } callback(null, true, exp.toString()); return; } // normalize SQL results into a JavaScript object // we can work with resultSet = dojox.sql._normalizeResults(resultSet); if(dojox.sql._autoClose){ dojox.sql.close(); } // are any decryptions necessary on the result set? if(dojox.sql._needsDecrypt(sql)){ // determine which of the result set columns needs decryption var needsDecrypt = self._determineDecryptedColumns(sql); // now decrypt columns asynchronously // decrypt columns that need it self._decrypt(resultSet, needsDecrypt, password, function(finalResultSet){ callback(finalResultSet, false, null); }); }else{ callback(resultSet, false, null); } }); }, _execDecryptSQL: function(sql, password, args, callback){ // strip the ENCRYPT/DECRYPT keywords from the SQL var strippedSQL = this._stripCryptoSQL(sql); // determine which columns needs decryption; this either // returns the value *, which means all result set columns will // be decrypted, or it will return the column names that need // decryption set on a hashtable so we can quickly test a given // column name; the key is the column name that needs // decryption and the value is 'true' (i.e. needsDecrypt["someColumn"] // would return 'true' if it needs decryption, and would be 'undefined' // or false otherwise) var needsDecrypt = this._determineDecryptedColumns(sql); // execute the SQL var error = false; var resultSet = []; var exp = null; try{ resultSet = dojox.sql.db.execute(strippedSQL, args); }catch(execError){ error = true; exp = execError.message||execError; } // was there an error during SQL execution? if(exp != null){ if(dojox.sql._autoClose){ try{ dojox.sql.close(); }catch(e){} } callback(resultSet, true, exp.toString()); return; } // normalize SQL results into a JavaScript object // we can work with resultSet = dojox.sql._normalizeResults(resultSet); if(dojox.sql._autoClose){ dojox.sql.close(); } // decrypt columns that need it this._decrypt(resultSet, needsDecrypt, password, function(finalResultSet){ callback(finalResultSet, false, null); }); }, _encrypt: function(sql, password, args, encryptColumns, callback){ //console.debug("_encrypt, sql="+sql+", password="+password+", encryptColumns="+encryptColumns+", args="+args); this._totalCrypto = 0; this._finishedCrypto = 0; this._finishedSpawningCrypto = false; this._finalArgs = args; for(var i = 0; i < args.length; i++){ if(encryptColumns[i]){ // we have an encrypt() keyword -- get just the value inside // the encrypt() parantheses -- for now this must be a ? var sqlParam = args[i]; var paramIndex = i; // update the total number of encryptions we know must be done asynchronously this._totalCrypto++; // FIXME: This currently uses DES as a proof-of-concept since the // DES code used is quite fast and was easy to work with. Modify dojox.sql // to be able to specify a different encryption provider through a // a SQL-like syntax, such as dojox.sql("SET ENCRYPTION BLOWFISH"), // and modify the dojox.crypto.Blowfish code to be able to work using // a Google Gears Worker Pool // do the actual encryption now, asychronously on a Gears worker thread dojox._sql._crypto.encrypt(sqlParam, password, dojo.hitch(this, function(results){ // set the new encrypted value this._finalArgs[paramIndex] = results; this._finishedCrypto++; // are we done with all encryption? if(this._finishedCrypto >= this._totalCrypto && this._finishedSpawningCrypto){ callback(this._finalArgs); } })); } } this._finishedSpawningCrypto = true; }, _decrypt: function(resultSet, needsDecrypt, password, callback){ //console.debug("decrypt, resultSet="+resultSet+", needsDecrypt="+needsDecrypt+", password="+password); this._totalCrypto = 0; this._finishedCrypto = 0; this._finishedSpawningCrypto = false; this._finalResultSet = resultSet; for(var i = 0; i < resultSet.length; i++){ var row = resultSet[i]; // go through each of the column names in row, // seeing if they need decryption for(var columnName in row){ if(needsDecrypt == "*" || needsDecrypt[columnName]){ this._totalCrypto++; var columnValue = row[columnName]; // forming a closure here can cause issues, with values not cleanly // saved on Firefox/Mac OS X for some of the values above that // are needed in the callback below; call a subroutine that will form // a closure inside of itself instead this._decryptSingleColumn(columnName, columnValue, password, i, function(finalResultSet){ callback(finalResultSet); }); } } } this._finishedSpawningCrypto = true; }, _stripCryptoSQL: function(sql){ // replace all DECRYPT(*) occurrences with a * sql = sql.replace(/DECRYPT\(\*\)/ig, "*"); // match any ENCRYPT(?, ?, ?, etc) occurrences, // then replace with just the question marks in the // middle var matches = sql.match(/ENCRYPT\([^\)]*\)/ig); if(matches != null){ for(var i = 0; i < matches.length; i++){ var encryptStatement = matches[i]; var encryptValue = encryptStatement.match(/ENCRYPT\(([^\)]*)\)/i)[1]; sql = sql.replace(encryptStatement, encryptValue); } } // match any DECRYPT(COL1, COL2, etc) occurrences, // then replace with just the column names // in the middle matches = sql.match(/DECRYPT\([^\)]*\)/ig); if(matches != null){ for(var i = 0; i < matches.length; i++){ var decryptStatement = matches[i]; var decryptValue = decryptStatement.match(/DECRYPT\(([^\)]*)\)/i)[1]; sql = sql.replace(decryptStatement, decryptValue); } } return sql; }, _flagEncryptedArgs: function(sql, args){ // capture literal strings that have question marks in them, // and also capture question marks that stand alone var tester = new RegExp(/([\"][^\"]*\?[^\"]*[\"])|([\'][^\']*\?[^\']*[\'])|(\?)/ig); var matches; var currentParam = 0; var results = []; while((matches = tester.exec(sql)) != null){ var currentMatch = RegExp.lastMatch+""; // are we a literal string? then ignore it if(/^[\"\']/.test(currentMatch)){ continue; } // do we have an encrypt keyword to our left? var needsEncrypt = false; if(/ENCRYPT\([^\)]*$/i.test(RegExp.leftContext)){ needsEncrypt = true; } // set the encrypted flag results[currentParam] = needsEncrypt; currentParam++; } return results; }, _determineDecryptedColumns: function(sql){ var results = {}; if(/DECRYPT\(\*\)/i.test(sql)){ results = "*";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -