Index: src/db.c ================================================================== --- src/db.c +++ src/db.c @@ -1584,10 +1584,11 @@ { "auto-captcha", "autocaptcha", 0, "on" }, { "auto-shun", 0, 0, "on" }, { "autosync", 0, 0, "on" }, { "binary-glob", 0, 32, "" }, { "clearsign", 0, 0, "off" }, + { "default-perms", 0, 16, "u" }, { "diff-command", 0, 16, "" }, { "dont-push", 0, 0, "off" }, { "editor", 0, 16, "" }, { "gdiff-command", 0, 16, "gdiff" }, { "ignore-glob", 0, 40, "" }, @@ -1596,10 +1597,11 @@ { "manifest", 0, 0, "off" }, { "mtime-changes", 0, 0, "on" }, { "pgp-command", 0, 32, "gpg --clearsign -o " }, { "proxy", 0, 32, "off" }, { "repo-cksum", 0, 0, "on" }, + { "self-register", 0, 0, "off" }, { "ssh-command", 0, 32, "" }, { "web-browser", 0, 32, "" }, { 0,0,0,0 } }; @@ -1634,10 +1636,14 @@ ** purposes. Example: *.xml ** ** clearsign When enabled, fossil will attempt to sign all commits ** with gpg. When disabled (the default), commits will ** be unsigned. Default: off +** +** default-perms Permissions given automatically to new users. For more +** information on permissions see Users page in Server +** Administration of the HTTP UI. Default: u. ** ** diff-command External command to run when performing a diff. ** If undefined, the internal text diff will be used. ** ** dont-push Prevent this repository from pushing from client to @@ -1677,10 +1683,15 @@ ** ** repo-cksum Compute checksums over all files in each checkout ** as a double-check of correctness. Defaults to "on". ** Disable on large repositories for a performance ** improvement. +** +** self-register Allow users to register themselves through the HTTP UI. +** This is useful if you want to see other names than +** "Anonymous" in e.g. ticketing system. On the other hand +** users can not be deleted. Default: off. ** ** ssh-command Command used to talk to a remote machine with ** the "ssh://" protocol. ** ** web-browser A shell command used to launch your preferred Index: src/login.c ================================================================== --- src/login.c +++ src/login.c @@ -266,10 +266,14 @@ } @ your user-id and password at the left and press the @ "Login" button. Your user name will be stored in a browser cookie. @ You must configure your web browser to accept cookies in order for @ the login to take.

+ if( db_get_boolean("self-register", 0) ){ + @

If you do not have an account, you can + @ create one. + } if( zAnonPw ){ unsigned int uSeed = captcha_seed(); char const *zDecoded = captcha_decode(uSeed); int bAutoCaptcha = db_get_boolean("auto-captcha", 1); char *zCaptcha = captcha_render(zDecoded); @@ -624,5 +628,138 @@ g.okCsrf = 1; return; } fossil_fatal("Cross-site request forgery attempt"); } + +/* +** WEBPAGE: register +** +** Generate the register page. +** +*/ +void register_page(void){ + const char *zUsername, *zPasswd, *zConfirm, *zContact, *zCS, *zPw, *zCap; + if( !db_get_boolean("self-register", 0) ){ + style_header("Registration not possible"); + @

This project does not allow user self-registration. Please contact the + @ project administrator to obtain an account.

+ style_footer(); + return; + } + + style_header("Register"); + zUsername = P("u"); + zPasswd = P("p"); + zConfirm = P("cp"); + zContact = P("c"); + zCap = P("cap"); + zCS = P("cs"); /* Captcha Secret */ + + /* Try to make any sense from user input. */ + if( P("new") ){ + if( zCS==0 ) fossil_redirect_home(); /* Forged request */ + zPw = captcha_decode((unsigned int)atoi(zCS)); + if( !(zUsername && zPasswd && zConfirm && zContact) ){ + @

+ @ All fields are obligatory. + @

+ }else if( strlen(zPasswd) < 6){ + @

+ @ Password too weak. + @

+ }else if( strcmp(zPasswd,zConfirm)!=0 ){ + @

+ @ The two copies of your new passwords do not match. + @

+ }else if( strcasecmp(zPw, zCap)!=0 ){ + @

+ @ Captcha text invalid. + @

+ }else{ + /* This almost is stupid copy-paste of code from user.c:user_cmd(). */ + Blob passwd, login, caps, contact; + + blob_init(&login, zUsername, -1); + blob_init(&contact, zContact, -1); + blob_init(&caps, db_get("default-perms", "u"), -1); + blob_init(&passwd, zPasswd, -1); + + if( db_exists("SELECT 1 FROM user WHERE login=%B", &login) ){ + /* Here lies the reason I don't use zErrMsg - it would not substitute + * this %s(zUsername), or at least I don't know how to force it to.*/ + @

+ @ %s(zUsername) already exists. + @

+ }else{ + char *zPw = sha1_shared_secret(blob_str(&passwd), blob_str(&login)); + db_multi_exec( + "INSERT INTO user(login,pw,cap,info)" + "VALUES(%B,%Q,%B,%B)", + &login, zPw, &caps, &contact + ); + free(zPw); + + /* The user is registered, now just log him in. */ + int uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUsername); + char *zCookie; + const char *zCookieName = login_cookie_name(); + const char *zExpire = db_get("cookie-expire","8766"); + int expires = atoi(zExpire)*3600; + const char *zIpAddr = PD("REMOTE_ADDR","nil"); + + zCookie = db_text(0, "SELECT '%d/' || hex(randomblob(25))", uid); + cgi_set_cookie(zCookieName, zCookie, 0, expires); + db_multi_exec( + "UPDATE user SET cookie=%Q, ipaddr=%Q, " + " cexpire=julianday('now')+%d/86400.0 WHERE uid=%d", + zCookie, zIpAddr, expires, uid + ); + redirect_to_g(); + + } + } + } + + /* Prepare the captcha. */ + unsigned int uSeed = captcha_seed(); + char const *zDecoded = captcha_decode(uSeed); + char *zCaptcha = captcha_render(zDecoded); + + /* Print out the registration form. */ + @
+ if( P("g") ){ + @ + } + @

+ @ + @ + @ + @ + @ + @ + @ + @ + @ + @ + @ + @ + @ + @ + @ + @ + @ + @ + @ + @ + @ + @ + @ + @ + @

+  @ %s(zCaptcha)
+  @ 
+ @ + style_footer(); + + free(zCaptcha); +} Index: src/setup.c ================================================================== --- src/setup.c +++ src/setup.c @@ -790,10 +790,26 @@ @

Fossil tries to limit out-bound sync, clone, and pull packets @ to this many bytes, uncompressed. If the client requires more data @ than this, then the client will issue multiple HTTP requests. @ Values below 1 million are not recommended. 5 million is a @ reasonable number.

+ + @
+ onoff_attribute("Allow users to register themselves", + "self-register", "selfregister", 0); + @

Allow users to register themselves through the HTTP UI. + @ The registration form always requires filling in a CAPTCHA + @ (auto-captcha setting is ignored). Still, bear in mind that anyone + @ can register under any user name. This option is useful for public projects + @ where you do not want everyone in any ticket discussion to be named + @ "Anonymous".

+ + @
+ entry_attribute("Default privileges", 10, "default-perms", "defaultperms", "u"); + @

Permissions given to users that register themselves using the HTTP UI + @ or are registered by the administrator using the command line interface. + @

@
onoff_attribute("Show javascript button to fill in CAPTCHA", "auto-captcha", "autocaptcha", 0); @

When enabled, a button appears on the login screen for user Index: src/user.c ================================================================== --- src/user.c +++ src/user.c @@ -180,12 +180,13 @@ if( g.argc<3 ){ usage("capabilities|default|list|new|password ..."); } n = strlen(g.argv[2]); if( n>=2 && strncmp(g.argv[2],"new",n)==0 ){ - Blob passwd, login, contact; + Blob passwd, login, caps, contact; char *zPw; + blob_init(&caps, db_get("default-perms", "u"), -1); if( g.argc>=4 ){ blob_init(&login, g.argv[3], -1); }else{ prompt_user("login: ", &login); @@ -204,12 +205,12 @@ prompt_for_password("password: ", &passwd, 1); } zPw = sha1_shared_secret(blob_str(&passwd), blob_str(&login)); db_multi_exec( "INSERT INTO user(login,pw,cap,info)" - "VALUES(%B,%Q,'v',%B)", - &login, zPw, &contact + "VALUES(%B,%Q,%B,%B)", + &login, zPw, &caps, &contact ); free(zPw); }else if( n>=2 && strncmp(g.argv[2],"default",n)==0 ){ user_select(); if( g.argc==3 ){