+1
upload/src/main.rs
+1
upload/src/main.rs
+64
upload/src/utils.rs
+64
upload/src/utils.rs
···
1
+
use regex::Regex;
2
+
3
+
pub 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
+
return Some(res);
36
+
}
37
+
38
+
pub 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
+
return Some(res);
64
+
}