[WIP] A (somewhat barebones) atproto app for creating custom sites without hosting!
1use regex::Regex;
2
3pub fn rkey_to_url(rkey: String) -> Option<String> {
4 let regex = Regex::new(
5 // symbols A-Za-z0-9 -._~: are all valid rkey characters
6 // however we use a subset of record keys where : is an escape character
7 // allow any rkey character except colons
8 // or any of the valid escape sequences
9 // from start of string to end between 0 and unlimited times
10 r"^(?:[A-Za-z0-9.\-_~]|(?:::)|(?::~)|(?::21)|(?::24)|(?::26)|(?::27)|(?::28)|(?::29)|(?::2A)|(?::2B)|(?::2C)|(?::3A)|(?::3B)|(?::3D)|(?::40))*$",
11 )
12 .expect("Regex failed to generate");
13
14 if !regex.is_match(&rkey) {
15 return None;
16 };
17
18 let res = rkey
19 .replace("::", "/")
20 .replace(":~", "%")
21 .replace(":21", "!")
22 .replace(":24", "$")
23 .replace(":26", "&")
24 .replace(":27", "'")
25 .replace(":28", "(")
26 .replace(":29", ")")
27 .replace(":2A", "*")
28 .replace(":2B", "+")
29 .replace(":2C", ",")
30 .replace(":3A", ":")
31 .replace(":3B", ";")
32 .replace(":3D", "=")
33 .replace(":40", "@");
34
35 Some(res)
36}
37
38pub fn url_to_rkey(url: String) -> Option<String> {
39 let regex = Regex::new(r"^(?:[a-zA-Z0-9/\-._~!$&'()*+,;=:@]|(?:%[0-9a-fA-F]{2}))*$")
40 .expect("Regex failed to generate");
41 if !regex.is_match(&url) {
42 return None;
43 }
44
45 let res = url
46 // : replace is hoisted so it doesnt replace colons from elsewhere
47 .replace(":", ":3A")
48 .replace("/", "::")
49 .replace("%", ":~")
50 .replace("!", ":21")
51 .replace("$", ":24")
52 .replace("&", ":26")
53 .replace("'", ":27")
54 .replace("(", ":28")
55 .replace(")", ":29")
56 .replace("*", ":2A")
57 .replace("+", ":2B")
58 .replace(",", ":2C")
59 .replace(";", ":3B")
60 .replace("=", ":3D")
61 .replace("@", ":40");
62
63 Some(res)
64}