Mercurial > paster
changeset 38:48834441dc86
pasterd: generate smaller identifiers, closes #2480 @1h
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 12 Feb 2020 20:55:00 +0100 |
parents | e05b26209ad3 |
children | 5e39e116c38d |
files | database.c http.c paste.c paste.h tests/test-database.c themes/minimal/index-paste.html themes/minimal/paste.html themes/siimple/index-paste.html themes/siimple/paste.html |
diffstat | 9 files changed, 90 insertions(+), 56 deletions(-) [+] |
line wrap: on
line diff
--- a/database.c Wed Feb 12 20:45:00 2020 +0100 +++ b/database.c Wed Feb 12 20:55:00 2020 +0100 @@ -116,31 +116,10 @@ return estrdup(s ? (const char *)(s) : ""); } -static const char * -create_id(void) -{ - static char uuid[256]; - - /* - * Not a very strong generation but does not require to link against - * util-linux. - * - * See https://stackoverflow.com/questions/2174768/generating-random-uuids-in-linux - */ - sprintf(uuid, "%x%x-%x-%x-%x-%x%x%x", - rand(), rand(), - rand(), - ((rand() & 0x0fff) | 0x4000), - rand() % 0x3fff + 0x8000, - rand(), rand(), rand()); - - return uuid; -} - static void convert(sqlite3_stmt *stmt, struct paste *paste) { - paste->uuid = dup(sqlite3_column_text(stmt, 0)); + paste->id = dup(sqlite3_column_text(stmt, 0)); paste->title = dup(sqlite3_column_text(stmt, 1)); paste->author = dup(sqlite3_column_text(stmt, 2)); paste->language = dup(sqlite3_column_text(stmt, 3)); @@ -150,6 +129,57 @@ paste->duration = sqlite3_column_int64(stmt, 7); } +static bool +exists(const char *id) +{ + assert(id); + + sqlite3_stmt *stmt = NULL; + bool ret = false; + + if (sqlite3_prepare(db, sql_get, -1, &stmt, NULL) != SQLITE_OK) { + log_warn("database: error (exists): %s", sqlite3_errmsg(db)); + return false; + } + + ret = sqlite3_step(stmt) == SQLITE_ROW; + sqlite3_finalize(stmt); + + return ret; +} + +static const char * +create_id(void) +{ + static const char table[] = "abcdefghijklmnopqrstuvwxyz1234567890"; + static char id[12]; + + for (int i = 0; i < sizeof (id); ++i) + id[i] = table[rand() % (sizeof (table))]; + + return id; +} + +static bool +set_id(struct paste *paste) +{ + assert(paste); + + paste->id = NULL; + + /* + * Avoid infinite loop, we only try to create a new id in 30 steps. + */ + int tries = 0; + + do { + free(paste->id); + paste->id = estrdup(create_id()); + } while (++tries < 30 && exists(paste->id)); + + return tries < 30; +} + bool database_open(const char *path) { @@ -252,7 +282,8 @@ { assert(paste); - sqlite3_stmt* stmt = NULL; + sqlite3_stmt *stmt = NULL; + log_debug("database: creating new paste"); if (sqlite3_exec(db, "BEGIN EXCLUSIVE TRANSACTION", NULL, NULL, NULL) != SQLITE_OK) { @@ -260,13 +291,16 @@ return false; } + if (!set_id(paste)) { + log_warn("database: unable to randomize unique identifier"); + sqlite3_exec(db, "END TRANSACTION", NULL, NULL, NULL); + return false; + } + if (sqlite3_prepare(db, sql_insert, -1, &stmt, NULL) != SQLITE_OK) goto sqlite_err; - /* Create a new uuid first. */ - paste->uuid = estrdup(create_id()); - - sqlite3_bind_text(stmt, 1, paste->uuid, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 1, paste->id, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, paste->title, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 3, paste->author, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 4, paste->language, -1, SQLITE_STATIC); @@ -281,7 +315,7 @@ sqlite3_finalize(stmt); log_info("database: new paste (%s) from %s expires in one %lld seconds", - paste->uuid, paste->author, paste->duration); + paste->id, paste->author, paste->duration); return true; @@ -292,8 +326,8 @@ if (stmt) sqlite3_finalize(stmt); - free(paste->uuid); - paste->uuid = NULL; + free(paste->id); + paste->id = NULL; return false; }
--- a/http.c Wed Feb 12 20:45:00 2020 +0100 +++ b/http.c Wed Feb 12 20:55:00 2020 +0100 @@ -94,7 +94,7 @@ }; static const char *tmpl_index_pastes_keywords[] = { - "uuid", + "id", "name", "author", "language", @@ -103,7 +103,7 @@ }; static const char *tmpl_paste_keywords[] = { - "uuid", + "id", "title", "author", "language", @@ -415,7 +415,7 @@ switch (index) { case 0: - khtml_puts(&htmlreq, paste->uuid); + khtml_puts(&htmlreq, paste->id); break; case 1: khtml_puts(&htmlreq, paste->title); @@ -458,7 +458,7 @@ switch (index) { case 0: - khtml_puts(&htmlreq, paste->uuid); + khtml_puts(&htmlreq, paste->id); break; case 1: khtml_puts(&htmlreq, paste->title); @@ -663,7 +663,7 @@ else { /* Redirect to paste details. */ khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_302]); - khttp_head(req, kresps[KRESP_LOCATION], "/paste/%s", paste.uuid); + khttp_head(req, kresps[KRESP_LOCATION], "/paste/%s", paste.id); khttp_body(req); khttp_free(req); } @@ -771,7 +771,7 @@ #endif khttp_head(req, kresps[KRESP_CONNECTION], "keep-alive"); khttp_head(req, kresps[KRESP_CONTENT_DISPOSITION], - "attachment; filename=\"%s.%s\"", paste.uuid, paste.language); + "attachment; filename=\"%s.%s\"", paste.id, paste.language); khttp_body(req); khttp_puts(req, paste.code); khttp_free(req);
--- a/paste.c Wed Feb 12 20:45:00 2020 +0100 +++ b/paste.c Wed Feb 12 20:55:00 2020 +0100 @@ -27,10 +27,10 @@ { assert(paste); + free(paste->id); free(paste->title); free(paste->author); free(paste->language); free(paste->code); - free(paste->uuid); memset(paste, 0, sizeof (struct paste)); }
--- a/paste.h Wed Feb 12 20:45:00 2020 +0100 +++ b/paste.h Wed Feb 12 20:55:00 2020 +0100 @@ -33,7 +33,7 @@ * Every string in the paste is assumed to be allocated on the heap. */ struct paste { - char *uuid; + char *id; char *title; char *author; char *language;
--- a/tests/test-database.c Wed Feb 12 20:45:00 2020 +0100 +++ b/tests/test-database.c Wed Feb 12 20:55:00 2020 +0100 @@ -80,7 +80,7 @@ GREATEST_FAIL(); GREATEST_ASSERT_EQ(max, 1); - GREATEST_ASSERT(pastes[0].uuid); + GREATEST_ASSERT(pastes[0].id); GREATEST_ASSERT_STR_EQ(pastes[0].title, "test 1"); GREATEST_ASSERT_STR_EQ(pastes[0].author, "unit test"); GREATEST_ASSERT_STR_EQ(pastes[0].language, "cpp"); @@ -145,7 +145,7 @@ for (int i = 0; i < 3; ++i) { /* Selected in most recents first. */ - GREATEST_ASSERT(pastes[i].uuid); + GREATEST_ASSERT(pastes[i].id); GREATEST_ASSERT_STR_EQ(pastes[i].title, bprintf("test %d", expected[i])); GREATEST_ASSERT_STR_EQ(pastes[i].author, @@ -191,7 +191,7 @@ for (int i = 0; i < 3; ++i) { /* Selected in most recents first. */ - GREATEST_ASSERT(pastes[i].uuid); + GREATEST_ASSERT(pastes[i].id); GREATEST_ASSERT_STR_EQ(pastes[i].title, bprintf("test %d", expected[i])); GREATEST_ASSERT_STR_EQ(pastes[i].author, @@ -232,10 +232,10 @@ if (!database_insert(&original)) GREATEST_FAIL(); - if (!database_get(&new, original.uuid)) + if (!database_get(&new, original.id)) GREATEST_FAIL(); - GREATEST_ASSERT_STR_EQ(new.uuid, original.uuid); + GREATEST_ASSERT_STR_EQ(new.id, original.id); GREATEST_ASSERT_STR_EQ(new.title, original.title); GREATEST_ASSERT_STR_EQ(new.author, original.author); GREATEST_ASSERT_STR_EQ(new.language, original.language); @@ -252,7 +252,7 @@ if (!database_get(&new, "unknown")) GREATEST_FAIL(); - GREATEST_ASSERT(!new.uuid); + GREATEST_ASSERT(!new.id); GREATEST_ASSERT(!new.title); GREATEST_ASSERT(!new.author); GREATEST_ASSERT(!new.language); @@ -315,7 +315,7 @@ GREATEST_FAIL(); GREATEST_ASSERT_EQ(max, 1); - GREATEST_ASSERT(searched[0].uuid); + GREATEST_ASSERT(searched[0].id); GREATEST_ASSERT_STR_EQ(searched[0].title, "This is in C"); GREATEST_ASSERT_STR_EQ(searched[0].author, "markand"); GREATEST_ASSERT_STR_EQ(searched[0].language, "cpp"); @@ -353,7 +353,7 @@ GREATEST_FAIL(); GREATEST_ASSERT_EQ(max, 0); - GREATEST_ASSERT(!searched.uuid); + GREATEST_ASSERT(!searched.id); GREATEST_ASSERT(!searched.title); GREATEST_ASSERT(!searched.author); GREATEST_ASSERT(!searched.language); @@ -389,7 +389,7 @@ GREATEST_FAIL(); GREATEST_ASSERT_EQ(max, 0); - GREATEST_ASSERT(!searched.uuid); + GREATEST_ASSERT(!searched.id); GREATEST_ASSERT(!searched.title); GREATEST_ASSERT(!searched.author); GREATEST_ASSERT(!searched.language); @@ -460,7 +460,7 @@ GREATEST_FAIL(); GREATEST_ASSERT_EQ(max, 1); - GREATEST_ASSERT(searched.uuid); + GREATEST_ASSERT(searched.id); GREATEST_ASSERT_STR_EQ(searched.title, "This is in python"); GREATEST_ASSERT_STR_EQ(searched.author, "NiReaS"); GREATEST_ASSERT_STR_EQ(searched.language, "python");
--- a/themes/minimal/index-paste.html Wed Feb 12 20:45:00 2020 +0100 +++ b/themes/minimal/index-paste.html Wed Feb 12 20:55:00 2020 +0100 @@ -1,5 +1,5 @@ <tr> - <td><a href="/paste/@@uuid@@">@@name@@</a></td> + <td><a href="/paste/@@id@@">@@name@@</a></td> <td>@@author@@</td> <td>@@language@@</td> <td>@@date@@</td>
--- a/themes/minimal/paste.html Wed Feb 12 20:45:00 2020 +0100 +++ b/themes/minimal/paste.html Wed Feb 12 20:55:00 2020 +0100 @@ -1,14 +1,14 @@ <h2>Actions</h2> <ul> - <li><a href="/fork/@@uuid@@">Fork</a></li> - <li><a href="/download/@@uuid@@">Download</a></li> + <li><a href="/fork/@@id@@">Fork</a></li> + <li><a href="/download/@@id@@">Download</a></li> </ul> <table> <tbody> <tr> <td>Identifier</td> - <td>@@uuid@@</td> + <td>@@id@@</td> </tr> <tr> <td>Title</td>
--- a/themes/siimple/index-paste.html Wed Feb 12 20:45:00 2020 +0100 +++ b/themes/siimple/index-paste.html Wed Feb 12 20:55:00 2020 +0100 @@ -1,5 +1,5 @@ <div class="siimple-table-row"> - <div class="siimple-table-cell"><a class="siimple-link" href="/paste/@@uuid@@">@@name@@</a></div> + <div class="siimple-table-cell"><a class="siimple-link" href="/paste/@@id@@">@@name@@</a></div> <div class="siimple-table-cell">@@author@@</div> <div class="siimple-table-cell">@@language@@</div> <div class="siimple-table-cell">@@date@@</div>
--- a/themes/siimple/paste.html Wed Feb 12 20:45:00 2020 +0100 +++ b/themes/siimple/paste.html Wed Feb 12 20:55:00 2020 +0100 @@ -1,12 +1,12 @@ <h1>@@title@@</h1> - <a class="siimple-btn siimple-btn--navy" href="/fork/@@uuid@@">Fork</a> - <a class="siimple-btn siimple-btn--navy" href="/download/@@uuid@@">Download</a> + <a class="siimple-btn siimple-btn--navy" href="/fork/@@id@@">Fork</a> + <a class="siimple-btn siimple-btn--navy" href="/download/@@id@@">Download</a> <div class="siimple-grid"> <div class="siimple-grid-row"> <div class="siimple-grid-col siimple-grid-col--2"><strong>Identifier</strong></div> - <div class="siimple-grid-col siimple-grid-col--10">@@uuid@@</div> + <div class="siimple-grid-col siimple-grid-col--10">@@id@@</div> </div> <div class="siimple-grid-row"> <div class="siimple-grid-col siimple-grid-col--2"><strong>Author</strong></div>