Fossil SCM

Add the ability to restrict subscriptions to specific email domains selected by GLOB patterns, and to require email verification before self-registration becomes effective.

drh 2020-04-24 05:21 trunk merge
Commit c00e9123cb89aacdc2992917af19bd3e30f2d021337c42d416baacfc8d7bd5bc
+60 -15
--- src/alerts.c
+++ src/alerts.c
@@ -1208,10 +1208,19 @@
12081208
int i, j, n;
12091209
char c;
12101210
12111211
*peErr = 0;
12121212
*pzErr = 0;
1213
+
1214
+ /* Verify the captcha first */
1215
+ if( needCaptcha ){
1216
+ if( !captcha_is_correct(1) ){
1217
+ *peErr = 2;
1218
+ *pzErr = mprintf("incorrect security code");
1219
+ return 0;
1220
+ }
1221
+ }
12131222
12141223
/* Check the validity of the email address.
12151224
**
12161225
** (1) Exactly one '@' character.
12171226
** (2) No other characters besides [a-zA-Z0-9._+-]
@@ -1219,11 +1228,15 @@
12191228
** The local part is currently more restrictive than RFC 5322 allows:
12201229
** https://stackoverflow.com/a/2049510/142454 We will expand this as
12211230
** necessary.
12221231
*/
12231232
zEAddr = P("e");
1224
- if( zEAddr==0 ) return 0;
1233
+ if( zEAddr==0 ){
1234
+ *peErr = 1;
1235
+ *pzErr = mprintf("required");
1236
+ return 0;
1237
+ }
12251238
for(i=j=n=0; (c = zEAddr[i])!=0; i++){
12261239
if( c=='@' ){
12271240
n = i;
12281241
j++;
12291242
continue;
@@ -1249,14 +1262,13 @@
12491262
*peErr = 1;
12501263
*pzErr = mprintf("email domain too short");
12511264
return 0;
12521265
}
12531266
1254
- /* Verify the captcha */
1255
- if( needCaptcha && !captcha_is_correct(1) ){
1256
- *peErr = 2;
1257
- *pzErr = mprintf("incorrect security code");
1267
+ if( authorized_subscription_email(zEAddr)==0 ){
1268
+ *peErr = 1;
1269
+ *pzErr = mprintf("not an authorized email address");
12581270
return 0;
12591271
}
12601272
12611273
/* Check to make sure the email address is available for reuse */
12621274
if( db_exists("SELECT 1 FROM subscriber WHERE semail=%Q", zEAddr) ){
@@ -1347,10 +1359,14 @@
13471359
/* Everybody else jumps to the page to administer their own
13481360
** account only. */
13491361
cgi_redirectf("%R/alerts");
13501362
return;
13511363
}
1364
+ }
1365
+ if( !g.perm.Admin && !db_get_boolean("anon-subscribe",1) ){
1366
+ register_page();
1367
+ return;
13521368
}
13531369
alert_submenu_common();
13541370
needCaptcha = !login_is_individual();
13551371
if( P("submit")
13561372
&& cgi_csrf_safe(1)
@@ -1415,11 +1431,11 @@
14151431
@ <blockquote><pre>
14161432
@ %h(pSender->zErr)
14171433
@ </pre></blockquote>
14181434
}else{
14191435
@ <p>An email has been sent to "%h(zEAddr)". That email contains a
1420
- @ hyperlink that you must click on in order to activate your
1436
+ @ hyperlink that you must click to activate your
14211437
@ subscription.</p>
14221438
}
14231439
alert_sender_free(pSender);
14241440
style_footer();
14251441
}
@@ -1447,16 +1463,22 @@
14471463
if( eErr==1 ){
14481464
@ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
14491465
}
14501466
@ </tr>
14511467
if( needCaptcha ){
1452
- uSeed = captcha_seed();
1468
+ const char *zInit = "";
1469
+ if( P("captchaseed")!=0 && eErr!=2 ){
1470
+ uSeed = strtoul(P("captchaseed"),0,10);
1471
+ zInit = P("captcha");
1472
+ }else{
1473
+ uSeed = captcha_seed();
1474
+ }
14531475
zDecoded = captcha_decode(uSeed);
14541476
zCaptcha = captcha_render(zDecoded);
14551477
@ <tr>
14561478
@ <td class="form_label">Security Code:</td>
1457
- @ <td><input type="text" name="captcha" value="" size="30">
1479
+ @ <td><input type="text" name="captcha" value="%h(zInit)" size="30">
14581480
captcha_speakit_button(uSeed, "Speak the code");
14591481
@ <input type="hidden" name="captchaseed" value="%u(uSeed)"></td>
14601482
@ </tr>
14611483
if( eErr==2 ){
14621484
@ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
@@ -1603,15 +1625,20 @@
16031625
char *zErr = 0; /* Error message text */
16041626
int sid = 0; /* Subscriber ID */
16051627
int nName; /* Length of zName in bytes */
16061628
char *zHalfCode; /* prefix of subscriberCode */
16071629
1608
- if( alert_webpages_disabled() ) return;
1630
+ db_begin_transaction();
1631
+ if( alert_webpages_disabled() ){
1632
+ db_commit_transaction();
1633
+ return;
1634
+ }
16091635
login_check_credentials();
16101636
if( !g.perm.EmailAlert ){
1637
+ db_commit_transaction();
16111638
login_needed(g.anon.EmailAlert);
1612
- return;
1639
+ /*NOTREACHED*/
16131640
}
16141641
isLogin = login_is_individual();
16151642
zName = P("name");
16161643
nName = zName ? (int)strlen(zName) : 0;
16171644
if( g.perm.Admin && P("sid")!=0 ){
@@ -1627,12 +1654,13 @@
16271654
if( sid==0 && isLogin ){
16281655
sid = db_int(0, "SELECT subscriberId FROM subscriber"
16291656
" WHERE suname=%Q", g.zLogin);
16301657
}
16311658
if( sid==0 ){
1659
+ db_commit_transaction();
16321660
cgi_redirect("subscribe");
1633
- return;
1661
+ /*NOTREACHED*/
16341662
}
16351663
alert_submenu_common();
16361664
if( P("submit")!=0 && cgi_csrf_safe(1) ){
16371665
char newSsub[10];
16381666
int nsub = 0;
@@ -1690,11 +1718,12 @@
16901718
eErr = 9;
16911719
zErr = mprintf("Select this checkbox and press \"Unsubscribe\" again to"
16921720
" unsubscribe");
16931721
}else{
16941722
alert_unsubscribe(sid);
1695
- return;
1723
+ db_commit_transaction();
1724
+ return;
16961725
}
16971726
}
16981727
style_header("Update Subscription");
16991728
db_prepare(&q,
17001729
"SELECT"
@@ -1709,12 +1738,13 @@
17091738
" datetime(sctime,'unixepoch')," /* 8 */
17101739
" hex(subscriberCode)" /* 9 */
17111740
" FROM subscriber WHERE subscriberId=%d", sid);
17121741
if( db_step(&q)!=SQLITE_ROW ){
17131742
db_finalize(&q);
1743
+ db_commit_transaction();
17141744
cgi_redirect("subscribe");
1715
- return;
1745
+ /*NOTREACHED*/
17161746
}
17171747
if( ssub==0 ){
17181748
semail = db_column_text(&q, 0);
17191749
sdonotcall = db_column_int(&q, 2);
17201750
sdigest = db_column_int(&q, 3);
@@ -1733,13 +1763,26 @@
17331763
smip = db_column_text(&q, 5);
17341764
mtime = db_column_text(&q, 7);
17351765
sctime = db_column_text(&q, 8);
17361766
if( !g.perm.Admin && !sverified ){
17371767
if( nName==64 ){
1738
- db_multi_exec(
1739
- "UPDATE subscriber SET sverified=1 WHERE subscriberCode=hextoblob(%Q)",
1768
+ db_multi_exec(
1769
+ "UPDATE subscriber SET sverified=1"
1770
+ " WHERE subscriberCode=hextoblob(%Q)",
17401771
zName);
1772
+ if( db_get_boolean("selfreg-verify",0) ){
1773
+ char *zNewCap = db_get("default-perms","u");
1774
+ db_multi_exec(
1775
+ "UPDATE user"
1776
+ " SET cap=%Q"
1777
+ " WHERE cap='7' AND login=("
1778
+ " SELECT suname FROM subscriber"
1779
+ " WHERE subscriberCode=hextoblob(%Q))",
1780
+ zNewCap, zName
1781
+ );
1782
+ login_set_capabilities(zNewCap, 0);
1783
+ }
17411784
@ <h1>Your email alert subscription has been verified!</h1>
17421785
@ <p>Use the form below to update your subscription information.</p>
17431786
@ <p>Hint: Bookmark this page so that you can more easily update
17441787
@ your subscription information in the future</p>
17451788
}else{
@@ -1855,10 +1898,12 @@
18551898
@ </table>
18561899
@ </form>
18571900
fossil_free(zErr);
18581901
db_finalize(&q);
18591902
style_footer();
1903
+ db_commit_transaction();
1904
+ return;
18601905
}
18611906
18621907
/* This is the message that gets sent to describe how to change
18631908
** or modify a subscription
18641909
*/
18651910
--- src/alerts.c
+++ src/alerts.c
@@ -1208,10 +1208,19 @@
1208 int i, j, n;
1209 char c;
1210
1211 *peErr = 0;
1212 *pzErr = 0;
 
 
 
 
 
 
 
 
 
1213
1214 /* Check the validity of the email address.
1215 **
1216 ** (1) Exactly one '@' character.
1217 ** (2) No other characters besides [a-zA-Z0-9._+-]
@@ -1219,11 +1228,15 @@
1219 ** The local part is currently more restrictive than RFC 5322 allows:
1220 ** https://stackoverflow.com/a/2049510/142454 We will expand this as
1221 ** necessary.
1222 */
1223 zEAddr = P("e");
1224 if( zEAddr==0 ) return 0;
 
 
 
 
1225 for(i=j=n=0; (c = zEAddr[i])!=0; i++){
1226 if( c=='@' ){
1227 n = i;
1228 j++;
1229 continue;
@@ -1249,14 +1262,13 @@
1249 *peErr = 1;
1250 *pzErr = mprintf("email domain too short");
1251 return 0;
1252 }
1253
1254 /* Verify the captcha */
1255 if( needCaptcha && !captcha_is_correct(1) ){
1256 *peErr = 2;
1257 *pzErr = mprintf("incorrect security code");
1258 return 0;
1259 }
1260
1261 /* Check to make sure the email address is available for reuse */
1262 if( db_exists("SELECT 1 FROM subscriber WHERE semail=%Q", zEAddr) ){
@@ -1347,10 +1359,14 @@
1347 /* Everybody else jumps to the page to administer their own
1348 ** account only. */
1349 cgi_redirectf("%R/alerts");
1350 return;
1351 }
 
 
 
 
1352 }
1353 alert_submenu_common();
1354 needCaptcha = !login_is_individual();
1355 if( P("submit")
1356 && cgi_csrf_safe(1)
@@ -1415,11 +1431,11 @@
1415 @ <blockquote><pre>
1416 @ %h(pSender->zErr)
1417 @ </pre></blockquote>
1418 }else{
1419 @ <p>An email has been sent to "%h(zEAddr)". That email contains a
1420 @ hyperlink that you must click on in order to activate your
1421 @ subscription.</p>
1422 }
1423 alert_sender_free(pSender);
1424 style_footer();
1425 }
@@ -1447,16 +1463,22 @@
1447 if( eErr==1 ){
1448 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
1449 }
1450 @ </tr>
1451 if( needCaptcha ){
1452 uSeed = captcha_seed();
 
 
 
 
 
 
1453 zDecoded = captcha_decode(uSeed);
1454 zCaptcha = captcha_render(zDecoded);
1455 @ <tr>
1456 @ <td class="form_label">Security Code:</td>
1457 @ <td><input type="text" name="captcha" value="" size="30">
1458 captcha_speakit_button(uSeed, "Speak the code");
1459 @ <input type="hidden" name="captchaseed" value="%u(uSeed)"></td>
1460 @ </tr>
1461 if( eErr==2 ){
1462 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
@@ -1603,15 +1625,20 @@
1603 char *zErr = 0; /* Error message text */
1604 int sid = 0; /* Subscriber ID */
1605 int nName; /* Length of zName in bytes */
1606 char *zHalfCode; /* prefix of subscriberCode */
1607
1608 if( alert_webpages_disabled() ) return;
 
 
 
 
1609 login_check_credentials();
1610 if( !g.perm.EmailAlert ){
 
1611 login_needed(g.anon.EmailAlert);
1612 return;
1613 }
1614 isLogin = login_is_individual();
1615 zName = P("name");
1616 nName = zName ? (int)strlen(zName) : 0;
1617 if( g.perm.Admin && P("sid")!=0 ){
@@ -1627,12 +1654,13 @@
1627 if( sid==0 && isLogin ){
1628 sid = db_int(0, "SELECT subscriberId FROM subscriber"
1629 " WHERE suname=%Q", g.zLogin);
1630 }
1631 if( sid==0 ){
 
1632 cgi_redirect("subscribe");
1633 return;
1634 }
1635 alert_submenu_common();
1636 if( P("submit")!=0 && cgi_csrf_safe(1) ){
1637 char newSsub[10];
1638 int nsub = 0;
@@ -1690,11 +1718,12 @@
1690 eErr = 9;
1691 zErr = mprintf("Select this checkbox and press \"Unsubscribe\" again to"
1692 " unsubscribe");
1693 }else{
1694 alert_unsubscribe(sid);
1695 return;
 
1696 }
1697 }
1698 style_header("Update Subscription");
1699 db_prepare(&q,
1700 "SELECT"
@@ -1709,12 +1738,13 @@
1709 " datetime(sctime,'unixepoch')," /* 8 */
1710 " hex(subscriberCode)" /* 9 */
1711 " FROM subscriber WHERE subscriberId=%d", sid);
1712 if( db_step(&q)!=SQLITE_ROW ){
1713 db_finalize(&q);
 
1714 cgi_redirect("subscribe");
1715 return;
1716 }
1717 if( ssub==0 ){
1718 semail = db_column_text(&q, 0);
1719 sdonotcall = db_column_int(&q, 2);
1720 sdigest = db_column_int(&q, 3);
@@ -1733,13 +1763,26 @@
1733 smip = db_column_text(&q, 5);
1734 mtime = db_column_text(&q, 7);
1735 sctime = db_column_text(&q, 8);
1736 if( !g.perm.Admin && !sverified ){
1737 if( nName==64 ){
1738 db_multi_exec(
1739 "UPDATE subscriber SET sverified=1 WHERE subscriberCode=hextoblob(%Q)",
 
1740 zName);
 
 
 
 
 
 
 
 
 
 
 
 
1741 @ <h1>Your email alert subscription has been verified!</h1>
1742 @ <p>Use the form below to update your subscription information.</p>
1743 @ <p>Hint: Bookmark this page so that you can more easily update
1744 @ your subscription information in the future</p>
1745 }else{
@@ -1855,10 +1898,12 @@
1855 @ </table>
1856 @ </form>
1857 fossil_free(zErr);
1858 db_finalize(&q);
1859 style_footer();
 
 
1860 }
1861
1862 /* This is the message that gets sent to describe how to change
1863 ** or modify a subscription
1864 */
1865
--- src/alerts.c
+++ src/alerts.c
@@ -1208,10 +1208,19 @@
1208 int i, j, n;
1209 char c;
1210
1211 *peErr = 0;
1212 *pzErr = 0;
1213
1214 /* Verify the captcha first */
1215 if( needCaptcha ){
1216 if( !captcha_is_correct(1) ){
1217 *peErr = 2;
1218 *pzErr = mprintf("incorrect security code");
1219 return 0;
1220 }
1221 }
1222
1223 /* Check the validity of the email address.
1224 **
1225 ** (1) Exactly one '@' character.
1226 ** (2) No other characters besides [a-zA-Z0-9._+-]
@@ -1219,11 +1228,15 @@
1228 ** The local part is currently more restrictive than RFC 5322 allows:
1229 ** https://stackoverflow.com/a/2049510/142454 We will expand this as
1230 ** necessary.
1231 */
1232 zEAddr = P("e");
1233 if( zEAddr==0 ){
1234 *peErr = 1;
1235 *pzErr = mprintf("required");
1236 return 0;
1237 }
1238 for(i=j=n=0; (c = zEAddr[i])!=0; i++){
1239 if( c=='@' ){
1240 n = i;
1241 j++;
1242 continue;
@@ -1249,14 +1262,13 @@
1262 *peErr = 1;
1263 *pzErr = mprintf("email domain too short");
1264 return 0;
1265 }
1266
1267 if( authorized_subscription_email(zEAddr)==0 ){
1268 *peErr = 1;
1269 *pzErr = mprintf("not an authorized email address");
 
1270 return 0;
1271 }
1272
1273 /* Check to make sure the email address is available for reuse */
1274 if( db_exists("SELECT 1 FROM subscriber WHERE semail=%Q", zEAddr) ){
@@ -1347,10 +1359,14 @@
1359 /* Everybody else jumps to the page to administer their own
1360 ** account only. */
1361 cgi_redirectf("%R/alerts");
1362 return;
1363 }
1364 }
1365 if( !g.perm.Admin && !db_get_boolean("anon-subscribe",1) ){
1366 register_page();
1367 return;
1368 }
1369 alert_submenu_common();
1370 needCaptcha = !login_is_individual();
1371 if( P("submit")
1372 && cgi_csrf_safe(1)
@@ -1415,11 +1431,11 @@
1431 @ <blockquote><pre>
1432 @ %h(pSender->zErr)
1433 @ </pre></blockquote>
1434 }else{
1435 @ <p>An email has been sent to "%h(zEAddr)". That email contains a
1436 @ hyperlink that you must click to activate your
1437 @ subscription.</p>
1438 }
1439 alert_sender_free(pSender);
1440 style_footer();
1441 }
@@ -1447,16 +1463,22 @@
1463 if( eErr==1 ){
1464 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
1465 }
1466 @ </tr>
1467 if( needCaptcha ){
1468 const char *zInit = "";
1469 if( P("captchaseed")!=0 && eErr!=2 ){
1470 uSeed = strtoul(P("captchaseed"),0,10);
1471 zInit = P("captcha");
1472 }else{
1473 uSeed = captcha_seed();
1474 }
1475 zDecoded = captcha_decode(uSeed);
1476 zCaptcha = captcha_render(zDecoded);
1477 @ <tr>
1478 @ <td class="form_label">Security Code:</td>
1479 @ <td><input type="text" name="captcha" value="%h(zInit)" size="30">
1480 captcha_speakit_button(uSeed, "Speak the code");
1481 @ <input type="hidden" name="captchaseed" value="%u(uSeed)"></td>
1482 @ </tr>
1483 if( eErr==2 ){
1484 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
@@ -1603,15 +1625,20 @@
1625 char *zErr = 0; /* Error message text */
1626 int sid = 0; /* Subscriber ID */
1627 int nName; /* Length of zName in bytes */
1628 char *zHalfCode; /* prefix of subscriberCode */
1629
1630 db_begin_transaction();
1631 if( alert_webpages_disabled() ){
1632 db_commit_transaction();
1633 return;
1634 }
1635 login_check_credentials();
1636 if( !g.perm.EmailAlert ){
1637 db_commit_transaction();
1638 login_needed(g.anon.EmailAlert);
1639 /*NOTREACHED*/
1640 }
1641 isLogin = login_is_individual();
1642 zName = P("name");
1643 nName = zName ? (int)strlen(zName) : 0;
1644 if( g.perm.Admin && P("sid")!=0 ){
@@ -1627,12 +1654,13 @@
1654 if( sid==0 && isLogin ){
1655 sid = db_int(0, "SELECT subscriberId FROM subscriber"
1656 " WHERE suname=%Q", g.zLogin);
1657 }
1658 if( sid==0 ){
1659 db_commit_transaction();
1660 cgi_redirect("subscribe");
1661 /*NOTREACHED*/
1662 }
1663 alert_submenu_common();
1664 if( P("submit")!=0 && cgi_csrf_safe(1) ){
1665 char newSsub[10];
1666 int nsub = 0;
@@ -1690,11 +1718,12 @@
1718 eErr = 9;
1719 zErr = mprintf("Select this checkbox and press \"Unsubscribe\" again to"
1720 " unsubscribe");
1721 }else{
1722 alert_unsubscribe(sid);
1723 db_commit_transaction();
1724 return;
1725 }
1726 }
1727 style_header("Update Subscription");
1728 db_prepare(&q,
1729 "SELECT"
@@ -1709,12 +1738,13 @@
1738 " datetime(sctime,'unixepoch')," /* 8 */
1739 " hex(subscriberCode)" /* 9 */
1740 " FROM subscriber WHERE subscriberId=%d", sid);
1741 if( db_step(&q)!=SQLITE_ROW ){
1742 db_finalize(&q);
1743 db_commit_transaction();
1744 cgi_redirect("subscribe");
1745 /*NOTREACHED*/
1746 }
1747 if( ssub==0 ){
1748 semail = db_column_text(&q, 0);
1749 sdonotcall = db_column_int(&q, 2);
1750 sdigest = db_column_int(&q, 3);
@@ -1733,13 +1763,26 @@
1763 smip = db_column_text(&q, 5);
1764 mtime = db_column_text(&q, 7);
1765 sctime = db_column_text(&q, 8);
1766 if( !g.perm.Admin && !sverified ){
1767 if( nName==64 ){
1768 db_multi_exec(
1769 "UPDATE subscriber SET sverified=1"
1770 " WHERE subscriberCode=hextoblob(%Q)",
1771 zName);
1772 if( db_get_boolean("selfreg-verify",0) ){
1773 char *zNewCap = db_get("default-perms","u");
1774 db_multi_exec(
1775 "UPDATE user"
1776 " SET cap=%Q"
1777 " WHERE cap='7' AND login=("
1778 " SELECT suname FROM subscriber"
1779 " WHERE subscriberCode=hextoblob(%Q))",
1780 zNewCap, zName
1781 );
1782 login_set_capabilities(zNewCap, 0);
1783 }
1784 @ <h1>Your email alert subscription has been verified!</h1>
1785 @ <p>Use the form below to update your subscription information.</p>
1786 @ <p>Hint: Bookmark this page so that you can more easily update
1787 @ your subscription information in the future</p>
1788 }else{
@@ -1855,10 +1898,12 @@
1898 @ </table>
1899 @ </form>
1900 fossil_free(zErr);
1901 db_finalize(&q);
1902 style_footer();
1903 db_commit_transaction();
1904 return;
1905 }
1906
1907 /* This is the message that gets sent to describe how to change
1908 ** or modify a subscription
1909 */
1910
--- src/capabilities.c
+++ src/capabilities.c
@@ -366,11 +366,11 @@
366366
CapabilityString *pCap;
367367
char *zSelfCap;
368368
char *zPubPages = db_get("public-pages",0);
369369
int hasPubPages = zPubPages && zPubPages[0];
370370
371
- pCap = capability_add(0, db_get("default-perms",0));
371
+ pCap = capability_add(0, db_get("default-perms","u"));
372372
capability_expand(pCap);
373373
zSelfCap = capability_string(pCap);
374374
capability_free(pCap);
375375
376376
db_prepare(&q,
377377
--- src/capabilities.c
+++ src/capabilities.c
@@ -366,11 +366,11 @@
366 CapabilityString *pCap;
367 char *zSelfCap;
368 char *zPubPages = db_get("public-pages",0);
369 int hasPubPages = zPubPages && zPubPages[0];
370
371 pCap = capability_add(0, db_get("default-perms",0));
372 capability_expand(pCap);
373 zSelfCap = capability_string(pCap);
374 capability_free(pCap);
375
376 db_prepare(&q,
377
--- src/capabilities.c
+++ src/capabilities.c
@@ -366,11 +366,11 @@
366 CapabilityString *pCap;
367 char *zSelfCap;
368 char *zPubPages = db_get("public-pages",0);
369 int hasPubPages = zPubPages && zPubPages[0];
370
371 pCap = capability_add(0, db_get("default-perms","u"));
372 capability_expand(pCap);
373 zSelfCap = capability_string(pCap);
374 capability_free(pCap);
375
376 db_prepare(&q,
377
+54 -10
--- src/login.c
+++ src/login.c
@@ -481,11 +481,11 @@
481481
int login_self_register_available(const char *zNeeded){
482482
CapabilityString *pCap;
483483
int rc;
484484
if( !db_get_boolean("self-register",0) ) return 0;
485485
if( zNeeded==0 ) return 1;
486
- pCap = capability_add(0, db_get("default-perms", 0));
486
+ pCap = capability_add(0, db_get("default-perms", "u"));
487487
capability_expand(pCap);
488488
rc = capability_has_any(pCap, zNeeded);
489489
capability_free(pCap);
490490
return rc;
491491
}
@@ -1128,11 +1128,11 @@
11281128
if( zPublicPages!=0 ){
11291129
Glob *pGlob = glob_create(zPublicPages);
11301130
const char *zUri = PD("REQUEST_URI","");
11311131
zUri += (int)strlen(g.zTop);
11321132
if( glob_match(pGlob, zUri) ){
1133
- login_set_capabilities(db_get("default-perms", 0), 0);
1133
+ login_set_capabilities(db_get("default-perms", "u"), 0);
11341134
}
11351135
glob_free(pGlob);
11361136
}
11371137
}
11381138
@@ -1459,10 +1459,38 @@
14591459
"SELECT 1 FROM event WHERE user=%Q OR euser=%Q",
14601460
zUserID, zUserID, zUserID
14611461
);
14621462
return rc;
14631463
}
1464
+
1465
+/*
1466
+** Check an email address and confirm that it is valid for self-registration.
1467
+** The email address is known already to be well-formed. Return true
1468
+** if the email address is on the allowed list.
1469
+**
1470
+** The default behavior is that any valid email address is accepted.
1471
+** But if the "auth-sub-email" setting exists and is not empty, then
1472
+** it is a comma-separated list of GLOB patterns for email addresses
1473
+** that are authorized to self-register.
1474
+*/
1475
+int authorized_subscription_email(const char *zEAddr){
1476
+ char *zGlob = db_get("auth-sub-email",0);
1477
+ Glob *pGlob;
1478
+ char *zAddr;
1479
+ int rc;
1480
+
1481
+ if( zGlob==0 || zGlob[0]==0 ) return 1;
1482
+ zGlob = fossil_strtolwr(fossil_strdup(zGlob));
1483
+ pGlob = glob_create(zGlob);
1484
+ fossil_free(zGlob);
1485
+
1486
+ zAddr = fossil_strtolwr(fossil_strdup(zEAddr));
1487
+ rc = glob_match(pGlob, zAddr);
1488
+ fossil_free(zAddr);
1489
+ glob_free(pGlob);
1490
+ return rc!=0;
1491
+}
14641492
14651493
/*
14661494
** WEBPAGE: register
14671495
**
14681496
** Page to allow users to self-register. The "self-register" setting
@@ -1471,13 +1499,14 @@
14711499
void register_page(void){
14721500
const char *zUserID, *zPasswd, *zConfirm, *zEAddr;
14731501
const char *zDName;
14741502
unsigned int uSeed;
14751503
const char *zDecoded;
1476
- char *zCaptcha;
14771504
int iErrLine = -1;
14781505
const char *zErr = 0;
1506
+ int captchaIsCorrect = 0; /* True on a correct captcha */
1507
+ char *zCaptcha = ""; /* Value of the captcha text */
14791508
char *zPerms; /* Permissions for the default user */
14801509
int canDoAlerts = 0; /* True if receiving email alerts is possible */
14811510
int doAlerts = 0; /* True if subscription is wanted too */
14821511
if( !db_get_boolean("self-register", 0) ){
14831512
style_header("Registration not possible");
@@ -1484,11 +1513,11 @@
14841513
@ <p>This project does not allow user self-registration. Please contact the
14851514
@ project administrator to obtain an account.</p>
14861515
style_footer();
14871516
return;
14881517
}
1489
- zPerms = db_get("default-perms", 0);
1518
+ zPerms = db_get("default-perms", "u");
14901519
14911520
/* Prompt the user for email alerts if this repository is configured for
14921521
** email alerts and if the default permissions include "7" */
14931522
canDoAlerts = alert_tables_exist() && db_int(0,
14941523
"SELECT fullcap(%Q) GLOB '*7*'", zPerms
@@ -1503,11 +1532,11 @@
15031532
15041533
/* Verify user imputs */
15051534
if( P("new")==0 || !cgi_csrf_safe(1) ){
15061535
/* This is not a valid form submission. Fall through into
15071536
** the form display */
1508
- }else if( !captcha_is_correct(1) ){
1537
+ }else if( (captchaIsCorrect = captcha_is_correct(1))==0 ){
15091538
iErrLine = 6;
15101539
zErr = "Incorrect CAPTCHA";
15111540
}else if( strlen(zUserID)<6 ){
15121541
iErrLine = 1;
15131542
zErr = "User ID too short. Must be at least 6 characters.";
@@ -1521,10 +1550,13 @@
15211550
iErrLine = 3;
15221551
zErr = "Required";
15231552
}else if( email_address_is_valid(zEAddr,0)==0 ){
15241553
iErrLine = 3;
15251554
zErr = "Not a valid email address";
1555
+ }else if( authorized_subscription_email(zEAddr)==0 ){
1556
+ iErrLine = 3;
1557
+ zErr = "Not an authorized email address";
15261558
}else if( strlen(zPasswd)<6 ){
15271559
iErrLine = 4;
15281560
zErr = "Password must be at least 6 characters long";
15291561
}else if( fossil_strcmp(zPasswd,zConfirm)!=0 ){
15301562
iErrLine = 5;
@@ -1548,16 +1580,24 @@
15481580
/* If all of the tests above have passed, that means that the submitted
15491581
** form contains valid data and we can proceed to create the new login */
15501582
Blob sql;
15511583
int uid;
15521584
char *zPass = sha1_shared_secret(zPasswd, zUserID, 0);
1585
+ const char *zStartPerms = zPerms;
1586
+ if( db_get_boolean("selfreg-verify",0) ){
1587
+ /* If email verification is required for self-registration, initalize
1588
+ ** the new user capabilities to just "7" (Sign up for email). The
1589
+ ** full "default-perms" permissions will be added when they click
1590
+ ** the verification link on the email they are sent. */
1591
+ zStartPerms = "7";
1592
+ }
15531593
blob_init(&sql, 0, 0);
15541594
blob_append_sql(&sql,
15551595
"INSERT INTO user(login,pw,cap,info,mtime)\n"
15561596
"VALUES(%Q,%Q,%Q,"
15571597
"'%q <%q>\nself-register from ip %q on '||datetime('now'),now())",
1558
- zUserID, zPass, zPerms, zDName, zEAddr, g.zIpAddr);
1598
+ zUserID, zPass, zStartPerms, zDName, zEAddr, g.zIpAddr);
15591599
fossil_free(zPass);
15601600
db_multi_exec("%s", blob_sql_text(&sql));
15611601
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUserID);
15621602
login_set_user_cookie(zUserID, uid, NULL);
15631603
if( doAlerts ){
@@ -1620,12 +1660,11 @@
16201660
@ <blockquote><pre>
16211661
@ %h(pSender->zErr)
16221662
@ </pre></blockquote>
16231663
}else{
16241664
@ <p>An email has been sent to "%h(zEAddr)". That email contains a
1625
- @ hyperlink that you must click on in order to activate your
1626
- @ subscription.</p>
1665
+ @ hyperlink that you must click to activate your account.</p>
16271666
}
16281667
alert_sender_free(pSender);
16291668
if( zGoto ){
16301669
@ <p><a href='%h(zGoto)'>Continue</a>
16311670
}
@@ -1634,11 +1673,15 @@
16341673
}
16351674
redirect_to_g();
16361675
}
16371676
16381677
/* Prepare the captcha. */
1639
- uSeed = captcha_seed();
1678
+ if( captchaIsCorrect ){
1679
+ uSeed = strtoul(P("captchaseed"),0,10);
1680
+ }else{
1681
+ uSeed = captcha_seed();
1682
+ }
16401683
zDecoded = captcha_decode(uSeed);
16411684
zCaptcha = captcha_render(zDecoded);
16421685
16431686
style_header("Register");
16441687
/* Print out the registration form. */
@@ -1693,11 +1736,12 @@
16931736
if( iErrLine==5 ){
16941737
@ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
16951738
}
16961739
@ <tr>
16971740
@ <td class="form_label" align="right">Captcha:</td>
1698
- @ <td><input type="text" name="captcha" value="" size="30">
1741
+ @ <td><input type="text" name="captcha" size="30"\
1742
+ @ value="%h(captchaIsCorrect?zDecoded:"")" size="30">
16991743
captcha_speakit_button(uSeed, "Speak the captcha text");
17001744
@ </td>
17011745
@ </tr>
17021746
if( iErrLine==6 ){
17031747
@ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
17041748
--- src/login.c
+++ src/login.c
@@ -481,11 +481,11 @@
481 int login_self_register_available(const char *zNeeded){
482 CapabilityString *pCap;
483 int rc;
484 if( !db_get_boolean("self-register",0) ) return 0;
485 if( zNeeded==0 ) return 1;
486 pCap = capability_add(0, db_get("default-perms", 0));
487 capability_expand(pCap);
488 rc = capability_has_any(pCap, zNeeded);
489 capability_free(pCap);
490 return rc;
491 }
@@ -1128,11 +1128,11 @@
1128 if( zPublicPages!=0 ){
1129 Glob *pGlob = glob_create(zPublicPages);
1130 const char *zUri = PD("REQUEST_URI","");
1131 zUri += (int)strlen(g.zTop);
1132 if( glob_match(pGlob, zUri) ){
1133 login_set_capabilities(db_get("default-perms", 0), 0);
1134 }
1135 glob_free(pGlob);
1136 }
1137 }
1138
@@ -1459,10 +1459,38 @@
1459 "SELECT 1 FROM event WHERE user=%Q OR euser=%Q",
1460 zUserID, zUserID, zUserID
1461 );
1462 return rc;
1463 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1464
1465 /*
1466 ** WEBPAGE: register
1467 **
1468 ** Page to allow users to self-register. The "self-register" setting
@@ -1471,13 +1499,14 @@
1471 void register_page(void){
1472 const char *zUserID, *zPasswd, *zConfirm, *zEAddr;
1473 const char *zDName;
1474 unsigned int uSeed;
1475 const char *zDecoded;
1476 char *zCaptcha;
1477 int iErrLine = -1;
1478 const char *zErr = 0;
 
 
1479 char *zPerms; /* Permissions for the default user */
1480 int canDoAlerts = 0; /* True if receiving email alerts is possible */
1481 int doAlerts = 0; /* True if subscription is wanted too */
1482 if( !db_get_boolean("self-register", 0) ){
1483 style_header("Registration not possible");
@@ -1484,11 +1513,11 @@
1484 @ <p>This project does not allow user self-registration. Please contact the
1485 @ project administrator to obtain an account.</p>
1486 style_footer();
1487 return;
1488 }
1489 zPerms = db_get("default-perms", 0);
1490
1491 /* Prompt the user for email alerts if this repository is configured for
1492 ** email alerts and if the default permissions include "7" */
1493 canDoAlerts = alert_tables_exist() && db_int(0,
1494 "SELECT fullcap(%Q) GLOB '*7*'", zPerms
@@ -1503,11 +1532,11 @@
1503
1504 /* Verify user imputs */
1505 if( P("new")==0 || !cgi_csrf_safe(1) ){
1506 /* This is not a valid form submission. Fall through into
1507 ** the form display */
1508 }else if( !captcha_is_correct(1) ){
1509 iErrLine = 6;
1510 zErr = "Incorrect CAPTCHA";
1511 }else if( strlen(zUserID)<6 ){
1512 iErrLine = 1;
1513 zErr = "User ID too short. Must be at least 6 characters.";
@@ -1521,10 +1550,13 @@
1521 iErrLine = 3;
1522 zErr = "Required";
1523 }else if( email_address_is_valid(zEAddr,0)==0 ){
1524 iErrLine = 3;
1525 zErr = "Not a valid email address";
 
 
 
1526 }else if( strlen(zPasswd)<6 ){
1527 iErrLine = 4;
1528 zErr = "Password must be at least 6 characters long";
1529 }else if( fossil_strcmp(zPasswd,zConfirm)!=0 ){
1530 iErrLine = 5;
@@ -1548,16 +1580,24 @@
1548 /* If all of the tests above have passed, that means that the submitted
1549 ** form contains valid data and we can proceed to create the new login */
1550 Blob sql;
1551 int uid;
1552 char *zPass = sha1_shared_secret(zPasswd, zUserID, 0);
 
 
 
 
 
 
 
 
1553 blob_init(&sql, 0, 0);
1554 blob_append_sql(&sql,
1555 "INSERT INTO user(login,pw,cap,info,mtime)\n"
1556 "VALUES(%Q,%Q,%Q,"
1557 "'%q <%q>\nself-register from ip %q on '||datetime('now'),now())",
1558 zUserID, zPass, zPerms, zDName, zEAddr, g.zIpAddr);
1559 fossil_free(zPass);
1560 db_multi_exec("%s", blob_sql_text(&sql));
1561 uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUserID);
1562 login_set_user_cookie(zUserID, uid, NULL);
1563 if( doAlerts ){
@@ -1620,12 +1660,11 @@
1620 @ <blockquote><pre>
1621 @ %h(pSender->zErr)
1622 @ </pre></blockquote>
1623 }else{
1624 @ <p>An email has been sent to "%h(zEAddr)". That email contains a
1625 @ hyperlink that you must click on in order to activate your
1626 @ subscription.</p>
1627 }
1628 alert_sender_free(pSender);
1629 if( zGoto ){
1630 @ <p><a href='%h(zGoto)'>Continue</a>
1631 }
@@ -1634,11 +1673,15 @@
1634 }
1635 redirect_to_g();
1636 }
1637
1638 /* Prepare the captcha. */
1639 uSeed = captcha_seed();
 
 
 
 
1640 zDecoded = captcha_decode(uSeed);
1641 zCaptcha = captcha_render(zDecoded);
1642
1643 style_header("Register");
1644 /* Print out the registration form. */
@@ -1693,11 +1736,12 @@
1693 if( iErrLine==5 ){
1694 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
1695 }
1696 @ <tr>
1697 @ <td class="form_label" align="right">Captcha:</td>
1698 @ <td><input type="text" name="captcha" value="" size="30">
 
1699 captcha_speakit_button(uSeed, "Speak the captcha text");
1700 @ </td>
1701 @ </tr>
1702 if( iErrLine==6 ){
1703 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
1704
--- src/login.c
+++ src/login.c
@@ -481,11 +481,11 @@
481 int login_self_register_available(const char *zNeeded){
482 CapabilityString *pCap;
483 int rc;
484 if( !db_get_boolean("self-register",0) ) return 0;
485 if( zNeeded==0 ) return 1;
486 pCap = capability_add(0, db_get("default-perms", "u"));
487 capability_expand(pCap);
488 rc = capability_has_any(pCap, zNeeded);
489 capability_free(pCap);
490 return rc;
491 }
@@ -1128,11 +1128,11 @@
1128 if( zPublicPages!=0 ){
1129 Glob *pGlob = glob_create(zPublicPages);
1130 const char *zUri = PD("REQUEST_URI","");
1131 zUri += (int)strlen(g.zTop);
1132 if( glob_match(pGlob, zUri) ){
1133 login_set_capabilities(db_get("default-perms", "u"), 0);
1134 }
1135 glob_free(pGlob);
1136 }
1137 }
1138
@@ -1459,10 +1459,38 @@
1459 "SELECT 1 FROM event WHERE user=%Q OR euser=%Q",
1460 zUserID, zUserID, zUserID
1461 );
1462 return rc;
1463 }
1464
1465 /*
1466 ** Check an email address and confirm that it is valid for self-registration.
1467 ** The email address is known already to be well-formed. Return true
1468 ** if the email address is on the allowed list.
1469 **
1470 ** The default behavior is that any valid email address is accepted.
1471 ** But if the "auth-sub-email" setting exists and is not empty, then
1472 ** it is a comma-separated list of GLOB patterns for email addresses
1473 ** that are authorized to self-register.
1474 */
1475 int authorized_subscription_email(const char *zEAddr){
1476 char *zGlob = db_get("auth-sub-email",0);
1477 Glob *pGlob;
1478 char *zAddr;
1479 int rc;
1480
1481 if( zGlob==0 || zGlob[0]==0 ) return 1;
1482 zGlob = fossil_strtolwr(fossil_strdup(zGlob));
1483 pGlob = glob_create(zGlob);
1484 fossil_free(zGlob);
1485
1486 zAddr = fossil_strtolwr(fossil_strdup(zEAddr));
1487 rc = glob_match(pGlob, zAddr);
1488 fossil_free(zAddr);
1489 glob_free(pGlob);
1490 return rc!=0;
1491 }
1492
1493 /*
1494 ** WEBPAGE: register
1495 **
1496 ** Page to allow users to self-register. The "self-register" setting
@@ -1471,13 +1499,14 @@
1499 void register_page(void){
1500 const char *zUserID, *zPasswd, *zConfirm, *zEAddr;
1501 const char *zDName;
1502 unsigned int uSeed;
1503 const char *zDecoded;
 
1504 int iErrLine = -1;
1505 const char *zErr = 0;
1506 int captchaIsCorrect = 0; /* True on a correct captcha */
1507 char *zCaptcha = ""; /* Value of the captcha text */
1508 char *zPerms; /* Permissions for the default user */
1509 int canDoAlerts = 0; /* True if receiving email alerts is possible */
1510 int doAlerts = 0; /* True if subscription is wanted too */
1511 if( !db_get_boolean("self-register", 0) ){
1512 style_header("Registration not possible");
@@ -1484,11 +1513,11 @@
1513 @ <p>This project does not allow user self-registration. Please contact the
1514 @ project administrator to obtain an account.</p>
1515 style_footer();
1516 return;
1517 }
1518 zPerms = db_get("default-perms", "u");
1519
1520 /* Prompt the user for email alerts if this repository is configured for
1521 ** email alerts and if the default permissions include "7" */
1522 canDoAlerts = alert_tables_exist() && db_int(0,
1523 "SELECT fullcap(%Q) GLOB '*7*'", zPerms
@@ -1503,11 +1532,11 @@
1532
1533 /* Verify user imputs */
1534 if( P("new")==0 || !cgi_csrf_safe(1) ){
1535 /* This is not a valid form submission. Fall through into
1536 ** the form display */
1537 }else if( (captchaIsCorrect = captcha_is_correct(1))==0 ){
1538 iErrLine = 6;
1539 zErr = "Incorrect CAPTCHA";
1540 }else if( strlen(zUserID)<6 ){
1541 iErrLine = 1;
1542 zErr = "User ID too short. Must be at least 6 characters.";
@@ -1521,10 +1550,13 @@
1550 iErrLine = 3;
1551 zErr = "Required";
1552 }else if( email_address_is_valid(zEAddr,0)==0 ){
1553 iErrLine = 3;
1554 zErr = "Not a valid email address";
1555 }else if( authorized_subscription_email(zEAddr)==0 ){
1556 iErrLine = 3;
1557 zErr = "Not an authorized email address";
1558 }else if( strlen(zPasswd)<6 ){
1559 iErrLine = 4;
1560 zErr = "Password must be at least 6 characters long";
1561 }else if( fossil_strcmp(zPasswd,zConfirm)!=0 ){
1562 iErrLine = 5;
@@ -1548,16 +1580,24 @@
1580 /* If all of the tests above have passed, that means that the submitted
1581 ** form contains valid data and we can proceed to create the new login */
1582 Blob sql;
1583 int uid;
1584 char *zPass = sha1_shared_secret(zPasswd, zUserID, 0);
1585 const char *zStartPerms = zPerms;
1586 if( db_get_boolean("selfreg-verify",0) ){
1587 /* If email verification is required for self-registration, initalize
1588 ** the new user capabilities to just "7" (Sign up for email). The
1589 ** full "default-perms" permissions will be added when they click
1590 ** the verification link on the email they are sent. */
1591 zStartPerms = "7";
1592 }
1593 blob_init(&sql, 0, 0);
1594 blob_append_sql(&sql,
1595 "INSERT INTO user(login,pw,cap,info,mtime)\n"
1596 "VALUES(%Q,%Q,%Q,"
1597 "'%q <%q>\nself-register from ip %q on '||datetime('now'),now())",
1598 zUserID, zPass, zStartPerms, zDName, zEAddr, g.zIpAddr);
1599 fossil_free(zPass);
1600 db_multi_exec("%s", blob_sql_text(&sql));
1601 uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUserID);
1602 login_set_user_cookie(zUserID, uid, NULL);
1603 if( doAlerts ){
@@ -1620,12 +1660,11 @@
1660 @ <blockquote><pre>
1661 @ %h(pSender->zErr)
1662 @ </pre></blockquote>
1663 }else{
1664 @ <p>An email has been sent to "%h(zEAddr)". That email contains a
1665 @ hyperlink that you must click to activate your account.</p>
 
1666 }
1667 alert_sender_free(pSender);
1668 if( zGoto ){
1669 @ <p><a href='%h(zGoto)'>Continue</a>
1670 }
@@ -1634,11 +1673,15 @@
1673 }
1674 redirect_to_g();
1675 }
1676
1677 /* Prepare the captcha. */
1678 if( captchaIsCorrect ){
1679 uSeed = strtoul(P("captchaseed"),0,10);
1680 }else{
1681 uSeed = captcha_seed();
1682 }
1683 zDecoded = captcha_decode(uSeed);
1684 zCaptcha = captcha_render(zDecoded);
1685
1686 style_header("Register");
1687 /* Print out the registration form. */
@@ -1693,11 +1736,12 @@
1736 if( iErrLine==5 ){
1737 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
1738 }
1739 @ <tr>
1740 @ <td class="form_label" align="right">Captcha:</td>
1741 @ <td><input type="text" name="captcha" size="30"\
1742 @ value="%h(captchaIsCorrect?zDecoded:"")" size="30">
1743 captcha_speakit_button(uSeed, "Speak the captcha text");
1744 @ </td>
1745 @ </tr>
1746 if( iErrLine==6 ){
1747 @ <tr><td><td><span class='loginError'>&uarr; %h(zErr)</span></td></tr>
1748
+8 -2
--- src/main.c
+++ src/main.c
@@ -2523,18 +2523,24 @@
25232523
**
25242524
** Works like the http command but gives setup permission to all users.
25252525
**
25262526
** Options:
25272527
** --th-trace trace TH1 execution (for debugging purposes)
2528
+** --usercap CAP user capability string. (Default: "sx")
25282529
**
25292530
*/
25302531
void cmd_test_http(void){
25312532
const char *zIpAddr; /* IP address of remote client */
2533
+ const char *zUserCap;
25322534
25332535
Th_InitTraceLog();
2534
- login_set_capabilities("sx", 0);
2535
- g.useLocalauth = 1;
2536
+ zUserCap = find_option("usercap",0,1);
2537
+ if( zUserCap==0 ){
2538
+ g.useLocalauth = 1;
2539
+ zUserCap = "sx";
2540
+ }
2541
+ login_set_capabilities(zUserCap, 0);
25362542
g.httpIn = stdin;
25372543
g.httpOut = stdout;
25382544
fossil_binary_mode(g.httpOut);
25392545
fossil_binary_mode(g.httpIn);
25402546
g.zExtRoot = find_option("extroot",0,1);
25412547
--- src/main.c
+++ src/main.c
@@ -2523,18 +2523,24 @@
2523 **
2524 ** Works like the http command but gives setup permission to all users.
2525 **
2526 ** Options:
2527 ** --th-trace trace TH1 execution (for debugging purposes)
 
2528 **
2529 */
2530 void cmd_test_http(void){
2531 const char *zIpAddr; /* IP address of remote client */
 
2532
2533 Th_InitTraceLog();
2534 login_set_capabilities("sx", 0);
2535 g.useLocalauth = 1;
 
 
 
 
2536 g.httpIn = stdin;
2537 g.httpOut = stdout;
2538 fossil_binary_mode(g.httpOut);
2539 fossil_binary_mode(g.httpIn);
2540 g.zExtRoot = find_option("extroot",0,1);
2541
--- src/main.c
+++ src/main.c
@@ -2523,18 +2523,24 @@
2523 **
2524 ** Works like the http command but gives setup permission to all users.
2525 **
2526 ** Options:
2527 ** --th-trace trace TH1 execution (for debugging purposes)
2528 ** --usercap CAP user capability string. (Default: "sx")
2529 **
2530 */
2531 void cmd_test_http(void){
2532 const char *zIpAddr; /* IP address of remote client */
2533 const char *zUserCap;
2534
2535 Th_InitTraceLog();
2536 zUserCap = find_option("usercap",0,1);
2537 if( zUserCap==0 ){
2538 g.useLocalauth = 1;
2539 zUserCap = "sx";
2540 }
2541 login_set_capabilities(zUserCap, 0);
2542 g.httpIn = stdin;
2543 g.httpOut = stdout;
2544 fossil_binary_mode(g.httpOut);
2545 fossil_binary_mode(g.httpIn);
2546 g.zExtRoot = find_option("extroot",0,1);
2547
--- src/security_audit.c
+++ src/security_audit.c
@@ -122,11 +122,11 @@
122122
zAnonCap = db_text("", "SELECT fullcap(NULL)");
123123
zDevCap = db_text("", "SELECT fullcap('v')");
124124
zReadCap = db_text("", "SELECT fullcap('u')");
125125
zPubPages = db_get("public-pages",0);
126126
hasSelfReg = db_get_boolean("self-register",0);
127
- pCap = capability_add(0, db_get("default-perms",0));
127
+ pCap = capability_add(0, db_get("default-perms","u"));
128128
capability_expand(pCap);
129129
zSelfCap = capability_string(pCap);
130130
capability_free(pCap);
131131
if( hasAnyCap(zAnonCap,"as") ){
132132
@ <li><p>This repository is <big><b>Wildly INSECURE</b></big> because
133133
--- src/security_audit.c
+++ src/security_audit.c
@@ -122,11 +122,11 @@
122 zAnonCap = db_text("", "SELECT fullcap(NULL)");
123 zDevCap = db_text("", "SELECT fullcap('v')");
124 zReadCap = db_text("", "SELECT fullcap('u')");
125 zPubPages = db_get("public-pages",0);
126 hasSelfReg = db_get_boolean("self-register",0);
127 pCap = capability_add(0, db_get("default-perms",0));
128 capability_expand(pCap);
129 zSelfCap = capability_string(pCap);
130 capability_free(pCap);
131 if( hasAnyCap(zAnonCap,"as") ){
132 @ <li><p>This repository is <big><b>Wildly INSECURE</b></big> because
133
--- src/security_audit.c
+++ src/security_audit.c
@@ -122,11 +122,11 @@
122 zAnonCap = db_text("", "SELECT fullcap(NULL)");
123 zDevCap = db_text("", "SELECT fullcap('v')");
124 zReadCap = db_text("", "SELECT fullcap('u')");
125 zPubPages = db_get("public-pages",0);
126 hasSelfReg = db_get_boolean("self-register",0);
127 pCap = capability_add(0, db_get("default-perms","u"));
128 capability_expand(pCap);
129 zSelfCap = capability_string(pCap);
130 capability_free(pCap);
131 if( hasAnyCap(zAnonCap,"as") ){
132 @ <li><p>This repository is <big><b>Wildly INSECURE</b></big> because
133
+34 -7
--- src/setup.c
+++ src/setup.c
@@ -500,17 +500,44 @@
500500
@ (Property: "public-pages")
501501
@ </p>
502502
503503
@ <hr />
504504
onoff_attribute("Allow users to register themselves",
505
- "self-register", "selfregister", 0, 0);
506
- @ <p>Allow users to register themselves through the HTTP UI.
507
- @ The registration form always requires filling in a CAPTCHA
508
- @ (<em>auto-captcha</em> setting is ignored). Still, bear in mind that anyone
509
- @ can register under any user name. This option is useful for public projects
510
- @ where you do not want everyone in any ticket discussion to be named
511
- @ "Anonymous". (Property: "self-register")</p>
505
+ "self-register", "selfreg", 0, 0);
506
+ @ <p>Allow users to register themselves on the /register webpage.
507
+ @ A self-registration creates a new entry in the USER table and
508
+ @ perhaps also in the SUBSCRIBER table if email notification is
509
+ @ enabled.
510
+ @ (Property: "self-register")</p>
511
+
512
+ @ <hr />
513
+ onoff_attribute("Email verification required for self-registration",
514
+ "selfreg-verify", "sfverify", 0, 0);
515
+ @ <p>If enabled, self-registration creates a new entry in the USER table
516
+ @ with only capabilities "7". The default user capabilities are not
517
+ @ added until the email address associated with the self-registration
518
+ @ has been verified. This setting only makes sense if
519
+ @ email notifications are enabled.
520
+ @ (Property: "selfreg-verify")</p>
521
+
522
+ @ <hr />
523
+ onoff_attribute("Allow anonymous subscriptions",
524
+ "anon-subscribe", "anonsub", 1, 0);
525
+ @ <p>If disabled, email notification subscriptions are only allowed
526
+ @ for users with a login. If Nobody or Anonymous visit the /subscribe
527
+ @ page, they are redirected to /register or /login.
528
+ @ (Property: "anon-subscribe")</p>
529
+
530
+ @ <hr />
531
+ entry_attribute("Authorized subscription email addresses", 35,
532
+ "auth-sub-email", "asemail", "", 0);
533
+ @ <p>This is a comma-separated list of GLOB patterns that specify
534
+ @ email addresses that are authorized to subscriptions. If blank
535
+ @ (the usual case), then any email address can be used to self-register.
536
+ @ This setting is used to limit subscriptions to members of a particular
537
+ @ organization or group based on their email address.
538
+ @ (Property: "auth-sub-email")</p>
512539
513540
@ <hr />
514541
entry_attribute("Default privileges", 10, "default-perms",
515542
"defaultperms", "u", 0);
516543
@ <p>Permissions given to users that... <ul><li>register themselves using
517544
--- src/setup.c
+++ src/setup.c
@@ -500,17 +500,44 @@
500 @ (Property: "public-pages")
501 @ </p>
502
503 @ <hr />
504 onoff_attribute("Allow users to register themselves",
505 "self-register", "selfregister", 0, 0);
506 @ <p>Allow users to register themselves through the HTTP UI.
507 @ The registration form always requires filling in a CAPTCHA
508 @ (<em>auto-captcha</em> setting is ignored). Still, bear in mind that anyone
509 @ can register under any user name. This option is useful for public projects
510 @ where you do not want everyone in any ticket discussion to be named
511 @ "Anonymous". (Property: "self-register")</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
512
513 @ <hr />
514 entry_attribute("Default privileges", 10, "default-perms",
515 "defaultperms", "u", 0);
516 @ <p>Permissions given to users that... <ul><li>register themselves using
517
--- src/setup.c
+++ src/setup.c
@@ -500,17 +500,44 @@
500 @ (Property: "public-pages")
501 @ </p>
502
503 @ <hr />
504 onoff_attribute("Allow users to register themselves",
505 "self-register", "selfreg", 0, 0);
506 @ <p>Allow users to register themselves on the /register webpage.
507 @ A self-registration creates a new entry in the USER table and
508 @ perhaps also in the SUBSCRIBER table if email notification is
509 @ enabled.
510 @ (Property: "self-register")</p>
511
512 @ <hr />
513 onoff_attribute("Email verification required for self-registration",
514 "selfreg-verify", "sfverify", 0, 0);
515 @ <p>If enabled, self-registration creates a new entry in the USER table
516 @ with only capabilities "7". The default user capabilities are not
517 @ added until the email address associated with the self-registration
518 @ has been verified. This setting only makes sense if
519 @ email notifications are enabled.
520 @ (Property: "selfreg-verify")</p>
521
522 @ <hr />
523 onoff_attribute("Allow anonymous subscriptions",
524 "anon-subscribe", "anonsub", 1, 0);
525 @ <p>If disabled, email notification subscriptions are only allowed
526 @ for users with a login. If Nobody or Anonymous visit the /subscribe
527 @ page, they are redirected to /register or /login.
528 @ (Property: "anon-subscribe")</p>
529
530 @ <hr />
531 entry_attribute("Authorized subscription email addresses", 35,
532 "auth-sub-email", "asemail", "", 0);
533 @ <p>This is a comma-separated list of GLOB patterns that specify
534 @ email addresses that are authorized to subscriptions. If blank
535 @ (the usual case), then any email address can be used to self-register.
536 @ This setting is used to limit subscriptions to members of a particular
537 @ organization or group based on their email address.
538 @ (Property: "auth-sub-email")</p>
539
540 @ <hr />
541 entry_attribute("Default privileges", 10, "default-perms",
542 "defaultperms", "u", 0);
543 @ <p>Permissions given to users that... <ul><li>register themselves using
544
+1 -1
--- src/setupuser.c
+++ src/setupuser.c
@@ -553,11 +553,11 @@
553553
if( alert_tables_exist() ){
554554
int sid;
555555
sid = db_int(0, "SELECT subscriberId FROM subscriber"
556556
" WHERE suname=%Q", zLogin);
557557
if( sid>0 ){
558
- @ &nbsp;&nbsp;<a href="%R/alerts?sid=%d(sid)>\
558
+ @ &nbsp;&nbsp;<a href="%R/alerts?sid=%d(sid)">\
559559
@ (subscription info for %h(zLogin))</a>\
560560
}
561561
}
562562
@ </td></tr>
563563
@ <tr>
564564
--- src/setupuser.c
+++ src/setupuser.c
@@ -553,11 +553,11 @@
553 if( alert_tables_exist() ){
554 int sid;
555 sid = db_int(0, "SELECT subscriberId FROM subscriber"
556 " WHERE suname=%Q", zLogin);
557 if( sid>0 ){
558 @ &nbsp;&nbsp;<a href="%R/alerts?sid=%d(sid)>\
559 @ (subscription info for %h(zLogin))</a>\
560 }
561 }
562 @ </td></tr>
563 @ <tr>
564
--- src/setupuser.c
+++ src/setupuser.c
@@ -553,11 +553,11 @@
553 if( alert_tables_exist() ){
554 int sid;
555 sid = db_int(0, "SELECT subscriberId FROM subscriber"
556 " WHERE suname=%Q", zLogin);
557 if( sid>0 ){
558 @ &nbsp;&nbsp;<a href="%R/alerts?sid=%d(sid)">\
559 @ (subscription info for %h(zLogin))</a>\
560 }
561 }
562 @ </td></tr>
563 @ <tr>
564
+1 -11
--- src/url.c
+++ src/url.c
@@ -66,20 +66,10 @@
6666
int proxyOrigPort; /* Tunneled port number for https through proxy */
6767
};
6868
#endif /* INTERFACE */
6969
7070
71
-/*
72
-** Convert a string to lower-case.
73
-*/
74
-static void url_tolower(char *z){
75
- while( *z ){
76
- *z = fossil_tolower(*z);
77
- z++;
78
- }
79
-}
80
-
8171
/*
8272
** Parse the given URL. Populate members of the provided UrlData structure
8373
** as follows:
8474
**
8575
** isFile True if FILE:
@@ -177,11 +167,11 @@
177167
pUrlData->name++;
178168
pUrlData->name[n-2] = 0;
179169
}
180170
zLogin = mprintf("");
181171
}
182
- url_tolower(pUrlData->name);
172
+ fossil_strtolwr(pUrlData->name);
183173
if( c==':' ){
184174
pUrlData->port = 0;
185175
i++;
186176
while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
187177
pUrlData->port = pUrlData->port*10 + c - '0';
188178
--- src/url.c
+++ src/url.c
@@ -66,20 +66,10 @@
66 int proxyOrigPort; /* Tunneled port number for https through proxy */
67 };
68 #endif /* INTERFACE */
69
70
71 /*
72 ** Convert a string to lower-case.
73 */
74 static void url_tolower(char *z){
75 while( *z ){
76 *z = fossil_tolower(*z);
77 z++;
78 }
79 }
80
81 /*
82 ** Parse the given URL. Populate members of the provided UrlData structure
83 ** as follows:
84 **
85 ** isFile True if FILE:
@@ -177,11 +167,11 @@
177 pUrlData->name++;
178 pUrlData->name[n-2] = 0;
179 }
180 zLogin = mprintf("");
181 }
182 url_tolower(pUrlData->name);
183 if( c==':' ){
184 pUrlData->port = 0;
185 i++;
186 while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
187 pUrlData->port = pUrlData->port*10 + c - '0';
188
--- src/url.c
+++ src/url.c
@@ -66,20 +66,10 @@
66 int proxyOrigPort; /* Tunneled port number for https through proxy */
67 };
68 #endif /* INTERFACE */
69
70
 
 
 
 
 
 
 
 
 
 
71 /*
72 ** Parse the given URL. Populate members of the provided UrlData structure
73 ** as follows:
74 **
75 ** isFile True if FILE:
@@ -177,11 +167,11 @@
167 pUrlData->name++;
168 pUrlData->name[n-2] = 0;
169 }
170 zLogin = mprintf("");
171 }
172 fossil_strtolwr(pUrlData->name);
173 if( c==':' ){
174 pUrlData->port = 0;
175 i++;
176 while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
177 pUrlData->port = pUrlData->port*10 + c - '0';
178
+15
--- src/util.c
+++ src/util.c
@@ -140,10 +140,25 @@
140140
}
141141
#else
142142
fossil_free(p);
143143
#endif
144144
}
145
+
146
+/*
147
+** Translate every upper-case character in the input string into
148
+** its equivalent lower-case.
149
+*/
150
+char *fossil_strtolwr(char *zIn){
151
+ char *zStart = zIn;
152
+ if( zIn ){
153
+ while( *zIn ){
154
+ *zIn = fossil_tolower(*zIn);
155
+ zIn++;
156
+ }
157
+ }
158
+ return zStart;
159
+}
145160
146161
/*
147162
** This function implements a cross-platform "system()" interface.
148163
*/
149164
int fossil_system(const char *zOrigCmd){
150165
--- src/util.c
+++ src/util.c
@@ -140,10 +140,25 @@
140 }
141 #else
142 fossil_free(p);
143 #endif
144 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
146 /*
147 ** This function implements a cross-platform "system()" interface.
148 */
149 int fossil_system(const char *zOrigCmd){
150
--- src/util.c
+++ src/util.c
@@ -140,10 +140,25 @@
140 }
141 #else
142 fossil_free(p);
143 #endif
144 }
145
146 /*
147 ** Translate every upper-case character in the input string into
148 ** its equivalent lower-case.
149 */
150 char *fossil_strtolwr(char *zIn){
151 char *zStart = zIn;
152 if( zIn ){
153 while( *zIn ){
154 *zIn = fossil_tolower(*zIn);
155 zIn++;
156 }
157 }
158 return zStart;
159 }
160
161 /*
162 ** This function implements a cross-platform "system()" interface.
163 */
164 int fossil_system(const char *zOrigCmd){
165

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button