Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Improved service handle validation logic (#7657)

* fix validation logic for 3p pdses

* fix bad import

* add service handle validation test

authored by

Samuel Newman and committed by
GitHub
1db2668a 00c08ba5

+51 -10
+42
__tests__/lib/strings/handles.test.ts
··· 1 + import {IsValidHandle, validateServiceHandle} from '#/lib/strings/handles' 2 + 3 + describe('handle validation', () => { 4 + const valid = [ 5 + ['ali', 'bsky.social'], 6 + ['alice', 'bsky.social'], 7 + ['a-lice', 'bsky.social'], 8 + ['a-----lice', 'bsky.social'], 9 + ['123', 'bsky.social'], 10 + ['123456789012345678', 'bsky.social'], 11 + ['alice', 'custom-pds.com'], 12 + ['alice', 'my-custom-pds-with-long-name.social'], 13 + ['123456789012345678', 'my-custom-pds-with-long-name.social'], 14 + ] 15 + it.each(valid)(`should be valid: %s.%s`, (handle, service) => { 16 + const result = validateServiceHandle(handle, service) 17 + expect(result.overall).toEqual(true) 18 + }) 19 + 20 + const invalid = [ 21 + ['al', 'bsky.social', 'frontLength'], 22 + ['-alice', 'bsky.social', 'hyphenStartOrEnd'], 23 + ['alice-', 'bsky.social', 'hyphenStartOrEnd'], 24 + ['%%%', 'bsky.social', 'handleChars'], 25 + ['1234567890123456789', 'bsky.social', 'frontLength'], 26 + [ 27 + '1234567890123456789', 28 + 'my-custom-pds-with-long-name.social', 29 + 'frontLength', 30 + ], 31 + ['al', 'my-custom-pds-with-long-name.social', 'frontLength'], 32 + ['a'.repeat(300), 'toolong.com', 'totalLength'], 33 + ] satisfies [string, string, keyof IsValidHandle][] 34 + it.each(invalid)( 35 + `should be invalid: %s.%s due to %s`, 36 + (handle, service, expectedError) => { 37 + const result = validateServiceHandle(handle, service) 38 + expect(result.overall).toEqual(false) 39 + expect(result[expectedError]).toEqual(false) 40 + }, 41 + ) 42 + })
+3 -4
src/lib/strings/handles.ts
··· 42 42 } 43 43 44 44 // More checks from https://github.com/bluesky-social/atproto/blob/main/packages/pds/src/handle/index.ts#L72 45 - export function validateHandle( 45 + export function validateServiceHandle( 46 46 str: string, 47 47 userDomain: string, 48 - isServiceHandle?: boolean, 49 48 ): IsValidHandle { 50 49 const fullHandle = createFullHandle(str, userDomain) 51 50 ··· 53 52 handleChars: 54 53 !str || (VALIDATE_REGEX.test(fullHandle) && !str.includes('.')), 55 54 hyphenStartOrEnd: !str.startsWith('-') && !str.endsWith('-'), 56 - frontLength: str.length >= 3, 57 - totalLength: fullHandle.length <= (isServiceHandle ? 30 : 253), 55 + frontLength: str.length >= 3 && str.length <= 18, 56 + totalLength: fullHandle.length <= 253, 58 57 } 59 58 60 59 return {
+2 -2
src/screens/Settings/components/ChangeHandleDialog.tsx
··· 17 17 18 18 import {HITSLOP_10} from '#/lib/constants' 19 19 import {cleanError} from '#/lib/strings/errors' 20 + import {createFullHandle, validateServiceHandle} from '#/lib/strings/handles' 20 21 import {sanitizeHandle} from '#/lib/strings/handles' 21 - import {createFullHandle, validateHandle} from '#/lib/strings/handles' 22 22 import {useFetchDid, useUpdateHandleMutation} from '#/state/queries/handle' 23 23 import {RQKEY as RQKEY_PROFILE} from '#/state/queries/profile' 24 24 import {useServiceQuery} from '#/state/queries/service' ··· 172 172 const host = serviceInfo.availableUserDomains[0] 173 173 174 174 const validation = useMemo( 175 - () => validateHandle(subdomain, host, true), 175 + () => validateServiceHandle(subdomain, host), 176 176 [subdomain, host], 177 177 ) 178 178
+3 -3
src/screens/Signup/StepHandle.tsx
··· 7 7 import { 8 8 createFullHandle, 9 9 maxServiceHandleLength, 10 - validateHandle, 10 + validateServiceHandle, 11 11 } from '#/lib/strings/handles' 12 12 import {useAgent} from '#/state/session' 13 13 import {ScreenTransition} from '#/screens/Login/ScreenTransition' ··· 37 37 value: handle, 38 38 }) 39 39 40 - const newValidCheck = validateHandle(handle, state.userDomain) 40 + const newValidCheck = validateServiceHandle(handle, state.userDomain) 41 41 if (!newValidCheck.overall) { 42 42 return 43 43 } ··· 97 97 }) 98 98 }, [dispatch, state.activeStep]) 99 99 100 - const validCheck = validateHandle(draftValue, state.userDomain, true) 100 + const validCheck = validateServiceHandle(draftValue, state.userDomain) 101 101 return ( 102 102 <ScreenTransition> 103 103 <View style={[a.gap_lg]}>
+1 -1
tsconfig.json
··· 3 3 "compilerOptions": { 4 4 "jsx": "react-jsx", 5 5 "module": "esnext", 6 - "types": ["node"], 6 + "types": ["node", "jest"], 7 7 "paths": { 8 8 "#/*": ["./src/*"], 9 9 "lib/*": ["./src/lib/*"],