Commit 90175b9f 90175b9f481c2fe313d941a576b6ad7d0da7f7fe by Nicolas Perriault

added a 'safeLogs' option to blur password value in debug logs

1 parent 2ffa3112
...@@ -80,6 +80,7 @@ var Casper = function Casper(options) { ...@@ -80,6 +80,7 @@ var Casper = function Casper(options) {
80 exitOnError: true, 80 exitOnError: true,
81 logLevel: "error", 81 logLevel: "error",
82 httpStatusHandlers: {}, 82 httpStatusHandlers: {},
83 safeLogs: true,
83 onAlert: null, 84 onAlert: null,
84 onDie: null, 85 onDie: null,
85 onError: null, 86 onError: null,
...@@ -385,7 +386,7 @@ Casper.prototype.die = function die(message, status) { ...@@ -385,7 +386,7 @@ Casper.prototype.die = function die(message, status) {
385 * @return Casper 386 * @return Casper
386 */ 387 */
387 Casper.prototype.download = function download(url, targetPath, method, data) { 388 Casper.prototype.download = function download(url, targetPath, method, data) {
388 var cu = require('clientutils').create(); 389 var cu = require('clientutils').create(this.options);
389 try { 390 try {
390 fs.write(targetPath, cu.decode(this.base64encode(url, method, data)), 'wb'); 391 fs.write(targetPath, cu.decode(this.base64encode(url, method, data)), 'wb');
391 this.emit('downloaded.file', targetPath); 392 this.emit('downloaded.file', targetPath);
...@@ -700,8 +701,13 @@ Casper.prototype.injectClientUtils = function injectClientUtils() { ...@@ -700,8 +701,13 @@ Casper.prototype.injectClientUtils = function injectClientUtils() {
700 if (true === this.page.injectJs(clientUtilsPath)) { 701 if (true === this.page.injectJs(clientUtilsPath)) {
701 this.log("Successfully injected Casper client-side utilities", "debug"); 702 this.log("Successfully injected Casper client-side utilities", "debug");
702 } else { 703 } else {
703 this.log("Failed to instantiate Casper client-side utilities!", "warning"); 704 this.warn("Failed to inject Casper client-side utilities");
704 } 705 }
706 // ClientUtils and Casper shares the same options
707 // These are not the lines I'm the most proud of in my life, but it works.
708 this.page.evaluate(function() {
709 __utils__ = new ClientUtils(__options);
710 }.toString().replace('__options', JSON.stringify(this.options)));
705 }; 711 };
706 712
707 /** 713 /**
......
...@@ -28,14 +28,15 @@ ...@@ -28,14 +28,15 @@
28 * 28 *
29 */ 29 */
30 (function(exports) { 30 (function(exports) {
31 exports.create = function create() { 31 exports.create = function create(options) {
32 return new this.ClientUtils(); 32 return new this.ClientUtils(options);
33 }; 33 };
34 34
35 /** 35 /**
36 * Casper client-side helpers. 36 * Casper client-side helpers.
37 */ 37 */
38 exports.ClientUtils = function ClientUtils() { 38 exports.ClientUtils = function ClientUtils(options) {
39 // private members
39 var BASE64_ENCODE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 40 var BASE64_ENCODE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
40 var BASE64_DECODE_CHARS = new Array( 41 var BASE64_DECODE_CHARS = new Array(
41 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
...@@ -49,6 +50,9 @@ ...@@ -49,6 +50,9 @@
49 ); 50 );
50 var SUPPORTED_SELECTOR_TYPES = ['css', 'xpath']; 51 var SUPPORTED_SELECTOR_TYPES = ['css', 'xpath'];
51 52
53 // public members
54 this.options = options || {};
55
52 /** 56 /**
53 * Clicks on the DOM element behind the provided selector. 57 * Clicks on the DOM element behind the provided selector.
54 * 58 *
...@@ -185,7 +189,7 @@ ...@@ -185,7 +189,7 @@
185 files: [] 189 files: []
186 }; 190 };
187 if (!(form instanceof HTMLElement) || typeof form === "string") { 191 if (!(form instanceof HTMLElement) || typeof form === "string") {
188 __utils__.log("attempting to fetch form element from selector: '" + form + "'", "info"); 192 this.log("attempting to fetch form element from selector: '" + form + "'", "info");
189 try { 193 try {
190 form = this.findOne(form); 194 form = this.findOne(form);
191 } catch (e) { 195 } catch (e) {
...@@ -463,7 +467,7 @@ ...@@ -463,7 +467,7 @@
463 */ 467 */
464 this.setField = function setField(field, value) { 468 this.setField = function setField(field, value) {
465 var fields, out; 469 var fields, out;
466 value = value || ""; 470 value = logValue = (value || "");
467 if (field instanceof NodeList) { 471 if (field instanceof NodeList) {
468 fields = field; 472 fields = field;
469 field = fields[0]; 473 field = fields[0];
...@@ -471,11 +475,15 @@ ...@@ -471,11 +475,15 @@
471 if (!field instanceof HTMLElement) { 475 if (!field instanceof HTMLElement) {
472 this.log("Invalid field type; only HTMLElement and NodeList are supported", "error"); 476 this.log("Invalid field type; only HTMLElement and NodeList are supported", "error");
473 } 477 }
474 this.log('Set "' + field.getAttribute('name') + '" field value to ' + value, "debug"); 478 if (this.options && this.options.safeLogs && field.getAttribute('type') === "password") {
479 // obfuscate password value
480 logValue = Array(value.length + 1).join("*");
481 }
482 this.log('Set "' + field.getAttribute('name') + '" field value to ' + logValue, "debug");
475 try { 483 try {
476 field.focus(); 484 field.focus();
477 } catch (e) { 485 } catch (e) {
478 __utils__.log("Unable to focus() input field " + field.getAttribute('name') + ": " + e, "warning"); 486 this.log("Unable to focus() input field " + field.getAttribute('name') + ": " + e, "warning");
479 } 487 }
480 var nodeName = field.nodeName.toLowerCase(); 488 var nodeName = field.nodeName.toLowerCase();
481 switch (nodeName) { 489 switch (nodeName) {
...@@ -544,7 +552,7 @@ ...@@ -544,7 +552,7 @@
544 try { 552 try {
545 field.blur(); 553 field.blur();
546 } catch (err) { 554 } catch (err) {
547 __utils__.log("Unable to blur() input field " + field.getAttribute('name') + ": " + err, "warning"); 555 this.log("Unable to blur() input field " + field.getAttribute('name') + ": " + err, "warning");
548 } 556 }
549 return out; 557 return out;
550 }; 558 };
...@@ -570,7 +578,4 @@ ...@@ -570,7 +578,4 @@
570 } 578 }
571 }; 579 };
572 }; 580 };
573
574 // silly "hack" to force having an instance available
575 exports.__utils__ = new exports.ClientUtils();
576 })(typeof exports === "object" ? exports : window); 581 })(typeof exports === "object" ? exports : window);
......
1 <!DOCTYPE html> 1 <!DOCTYPE html>
2 <html> 2 <html>
3 <head> 3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5 <title>CasperJS test form</title> 5 <title>CasperJS test form</title>
6 </head> 6 </head>
7 <body> 7 <body>
8 <form action="result.html" enctype="multipart/form-data"> 8 <form action="result.html" enctype="multipart/form-data">
9 <input type="text" name="email" placeholder="email" /> 9 <input type="text" name="email" placeholder="email">
10 <input type="password" name="password" placeholder="password">
10 <textarea name="content"></textarea> 11 <textarea name="content"></textarea>
11 <select name="topic"> 12 <select name="topic">
12 <option>foo</option> 13 <option>foo</option>
13 <option value="bar">baz</option> 14 <option value="bar">baz</option>
14 </select> 15 </select>
15 <input type="checkbox" name="check" /> 16 <input type="checkbox" name="check">
16 <input type="radio" name="choice" value="yes"/> 17 <input type="radio" name="choice" value="yes">
17 <input type="radio" name="choice" value="no"/> 18 <input type="radio" name="choice" value="no">
18 <input type="file" name="file"/> 19 <input type="file" name="file">
19 <input type="checkbox" name="checklist[]" value="1" /> 20 <input type="checkbox" name="checklist[]" value="1">
20 <input type="checkbox" name="checklist[]" value="2" /> 21 <input type="checkbox" name="checklist[]" value="2">
21 <input type="checkbox" name="checklist[]" value="3" /> 22 <input type="checkbox" name="checklist[]" value="3">
22 <input type="submit" name="submit" value="submit" /> 23 <input type="submit" name="submit" value="submit">
23 </form> 24 </form>
24 </body> 25 </body>
25 </html> 26 </html>
......
...@@ -2,6 +2,7 @@ casper.start('tests/site/form.html', function() { ...@@ -2,6 +2,7 @@ casper.start('tests/site/form.html', function() {
2 this.test.comment('Casper.fill()'); 2 this.test.comment('Casper.fill()');
3 this.fill('form[action="result.html"]', { 3 this.fill('form[action="result.html"]', {
4 email: 'chuck@norris.com', 4 email: 'chuck@norris.com',
5 password: 'chuck',
5 content: 'Am watching thou', 6 content: 'Am watching thou',
6 check: true, 7 check: true,
7 choice: 'no', 8 choice: 'no',
...@@ -13,6 +14,9 @@ casper.start('tests/site/form.html', function() { ...@@ -13,6 +14,9 @@ casper.start('tests/site/form.html', function() {
13 return document.querySelector('input[name="email"]').value; 14 return document.querySelector('input[name="email"]').value;
14 }, 'chuck@norris.com', 'Casper.fill() can fill an input[type=text] form field'); 15 }, 'chuck@norris.com', 'Casper.fill() can fill an input[type=text] form field');
15 this.test.assertEvalEquals(function() { 16 this.test.assertEvalEquals(function() {
17 return document.querySelector('input[name="password"]').value;
18 }, 'chuck', 'Casper.fill() can fill an input[type=password] form field');
19 this.test.assertEvalEquals(function() {
16 return document.querySelector('textarea[name="content"]').value; 20 return document.querySelector('textarea[name="content"]').value;
17 }, 'Am watching thou', 'Casper.fill() can fill a textarea form field'); 21 }, 'Am watching thou', 'Casper.fill() can fill a textarea form field');
18 this.test.assertEvalEquals(function() { 22 this.test.assertEvalEquals(function() {
...@@ -41,6 +45,7 @@ casper.start('tests/site/form.html', function() { ...@@ -41,6 +45,7 @@ casper.start('tests/site/form.html', function() {
41 casper.then(function() { 45 casper.then(function() {
42 this.test.comment('Form submitted'); 46 this.test.comment('Form submitted');
43 this.test.assertUrlMatch(/email=chuck@norris.com/, 'Casper.fill() input[type=email] field was submitted'); 47 this.test.assertUrlMatch(/email=chuck@norris.com/, 'Casper.fill() input[type=email] field was submitted');
48 this.test.assertUrlMatch(/password=chuck/, 'Casper.fill() input[type=password] field was submitted');
44 this.test.assertUrlMatch(/content=Am\+watching\+thou/, 'Casper.fill() textarea field was submitted'); 49 this.test.assertUrlMatch(/content=Am\+watching\+thou/, 'Casper.fill() textarea field was submitted');
45 this.test.assertUrlMatch(/check=on/, 'Casper.fill() input[type=checkbox] field was submitted'); 50 this.test.assertUrlMatch(/check=on/, 'Casper.fill() input[type=checkbox] field was submitted');
46 this.test.assertUrlMatch(/choice=no/, 'Casper.fill() input[type=radio] field was submitted'); 51 this.test.assertUrlMatch(/choice=no/, 'Casper.fill() input[type=radio] field was submitted');
......