From 15bb6e0a85bf40f8fa2ac072c04725b39eb7936d Mon Sep 17 00:00:00 2001 From: Raphael Gauthier Date: Wed, 12 Jul 2023 14:01:04 +0200 Subject: [PATCH] Fixes #23060: Rewrite angular app \"passwordForm\" in JavaScript --- .../javascript/rudder/angular/passwordForm.js | 7 +- .../javascript/rudder/directive-inputs.js | 352 ++++++++++++++++++ .../web/model/DirectiveFieldEditors.scala | 38 +- .../main/style/rudder/rudder-directives.css | 3 + .../src/main/style/rudder/rudder-main.css | 4 + .../rudder-web/src/main/webapp/index.html | 2 +- .../components/passwordInput.html | 178 ++++----- 7 files changed, 472 insertions(+), 112 deletions(-) diff --git a/webapp/sources/rudder/rudder-web/src/main/javascript/rudder/angular/passwordForm.js b/webapp/sources/rudder/rudder-web/src/main/javascript/rudder/angular/passwordForm.js index 09ea459abdd..a769af75bc4 100644 --- a/webapp/sources/rudder/rudder-web/src/main/javascript/rudder/angular/passwordForm.js +++ b/webapp/sources/rudder/rudder-web/src/main/javascript/rudder/angular/passwordForm.js @@ -89,10 +89,7 @@ passwordModule.controller("passwordController", function($scope) { $scope.current.isScript = isScript; } defaultHash = currentHash - if (current === undefined) { - currentAction = "change" - $scope.action = "change"; - } + if (currentAction === "change") { $scope.newPassword.password=current; $scope.newPassword.hash = currentHash; @@ -114,7 +111,7 @@ passwordModule.controller("passwordController", function($scope) { } $scope.hashes = hashes; $scope.displayedPass = $scope.current.password; - $scope.action = currentAction; + $scope.action = currentAction === undefined ? "change" : currentAction; $scope.otherPasswords = otherPasswords; $scope.canBeDeleted = canBeDeleted; $scope.scriptEnabled = scriptEnabled; diff --git a/webapp/sources/rudder/rudder-web/src/main/javascript/rudder/directive-inputs.js b/webapp/sources/rudder/rudder-web/src/main/javascript/rudder/directive-inputs.js index 50d5fd2722d..d1efb02bdf6 100644 --- a/webapp/sources/rudder/rudder-web/src/main/javascript/rudder/directive-inputs.js +++ b/webapp/sources/rudder/rudder-web/src/main/javascript/rudder/directive-inputs.js @@ -36,6 +36,7 @@ // Dict containing all directive input data var directiveInputs = new Object(); +var passwordForms = new Object(); function newInputText(id, value, prefix, featureEnabled){ // New input data @@ -93,4 +94,355 @@ function updateResult(element){ var newValue = inputModel.feature ? (inputModel.prefix + value) : value; var inputResult = $("#" + formId + "-value"); inputResult.val(newValue); +} + + +// === Password field +class PasswordForm { + // Current password, and 'other passwords' defined if there is a 'slave' field, displayedPass is the pass we currently display + current = + { password : undefined + , hash : "md5" + , show : false + , isScript : false + }; + + otherPasswords = undefined; + displayedPass = undefined; + + // New password if we want to change it + newPassword = + { password : undefined + , hash : "md5" + , show : false + , isScript : false + }; + + // Possible hashes defined for this password input + hashes = {}; + #defaultHash = undefined; + + // Default value + action = "keep"; + formType = "withHashes"; + canBeDeleted = false; + scriptEnabled = false; + + // Result (the value that will be sent back to Lift form), initialized as undefined, but will be update directly and on every change of action and the new password (so will be changed on init) + result = undefined; + + formId = ""; + + constructor(currentValue, currentHash, isScript, currentAction, hashes, otherPasswords, canBeDeleted, scriptEnabled, previousHash, previousAlgo, previousIsScript, formId) { + console.log(currentHash) + this.defaultHash = currentHash; + + if (currentAction === "keep") { + this.current.password = currentValue; + this.current.hash = currentHash; + this.current.isScript = isScript; + + } else if (currentAction === "change") { + this.newPassword.password = currentValue; + this.newPassword.hash = currentHash; + this.newPassword.isScript = isScript; + + if (isScript) { + this.formType = "script"; + } else if (currentHash === "pre-hashed") { + this.formType = "preHashed"; + } else if (currentHash === "plain") { + this.formType = "clearText"; + } else { + this.formType = "withHashes"; + } + + this.current.password = previousPass; + this.current.hash = previousHash; + this.current.isScript = previousIsScript; + } + + this.hashes = hashes; + this.displayedPass = this.current.password; + this.action = currentAction === undefined ? "change" : currentAction; + this.otherPasswords = otherPasswords; + this.canBeDeleted = canBeDeleted; + this.scriptEnabled = scriptEnabled; + + this.formId = formId; + } + + updateView() { + console.log("updating view") + updatePasswordFormView(this.formId); + } + + updateResult() { + // Keep and delete, use current password as base + let result = this.action === "change" ? Object.assign({}, this.newPassword) : Object.assign({}, this.current) + + if (result.hash === "plain" && result.isScript) { + result.password = "evaljs:" + result.password; + } + + // Action will allow to differentiate between 'delete' and 'keep' and is used for 'change' too + result.action = this.action + this.result = JSON.stringify(result); + + // Update html + this.updateView(); + } + + displayCurrentHash() { + if (this.current.hash === "plain") { + return "Clear text password"; + } else if (this.current.hash === "pre-hashed") { + return "Pre hashed password"; + } else { + return this.hashes[this.current.hash] + " hash"; + } + } + + changeDisplayPass(password) { + this.displayedPass = password; + this.updateView(); + } + + passwordType(formType) { + this.newPassword.isScript = false; + if(formType === "withHashes") { + // If no hash was set put it to default hash + this.newPassword.hash = this.defaultHash; + } else if (formType === "clearText") { + this.newPassword.hash = "plain"; + } else if (formType === "preHashed") { + this.newPassword.hash = "pre-hashed"; + } else if (formType === "script") { + this.newPassword.hash = "plain"; + this.newPassword.isScript = true; + } + this.formType = formType; + + console.log("-- Change form type & update result & view"); + this.updateResult(); + } + + changeAction(action) { + this.action = action; + if (action === "change") { + if (this.current.isScript) { + this.formType = "script"; + this.newPassword = this.current; + } else if (this.current.hash === "pre-hashed") { + this.formType = "preHashed"; + } else if (this.current.hash === "plain") { + this.formType = "clearText"; + } else { + this.formType = "withHashes"; + } + this.newPassword.hash = this.current.hash; + } + console.log("-- Change action & update result & view"); + this.updateResult(); + } + + // Do not display current password if undefined or if you want to delete password + displayCurrent() { + return this.current.password !== undefined && this.action !== 'delete'; + } + + revealPassword(passwd){ + if (passwd === "current"){ + this.current.show = !this.current.show; + }else{ + this.newPassword.show = !this.newPassword.show; + } + this.updateView(); + } +} + + +function initPasswordFormEvents(formId){ + // Get passwordForm data + var passwordForm = passwordForms[formId]; + if (passwordForm === undefined) return false; + + var formContainer = $('#' + formId); + + formContainer.find(".btn.reveal-password").on('click', function(){ + var data = $(this).attr('data-reveal'); + passwordForm.revealPassword(data); + }); + + // Init buttons that change the password type + formContainer.find("[data-form]").on('click', function(){ + var type = $(this).attr('data-form'); + passwordForm.passwordType(type); + }); + + // Init buttons that change the current action + formContainer.find("[data-action]").on('click', function(){ + var action = $(this).attr("data-action"); + passwordForm.changeAction(action); + }); + + // Init passwords dropdown list + var btnToggle = formContainer.find(".dropdown-toggle"); + var ulToggle = formContainer.find(".dropdown-menu"); + if(passwordForm.otherPasswords !== undefined){ + var li = $("
  • "); + var a = $("").text("Default").on('click', function(){ + passwordForm.changeDisplayPass(passwordForm.otherPasswords[passwordForm.current.password]); + }); + li.append(a); + ulToggle.append(li) + for (pwd in passwordForm.otherPasswords){ + li = $("
  • "); + a = $("").text(pwd).on('click', function(){ + passwordForm.changeDisplayPass(passwordForm.otherPasswords[pwd]); + }); + li.append(a); + ulToggle.append(li) + } + }else{ + btnToggle.hide(); + } + + // Update model when password changes + formContainer.find(".input-new-passwd").on("input", function(){ + var newVal = this.value; + // TODO : Check + //passwordForm.current.password = newVal; + //passwordForm.displayedPass = newVal; + console.log("-- Update value: "+ newVal) + }); + + // Hash algorithm select + var selectHash = formContainer.find(".new-password-hash"); + var hash, opt; + for (hash in passwordForm.hashes){ + opt = $("
    diff --git a/webapp/sources/rudder/rudder-web/src/main/webapp/templates-hidden/components/passwordInput.html b/webapp/sources/rudder/rudder-web/src/main/webapp/templates-hidden/components/passwordInput.html index a0efbe17071..df0b76259a8 100644 --- a/webapp/sources/rudder/rudder-web/src/main/webapp/templates-hidden/components/passwordInput.html +++ b/webapp/sources/rudder/rudder-web/src/main/webapp/templates-hidden/components/passwordInput.html @@ -1,121 +1,123 @@
    -
    -
    -
    - - +
    + +
    +
    + +
    + + + + + + + + + +
    +
    -
    +
    - - - - + + + +
    - +
    +
    -
    -

    Password will not be managed by Rudder anymore - + +
    +

    Password will not be managed by Rudder anymore +

    -
    + +
    -
    -
    -
    - - + +
    +
    +
    + +
    + + + +
    -
    -
    - -
    - - - This password will be hashed using the {{hashes[newPassword.hash]}} algorithm and stored and distributed only as a hash. - The plain text value entered above will not be stored. - +
    + +
    + + + This password will be hashed using the algorithm and stored and distributed only as a hash. The plain text value entered above will not be stored. + +
    -
    -
    -
    + +
    -
    - - - - -
    -
    - -
    - This {{formType === 'preHashed' ? "hash" : "password"}} will be stored and distributed verbatim (plain text). - + This will be stored and distributed verbatim (plain text). +
    -
    -
    -
    -
    - -
    - - - You can enter a JavaScript expression here. See documentation here for details.
    - Passwords will be computed for each node during policy generation. To use hashed passwords, make sure to call the rudder.password function in the script above. -
    + +
    +
    +
    + +
    + + + You can enter a JavaScript expression here. See documentation here for details.
    + Passwords will be computed for each node during policy generation. To use hashed passwords, make sure to call the rudder.password function in the script above. +
    +
    +
    +
    -
    -
    - + \ No newline at end of file