From 10a413574050db39ece41592fc6e4eff73d3d444 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke <ben@bnf.dev> Date: Fri, 7 Jul 2023 15:09:12 +0200 Subject: [PATCH] [BUGFIX] Fix sudo mode in non-Sec-Fetch-Dest context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since #94084 all module URLs are automatically framed by the TYPO3 main controller whenever they are opened in a Sec-Fetch-Dest aware request. (HTTPS or localhost domain) The intention of API is to allow module-links to be opened in a new tab by user intent – but due to technical limitation that feature is limited to secure contexts, and must therefore not be relied on as an API for internal redirects. sudo mode made use of this API and redirected via top.location to the privileged module, relying on the fact that iframe module-requests where detected to be loaded in the wrong context, to produce a redirect to the proper backend-frame, this didn't work for non HTTPS requests. This workaround has been done to remove "sudo-mode" from the URL bar. That workaround is no longer needed as #101287 added support for installtool URL bar synchronisation. ContentContainer API is now used to set the URL. Releases: main, 12.4 Resolves: #101288 Related: #101287 Change-Id: Id8b828662e3cd2739a93eda5f9517f896c65e941 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/79921 Tested-by: Benjamin Franzke <ben@bnf.dev> Reviewed-by: Benjamin Franzke <ben@bnf.dev> Tested-by: core-ci <typo3@b13.com> --- .../Sources/TypeScript/backend/security/element/sudo-mode.ts | 5 ++--- .../Classes/Controller/Security/SudoModeController.php | 1 - .../Public/JavaScript/security/element/sudo-mode.js | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Build/Sources/TypeScript/backend/security/element/sudo-mode.ts b/Build/Sources/TypeScript/backend/security/element/sudo-mode.ts index 7c25a62cfd52..47b078d23e4c 100644 --- a/Build/Sources/TypeScript/backend/security/element/sudo-mode.ts +++ b/Build/Sources/TypeScript/backend/security/element/sudo-mode.ts @@ -16,12 +16,12 @@ import { html, LitElement, nothing, PropertyValues, TemplateResult } from 'lit'; import AjaxRequest from '@typo3/core/ajax/ajax-request'; import { AjaxResponse } from '@typo3/core/ajax/ajax-response'; import { styleTag, lll } from '@typo3/core/lit-helper'; +import Viewport from '@typo3/backend/viewport'; interface SudoModeResponse { message: string; redirect?: { uri: string, - target: string, } } @@ -100,8 +100,7 @@ export class SudoMode extends LitElement { .then(async (ajaxResponse: AjaxResponse) => { const response: SudoModeResponse = await ajaxResponse.resolve('application/json'); if (response.redirect) { - const targetDocument = response.redirect.target === 'top' ? top.document : document; - targetDocument.location.href = response.redirect.uri; + Viewport.ContentContainer.setUrl(response.redirect.uri); } }) .catch(async (ajaxResponse: AjaxResponse) => { diff --git a/typo3/sysext/backend/Classes/Controller/Security/SudoModeController.php b/typo3/sysext/backend/Classes/Controller/Security/SudoModeController.php index 218622b63bb1..3e6b3f05225e 100644 --- a/typo3/sysext/backend/Classes/Controller/Security/SudoModeController.php +++ b/typo3/sysext/backend/Classes/Controller/Security/SudoModeController.php @@ -142,7 +142,6 @@ final class SudoModeController implements LoggerAwareInterface self::ROUTE_PATH_APPLY, $this->buildUriParametersForClaim($claim, 'apply') ), - 'target' => 'top', ]; if ($useInstallToolPassword && $this->passwordVerification->verifyInstallToolPassword($password)) { $this->logger->info('Verified with install tool password', $loggerContext); diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/security/element/sudo-mode.js b/typo3/sysext/backend/Resources/Public/JavaScript/security/element/sudo-mode.js index 32cb19d64222..118e974f705d 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/security/element/sudo-mode.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/security/element/sudo-mode.js @@ -10,7 +10,7 @@ * * The TYPO3 project - inspiring people to share! */ -var __decorate=function(e,o,s,t){var r,l=arguments.length,a=l<3?o:null===t?t=Object.getOwnPropertyDescriptor(o,s):t;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,o,s,t);else for(var d=e.length-1;d>=0;d--)(r=e[d])&&(a=(l<3?r(a):l>3?r(o,s,a):r(o,s))||a);return l>3&&a&&Object.defineProperty(o,s,a),a};import{customElement,property,query,state}from"lit/decorators.js";import{html,LitElement,nothing}from"lit";import AjaxRequest from"@typo3/core/ajax/ajax-request.js";import{styleTag,lll}from"@typo3/core/lit-helper.js";let SudoMode=class extends LitElement{constructor(){super(...arguments),this.useInstallToolPassword=!1,this.errorMessage=null}createRenderRoot(){return this}render(){return html` +var __decorate=function(e,o,s,t){var r,l=arguments.length,a=l<3?o:null===t?t=Object.getOwnPropertyDescriptor(o,s):t;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,o,s,t);else for(var d=e.length-1;d>=0;d--)(r=e[d])&&(a=(l<3?r(a):l>3?r(o,s,a):r(o,s))||a);return l>3&&a&&Object.defineProperty(o,s,a),a};import{customElement,property,query,state}from"lit/decorators.js";import{html,LitElement,nothing}from"lit";import AjaxRequest from"@typo3/core/ajax/ajax-request.js";import{styleTag,lll}from"@typo3/core/lit-helper.js";import Viewport from"@typo3/backend/viewport.js";let SudoMode=class extends LitElement{constructor(){super(...arguments),this.useInstallToolPassword=!1,this.errorMessage=null}createRenderRoot(){return this}render(){return html` ${styleTag` :host { display: block; } #sudo-mode-verification { display: block; } @@ -50,4 +50,4 @@ var __decorate=function(e,o,s,t){var r,l=arguments.length,a=l<3?o:null===t?t=Obj </div> </div> </div> - `}firstUpdated(e){super.firstUpdated(e),this.passwordElement.focus()}verifyPassword(e){e.preventDefault(),this.errorMessage=null,new AjaxRequest(this.verifyActionUri).post({password:this.passwordElement.value,useInstallToolPassword:this.useInstallToolPassword?1:0}).then((async e=>{const o=await e.resolve("application/json");if(o.redirect){("top"===o.redirect.target?top.document:document).location.href=o.redirect.uri}})).catch((async e=>{const o=await e.resolve("application/json");this.errorMessage=o.message}))}toggleUseInstallToolPassword(e){e.preventDefault(),this.useInstallToolPassword=!this.useInstallToolPassword}};__decorate([property({type:String})],SudoMode.prototype,"verifyActionUri",void 0),__decorate([state()],SudoMode.prototype,"useInstallToolPassword",void 0),__decorate([state()],SudoMode.prototype,"errorMessage",void 0),__decorate([query("#password")],SudoMode.prototype,"passwordElement",void 0),SudoMode=__decorate([customElement("typo3-backend-security-sudo-mode")],SudoMode);export{SudoMode}; \ No newline at end of file + `}firstUpdated(e){super.firstUpdated(e),this.passwordElement.focus()}verifyPassword(e){e.preventDefault(),this.errorMessage=null,new AjaxRequest(this.verifyActionUri).post({password:this.passwordElement.value,useInstallToolPassword:this.useInstallToolPassword?1:0}).then((async e=>{const o=await e.resolve("application/json");o.redirect&&Viewport.ContentContainer.setUrl(o.redirect.uri)})).catch((async e=>{const o=await e.resolve("application/json");this.errorMessage=o.message}))}toggleUseInstallToolPassword(e){e.preventDefault(),this.useInstallToolPassword=!this.useInstallToolPassword}};__decorate([property({type:String})],SudoMode.prototype,"verifyActionUri",void 0),__decorate([state()],SudoMode.prototype,"useInstallToolPassword",void 0),__decorate([state()],SudoMode.prototype,"errorMessage",void 0),__decorate([query("#password")],SudoMode.prototype,"passwordElement",void 0),SudoMode=__decorate([customElement("typo3-backend-security-sudo-mode")],SudoMode);export{SudoMode}; \ No newline at end of file -- GitLab