Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 18119d54aa | |||
| 487e38f1a4 | |||
| 2e011dd383 | |||
| 3c12ebba16 |
@@ -4,6 +4,11 @@ All notable changes to this project are documented here. Format loosely
|
|||||||
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions
|
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions
|
||||||
correspond to git tags (`vX.Y.Z`) and `nodejs/package.json`'s `version`.
|
correspond to git tags (`vX.Y.Z`) and `nodejs/package.json`'s `version`.
|
||||||
|
|
||||||
|
## [1.6.1] - 2026-07-27
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- **Removed every native `alert()`/`confirm()` call**, replacing them with `app.messages.action`/`confirm`/`toast`. Native `confirm()` blocks all further browser events on the page (discovered live, mid browser-verification of the 1.6.0 `app.messages`/`app.modal` adoption, on `directory.ejs`'s "Rotate Client Secret" — it froze the whole tab). Also deleted `app.user.remove`/`app.oauthClient.remove` in `public/js/app.js`, which had native `confirm()` guards and zero callers anywhere in the app.
|
||||||
|
|
||||||
## [1.6.0] - 2026-07-27
|
## [1.6.0] - 2026-07-27
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "t42-sso-manager",
|
"name": "t42-sso-manager",
|
||||||
"version": "1.6.0",
|
"version": "1.6.1",
|
||||||
"description": "A very simple LDAP management and SSO system",
|
"description": "A very simple LDAP management and SSO system",
|
||||||
"author": [
|
"author": [
|
||||||
{
|
{
|
||||||
|
|||||||
+2
-16
@@ -67,13 +67,6 @@ app.user = (function(app){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function remove(args, callack){
|
|
||||||
if(!confirm('Delete '+ args.uid+ 'user?')) return false;
|
|
||||||
app.api.delete('user/'+ args.uid, function(error, data){
|
|
||||||
callack(error, data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function changePassword(args, callack){
|
function changePassword(args, callack){
|
||||||
app.api.put('users/'+ arg.uid || '', args, function(error, data){
|
app.api.put('users/'+ arg.uid || '', args, function(error, data){
|
||||||
callack(error, data);
|
callack(error, data);
|
||||||
@@ -110,7 +103,7 @@ app.user = (function(app){
|
|||||||
return m ? m[1] : dn;
|
return m ? m[1] : dn;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {list, remove, createInvite, setActive, dnToUid};
|
return {list, createInvite, setActive, dnToUid};
|
||||||
|
|
||||||
})(app);
|
})(app);
|
||||||
|
|
||||||
@@ -306,13 +299,6 @@ app.oauthClient = (function(app){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function remove(args, callack){
|
|
||||||
if(!confirm('Delete OAuth client "' + args.client_id + '"?')) return false;
|
|
||||||
app.api.delete('oauth/client/' + args.client_id, function(error, data){
|
|
||||||
callack(error, data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function update(args, callack){
|
function update(args, callack){
|
||||||
app.api.put('oauth/client/' + args.client_id, args, function(error, data){
|
app.api.put('oauth/client/' + args.client_id, args, function(error, data){
|
||||||
callack(error, data);
|
callack(error, data);
|
||||||
@@ -325,7 +311,7 @@ app.oauthClient = (function(app){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return { list, add, remove, update, rotateSecret };
|
return { list, add, update, rotateSecret };
|
||||||
})(app);
|
})(app);
|
||||||
|
|
||||||
app.tos = (function(app){
|
app.tos = (function(app){
|
||||||
|
|||||||
+21
-15
@@ -369,7 +369,7 @@
|
|||||||
renderTable();
|
renderTable();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
alert('Failed to load data');
|
app.messages.toast('Failed to load data', 'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -718,21 +718,22 @@
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
alert(err.message || 'Failed to save');
|
app.messages.action(err.message || 'Failed to save', $('#resourceModal'), 'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function rotateSecret() {
|
async function rotateSecret() {
|
||||||
const id = $('#res-id').val();
|
const id = $('#res-id').val();
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
if (!confirm('Are you sure you want to rotate the OAuth secret? Any existing integrations using the old secret will break.')) return;
|
const ok = await app.messages.confirm('Are you sure you want to rotate the OAuth secret? Any existing integrations using the old secret will break.', $('#resourceModal'), 'warning');
|
||||||
|
if (!ok) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await app.api.post(`directory-admin/resources/${id}/rotate-secret`);
|
const res = await app.api.post(`directory-admin/resources/${id}/rotate-secret`);
|
||||||
app.modal.open({title: 'Secret Rotated', bodyHtml: 'Save this NEW client secret, it will not be shown again: <br><br><code>' + res.secret + '</code>'});
|
app.modal.open({title: 'Secret Rotated', bodyHtml: 'Save this NEW client secret, it will not be shown again: <br><br><code>' + res.secret + '</code>'});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
alert(err.message || 'Failed to rotate secret');
|
app.messages.action(err.message || 'Failed to rotate secret', $('#resourceModal'), 'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -741,7 +742,7 @@
|
|||||||
const groupCn = $('#new-group-cn').val().trim();
|
const groupCn = $('#new-group-cn').val().trim();
|
||||||
const accessLevel = $('#new-group-level').val();
|
const accessLevel = $('#new-group-level').val();
|
||||||
|
|
||||||
if (!groupCn) return alert('Group CN is required');
|
if (!groupCn) return app.messages.action('Group CN is required', $('#resourceModal'), 'danger');
|
||||||
try {
|
try {
|
||||||
const res = await app.api.post('directory-admin/groups', {
|
const res = await app.api.post('directory-admin/groups', {
|
||||||
resourceId,
|
resourceId,
|
||||||
@@ -753,10 +754,10 @@
|
|||||||
$('#new-group-cn').val('');
|
$('#new-group-cn').val('');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
alert('Failed to add group');
|
app.messages.action('Failed to add group', $('#resourceModal'), 'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeGroup(id) {
|
async function removeGroup(id) {
|
||||||
try {
|
try {
|
||||||
await app.api.delete('directory-admin/groups/' + id);
|
await app.api.delete('directory-admin/groups/' + id);
|
||||||
@@ -764,7 +765,7 @@
|
|||||||
refreshGroupsUI($('#res-id').val());
|
refreshGroupsUI($('#res-id').val());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
alert('Failed to remove group');
|
app.messages.action('Failed to remove group', $('#resourceModal'), 'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -774,7 +775,7 @@
|
|||||||
const targetId = $('#new-edge-target').val();
|
const targetId = $('#new-edge-target').val();
|
||||||
const relation = $('#new-edge-relation').val().trim() || 'hosts';
|
const relation = $('#new-edge-relation').val().trim() || 'hosts';
|
||||||
|
|
||||||
if (!targetId) return alert('Select a target resource');
|
if (!targetId) return app.messages.action('Select a target resource', $('#resourceModal'), 'danger');
|
||||||
|
|
||||||
const data = { relation };
|
const data = { relation };
|
||||||
if (dir === 'parent') {
|
if (dir === 'parent') {
|
||||||
@@ -792,10 +793,10 @@
|
|||||||
$('#new-edge-target').val('');
|
$('#new-edge-target').val('');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
alert('Failed to add edge');
|
app.messages.action('Failed to add edge', $('#resourceModal'), 'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeEdge(id) {
|
async function removeEdge(id) {
|
||||||
try {
|
try {
|
||||||
await app.api.delete('directory-admin/edges/' + id);
|
await app.api.delete('directory-admin/edges/' + id);
|
||||||
@@ -803,18 +804,23 @@
|
|||||||
refreshEdgesUI($('#res-id').val());
|
refreshEdgesUI($('#res-id').val());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
alert('Failed to remove edge');
|
app.messages.action('Failed to remove edge', $('#resourceModal'), 'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteResource(id) {
|
async function deleteResource(id) {
|
||||||
if (!confirm('Are you sure you want to delete this resource? All relationships will be destroyed.')) return;
|
// Called from the outer table's row button, not from inside
|
||||||
|
// #resourceModal — target the page's own card so the confirm/error
|
||||||
|
// renders somewhere actually visible.
|
||||||
|
const $target = $('#resources-list');
|
||||||
|
const ok = await app.messages.confirm('Are you sure you want to delete this resource? All relationships will be destroyed.', $target, 'danger');
|
||||||
|
if (!ok) return;
|
||||||
try {
|
try {
|
||||||
await app.api.delete('directory-admin/resources/' + id);
|
await app.api.delete('directory-admin/resources/' + id);
|
||||||
await loadResources();
|
await loadResources();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
alert('Failed to delete');
|
app.messages.action('Failed to delete', $target, 'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -117,8 +117,8 @@
|
|||||||
const msgEl = document.getElementById('notif-result');
|
const msgEl = document.getElementById('notif-result');
|
||||||
const $compose = $('#notif-subject').closest('.card-body');
|
const $compose = $('#notif-subject').closest('.card-body');
|
||||||
|
|
||||||
if (!subject || !message) { alert('Subject and message are required.'); return; }
|
if (!subject || !message) { app.messages.action('Subject and message are required.', $compose, 'danger'); return; }
|
||||||
if (!filterCheck) { alert('Choose who to send this to.'); return; }
|
if (!filterCheck) { app.messages.action('Choose who to send this to.', $compose, 'danger'); return; }
|
||||||
const filterType = filterCheck.value;
|
const filterType = filterCheck.value;
|
||||||
|
|
||||||
let filter_value = '';
|
let filter_value = '';
|
||||||
@@ -179,7 +179,12 @@
|
|||||||
const resetAcceptance = document.getElementById('tos-reset-acceptance').checked;
|
const resetAcceptance = document.getElementById('tos-reset-acceptance').checked;
|
||||||
const msgEl = document.getElementById('tos-result');
|
const msgEl = document.getElementById('tos-result');
|
||||||
|
|
||||||
if (!content) { alert('Terms of Service text cannot be empty.'); return; }
|
if (!content) {
|
||||||
|
msgEl.className = 'alert alert-danger mt-2';
|
||||||
|
msgEl.textContent = 'Terms of Service text cannot be empty.';
|
||||||
|
msgEl.style.display = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
app.tos.update({content, resetAcceptance}, function(error, data) {
|
app.tos.update({content, resetAcceptance}, function(error, data) {
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
function startImpersonate(uid){
|
function startImpersonate(uid){
|
||||||
app.impersonate.create(uid, function(error, data){
|
app.impersonate.create(uid, function(error, data){
|
||||||
if(error){
|
if(error){
|
||||||
alert('Could not start impersonation: ' + (data && data.message ? data.message : 'Unknown error'));
|
app.messages.toast('Could not start impersonation: ' + (data && data.message ? data.message : 'Unknown error'), 'danger');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$('#impersonateModalTitle').text(data.uid);
|
$('#impersonateModalTitle').text(data.uid);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
async function acceptTos() {
|
async function acceptTos() {
|
||||||
var checkbox = document.getElementById('tosCheckbox');
|
var checkbox = document.getElementById('tosCheckbox');
|
||||||
if (!checkbox.checked) {
|
if (!checkbox.checked) {
|
||||||
alert('Please read and check the box to accept the Terms of Service.');
|
app.messages.toast('Please read and check the box to accept the Terms of Service.', 'danger');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -50,14 +50,14 @@
|
|||||||
document.getElementById('section-tos').style.display = 'none';
|
document.getElementById('section-tos').style.display = 'none';
|
||||||
checkAllDone();
|
checkAllDone();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
alert('Could not save TOS acceptance. Please try again.');
|
app.messages.toast('Could not save TOS acceptance. Please try again.', 'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveDob() {
|
async function saveDob() {
|
||||||
var dob = document.getElementById('dobInput').value;
|
var dob = document.getElementById('dobInput').value;
|
||||||
if (!dob) {
|
if (!dob) {
|
||||||
alert('Please enter your date of birth.');
|
app.messages.toast('Please enter your date of birth.', 'danger');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
document.getElementById('section-dob').style.display = 'none';
|
document.getElementById('section-dob').style.display = 'none';
|
||||||
checkAllDone();
|
checkAllDone();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
alert('Could not save date of birth. Please try again.');
|
app.messages.toast('Could not save date of birth. Please try again.', 'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,11 +81,11 @@
|
|||||||
var pw = document.getElementById('pwInput').value;
|
var pw = document.getElementById('pwInput').value;
|
||||||
var pw2 = document.getElementById('pwInput2').value;
|
var pw2 = document.getElementById('pwInput2').value;
|
||||||
if (!pw || pw.length < 5) {
|
if (!pw || pw.length < 5) {
|
||||||
alert('Password must be at least 5 characters.');
|
app.messages.toast('Password must be at least 5 characters.', 'danger');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (pw !== pw2) {
|
if (pw !== pw2) {
|
||||||
alert('Passwords do not match.');
|
app.messages.toast('Passwords do not match.', 'danger');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -101,7 +101,7 @@
|
|||||||
document.getElementById('section-password').style.display = 'none';
|
document.getElementById('section-password').style.display = 'none';
|
||||||
checkAllDone();
|
checkAllDone();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
alert('Could not change password. Please try again.');
|
app.messages.toast('Could not change password. Please try again.', 'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -176,7 +176,7 @@
|
|||||||
|
|
||||||
async function toggleActive(uid, active){
|
async function toggleActive(uid, active){
|
||||||
app.user.setActive(uid, active, async function(error, data){
|
app.user.setActive(uid, active, async function(error, data){
|
||||||
if(error) return alert('Failed to update user status');
|
if(error) return app.messages.toast('Failed to update user status', 'danger');
|
||||||
currentUser = await determinUser();
|
currentUser = await determinUser();
|
||||||
renderProfile(currentUser);
|
renderProfile(currentUser);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
function toggleActive(uid, active){
|
function toggleActive(uid, active){
|
||||||
app.user.setActive(uid, active, function(error, data){
|
app.user.setActive(uid, active, function(error, data){
|
||||||
if(error) return alert('Failed to update user status');
|
if(error) return app.messages.toast('Failed to update user status', 'danger');
|
||||||
renderUsers();
|
renderUsers();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -137,7 +137,7 @@
|
|||||||
await app.api.delete(`user/invite/${tokenId}`);
|
await app.api.delete(`user/invite/${tokenId}`);
|
||||||
loadInvites();
|
loadInvites();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
alert('Failed to revoke invite.');
|
app.messages.action('Failed to revoke invite.', $thisRow, 'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user