refactor: Move URL join utility function to PathUtil

This commit is contained in:
Joachim Van Herwegen 2021-08-18 15:22:02 +02:00
parent 80ebd02cc4
commit f0f59a8f27
8 changed files with 21 additions and 17 deletions

View File

@ -1,4 +1,3 @@
import urljoin from 'url-join';
import type { ErrorHandler } from '../ldp/http/ErrorHandler'; import type { ErrorHandler } from '../ldp/http/ErrorHandler';
import type { RequestParser } from '../ldp/http/RequestParser'; import type { RequestParser } from '../ldp/http/RequestParser';
import { OkResponseDescription } from '../ldp/http/response/OkResponseDescription'; import { OkResponseDescription } from '../ldp/http/response/OkResponseDescription';
@ -18,7 +17,7 @@ import { APPLICATION_JSON } from '../util/ContentTypes';
import { BadRequestHttpError } from '../util/errors/BadRequestHttpError'; import { BadRequestHttpError } from '../util/errors/BadRequestHttpError';
import { assertError, createErrorMessage } from '../util/errors/ErrorUtil'; import { assertError, createErrorMessage } from '../util/errors/ErrorUtil';
import { InternalServerError } from '../util/errors/InternalServerError'; import { InternalServerError } from '../util/errors/InternalServerError';
import { trimTrailingSlashes } from '../util/PathUtil'; import { joinUrl, trimTrailingSlashes } from '../util/PathUtil';
import { addTemplateMetadata } from '../util/ResourceUtil'; import { addTemplateMetadata } from '../util/ResourceUtil';
import type { ProviderFactory } from './configuration/ProviderFactory'; import type { ProviderFactory } from './configuration/ProviderFactory';
import type { import type {
@ -113,7 +112,7 @@ export class IdentityProviderHttpHandler extends HttpHandler {
) { ) {
super(); super();
// Trimming trailing slashes so the relative URL starts with a slash after slicing this off // Trimming trailing slashes so the relative URL starts with a slash after slicing this off
this.baseUrl = trimTrailingSlashes(urljoin(baseUrl, idpPath)); this.baseUrl = trimTrailingSlashes(joinUrl(baseUrl, idpPath));
this.requestParser = requestParser; this.requestParser = requestParser;
this.providerFactory = providerFactory; this.providerFactory = providerFactory;
this.interactionRoutes = interactionRoutes; this.interactionRoutes = interactionRoutes;

View File

@ -12,11 +12,10 @@ import type { AnyObject,
Account, Account,
ErrorOut, Adapter } from 'oidc-provider'; ErrorOut, Adapter } from 'oidc-provider';
import { Provider } from 'oidc-provider'; import { Provider } from 'oidc-provider';
import urljoin from 'url-join';
import type { ErrorHandler } from '../../ldp/http/ErrorHandler'; import type { ErrorHandler } from '../../ldp/http/ErrorHandler';
import type { ResponseWriter } from '../../ldp/http/ResponseWriter'; import type { ResponseWriter } from '../../ldp/http/ResponseWriter';
import type { KeyValueStorage } from '../../storage/keyvalue/KeyValueStorage'; import type { KeyValueStorage } from '../../storage/keyvalue/KeyValueStorage';
import { ensureTrailingSlash } from '../../util/PathUtil'; import { ensureTrailingSlash, joinUrl } from '../../util/PathUtil';
import type { AdapterFactory } from '../storage/AdapterFactory'; import type { AdapterFactory } from '../storage/AdapterFactory';
import type { ProviderFactory } from './ProviderFactory'; import type { ProviderFactory } from './ProviderFactory';
@ -213,7 +212,7 @@ export class IdentityProviderFactory implements ProviderFactory {
* this would result in `/foo/idp/device/auth`. * this would result in `/foo/idp/device/auth`.
*/ */
private createRoute(relative: string): string { private createRoute(relative: string): string {
return new URL(urljoin(this.baseUrl, this.idpPath, relative)).pathname; return new URL(joinUrl(this.baseUrl, this.idpPath, relative)).pathname;
} }
/** /**

View File

@ -1,7 +1,6 @@
import assert from 'assert'; import assert from 'assert';
import urljoin from 'url-join';
import { getLoggerFor } from '../../../../logging/LogUtil'; import { getLoggerFor } from '../../../../logging/LogUtil';
import { ensureTrailingSlash } from '../../../../util/PathUtil'; import { ensureTrailingSlash, joinUrl } from '../../../../util/PathUtil';
import type { TemplateEngine } from '../../../../util/templates/TemplateEngine'; import type { TemplateEngine } from '../../../../util/templates/TemplateEngine';
import type { EmailSender } from '../../util/EmailSender'; import type { EmailSender } from '../../util/EmailSender';
import { getFormDataRequestBody } from '../../util/FormDataUtil'; import { getFormDataRequestBody } from '../../util/FormDataUtil';
@ -74,7 +73,7 @@ export class ForgotPasswordHandler extends InteractionHandler {
*/ */
private async sendResetMail(recordId: string, email: string): Promise<void> { private async sendResetMail(recordId: string, email: string): Promise<void> {
this.logger.info(`Sending password reset to ${email}`); this.logger.info(`Sending password reset to ${email}`);
const resetLink = urljoin(this.baseUrl, this.idpPath, `resetpassword/${recordId}`); const resetLink = joinUrl(this.baseUrl, this.idpPath, `resetpassword/${recordId}`);
const renderedEmail = await this.templateEngine.render({ resetLink }); const renderedEmail = await this.templateEngine.render({ resetLink });
await this.emailSender.handleSafe({ await this.emailSender.handleSafe({
recipient: email, recipient: email,

View File

@ -1,11 +1,11 @@
import assert from 'assert'; import assert from 'assert';
import urljoin from 'url-join';
import type { Operation } from '../../../../ldp/operations/Operation'; import type { Operation } from '../../../../ldp/operations/Operation';
import type { ResourceIdentifier } from '../../../../ldp/representation/ResourceIdentifier'; import type { ResourceIdentifier } from '../../../../ldp/representation/ResourceIdentifier';
import { getLoggerFor } from '../../../../logging/LogUtil'; import { getLoggerFor } from '../../../../logging/LogUtil';
import type { IdentifierGenerator } from '../../../../pods/generate/IdentifierGenerator'; import type { IdentifierGenerator } from '../../../../pods/generate/IdentifierGenerator';
import type { PodManager } from '../../../../pods/PodManager'; import type { PodManager } from '../../../../pods/PodManager';
import type { PodSettings } from '../../../../pods/settings/PodSettings'; import type { PodSettings } from '../../../../pods/settings/PodSettings';
import { joinUrl } from '../../../../util/PathUtil';
import type { OwnershipValidator } from '../../../ownership/OwnershipValidator'; import type { OwnershipValidator } from '../../../ownership/OwnershipValidator';
import { getFormDataRequestBody } from '../../util/FormDataUtil'; import { getFormDataRequestBody } from '../../util/FormDataUtil';
import { assertPassword, throwIdpInteractionError } from '../EmailPasswordUtil'; import { assertPassword, throwIdpInteractionError } from '../EmailPasswordUtil';
@ -129,7 +129,7 @@ export class RegistrationHandler extends InteractionHandler {
// Create or verify the WebID // Create or verify the WebID
if (result.createWebId) { if (result.createWebId) {
result.webId = urljoin(podBaseUrl!.path, this.webIdSuffix); result.webId = joinUrl(podBaseUrl!.path, this.webIdSuffix);
} else { } else {
await this.ownershipValidator.handleSafe({ webId: result.webId! }); await this.ownershipValidator.handleSafe({ webId: result.webId! });
} }

View File

@ -1,4 +1,5 @@
import { posix, win32 } from 'path'; import { posix, win32 } from 'path';
import urljoin from 'url-join';
import type { ResourceIdentifier } from '../ldp/representation/ResourceIdentifier'; import type { ResourceIdentifier } from '../ldp/representation/ResourceIdentifier';
/** /**
@ -190,3 +191,9 @@ export function resolveAssetPath(path: string = modulePathPlaceholder): string {
} }
return absoluteFilePath(path); return absoluteFilePath(path);
} }
/**
* Concatenates all the given strings into a normalized URL.
* Will place slashes between input strings if necessary.
*/
export const joinUrl = urljoin;

View File

@ -3,9 +3,9 @@ import { URL } from 'url';
import { load } from 'cheerio'; import { load } from 'cheerio';
import type { Response } from 'cross-fetch'; import type { Response } from 'cross-fetch';
import { fetch } from 'cross-fetch'; import { fetch } from 'cross-fetch';
import urljoin from 'url-join';
import type { App } from '../../src/init/App'; import type { App } from '../../src/init/App';
import { APPLICATION_X_WWW_FORM_URLENCODED } from '../../src/util/ContentTypes'; import { APPLICATION_X_WWW_FORM_URLENCODED } from '../../src/util/ContentTypes';
import { joinUrl } from '../../src/util/PathUtil';
import { getPort } from '../util/Util'; import { getPort } from '../util/Util';
import { getDefaultVariables, getTestConfigPath, instantiateFromConfig } from './Config'; import { getDefaultVariables, getTestConfigPath, instantiateFromConfig } from './Config';
import { IdentityTestState } from './IdentityTestState'; import { IdentityTestState } from './IdentityTestState';
@ -51,7 +51,7 @@ describe('A Solid server with IDP', (): void => {
let app: App; let app: App;
const redirectUrl = 'http://mockedredirect/'; const redirectUrl = 'http://mockedredirect/';
const oidcIssuer = baseUrl; const oidcIssuer = baseUrl;
const card = urljoin(baseUrl, 'profile/card'); const card = joinUrl(baseUrl, 'profile/card');
const webId = `${card}#me`; const webId = `${card}#me`;
const email = 'test@test.com'; const email = 'test@test.com';
const password = 'password!'; const password = 'password!';

View File

@ -1,5 +1,4 @@
import type { Provider } from 'oidc-provider'; import type { Provider } from 'oidc-provider';
import urljoin from 'url-join';
import type { ProviderFactory } from '../../../src/identity/configuration/ProviderFactory'; import type { ProviderFactory } from '../../../src/identity/configuration/ProviderFactory';
import { InteractionRoute, IdentityProviderHttpHandler } from '../../../src/identity/IdentityProviderHttpHandler'; import { InteractionRoute, IdentityProviderHttpHandler } from '../../../src/identity/IdentityProviderHttpHandler';
import type { InteractionHandler } from '../../../src/identity/interaction/email-password/handler/InteractionHandler'; import type { InteractionHandler } from '../../../src/identity/interaction/email-password/handler/InteractionHandler';
@ -19,6 +18,7 @@ import type {
} from '../../../src/storage/conversion/RepresentationConverter'; } from '../../../src/storage/conversion/RepresentationConverter';
import { BadRequestHttpError } from '../../../src/util/errors/BadRequestHttpError'; import { BadRequestHttpError } from '../../../src/util/errors/BadRequestHttpError';
import { InternalServerError } from '../../../src/util/errors/InternalServerError'; import { InternalServerError } from '../../../src/util/errors/InternalServerError';
import { joinUrl } from '../../../src/util/PathUtil';
import { readableToString } from '../../../src/util/StreamUtil'; import { readableToString } from '../../../src/util/StreamUtil';
import { SOLID_HTTP, SOLID_META } from '../../../src/util/Vocabularies'; import { SOLID_HTTP, SOLID_META } from '../../../src/util/Vocabularies';
@ -43,7 +43,7 @@ describe('An IdentityProviderHttpHandler', (): void => {
requestParser = { requestParser = {
handleSafe: jest.fn(async(req: HttpRequest): Promise<Operation> => ({ handleSafe: jest.fn(async(req: HttpRequest): Promise<Operation> => ({
target: { path: urljoin(baseUrl, req.url!) }, target: { path: joinUrl(baseUrl, req.url!) },
method: req.method!, method: req.method!,
body: new BasicRepresentation('', req.headers['content-type'] ?? 'text/plain'), body: new BasicRepresentation('', req.headers['content-type'] ?? 'text/plain'),
preferences: { type: { 'text/html': 1 }}, preferences: { type: { 'text/html': 1 }},

View File

@ -1,4 +1,3 @@
import urljoin from 'url-join';
import { import {
RegistrationHandler, RegistrationHandler,
} from '../../../../../../src/identity/interaction/email-password/handler/RegistrationHandler'; } from '../../../../../../src/identity/interaction/email-password/handler/RegistrationHandler';
@ -10,6 +9,7 @@ import type { ResourceIdentifier } from '../../../../../../src/ldp/representatio
import type { IdentifierGenerator } from '../../../../../../src/pods/generate/IdentifierGenerator'; import type { IdentifierGenerator } from '../../../../../../src/pods/generate/IdentifierGenerator';
import type { PodManager } from '../../../../../../src/pods/PodManager'; import type { PodManager } from '../../../../../../src/pods/PodManager';
import type { PodSettings } from '../../../../../../src/pods/settings/PodSettings'; import type { PodSettings } from '../../../../../../src/pods/settings/PodSettings';
import { joinUrl } from '../../../../../../src/util/PathUtil';
import { createPostFormOperation } from './Util'; import { createPostFormOperation } from './Util';
describe('A RegistrationHandler', (): void => { describe('A RegistrationHandler', (): void => {
@ -248,7 +248,7 @@ describe('A RegistrationHandler', (): void => {
it('can create a WebID with an account and pod.', async(): Promise<void> => { it('can create a WebID with an account and pod.', async(): Promise<void> => {
const params = { email, password, confirmPassword, podName, createWebId, register, createPod }; const params = { email, password, confirmPassword, podName, createWebId, register, createPod };
const generatedWebID = urljoin(baseUrl, podName, webIdSuffix); const generatedWebID = joinUrl(baseUrl, podName, webIdSuffix);
podSettings.webId = generatedWebID; podSettings.webId = generatedWebID;
podSettings.oidcIssuer = baseUrl; podSettings.oidcIssuer = baseUrl;