Skip to content

Commit

Permalink
match url whitelist to domain (directus#5694)
Browse files Browse the repository at this point in the history
* match url whitelist to domain

* Improve url-domain check

* Update lockfile

Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
  • Loading branch information
odama626 and rijkvanzanten authored Jun 9, 2021
1 parent 7ecbe49 commit c1b30a6
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 7 deletions.
9 changes: 3 additions & 6 deletions api/src/services/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import { RecordNotUniqueException } from '../exceptions/database/record-not-unique';
import logger from '../logger';
import { AbstractServiceOptions, Accountability, Item, PrimaryKey, Query, SchemaOverview } from '../types';
import isUrlAllowed from '../utils/is-url-allowed';
import { toArray } from '../utils/to-array';
import { AuthenticationService } from './authentication';
import { ItemsService, MutationOptions } from './items';
Expand Down Expand Up @@ -226,9 +227,7 @@ export class UsersService extends ItemsService {
async inviteUser(email: string | string[], role: string, url: string | null, subject?: string | null): Promise<void> {
const emails = toArray(email);

const urlWhitelist = toArray(env.USER_INVITE_URL_ALLOW_LIST);

if (url && urlWhitelist.includes(url) === false) {
if (url && isUrlAllowed(url, env.USER_INVITE_URL_ALLOW_LIST) === false) {
throw new InvalidPayloadException(`Url "${url}" can't be used to invite users.`);
}

Expand Down Expand Up @@ -305,9 +304,7 @@ export class UsersService extends ItemsService {
const payload = { email, scope: 'password-reset' };
const token = jwt.sign(payload, env.SECRET as string, { expiresIn: '1d' });

const urlWhitelist = toArray(env.PASSWORD_RESET_URL_ALLOW_LIST);

if (url && urlWhitelist.includes(url) === false) {
if (url && isUrlAllowed(url, env.PASSWORD_RESET_URL_ALLOW_LIST) === false) {
throw new InvalidPayloadException(`Url "${url}" can't be used to reset passwords.`);
}

Expand Down
29 changes: 29 additions & 0 deletions api/src/utils/is-url-allowed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { toArray } from './to-array';
import logger from '../logger';

/**
* Check if url matches allow list either exactly or by domain+path
*/
export default function isUrlAllowed(url: string, allowList: string | string[]): boolean {
console.log(url, allowList);

const urlAllowList = toArray(allowList);

if (urlAllowList.includes(url)) return true;

const parsedWhitelist = urlAllowList.map((allowedURL) => {
try {
const { hostname, pathname } = new URL(allowedURL);
return hostname + pathname;
} catch {
logger.warn(`Invalid URL used "${url}"`);
}
});

try {
const { hostname, pathname } = new URL(url);
return parsedWhitelist.includes(hostname + pathname);
} catch {
return false;
}
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit c1b30a6

Please sign in to comment.