Fossil SCM

Fix bugs in the /subscribe page that could allow an attacker to subscribe and verify without actually having a working email address.

drh 2020-04-23 22:17 trunk
Commit 15e15298f8eebef8f97ef9b3ce88a70e5ba92668d13dc1c6d6db382690c764b2
3 files changed +88 -46 +8 -4 +5 -6
+88 -46
--- src/alerts.c
+++ src/alerts.c
@@ -1389,11 +1389,15 @@
13891389
id);
13901390
if( !needCaptcha ){
13911391
/* The new subscription has been added on behalf of a logged-in user.
13921392
** No verification is required. Jump immediately to /alerts page.
13931393
*/
1394
- cgi_redirectf("%R/alerts/%s", zCode);
1394
+ if( g.perm.Admin ){
1395
+ cgi_redirectf("%R/alerts/%.32s", zCode);
1396
+ }else{
1397
+ cgi_redirectf("%R/alerts");
1398
+ }
13951399
return;
13961400
}else{
13971401
/* We need to send a verification email */
13981402
Blob hdr, body;
13991403
AlertSender *pSender = alert_sender_new(0,0);
@@ -1534,21 +1538,20 @@
15341538
/*
15351539
** Either shutdown or completely delete a subscription entry given
15361540
** by the hex value zName. Then paint a webpage that explains that
15371541
** the entry has been removed.
15381542
*/
1539
-static void alert_unsubscribe(const char *zName){
1543
+static void alert_unsubscribe(int sid){
15401544
char *zEmail;
15411545
zEmail = db_text(0, "SELECT semail FROM subscriber"
1542
- " WHERE subscriberCode=hextoblob(%Q)", zName);
1546
+ " WHERE subscriberId=%d", sid);
15431547
if( zEmail==0 ){
15441548
style_header("Unsubscribe Fail");
15451549
@ <p>Unable to locate a subscriber with the requested key</p>
15461550
}else{
15471551
db_multi_exec(
1548
- "DELETE FROM subscriber WHERE subscriberCode=hextoblob(%Q)",
1549
- zName
1552
+ "DELETE FROM subscriber WHERE subscriberId=%d", sid
15501553
);
15511554
style_header("Unsubscribed");
15521555
@ <p>The "%h(zEmail)" email address has been delisted.
15531556
@ All traces of that email address have been removed</p>
15541557
}
@@ -1559,46 +1562,75 @@
15591562
/*
15601563
** WEBPAGE: alerts
15611564
**
15621565
** Edit email alert and notification settings.
15631566
**
1564
-** The subscriber is identified in either of two ways:
1567
+** The subscriber is identified in several ways:
1568
+**
1569
+** (1) The name= query parameter contains the complete subscriberCode.
1570
+** This only happens when the user receives a verification
1571
+** email and clicks on the link in the email. When a
1572
+** compilete subscriberCode is seen on the name= query parameter,
1573
+** that constitutes verification of the email address.
15651574
**
1566
-** (1) The name= query parameter contains the subscriberCode.
1575
+** (2) The sid= query parameter contains an integer subscriberId.
1576
+** This only works for the administrator. It allows the
1577
+** administrator to edit any subscription.
15671578
**
1568
-** (2) The user is logged into an account other than "nobody" or
1579
+** (3) The user is logged into an account other than "nobody" or
15691580
** "anonymous". In that case the notification settings
15701581
** associated with that account can be edited without needing
15711582
** to know the subscriber code.
1583
+**
1584
+** (4) The name= query parameter contains a 32-digit prefix of
1585
+** subscriber code. (Subscriber codes are normally 64 hex digits
1586
+** in length.) This uniquely identifies the subscriber without
1587
+** revealing the complete subscriber code, and hence without
1588
+** verifying the email address.
15721589
*/
15731590
void alert_page(void){
1574
- const char *zName = P("name");
1575
- Stmt q;
1576
- int sa, sc, sf, st, sw, sx;
1577
- int sdigest = 0, sdonotcall = 0, sverified = 0;
1578
- int isLogin; /* Logged in as an individual */
1579
- const char *ssub = 0;
1580
- const char *semail = 0;
1581
- const char *smip;
1582
- const char *suname = 0;
1583
- const char *mtime;
1584
- const char *sctime;
1585
- int eErr = 0;
1586
- char *zErr = 0;
1591
+ const char *zName = 0; /* Value of the name= query parameter */
1592
+ Stmt q; /* For querying the database */
1593
+ int sa, sc, sf, st, sw, sx; /* Types of notifications requested */
1594
+ int sdigest = 0, sdonotcall = 0, sverified = 0; /* Other fields */
1595
+ int isLogin; /* True if logged in as an individual */
1596
+ const char *ssub = 0; /* Subscription flags */
1597
+ const char *semail = 0; /* Email address */
1598
+ const char *smip; /* */
1599
+ const char *suname = 0; /* Corresponding user.login value */
1600
+ const char *mtime; /* */
1601
+ const char *sctime; /* Time subscription created */
1602
+ int eErr = 0; /* Type of error */
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 */
15871607
15881608
if( alert_webpages_disabled() ) return;
15891609
login_check_credentials();
15901610
if( !g.perm.EmailAlert ){
15911611
login_needed(g.anon.EmailAlert);
15921612
return;
15931613
}
15941614
isLogin = login_is_individual();
1595
- if( zName==0 && isLogin ){
1596
- zName = db_text(0, "SELECT hex(subscriberCode) FROM subscriber"
1597
- " WHERE suname=%Q", g.zLogin);
1615
+ zName = P("name");
1616
+ nName = zName ? (int)strlen(zName) : 0;
1617
+ if( g.perm.Admin && P("sid")!=0 ){
1618
+ sid = atoi(P("sid"));
1619
+ }
1620
+ if( sid==0 && nName>=32 ){
1621
+ sid = db_int(0,
1622
+ "SELECT CASE WHEN hex(subscriberCode) LIKE (%Q||'%%')"
1623
+ " THEN subscriberId ELSE 0 END"
1624
+ " FROM subscriber WHERE subscriberCode>=hextoblob(%Q)"
1625
+ " LIMIT 1", zName, zName);
1626
+ }
1627
+ if( sid==0 && isLogin ){
1628
+ sid = db_int(0, "SELECT subscriberId FROM subscriber"
1629
+ " WHERE suname=%Q", g.zLogin);
15981630
}
1599
- if( zName==0 || !validate16(zName, -1) ){
1631
+ if( sid==0 ){
16001632
cgi_redirect("subscribe");
16011633
return;
16021634
}
16031635
alert_submenu_common();
16041636
if( P("submit")!=0 && cgi_csrf_safe(1) ){
@@ -1644,11 +1676,11 @@
16441676
if( semail==0 || email_address_is_valid(semail,0)==0 ){
16451677
eErr = 8;
16461678
}
16471679
blob_append_sql(&update, ", semail=%Q", semail);
16481680
}
1649
- blob_append_sql(&update," WHERE subscriberCode=hextoblob(%Q)", zName);
1681
+ blob_append_sql(&update," WHERE subscriberId=%d", sid);
16501682
if( eErr==0 ){
16511683
db_exec_sql(blob_str(&update));
16521684
ssub = 0;
16531685
}
16541686
blob_reset(&update);
@@ -1657,11 +1689,11 @@
16571689
if( !PB("dodelete") ){
16581690
eErr = 9;
16591691
zErr = mprintf("Select this checkbox and press \"Unsubscribe\" again to"
16601692
" unsubscribe");
16611693
}else{
1662
- alert_unsubscribe(zName);
1694
+ alert_unsubscribe(sid);
16631695
return;
16641696
}
16651697
}
16661698
style_header("Update Subscription");
16671699
db_prepare(&q,
@@ -1672,12 +1704,13 @@
16721704
" sdigest," /* 3 */
16731705
" ssub," /* 4 */
16741706
" smip," /* 5 */
16751707
" suname," /* 6 */
16761708
" datetime(mtime,'unixepoch')," /* 7 */
1677
- " datetime(sctime,'unixepoch')" /* 8 */
1678
- " FROM subscriber WHERE subscriberCode=hextoblob(%Q)", zName);
1709
+ " datetime(sctime,'unixepoch')," /* 8 */
1710
+ " hex(subscriberCode)" /* 9 */
1711
+ " FROM subscriber WHERE subscriberId=%d", sid);
16791712
if( db_step(&q)!=SQLITE_ROW ){
16801713
db_finalize(&q);
16811714
cgi_redirect("subscribe");
16821715
return;
16831716
}
@@ -1699,23 +1732,32 @@
16991732
sx = strchr(ssub,'x')!=0;
17001733
smip = db_column_text(&q, 5);
17011734
mtime = db_column_text(&q, 7);
17021735
sctime = db_column_text(&q, 8);
17031736
if( !g.perm.Admin && !sverified ){
1704
- db_multi_exec(
1705
- "UPDATE subscriber SET sverified=1 WHERE subscriberCode=hextoblob(%Q)",
1706
- zName);
1707
- @ <h1>Your email alert subscription has been verified!</h1>
1708
- @ <p>Use the form below to update your subscription information.</p>
1709
- @ <p>Hint: Bookmark this page so that you can more easily update
1710
- @ your subscription information in the future</p>
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{
1746
+ @ <h2>Your email address is unverified</h2>
1747
+ @ <p>You should have received an email message containing a link
1748
+ @ that you must visit to verify your account. No email notifications
1749
+ @ will be sent until your email address has been verified.</p>
1750
+ }
17111751
}else{
17121752
@ <p>Make changes to the email subscription shown below and
17131753
@ press "Submit".</p>
17141754
}
17151755
form_begin(0, "%R/alerts");
1716
- @ <input type="hidden" name="name" value="%h(zName)">
1756
+ zHalfCode = db_text("x","SELECT hex(substr(subscriberCode,1,16))"
1757
+ " FROM subscriber WHERE subscriberId=%d", sid);
1758
+ @ <input type="hidden" name="name" value="%h(zHalfCode)">
17171759
@ <table class="subscribe">
17181760
@ <tr>
17191761
@ <td class="form_label">Email&nbsp;Address:</td>
17201762
if( isLogin ){
17211763
@ <td><input type="text" name="semail" value="%h(semail)" size="30">\
@@ -1742,10 +1784,13 @@
17421784
@ </tr>
17431785
@ <tr>
17441786
@ <td class='form_label'>IP Address:</td>
17451787
@ <td>%h(smip)</td>
17461788
@ </tr>
1789
+ @ <tr>
1790
+ @ <td class='form_label'>Subscriber&nbsp;Code:</td>
1791
+ @ <td>%h(db_column_text(&q,9))</td>
17471792
@ <tr>
17481793
@ <td class="form_label">User:</td>
17491794
@ <td><input type="text" name="suname" value="%h(suname?suname:"")" \
17501795
@ size="30">\
17511796
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", suname);
@@ -1783,14 +1828,10 @@
17831828
@ <td><select size="1" name="sdigest">
17841829
@ <option value="0" %s(sdigest?"":"selected")>Individual Emails</option>
17851830
@ <option value="1" %s(sdigest?"selected":"")>Daily Digest</option>
17861831
@ </select></td>
17871832
@ </tr>
1788
-#if 0
1789
- @ <label><input type="checkbox" name="sdigest" %s(sdigest?"checked":"")>\
1790
- @ Daily digest only</label><br>
1791
-#endif
17921833
if( g.perm.Admin ){
17931834
@ <tr>
17941835
@ <td class="form_label">Admin Options:</td><td>
17951836
@ <label><input type="checkbox" name="sdonotcall" \
17961837
@ %s(sdonotcall?"checked":"")> Do not disturb</label><br>
@@ -1855,18 +1896,19 @@
18551896
char *zCaptcha = 0;
18561897
int dx;
18571898
int bSubmit;
18581899
const char *zEAddr;
18591900
char *zCode = 0;
1901
+ int sid = 0;
18601902
18611903
/* If a valid subscriber code is supplied, then unsubscribe immediately.
18621904
*/
18631905
if( zName
1864
- && db_exists("SELECT 1 FROM subscriber WHERE subscriberCode=hextoblob(%Q)",
1865
- zName)
1906
+ && (sid = db_int(0, "SELECT subscriberId FROM subscriber"
1907
+ " WHERE subscriberCode=hextoblob(%Q)", zName))!=0
18661908
){
1867
- alert_unsubscribe(zName);
1909
+ alert_unsubscribe(sid);
18681910
return;
18691911
}
18701912
18711913
/* Logged in users are redirected to the /alerts page */
18721914
login_check_credentials();
@@ -2024,11 +2066,11 @@
20242066
if( nDel>0 ){
20252067
@ <p>*** %d(nDel) pending subscriptions deleted ***</p>
20262068
}
20272069
blob_init(&sql, 0, 0);
20282070
blob_append_sql(&sql,
2029
- "SELECT hex(subscriberCode)," /* 0 */
2071
+ "SELECT subscriberId," /* 0 */
20302072
" semail," /* 1 */
20312073
" ssub," /* 2 */
20322074
" suname," /* 3 */
20332075
" sverified," /* 4 */
20342076
" sdigest," /* 5 */
@@ -2061,11 +2103,11 @@
20612103
sqlite3_int64 iMtime = db_column_int64(&q, 6);
20622104
double rAge = (iNow - iMtime)/86400.0;
20632105
int uid = db_column_int(&q, 8);
20642106
const char *zUname = db_column_text(&q, 3);
20652107
@ <tr>
2066
- @ <td><a href='%R/alerts/%s(db_column_text(&q,0))'>\
2108
+ @ <td><a href='%R/alerts?sid=%d(db_column_int(&q,0))'>\
20672109
@ %h(db_column_text(&q,1))</a></td>
20682110
@ <td>%h(db_column_text(&q,2))</td>
20692111
@ <td>%s(db_column_int(&q,5)?"digest":"")</td>
20702112
if( uid ){
20712113
@ <td><a href='%R/setup_uedit?id=%d(uid)'>%h(zUname)</a>
20722114
--- src/alerts.c
+++ src/alerts.c
@@ -1389,11 +1389,15 @@
1389 id);
1390 if( !needCaptcha ){
1391 /* The new subscription has been added on behalf of a logged-in user.
1392 ** No verification is required. Jump immediately to /alerts page.
1393 */
1394 cgi_redirectf("%R/alerts/%s", zCode);
 
 
 
 
1395 return;
1396 }else{
1397 /* We need to send a verification email */
1398 Blob hdr, body;
1399 AlertSender *pSender = alert_sender_new(0,0);
@@ -1534,21 +1538,20 @@
1534 /*
1535 ** Either shutdown or completely delete a subscription entry given
1536 ** by the hex value zName. Then paint a webpage that explains that
1537 ** the entry has been removed.
1538 */
1539 static void alert_unsubscribe(const char *zName){
1540 char *zEmail;
1541 zEmail = db_text(0, "SELECT semail FROM subscriber"
1542 " WHERE subscriberCode=hextoblob(%Q)", zName);
1543 if( zEmail==0 ){
1544 style_header("Unsubscribe Fail");
1545 @ <p>Unable to locate a subscriber with the requested key</p>
1546 }else{
1547 db_multi_exec(
1548 "DELETE FROM subscriber WHERE subscriberCode=hextoblob(%Q)",
1549 zName
1550 );
1551 style_header("Unsubscribed");
1552 @ <p>The "%h(zEmail)" email address has been delisted.
1553 @ All traces of that email address have been removed</p>
1554 }
@@ -1559,46 +1562,75 @@
1559 /*
1560 ** WEBPAGE: alerts
1561 **
1562 ** Edit email alert and notification settings.
1563 **
1564 ** The subscriber is identified in either of two ways:
 
 
 
 
 
 
1565 **
1566 ** (1) The name= query parameter contains the subscriberCode.
 
 
1567 **
1568 ** (2) The user is logged into an account other than "nobody" or
1569 ** "anonymous". In that case the notification settings
1570 ** associated with that account can be edited without needing
1571 ** to know the subscriber code.
 
 
 
 
 
 
1572 */
1573 void alert_page(void){
1574 const char *zName = P("name");
1575 Stmt q;
1576 int sa, sc, sf, st, sw, sx;
1577 int sdigest = 0, sdonotcall = 0, sverified = 0;
1578 int isLogin; /* Logged in as an individual */
1579 const char *ssub = 0;
1580 const char *semail = 0;
1581 const char *smip;
1582 const char *suname = 0;
1583 const char *mtime;
1584 const char *sctime;
1585 int eErr = 0;
1586 char *zErr = 0;
 
 
 
1587
1588 if( alert_webpages_disabled() ) return;
1589 login_check_credentials();
1590 if( !g.perm.EmailAlert ){
1591 login_needed(g.anon.EmailAlert);
1592 return;
1593 }
1594 isLogin = login_is_individual();
1595 if( zName==0 && isLogin ){
1596 zName = db_text(0, "SELECT hex(subscriberCode) FROM subscriber"
1597 " WHERE suname=%Q", g.zLogin);
 
 
 
 
 
 
 
 
 
 
 
 
1598 }
1599 if( zName==0 || !validate16(zName, -1) ){
1600 cgi_redirect("subscribe");
1601 return;
1602 }
1603 alert_submenu_common();
1604 if( P("submit")!=0 && cgi_csrf_safe(1) ){
@@ -1644,11 +1676,11 @@
1644 if( semail==0 || email_address_is_valid(semail,0)==0 ){
1645 eErr = 8;
1646 }
1647 blob_append_sql(&update, ", semail=%Q", semail);
1648 }
1649 blob_append_sql(&update," WHERE subscriberCode=hextoblob(%Q)", zName);
1650 if( eErr==0 ){
1651 db_exec_sql(blob_str(&update));
1652 ssub = 0;
1653 }
1654 blob_reset(&update);
@@ -1657,11 +1689,11 @@
1657 if( !PB("dodelete") ){
1658 eErr = 9;
1659 zErr = mprintf("Select this checkbox and press \"Unsubscribe\" again to"
1660 " unsubscribe");
1661 }else{
1662 alert_unsubscribe(zName);
1663 return;
1664 }
1665 }
1666 style_header("Update Subscription");
1667 db_prepare(&q,
@@ -1672,12 +1704,13 @@
1672 " sdigest," /* 3 */
1673 " ssub," /* 4 */
1674 " smip," /* 5 */
1675 " suname," /* 6 */
1676 " datetime(mtime,'unixepoch')," /* 7 */
1677 " datetime(sctime,'unixepoch')" /* 8 */
1678 " FROM subscriber WHERE subscriberCode=hextoblob(%Q)", zName);
 
1679 if( db_step(&q)!=SQLITE_ROW ){
1680 db_finalize(&q);
1681 cgi_redirect("subscribe");
1682 return;
1683 }
@@ -1699,23 +1732,32 @@
1699 sx = strchr(ssub,'x')!=0;
1700 smip = db_column_text(&q, 5);
1701 mtime = db_column_text(&q, 7);
1702 sctime = db_column_text(&q, 8);
1703 if( !g.perm.Admin && !sverified ){
1704 db_multi_exec(
1705 "UPDATE subscriber SET sverified=1 WHERE subscriberCode=hextoblob(%Q)",
1706 zName);
1707 @ <h1>Your email alert subscription has been verified!</h1>
1708 @ <p>Use the form below to update your subscription information.</p>
1709 @ <p>Hint: Bookmark this page so that you can more easily update
1710 @ your subscription information in the future</p>
 
 
 
 
 
 
 
1711 }else{
1712 @ <p>Make changes to the email subscription shown below and
1713 @ press "Submit".</p>
1714 }
1715 form_begin(0, "%R/alerts");
1716 @ <input type="hidden" name="name" value="%h(zName)">
 
 
1717 @ <table class="subscribe">
1718 @ <tr>
1719 @ <td class="form_label">Email&nbsp;Address:</td>
1720 if( isLogin ){
1721 @ <td><input type="text" name="semail" value="%h(semail)" size="30">\
@@ -1742,10 +1784,13 @@
1742 @ </tr>
1743 @ <tr>
1744 @ <td class='form_label'>IP Address:</td>
1745 @ <td>%h(smip)</td>
1746 @ </tr>
 
 
 
1747 @ <tr>
1748 @ <td class="form_label">User:</td>
1749 @ <td><input type="text" name="suname" value="%h(suname?suname:"")" \
1750 @ size="30">\
1751 uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", suname);
@@ -1783,14 +1828,10 @@
1783 @ <td><select size="1" name="sdigest">
1784 @ <option value="0" %s(sdigest?"":"selected")>Individual Emails</option>
1785 @ <option value="1" %s(sdigest?"selected":"")>Daily Digest</option>
1786 @ </select></td>
1787 @ </tr>
1788 #if 0
1789 @ <label><input type="checkbox" name="sdigest" %s(sdigest?"checked":"")>\
1790 @ Daily digest only</label><br>
1791 #endif
1792 if( g.perm.Admin ){
1793 @ <tr>
1794 @ <td class="form_label">Admin Options:</td><td>
1795 @ <label><input type="checkbox" name="sdonotcall" \
1796 @ %s(sdonotcall?"checked":"")> Do not disturb</label><br>
@@ -1855,18 +1896,19 @@
1855 char *zCaptcha = 0;
1856 int dx;
1857 int bSubmit;
1858 const char *zEAddr;
1859 char *zCode = 0;
 
1860
1861 /* If a valid subscriber code is supplied, then unsubscribe immediately.
1862 */
1863 if( zName
1864 && db_exists("SELECT 1 FROM subscriber WHERE subscriberCode=hextoblob(%Q)",
1865 zName)
1866 ){
1867 alert_unsubscribe(zName);
1868 return;
1869 }
1870
1871 /* Logged in users are redirected to the /alerts page */
1872 login_check_credentials();
@@ -2024,11 +2066,11 @@
2024 if( nDel>0 ){
2025 @ <p>*** %d(nDel) pending subscriptions deleted ***</p>
2026 }
2027 blob_init(&sql, 0, 0);
2028 blob_append_sql(&sql,
2029 "SELECT hex(subscriberCode)," /* 0 */
2030 " semail," /* 1 */
2031 " ssub," /* 2 */
2032 " suname," /* 3 */
2033 " sverified," /* 4 */
2034 " sdigest," /* 5 */
@@ -2061,11 +2103,11 @@
2061 sqlite3_int64 iMtime = db_column_int64(&q, 6);
2062 double rAge = (iNow - iMtime)/86400.0;
2063 int uid = db_column_int(&q, 8);
2064 const char *zUname = db_column_text(&q, 3);
2065 @ <tr>
2066 @ <td><a href='%R/alerts/%s(db_column_text(&q,0))'>\
2067 @ %h(db_column_text(&q,1))</a></td>
2068 @ <td>%h(db_column_text(&q,2))</td>
2069 @ <td>%s(db_column_int(&q,5)?"digest":"")</td>
2070 if( uid ){
2071 @ <td><a href='%R/setup_uedit?id=%d(uid)'>%h(zUname)</a>
2072
--- src/alerts.c
+++ src/alerts.c
@@ -1389,11 +1389,15 @@
1389 id);
1390 if( !needCaptcha ){
1391 /* The new subscription has been added on behalf of a logged-in user.
1392 ** No verification is required. Jump immediately to /alerts page.
1393 */
1394 if( g.perm.Admin ){
1395 cgi_redirectf("%R/alerts/%.32s", zCode);
1396 }else{
1397 cgi_redirectf("%R/alerts");
1398 }
1399 return;
1400 }else{
1401 /* We need to send a verification email */
1402 Blob hdr, body;
1403 AlertSender *pSender = alert_sender_new(0,0);
@@ -1534,21 +1538,20 @@
1538 /*
1539 ** Either shutdown or completely delete a subscription entry given
1540 ** by the hex value zName. Then paint a webpage that explains that
1541 ** the entry has been removed.
1542 */
1543 static void alert_unsubscribe(int sid){
1544 char *zEmail;
1545 zEmail = db_text(0, "SELECT semail FROM subscriber"
1546 " WHERE subscriberId=%d", sid);
1547 if( zEmail==0 ){
1548 style_header("Unsubscribe Fail");
1549 @ <p>Unable to locate a subscriber with the requested key</p>
1550 }else{
1551 db_multi_exec(
1552 "DELETE FROM subscriber WHERE subscriberId=%d", sid
 
1553 );
1554 style_header("Unsubscribed");
1555 @ <p>The "%h(zEmail)" email address has been delisted.
1556 @ All traces of that email address have been removed</p>
1557 }
@@ -1559,46 +1562,75 @@
1562 /*
1563 ** WEBPAGE: alerts
1564 **
1565 ** Edit email alert and notification settings.
1566 **
1567 ** The subscriber is identified in several ways:
1568 **
1569 ** (1) The name= query parameter contains the complete subscriberCode.
1570 ** This only happens when the user receives a verification
1571 ** email and clicks on the link in the email. When a
1572 ** compilete subscriberCode is seen on the name= query parameter,
1573 ** that constitutes verification of the email address.
1574 **
1575 ** (2) The sid= query parameter contains an integer subscriberId.
1576 ** This only works for the administrator. It allows the
1577 ** administrator to edit any subscription.
1578 **
1579 ** (3) The user is logged into an account other than "nobody" or
1580 ** "anonymous". In that case the notification settings
1581 ** associated with that account can be edited without needing
1582 ** to know the subscriber code.
1583 **
1584 ** (4) The name= query parameter contains a 32-digit prefix of
1585 ** subscriber code. (Subscriber codes are normally 64 hex digits
1586 ** in length.) This uniquely identifies the subscriber without
1587 ** revealing the complete subscriber code, and hence without
1588 ** verifying the email address.
1589 */
1590 void alert_page(void){
1591 const char *zName = 0; /* Value of the name= query parameter */
1592 Stmt q; /* For querying the database */
1593 int sa, sc, sf, st, sw, sx; /* Types of notifications requested */
1594 int sdigest = 0, sdonotcall = 0, sverified = 0; /* Other fields */
1595 int isLogin; /* True if logged in as an individual */
1596 const char *ssub = 0; /* Subscription flags */
1597 const char *semail = 0; /* Email address */
1598 const char *smip; /* */
1599 const char *suname = 0; /* Corresponding user.login value */
1600 const char *mtime; /* */
1601 const char *sctime; /* Time subscription created */
1602 int eErr = 0; /* Type of error */
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 ){
1618 sid = atoi(P("sid"));
1619 }
1620 if( sid==0 && nName>=32 ){
1621 sid = db_int(0,
1622 "SELECT CASE WHEN hex(subscriberCode) LIKE (%Q||'%%')"
1623 " THEN subscriberId ELSE 0 END"
1624 " FROM subscriber WHERE subscriberCode>=hextoblob(%Q)"
1625 " LIMIT 1", zName, zName);
1626 }
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) ){
@@ -1644,11 +1676,11 @@
1676 if( semail==0 || email_address_is_valid(semail,0)==0 ){
1677 eErr = 8;
1678 }
1679 blob_append_sql(&update, ", semail=%Q", semail);
1680 }
1681 blob_append_sql(&update," WHERE subscriberId=%d", sid);
1682 if( eErr==0 ){
1683 db_exec_sql(blob_str(&update));
1684 ssub = 0;
1685 }
1686 blob_reset(&update);
@@ -1657,11 +1689,11 @@
1689 if( !PB("dodelete") ){
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,
@@ -1672,12 +1704,13 @@
1704 " sdigest," /* 3 */
1705 " ssub," /* 4 */
1706 " smip," /* 5 */
1707 " suname," /* 6 */
1708 " datetime(mtime,'unixepoch')," /* 7 */
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 }
@@ -1699,23 +1732,32 @@
1732 sx = strchr(ssub,'x')!=0;
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{
1746 @ <h2>Your email address is unverified</h2>
1747 @ <p>You should have received an email message containing a link
1748 @ that you must visit to verify your account. No email notifications
1749 @ will be sent until your email address has been verified.</p>
1750 }
1751 }else{
1752 @ <p>Make changes to the email subscription shown below and
1753 @ press "Submit".</p>
1754 }
1755 form_begin(0, "%R/alerts");
1756 zHalfCode = db_text("x","SELECT hex(substr(subscriberCode,1,16))"
1757 " FROM subscriber WHERE subscriberId=%d", sid);
1758 @ <input type="hidden" name="name" value="%h(zHalfCode)">
1759 @ <table class="subscribe">
1760 @ <tr>
1761 @ <td class="form_label">Email&nbsp;Address:</td>
1762 if( isLogin ){
1763 @ <td><input type="text" name="semail" value="%h(semail)" size="30">\
@@ -1742,10 +1784,13 @@
1784 @ </tr>
1785 @ <tr>
1786 @ <td class='form_label'>IP Address:</td>
1787 @ <td>%h(smip)</td>
1788 @ </tr>
1789 @ <tr>
1790 @ <td class='form_label'>Subscriber&nbsp;Code:</td>
1791 @ <td>%h(db_column_text(&q,9))</td>
1792 @ <tr>
1793 @ <td class="form_label">User:</td>
1794 @ <td><input type="text" name="suname" value="%h(suname?suname:"")" \
1795 @ size="30">\
1796 uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", suname);
@@ -1783,14 +1828,10 @@
1828 @ <td><select size="1" name="sdigest">
1829 @ <option value="0" %s(sdigest?"":"selected")>Individual Emails</option>
1830 @ <option value="1" %s(sdigest?"selected":"")>Daily Digest</option>
1831 @ </select></td>
1832 @ </tr>
 
 
 
 
1833 if( g.perm.Admin ){
1834 @ <tr>
1835 @ <td class="form_label">Admin Options:</td><td>
1836 @ <label><input type="checkbox" name="sdonotcall" \
1837 @ %s(sdonotcall?"checked":"")> Do not disturb</label><br>
@@ -1855,18 +1896,19 @@
1896 char *zCaptcha = 0;
1897 int dx;
1898 int bSubmit;
1899 const char *zEAddr;
1900 char *zCode = 0;
1901 int sid = 0;
1902
1903 /* If a valid subscriber code is supplied, then unsubscribe immediately.
1904 */
1905 if( zName
1906 && (sid = db_int(0, "SELECT subscriberId FROM subscriber"
1907 " WHERE subscriberCode=hextoblob(%Q)", zName))!=0
1908 ){
1909 alert_unsubscribe(sid);
1910 return;
1911 }
1912
1913 /* Logged in users are redirected to the /alerts page */
1914 login_check_credentials();
@@ -2024,11 +2066,11 @@
2066 if( nDel>0 ){
2067 @ <p>*** %d(nDel) pending subscriptions deleted ***</p>
2068 }
2069 blob_init(&sql, 0, 0);
2070 blob_append_sql(&sql,
2071 "SELECT subscriberId," /* 0 */
2072 " semail," /* 1 */
2073 " ssub," /* 2 */
2074 " suname," /* 3 */
2075 " sverified," /* 4 */
2076 " sdigest," /* 5 */
@@ -2061,11 +2103,11 @@
2103 sqlite3_int64 iMtime = db_column_int64(&q, 6);
2104 double rAge = (iNow - iMtime)/86400.0;
2105 int uid = db_column_int(&q, 8);
2106 const char *zUname = db_column_text(&q, 3);
2107 @ <tr>
2108 @ <td><a href='%R/alerts?sid=%d(db_column_int(&q,0))'>\
2109 @ %h(db_column_text(&q,1))</a></td>
2110 @ <td>%h(db_column_text(&q,2))</td>
2111 @ <td>%s(db_column_int(&q,5)?"digest":"")</td>
2112 if( uid ){
2113 @ <td><a href='%R/setup_uedit?id=%d(uid)'>%h(zUname)</a>
2114
+8 -4
--- src/login.c
+++ src/login.c
@@ -1567,16 +1567,20 @@
15671567
sqlite3_int64 id; /* New subscriber Id */
15681568
const char *zCode; /* New subscriber code (in hex) */
15691569
const char *zGoto = P("g");
15701570
int nsub = 0;
15711571
char ssub[20];
1572
+ CapabilityString *pCap;
1573
+ pCap = capability_add(0, zPerms);
1574
+ capability_expand(pCap);
15721575
ssub[nsub++] = 'a';
1573
- if( g.perm.Read ) ssub[nsub++] = 'c';
1574
- if( g.perm.RdForum ) ssub[nsub++] = 'f';
1575
- if( g.perm.RdTkt ) ssub[nsub++] = 't';
1576
- if( g.perm.RdWiki ) ssub[nsub++] = 'w';
1576
+ if( capability_has_any(pCap,"o") ) ssub[nsub++] = 'c';
1577
+ if( capability_has_any(pCap,"2") ) ssub[nsub++] = 'f';
1578
+ if( capability_has_any(pCap,"r") ) ssub[nsub++] = 't';
1579
+ if( capability_has_any(pCap,"j") ) ssub[nsub++] = 'w';
15771580
ssub[nsub] = 0;
1581
+ capability_free(pCap);
15781582
/* Also add the user to the subscriber table. */
15791583
db_multi_exec(
15801584
"INSERT INTO subscriber(semail,suname,"
15811585
" sverified,sdonotcall,sdigest,ssub,sctime,mtime,smip)"
15821586
" VALUES(%Q,%Q,%d,0,%d,%Q,now(),now(),%Q)"
15831587
--- src/login.c
+++ src/login.c
@@ -1567,16 +1567,20 @@
1567 sqlite3_int64 id; /* New subscriber Id */
1568 const char *zCode; /* New subscriber code (in hex) */
1569 const char *zGoto = P("g");
1570 int nsub = 0;
1571 char ssub[20];
 
 
 
1572 ssub[nsub++] = 'a';
1573 if( g.perm.Read ) ssub[nsub++] = 'c';
1574 if( g.perm.RdForum ) ssub[nsub++] = 'f';
1575 if( g.perm.RdTkt ) ssub[nsub++] = 't';
1576 if( g.perm.RdWiki ) ssub[nsub++] = 'w';
1577 ssub[nsub] = 0;
 
1578 /* Also add the user to the subscriber table. */
1579 db_multi_exec(
1580 "INSERT INTO subscriber(semail,suname,"
1581 " sverified,sdonotcall,sdigest,ssub,sctime,mtime,smip)"
1582 " VALUES(%Q,%Q,%d,0,%d,%Q,now(),now(),%Q)"
1583
--- src/login.c
+++ src/login.c
@@ -1567,16 +1567,20 @@
1567 sqlite3_int64 id; /* New subscriber Id */
1568 const char *zCode; /* New subscriber code (in hex) */
1569 const char *zGoto = P("g");
1570 int nsub = 0;
1571 char ssub[20];
1572 CapabilityString *pCap;
1573 pCap = capability_add(0, zPerms);
1574 capability_expand(pCap);
1575 ssub[nsub++] = 'a';
1576 if( capability_has_any(pCap,"o") ) ssub[nsub++] = 'c';
1577 if( capability_has_any(pCap,"2") ) ssub[nsub++] = 'f';
1578 if( capability_has_any(pCap,"r") ) ssub[nsub++] = 't';
1579 if( capability_has_any(pCap,"j") ) ssub[nsub++] = 'w';
1580 ssub[nsub] = 0;
1581 capability_free(pCap);
1582 /* Also add the user to the subscriber table. */
1583 db_multi_exec(
1584 "INSERT INTO subscriber(semail,suname,"
1585 " sverified,sdonotcall,sdigest,ssub,sctime,mtime,smip)"
1586 " VALUES(%Q,%Q,%d,0,%d,%Q,now(),now(),%Q)"
1587
+5 -6
--- src/setupuser.c
+++ src/setupuser.c
@@ -549,18 +549,17 @@
549549
if( login_is_special(zLogin) ){
550550
@ <td><b>%h(zLogin)</b></td>
551551
}else{
552552
@ <td><input type="text" name="login" value="%h(zLogin)" />\
553553
if( alert_tables_exist() ){
554
- char *zSCode; /* Subscriber Code */
555
- zSCode = db_text(0, "SELECT hex(subscriberCode) FROM subscriber"
556
- " WHERE suname=%Q", zLogin);
557
- if( zSCode && zSCode[0] ){
558
- @ &nbsp;&nbsp;<a href="%R/alerts/%s(zSCode)">\
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)>\
559559
@ (subscription info for %h(zLogin))</a>\
560560
}
561
- fossil_free(zSCode);
562561
}
563562
@ </td></tr>
564563
@ <tr>
565564
@ <td class="usetupEditLabel">Contact&nbsp;Info:</td>
566565
@ <td><textarea name="info" cols="40" rows="2">%h(zInfo)</textarea></td>
567566
--- src/setupuser.c
+++ src/setupuser.c
@@ -549,18 +549,17 @@
549 if( login_is_special(zLogin) ){
550 @ <td><b>%h(zLogin)</b></td>
551 }else{
552 @ <td><input type="text" name="login" value="%h(zLogin)" />\
553 if( alert_tables_exist() ){
554 char *zSCode; /* Subscriber Code */
555 zSCode = db_text(0, "SELECT hex(subscriberCode) FROM subscriber"
556 " WHERE suname=%Q", zLogin);
557 if( zSCode && zSCode[0] ){
558 @ &nbsp;&nbsp;<a href="%R/alerts/%s(zSCode)">\
559 @ (subscription info for %h(zLogin))</a>\
560 }
561 fossil_free(zSCode);
562 }
563 @ </td></tr>
564 @ <tr>
565 @ <td class="usetupEditLabel">Contact&nbsp;Info:</td>
566 @ <td><textarea name="info" cols="40" rows="2">%h(zInfo)</textarea></td>
567
--- src/setupuser.c
+++ src/setupuser.c
@@ -549,18 +549,17 @@
549 if( login_is_special(zLogin) ){
550 @ <td><b>%h(zLogin)</b></td>
551 }else{
552 @ <td><input type="text" name="login" value="%h(zLogin)" />\
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 @ <td class="usetupEditLabel">Contact&nbsp;Info:</td>
565 @ <td><textarea name="info" cols="40" rows="2">%h(zInfo)</textarea></td>
566

Keyboard Shortcuts

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