feat: added secure random URL option
ci/woodpecker/push/woodpecker Pipeline was successful Details

trie-skips
Jef Roosens 2022-11-21 21:02:33 +01:00
parent b66c0f0e00
commit 22a7b5b3fc
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
4 changed files with 101 additions and 52 deletions

View File

@ -3,16 +3,35 @@
API_KEY=test API_KEY=test
URL=http://localhost:18080 URL=http://localhost:18080
if [ "$1" = add ]; then if [ "$1" = g ]; then
curl -is "$URL/$2" |
sed -En 's/^[lL]ocation: (.*)/\1/p'
elif [ "$1" = s ]; then
curl \ curl \
-XPOST \ -XPOST \
-d "$2" \ -d "$2" \
-H "X-Api-Key: $API_KEY" \ -H "X-Api-Key: $API_KEY" \
"$URL/s/$3" "$URL/s/$3"
elif [ "$1" = get ]; then elif [ "$1" = sl ]; then
curl -is "$URL/$2" | sed -En 's/^[lL]ocation: (.*)/\1/p' curl \
-XPOST \
-d "$2" \
-H "X-Api-Key: $API_KEY" \
"$URL/sl/$3"
elif [ "$1" = paste ]; then elif [ "$1" = p ]; then
curl --data-binary @"$2" -XPOST -H "X-Api-Key: $API_KEY" "$URL/p/$3" curl \
-XPOST \
-H "X-Api-Key: $API_KEY" \
--data-binary @"$2" \
"$URL/p/$3"
elif [ "$1" = pl ]; then
curl \
-XPOST \
-H "X-Api-Key: $API_KEY" \
--data-binary @"$2" \
"$URL/pl/$3"
fi fi

View File

@ -21,6 +21,55 @@ extern "C" {
return crow::response(crow::status::UNAUTHORIZED); \ return crow::response(crow::status::UNAUTHORIZED); \
} }
crow::response add_redirect(std::string base_url, TernaryTrie *trie,
const char *url, bool secure) {
Entry *new_entry = entry_new(Redirect, url);
char *key = ternarytrie_add_random(trie, new_entry, secure);
if (key == NULL) {
return crow::response(crow::status::INTERNAL_SERVER_ERROR);
}
std::string res = base_url + key;
free(key);
return crow::response(res);
}
bool store_paste(const char *key, const char *body) {
// Write paste contents to file
std::fstream file;
file.open(std::string("pastes/") + key, std::ios_base::out);
if (!file.is_open()) {
return false;
}
file << body;
file.close();
return true;
}
crow::response add_paste(std::string base_url, TernaryTrie *trie,
const char *body, bool secure) {
Entry *new_entry = entry_new(Paste, "");
char *key = ternarytrie_add_random(trie, new_entry, secure);
if (key == NULL) {
return crow::response(crow::status::INTERNAL_SERVER_ERROR);
}
if (!store_paste(key, body)) {
return crow::response(crow::status::INTERNAL_SERVER_ERROR);
}
std::string res = base_url + key;
free(key);
return crow::response(res);
}
int main() { int main() {
// Initialize random seed for generating URLs // Initialize random seed for generating URLs
srand(time(NULL)); srand(time(NULL));
@ -72,23 +121,22 @@ int main() {
res.end(); res.end();
}); });
// Add a new Redirect with a randomly generated key // Add a new Redirect with a short randomly generated key
CROW_ROUTE(app, "/s/") CROW_ROUTE(app, "/s/")
.methods(crow::HTTPMethod::Post)( .methods(crow::HTTPMethod::Post)(
[api_key, base_url, trie](const crow::request req) { [api_key, base_url, trie](const crow::request req) {
AUTH(); AUTH();
Entry *new_entry = entry_new(Redirect, req.body.c_str()); return add_redirect(base_url, trie, req.body.c_str(), false);
char *key = ternarytrie_add_random(trie, new_entry); });
if (key == NULL) { // Add a new Redirect with a long randomly generated key
return crow::response(crow::status::INTERNAL_SERVER_ERROR); CROW_ROUTE(app, "/sl/")
} .methods(crow::HTTPMethod::Post)(
[api_key, base_url, trie](const crow::request req) {
AUTH();
std::string res = base_url + key; return add_redirect(base_url, trie, req.body.c_str(), true);
free(key);
return crow::response(res);
}); });
// Add a new Redirect with a given key // Add a new Redirect with a given key
@ -108,35 +156,22 @@ int main() {
return crow::response(base_url + key); return crow::response(base_url + key);
}); });
// Add a new Paste with a randomly generated key // Add a new Paste with a short randomly generated key
CROW_ROUTE(app, "/p/") CROW_ROUTE(app, "/p/")
.methods(crow::HTTPMethod::Post)( .methods(crow::HTTPMethod::Post)(
[api_key, base_url, trie](const crow::request &req) { [api_key, base_url, trie](const crow::request &req) {
AUTH(); AUTH();
Entry *new_entry = entry_new(Paste, ""); return add_paste(base_url, trie, req.body.c_str(), false);
char *key = ternarytrie_add_random(trie, new_entry); });
if (key == NULL) { // Add a new Paste with a long randomly generated key
return crow::response(crow::status::INTERNAL_SERVER_ERROR); CROW_ROUTE(app, "/pl/")
} .methods(crow::HTTPMethod::Post)(
[api_key, base_url, trie](const crow::request &req) {
AUTH();
// Write paste contents to file return add_paste(base_url, trie, req.body.c_str(), true);
std::fstream file;
file.open(std::string("pastes/") + key, std::ios_base::out);
if (!file.is_open()) {
free(key);
return crow::response(crow::status::INTERNAL_SERVER_ERROR);
}
file << req.body;
file.close();
std::string res = base_url + key;
free(key);
return crow::response(res);
}); });
// Add a paste with a given key // Add a paste with a given key
@ -146,24 +181,16 @@ int main() {
AUTH(); AUTH();
Entry *new_entry = entry_new(Paste, ""); Entry *new_entry = entry_new(Paste, "");
bool added = ternarytrie_add(trie, key.c_str(), new_entry); bool added = ternarytrie_add(trie, key.c_str(), new_entry);
if (!added) { if (!added) {
return crow::response(crow::status::CONFLICT); return crow::response(crow::status::CONFLICT);
} }
// Write paste contents to file if (!store_paste(key.c_str(), req.body.c_str())) {
std::fstream file;
file.open(std::string("pastes/") + key, std::ios_base::out);
if (!file.is_open()) {
return crow::response(crow::status::INTERNAL_SERVER_ERROR); return crow::response(crow::status::INTERNAL_SERVER_ERROR);
} }
file << req.body;
file.close();
return crow::response(base_url + key); return crow::response(base_url + key);
}); });
app.port(18080).multithreaded().run(); app.port(18080).multithreaded().run();

View File

@ -14,7 +14,8 @@ static const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVW
static const size_t charset_len = sizeof(charset) - 1; static const size_t charset_len = sizeof(charset) - 1;
// Length of randomly generated keys // Length of randomly generated keys
#define RANDOM_KEY_LENGTH 4 #define RANDOM_KEY_LENGTH_SHORT 4
#define RANDOM_KEY_LENGTH_LONG 16
/** /**
* Type definition for the struct representing the current Trie. * Type definition for the struct representing the current Trie.
@ -83,9 +84,10 @@ bool ternarytrie_add(TernaryTrie* trie, const char* key, Entry *entry);
* *
* @param trie * @param trie
* @param entry entry to add * @param entry entry to add
* @param secure whether to generate a longer, more secure random key
* @return the generated key * @return the generated key
*/ */
char *ternarytrie_add_random(TernaryTrie *trie, Entry *entry); char *ternarytrie_add_random(TernaryTrie *trie, Entry *entry, bool secure);
/** /**
* Remove an entry from this trie given its key. * Remove an entry from this trie given its key.

View File

@ -333,19 +333,20 @@ bool ternarytrie_add(TernaryTrie *trie, const char *key, Entry *entry) {
return return_value; return return_value;
} }
char* ternarytrie_add_random(TernaryTrie *trie, Entry *entry) { char* ternarytrie_add_random(TernaryTrie *trie, Entry *entry, bool secure) {
pthread_rwlock_wrlock(&trie->lock); pthread_rwlock_wrlock(&trie->lock);
// Generate random key // Generate random key
bool ok = false; bool ok = false;
char *key = malloc(RANDOM_KEY_LENGTH + 1); int key_length = secure ? RANDOM_KEY_LENGTH_LONG : RANDOM_KEY_LENGTH_SHORT;
key[RANDOM_KEY_LENGTH] = '\0'; char *key = malloc(key_length + 1);
key[key_length] = '\0';
// We naively generate new keys until we find a key that isn't in the trie // We naively generate new keys until we find a key that isn't in the trie
// yet. With charset_len ** RANDOM_KEY_LENGTH sufficiently large, this isn't a // yet. With charset_len ** RANDOM_KEY_LENGTH sufficiently large, this isn't a
// problem, because the chances of collisions are extremely small. // problem, because the chances of collisions are extremely small.
while (!ok) { while (!ok) {
for (int i = 0; i < RANDOM_KEY_LENGTH; i++) { for (int i = 0; i < key_length; i++) {
key[i] = charset[rand() % charset_len]; key[i] = charset[rand() % charset_len];
} }