Fossil

Check-in [3b7970e032]
Login

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

Overview
Comment:Add the ability to deny capabilities to self-registered accounts until the email verification comes through.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | restricted-self-registration
Files: files | file ages | folders
SHA3-256: 3b7970e032b39c6bab92a635d2c49430f0f833b01690df13e123403bd13ceb1f
User & Date: drh 2020-04-24 00:49:30.747
Context
2020-04-24
01:47
When there are repeated errors on a subscription or self-registration entry form, do not force the user to reenter the captcha if they have already entered it correctly once. ... (check-in: 3d80481216 user: drh tags: restricted-self-registration)
00:49
Add the ability to deny capabilities to self-registered accounts until the email verification comes through. ... (check-in: 3b7970e032 user: drh tags: restricted-self-registration)
2020-04-23
23:00
Merge the /subscribe fix from trunk. ... (check-in: fb38b92501 user: drh tags: restricted-self-registration)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/alerts.c.
1731
1732
1733
1734
1735
1736
1737
1738
1739

1740












1741
1742
1743
1744
1745
1746
1747
  sw = strchr(ssub,'w')!=0;
  sx = strchr(ssub,'x')!=0;
  smip = db_column_text(&q, 5);
  mtime = db_column_text(&q, 7);
  sctime = db_column_text(&q, 8);
  if( !g.perm.Admin && !sverified ){
    if( nName==64 ){
       db_multi_exec(
        "UPDATE subscriber SET sverified=1 WHERE subscriberCode=hextoblob(%Q)",

        zName);












      @ <h1>Your email alert subscription has been verified!</h1>
      @ <p>Use the form below to update your subscription information.</p>
      @ <p>Hint:  Bookmark this page so that you can more easily update
      @ your subscription information in the future</p>
    }else{
      @ <h2>Your email address is unverified</h2>
      @ <p>You should have received an email message containing a link







|
|
>

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







1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
  sw = strchr(ssub,'w')!=0;
  sx = strchr(ssub,'x')!=0;
  smip = db_column_text(&q, 5);
  mtime = db_column_text(&q, 7);
  sctime = db_column_text(&q, 8);
  if( !g.perm.Admin && !sverified ){
    if( nName==64 ){
      db_multi_exec(
        "UPDATE subscriber SET sverified=1"
        " WHERE subscriberCode=hextoblob(%Q)",
        zName);
      if( db_get_boolean("selfreg-verify",0) ){
        char *zNewCap = db_get("default-perms","u");
        db_multi_exec(
           "UPDATE user"
           "   SET cap=%Q"
           " WHERE cap='7' AND login=("
           "   SELECT suname FROM subscriber"
           "    WHERE subscriberCode=hextoblob(%Q))",
           zNewCap, zName
        );
        login_set_capabilities(zNewCap, 0);
      }
      @ <h1>Your email alert subscription has been verified!</h1>
      @ <p>Use the form below to update your subscription information.</p>
      @ <p>Hint:  Bookmark this page so that you can more easily update
      @ your subscription information in the future</p>
    }else{
      @ <h2>Your email address is unverified</h2>
      @ <p>You should have received an email message containing a link
Changes to src/capabilities.c.
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
void capability_summary(void){
  Stmt q;
  CapabilityString *pCap;
  char *zSelfCap;
  char *zPubPages = db_get("public-pages",0);
  int hasPubPages = zPubPages && zPubPages[0];

  pCap = capability_add(0, db_get("default-perms",0));
  capability_expand(pCap);
  zSelfCap = capability_string(pCap);
  capability_free(pCap);

  db_prepare(&q,
    "WITH t(id,seq) AS (VALUES('nobody',1),('anonymous',2),('reader',3),"
                       "('developer',4))"







|







364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
void capability_summary(void){
  Stmt q;
  CapabilityString *pCap;
  char *zSelfCap;
  char *zPubPages = db_get("public-pages",0);
  int hasPubPages = zPubPages && zPubPages[0];

  pCap = capability_add(0, db_get("default-perms","u"));
  capability_expand(pCap);
  zSelfCap = capability_string(pCap);
  capability_free(pCap);

  db_prepare(&q,
    "WITH t(id,seq) AS (VALUES('nobody',1),('anonymous',2),('reader',3),"
                       "('developer',4))"
Changes to src/login.c.
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
** to self-registered users.
*/
int login_self_register_available(const char *zNeeded){
  CapabilityString *pCap;
  int rc;
  if( !db_get_boolean("self-register",0) ) return 0;
  if( zNeeded==0 ) return 1;
  pCap = capability_add(0, db_get("default-perms", 0));
  capability_expand(pCap);
  rc = capability_has_any(pCap, zNeeded);
  capability_free(pCap);
  return rc;
}

/*







|







479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
** to self-registered users.
*/
int login_self_register_available(const char *zNeeded){
  CapabilityString *pCap;
  int rc;
  if( !db_get_boolean("self-register",0) ) return 0;
  if( zNeeded==0 ) return 1;
  pCap = capability_add(0, db_get("default-perms", "u"));
  capability_expand(pCap);
  rc = capability_has_any(pCap, zNeeded);
  capability_free(pCap);
  return rc;
}

/*
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
  */
  zPublicPages = db_get("public-pages",0);
  if( zPublicPages!=0 ){
    Glob *pGlob = glob_create(zPublicPages);
    const char *zUri = PD("REQUEST_URI","");
    zUri += (int)strlen(g.zTop);
    if( glob_match(pGlob, zUri) ){
      login_set_capabilities(db_get("default-perms", 0), 0);
    }
    glob_free(pGlob);
  }
}

/*
** Memory of settings







|







1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
  */
  zPublicPages = db_get("public-pages",0);
  if( zPublicPages!=0 ){
    Glob *pGlob = glob_create(zPublicPages);
    const char *zUri = PD("REQUEST_URI","");
    zUri += (int)strlen(g.zTop);
    if( glob_match(pGlob, zUri) ){
      login_set_capabilities(db_get("default-perms", "u"), 0);
    }
    glob_free(pGlob);
  }
}

/*
** Memory of settings
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
  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;
  }
  zPerms = db_get("default-perms", 0);

  /* Prompt the user for email alerts if this repository is configured for
  ** email alerts and if the default permissions include "7" */
  canDoAlerts = alert_tables_exist() && db_int(0,
    "SELECT fullcap(%Q) GLOB '*7*'", zPerms
  );
  doAlerts = canDoAlerts && atoi(PD("alerts","1"))!=0;







|







1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
  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;
  }
  zPerms = db_get("default-perms", "u");

  /* Prompt the user for email alerts if this repository is configured for
  ** email alerts and if the default permissions include "7" */
  canDoAlerts = alert_tables_exist() && db_int(0,
    "SELECT fullcap(%Q) GLOB '*7*'", zPerms
  );
  doAlerts = canDoAlerts && atoi(PD("alerts","1"))!=0;
1576
1577
1578
1579
1580
1581
1582








1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
    zErr = "This email address is already claimed by another user";
  }else{
    /* If all of the tests above have passed, that means that the submitted
    ** form contains valid data and we can proceed to create the new login */
    Blob sql;
    int uid;
    char *zPass = sha1_shared_secret(zPasswd, zUserID, 0);








    blob_init(&sql, 0, 0);
    blob_append_sql(&sql,
       "INSERT INTO user(login,pw,cap,info,mtime)\n"
       "VALUES(%Q,%Q,%Q,"
       "'%q <%q>\nself-register from ip %q on '||datetime('now'),now())",
       zUserID, zPass, zPerms, zDName, zEAddr, g.zIpAddr);
    fossil_free(zPass);
    db_multi_exec("%s", blob_sql_text(&sql));
    uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUserID);
    login_set_user_cookie(zUserID, uid, NULL);
    if( doAlerts ){
      /* Also make the new user a subscriber. */
      Blob hdr, body;







>
>
>
>
>
>
>
>





|







1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
    zErr = "This email address is already claimed by another user";
  }else{
    /* If all of the tests above have passed, that means that the submitted
    ** form contains valid data and we can proceed to create the new login */
    Blob sql;
    int uid;
    char *zPass = sha1_shared_secret(zPasswd, zUserID, 0);
    const char *zStartPerms = zPerms;
    if( db_get_boolean("selfreg-verify",0) ){
      /* If email verification is required for self-registration, initalize
      ** the new user capabilities to just "7" (Sign up for email).  The
      ** full "default-perms" permissions will be added when they click
      ** the verification link on the email they are sent. */
      zStartPerms = "7";
    }
    blob_init(&sql, 0, 0);
    blob_append_sql(&sql,
       "INSERT INTO user(login,pw,cap,info,mtime)\n"
       "VALUES(%Q,%Q,%Q,"
       "'%q <%q>\nself-register from ip %q on '||datetime('now'),now())",
       zUserID, zPass, zStartPerms, zDName, zEAddr, g.zIpAddr);
    fossil_free(zPass);
    db_multi_exec("%s", blob_sql_text(&sql));
    uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUserID);
    login_set_user_cookie(zUserID, uid, NULL);
    if( doAlerts ){
      /* Also make the new user a subscriber. */
      Blob hdr, body;
Changes to src/security_audit.c.
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
  ** though some content may be accessible anonymously.
  */
  zAnonCap = db_text("", "SELECT fullcap(NULL)");
  zDevCap  = db_text("", "SELECT fullcap('v')");
  zReadCap = db_text("", "SELECT fullcap('u')");
  zPubPages = db_get("public-pages",0);
  hasSelfReg = db_get_boolean("self-register",0);
  pCap = capability_add(0, db_get("default-perms",0));
  capability_expand(pCap);
  zSelfCap = capability_string(pCap);
  capability_free(pCap);
  if( hasAnyCap(zAnonCap,"as") ){
    @ <li><p>This repository is <big><b>Wildly INSECURE</b></big> because
    @ it grants administrator privileges to anonymous users.  You
    @ should <a href="takeitprivate">take this repository private</a>







|







120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
  ** though some content may be accessible anonymously.
  */
  zAnonCap = db_text("", "SELECT fullcap(NULL)");
  zDevCap  = db_text("", "SELECT fullcap('v')");
  zReadCap = db_text("", "SELECT fullcap('u')");
  zPubPages = db_get("public-pages",0);
  hasSelfReg = db_get_boolean("self-register",0);
  pCap = capability_add(0, db_get("default-perms","u"));
  capability_expand(pCap);
  zSelfCap = capability_string(pCap);
  capability_free(pCap);
  if( hasAnyCap(zAnonCap,"as") ){
    @ <li><p>This repository is <big><b>Wildly INSECURE</b></big> because
    @ it grants administrator privileges to anonymous users.  You
    @ should <a href="takeitprivate">take this repository private</a>
Changes to src/setup.c.
506
507
508
509
510
511
512








513
514
515
516
517
518
519
  @ <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).  Keep 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".  (Property: "self-register")</p>









  @ <hr />
  entry_attribute("Authorized self-registration email addresses", 35,
                  "self-reg-email", "selfregemail", "", 0);
  @ <p>This is a comma-separated list of GLOB patterns that specify
  @ email addresses that are authorized to self-register.  If blank
  @ (the usual case), then any email address can be used to self-register.
  @ This setting is used to limit self-registration to members of a particular







>
>
>
>
>
>
>
>







506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
  @ <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).  Keep 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".  (Property: "self-register")</p>

  @ <hr />
  onoff_attribute("Email verification required for self-registration",
                  "selfreg-verify", "selfregver", 0, 0);
  @ <p>If enabled, self-registration creates a new entry in the USER table
  @ but with provide any new capabilities until the email address provided
  @ with registration has been verified.
  @ (Property: "selfreg-verify")</p>

  @ <hr />
  entry_attribute("Authorized self-registration email addresses", 35,
                  "self-reg-email", "selfregemail", "", 0);
  @ <p>This is a comma-separated list of GLOB patterns that specify
  @ email addresses that are authorized to self-register.  If blank
  @ (the usual case), then any email address can be used to self-register.
  @ This setting is used to limit self-registration to members of a particular
Changes to src/setupuser.c.
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
  }else{
    @   <td><input type="text" name="login" value="%h(zLogin)" />\
    if( alert_tables_exist() ){
      int sid;
      sid = db_int(0, "SELECT subscriberId FROM subscriber"
                      " WHERE suname=%Q", zLogin);
      if( sid>0 ){
        @ &nbsp;&nbsp;<a href="%R/alerts?sid=%d(sid)>\
        @ (subscription info for %h(zLogin))</a>\
      }
    }
    @ </td></tr>
    @ <tr>
    @   <td class="usetupEditLabel">Contact&nbsp;Info:</td>
    @   <td><textarea name="info" cols="40" rows="2">%h(zInfo)</textarea></td>







|







551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
  }else{
    @   <td><input type="text" name="login" value="%h(zLogin)" />\
    if( alert_tables_exist() ){
      int sid;
      sid = db_int(0, "SELECT subscriberId FROM subscriber"
                      " WHERE suname=%Q", zLogin);
      if( sid>0 ){
        @ &nbsp;&nbsp;<a href="%R/alerts?sid=%d(sid)">\
        @ (subscription info for %h(zLogin))</a>\
      }
    }
    @ </td></tr>
    @ <tr>
    @   <td class="usetupEditLabel">Contact&nbsp;Info:</td>
    @   <td><textarea name="info" cols="40" rows="2">%h(zInfo)</textarea></td>