diff --git a/plugins/tools/frontend/views/SecureSendCreate.vue b/plugins/tools/frontend/views/SecureSendCreate.vue index 5c2621a8..591acd99 100644 --- a/plugins/tools/frontend/views/SecureSendCreate.vue +++ b/plugins/tools/frontend/views/SecureSendCreate.vue @@ -151,12 +151,19 @@ async function createLink() { // withBase for the path: a site served under /shopdb or /ops carries that // in front of every route, and leaving it off produced a 404 from IIS for a // secret that existed - with the sender shown a link that could never work. - const origin = (await getSiteBaseUrl()).replace(/\/+$/, '') - const path = withBase(`/s/${token}`) + // site_base_url is DOCUMENTED as scheme + host, but sites really do set the + // full base including the subpath - and appending the mount to one that + // already carries it produced /shopdb/shopdb/s/. Tolerate both + // rather than trusting the description: add the mount only when it is not + // there already. + const configured = (await getSiteBaseUrl()).replace(/\/+$/, '') + const mount = withBase('/').replace(/\/+$/, '') + const needsMount = mount && !configured.endsWith(mount) // The key rides in the FRAGMENT. Browsers never send it, so it reaches the // recipient and nowhere else. - link.value = `${origin}${path}#${sealed.fragmentKey}` + link.value = + `${configured}${needsMount ? mount : ''}/s/${token}#${sealed.fragmentKey}` // Drop the plaintext as soon as it is sealed: no reason to keep it in memory // behind the link that replaced it. plaintext.value = ''