Fix admin PIN after profile switches
Reset profile PIN dialog controls each time it opens so stale profile-specific event listeners cannot submit an admin PIN against a previously selected profile. Keep failed PIN attempts retryable and restrict launch-lock verification to the admin profile PIN only, so non-admin profile PINs cannot mark the admin lock as verified.
This commit is contained in:
parent
5d1f3c1b48
commit
4ebbffb898
2 changed files with 26 additions and 10 deletions
|
|
@ -24315,9 +24315,10 @@ def select_profile():
|
||||||
return jsonify({'success': False, 'error': 'Invalid PIN'}), 401
|
return jsonify({'success': False, 'error': 'Invalid PIN'}), 401
|
||||||
|
|
||||||
session['profile_id'] = profile_id
|
session['profile_id'] = profile_id
|
||||||
# If PIN was just validated, also mark launch PIN as verified
|
# If the admin PIN was just validated, also mark launch PIN as
|
||||||
# so the subsequent page reload doesn't ask again
|
# verified so the subsequent page reload doesn't ask again. A
|
||||||
if pin:
|
# non-admin profile PIN must not unlock the admin launch lock.
|
||||||
|
if pin and profile_id == 1:
|
||||||
session['launch_pin_verified'] = True
|
session['launch_pin_verified'] = True
|
||||||
return jsonify({'success': True, 'profile': profile})
|
return jsonify({'success': True, 'profile': profile})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -24402,12 +24403,16 @@ def reset_pin_via_credential():
|
||||||
|
|
||||||
# Credential verified — clear PIN for the requested profile (default: admin)
|
# Credential verified — clear PIN for the requested profile (default: admin)
|
||||||
database = get_database()
|
database = get_database()
|
||||||
target_profile = data.get('profile_id', 1)
|
try:
|
||||||
|
target_profile = int(data.get('profile_id', 1))
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
target_profile = 1
|
||||||
database.update_profile(target_profile, pin_hash=None)
|
database.update_profile(target_profile, pin_hash=None)
|
||||||
# If clearing admin PIN, also disable launch lock
|
# If clearing admin PIN, also disable launch lock
|
||||||
if target_profile == 1:
|
if target_profile == 1:
|
||||||
config_manager.set('security.require_pin_on_launch', False)
|
config_manager.set('security.require_pin_on_launch', False)
|
||||||
session['launch_pin_verified'] = True
|
if target_profile == 1:
|
||||||
|
session['launch_pin_verified'] = True
|
||||||
|
|
||||||
return jsonify({'success': True, 'message': 'PIN cleared. You can set a new PIN in Settings.'})
|
return jsonify({'success': True, 'message': 'PIN cleared. You can set a new PIN in Settings.'})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -707,8 +707,19 @@ function showPinDialog(profile) {
|
||||||
const dialog = document.getElementById('profile-pin-dialog');
|
const dialog = document.getElementById('profile-pin-dialog');
|
||||||
const avatar = document.getElementById('profile-pin-avatar');
|
const avatar = document.getElementById('profile-pin-avatar');
|
||||||
const nameEl = document.getElementById('profile-pin-name');
|
const nameEl = document.getElementById('profile-pin-name');
|
||||||
const input = document.getElementById('profile-pin-input');
|
|
||||||
const errorEl = document.getElementById('profile-pin-error');
|
const errorEl = document.getElementById('profile-pin-error');
|
||||||
|
const oldInput = document.getElementById('profile-pin-input');
|
||||||
|
const oldSubmit = document.getElementById('profile-pin-submit');
|
||||||
|
const oldCancel = document.getElementById('profile-pin-cancel');
|
||||||
|
|
||||||
|
// Replace controls on every open so stale listeners from a previous
|
||||||
|
// profile cannot submit the new PIN against the old profile id.
|
||||||
|
const input = oldInput.cloneNode(true);
|
||||||
|
const submit = oldSubmit.cloneNode(true);
|
||||||
|
const cancel = oldCancel.cloneNode(true);
|
||||||
|
oldInput.parentNode.replaceChild(input, oldInput);
|
||||||
|
oldSubmit.parentNode.replaceChild(submit, oldSubmit);
|
||||||
|
oldCancel.parentNode.replaceChild(cancel, oldCancel);
|
||||||
|
|
||||||
renderProfileAvatar(avatar, profile);
|
renderProfileAvatar(avatar, profile);
|
||||||
nameEl.textContent = profile.name;
|
nameEl.textContent = profile.name;
|
||||||
|
|
@ -718,13 +729,12 @@ function showPinDialog(profile) {
|
||||||
dialog.style.display = 'flex';
|
dialog.style.display = 'flex';
|
||||||
setTimeout(() => input.focus(), 100);
|
setTimeout(() => input.focus(), 100);
|
||||||
|
|
||||||
const submit = document.getElementById('profile-pin-submit');
|
|
||||||
const cancel = document.getElementById('profile-pin-cancel');
|
|
||||||
|
|
||||||
const wasSwitching = !!currentProfile;
|
const wasSwitching = !!currentProfile;
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
const pin = input.value;
|
const pin = input.value;
|
||||||
if (!pin) return;
|
if (!pin) return;
|
||||||
|
submit.disabled = true;
|
||||||
|
submit.textContent = 'Verifying...';
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/profiles/select', {
|
const res = await fetch('/api/profiles/select', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
@ -753,7 +763,8 @@ function showPinDialog(profile) {
|
||||||
errorEl.textContent = 'Connection error';
|
errorEl.textContent = 'Connection error';
|
||||||
errorEl.style.display = '';
|
errorEl.style.display = '';
|
||||||
}
|
}
|
||||||
cleanup();
|
submit.disabled = false;
|
||||||
|
submit.textContent = 'Submit';
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue