diff options
author | John Ankarström <john@ankarstrom.se> | 2021-09-18 22:51:30 +0200 |
---|---|---|
committer | John Ankarström <john@ankarstrom.se> | 2021-09-18 22:51:44 +0200 |
commit | 9ff1b81d65c370a938cd9d9c033e04e395f00704 (patch) | |
tree | 3f507a48d8d39f27a36b3fab32b0a230abe512f4 | |
parent | 2b915a42f6665b4110338cfde30eedc55abe7f3c (diff) | |
download | cforum-9ff1b81d65c370a938cd9d9c033e04e395f00704.tar.gz |
New user
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | README | 19 | ||||
-rw-r--r-- | ctl.c | 82 | ||||
-rw-r--r-- | db.c | 44 | ||||
-rw-r--r-- | db.h | 4 | ||||
-rw-r--r-- | query.c | 11 | ||||
-rw-r--r-- | site.h | 19 | ||||
-rw-r--r-- | t/front.t | 3 | ||||
-rw-r--r-- | t/head.t | 8 | ||||
-rw-r--r-- | t/newuser.t | 35 | ||||
-rw-r--r-- | t/post.t | 2 |
11 files changed, 210 insertions, 19 deletions
@@ -33,5 +33,5 @@ db: sqlite3 db "CREATE TABLE posts(parent INT, user INT NOT NULL, created INT NOT NULL, edited INT, subject NOT NULL, text NOT NULL, FOREIGN KEY (user) REFERENCES users(oid));" sqlite3 db "INSERT INTO posts values(NULL, 1, 1462137896, NULL, 'Hello World!', 'This is the first post.');" sqlite3 db "INSERT INTO posts values(1, 1, 1462138896, NULL, 'Re: Hello World!', 'This is the second post!');" - sqlite3 db "CREATE TABLE atts(post INT NOT NULL, name NOT NULL, description, mime NOT NULL, data BLOB, FOREIGN KEY (post) REFERENCES posts(oid));" + sqlite3 db "CREATE TABLE atts(post INT NOT NULL, name NOT NULL, desc, mime NOT NULL, data BLOB, FOREIGN KEY (post) REFERENCES posts(oid));" sqlite3 db "$$(printf "INSERT INTO atts values(1, 'example', 'Some example shell code.', 'text/plain', '#!/bin/sh\necho Hello World!');")"
\ No newline at end of file @@ -8,21 +8,22 @@ C89, it can be run on practically any UNIX system. It is also rather small: wc -l *.c *.h */*.t */*.lex - 100 cforum.c - 143 ctl.c - 230 db.c + 101 cforum.c + 223 ctl.c + 268 db.c 10 err.c - 106 query.c + 113 query.c 6 ctl.h 40 db.h 0 err.h 14 query.h - 2 site.h + 21 site.h 3 t/err.t 1 t/foot.t - 26 t/front.t - 6 t/head.t + 29 t/front.t + 14 t/head.t + 34 t/newuser.t 28 t/post.t 12 t/user.t - 87 mktpl/mktpl.lex - 814 total + 95 mktpl/mktpl.lex + 1012 total @@ -1,3 +1,4 @@ +#include <err.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -35,7 +36,86 @@ newpost() void newuser() -{} +{ + char *confirm, *hlite, *msg, *name, *full, *p, *pass, *v; + char title[] = "New User"; + + if(!(msg = malloc(128))) + err(1, "malloc"); + + *msg = 0; + confirm = hlite = name = full = pass = NULL; + + if(query.method == GET){ + printf("Content-Type: text/html\n\n"); + #include "t/newuser.tc" + return; + } + + while(p = nextparam(POST, MAXUSERPARAM)){ + if(!(v = split(p))) continue; + + if(!confirm && strcmp(p, "confirm") == 0) + confirm = strdup(v); + else if(!name && strcmp(p, "name") == 0) + name = strdup(v); + else if(!full && strcmp(p, "full") == 0) + full = strdup(v); + else if(!pass && strcmp(p, "pass") == 0) + pass = strdup(v); + else + continue; + + if(TRUNCATED(p)){ + hlite = strdup(p); + snprintf(msg, 128, + "Input length exceeds server limitations"); + goto err; + } + } + + /* Ensure all required fields are there. */ + if(!name || !*name || !pass || !*pass){ + hlite = (!name || !*name)? strdup("name"): strdup("pass"); + snprintf(msg, 128, "Required field missing"); + goto err; + } + + /* Decode URL-encoded fields. */ + + /* Restrain lengths of decoded fields. */ + if(name && *name && strlen(name)-1 > MAXUSERNAME){ + hlite = strdup("name"); + snprintf(msg, 128, "Username longer than %d characters", + MAXUSERNAME-1); + goto err; + } + if(full && *full && strlen(full)-1 > MAXUSERFULL){ + hlite = strdup("full"); + snprintf(msg, 128, "Full name longer than %d characters", + MAXUSERFULL-1); + goto err; + } + if(pass && *pass && strlen(pass)-1 > MAXUSERPASS){ + hlite = strdup("pass"); + snprintf(msg, 128, "Password longer than %d characters", + MAXUSERPASS-1); + goto err; + } + + if(pass && confirm && strcmp(pass, confirm) != 0){ + snprintf(msg, 128, "Passwords do not match"); + goto err; + } + + printf("Content-Type: text/html\n\n"); + printf("You are valid\n"); + return; +err: + printf("Content-Type: text/html\n\n"); + #include "t/newuser.tc" + return; +} /* * The `show' functions show an existing attachment/post/user @@ -17,7 +17,7 @@ addatt(struct att *att) sqlite3_stmt *stmt; if(sqlite3_prepare(db, "INSERT INTO atts" - " (post, name, description, mime, data)" + " (post, name, desc, mime, data)" " VALUES (?, ?, ?, ?, ?)", -1, &stmt, 0) != SQLITE_OK) goto err; @@ -30,7 +30,7 @@ addatt(struct att *att) != SQLITE_OK) goto err; - if(sqlite3_bind_text(stmt, 3, att->description, -1, SQLITE_STATIC) + if(sqlite3_bind_text(stmt, 3, att->desc, -1, SQLITE_STATIC) != SQLITE_OK) goto err; @@ -53,6 +53,44 @@ err: } int +addpost(struct post *post) +{ + sqlite3_stmt *stmt; + + if(sqlite3_prepare(db, "INSERT INTO posts" + " (parent, user, created, subject, text)" + " VALUES (?, ?, ?, ?, ?)", + -1, &stmt, 0) != SQLITE_OK) + goto err; + + if(sqlite3_bind_int(stmt, 1, post->parent) != SQLITE_OK) + goto err; + + if(sqlite3_bind_int(stmt, 2, post->user) != SQLITE_OK) + goto err; + + if(sqlite3_bind_int(stmt, 3, post->created) != SQLITE_OK) + goto err; + + if(sqlite3_bind_text(stmt, 4, post->subject, -1, SQLITE_STATIC) + != SQLITE_OK) + goto err; + + if(sqlite3_bind_text(stmt, 5, post->text, -1, SQLITE_STATIC) + != SQLITE_OK) + goto err; + + if(sqlite3_step(stmt) != SQLITE_DONE) + goto err; + + sqlite3_finalize(stmt); + return 1; +err: + sqlite3_finalize(stmt); + return 0; +} + +int adduser(struct user *user) { sqlite3_stmt *stmt; @@ -141,7 +179,7 @@ nextatt(sqlite3_stmt *stmt) att->id = sqlite3_column_int(stmt, 0); att->post = sqlite3_column_int(stmt, 1); att->name = strdupn(sqlite3_column_text(stmt, 2)); - att->description = strdupn(sqlite3_column_text(stmt, 3)); + att->desc = strdupn(sqlite3_column_text(stmt, 3)); att->mime = strdupn(sqlite3_column_text(stmt, 4)); att->bytes = sqlite3_column_bytes(stmt, 5); @@ -5,9 +5,9 @@ sqlite3 *db; struct att{ int id; int post; - int bytes; + int bytes; /* Size of data. */ char *name; - char *description; + char *desc; char *mime; char *data; }; @@ -6,8 +6,9 @@ /* * Return an allocated string containing the next query string parameter - * ("key=value"). The string is truncated to max characters. If truncation - * occurred, the -1th character of the string is set to 1. + * ("key=value"). The string is truncated to max characters (but is always + * NUL-terminated). If truncation occurred, the -1th character of the string + * is set to 1. */ char * nextparam(enum method method, int max) @@ -104,4 +105,10 @@ split(char *param) return NULL; param[n] = 0; return param+n+1; +} + +void +urldecode(char *s) +{ + }
\ No newline at end of file @@ -1,3 +1,22 @@ +/* + * TODO: It is probably better to use the CONTENT_LENGTH + * environment variable to decide the length of the entire + * posted query string and then compare it to a max value, + * such as: + */ + +#define MAXATTDATA 4096 +#define MAXUSERDATA 512 +#define MAXPOSTDATA 4096 + +/* Maximum size of newuser parameter, incl. NUL. */ +#define MAXUSERPARAM 512 + +/* Maximum size of user information, incl. NUL. */ +#define MAXUSERNAME 80 +#define MAXUSERFULL 128 +#define MAXUSERPASS 128 + struct site{ char *name; } site;
\ No newline at end of file @@ -1,5 +1,8 @@ <% #include "head.tc" %> <h1><%= site.name %></h1> +<ul> + <li><a href="?new=user">Sign up</a></li> +</ul> <h3>Latest posts</h3> <table border="1"> <% while(post = nextpost(pstmt)){ @@ -3,5 +3,13 @@ <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <title><%= title %></title> +<style type="text/css"> + form.hlite-confirm #confirm, + form.hlite-name #name, + form.hlite-full #full, + form.hlite-pass #pass { + background: #f66; + } +</style> </head> <body>
\ No newline at end of file diff --git a/t/newuser.t b/t/newuser.t new file mode 100644 index 0000000..a0a0dd9 --- /dev/null +++ b/t/newuser.t @@ -0,0 +1,35 @@ +<% #include "head.tc" %> +<h1>New User</h1> +<% if(*msg){ %> +<p style="color: red;"><%= msg %></p> +<% } %> +<form class="<% if(hlite) printf("hlite-%s", hlite); %>" action="?new=user" method="POST"> + <table border="0"> + <tr id="name"> + <td><label for="name">Username</label></td> + <td><input type="text" name="name" value="<% if(name) printf("%s", name); %>"></td> + </tr> + <tr id="full"> + <td><label for="full">Full Name</label></td> + <td><input type="text" name="full" value="<% if(full) printf("%s", full); %>"></td> + <td><small>(optional)</small></td> + </tr> + <tr id="pass"> + <td><label for="pass">Password</label></td> + <td><input type="password" name="pass" value=""></td> + </tr> + <tr id="confirm"> + <td><label for="confirm">Confirm</label></td> + <td><input type="password" name="confirm" value=""></td> + </tr> + </table> + <p>By clicking <i>Create</i>, you confirm</p> + <ol> + <li>that this user is a real human,</li> + <li>that you will not abuse the service,</li> + <li>that the information you provide will be saved on the server, and</li> + <li>that your user may be terminated by an administrator at any point and for any reason.</li> + </ol> + <p><input type="submit" value="Create →"></p> +</form> +<% #include "foot.tc" %>
\ No newline at end of file @@ -20,7 +20,7 @@ <tr> <td><a href="?att=<% printf("%d", att->id); %>"><%= att->name %></a></td> <td><%= att->mime %></td> - <td><%= att->description %></td> + <td><%= att->desc %></td> </tr> <% free(att); }while(att = nextatt(stmt)); %> |