| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package At::Protocol::Handle 1.0 { |
|
2
|
5
|
|
|
5
|
|
217630
|
use v5.42; |
|
|
5
|
|
|
|
|
18
|
|
|
3
|
5
|
|
|
5
|
|
474
|
use At::Error qw[register throw]; |
|
|
5
|
|
|
|
|
9
|
|
|
|
5
|
|
|
|
|
63
|
|
|
4
|
5
|
|
|
5
|
|
496
|
use parent -norequire => 'Exporter'; |
|
|
5
|
|
|
|
|
390
|
|
|
|
5
|
|
|
|
|
28
|
|
|
5
|
5
|
|
|
5
|
|
312
|
use feature 'try'; |
|
|
5
|
|
|
|
|
17
|
|
|
|
5
|
|
|
|
|
565
|
|
|
6
|
5
|
|
|
5
|
|
24
|
no warnings qw[experimental::try]; |
|
|
5
|
|
|
|
|
16
|
|
|
|
5
|
|
|
|
|
460
|
|
|
7
|
|
|
|
|
|
|
use overload |
|
8
|
27
|
|
|
27
|
|
4249
|
'""' => sub ( $s, $u, $q ) { |
|
|
27
|
|
|
|
|
46
|
|
|
|
27
|
|
|
|
|
42
|
|
|
|
27
|
|
|
|
|
35
|
|
|
|
27
|
|
|
|
|
37
|
|
|
9
|
27
|
|
|
|
|
118
|
$$s; |
|
10
|
5
|
|
|
5
|
|
31
|
}; |
|
|
5
|
|
|
|
|
8
|
|
|
|
5
|
|
|
|
|
36
|
|
|
11
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( |
|
12
|
|
|
|
|
|
|
all => [ |
|
13
|
|
|
|
|
|
|
our @EXPORT_OK |
|
14
|
|
|
|
|
|
|
= qw[ |
|
15
|
|
|
|
|
|
|
ensureValidHandle ensureValidHandleRegex |
|
16
|
|
|
|
|
|
|
normalizeHandle normalizeAndEnsureValidHandle |
|
17
|
|
|
|
|
|
|
isValidHandle isValidTld] |
|
18
|
|
|
|
|
|
|
] |
|
19
|
|
|
|
|
|
|
); |
|
20
|
|
|
|
|
|
|
# |
|
21
|
|
|
|
|
|
|
my $INVALID_HANDLE = 'handle.invalid'; |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
#~ Currently these are registration-time restrictions, not protocol-level |
|
24
|
|
|
|
|
|
|
#~ restrictions. We have a couple accounts in the wild that we need to clean up |
|
25
|
|
|
|
|
|
|
#~ before hard-disallow. |
|
26
|
|
|
|
|
|
|
#~ See also: https://en.wikipedia.org/wiki/Top-level_domain#Reserved_domains |
|
27
|
|
|
|
|
|
|
my @DISALLOWED_TLDS = ( |
|
28
|
|
|
|
|
|
|
'.local', '.arpa', '.invalid', '.localhost', '.internal', '.example', '.alt', |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# policy could concievably change on ".onion" some day |
|
31
|
|
|
|
|
|
|
'.onion', |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
#~ NOTE: .test is allowed in testing and devopment. In practical terms |
|
34
|
|
|
|
|
|
|
#~ "should" "never" actually resolve and get registered in production |
|
35
|
|
|
|
|
|
|
); |
|
36
|
|
|
|
|
|
|
|
|
37
|
22
|
|
|
22
|
1
|
290475
|
sub new( $class, $id ) { |
|
|
22
|
|
|
|
|
34
|
|
|
|
22
|
|
|
|
|
34
|
|
|
|
22
|
|
|
|
|
25
|
|
|
38
|
22
|
100
|
|
|
|
59
|
throw UnsupportedDomainError('invalid TLD') unless isValidTld($id); |
|
39
|
19
|
|
|
|
|
47
|
ensureValidHandle($id); |
|
40
|
10
|
|
|
|
|
21
|
ensureValidHandleRegex($id); |
|
41
|
10
|
|
100
|
|
|
23
|
CORE::state $warned //= 0; |
|
42
|
10
|
100
|
100
|
|
|
29
|
if ( $id =~ /\.(test)$/ && !$warned ) { |
|
43
|
1
|
|
|
|
|
8
|
require Carp; |
|
44
|
1
|
|
|
|
|
158
|
Carp::carp 'development or testing TLD used in handle: ' . $id; |
|
45
|
1
|
|
|
|
|
5
|
$warned = 1; |
|
46
|
|
|
|
|
|
|
} |
|
47
|
10
|
|
|
|
|
72
|
bless \$id, $class; |
|
48
|
|
|
|
|
|
|
} |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# Taken from https://github.com/bluesky-social/atproto/blob/main/packages/syntax/src/handle.ts |
|
51
|
|
|
|
|
|
|
# Handle constraints, in English: |
|
52
|
|
|
|
|
|
|
# - must be a possible domain name |
|
53
|
|
|
|
|
|
|
# - RFC-1035 is commonly referenced, but has been updated. eg, RFC-3696, |
|
54
|
|
|
|
|
|
|
# section 2. and RFC-3986, section 3. can now have leading numbers (eg, |
|
55
|
|
|
|
|
|
|
# 4chan.org) |
|
56
|
|
|
|
|
|
|
# - "labels" (sub-names) are made of ASCII letters, digits, hyphens |
|
57
|
|
|
|
|
|
|
# - can not start or end with a hyphen |
|
58
|
|
|
|
|
|
|
# - TLD (last component) should not start with a digit |
|
59
|
|
|
|
|
|
|
# - can't end with a hyphen (can end with digit) |
|
60
|
|
|
|
|
|
|
# - each segment must be between 1 and 63 characters (not including any periods) |
|
61
|
|
|
|
|
|
|
# - overall length can't be more than 253 characters |
|
62
|
|
|
|
|
|
|
# - separated by (ASCII) periods; does not start or end with period |
|
63
|
|
|
|
|
|
|
# - case insensitive |
|
64
|
|
|
|
|
|
|
# - domains (handles) are equal if they are the same lower-case |
|
65
|
|
|
|
|
|
|
# - punycode allowed for internationalization |
|
66
|
|
|
|
|
|
|
# - no whitespace, null bytes, joining chars, etc |
|
67
|
|
|
|
|
|
|
# - does not validate whether domain or TLD exists, or is a reserved or |
|
68
|
|
|
|
|
|
|
# special TLD (eg, .onion or .local) |
|
69
|
|
|
|
|
|
|
# - does not validate punycode |
|
70
|
291
|
|
|
291
|
1
|
869659
|
sub ensureValidHandle ($handle) { |
|
|
291
|
|
|
|
|
889
|
|
|
|
291
|
|
|
|
|
479
|
|
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
# check that all chars are boring ASCII |
|
73
|
291
|
100
|
|
|
|
2090
|
throw InvalidHandleError('Disallowed characters in handle (ASCII letters, digits, dashes, periods only)') if $handle !~ /^[a-zA-Z0-9.-]*$/; |
|
74
|
|
|
|
|
|
|
# |
|
75
|
243
|
100
|
|
|
|
876
|
throw InvalidHandleError('Handle is too long (253 chars max)') if length $handle > 253; |
|
76
|
|
|
|
|
|
|
# |
|
77
|
240
|
|
|
|
|
924
|
my @labels = split /\./, $handle, -1; # negative limit, ftw |
|
78
|
240
|
100
|
|
|
|
748
|
throw InvalidHandleError('Handle domain needs at least two parts') if scalar @labels < 2; |
|
79
|
221
|
|
|
|
|
912
|
for my $i ( 0 .. $#labels ) { |
|
80
|
512
|
|
|
|
|
993
|
my $l = $labels[$i]; |
|
81
|
512
|
100
|
|
|
|
1036
|
throw InvalidHandleError('Handle parts can not be empty') if !length $l; |
|
82
|
496
|
100
|
|
|
|
1075
|
throw InvalidHandleError('Handle part too long (max 63 chars)') if length $l > 63; |
|
83
|
494
|
100
|
|
|
|
2559
|
throw InvalidHandleError('Handle parts can not start or end with hyphens') if $l =~ /^-|-$/; |
|
84
|
475
|
100
|
100
|
|
|
2213
|
throw InvalidHandleError('Handle final component (TLD) must start with ASCII letter') if $i == $#labels && $l !~ /^[a-zA-Z]/; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
166
|
|
|
|
|
1269
|
1; |
|
87
|
|
|
|
|
|
|
} |
|
88
|
|
|
|
|
|
|
|
|
89
|
357
|
|
|
357
|
1
|
53897
|
sub ensureValidHandleRegex ($handle) { |
|
|
357
|
|
|
|
|
765
|
|
|
|
357
|
|
|
|
|
685
|
|
|
90
|
357
|
100
|
|
|
|
4140
|
throw InvalidHandleError(q[Handle didn't validate via regex]) |
|
91
|
|
|
|
|
|
|
unless $handle =~ /^([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])?$/; |
|
92
|
160
|
100
|
|
|
|
545
|
throw InvalidHandleError('Handle is too long (253 chars max)') if length $handle > 253; |
|
93
|
157
|
|
|
|
|
512
|
1; |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
|
|
96
|
2
|
|
|
2
|
1
|
4
|
sub normalizeHandle ($handle) { |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
5
|
|
|
97
|
2
|
|
|
|
|
7
|
lc $handle; |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
|
|
100
|
2
|
|
|
2
|
1
|
133922
|
sub normalizeAndEnsureValidHandle($handle) { |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
5
|
|
|
101
|
2
|
|
|
|
|
6
|
my $normalized = normalizeHandle($handle); |
|
102
|
2
|
|
|
|
|
7
|
ensureValidHandle($normalized); |
|
103
|
1
|
|
|
|
|
9
|
$normalized; |
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
|
|
106
|
0
|
|
|
0
|
1
|
0
|
sub isValidHandle ($handle) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
107
|
0
|
|
|
|
|
0
|
try { |
|
108
|
0
|
|
|
|
|
0
|
ensureValidHandle($handle) |
|
109
|
|
|
|
|
|
|
} |
|
110
|
|
|
|
|
|
|
catch ($err) { # TODO: I want this to work by checking the type of thrown error but this is perl... |
|
111
|
0
|
0
|
|
|
|
0
|
if ( $err =~ /Handle/ ) { |
|
112
|
0
|
|
|
|
|
0
|
return 0; |
|
113
|
|
|
|
|
|
|
} |
|
114
|
0
|
|
|
|
|
0
|
die $err; |
|
115
|
|
|
|
|
|
|
} |
|
116
|
0
|
|
|
|
|
0
|
1; |
|
117
|
|
|
|
|
|
|
} |
|
118
|
|
|
|
|
|
|
|
|
119
|
22
|
|
|
22
|
1
|
30
|
sub isValidTld($handle) { |
|
|
22
|
|
|
|
|
27
|
|
|
|
22
|
|
|
|
|
31
|
|
|
120
|
22
|
|
|
|
|
44
|
for my $tld (@DISALLOWED_TLDS) { |
|
121
|
163
|
100
|
|
|
|
1579
|
return 0 if $handle =~ /${tld}$/; |
|
122
|
|
|
|
|
|
|
} |
|
123
|
19
|
|
|
|
|
58
|
1; |
|
124
|
|
|
|
|
|
|
} |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# All fatal errors |
|
127
|
|
|
|
|
|
|
register 'InvalidHandleError', (), 1; |
|
128
|
|
|
|
|
|
|
register 'ReservedHandleError', (), 1; |
|
129
|
|
|
|
|
|
|
register 'UnsupportedDomainError', (), 1; |
|
130
|
|
|
|
|
|
|
register 'DisallowedDomainError', (), 1; |
|
131
|
|
|
|
|
|
|
}; |
|
132
|
|
|
|
|
|
|
1; |
|
133
|
|
|
|
|
|
|
__END__ |