Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
"default": "./dist/cjs/index.js"
}
},
"./utils": {
"import": {
"types": "./dist/esm/utils.d.mts",
"default": "./dist/esm/utils/index.mjs"
},
"require": {
"types": "./dist/cjs/utils.d.ts",
"default": "./dist/cjs/utils/index.js"
}
},
"./package.json": "./package.json"
},
"files": [
Expand Down
65 changes: 5 additions & 60 deletions src/nurl.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {decode, encode} from './punycode'
import {mask, MaskOptions, match as matchUrlPattern} from './utils'
import {
extractPathKey,
getDynamicPaths,
Expand All @@ -8,8 +9,7 @@ import {
refineQueryWithPathname,
convertQueryToArray,
Query,
getPathPriority,
} from './utils'
} from './utils/internal'

interface URLOptions
extends Partial<
Expand All @@ -32,14 +32,6 @@ interface URLOptions
basePath?: string
}

export interface MaskOptions {
patterns: string[]
sensitiveParams: string[]
maskChar?: string
maskLength?: number
preserveLength?: boolean
}

export default class NURL implements URL {
private _href: string = ''
private _protocol: string = ''
Expand Down Expand Up @@ -483,57 +475,10 @@ export default class NURL implements URL {
}

static match(url: string, pattern: string) {
if (!NURL.canParse(url) || !NURL.canParse(pattern)) {
return null
}

const urlSegments = url.split(/[?#]/)[0]?.split('/').filter(Boolean) || []
const patternSegments = pattern.split(/[?#]/)[0]?.split('/').filter(Boolean) || []

if (urlSegments.length !== patternSegments.length) {
return null
}

const params: Record<string, string> = {}

for (let i = 0; i < patternSegments.length; i++) {
const patternSegment = patternSegments[i]
const urlSegment = urlSegments[i]

if (isDynamicPath(patternSegment)) {
const pathKey = extractPathKey(patternSegment)
params[pathKey] = urlSegment
} else if (patternSegment !== urlSegment) {
return null
}
}

return params
return matchUrlPattern(url, pattern)
}

static mask(
url: string,
{patterns, sensitiveParams, maskChar = '*', maskLength = 4, preserveLength = false}: MaskOptions,
) {
const sortedPatterns = [...patterns].sort((a, b) => (getPathPriority(b) > getPathPriority(a) ? 1 : -1))
for (const pattern of sortedPatterns) {
const urlObj = NURL.create(url)
const matchedParams = NURL.match(urlObj.pathname, pattern)
if (!matchedParams) {
continue
}
sensitiveParams.forEach((sensitiveParam) => {
if (sensitiveParam in matchedParams) {
const originalValue = matchedParams[sensitiveParam]
const lengthToMask = preserveLength ? originalValue.length : maskLength
matchedParams[sensitiveParam] = maskChar.repeat(lengthToMask)
}
})

urlObj.pathname = refinePathnameWithQuery(pattern, matchedParams)
return urlObj.toString()
}

return url
static mask(url: string, options: MaskOptions) {
return mask(url, options)
}
}
65 changes: 65 additions & 0 deletions src/utils/external.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import NURL from '../nurl'
import {extractPathKey, getPathPriority, isDynamicPath, refinePathnameWithQuery} from './internal'

export const match = (url: string, pattern: string): Record<string, string> | null => {
if (!NURL.canParse(url) || !NURL.canParse(pattern)) {
return null
}

const urlSegments = url.split(/[?#]/)[0]?.split('/').filter(Boolean) || []
const patternSegments = pattern.split(/[?#]/)[0]?.split('/').filter(Boolean) || []

if (urlSegments.length !== patternSegments.length) {
return null
}

const params: Record<string, string> = {}

for (let i = 0; i < patternSegments.length; i++) {
const patternSegment = patternSegments[i]
const urlSegment = urlSegments[i]

if (isDynamicPath(patternSegment)) {
const pathKey = extractPathKey(patternSegment)
params[pathKey] = urlSegment
} else if (patternSegment !== urlSegment) {
return null
}
}

return params
}

export interface MaskOptions {
patterns: string[]
sensitiveParams: string[]
maskChar?: string
maskLength?: number
preserveLength?: boolean
}

export const mask = (
url: string,
{patterns, sensitiveParams, maskChar = '*', maskLength = 4, preserveLength = false}: MaskOptions,
) => {
const sortedPatterns = [...patterns].sort((a, b) => (getPathPriority(b) > getPathPriority(a) ? 1 : -1))
for (const pattern of sortedPatterns) {
const urlObj = NURL.create(url)
const matchedParams = match(urlObj.pathname, pattern)
if (!matchedParams) {
continue
}
sensitiveParams.forEach((sensitiveParam) => {
if (sensitiveParam in matchedParams) {
const originalValue = matchedParams[sensitiveParam]
const lengthToMask = preserveLength ? originalValue.length : maskLength
matchedParams[sensitiveParam] = maskChar.repeat(lengthToMask)
}
})

urlObj.pathname = refinePathnameWithQuery(pattern, matchedParams)
return urlObj.toString()
}

return url
}
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './external'
File renamed without changes.
1 change: 1 addition & 0 deletions vite.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default createViteConfig({
cwd: __dirname,
entry: {
index: './src/index.ts',
utils: './src/utils/index.ts',
},
outputs: [
{format: 'es', dist: 'dist/esm'},
Expand Down
Loading