Frontend: single origins table; lockout guard in the domain editor
- Domain dialog submits one origins map (in-domain + related together);
classification is derived, the submit-time split is gone
- Placeholder-row machinery deleted: an empty list now means 'nothing
allowed'; new domains get a real pre-filled '*.{rp-id}' row that
follows rp-id edits until touched
- Plain '*' is invalid; wildcards only within the domain
- Editing the domain in use: when no auth host is marked and the admin's
current page origin would no longer be allowed to run ceremonies, Save
is disabled with an explanatory error (mirrors the backend guard)
- Origin list display: single table with derived related badges; '*'
sort special case removed
This commit is contained in:
@@ -479,15 +479,13 @@ function createDomain() {
|
||||
auth_host: '',
|
||||
origins: [],
|
||||
originValidation: [],
|
||||
originPlaceholders: [],
|
||||
wellKnownCheck: null,
|
||||
})
|
||||
}
|
||||
|
||||
function openDomain(domain) {
|
||||
// One combined list for editing, in display order: in-domain sites and
|
||||
// related origins, classified by hostname. An empty origins object shows
|
||||
// as a '*' placeholder row, omitted again on submit unless edited.
|
||||
// related origins, classified by hostname against the rp-id.
|
||||
const rows = originDisplayEntries(domain)
|
||||
openDialog('domain-edit', {
|
||||
isNew: false,
|
||||
@@ -496,7 +494,6 @@ function openDomain(domain) {
|
||||
auth_host: rows.find(r => r.auth)?.key || '',
|
||||
origins: rows.map(r => r.key),
|
||||
originValidation: rows.map(() => null),
|
||||
originPlaceholders: rows.map(r => !!r.placeholder),
|
||||
wellKnownCheck: null,
|
||||
})
|
||||
}
|
||||
@@ -914,41 +911,21 @@ async function submitDialog() {
|
||||
if (!rp_id) throw new Error('Domain (rp-id) required')
|
||||
const rp_name = d.rp_name?.trim() || ''
|
||||
const auth_host = d.auth_host?.trim().toLowerCase() || ''
|
||||
// The combined origins list is split by hostname: entries on the
|
||||
// rp-id domain form the in-domain origins object (the auth host
|
||||
// entry is marked), entries elsewhere are related origins (ROR).
|
||||
// Wildcards ('*.app.example.com') classify by their base domain.
|
||||
// One origins object holds in-domain sites and related origins
|
||||
// (ROR) together; the server classifies each key against the rp-id.
|
||||
// Keys are stored lowercased, without the https:// scheme.
|
||||
const keyOf = o => o.replace(/^https:\/\//i, '').replace(/\/+$/, '').toLowerCase()
|
||||
const origins = {}
|
||||
const related = {}
|
||||
for (const [i, o] of (d.origins || []).entries()) {
|
||||
for (const o of d.origins || []) {
|
||||
const key = keyOf(o.trim())
|
||||
// An untouched placeholder row only displays the empty-origins
|
||||
// default (any scheme in-domain) — don't persist it as '*'
|
||||
if (!key || d.originPlaceholders?.[i]) continue
|
||||
if (key === '*') {
|
||||
origins['*'] = true // shorthand for '*.{rp-id}' (https-only outside localhost)
|
||||
continue
|
||||
}
|
||||
let hn = null
|
||||
if (key.startsWith('*.')) {
|
||||
hn = key.slice(2).replace(/\.+$/, '')
|
||||
} else {
|
||||
try { hn = new URL(key.startsWith('http') ? key : 'https://' + key).hostname } catch { continue }
|
||||
}
|
||||
if (!hn) continue
|
||||
if (hn === rp_id || hn.endsWith('.' + rp_id)) {
|
||||
origins[key] = key === auth_host ? { auth_host: true } : true
|
||||
} else {
|
||||
related[key] = true
|
||||
}
|
||||
if (!key) continue
|
||||
origins[key] = key === auth_host ? { auth_host: true } : true
|
||||
}
|
||||
|
||||
closeDialog()
|
||||
const req = d.isNew
|
||||
? apiJson('/auth/api/admin/domains/', { method: 'POST', body: { rp_id, rp_name, origins, related } })
|
||||
: apiJson(`/auth/api/admin/domains/${rp_id}`, { method: 'PATCH', body: { rp_name, origins, related } })
|
||||
? apiJson('/auth/api/admin/domains/', { method: 'POST', body: { rp_id, rp_name, origins } })
|
||||
: apiJson(`/auth/api/admin/domains/${rp_id}`, { method: 'PATCH', body: { rp_name, origins } })
|
||||
req
|
||||
.then(() => {
|
||||
authStore.showMessage(`Domain "${rp_id}" ${d.isNew ? 'created' : 'updated'}.`, 'success', 2500)
|
||||
|
||||
Reference in New Issue
Block a user