Fossil SCM
Do not allow edits to wiki pages associated with branches, checkins, or tags for users who do not also have checkin privileges.
Commit
60e8a08f2200140bd5d94fedbc195bcfc59d595da4a28c4089eb0463683236c8
Parent
f17a5198f55845b…
2 files changed
+26
-8
+31
-1
+26
-8
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -691,10 +691,11 @@ | ||
| 691 | 691 | const char *zOrigUser; |
| 692 | 692 | const char *zComment; |
| 693 | 693 | const char *zDate; |
| 694 | 694 | const char *zOrigDate; |
| 695 | 695 | const char *zBrName; |
| 696 | + int okWiki = 0; | |
| 696 | 697 | Blob wiki_links = BLOB_INITIALIZER; |
| 697 | 698 | |
| 698 | 699 | style_header("Check-in [%S]", zUuid); |
| 699 | 700 | login_anonymous_available(); |
| 700 | 701 | zEUser = db_text(0, |
| @@ -761,16 +762,20 @@ | ||
| 761 | 762 | " AND +tag.tagname GLOB 'sym-*'", rid); |
| 762 | 763 | while( db_step(&q2)==SQLITE_ROW ){ |
| 763 | 764 | const char *zTagName = db_column_text(&q2, 0); |
| 764 | 765 | if( fossil_strcmp(zTagName,zBrName)==0 ){ |
| 765 | 766 | @ | %z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)</a> |
| 766 | - blob_appendf(&wiki_links, " | %z%h</a>", | |
| 767 | - href("%R/wiki?name=branch/%h",zTagName), zTagName); | |
| 767 | + if( g.perm.Write || wiki_tagid2("branch",zTagName)!=0 ){ | |
| 768 | + blob_appendf(&wiki_links, " | %z%h</a>", | |
| 769 | + href("%R/wiki?name=branch/%h",zTagName), zTagName); | |
| 770 | + } | |
| 768 | 771 | }else{ |
| 769 | 772 | @ | %z(href("%R/timeline?t=%T&unhide",zTagName))%h(zTagName)</a> |
| 770 | - blob_appendf(&wiki_links, " | %z%h</a>", | |
| 771 | - href("%R/wiki?name=tag/%h",zTagName), zTagName); | |
| 773 | + if( g.perm.Write || wiki_tagid2("tag",zTagName)!=0 ){ | |
| 774 | + blob_appendf(&wiki_links, " | %z%h</a>", | |
| 775 | + href("%R/wiki?name=tag/%h",zTagName), zTagName); | |
| 776 | + } | |
| 772 | 777 | } |
| 773 | 778 | } |
| 774 | 779 | db_finalize(&q2); |
| 775 | 780 | @ </td></tr> |
| 776 | 781 | |
| @@ -816,15 +821,28 @@ | ||
| 816 | 821 | @ <tr><th>Received From:</th> |
| 817 | 822 | @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr> |
| 818 | 823 | } |
| 819 | 824 | db_finalize(&q2); |
| 820 | 825 | } |
| 821 | - if( g.perm.RdWiki && db_get_boolean("wiki-about",1) ){ | |
| 822 | - @ <tr><th>Wiki:</th> | |
| 823 | - @ <td>%z(href("%R/wiki?name=checkin/%s",zUuid))this checkin</a> | |
| 824 | - @ %b(&wiki_links)</td> | |
| 826 | + | |
| 827 | + /* Only show links to wiki pages if the users can read wiki, | |
| 828 | + ** and only if the wiki pages already exist or the user has the | |
| 829 | + ** ability to create new ones. */ | |
| 830 | + if( g.perm.RdWiki | |
| 831 | + && (g.perm.Write || blob_size(&wiki_links)>0 | |
| 832 | + || (okWiki = wiki_tagid2("checkin",zUuid))!=0) | |
| 833 | + && db_get_boolean("wiki-about",1) | |
| 834 | + ){ | |
| 835 | + const char *zLinks = blob_str(&wiki_links); | |
| 836 | + if( zLinks[0] ) zLinks += 3; | |
| 837 | + @ <tr><th>Wiki:</th><td>\ | |
| 838 | + if( g.perm.Write || okWiki ){ | |
| 839 | + @ %z(href("%R/wiki?name=checkin/%s",zUuid))this checkin</a> | \ | |
| 840 | + } | |
| 841 | + @ %s(zLinks)</td></tr> | |
| 825 | 842 | } |
| 843 | + | |
| 826 | 844 | if( g.perm.Hyperlink ){ |
| 827 | 845 | @ <tr><th>Other Links:</th> |
| 828 | 846 | @ <td> |
| 829 | 847 | @ %z(href("%R/artifact/%!S",zUuid))manifest</a> |
| 830 | 848 | @ | %z(href("%R/ci_tags/%!S",zUuid))tags</a> |
| 831 | 849 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -691,10 +691,11 @@ | |
| 691 | const char *zOrigUser; |
| 692 | const char *zComment; |
| 693 | const char *zDate; |
| 694 | const char *zOrigDate; |
| 695 | const char *zBrName; |
| 696 | Blob wiki_links = BLOB_INITIALIZER; |
| 697 | |
| 698 | style_header("Check-in [%S]", zUuid); |
| 699 | login_anonymous_available(); |
| 700 | zEUser = db_text(0, |
| @@ -761,16 +762,20 @@ | |
| 761 | " AND +tag.tagname GLOB 'sym-*'", rid); |
| 762 | while( db_step(&q2)==SQLITE_ROW ){ |
| 763 | const char *zTagName = db_column_text(&q2, 0); |
| 764 | if( fossil_strcmp(zTagName,zBrName)==0 ){ |
| 765 | @ | %z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)</a> |
| 766 | blob_appendf(&wiki_links, " | %z%h</a>", |
| 767 | href("%R/wiki?name=branch/%h",zTagName), zTagName); |
| 768 | }else{ |
| 769 | @ | %z(href("%R/timeline?t=%T&unhide",zTagName))%h(zTagName)</a> |
| 770 | blob_appendf(&wiki_links, " | %z%h</a>", |
| 771 | href("%R/wiki?name=tag/%h",zTagName), zTagName); |
| 772 | } |
| 773 | } |
| 774 | db_finalize(&q2); |
| 775 | @ </td></tr> |
| 776 | |
| @@ -816,15 +821,28 @@ | |
| 816 | @ <tr><th>Received From:</th> |
| 817 | @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr> |
| 818 | } |
| 819 | db_finalize(&q2); |
| 820 | } |
| 821 | if( g.perm.RdWiki && db_get_boolean("wiki-about",1) ){ |
| 822 | @ <tr><th>Wiki:</th> |
| 823 | @ <td>%z(href("%R/wiki?name=checkin/%s",zUuid))this checkin</a> |
| 824 | @ %b(&wiki_links)</td> |
| 825 | } |
| 826 | if( g.perm.Hyperlink ){ |
| 827 | @ <tr><th>Other Links:</th> |
| 828 | @ <td> |
| 829 | @ %z(href("%R/artifact/%!S",zUuid))manifest</a> |
| 830 | @ | %z(href("%R/ci_tags/%!S",zUuid))tags</a> |
| 831 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -691,10 +691,11 @@ | |
| 691 | const char *zOrigUser; |
| 692 | const char *zComment; |
| 693 | const char *zDate; |
| 694 | const char *zOrigDate; |
| 695 | const char *zBrName; |
| 696 | int okWiki = 0; |
| 697 | Blob wiki_links = BLOB_INITIALIZER; |
| 698 | |
| 699 | style_header("Check-in [%S]", zUuid); |
| 700 | login_anonymous_available(); |
| 701 | zEUser = db_text(0, |
| @@ -761,16 +762,20 @@ | |
| 762 | " AND +tag.tagname GLOB 'sym-*'", rid); |
| 763 | while( db_step(&q2)==SQLITE_ROW ){ |
| 764 | const char *zTagName = db_column_text(&q2, 0); |
| 765 | if( fossil_strcmp(zTagName,zBrName)==0 ){ |
| 766 | @ | %z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)</a> |
| 767 | if( g.perm.Write || wiki_tagid2("branch",zTagName)!=0 ){ |
| 768 | blob_appendf(&wiki_links, " | %z%h</a>", |
| 769 | href("%R/wiki?name=branch/%h",zTagName), zTagName); |
| 770 | } |
| 771 | }else{ |
| 772 | @ | %z(href("%R/timeline?t=%T&unhide",zTagName))%h(zTagName)</a> |
| 773 | if( g.perm.Write || wiki_tagid2("tag",zTagName)!=0 ){ |
| 774 | blob_appendf(&wiki_links, " | %z%h</a>", |
| 775 | href("%R/wiki?name=tag/%h",zTagName), zTagName); |
| 776 | } |
| 777 | } |
| 778 | } |
| 779 | db_finalize(&q2); |
| 780 | @ </td></tr> |
| 781 | |
| @@ -816,15 +821,28 @@ | |
| 821 | @ <tr><th>Received From:</th> |
| 822 | @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr> |
| 823 | } |
| 824 | db_finalize(&q2); |
| 825 | } |
| 826 | |
| 827 | /* Only show links to wiki pages if the users can read wiki, |
| 828 | ** and only if the wiki pages already exist or the user has the |
| 829 | ** ability to create new ones. */ |
| 830 | if( g.perm.RdWiki |
| 831 | && (g.perm.Write || blob_size(&wiki_links)>0 |
| 832 | || (okWiki = wiki_tagid2("checkin",zUuid))!=0) |
| 833 | && db_get_boolean("wiki-about",1) |
| 834 | ){ |
| 835 | const char *zLinks = blob_str(&wiki_links); |
| 836 | if( zLinks[0] ) zLinks += 3; |
| 837 | @ <tr><th>Wiki:</th><td>\ |
| 838 | if( g.perm.Write || okWiki ){ |
| 839 | @ %z(href("%R/wiki?name=checkin/%s",zUuid))this checkin</a> | \ |
| 840 | } |
| 841 | @ %s(zLinks)</td></tr> |
| 842 | } |
| 843 | |
| 844 | if( g.perm.Hyperlink ){ |
| 845 | @ <tr><th>Other Links:</th> |
| 846 | @ <td> |
| 847 | @ %z(href("%R/artifact/%!S",zUuid))manifest</a> |
| 848 | @ | %z(href("%R/ci_tags/%!S",zUuid))tags</a> |
| 849 |
+31
-1
| --- src/wiki.c | ||
| +++ src/wiki.c | ||
| @@ -78,10 +78,14 @@ | ||
| 78 | 78 | ** Return the tagid associated with a particular wiki page. |
| 79 | 79 | */ |
| 80 | 80 | int wiki_tagid(const char *zPageName){ |
| 81 | 81 | return db_int(0, "SELECT tagid FROM tag WHERE tagname='wiki-%q'",zPageName); |
| 82 | 82 | } |
| 83 | +int wiki_tagid2(const char *zPrefix, const char *zPageName){ | |
| 84 | + return db_int(0, "SELECT tagid FROM tag WHERE tagname='wiki-%q/%q'", | |
| 85 | + zPrefix, zPageName); | |
| 86 | +} | |
| 83 | 87 | |
| 84 | 88 | /* |
| 85 | 89 | ** Return the RID of the next or previous version of a wiki page. |
| 86 | 90 | ** Return 0 if rid is the last/first version. |
| 87 | 91 | */ |
| @@ -371,10 +375,30 @@ | ||
| 371 | 375 | } |
| 372 | 376 | else{ |
| 373 | 377 | style_header("%s%s", zExtra, zPageName); |
| 374 | 378 | } |
| 375 | 379 | } |
| 380 | + | |
| 381 | +/* | |
| 382 | +** Wiki pages with special names "branch/...", "checkin/...", and "tag/..." | |
| 383 | +** requires perm.Write privilege in addition to perm.WrWiki in order | |
| 384 | +** to write. This function determines whether the extra perm.Write | |
| 385 | +** is required and available. Return true if writing to the wiki page | |
| 386 | +** may proceed, and return false if permission is lacking. | |
| 387 | +*/ | |
| 388 | +static int wiki_special_permission(const char *zPageName){ | |
| 389 | + if( strncmp(zPageName,"branch/",7)!=0 | |
| 390 | + && strncmp(zPageName,"checkin/",8)!=0 | |
| 391 | + && strncmp(zPageName,"tag/",4)!=0 | |
| 392 | + ){ | |
| 393 | + return 1; | |
| 394 | + } | |
| 395 | + if( db_get_boolean("wiki-about",1)==0 ){ | |
| 396 | + return 1; | |
| 397 | + } | |
| 398 | + return g.perm.Write; | |
| 399 | +} | |
| 376 | 400 | |
| 377 | 401 | /* |
| 378 | 402 | ** WEBPAGE: wiki |
| 379 | 403 | ** URL: /wiki?name=PAGENAME |
| 380 | 404 | */ |
| @@ -424,11 +448,13 @@ | ||
| 424 | 448 | zMimetype = pWiki->zMimetype; |
| 425 | 449 | } |
| 426 | 450 | } |
| 427 | 451 | zMimetype = wiki_filter_mimetypes(zMimetype); |
| 428 | 452 | if( !g.isHome ){ |
| 429 | - if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){ | |
| 453 | + if( ((rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki)) | |
| 454 | + && wiki_special_permission(zPageName) | |
| 455 | + ){ | |
| 430 | 456 | if( db_get_boolean("wysiwyg-wiki", 0) ){ |
| 431 | 457 | style_submenu_element("Edit", "%s/wikiedit?name=%T&wysiwyg=1", |
| 432 | 458 | g.zTop, zPageName); |
| 433 | 459 | }else{ |
| 434 | 460 | style_submenu_element("Edit", "%s/wikiedit?name=%T", g.zTop, zPageName); |
| @@ -554,10 +580,14 @@ | ||
| 554 | 580 | "SELECT rid FROM tagxref" |
| 555 | 581 | " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)" |
| 556 | 582 | " ORDER BY mtime DESC", zTag |
| 557 | 583 | ); |
| 558 | 584 | free(zTag); |
| 585 | + if( !wiki_special_permission(zPageName) ){ | |
| 586 | + login_needed(0); | |
| 587 | + return; | |
| 588 | + } | |
| 559 | 589 | if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){ |
| 560 | 590 | login_needed(rid ? g.anon.WrWiki : g.anon.NewWiki); |
| 561 | 591 | return; |
| 562 | 592 | } |
| 563 | 593 | if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){ |
| 564 | 594 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -78,10 +78,14 @@ | |
| 78 | ** Return the tagid associated with a particular wiki page. |
| 79 | */ |
| 80 | int wiki_tagid(const char *zPageName){ |
| 81 | return db_int(0, "SELECT tagid FROM tag WHERE tagname='wiki-%q'",zPageName); |
| 82 | } |
| 83 | |
| 84 | /* |
| 85 | ** Return the RID of the next or previous version of a wiki page. |
| 86 | ** Return 0 if rid is the last/first version. |
| 87 | */ |
| @@ -371,10 +375,30 @@ | |
| 371 | } |
| 372 | else{ |
| 373 | style_header("%s%s", zExtra, zPageName); |
| 374 | } |
| 375 | } |
| 376 | |
| 377 | /* |
| 378 | ** WEBPAGE: wiki |
| 379 | ** URL: /wiki?name=PAGENAME |
| 380 | */ |
| @@ -424,11 +448,13 @@ | |
| 424 | zMimetype = pWiki->zMimetype; |
| 425 | } |
| 426 | } |
| 427 | zMimetype = wiki_filter_mimetypes(zMimetype); |
| 428 | if( !g.isHome ){ |
| 429 | if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){ |
| 430 | if( db_get_boolean("wysiwyg-wiki", 0) ){ |
| 431 | style_submenu_element("Edit", "%s/wikiedit?name=%T&wysiwyg=1", |
| 432 | g.zTop, zPageName); |
| 433 | }else{ |
| 434 | style_submenu_element("Edit", "%s/wikiedit?name=%T", g.zTop, zPageName); |
| @@ -554,10 +580,14 @@ | |
| 554 | "SELECT rid FROM tagxref" |
| 555 | " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)" |
| 556 | " ORDER BY mtime DESC", zTag |
| 557 | ); |
| 558 | free(zTag); |
| 559 | if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){ |
| 560 | login_needed(rid ? g.anon.WrWiki : g.anon.NewWiki); |
| 561 | return; |
| 562 | } |
| 563 | if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){ |
| 564 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -78,10 +78,14 @@ | |
| 78 | ** Return the tagid associated with a particular wiki page. |
| 79 | */ |
| 80 | int wiki_tagid(const char *zPageName){ |
| 81 | return db_int(0, "SELECT tagid FROM tag WHERE tagname='wiki-%q'",zPageName); |
| 82 | } |
| 83 | int wiki_tagid2(const char *zPrefix, const char *zPageName){ |
| 84 | return db_int(0, "SELECT tagid FROM tag WHERE tagname='wiki-%q/%q'", |
| 85 | zPrefix, zPageName); |
| 86 | } |
| 87 | |
| 88 | /* |
| 89 | ** Return the RID of the next or previous version of a wiki page. |
| 90 | ** Return 0 if rid is the last/first version. |
| 91 | */ |
| @@ -371,10 +375,30 @@ | |
| 375 | } |
| 376 | else{ |
| 377 | style_header("%s%s", zExtra, zPageName); |
| 378 | } |
| 379 | } |
| 380 | |
| 381 | /* |
| 382 | ** Wiki pages with special names "branch/...", "checkin/...", and "tag/..." |
| 383 | ** requires perm.Write privilege in addition to perm.WrWiki in order |
| 384 | ** to write. This function determines whether the extra perm.Write |
| 385 | ** is required and available. Return true if writing to the wiki page |
| 386 | ** may proceed, and return false if permission is lacking. |
| 387 | */ |
| 388 | static int wiki_special_permission(const char *zPageName){ |
| 389 | if( strncmp(zPageName,"branch/",7)!=0 |
| 390 | && strncmp(zPageName,"checkin/",8)!=0 |
| 391 | && strncmp(zPageName,"tag/",4)!=0 |
| 392 | ){ |
| 393 | return 1; |
| 394 | } |
| 395 | if( db_get_boolean("wiki-about",1)==0 ){ |
| 396 | return 1; |
| 397 | } |
| 398 | return g.perm.Write; |
| 399 | } |
| 400 | |
| 401 | /* |
| 402 | ** WEBPAGE: wiki |
| 403 | ** URL: /wiki?name=PAGENAME |
| 404 | */ |
| @@ -424,11 +448,13 @@ | |
| 448 | zMimetype = pWiki->zMimetype; |
| 449 | } |
| 450 | } |
| 451 | zMimetype = wiki_filter_mimetypes(zMimetype); |
| 452 | if( !g.isHome ){ |
| 453 | if( ((rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki)) |
| 454 | && wiki_special_permission(zPageName) |
| 455 | ){ |
| 456 | if( db_get_boolean("wysiwyg-wiki", 0) ){ |
| 457 | style_submenu_element("Edit", "%s/wikiedit?name=%T&wysiwyg=1", |
| 458 | g.zTop, zPageName); |
| 459 | }else{ |
| 460 | style_submenu_element("Edit", "%s/wikiedit?name=%T", g.zTop, zPageName); |
| @@ -554,10 +580,14 @@ | |
| 580 | "SELECT rid FROM tagxref" |
| 581 | " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)" |
| 582 | " ORDER BY mtime DESC", zTag |
| 583 | ); |
| 584 | free(zTag); |
| 585 | if( !wiki_special_permission(zPageName) ){ |
| 586 | login_needed(0); |
| 587 | return; |
| 588 | } |
| 589 | if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){ |
| 590 | login_needed(rid ? g.anon.WrWiki : g.anon.NewWiki); |
| 591 | return; |
| 592 | } |
| 593 | if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){ |
| 594 |