Improved service handle validation logic (#7657)
* fix validation logic for 3p pdses * fix bad import * add service handle validation test
This commit is contained in:
@@ -0,0 +1,42 @@
|
|||||||
|
import {IsValidHandle, validateServiceHandle} from '#/lib/strings/handles'
|
||||||
|
|
||||||
|
describe('handle validation', () => {
|
||||||
|
const valid = [
|
||||||
|
['ali', 'bsky.social'],
|
||||||
|
['alice', 'bsky.social'],
|
||||||
|
['a-lice', 'bsky.social'],
|
||||||
|
['a-----lice', 'bsky.social'],
|
||||||
|
['123', 'bsky.social'],
|
||||||
|
['123456789012345678', 'bsky.social'],
|
||||||
|
['alice', 'custom-pds.com'],
|
||||||
|
['alice', 'my-custom-pds-with-long-name.social'],
|
||||||
|
['123456789012345678', 'my-custom-pds-with-long-name.social'],
|
||||||
|
]
|
||||||
|
it.each(valid)(`should be valid: %s.%s`, (handle, service) => {
|
||||||
|
const result = validateServiceHandle(handle, service)
|
||||||
|
expect(result.overall).toEqual(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
const invalid = [
|
||||||
|
['al', 'bsky.social', 'frontLength'],
|
||||||
|
['-alice', 'bsky.social', 'hyphenStartOrEnd'],
|
||||||
|
['alice-', 'bsky.social', 'hyphenStartOrEnd'],
|
||||||
|
['%%%', 'bsky.social', 'handleChars'],
|
||||||
|
['1234567890123456789', 'bsky.social', 'frontLength'],
|
||||||
|
[
|
||||||
|
'1234567890123456789',
|
||||||
|
'my-custom-pds-with-long-name.social',
|
||||||
|
'frontLength',
|
||||||
|
],
|
||||||
|
['al', 'my-custom-pds-with-long-name.social', 'frontLength'],
|
||||||
|
['a'.repeat(300), 'toolong.com', 'totalLength'],
|
||||||
|
] satisfies [string, string, keyof IsValidHandle][]
|
||||||
|
it.each(invalid)(
|
||||||
|
`should be invalid: %s.%s due to %s`,
|
||||||
|
(handle, service, expectedError) => {
|
||||||
|
const result = validateServiceHandle(handle, service)
|
||||||
|
expect(result.overall).toEqual(false)
|
||||||
|
expect(result[expectedError]).toEqual(false)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
@@ -42,10 +42,9 @@ export interface IsValidHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// More checks from https://github.com/bluesky-social/atproto/blob/main/packages/pds/src/handle/index.ts#L72
|
// More checks from https://github.com/bluesky-social/atproto/blob/main/packages/pds/src/handle/index.ts#L72
|
||||||
export function validateHandle(
|
export function validateServiceHandle(
|
||||||
str: string,
|
str: string,
|
||||||
userDomain: string,
|
userDomain: string,
|
||||||
isServiceHandle?: boolean,
|
|
||||||
): IsValidHandle {
|
): IsValidHandle {
|
||||||
const fullHandle = createFullHandle(str, userDomain)
|
const fullHandle = createFullHandle(str, userDomain)
|
||||||
|
|
||||||
@@ -53,8 +52,8 @@ export function validateHandle(
|
|||||||
handleChars:
|
handleChars:
|
||||||
!str || (VALIDATE_REGEX.test(fullHandle) && !str.includes('.')),
|
!str || (VALIDATE_REGEX.test(fullHandle) && !str.includes('.')),
|
||||||
hyphenStartOrEnd: !str.startsWith('-') && !str.endsWith('-'),
|
hyphenStartOrEnd: !str.startsWith('-') && !str.endsWith('-'),
|
||||||
frontLength: str.length >= 3,
|
frontLength: str.length >= 3 && str.length <= 18,
|
||||||
totalLength: fullHandle.length <= (isServiceHandle ? 30 : 253),
|
totalLength: fullHandle.length <= 253,
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ import {useMutation, useQueryClient} from '@tanstack/react-query'
|
|||||||
|
|
||||||
import {HITSLOP_10} from '#/lib/constants'
|
import {HITSLOP_10} from '#/lib/constants'
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
import {cleanError} from '#/lib/strings/errors'
|
||||||
|
import {createFullHandle, validateServiceHandle} from '#/lib/strings/handles'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
import {createFullHandle, validateHandle} from '#/lib/strings/handles'
|
|
||||||
import {useFetchDid, useUpdateHandleMutation} from '#/state/queries/handle'
|
import {useFetchDid, useUpdateHandleMutation} from '#/state/queries/handle'
|
||||||
import {RQKEY as RQKEY_PROFILE} from '#/state/queries/profile'
|
import {RQKEY as RQKEY_PROFILE} from '#/state/queries/profile'
|
||||||
import {useServiceQuery} from '#/state/queries/service'
|
import {useServiceQuery} from '#/state/queries/service'
|
||||||
@@ -172,7 +172,7 @@ function ProvidedHandlePage({
|
|||||||
const host = serviceInfo.availableUserDomains[0]
|
const host = serviceInfo.availableUserDomains[0]
|
||||||
|
|
||||||
const validation = useMemo(
|
const validation = useMemo(
|
||||||
() => validateHandle(subdomain, host, true),
|
() => validateServiceHandle(subdomain, host),
|
||||||
[subdomain, host],
|
[subdomain, host],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {logEvent} from '#/lib/statsig/statsig'
|
|||||||
import {
|
import {
|
||||||
createFullHandle,
|
createFullHandle,
|
||||||
maxServiceHandleLength,
|
maxServiceHandleLength,
|
||||||
validateHandle,
|
validateServiceHandle,
|
||||||
} from '#/lib/strings/handles'
|
} from '#/lib/strings/handles'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
import {ScreenTransition} from '#/screens/Login/ScreenTransition'
|
import {ScreenTransition} from '#/screens/Login/ScreenTransition'
|
||||||
@@ -37,7 +37,7 @@ export function StepHandle() {
|
|||||||
value: handle,
|
value: handle,
|
||||||
})
|
})
|
||||||
|
|
||||||
const newValidCheck = validateHandle(handle, state.userDomain)
|
const newValidCheck = validateServiceHandle(handle, state.userDomain)
|
||||||
if (!newValidCheck.overall) {
|
if (!newValidCheck.overall) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -97,7 +97,7 @@ export function StepHandle() {
|
|||||||
})
|
})
|
||||||
}, [dispatch, state.activeStep])
|
}, [dispatch, state.activeStep])
|
||||||
|
|
||||||
const validCheck = validateHandle(draftValue, state.userDomain, true)
|
const validCheck = validateServiceHandle(draftValue, state.userDomain)
|
||||||
return (
|
return (
|
||||||
<ScreenTransition>
|
<ScreenTransition>
|
||||||
<View style={[a.gap_lg]}>
|
<View style={[a.gap_lg]}>
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"types": ["node"],
|
"types": ["node", "jest"],
|
||||||
"paths": {
|
"paths": {
|
||||||
"#/*": ["./src/*"],
|
"#/*": ["./src/*"],
|
||||||
"lib/*": ["./src/lib/*"],
|
"lib/*": ["./src/lib/*"],
|
||||||
|
|||||||
Reference in New Issue
Block a user