about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--__tests__/lib/strings/handles.test.ts42
-rw-r--r--src/lib/strings/handles.ts7
-rw-r--r--src/screens/Settings/components/ChangeHandleDialog.tsx4
-rw-r--r--src/screens/Signup/StepHandle.tsx6
-rw-r--r--tsconfig.json2
5 files changed, 51 insertions, 10 deletions
diff --git a/__tests__/lib/strings/handles.test.ts b/__tests__/lib/strings/handles.test.ts
new file mode 100644
index 000000000..4456fae94
--- /dev/null
+++ b/__tests__/lib/strings/handles.test.ts
@@ -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)
+    },
+  )
+})
diff --git a/src/lib/strings/handles.ts b/src/lib/strings/handles.ts
index bf329a869..754d219ed 100644
--- a/src/lib/strings/handles.ts
+++ b/src/lib/strings/handles.ts
@@ -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
-export function validateHandle(
+export function validateServiceHandle(
   str: string,
   userDomain: string,
-  isServiceHandle?: boolean,
 ): IsValidHandle {
   const fullHandle = createFullHandle(str, userDomain)
 
@@ -53,8 +52,8 @@ export function validateHandle(
     handleChars:
       !str || (VALIDATE_REGEX.test(fullHandle) && !str.includes('.')),
     hyphenStartOrEnd: !str.startsWith('-') && !str.endsWith('-'),
-    frontLength: str.length >= 3,
-    totalLength: fullHandle.length <= (isServiceHandle ? 30 : 253),
+    frontLength: str.length >= 3 && str.length <= 18,
+    totalLength: fullHandle.length <= 253,
   }
 
   return {
diff --git a/src/screens/Settings/components/ChangeHandleDialog.tsx b/src/screens/Settings/components/ChangeHandleDialog.tsx
index 37f6ed9ef..6450e24b2 100644
--- a/src/screens/Settings/components/ChangeHandleDialog.tsx
+++ b/src/screens/Settings/components/ChangeHandleDialog.tsx
@@ -17,8 +17,8 @@ import {useMutation, useQueryClient} from '@tanstack/react-query'
 
 import {HITSLOP_10} from '#/lib/constants'
 import {cleanError} from '#/lib/strings/errors'
+import {createFullHandle, validateServiceHandle} 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 {RQKEY as RQKEY_PROFILE} from '#/state/queries/profile'
 import {useServiceQuery} from '#/state/queries/service'
@@ -172,7 +172,7 @@ function ProvidedHandlePage({
   const host = serviceInfo.availableUserDomains[0]
 
   const validation = useMemo(
-    () => validateHandle(subdomain, host, true),
+    () => validateServiceHandle(subdomain, host),
     [subdomain, host],
   )
 
diff --git a/src/screens/Signup/StepHandle.tsx b/src/screens/Signup/StepHandle.tsx
index 1d04264ae..c06fa29d1 100644
--- a/src/screens/Signup/StepHandle.tsx
+++ b/src/screens/Signup/StepHandle.tsx
@@ -7,7 +7,7 @@ import {logEvent} from '#/lib/statsig/statsig'
 import {
   createFullHandle,
   maxServiceHandleLength,
-  validateHandle,
+  validateServiceHandle,
 } from '#/lib/strings/handles'
 import {useAgent} from '#/state/session'
 import {ScreenTransition} from '#/screens/Login/ScreenTransition'
@@ -37,7 +37,7 @@ export function StepHandle() {
       value: handle,
     })
 
-    const newValidCheck = validateHandle(handle, state.userDomain)
+    const newValidCheck = validateServiceHandle(handle, state.userDomain)
     if (!newValidCheck.overall) {
       return
     }
@@ -97,7 +97,7 @@ export function StepHandle() {
     })
   }, [dispatch, state.activeStep])
 
-  const validCheck = validateHandle(draftValue, state.userDomain, true)
+  const validCheck = validateServiceHandle(draftValue, state.userDomain)
   return (
     <ScreenTransition>
       <View style={[a.gap_lg]}>
diff --git a/tsconfig.json b/tsconfig.json
index 1c5e27eec..001b5247e 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -3,7 +3,7 @@
   "compilerOptions": {
     "jsx": "react-jsx",
     "module": "esnext",
-    "types": ["node"],
+    "types": ["node", "jest"],
     "paths": {
       "#/*": ["./src/*"],
       "lib/*": ["./src/lib/*"],