Fossil

Check-in [13deb432]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Implemented all suggested changes to the self-register related code.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | self-register
Files: files | file ages | folders
SHA1:13deb4321bda1f1060be8b014f5e9f0ba5a64ba6
User & Date: lrem 2011-01-04 17:13:54
Context
2011-01-04
18:05
Merge the self-registration changes into the trunk. check-in: 9039a6ab user: drh tags: trunk
17:13
Implemented all suggested changes to the self-register related code. Closed-Leaf check-in: 13deb432 user: lrem tags: self-register
2010-12-22
23:57
First cut at code to allow anonymous users to self-register. check-in: fedf27e4 user: drh tags: self-register
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/db.c.

1582
1583
1584
1585
1586
1587
1588

1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600

1601
1602
1603
1604
1605
1606
1607
....
1632
1633
1634
1635
1636
1637
1638




1639
1640
1641
1642
1643
1644
1645
....
1675
1676
1677
1678
1679
1680
1681





1682
1683
1684
1685
1686
1687
1688
#endif /* INTERFACE */
struct stControlSettings const ctrlSettings[] = {
  { "auto-captcha",  "autocaptcha",    0, "on"                  },
  { "auto-shun",     0,                0, "on"                  },
  { "autosync",      0,                0, "on"                  },
  { "binary-glob",   0,               32, ""                    },
  { "clearsign",     0,                0, "off"                 },

  { "diff-command",  0,               16, ""                    },
  { "dont-push",     0,                0, "off"                 },
  { "editor",        0,               16, ""                    },
  { "gdiff-command", 0,               16, "gdiff"               },
  { "ignore-glob",   0,               40, ""                    },
  { "http-port",     0,               16, "8080"                },
  { "localauth",     0,                0, "off"                 },
  { "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"                  },

  { "ssh-command",   0,               32, ""                    },
  { "web-browser",   0,               32, ""                    },
  { 0,0,0,0 }
};

/*
** COMMAND: settings
................................................................................
**    binary-glob      The VALUE is a comma-separated list of GLOB patterns
**                     that should be treated as binary files for merging
**                     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




**
**    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
**                     server.  Useful when setting up a private branch.
**
................................................................................
**                     If the http_proxy environment variable is undefined
**                     then a direct HTTP connection is used.
**
**    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.





**
**    ssh-command      Command used to talk to a remote machine with
**                     the "ssh://" protocol.
**
**    web-browser      A shell command used to launch your preferred
**                     web browser when given a URL as an argument.
**                     Defaults to "start" on windows, "open" on Mac,







>












>







 







>
>
>
>







 







>
>
>
>
>







1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
....
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
....
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
#endif /* INTERFACE */
struct stControlSettings const ctrlSettings[] = {
  { "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, ""                    },
  { "http-port",     0,               16, "8080"                },
  { "localauth",     0,                0, "off"                 },
  { "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 }
};

/*
** COMMAND: settings
................................................................................
**    binary-glob      The VALUE is a comma-separated list of GLOB patterns
**                     that should be treated as binary files for merging
**                     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
**                     server.  Useful when setting up a private branch.
**
................................................................................
**                     If the http_proxy environment variable is undefined
**                     then a direct HTTP connection is used.
**
**    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
**                     web browser when given a URL as an argument.
**                     Defaults to "start" on windows, "open" on Mac,

Changes to src/login.c.

264
265
266
267
268
269
270
271

272
273

274
275
276
277
278
279
280
...
634
635
636
637
638
639
640







641
642
643
644
645
646
647
...
650
651
652
653
654
655
656




657
658
659
660
661
662
663
664
665
666
667
668
669
670
671

672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
    @ <p>You are currently logged in as <b>%h(g.zLogin)</b></p>
    @ <p>To change your login to a different user, enter
  }
  @ 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.</p>
  @

  @ <p>If you do not have an account, you can 
  @ <a href="%s(g.zTop)/register?g=%T(P("G"))">create one</a>.

  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);

    @ <p><input type="hidden" name="cs" value="%u(uSeed)" />
................................................................................
** WEBPAGE: register
**
** Generate the register page.
**
*/
void register_page(void){
  const char *zUsername, *zPasswd, *zConfirm, *zContact, *zCS, *zPw, *zCap;








  style_header("Register");
  zUsername = P("u");
  zPasswd = P("p");
  zConfirm = P("cp");
  zContact = P("c");
  zCap = P("cap");
................................................................................
  /* 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) ){
      @ <p><span class="loginError">
      @ All fields are obligatory.




      @ </span></p>
    }else if( strcmp(zPasswd,zConfirm)!=0 ){
      @ <p><span class="loginError">
      @ The two copies of your new passwords do not match.
      @ </span></p>
    }else if( strcasecmp(zPw, zCap)!=0 ){
      @ <p><span class="loginError">
      @ Captcha text invalid.
      @ </span></p>
    }else{
      /* This almost is stupid copy-paste of code from user.c:user_cmd(). */
      Blob passwd, login, contact;

      blob_init(&login, zUsername, -1);
      blob_init(&contact, zContact, -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.*/
        @ <p><span class="loginError">
        @ %s(zUsername) already exists.
        @ </span></p>
      }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,'u',%B)", /* u - register as reader, not developer! */
            &login, zPw, &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();







<
>
|
|
>







 







>
>
>
>
>
>
>







 







>
>
>
>











|



>












|
|







264
265
266
267
268
269
270

271
272
273
274
275
276
277
278
279
280
281
...
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
...
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
    @ <p>You are currently logged in as <b>%h(g.zLogin)</b></p>
    @ <p>To change your login to a different user, enter
  }
  @ 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.</p>

  if( db_get_boolean("self-register", 0) ){
    @ <p>If you do not have an account, you can 
    @ <a href="%s(g.zTop)/register?g=%T(P("G"))">create one</a>.
  }
  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);

    @ <p><input type="hidden" name="cs" value="%u(uSeed)" />
................................................................................
** 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");
    @ <p>This project does not allow user self-registration. Please contact the
    @ project administrator to obtain an account.</p>
    style_footer();
    return;
  }

  style_header("Register");
  zUsername = P("u");
  zPasswd = P("p");
  zConfirm = P("cp");
  zContact = P("c");
  zCap = P("cap");
................................................................................
  /* 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) ){
      @ <p><span class="loginError">
      @ All fields are obligatory.
      @ </span></p>
    }else if( strlen(zPasswd) < 6){
      @ <p><span class="loginError">
      @ Password too weak.
      @ </span></p>
    }else if( strcmp(zPasswd,zConfirm)!=0 ){
      @ <p><span class="loginError">
      @ The two copies of your new passwords do not match.
      @ </span></p>
    }else if( strcasecmp(zPw, zCap)!=0 ){
      @ <p><span class="loginError">
      @ Captcha text invalid.
      @ </span></p>
    }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.*/
        @ <p><span class="loginError">
        @ %s(zUsername) already exists.
        @ </span></p>
      }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();

Changes to src/setup.c.

788
789
790
791
792
793
794
















795
796
797
798
799
800
801
  entry_attribute("Download packet limit", 10, "max-download", "mxdwn",
                  "5000000");
  @ <p>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.</p>

















  @ <hr />
  onoff_attribute("Show javascript button to fill in CAPTCHA",
                  "auto-captcha", "autocaptcha", 0);
  @ <p>When enabled, a button appears on the login screen for user
  @ "anonymous" that will automatically fill in the CAPTCHA password.
  @ This is less secure than forcing the user to do it manually, but is







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
  entry_attribute("Download packet limit", 10, "max-download", "mxdwn",
                  "5000000");
  @ <p>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.</p>

  @ <hr />
  onoff_attribute("Allow users to register themselves",
                  "self-register", "selfregister", 0);
  @ <p>Allow users to register themselves through the HTTP UI. 
  @ The registration form always requires filling in a CAPTCHA 
  @ (<em>auto-captcha</em> 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".</p>

  @ <hr />
  entry_attribute("Default privileges", 10, "default-perms", "defaultperms", "u");
  @ <p>Permissions given to users that register themselves using the HTTP UI
  @ or are registered by the administrator using the command line interface.
  @ </p>

  @ <hr />
  onoff_attribute("Show javascript button to fill in CAPTCHA",
                  "auto-captcha", "autocaptcha", 0);
  @ <p>When enabled, a button appears on the login screen for user
  @ "anonymous" that will automatically fill in the CAPTCHA password.
  @ This is less secure than forcing the user to do it manually, but is

Changes to src/user.c.

178
179
180
181
182
183
184
185
186

187
188
189
190
191
192
193
...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
  int n;
  db_find_and_open_repository(0, 0);
  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;
    char *zPw;


    if( g.argc>=4 ){
      blob_init(&login, g.argv[3], -1);
    }else{
      prompt_user("login: ", &login);
    }
    if( db_exists("SELECT 1 FROM user WHERE login=%B", &login) ){
................................................................................
      blob_init(&passwd, g.argv[5], -1);
    }else{
      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
    );
    free(zPw);
  }else if( n>=2 && strncmp(g.argv[2],"default",n)==0 ){
    user_select();
    if( g.argc==3 ){
      printf("%s\n", g.zLogin);
    }else{







|

>







 







|
|







178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  int n;
  db_find_and_open_repository(0, 0);
  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, 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);
    }
    if( db_exists("SELECT 1 FROM user WHERE login=%B", &login) ){
................................................................................
      blob_init(&passwd, g.argv[5], -1);
    }else{
      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,%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 ){
      printf("%s\n", g.zLogin);
    }else{