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