Skip to content

Commit

Permalink
feat: use tsdoc
Browse files Browse the repository at this point in the history
  • Loading branch information
zeyu2001 committed Jul 17, 2024
1 parent cf7febe commit 9586a1e
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 2 deletions.
5 changes: 3 additions & 2 deletions packages/validators/.eslintrc
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{
"extends": ["opengovsg"],
"ignorePatterns": ["dist/**/*", "vitest.config.ts"],
"plugins": ["import"],
"plugins": ["import", "eslint-plugin-tsdoc"],
"rules": {
"import/no-unresolved": "error"
"import/no-unresolved": "error",
"tsdoc/syntax": "error"
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
Expand Down
1 change: 1 addition & 0 deletions packages/validators/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-tsdoc": "^0.3.0",
"prettier": "^2.8.4",
"tsup": "^8.1.0",
"typescript": "^5.4.5"
Expand Down
28 changes: 28 additions & 0 deletions packages/validators/src/url/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,28 @@ import { OptionsError, UrlValidationError } from '@/url/errors'
import { defaultOptions, Options, optionsSchema } from '@/url/options'
import { createUrlSchema } from '@/url/schema'

/**
* Validates URLs against a whitelist of allowed protocols and hostnames, preventing open redirects, XSS, SSRF, and other security vulnerabilities.
*/
export class UrlValidator {
private schema

/**
* Creates a new UrlValidator instance. If no options are provided, the validator will use the default options:
*
* ```ts
* {
* whitelist: {
* protocols: ['http', 'https'],
* },
* }
* ```
*
* @param options - The options to use for validation
* @throws {@link OptionsError} If the options are invalid
*
* @public
*/
constructor(options: Options = defaultOptions) {
const result = optionsSchema.safeParse({ ...defaultOptions, ...options })
if (result.success) {
Expand All @@ -17,6 +36,15 @@ export class UrlValidator {
throw new OptionsError(fromError(result.error).toString())
}

/**
* Parses a URL string.
*
* @param url - The URL to validate
* @returns The URL object if the URL is valid
* @throws {@link UrlValidationError} If the URL is invalid
*
* @public
*/
parse(url: string): URL {
const result = this.schema.safeParse(url)
if (result.success) {
Expand Down
10 changes: 10 additions & 0 deletions packages/validators/src/url/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,17 @@ export const defaultOptions = {
}

export const whitelistSchema = z.object({
/**
* The list of allowed protocols.
* Caution: allowing `javascript` or `data` protocols can lead to XSS vulnerabilities.
*
* @defaultValue ['http', 'https']
*/
protocols: z.array(z.string()).default(defaultOptions.whitelist.protocols),
/**
* The list of allowed hostnames.
* It is recommended to provide a list of allowed hostnames to prevent open redirects.
*/
hosts: z.array(z.string()).optional(),
})

Expand Down
52 changes: 52 additions & 0 deletions pnpm-lock.yaml

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

0 comments on commit 9586a1e

Please sign in to comment.