Fossil SCM

Enforce well-formedness constraints on wiki pagenames.

drh 2007-10-06 17:10 trunk
Commit 488afb97461a34ae63ac2a1f5e8b018e68466686
--- src/manifest.c
+++ src/manifest.c
@@ -370,10 +370,13 @@
370370
if( p->zWikiTitle!=0 ) goto manifest_syntax_error;
371371
if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
372372
if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error;
373373
p->zWikiTitle = blob_terminate(&a1);
374374
defossilize(p->zWikiTitle);
375
+ if( !wiki_name_is_wellformed(p->zWikiTitle) ){
376
+ goto manifest_syntax_error;
377
+ }
375378
break;
376379
}
377380
378381
/*
379382
** M <uuid>
380383
--- src/manifest.c
+++ src/manifest.c
@@ -370,10 +370,13 @@
370 if( p->zWikiTitle!=0 ) goto manifest_syntax_error;
371 if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
372 if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error;
373 p->zWikiTitle = blob_terminate(&a1);
374 defossilize(p->zWikiTitle);
 
 
 
375 break;
376 }
377
378 /*
379 ** M <uuid>
380
--- src/manifest.c
+++ src/manifest.c
@@ -370,10 +370,13 @@
370 if( p->zWikiTitle!=0 ) goto manifest_syntax_error;
371 if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
372 if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error;
373 p->zWikiTitle = blob_terminate(&a1);
374 defossilize(p->zWikiTitle);
375 if( !wiki_name_is_wellformed(p->zWikiTitle) ){
376 goto manifest_syntax_error;
377 }
378 break;
379 }
380
381 /*
382 ** M <uuid>
383
+47 -2
--- src/wiki.c
+++ src/wiki.c
@@ -25,10 +25,53 @@
2525
*/
2626
#include <assert.h>
2727
#include "config.h"
2828
#include "wiki.h"
2929
30
+/*
31
+** Return true if the input string is a well-formed wiki page name.
32
+**
33
+** Well-formed wiki page names do not begin or end with whitespace,
34
+** and do not contain tabs or other control characters and do not
35
+** contain more than a single space character in a row. Well-formed
36
+** names must be between 3 and 100 chracters in length, inclusive.
37
+*/
38
+int wiki_name_is_wellformed(const char *z){
39
+ int i;
40
+ if( z[0]<=0x20 ){
41
+ return 0;
42
+ }
43
+ for(i=1; z[i]; i++){
44
+ if( z[i]<0x20 ) return 0;
45
+ if( z[i]==0x20 && z[i-1]==0x20 ) return 0;
46
+ }
47
+ if( z[i-1]==' ' ) return 0;
48
+ if( i<3 || i>100 ) return 0;
49
+ return 1;
50
+}
51
+
52
+/*
53
+** Check a wiki name. If it is not well-formed, then issue an error
54
+** and return true. If it is well-formed, return false.
55
+*/
56
+static int check_name(const char *z){
57
+ if( !wiki_name_is_wellformed(z) ){
58
+ style_header("Wiki Page Name Error");
59
+ @ The wiki name "<b>%h(z)</b>" is not well-formed. Rules for
60
+ @ wiki page names:
61
+ @ <ul>
62
+ @ <li> Must not begin or end with a space.
63
+ @ <li> Must not contain any control characters, including tab or
64
+ @ newline.
65
+ @ <li> Must not have two or more spaces in a row internally.
66
+ @ <li> Must be between 3 and 100 characters in length.
67
+ @ </ul>
68
+ style_footer();
69
+ return 1;
70
+ }
71
+ return 0;
72
+}
3073
3174
/*
3275
** WEBPAGE: wiki
3376
** URL: /wiki/PAGENAME
3477
*/
@@ -43,10 +86,11 @@
4386
4487
login_check_credentials();
4588
if( !g.okRdWiki ){ login_needed(); return; }
4689
zPageName = mprintf("%s", g.zExtra);
4790
dehttpize(zPageName);
91
+ if( check_name(zPageName) ) return;
4892
zTag = mprintf("wiki-%s", zPageName);
4993
rid = db_int(0,
5094
"SELECT rid FROM tagxref"
5195
" WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
5296
" ORDER BY mtime DESC", zTag
@@ -66,11 +110,11 @@
66110
style_header(zHtmlPageName);
67111
blob_init(&wiki, zBody, -1);
68112
wiki_convert(&wiki, 0);
69113
blob_reset(&wiki);
70114
manifest_clear(&m);
71
- if( zPageName[0] && ((rid && g.okWrWiki) || (!rid && g.okNewWiki)) ){
115
+ if( (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){
72116
@ <hr>
73117
@ [<a href="%s(g.zBaseURL)/wikiedit/%s(g.zExtra)">Edit</a>]
74118
}
75119
style_footer();
76120
}
@@ -94,10 +138,11 @@
94138
zBody = mprintf("%s", zBody);
95139
}
96140
login_check_credentials();
97141
zPageName = mprintf("%s", g.zExtra);
98142
dehttpize(zPageName);
143
+ if( check_name(zPageName) ) return;
99144
zTag = mprintf("wiki-%s", zPageName);
100145
rid = db_int(0,
101146
"SELECT rid FROM tagxref"
102147
" WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
103148
" ORDER BY mtime DESC", zTag
@@ -146,11 +191,11 @@
146191
blob_reset(&wiki);
147192
content_deltify(rid, nrid, 0);
148193
db_end_transaction(0);
149194
cgi_redirect(mprintf("wiki/%s", g.zExtra));
150195
}
151
- if( P("cancel")!=0 || zPageName[0]==0 ){
196
+ if( P("cancel")!=0 ){
152197
cgi_redirect(mprintf("wiki/%s", g.zExtra));
153198
return;
154199
}
155200
if( zBody==0 ){
156201
zBody = mprintf("<i>Empty Page</i>");
157202
--- src/wiki.c
+++ src/wiki.c
@@ -25,10 +25,53 @@
25 */
26 #include <assert.h>
27 #include "config.h"
28 #include "wiki.h"
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
31 /*
32 ** WEBPAGE: wiki
33 ** URL: /wiki/PAGENAME
34 */
@@ -43,10 +86,11 @@
43
44 login_check_credentials();
45 if( !g.okRdWiki ){ login_needed(); return; }
46 zPageName = mprintf("%s", g.zExtra);
47 dehttpize(zPageName);
 
48 zTag = mprintf("wiki-%s", zPageName);
49 rid = db_int(0,
50 "SELECT rid FROM tagxref"
51 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
52 " ORDER BY mtime DESC", zTag
@@ -66,11 +110,11 @@
66 style_header(zHtmlPageName);
67 blob_init(&wiki, zBody, -1);
68 wiki_convert(&wiki, 0);
69 blob_reset(&wiki);
70 manifest_clear(&m);
71 if( zPageName[0] && ((rid && g.okWrWiki) || (!rid && g.okNewWiki)) ){
72 @ <hr>
73 @ [<a href="%s(g.zBaseURL)/wikiedit/%s(g.zExtra)">Edit</a>]
74 }
75 style_footer();
76 }
@@ -94,10 +138,11 @@
94 zBody = mprintf("%s", zBody);
95 }
96 login_check_credentials();
97 zPageName = mprintf("%s", g.zExtra);
98 dehttpize(zPageName);
 
99 zTag = mprintf("wiki-%s", zPageName);
100 rid = db_int(0,
101 "SELECT rid FROM tagxref"
102 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
103 " ORDER BY mtime DESC", zTag
@@ -146,11 +191,11 @@
146 blob_reset(&wiki);
147 content_deltify(rid, nrid, 0);
148 db_end_transaction(0);
149 cgi_redirect(mprintf("wiki/%s", g.zExtra));
150 }
151 if( P("cancel")!=0 || zPageName[0]==0 ){
152 cgi_redirect(mprintf("wiki/%s", g.zExtra));
153 return;
154 }
155 if( zBody==0 ){
156 zBody = mprintf("<i>Empty Page</i>");
157
--- src/wiki.c
+++ src/wiki.c
@@ -25,10 +25,53 @@
25 */
26 #include <assert.h>
27 #include "config.h"
28 #include "wiki.h"
29
30 /*
31 ** Return true if the input string is a well-formed wiki page name.
32 **
33 ** Well-formed wiki page names do not begin or end with whitespace,
34 ** and do not contain tabs or other control characters and do not
35 ** contain more than a single space character in a row. Well-formed
36 ** names must be between 3 and 100 chracters in length, inclusive.
37 */
38 int wiki_name_is_wellformed(const char *z){
39 int i;
40 if( z[0]<=0x20 ){
41 return 0;
42 }
43 for(i=1; z[i]; i++){
44 if( z[i]<0x20 ) return 0;
45 if( z[i]==0x20 && z[i-1]==0x20 ) return 0;
46 }
47 if( z[i-1]==' ' ) return 0;
48 if( i<3 || i>100 ) return 0;
49 return 1;
50 }
51
52 /*
53 ** Check a wiki name. If it is not well-formed, then issue an error
54 ** and return true. If it is well-formed, return false.
55 */
56 static int check_name(const char *z){
57 if( !wiki_name_is_wellformed(z) ){
58 style_header("Wiki Page Name Error");
59 @ The wiki name "<b>%h(z)</b>" is not well-formed. Rules for
60 @ wiki page names:
61 @ <ul>
62 @ <li> Must not begin or end with a space.
63 @ <li> Must not contain any control characters, including tab or
64 @ newline.
65 @ <li> Must not have two or more spaces in a row internally.
66 @ <li> Must be between 3 and 100 characters in length.
67 @ </ul>
68 style_footer();
69 return 1;
70 }
71 return 0;
72 }
73
74 /*
75 ** WEBPAGE: wiki
76 ** URL: /wiki/PAGENAME
77 */
@@ -43,10 +86,11 @@
86
87 login_check_credentials();
88 if( !g.okRdWiki ){ login_needed(); return; }
89 zPageName = mprintf("%s", g.zExtra);
90 dehttpize(zPageName);
91 if( check_name(zPageName) ) return;
92 zTag = mprintf("wiki-%s", zPageName);
93 rid = db_int(0,
94 "SELECT rid FROM tagxref"
95 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
96 " ORDER BY mtime DESC", zTag
@@ -66,11 +110,11 @@
110 style_header(zHtmlPageName);
111 blob_init(&wiki, zBody, -1);
112 wiki_convert(&wiki, 0);
113 blob_reset(&wiki);
114 manifest_clear(&m);
115 if( (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){
116 @ <hr>
117 @ [<a href="%s(g.zBaseURL)/wikiedit/%s(g.zExtra)">Edit</a>]
118 }
119 style_footer();
120 }
@@ -94,10 +138,11 @@
138 zBody = mprintf("%s", zBody);
139 }
140 login_check_credentials();
141 zPageName = mprintf("%s", g.zExtra);
142 dehttpize(zPageName);
143 if( check_name(zPageName) ) return;
144 zTag = mprintf("wiki-%s", zPageName);
145 rid = db_int(0,
146 "SELECT rid FROM tagxref"
147 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
148 " ORDER BY mtime DESC", zTag
@@ -146,11 +191,11 @@
191 blob_reset(&wiki);
192 content_deltify(rid, nrid, 0);
193 db_end_transaction(0);
194 cgi_redirect(mprintf("wiki/%s", g.zExtra));
195 }
196 if( P("cancel")!=0 ){
197 cgi_redirect(mprintf("wiki/%s", g.zExtra));
198 return;
199 }
200 if( zBody==0 ){
201 zBody = mprintf("<i>Empty Page</i>");
202
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -760,12 +760,14 @@
760760
|| strncmp(zTarget, "https:", 6)==0
761761
|| strncmp(zTarget, "ftp:", 4)==0
762762
|| strncmp(zTarget, "mailto:", 7)==0
763763
){
764764
blob_appendf(p->pOut, zTarget);
765
- }else{
765
+ }else if( wiki_name_is_wellformed(zTarget) ){
766766
blob_appendf(p->pOut, "%s/wiki/%T", g.zBaseURL, zTarget);
767
+ }else{
768
+ blob_appendf(p->pOut, "error");
767769
}
768770
}
769771
770772
/*
771773
** Check to see if the given parsed markup is the correct
@@ -862,18 +864,19 @@
862864
break;
863865
}
864866
case TOKEN_LINK: {
865867
char *zTarget;
866868
char *zDisplay = 0;
867
- int i;
869
+ int i, j;
868870
int savedState;
869871
addMissingMarkup(p);
870872
zTarget = &z[1];
871873
for(i=1; z[i] && z[i]!=']'; i++){
872874
if( z[i]=='|' && zDisplay==0 ){
873875
zDisplay = &z[i+1];
874876
z[i] = 0;
877
+ for(j=i-1; j>0 && isspace(z[j]); j--){ z[j] = 0; }
875878
}
876879
}
877880
z[i] = 0;
878881
if( zDisplay==0 ){
879882
zDisplay = zTarget;
880883
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -760,12 +760,14 @@
760 || strncmp(zTarget, "https:", 6)==0
761 || strncmp(zTarget, "ftp:", 4)==0
762 || strncmp(zTarget, "mailto:", 7)==0
763 ){
764 blob_appendf(p->pOut, zTarget);
765 }else{
766 blob_appendf(p->pOut, "%s/wiki/%T", g.zBaseURL, zTarget);
 
 
767 }
768 }
769
770 /*
771 ** Check to see if the given parsed markup is the correct
@@ -862,18 +864,19 @@
862 break;
863 }
864 case TOKEN_LINK: {
865 char *zTarget;
866 char *zDisplay = 0;
867 int i;
868 int savedState;
869 addMissingMarkup(p);
870 zTarget = &z[1];
871 for(i=1; z[i] && z[i]!=']'; i++){
872 if( z[i]=='|' && zDisplay==0 ){
873 zDisplay = &z[i+1];
874 z[i] = 0;
 
875 }
876 }
877 z[i] = 0;
878 if( zDisplay==0 ){
879 zDisplay = zTarget;
880
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -760,12 +760,14 @@
760 || strncmp(zTarget, "https:", 6)==0
761 || strncmp(zTarget, "ftp:", 4)==0
762 || strncmp(zTarget, "mailto:", 7)==0
763 ){
764 blob_appendf(p->pOut, zTarget);
765 }else if( wiki_name_is_wellformed(zTarget) ){
766 blob_appendf(p->pOut, "%s/wiki/%T", g.zBaseURL, zTarget);
767 }else{
768 blob_appendf(p->pOut, "error");
769 }
770 }
771
772 /*
773 ** Check to see if the given parsed markup is the correct
@@ -862,18 +864,19 @@
864 break;
865 }
866 case TOKEN_LINK: {
867 char *zTarget;
868 char *zDisplay = 0;
869 int i, j;
870 int savedState;
871 addMissingMarkup(p);
872 zTarget = &z[1];
873 for(i=1; z[i] && z[i]!=']'; i++){
874 if( z[i]=='|' && zDisplay==0 ){
875 zDisplay = &z[i+1];
876 z[i] = 0;
877 for(j=i-1; j>0 && isspace(z[j]); j--){ z[j] = 0; }
878 }
879 }
880 z[i] = 0;
881 if( zDisplay==0 ){
882 zDisplay = zTarget;
883

Keyboard Shortcuts

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