forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1// Regex from the go implementation
2// https://github.com/bluesky-social/indigo/blob/main/atproto/syntax/handle.go#L10
3import {forceLTR} from '#/lib/strings/bidi'
4
5const VALIDATE_REGEX =
6 /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/
7
8export const MAX_SERVICE_HANDLE_LENGTH = 18
9
10export function isValidHandle(handle: string): boolean {
11 return VALIDATE_REGEX.test(handle)
12}
13
14export function makeValidHandle(str: string): string {
15 if (str.length > 20) {
16 str = str.slice(0, 20)
17 }
18 str = str.toLowerCase()
19 return str.replace(/^[^a-z0-9]+/g, '').replace(/[^a-z0-9-]/g, '')
20}
21
22export function createFullHandle(name: string, domain: string): string {
23 name = (name || '').replace(/[.]+$/, '')
24 domain = (domain || '').replace(/^[.]+/, '')
25 return `${name}.${domain}`
26}
27
28export function isInvalidHandle(handle: string): boolean {
29 return handle === 'handle.invalid'
30}
31
32export function sanitizeHandle(
33 handle: string,
34 prefix = '',
35 forceLeftToRight = true,
36): string {
37 const lowercasedWithPrefix = `${prefix}${handle.toLocaleLowerCase()}`
38 return isInvalidHandle(handle)
39 ? '鈿營nvalid Handle'
40 : forceLeftToRight
41 ? forceLTR(lowercasedWithPrefix)
42 : lowercasedWithPrefix
43}
44
45export interface IsValidHandle {
46 handleChars: boolean
47 hyphenStartOrEnd: boolean
48 frontLengthNotTooShort: boolean
49 frontLengthNotTooLong: boolean
50 totalLength: boolean
51 overall: boolean
52}
53
54// More checks from https://github.com/bluesky-social/atproto/blob/main/packages/pds/src/handle/index.ts#L72
55export function validateServiceHandle(
56 str: string,
57 userDomain: string,
58): IsValidHandle {
59 const fullHandle = createFullHandle(str, userDomain)
60
61 const results = {
62 handleChars:
63 !str || (VALIDATE_REGEX.test(fullHandle) && !str.includes('.')),
64 hyphenStartOrEnd: !str.startsWith('-') && !str.endsWith('-'),
65 frontLengthNotTooShort: str.length >= 3,
66 frontLengthNotTooLong: str.length <= MAX_SERVICE_HANDLE_LENGTH,
67 totalLength: fullHandle.length <= 253,
68 }
69
70 return {
71 ...results,
72 overall: !Object.values(results).includes(false),
73 }
74}