Skip to content

Commit

Permalink
refactor: rename baseUrl as baseOrigin
Browse files Browse the repository at this point in the history
  • Loading branch information
zeyu2001 committed Jul 16, 2024
1 parent f65c7cf commit 2aae17f
Show file tree
Hide file tree
Showing 5 changed files with 15 additions and 13 deletions.
2 changes: 1 addition & 1 deletion packages/validators/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Validates URLs against a whitelist of allowed protocols and hostnames, preventin

`options?`: `<Object>`

- `baseUrl`: `<string>` - The base URL to use for relative URLs. If no base URL is provided, relative URLs will be considered invalid.
- `baseOrigin`: `<string>` - The base origin to use for relative URLs. If no base origin is provided, relative URLs will be considered invalid. An origin does not include the path or query parameters. For example, a valid base origin is `https://example.com`.
- `whitelist`: `<Object>`
- `protocols`: `<string[]>` - A list of allowed protocols. If no protocols are provided, the validator will use the default protocols: `['http', 'https']`. **Caution: allowing `javascript` or `data` protocols can lead to XSS vulnerabilities.**
- `hostnames`: `<string[]>` - A list of allowed hostnames. If no hostnames are provided, the validator will allow any hostname. **It is recommended to provide a list of allowed hostnames to prevent open redirects.**
Expand Down
10 changes: 6 additions & 4 deletions packages/validators/src/__tests__/url.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ describe('UrlValidator with custom host whitelist', () => {

describe('UrlValidator with base URL', () => {
const validator = new UrlValidator({
baseUrl: 'https://example.com',
baseOrigin: 'https://example.com',
})

it('should parse a valid relative URL', () => {
Expand Down Expand Up @@ -131,18 +131,20 @@ describe('UrlValidator with base URL', () => {

describe('UrlValidator with invalid options', () => {
it('should throw an error when the base URL is not a valid URL', () => {
expect(() => new UrlValidator({ baseUrl: 'invalid' })).toThrow(OptionsError)
expect(() => new UrlValidator({ baseOrigin: 'invalid' })).toThrow(
OptionsError,
)
})

it('should throw an error when the base URL protocol is not http or https', () => {
expect(() => new UrlValidator({ baseUrl: 'ftp://example.com' })).toThrow(
expect(() => new UrlValidator({ baseOrigin: 'ftp://example.com' })).toThrow(
OptionsError,
)
})

it('should throw an error when the base URL has a path', () => {
expect(
() => new UrlValidator({ baseUrl: 'https://example.com/path' }),
() => new UrlValidator({ baseOrigin: 'https://example.com/path' }),
).toThrow(OptionsError)
})
})
2 changes: 1 addition & 1 deletion packages/validators/src/url/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const whitelistSchema = z.object({
export type Whitelist = z.infer<typeof whitelistSchema>

export const optionsSchema = z.object({
baseUrl: z
baseOrigin: z
.string()
.transform((value, ctx) => {
if (!URL.canParse(value)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/validators/src/url/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { isSafeUrl, resolveRelativeUrl } from '@/url/utils'
export const createUrlSchema = (options: Options) => {
return z
.string()
.transform((url) => resolveRelativeUrl(url, options.baseUrl))
.transform((url) => resolveRelativeUrl(url, options.baseOrigin))
.refine((url) => isSafeUrl(url, options.whitelist), {
message: 'Unsafe URL',
})
Expand Down
12 changes: 6 additions & 6 deletions packages/validators/src/url/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@ import { Whitelist } from '@/url/options'

const DYNAMIC_ROUTE_SEGMENT_REGEX = /\[\[?([^\]]+)\]?\]/g

export const resolveRelativeUrl = (url: string, baseUrl?: URL): URL => {
if (!baseUrl) {
export const resolveRelativeUrl = (url: string, baseOrigin?: URL): URL => {
if (!baseOrigin) {
if (!URL.canParse(url)) {
throw new UrlValidationError(`Invalid URL: ${url}`)
}
return new URL(url)
}

if (!URL.canParse(url, baseUrl)) {
if (!URL.canParse(url, baseOrigin)) {
throw new UrlValidationError(`Invalid URL: ${url}`)
}
const normalizedUrl = new URL(url, baseUrl)
const normalizedUrl = new URL(url, baseOrigin)

if (new URL(baseUrl).origin !== normalizedUrl.origin) {
if (new URL(baseOrigin).origin !== normalizedUrl.origin) {
throw new UrlValidationError(
`Invalid URL: ${url} is not on the same origin as base URL ${baseUrl.href}`,
`Invalid URL: ${url} is not on the same origin as base URL ${baseOrigin.href}`,
)
}
return normalizedUrl
Expand Down

0 comments on commit 2aae17f

Please sign in to comment.