PasswordValidator.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.form.PasswordValidator"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.form.PasswordValidator"] = true;
  8. dojo.provide("dojox.form.PasswordValidator");
  9. dojo.require("dijit.form._FormWidget");
  10. dojo.require("dijit.form.ValidationTextBox");
  11. dojo.requireLocalization("dojox.form", "PasswordValidator", null, "ROOT,ar,az,bg,ca,cs,da,de,el,es,fi,fr,he,hr,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw");
  12. dojo.declare("dojox.form._ChildTextBox", dijit.form.ValidationTextBox, {
  13. // summary:
  14. // A class that is shared between all our children - extends
  15. // ValidationTextBox and provides some shared functionality
  16. //
  17. // containerWidget: widget
  18. // Our parent (the PasswordValidator)
  19. containerWidget: null,
  20. // type: string
  21. // Don't override this - we are all "password" types
  22. type: "password",
  23. reset: function(){
  24. // summary:
  25. // Force-set to empty string (we don't save passwords EVER)...and
  26. // since _OldPWBox overrides _setValueAttr to check for empty string,
  27. // call our parent class directly (not this.inherited())
  28. dijit.form.ValidationTextBox.prototype._setValueAttr.call(this, "", true);
  29. this._hasBeenBlurred = false;
  30. },
  31. postCreate: function(){
  32. // summary:
  33. // We want to remove the "name" attribute from our focus node if
  34. // we don't have one set - this prevents all our extra values
  35. // from being posted on submit
  36. this.inherited(arguments);
  37. if(!this.name){
  38. dojo.removeAttr(this.focusNode, "name");
  39. }
  40. this.connect(this.focusNode, "onkeypress", "_onChildKeyPress");
  41. },
  42. _onChildKeyPress: function(e){
  43. // Check if we pressed <enter> - if so, set our blur value so that
  44. // the parent widget will be updated correctly.
  45. if(e && e.keyCode == dojo.keys.ENTER){
  46. this._setBlurValue();
  47. }
  48. }
  49. });
  50. dojo.declare("dojox.form._OldPWBox", dojox.form._ChildTextBox, {
  51. // summary:
  52. // A class representing our "old password" box.
  53. //
  54. // _isPWValid: boolean
  55. // Whether or not the password is valid
  56. _isPWValid: false,
  57. _setValueAttr: function(/* anything */ newVal, /* boolean? */ priority){
  58. // summary:
  59. // Updates _isPWValid if this isn't our initial update by calling
  60. // our PasswordValidator's pwCheck function
  61. if(newVal === ""){
  62. newVal = dojox.form._OldPWBox.superclass.attr.call(this, "value");
  63. }
  64. if(priority !== null){
  65. // Priority is passed in as null, explicitly when this is an
  66. // update (not initially set). We want to check our password now.
  67. this._isPWValid = this.containerWidget.pwCheck(newVal);
  68. }
  69. this.inherited(arguments);
  70. // Trigger the containerWidget to recheck its value, if needed
  71. this.containerWidget._childValueAttr(this.containerWidget._inputWidgets[1].get("value"));
  72. },
  73. isValid: function(/* boolean */ isFocused){
  74. // Take into account the isPWValid setting
  75. return this.inherited("isValid", arguments) && this._isPWValid;
  76. },
  77. _update: function(/* event */ e){
  78. // Only call validate() if we've been blurred or else we get popups
  79. // too early.
  80. if(this._hasBeenBlurred){ this.validate(true); }
  81. this._onMouse(e);
  82. },
  83. _getValueAttr: function(){
  84. if(this.containerWidget._started && this.containerWidget.isValid()){
  85. return this.inherited(arguments);
  86. }
  87. return "";
  88. },
  89. _setBlurValue: function(){
  90. // TextBox._setBlurValue calls this._setValueAttr(this.get('value'), ...)
  91. // Because we are overridding _getValueAttr to return "" when the containerWidget
  92. // is not valid, TextBox._setBlurValue will cause OldPWBox's value to be set to ""
  93. //
  94. // So, we directly call ValidationTextBox._getValueAttr to bypass our _getValueAttr
  95. var value = dijit.form.ValidationTextBox.prototype._getValueAttr.call(this);
  96. this._setValueAttr(value, (this.isValid ? this.isValid() : true));
  97. }
  98. });
  99. dojo.declare("dojox.form._NewPWBox", dojox.form._ChildTextBox, {
  100. // summary:
  101. // A class representing our new password textbox
  102. // required: boolean
  103. // Whether or not this widget is required (default: true)
  104. required: true,
  105. onChange: function(){
  106. // summary:
  107. // Validates our verify box - to make sure that a change to me is
  108. // reflected there
  109. this.containerWidget._inputWidgets[2].validate(false);
  110. this.inherited(arguments);
  111. }
  112. });
  113. dojo.declare("dojox.form._VerifyPWBox", dojox.form._ChildTextBox, {
  114. // summary:
  115. // A class representing our verify textbox
  116. isValid: function(isFocused){
  117. // summary:
  118. // Validates that we match the "real" password
  119. return this.inherited("isValid", arguments) &&
  120. (this.get("value") == this.containerWidget._inputWidgets[1].get("value"));
  121. }
  122. });
  123. dojo.declare("dojox.form.PasswordValidator", dijit.form._FormValueWidget, {
  124. // summary:
  125. // A password validation widget that simplifies the "old/new/verify"
  126. // style of requesting passwords. You will probably want to override
  127. // this class and implement your own pwCheck function.
  128. //
  129. // required: boolean
  130. // Whether or not it is required for form submission
  131. required: true,
  132. // inputWidgets: TextBox[]
  133. // An array of text boxes that are our components
  134. _inputWidgets: null,
  135. // oldName: string?
  136. // The name to send our old password as (when form is posted)
  137. oldName: "",
  138. templateString: dojo.cache("dojox.form", "resources/PasswordValidator.html", "<div dojoAttachPoint=\"containerNode\">\n\t<input type=\"hidden\" name=\"${name}\" value=\"\" dojoAttachPoint=\"focusNode\" />\n</div>\n"),
  139. _hasBeenBlurred: false,
  140. isValid: function(/* boolean */ isFocused){
  141. // summary: we are valid if ALL our children are valid
  142. return dojo.every(this._inputWidgets, function(i){
  143. if(i && i._setStateClass){ i._setStateClass(); }
  144. return (!i || i.isValid());
  145. });
  146. },
  147. validate: function(/* boolean */ isFocused){
  148. // summary: Validating this widget validates all our children
  149. return dojo.every(dojo.map(this._inputWidgets, function(i){
  150. if(i && i.validate){
  151. i._hasBeenBlurred = (i._hasBeenBlurred || this._hasBeenBlurred);
  152. return i.validate();
  153. }
  154. return true;
  155. }, this), "return item;");
  156. },
  157. reset: function(){
  158. // summary: Resetting this widget resets all our children
  159. this._hasBeenBlurred = false;
  160. dojo.forEach(this._inputWidgets, function(i){
  161. if(i && i.reset){ i.reset(); }
  162. }, this);
  163. },
  164. _createSubWidgets: function(){
  165. // summary:
  166. // Turns the inputs inside this widget into "real" validation
  167. // widgets - and sets up the needed connections.
  168. var widgets = this._inputWidgets,
  169. msg = dojo.i18n.getLocalization("dojox.form", "PasswordValidator", this.lang);
  170. dojo.forEach(widgets, function(i, idx){
  171. if(i){
  172. var p = {containerWidget: this}, c;
  173. if(idx === 0){
  174. p.name = this.oldName;
  175. p.invalidMessage = msg.badPasswordMessage;
  176. c = dojox.form._OldPWBox;
  177. }else if(idx === 1){
  178. p.required = this.required;
  179. c = dojox.form._NewPWBox;
  180. }else if(idx === 2){
  181. p.invalidMessage = msg.nomatchMessage;
  182. c = dojox.form._VerifyPWBox;
  183. }
  184. widgets[idx] = new c(p, i);
  185. }
  186. }, this);
  187. },
  188. pwCheck: function(/* string */ password){
  189. // summary:
  190. // Overridable function for validation of the old password box.
  191. //
  192. // This function is called and passed the old password. Return
  193. // true if it's OK to continue, and false if it is not.
  194. //
  195. // IMPORTANT SECURITY NOTE: Do NOT EVER EVER EVER check this in
  196. // HTML or JavaScript!!!
  197. //
  198. // You will probably want to override this function to callback
  199. // to a server to verify the password (the callback will need to
  200. // be syncronous) - and it's probably a good idea to validate
  201. // it again on form submission before actually doing
  202. // anything destructive - that's why the "oldName" value
  203. // is available.
  204. //
  205. // And don't just fetch the password from the server
  206. // either :) Send the test password (probably hashed, for
  207. // security) and return from the server a status instead.
  208. //
  209. // Again - DON'T BE INSECURE!!! Security is left as an exercise
  210. // for the reader :)
  211. return false;
  212. },
  213. postCreate: function(){
  214. // summary:
  215. // Sets up the correct widgets. You *MUST* specify one child
  216. // text box (a simple HTML <input> element) with pwType="new"
  217. // *and* one child text box with pwType="verify". You *MAY*
  218. // specify a third child text box with pwType="old" in order to
  219. // prompt the user to enter in their old password before the
  220. // widget returns that it is valid.
  221. this.inherited(arguments);
  222. // Turn my inputs into the correct stuff....
  223. var widgets = this._inputWidgets = [];
  224. dojo.forEach(["old","new","verify"], function(i){
  225. widgets.push(dojo.query("input[pwType=" + i + "]", this.containerNode)[0]);
  226. }, this);
  227. if (!widgets[1] || !widgets[2]){
  228. throw new Error("Need at least pwType=\"new\" and pwType=\"verify\"");
  229. }
  230. if (this.oldName && !widgets[0]){
  231. throw new Error("Need to specify pwType=\"old\" if using oldName");
  232. }
  233. this.containerNode = this.domNode;
  234. this._createSubWidgets();
  235. this.connect(this._inputWidgets[1], "_setValueAttr", "_childValueAttr");
  236. this.connect(this._inputWidgets[2], "_setValueAttr", "_childValueAttr");
  237. },
  238. _childValueAttr: function(v){
  239. this.set("value", this.isValid() ? v : "");
  240. },
  241. _setDisabledAttr: function(value){
  242. this.inherited(arguments);
  243. dojo.forEach(this._inputWidgets, function(i){
  244. if(i && i.set){ i.set("disabled", value);}
  245. });
  246. },
  247. _setRequiredAttribute: function(value){
  248. this.required = value;
  249. dojo.attr(this.focusNode, "required", value);
  250. dijit.setWaiState(this.focusNode, "required", value);
  251. this._refreshState();
  252. dojo.forEach(this._inputWidgets, function(i){
  253. if(i && i.set){ i.set("required", value);}
  254. });
  255. },
  256. _setValueAttr: function(v){
  257. this.inherited(arguments);
  258. dojo.attr(this.focusNode, "value", v);
  259. },
  260. _getValueAttr: function(){
  261. // Make sure we don't return undefined....
  262. return this.inherited(arguments)||"";
  263. },
  264. focus: function(){
  265. // summary:
  266. // places focus on the first invalid input widget - if all
  267. // input widgets are valid, the first widget is focused.
  268. var f = false;
  269. dojo.forEach(this._inputWidgets, function(i){
  270. if(i && !i.isValid() && !f){
  271. i.focus();
  272. f = true;
  273. }
  274. });
  275. if(!f){ this._inputWidgets[1].focus(); }
  276. }
  277. });
  278. }