fix(dashboard): F-S-014 warn on any permissiveness increase in topic edit modal
editFlipToExternal warned only on the internal → external transition. Switching `token → public` or `session → public` while already external is equally risky (opens topic to anonymous subscribers) but produced no warning. Replace with editPermissivenessChange that ranks the (external, auth_mode) pair on a 0..3 scale and fires the warning whenever the resulting rank strictly exceeds the current one: 0 internal (any auth) 1 external + session 2 external + token 3 external + public Keep `editFlipToExternal` as an alias pointing at the new derived so nothing downstream breaks. AUDIT.md anchor: F-S-014. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -412,10 +412,24 @@
|
|||||||
let editTopicAuthMode = $state<TopicAuthMode>('public');
|
let editTopicAuthMode = $state<TopicAuthMode>('public');
|
||||||
let savingTopic = $state(false);
|
let savingTopic = $state(false);
|
||||||
let editTopicError = $state<string | null>(null);
|
let editTopicError = $state<string | null>(null);
|
||||||
// Flipping internal → external is the security-sensitive change.
|
// F-S-014: warn whenever the resulting (external, auth_mode) pair is
|
||||||
const editFlipToExternal = $derived(
|
// strictly more permissive than the current one — not just on the
|
||||||
!!topicToEdit && !topicToEdit.external_subscribable && editTopicExternal
|
// internal → external flip. The order least → most permissive is:
|
||||||
);
|
// internal (any auth) < external+session < external+token < external+public
|
||||||
|
const editPermissivenessChange = $derived.by(() => {
|
||||||
|
if (!topicToEdit) return false;
|
||||||
|
const rank = (external: boolean, mode: TopicAuthMode) => {
|
||||||
|
if (!external) return 0;
|
||||||
|
if (mode === 'session') return 1;
|
||||||
|
if (mode === 'token') return 2;
|
||||||
|
return 3; // public
|
||||||
|
};
|
||||||
|
const before = rank(topicToEdit.external_subscribable, topicToEdit.auth_mode);
|
||||||
|
const after = rank(editTopicExternal, editTopicAuthMode);
|
||||||
|
return after > before;
|
||||||
|
});
|
||||||
|
// Kept for narrow callers; semantics now covered by editPermissivenessChange.
|
||||||
|
const editFlipToExternal = $derived(editPermissivenessChange);
|
||||||
// Delete confirm.
|
// Delete confirm.
|
||||||
let topicToRemove = $state<Topic | null>(null);
|
let topicToRemove = $state<Topic | null>(null);
|
||||||
let removingTopic = $state(false);
|
let removingTopic = $state(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user