github.com/lunarobliq/gophish@v0.8.1-0.20230523153303-93511002234d/static/js/src/app/users.js (about) 1 let users = [] 2 3 // Save attempts to POST or PUT to /users/ 4 const save = (id) => { 5 // Validate that the passwords match 6 if ($("#password").val() !== $("#confirm_password").val()) { 7 modalError("Passwords must match.") 8 return 9 } 10 let user = { 11 username: $("#username").val(), 12 password: $("#password").val(), 13 role: $("#role").val(), 14 password_change_required: $("#force_password_change_checkbox").prop('checked'), 15 account_locked: $("#account_locked_checkbox").prop('checked') 16 } 17 // Submit the user 18 if (id != -1) { 19 // If we're just editing an existing user, 20 // we need to PUT /user/:id 21 user.id = id 22 api.userId.put(user) 23 .success((data) => { 24 successFlash("User " + escapeHtml(user.username) + " updated successfully!") 25 load() 26 dismiss() 27 $("#modal").modal('hide') 28 }) 29 .error((data) => { 30 modalError(data.responseJSON.message) 31 }) 32 } else { 33 // Else, if this is a new user, POST it 34 // to /user 35 api.users.post(user) 36 .success((data) => { 37 successFlash("User " + escapeHtml(user.username) + " registered successfully!") 38 load() 39 dismiss() 40 $("#modal").modal('hide') 41 }) 42 .error((data) => { 43 modalError(data.responseJSON.message) 44 }) 45 } 46 } 47 48 const dismiss = () => { 49 $("#username").val("") 50 $("#password").val("") 51 $("#confirm_password").val("") 52 $("#role").val("") 53 $("#force_password_change_checkbox").prop('checked', true) 54 $("#account_locked_checkbox").prop('checked', false) 55 $("#modal\\.flashes").empty() 56 } 57 58 const edit = (id) => { 59 $("#username").attr("disabled", false); 60 $("#modalSubmit").unbind('click').click(() => { 61 save(id) 62 }) 63 $("#role").select2() 64 if (id == -1) { 65 $("#userModalLabel").text("New User") 66 $("#role").val("user") 67 $("#role").trigger("change") 68 } else { 69 $("#userModalLabel").text("Edit User") 70 api.userId.get(id) 71 .success((user) => { 72 $("#username").val(user.username) 73 $("#role").val(user.role.slug) 74 $("#role").trigger("change") 75 $("#force_password_change_checkbox").prop('checked', user.password_change_required) 76 $("#account_locked_checkbox").prop('checked', user.account_locked) 77 if (user.username == "admin") { 78 $("#username").attr("disabled", true); 79 } 80 }) 81 .error(function () { 82 errorFlash("Error fetching user") 83 }) 84 } 85 } 86 87 const deleteUser = (id) => { 88 var user = users.find(x => x.id == id) 89 if (!user) { 90 return 91 } 92 if (user.username == "admin") { 93 Swal.fire({ 94 title: "Unable to Delete User", 95 text: "The user account " + escapeHtml(user.username) + " cannot be deleted.", 96 type: "info" 97 }); 98 return 99 } 100 Swal.fire({ 101 title: "Are you sure?", 102 text: "This will delete the account for " + escapeHtml(user.username) + " as well as all of the objects they have created.\n\nThis can't be undone!", 103 type: "warning", 104 animation: false, 105 showCancelButton: true, 106 confirmButtonText: "Delete", 107 confirmButtonColor: "#428bca", 108 reverseButtons: true, 109 allowOutsideClick: false, 110 preConfirm: function () { 111 return new Promise((resolve, reject) => { 112 api.userId.delete(id) 113 .success((msg) => { 114 resolve() 115 }) 116 .error((data) => { 117 reject(data.responseJSON.message) 118 }) 119 }) 120 .catch(error => { 121 Swal.showValidationMessage(error) 122 }) 123 } 124 }).then(function (result) { 125 if (result.value){ 126 Swal.fire( 127 'User Deleted!', 128 "The user account for " + escapeHtml(user.username) + " and all associated objects have been deleted!", 129 'success' 130 ); 131 } 132 $('button:contains("OK")').on('click', function () { 133 location.reload() 134 }) 135 }) 136 } 137 138 const impersonate = (id) => { 139 var user = users.find(x => x.id == id) 140 if (!user) { 141 return 142 } 143 Swal.fire({ 144 title: "Are you sure?", 145 html: "You will be logged out of your account and logged in as <strong>" + escapeHtml(user.username) + "</strong>", 146 type: "warning", 147 animation: false, 148 showCancelButton: true, 149 confirmButtonText: "Swap User", 150 confirmButtonColor: "#428bca", 151 reverseButtons: true, 152 allowOutsideClick: false, 153 }).then((result) => { 154 if (result.value) { 155 156 fetch('/impersonate', { 157 method: 'post', 158 body: "username=" + user.username + "&csrf_token=" + encodeURIComponent(csrf_token), 159 headers: { 160 'Content-Type': 'application/x-www-form-urlencoded', 161 }, 162 }).then((response) => { 163 if (response.status == 200) { 164 Swal.fire({ 165 title: "Success!", 166 html: "Successfully changed to user <strong>" + escapeHtml(user.username) + "</strong>.", 167 type: "success", 168 showCancelButton: false, 169 confirmButtonText: "Home", 170 allowOutsideClick: false, 171 }).then((result) => { 172 if (result.value) { 173 window.location.href = "/" 174 }}); 175 } else { 176 Swal.fire({ 177 title: "Error!", 178 type: "error", 179 html: "Failed to change to user <strong>" + escapeHtml(user.username) + "</strong>.", 180 showCancelButton: false, 181 }) 182 } 183 }) 184 } 185 }) 186 } 187 188 const load = () => { 189 $("#userTable").hide() 190 $("#loading").show() 191 api.users.get() 192 .success((us) => { 193 users = us 194 $("#loading").hide() 195 $("#userTable").show() 196 let userTable = $("#userTable").DataTable({ 197 destroy: true, 198 columnDefs: [{ 199 orderable: false, 200 targets: "no-sort" 201 }] 202 }); 203 userTable.clear(); 204 userRows = [] 205 $.each(users, (i, user) => { 206 lastlogin = "" 207 if (user.last_login != "0001-01-01T00:00:00Z") { 208 lastlogin = moment(user.last_login).format('MMMM Do YYYY, h:mm:ss a') 209 } 210 userRows.push([ 211 escapeHtml(user.username), 212 escapeHtml(user.role.name), 213 lastlogin, 214 "<div class='pull-right'>\ 215 <button class='btn btn-warning impersonate_button' data-user-id='" + user.id + "'>\ 216 <i class='fa fa-retweet'></i>\ 217 </button>\ 218 <button class='btn btn-primary edit_button' data-toggle='modal' data-backdrop='static' data-target='#modal' data-user-id='" + user.id + "'>\ 219 <i class='fa fa-pencil'></i>\ 220 </button>\ 221 <button class='btn btn-danger delete_button' data-user-id='" + user.id + "'>\ 222 <i class='fa fa-trash-o'></i>\ 223 </button></div>" 224 ]) 225 }) 226 userTable.rows.add(userRows).draw(); 227 }) 228 .error(() => { 229 errorFlash("Error fetching users") 230 }) 231 } 232 233 $(document).ready(function () { 234 load() 235 // Setup the event listeners 236 $("#modal").on("hide.bs.modal", function () { 237 dismiss(); 238 }); 239 // Select2 Defaults 240 $.fn.select2.defaults.set("width", "100%"); 241 $.fn.select2.defaults.set("dropdownParent", $("#role-select")); 242 $.fn.select2.defaults.set("theme", "bootstrap"); 243 $.fn.select2.defaults.set("sorter", function (data) { 244 return data.sort(function (a, b) { 245 if (a.text.toLowerCase() > b.text.toLowerCase()) { 246 return 1; 247 } 248 if (a.text.toLowerCase() < b.text.toLowerCase()) { 249 return -1; 250 } 251 return 0; 252 }); 253 }) 254 $("#new_button").on("click", function () { 255 edit(-1) 256 }) 257 $("#userTable").on('click', '.edit_button', function (e) { 258 edit($(this).attr('data-user-id')) 259 }) 260 $("#userTable").on('click', '.delete_button', function (e) { 261 deleteUser($(this).attr('data-user-id')) 262 }) 263 $("#userTable").on('click', '.impersonate_button', function (e) { 264 impersonate($(this).attr('data-user-id')) 265 }) 266 });