Merge remote-tracking branch 'origin/v16/dev'
This commit is contained in:
@@ -9,6 +9,7 @@ schedules:
|
||||
branches:
|
||||
include:
|
||||
- v15/dev
|
||||
- v16/dev
|
||||
- main
|
||||
- v17/dev
|
||||
|
||||
@@ -695,4 +696,4 @@ stages:
|
||||
--data "$PAYLOAD" \
|
||||
"$SLACK_WEBHOOK_URL"
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: $(E2ESLACKWEBHOOKURL)
|
||||
SLACK_WEBHOOK_URL: $(E2ESLACKWEBHOOKURL)
|
||||
|
||||
@@ -77,6 +77,41 @@ export class RedirectRequestHandler extends AuthorizationRequestHandler {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup all stale authorization requests and configurations from storage.
|
||||
* This scans localStorage for any keys matching the appauth patterns and removes them,
|
||||
* including the authorization request handle key.
|
||||
*/
|
||||
public cleanupStaleAuthorizationData(): Promise<void> {
|
||||
// Check if we're in a browser environment with localStorage
|
||||
if (typeof window === 'undefined' || !window.localStorage) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const keysToRemove: string[] = [];
|
||||
|
||||
// Scan localStorage for all appauth-related keys
|
||||
for (let i = 0; i < window.localStorage.length; i++) {
|
||||
const key = window.localStorage.key(i);
|
||||
if (
|
||||
key &&
|
||||
(key.includes('_appauth_authorization_request') ||
|
||||
key.includes('_appauth_authorization_service_configuration') ||
|
||||
key === AUTHORIZATION_REQUEST_HANDLE_KEY)
|
||||
) {
|
||||
keysToRemove.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all found stale keys
|
||||
const removePromises = keysToRemove.map((key) => this.storageBackend.removeItem(key));
|
||||
return Promise.all(removePromises).then(() => {
|
||||
if (keysToRemove.length > 0) {
|
||||
log(`Cleaned up ${keysToRemove.length} stale authorization data entries`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to introspect the contents of storage backend and completes the
|
||||
* request.
|
||||
@@ -119,12 +154,8 @@ export class RedirectRequestHandler extends AuthorizationRequestHandler {
|
||||
} else {
|
||||
authorizationResponse = new AuthorizationResponse({ code: code, state: state });
|
||||
}
|
||||
// cleanup state
|
||||
return Promise.all([
|
||||
this.storageBackend.removeItem(AUTHORIZATION_REQUEST_HANDLE_KEY),
|
||||
this.storageBackend.removeItem(authorizationRequestKey(handle)),
|
||||
this.storageBackend.removeItem(authorizationServiceConfigurationKey(handle)),
|
||||
]).then(() => {
|
||||
// cleanup all authorization data including current and stale entries
|
||||
return this.cleanupStaleAuthorizationData().then(() => {
|
||||
log('Delivering authorization response');
|
||||
return {
|
||||
request: request,
|
||||
@@ -134,7 +165,10 @@ export class RedirectRequestHandler extends AuthorizationRequestHandler {
|
||||
});
|
||||
} else {
|
||||
log('Mismatched request (state and request_uri) dont match.');
|
||||
return Promise.resolve(null);
|
||||
// cleanup all authorization data even on mismatch to prevent stale PKCE data
|
||||
return this.cleanupStaleAuthorizationData().then(() => {
|
||||
return null;
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
@@ -247,6 +247,10 @@ export class UmbAuthFlow {
|
||||
|
||||
// clear the internal state
|
||||
this.#tokenResponse.setValue(undefined);
|
||||
|
||||
// Also cleanup any OAuth/PKCE artifacts that may still be in localStorage
|
||||
// This is a defense-in-depth measure during logout
|
||||
await this.#authorizationHandler.cleanupStaleAuthorizationData();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,4 +27,4 @@
|
||||
"dotenv": "^16.3.1",
|
||||
"node-fetch": "^2.6.7"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,8 @@ test('can copy and paste a single block into the same document but different gro
|
||||
await umbracoUi.content.doesBlockEditorBlockWithNameContainValue(elementGroupName, elementPropertyName, ConstantHelper.inputTypes.tipTap, blockPropertyValue);
|
||||
});
|
||||
|
||||
test('can copy and paste a single block into another document', async ({umbracoApi, umbracoUi}) => {
|
||||
// Remove skip after this issue is resolved: https://github.com/umbraco/Umbraco-CMS/issues/20680
|
||||
test.skip('can copy and paste a single block into another document', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
await umbracoApi.document.ensureNameNotExists(secondContentName);
|
||||
await umbracoApi.document.createDefaultDocumentWithABlockGridEditorAndBlockWithValue(contentName, documentTypeName, blockGridDataTypeName, elementTypeId, AliasHelper.toAlias(elementPropertyName), blockPropertyValue, richTextDataTypeUiAlias);
|
||||
|
||||
@@ -106,7 +106,8 @@ test('can copy and paste a single block into the same document but different gro
|
||||
await umbracoUi.content.doesBlockEditorBlockWithNameContainValue(elementGroupName, elementPropertyName, ConstantHelper.inputTypes.tipTap, blockPropertyValue);
|
||||
});
|
||||
|
||||
test('can copy and paste a single block into another document', async ({umbracoApi, umbracoUi}) => {
|
||||
// Remove skip after this issue is resolved: https://github.com/umbraco/Umbraco-CMS/issues/20680
|
||||
test.skip('can copy and paste a single block into another document', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
await umbracoApi.document.ensureNameNotExists(secondContentName);
|
||||
await umbracoApi.document.createDefaultDocumentWithABlockListEditorAndBlockWithValue(contentName, documentTypeName, blockListDataTypeName, elementTypeId, AliasHelper.toAlias(elementPropertyName), blockPropertyValue, elementDataTypeUiAlias, groupName);
|
||||
|
||||
@@ -14,7 +14,7 @@ test.afterEach(async ({umbracoApi}) => {
|
||||
await umbracoApi.webhook.ensureNameNotExists(webhookName);
|
||||
});
|
||||
|
||||
test('can create a webhook', {tag: '@release'}, async ({umbracoApi, umbracoUi}) => {
|
||||
test('can create a webhook', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
const event = 'Content Deleted';
|
||||
const webhookSiteUrl = umbracoApi.webhook.webhookSiteUrl + webhookSiteToken;
|
||||
@@ -122,7 +122,7 @@ test('can disable a webhook', async ({umbracoApi, umbracoUi}) => {
|
||||
await umbracoApi.webhook.isWebhookEnabled(webhookName, false);
|
||||
});
|
||||
|
||||
test('cannot remove all events from a webhook', {tag: '@release'}, async ({umbracoApi, umbracoUi}) => {
|
||||
test('cannot remove all events from a webhook', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
const event = 'Content Deleted';
|
||||
await umbracoApi.webhook.createDefaultWebhook(webhookName, webhookSiteToken, event);
|
||||
|
||||
Reference in New Issue
Block a user