diff --git a/lib/util/http/index.spec.ts b/lib/util/http/index.spec.ts index f97e240dc77c21..e2a73c8a690acb 100644 --- a/lib/util/http/index.spec.ts +++ b/lib/util/http/index.spec.ts @@ -2,7 +2,7 @@ import nock from 'nock'; import { getName } from '../../../test/util'; import { EXTERNAL_HOST_ERROR } from '../../constants/error-messages'; import * as hostRules from '../host-rules'; -import { Http } from '.'; +import { Http, removeAuthorizationHeaders } from '.'; const baseUrl = 'http://renovate.com'; @@ -106,4 +106,84 @@ describe(getName(__filename), () => { expect(data).toBe('{}'); expect(nock.isDone()).toBe(true); }); + + it('removeAuthorizationHeaders Amazon', async () => { + expect( + await removeAuthorizationHeaders({ + auth: 'auth', + headers: { + authorization: 'auth', + }, + hostname: 'amazon.com', + href: 'https://amazon.com', + search: 'something X-Amz-Algorithm something', + }) + ).toEqual({ + headers: {}, + hostname: 'amazon.com', + href: 'https://amazon.com', + search: 'something X-Amz-Algorithm something', + }); + }); + + it('removeAuthorizationHeaders Amazon ports', async () => { + expect( + await removeAuthorizationHeaders({ + auth: 'auth', + headers: { + authorization: 'auth', + }, + hostname: 'amazon.com', + href: 'https://amazon.com', + port: 3000, + search: 'something X-Amz-Algorithm something', + }) + ).toEqual({ + headers: {}, + hostname: 'amazon.com', + href: 'https://amazon.com', + search: 'something X-Amz-Algorithm something', + }); + }); + + it('removeAuthorizationHeaders Azure blob', async () => { + expect( + await removeAuthorizationHeaders({ + auth: 'auth', + headers: { + authorization: 'auth', + }, + hostname: 'store123.blob.core.windows.net', + href: + 'https://.blob.core.windows.net///docker/registry/v2/blobs', + }) + ).toEqual({ + headers: {}, + hostname: 'store123.blob.core.windows.net', + href: + 'https://.blob.core.windows.net///docker/registry/v2/blobs', + }); + }); + + it('removeAuthorizationHeaders keep auth', async () => { + expect( + await removeAuthorizationHeaders({ + auth: 'auth', + headers: { + authorization: 'auth', + }, + hostname: 'renovate.com', + href: 'https://renovate.com', + search: 'something', + }) + ).toEqual({ + auth: 'auth', + headers: { + authorization: 'auth', + }, + hostname: 'renovate.com', + href: 'https://renovate.com', + search: 'something', + }); + }); }); diff --git a/lib/util/http/index.ts b/lib/util/http/index.ts index c140432f724c77..96101174a6f6c8 100644 --- a/lib/util/http/index.ts +++ b/lib/util/http/index.ts @@ -57,6 +57,40 @@ async function resolveResponse( } } +// isAmazon return true if request options contains Amazon related headers +function isAmazon(opts: any): boolean { + return opts.search?.includes('X-Amz-Algorithm'); +} + +// isAzureBlob return true if request options contains Azure container registry related data +function isAzureBlob(opts: any): boolean { + return ( + opts.hostname?.endsWith('blob.core.windows.net') && // lgtm [js/incomplete-url-substring-sanitization] + opts.href?.includes('/docker/registry') + ); +} + +// removeAuthorizationHeaders from the redirect options +export function removeAuthorizationHeaders(opts: any): any { + // Check if request has been redirected to Amazon or an Azure blob (ACR) + if (isAmazon(opts) || isAzureBlob(opts)) { + // if there is no port in the redirect URL string, then delete it from the redirect options. + // This can be evaluated for removal after upgrading to Got v10 + const portInUrl = opts.href.split('/')[2].split(':')[1]; + if (!portInUrl) { + // eslint-disable-next-line no-param-reassign + delete opts.port; // Redirect will instead use 80 or 443 for HTTP or HTTPS respectively + } + + // registry is hosted on Amazon or Azure blob, redirect url includes + // authentication which is not required and should be removed + delete opts.headers.authorization; // eslint-disable-line no-param-reassign + delete opts.auth; // eslint-disable-line no-param-reassign + } + + return opts; +} + export class Http { constructor(private hostType: string, private options?: HttpOptions) {} @@ -79,24 +113,7 @@ export class Http { options.retry = 0; } options.hooks = { - beforeRedirect: [ - (opts: any): void => { - // Check if request has been redirected to Amazon - if (opts.search?.includes('X-Amz-Algorithm')) { - // if there is no port in the redirect URL string, then delete it from the redirect options. - // This can be evaluated for removal after upgrading to Got v10 - const portInUrl = opts.href.split('/')[2].split(':')[1]; - if (!portInUrl) { - // eslint-disable-next-line no-param-reassign - delete opts.port; // Redirect will instead use 80 or 443 for HTTP or HTTPS respectively - } - - // registry is hosted on amazon, redirect url includes authentication. - delete opts.headers.authorization; // eslint-disable-line no-param-reassign - delete opts.auth; // eslint-disable-line no-param-reassign - } - }, - ], + beforeRedirect: [removeAuthorizationHeaders], }; options.headers = { ...options.headers,