auth-node: move parseWebPessageResponse to test util + fix error value handling

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2023-08-11 16:19:13 +02:00
parent ac8d9dc296
commit 296c818ddf
4 changed files with 60 additions and 22 deletions
@@ -0,0 +1,28 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { WebMessageResponse } from '../sendWebMessageResponse';
export function parseWebMessageResponse(text: string): {
response: WebMessageResponse;
origin: string;
} {
const [response, origin] = text.matchAll(/decodeURIComponent\('(.+?)'\)/g);
return {
response: JSON.parse(decodeURIComponent(response[1])),
origin: decodeURIComponent(origin[1]),
};
}
@@ -20,6 +20,7 @@ import {
sendWebMessageResponse,
type WebMessageResponse,
} from './sendWebMessageResponse';
import { parseWebMessageResponse } from './__testUtils__/parseWebMessageResponse';
describe('oauth helpers', () => {
describe('safelyEncodeURIComponent', () => {
@@ -78,7 +79,12 @@ describe('oauth helpers', () => {
type: 'authorization_response',
error: new Error('Unknown error occurred'),
};
const encoded = safelyEncodeURIComponent(JSON.stringify(data));
const encoded = safelyEncodeURIComponent(
JSON.stringify({
type: 'authorization_response',
error: { name: 'Error', message: 'Unknown error occurred' },
}),
);
sendWebMessageResponse(mockResponse, appOrigin, data);
expect(mockResponse.setHeader).toHaveBeenCalledTimes(3);
@@ -122,20 +128,29 @@ describe('oauth helpers', () => {
},
};
sendWebMessageResponse(mockResponse, appOrigin, data);
expect(responseBody.match(/.postMessage\(/g)).toHaveLength(2);
expect(
responseBody.match(/.postMessage\([a-zA-z.()]*, \'\*\'\)/g),
).toHaveLength(1);
expect(parseWebMessageResponse(responseBody).response).toEqual({
type: 'authorization_response',
response: {
providerInfo: expect.any(Object),
profile: {
email: 'foo@bar.com',
},
backstageIdentity: expect.any(Object),
},
});
const errData: WebMessageResponse = {
type: 'authorization_response',
error: new Error('Unknown error occurred'),
};
sendWebMessageResponse(mockResponse, appOrigin, errData);
expect(responseBody.match(/.postMessage\(/g)).toHaveLength(2);
expect(
responseBody.match(/.postMessage\([a-zA-z.()]*, \'\*\'\)/g),
).toHaveLength(1);
expect(parseWebMessageResponse(responseBody).response).toEqual({
type: 'authorization_response',
error: {
name: 'Error',
message: 'Unknown error occurred',
},
});
});
it('handles single quotes and unicode chars safely', () => {
@@ -17,6 +17,7 @@
import { Response } from 'express';
import crypto from 'crypto';
import { ClientAuthResponse } from '../types';
import { serializeError } from '@backstage/errors';
/**
* Payload sent as a post message after the auth request is complete.
@@ -47,7 +48,12 @@ export function sendWebMessageResponse(
appOrigin: string,
response: WebMessageResponse,
): void {
const jsonData = JSON.stringify(response);
const jsonData = JSON.stringify(response, (_, value) => {
if (value instanceof Error) {
return serializeError(value);
}
return value;
});
const base64Data = safelyEncodeURIComponent(jsonData);
const base64Origin = safelyEncodeURIComponent(appOrigin);
@@ -24,8 +24,8 @@ import { createOAuthRouteHandlers } from './createOAuthRouteHandlers';
import { OAuthAuthenticator } from './types';
import { errorHandler } from '@backstage/backend-common';
import { encodeOAuthState, OAuthState } from './state';
import { WebMessageResponse } from '../flow';
import { PassportProfile } from '../passport';
import { parseWebMessageResponse } from '../flow/__testUtils__/parseWebMessageResponse';
const mockAuthenticator: jest.Mocked<OAuthAuthenticator<unknown, unknown>> = {
initialize: jest.fn(_r => ({ ctx: 'authenticator' })),
@@ -109,17 +109,6 @@ function getGrantedScopesCookie(test: SuperAgentTest) {
});
}
function parseWebMessageResponse(text: string): {
response: WebMessageResponse;
origin: string;
} {
const [response, origin] = text.matchAll(/decodeURIComponent\('(.+?)'\)/g);
return {
response: JSON.parse(decodeURIComponent(response[1])),
origin: decodeURIComponent(origin[1]),
};
}
describe('createOAuthRouteHandlers', () => {
afterEach(() => jest.clearAllMocks());