36 Commits

Author SHA1 Message Date
fdb854e6c7 doc: changelog 2017-10-29 15:10:35 +13:00
f934c2917f catch one more case of title normalisation 2017-10-29 15:09:53 +13:00
1bfefdccb3 bump all versions to 3.1.3 2017-10-29 14:11:31 +13:00
9ca58bc16c doc: update readme 2017-10-29 14:08:10 +13:00
122acf6999 rebuild staticResources.go 2017-10-29 14:05:20 +13:00
f627946c0d use 'dep' for dependency management 2017-10-29 14:04:26 +13:00
5b42685956 diff/test: fix package import path 2017-10-29 14:01:16 +13:00
90fedf86d9 serve proper 404 if favicon.ico not configured 2017-10-29 13:40:15 +13:00
a9a6b51a3f show yatwiki version in Server header 2017-10-29 13:40:00 +13:00
9687f90cf5 build: use simpler cleanup target 2017-10-29 13:29:12 +13:00
5cc93387e7 fix a regression with not normalising titles to lowercase/trim 2017-10-29 13:19:24 +13:00
fc57e4d8f3 bump version to 3.1.2 2017-10-15 20:02:20 +13:00
2bc26c5966 bump version to 3.1.1 2017-10-15 20:01:59 +13:00
f5767db840 load contented without jquery, but it's present by the callback 2017-10-15 20:00:04 +13:00
edf88d1f31 doc: changelog update 2017-10-15 19:58:04 +13:00
262c3ba903 contented: update integration to 1.1.0 2017-10-15 19:56:03 +13:00
a260d102ee doc: update readme, bump version to 3.1.0 2017-10-08 17:09:15 +13:00
179617d058 contented integration 2017-10-08 17:08:26 +13:00
5347efb51a bump version to 3.0.3 2017-08-13 18:29:21 +12:00
e3cee5b94c doc: changelog update 2017-08-13 18:27:04 +12:00
e4cf02cde7 restructure error handling to prevent reflected XSS 2017-08-13 18:25:58 +12:00
06e5b4ddf9 bump version to 3.0.1 2017-08-13 18:07:29 +12:00
dbf5e1b246 gitignore 2017-08-13 18:05:34 +12:00
fbad854279 doc: preliminary changelog update 2017-08-13 18:05:28 +12:00
d78429129f also use path escaping function for whole-template links 2017-08-13 18:04:26 +12:00
d937ea6562 prevent viewing history for unknown articles 2017-08-13 17:58:01 +12:00
884acd3040 remove debugging code 2017-08-13 17:53:21 +12:00
e515d73052 use PathEscape instead of QueryEscape for titles in URLs 2017-08-13 17:51:44 +12:00
c87eaa637a doc: preliminary changelog update 2017-08-13 17:33:27 +12:00
043720a086 new TrustXForwardedFor option 2017-08-13 17:32:54 +12:00
a12af6967c fix crash with [html] tags 2017-08-13 17:28:44 +12:00
9792c262a2 readme: fix version tags for download alignment on website 2017-08-13 13:52:40 +12:00
6d9079e1dc doc: update git repo in docs 2017-07-12 18:46:49 +12:00
1c4505a2d9 rename package yatwiki3->yatwiki 2017-07-12 18:43:11 +12:00
11a4f97212 bump all versions to 3.0.1 2017-07-12 18:41:39 +12:00
74b3124997 doc: add 'go get' information to readme 2017-07-11 20:23:17 +12:00
27 changed files with 245 additions and 84 deletions

5
.gitignore vendored
View File

@@ -6,5 +6,8 @@ build/
cmd/yatwiki-server/yatwiki-server
# Development db files
cmd/yatwiki-server/wiki.db
cmd/yatwiki-server/*.db
cmd/yatwiki-server/config.json
# Vendor
vendor/

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"crypto/md5"
@@ -11,8 +11,16 @@ func RemoteAddrToIPAddress(remoteAddr string) string {
return strings.TrimRight(strings.TrimRight(remoteAddr, `0123456789`), `:`) // trim trailing port; IPv4 and IPv6-safe
}
func Author(r *http.Request) string {
func Author(r *http.Request, trustXForwardedFor bool) string {
userAgentHash := md5.Sum([]byte(r.UserAgent()))
return RemoteAddrToIPAddress(r.RemoteAddr) + "-" + hex.EncodeToString(userAgentHash[:])[:6]
ipAddress := RemoteAddrToIPAddress(r.RemoteAddr)
if trustXForwardedFor {
if xff := r.Header.Get("X-Forwarded-For"); len(xff) > 0 {
ipAddress = xff
}
}
return ipAddress + "-" + hex.EncodeToString(userAgentHash[:])[:6]
}

16
DB.go
View File

@@ -1,8 +1,9 @@
package yatwiki3
package yatwiki
import (
"database/sql"
"fmt"
"strings"
"time"
_ "github.com/mattn/go-sqlite3"
@@ -91,7 +92,7 @@ func (this *WikiDB) GetRevision(revId int) (*Article, error) {
}
func (this *WikiDB) GetLatestVersion(title string) (*Article, error) {
row := this.db.QueryRow(`SELECT articles.* FROM articles WHERE article = (SELECT id FROM titles WHERE title = ?) ORDER BY modified DESC LIMIT 1`, title)
row := this.db.QueryRow(`SELECT articles.* FROM articles WHERE article = (SELECT id FROM titles WHERE title = ?) ORDER BY modified DESC LIMIT 1`, this.normaliseTitle(title))
return this.parseArticle(row)
}
@@ -103,6 +104,10 @@ func (aae ArticleAlteredError) Error() string {
return fmt.Sprintf("Warning: Your changes were not based on the most recent version of the page (r%d ≠ r%d). No changes were saved.", aae.got, aae.expected)
}
func (this *WikiDB) normaliseTitle(title string) string {
return strings.ToLower(strings.Trim(title, " \r\n\t"))
}
func (this *WikiDB) SaveArticle(title, author, body string, expectBaseRev int64) error {
isNewArticle := false
a, err := this.GetLatestVersion(title)
@@ -125,7 +130,7 @@ func (this *WikiDB) SaveArticle(title, author, body string, expectBaseRev int64)
var titleId int64
if isNewArticle {
titleInsert, err := this.db.Exec(`INSERT INTO titles (title) VALUES (?)`, title)
titleInsert, err := this.db.Exec(`INSERT INTO titles (title) VALUES (?)`, this.normaliseTitle(title))
if err != nil {
return err
}
@@ -147,7 +152,10 @@ func (this *WikiDB) SaveArticle(title, author, body string, expectBaseRev int64)
}
func (this *WikiDB) GetRevisionHistory(title string) ([]Article, error) {
rows, err := this.db.Query(`SELECT articles.id, articles.modified, articles.author FROM articles WHERE article = (SELECT id FROM titles WHERE title = ?) ORDER BY modified DESC`, title)
rows, err := this.db.Query(
`SELECT articles.id, articles.modified, articles.author FROM articles WHERE article = (SELECT id FROM titles WHERE title = ?) ORDER BY modified DESC`,
this.normaliseTitle(title),
)
if err != nil {
return nil, err
}

21
Gopkg.lock generated Normal file
View File

@@ -0,0 +1,21 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/mattn/go-sqlite3"
packages = ["."]
revision = "5160b48509cf5c877bc22c11c373f8c7738cdb38"
version = "v1.3.0"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = ["context"]
revision = "c73622c77280266305273cb545f54516ced95b93"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "a1f2d643f8c1770c92ee1759184a0c7004af5672869db579328d05bb7cfd6bef"
solver-name = "gps-cdcl"
solver-version = 1

26
Gopkg.toml Normal file
View File

@@ -0,0 +1,26 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
name = "github.com/mattn/go-sqlite3"
version = "1.3.0"

View File

@@ -2,20 +2,24 @@
# Makefile for YATWiki3
#
VERSION:=3.0
VERSION:=3.1.3
SOURCES:=Makefile \
static \
cmd $(wildcard cmd/yatwiki-server/*.go) \
Gopkg.lock Gopkg.toml \
$(wildcard *.go)
GOFLAGS := -ldflags='-s -w' -gcflags='-trimpath=$(GOPATH)' -asmflags='-trimpath=$(GOPATH)'
GOFLAGS:=-a \
-ldflags "-s -w -X code.ivysaur.me/yatwiki.SERVER_HEADER=YATWiki/$(VERSION)" \
-gcflags '-trimpath=$(GOPATH)' \
-asmflags '-trimpath=$(GOPATH)'
#
# Phony targets
#
.PHONY: all dist clean
.PHONY: all dist clean deps
all: build/linux64/yatwiki-server build/win32/yatwiki-server.exe
@@ -25,16 +29,21 @@ dist: \
_dist/yatwiki-$(VERSION)-src.zip
clean:
if [ -f ./staticResources.go ] ; then rm ./staticResources.go ; fi
if [ -d ./build ] ; then rm -r ./build ; fi
if [ -f ./yatwiki ] ; then rm ./yatwiki ; fi
rm -f ./staticResources.go
rm -fr ./build
rm -f ./yatwiki
deps:
go get -u github.com/jteeuwen/go-bindata/...
go get -u github.com/golang/dep/cmd/dep
dep ensure
#
# Generated files
#
staticResources.go: static/ static/*
go-bindata -o staticResources.go -prefix static -pkg yatwiki3 static
go-bindata -o staticResources.go -prefix static -pkg yatwiki static
#

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"time"
@@ -13,6 +13,7 @@ type ServerOptions struct {
DBFilePath string
FaviconFilePath string
AllowDBDownload bool
TrustXForwardedFor bool // Introduced in 3.0.1 - default false
RecentChanges int
RecentChangesRSS int
GzipCompressionLevel int
@@ -20,6 +21,7 @@ type ServerOptions struct {
ExternalBaseURL string
DeclareRSSLanguage string
DeclareRSSEmail string
ContentedServer string
}
func DefaultOptions() *ServerOptions {
@@ -32,6 +34,7 @@ func DefaultOptions() *ServerOptions {
DBFilePath: "wiki.db",
FaviconFilePath: "", // no favicon
AllowDBDownload: true,
TrustXForwardedFor: false,
RecentChanges: 20,
RecentChangesRSS: 10,
GzipCompressionLevel: 9,
@@ -39,5 +42,6 @@ func DefaultOptions() *ServerOptions {
ExternalBaseURL: "http://127.0.0.1/",
DeclareRSSLanguage: "en-GB",
DeclareRSSEmail: `nobody@example.com`,
ContentedServer: "",
}
}

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"database/sql"
@@ -14,6 +14,8 @@ import (
"time"
)
var SERVER_HEADER string = "YATWiki/0.0.0-devel"
type WikiServer struct {
db *WikiDB
opts *ServerOptions
@@ -37,7 +39,13 @@ func NewWikiServer(opts *ServerOptions) (*WikiServer, error) {
}
}
tmpl, err := template.New("yatwiki/page").Parse(pageTemplate)
tmpl := template.New("yatwiki/page")
tmpl.Funcs(map[string]interface{}{
"pathcomponent": func(s string) string {
return url.PathEscape(s)
},
})
_, err = tmpl.Parse(pageTemplate)
if err != nil {
return nil, err
}
@@ -73,7 +81,7 @@ func (this *WikiServer) Close() {
}
func (this *WikiServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Server", "YATWiki3")
w.Header().Set("Server", SERVER_HEADER)
if len(this.bans) > 0 {
remoteIP := RemoteAddrToIPAddress(r.RemoteAddr)
@@ -104,9 +112,13 @@ func (this *WikiServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write(content)
return
} else if remainingPath == "favicon.ico" && len(this.opts.FaviconFilePath) > 0 {
w.Header().Set("Content-Type", "image/x-icon")
http.ServeFile(w, r, this.opts.FaviconFilePath)
} else if remainingPath == "favicon.ico" {
if len(this.opts.FaviconFilePath) > 0 {
w.Header().Set("Content-Type", "image/x-icon")
http.ServeFile(w, r, this.opts.FaviconFilePath)
} else {
http.Error(w, "Not found", 404)
}
return
} else if remainingPath == "download-database" {
@@ -128,7 +140,7 @@ func (this *WikiServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
} else if remainingPath == "" {
this.serveRedirect(w, this.opts.ExpectBaseURL+`view/`+url.QueryEscape(this.opts.DefaultPage))
this.serveRedirect(w, this.opts.ExpectBaseURL+`view/`+url.PathEscape(this.opts.DefaultPage))
return
} else if remainingPath == "random" {
@@ -139,11 +151,11 @@ func (this *WikiServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
chosenArticle := titles[rand.Intn(len(titles))]
this.serveRedirect(w, this.opts.ExpectBaseURL+`view/`+url.QueryEscape(chosenArticle))
this.serveRedirect(w, this.opts.ExpectBaseURL+`view/`+url.PathEscape(chosenArticle))
return
} else if strings.HasPrefix(remainingPath, "view/") {
articleTitle, err := url.QueryUnescape(remainingPath[len("view/"):])
articleTitle, err := url.PathUnescape(remainingPath[len("view/"):])
if err != nil {
this.serveErrorMessage(w, err)
return
@@ -152,7 +164,7 @@ func (this *WikiServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
} else if strings.HasPrefix(remainingPath, "modify/") {
articleTitle, err := url.QueryUnescape(remainingPath[len("modify/"):])
articleTitle, err := url.PathUnescape(remainingPath[len("modify/"):])
if err != nil {
this.serveErrorMessage(w, err)
return
@@ -161,7 +173,7 @@ func (this *WikiServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
} else if strings.HasPrefix(remainingPath, "history/") {
articleTitle, err := url.QueryUnescape(remainingPath[len("history/"):])
articleTitle, err := url.PathUnescape(remainingPath[len("history/"):])
if err != nil {
this.serveErrorMessage(w, err)
return
@@ -255,13 +267,13 @@ func (this *WikiServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
err = this.db.SaveArticle(title, Author(r), body, int64(expectRev))
err = this.db.SaveArticle(title, Author(r, this.opts.TrustXForwardedFor), body, int64(expectRev))
if err != nil {
this.serveErrorMessage(w, err)
return
}
this.serveRedirect(w, this.opts.ExpectBaseURL+`view/`+url.QueryEscape(title))
this.serveRedirect(w, this.opts.ExpectBaseURL+`view/`+url.PathEscape(title))
return
}

View File

@@ -1,6 +1,6 @@
A semi-anonymous wiki for use in trusted environments.
As of the 20150901 release, a desktop version is available for Windows (based on PHPDesktop).
For the 20150901 release, a desktop version is available for Windows (based on PHPDesktop).
As of the 3.0 release, YATWiki is now a standalone server instead of a PHP script.
@@ -14,6 +14,7 @@ As of the 3.0 release, YATWiki is now a standalone server instead of a PHP scrip
- IP-based ban system
- Article index, random article, download database backup
- Source code highlighting (thanks [url=https://github.com/isagalaev/highlight.js]highlight.js[/url])
- Optional integration with `contented` for file/image uploads
Written in Golang, PHP
@@ -28,9 +29,38 @@ You can start YATWiki by running the binary. A default configuration file and da
Bind address (default "127.0.0.1:80")
`
=GO GET=
This package can be installed via go get: `go get code.ivysaur.me/yatwiki`
[go-get]code.ivysaur.me/yatwiki git https://git.ivysaur.me/code.ivysaur.me/yatwiki.git[/go-get]
=CHANGELOG=
2017-07-11 v3.0
2017-10-29 3.1.3
- Fix one more case of article title normalisation
2017-10-29 3.1.2
- Lock dependency versions
- Enhancement: Advertise build number in Server headers
- Fix a regression in 3.x series with not normalising article titles
- Fix server response if favicon is not configured
2017-10-15 3.1.1
- Update `contented` integration (requires `contented` >= 1.1.0)
2017-10-08 3.1.0
- Feature: Support content upload to a `contented` server
2017-08-11 3.0.2
- Fix an issue with XSS prevention for web browsers other than Chrome
2017-08-11 3.0.1
- Feature: New `TrustXForwardedFor` config option for usage behind reverse proxies
- Fix an issue with article titles containing `+`
- Fix an issue with `[html]` tags
- Fix an issue with viewing history for unknown articles
2017-07-11 3.0
- YATWiki was rewritten in Go.
- Enhancement: Standalone binary server
- Enhancement: No longer requires cookies for error messages
@@ -43,11 +73,13 @@ You can start YATWiki by running the binary. A default configuration file and da
- Fix a number of issues with handling of base URLs in links
- Fix a cosmetic issue with file caching for CSS content
2016-11-16 (no public release)
2016-11-16 20161116
- (no public release)
- Enhancement: Always open the formatting help in a new tab
- Fix a cosmetic issue with display of backslash characters caused by Meiryo font
2016-08-24 (no public release)
2016-08-24 20160824
- (no public release)
- Feature: Add Compare button to both top and bottom of article revision list
- Fix an issue with noncompliant HTML when comparing diffs

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"encoding/json"
@@ -45,10 +45,10 @@ func (this *BBCodeRenderer) bbcode(data string) string {
pregReplaceRule{regexp.MustCompile(`(?si)\[\*\]`), `</li><li>`, nil},
pregReplaceRule{regexp.MustCompile(`(?si)\[url=(.*?)\](.*?)\[/url\]`), `<a rel="noreferrer" href="$1">$2</a>`, nil},
pregReplaceRule{regexp.MustCompile(`(?si)\[article=(.*?)\](.*?)\[/article\]`), "", func(m []string) string {
return `<a href="` + template.HTMLEscapeString(this.baseUrl+`view/`+url.QueryEscape(m[1])) + `">` + m[2] + `</a>`
return `<a href="` + template.HTMLEscapeString(this.baseUrl+`view/`+url.PathEscape(m[1])) + `">` + m[2] + `</a>`
}},
pregReplaceRule{regexp.MustCompile(`(?si)\[rev=(.*?)\](.*?)\[/rev\]`), "", func(m []string) string {
return `<a href="` + template.HTMLEscapeString(this.baseUrl+`archive/`+url.QueryEscape(m[1])) + `">` + m[2] + `</a>`
return `<a href="` + template.HTMLEscapeString(this.baseUrl+`archive/`+url.PathEscape(m[1])) + `">` + m[2] + `</a>`
}},
pregReplaceRule{regexp.MustCompile(`(?si)\[imgur\](.*?)\.(...)\[/imgur\]`),
@@ -177,7 +177,7 @@ func (this *BBCodeRenderer) displayfmt(s string) string {
}
epos += spos
jsonInnerContent, _ := json.Marshal(s[spos : epos-spos])
jsonInnerContent, _ := json.Marshal(s[spos:epos])
ret += `<div class="html"><a href="javascript:;" onclick="` + template.HTMLEscapeString(`els(this, `+string(jsonInnerContent)+`);`) + `">` + this.DynamicContentWarning + `</a></div>`
hpos = epos + 7

View File

@@ -8,7 +8,7 @@ import (
"net/http"
"os"
"code.ivysaur.me/yatwiki3"
"code.ivysaur.me/yatwiki"
)
func main() {
@@ -17,13 +17,13 @@ func main() {
configPath := flag.String("config", "config.json", "Configuration file")
flag.Parse()
opts := yatwiki3.ServerOptions{}
opts := yatwiki.ServerOptions{}
cfg, err := ioutil.ReadFile(*configPath)
if err != nil {
if os.IsNotExist(err) {
opts = *yatwiki3.DefaultOptions()
opts = *yatwiki.DefaultOptions()
if cfg, err := json.MarshalIndent(opts, "", "\t"); err == nil {
err := ioutil.WriteFile(*configPath, cfg, 0644)
if err != nil {
@@ -43,7 +43,7 @@ func main() {
}
}
ws, err := yatwiki3.NewWikiServer(&opts)
ws, err := yatwiki.NewWikiServer(&opts)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)

View File

@@ -4,7 +4,7 @@ import (
"reflect"
"testing"
"code.ivysaur.me/yatwiki3/diff"
"code.ivysaur.me/yatwiki/diff"
)
func TestDiff(t *testing.T) {

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"bytes"

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"fmt"
@@ -17,7 +17,9 @@ type pageTemplateOptions struct {
LoadCodeResources bool
DefaultPage string
AllowDownload bool
SessionMessage template.HTML
SessionMessage string
PageNotExistsError bool
PageNotExistsTarget string
}
func DefaultPageTemplateOptions(opts *ServerOptions) *pageTemplateOptions {
@@ -85,13 +87,13 @@ function els(e,s){ // no js exec in innerHTML
</head>
<body>
<div class="header">
<a href="{{.BaseURL}}view/{{.DefaultPage | urlquery}}" title="Home"><div class="sprite hm"></div></a>
<a href="{{.BaseURL}}view/{{.DefaultPage | pathcomponent}}" title="Home"><div class="sprite hm"></div></a>
<a href="javascript:;" onclick="tid('spm');tid('tr1');tid('tr2');" title="Menu"><div class="sprite sp"></div></a>
<a href="{{.BaseURL}}modify/{{.NewArticleTitle | urlquery}}" title="New Page"><div class="sprite nw"></div></a>
<a href="{{.BaseURL}}modify/{{.NewArticleTitle | pathcomponent}}" title="New Page"><div class="sprite nw"></div></a>
{{if .CurrentPageIsArticle }}
<div class="sep"></div>
<a href="{{.BaseURL}}history/{{.CurrentPageName | urlquery}}" title="Page History"><div class="sprite hs"></div></a>
<a href="{{.BaseURL}}modify/{{.CurrentPageName | urlquery}}" title="Modify Page"><div class="sprite ed"></div></a>
<a href="{{.BaseURL}}history/{{.CurrentPageName | pathcomponent}}" title="Page History"><div class="sprite hs"></div></a>
<a href="{{.BaseURL}}modify/{{.CurrentPageName | pathcomponent}}" title="Modify Page"><div class="sprite ed"></div></a>
{{end}}
</div>
<div id="tr1" style="display:none;"></div>
@@ -105,6 +107,12 @@ function els(e,s){ // no js exec in innerHTML
{{end}}
</div>
<div class="content">
{{if .PageNotExistsError}}
<div class="info">
No such article exists.
<a href="{{.BaseURL}}modify/{{.PageNotExistsTarget | pathcomponent}}">Click here</a> to create it.
</div>
{{end}}
{{if len .SessionMessage}}
<div class="info">{{.SessionMessage}}</div>
{{end}}

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"database/sql"
@@ -30,7 +30,7 @@ func (this *WikiServer) routeArchive(w http.ResponseWriter, r *http.Request, rev
`<div class="info">`+
`You are viewing specific revision of this page, last modified `+
time.Unix(a.Modified, 0).In(this.loc).Format(this.opts.DateFormat)+`. `+
`Click <a href="`+template.HTMLEscapeString(this.opts.ExpectBaseURL+`view/`+url.QueryEscape(a.Title))+`">here</a> to see the latest revision.`+
`Click <a href="`+template.HTMLEscapeString(this.opts.ExpectBaseURL+`view/`+url.PathEscape(a.Title))+`">here</a> to see the latest revision.`+
`</div>`,
) + bcr.RenderHTML(string(a.Body))
pto.LoadCodeResources = bcr.CodePresent

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"bytes"
@@ -8,7 +8,7 @@ import (
"html/template"
"net/http"
"code.ivysaur.me/yatwiki3/diff"
"code.ivysaur.me/yatwiki/diff"
)
func (this *WikiServer) routeDiff(w http.ResponseWriter, r *http.Request, oldRev, newRev int) {

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"html/template"
@@ -8,12 +8,8 @@ import (
"time"
)
func (this *WikiServer) noSuchArticleError(title string) template.HTML {
return template.HTML(`No such article exists. <a href="` + this.opts.ExpectBaseURL + `modify/` + template.HTMLEscapeString(url.QueryEscape(title)) + `">Click here</a> to create it.`)
}
func (this *WikiServer) serveErrorMessage(w http.ResponseWriter, message error) {
this.serveErrorHTMLMessage(w, template.HTML(template.HTMLEscapeString(message.Error())))
func (this *WikiServer) serveErrorMessage(w http.ResponseWriter, err error) {
this.serveErrorText(w, err.Error())
}
func (this *WikiServer) serveInternalError(w http.ResponseWriter, r *http.Request, e error) {
@@ -21,8 +17,12 @@ func (this *WikiServer) serveInternalError(w http.ResponseWriter, r *http.Reques
http.Error(w, "An internal error occurred. Please ask an administrator to check the log file.", 500)
}
func (this *WikiServer) serveErrorHTMLMessage(w http.ResponseWriter, msg template.HTML) {
this.serveRedirect(w, this.opts.ExpectBaseURL+"view/"+url.QueryEscape(this.opts.DefaultPage)+"?error="+url.QueryEscape(string(msg)))
func (this *WikiServer) serveErrorText(w http.ResponseWriter, msg string) {
this.serveRedirect(w, this.opts.ExpectBaseURL+"view/"+url.PathEscape(this.opts.DefaultPage)+"?error="+url.QueryEscape(msg))
}
func (this *WikiServer) serveNoSuchArticle(w http.ResponseWriter, lookingFor string) {
this.serveRedirect(w, this.opts.ExpectBaseURL+"view/"+url.PathEscape(this.opts.DefaultPage)+"?notfound="+url.QueryEscape(lookingFor))
}
func (this *WikiServer) serveRedirect(w http.ResponseWriter, location string) {
@@ -32,7 +32,14 @@ func (this *WikiServer) serveRedirect(w http.ResponseWriter, location string) {
func (this *WikiServer) servePageResponse(w http.ResponseWriter, r *http.Request, pto *pageTemplateOptions) {
w.WriteHeader(200)
pto.SessionMessage = template.HTML(r.URL.Query().Get("error")) // FIXME reflected XSS (although Chrome automatically blocks it..)
if noSuchArticleTarget, ok := r.URL.Query()["notfound"]; ok {
pto.PageNotExistsError = true
pto.PageNotExistsTarget = noSuchArticleTarget[0]
} else {
pto.SessionMessage = r.URL.Query().Get("error")
}
err := this.pageTmp.Execute(w, pto)
if err != nil {
@@ -46,5 +53,5 @@ func (this *WikiServer) formatTimestamp(m int64) string {
}
func (this *WikiServer) viewLink(articleTitle string) template.HTML {
return template.HTML(`&quot;<a href="` + template.HTMLEscapeString(this.opts.ExpectBaseURL+`view/`+url.QueryEscape(articleTitle)) + `">` + template.HTMLEscapeString(articleTitle) + `</a>&quot;`)
return template.HTML(`&quot;<a href="` + template.HTMLEscapeString(this.opts.ExpectBaseURL+`view/`+url.PathEscape(articleTitle)) + `">` + template.HTMLEscapeString(articleTitle) + `</a>&quot;`)
}

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"net/http"

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"database/sql"
@@ -12,7 +12,7 @@ func (this *WikiServer) routeHistory(w http.ResponseWriter, r *http.Request, art
revs, err := this.db.GetRevisionHistory(articleTitle)
if err != nil {
if err == sql.ErrNoRows {
this.serveErrorHTMLMessage(w, this.noSuchArticleError(articleTitle))
this.serveNoSuchArticle(w, articleTitle)
return
}
@@ -20,12 +20,17 @@ func (this *WikiServer) routeHistory(w http.ResponseWriter, r *http.Request, art
return
}
if len(revs) == 0 {
this.serveNoSuchArticle(w, articleTitle)
return
}
pto := DefaultPageTemplateOptions(this.opts)
pto.CurrentPageName = articleTitle
pto.CurrentPageIsArticle = true
content := `<h2>Page History</h2><br>` +
`<em>There have been ` + fmt.Sprintf("%d", len(revs)) + ` edits to the page &quot;<a href="` + template.HTMLEscapeString(this.opts.ExpectBaseURL+`view/`+url.QueryEscape(articleTitle)) + `">` + template.HTMLEscapeString(articleTitle) + `</a>&quot;.</em>` +
`<em>There have been ` + fmt.Sprintf("%d", len(revs)) + ` edits to the page &quot;<a href="` + template.HTMLEscapeString(this.opts.ExpectBaseURL+`view/`+url.PathEscape(articleTitle)) + `">` + template.HTMLEscapeString(articleTitle) + `</a>&quot;.</em>` +
`<br><br>` +
`<form method="GET" action="` + template.HTMLEscapeString(this.opts.ExpectBaseURL+`diff`) + `">` +
`<table>`

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"fmt"
@@ -22,7 +22,7 @@ func (this *WikiServer) routeIndex(w http.ResponseWriter, r *http.Request) {
content := fmt.Sprintf(`<h2>Article Index</h2><br><em>There are %d edits to %d pages.</em><br><br><ul>`, totalRevs, len(titles))
for _, title := range titles {
content += `<li><a href="` + template.HTMLEscapeString(this.opts.ExpectBaseURL+`view/`+url.QueryEscape(title)) + `">` + template.HTMLEscapeString(title) + `</a></li>`
content += `<li><a href="` + template.HTMLEscapeString(this.opts.ExpectBaseURL+`view/`+url.PathEscape(title)) + `">` + template.HTMLEscapeString(title) + `</a></li>`
}
content += `</ul>`

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"database/sql"
@@ -32,7 +32,7 @@ func (this *WikiServer) routeModify(w http.ResponseWriter, r *http.Request, arti
pageTitleHTML = `Creating new article`
baseRev = 0
} else {
pageTitleHTML = `Editing article &quot;<a href="` + template.HTMLEscapeString(this.opts.ExpectBaseURL+`view/`+url.QueryEscape(articleTitle)) + `">` + template.HTMLEscapeString(articleTitle) + `</a>&quot;`
pageTitleHTML = `Editing article &quot;<a href="` + template.HTMLEscapeString(this.opts.ExpectBaseURL+`view/`+url.PathEscape(articleTitle)) + `">` + template.HTMLEscapeString(articleTitle) + `</a>&quot;`
baseRev = a.ID
existingBody = string(a.Body)
}
@@ -49,6 +49,24 @@ func (this *WikiServer) routeModify(w http.ResponseWriter, r *http.Request, arti
</label>
<input type="submit" value="Save &raquo;">
| <a href="` + template.HTMLEscapeString(this.opts.ExpectBaseURL+`formatting`) + `" target="_blank">formatting&nbsp;help</a>
`
if len(this.opts.ContentedServer) > 0 {
content += `
<script type="text/javascript" src="` + this.opts.ContentedServer + `sdk.js"></script>
| <a href="javascript:;" id="open-contented-uploader">upload...</a>
<script type="text/javascript">
document.getElementById("open-contented-uploader").addEventListener("click", function() {
contented.init("#contentctr", function(items) {
for (var i = 0; i < items.length; ++i) {
$("#contentctr textarea").append(" " + contented.getPreviewURL(items[i]) + " ");
}
});
});
</script>
`
}
content += `
</div>
<div id="contentctr"><textarea name="content">` + template.HTMLEscapeString(existingBody) + `</textarea></div>
</form>

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"fmt"
@@ -33,7 +33,7 @@ func (this *WikiServer) routeRecentChangesRSS(w http.ResponseWriter, r *http.Req
<author>` + template.HTMLEscapeString(this.opts.DeclareRSSEmail+` (`+this.opts.PageTitle+` `+a.Author+`)`) + `</author>
<pubDate>` + template.HTMLEscapeString(time.Unix(a.Modified, 0).In(this.loc).Format(time.RFC1123Z)) + `</pubDate>
<description>` + template.HTMLEscapeString(`
<a href="`+template.HTMLEscapeString(this.opts.ExternalBaseURL+`view/`+url.QueryEscape(a.Title))+`">latest version</a>
<a href="`+template.HTMLEscapeString(this.opts.ExternalBaseURL+`view/`+url.PathEscape(a.Title))+`">latest version</a>
|
<a href="`+template.HTMLEscapeString(this.opts.ExternalBaseURL+`archive/`+fmt.Sprintf("%d", a.ID))+`">revision `+fmt.Sprintf("%d", a.ID)+`</a>
|

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"database/sql"

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"errors"
@@ -41,7 +41,7 @@ func (this *WikiServer) routeRecentChanges(w http.ResponseWriter, r *http.Reques
`<table>`
for _, rev := range recents {
content += `<tr>` +
`<td><a href="` + template.HTMLEscapeString(this.opts.ExpectBaseURL+`view/`+url.QueryEscape(rev.Title)) + `">` + template.HTMLEscapeString(rev.Title) + `</a>` +
`<td><a href="` + template.HTMLEscapeString(this.opts.ExpectBaseURL+`view/`+url.PathEscape(rev.Title)) + `">` + template.HTMLEscapeString(rev.Title) + `</a>` +
` [<a href="` + template.HTMLEscapeString(this.opts.ExpectBaseURL+`archive/`+fmt.Sprintf("%d", rev.ID)) + `">a</a>]` +
`</td>` +
`<td>` + this.formatTimestamp(rev.Modified) + ` by ` + template.HTMLEscapeString(rev.Author) + `</td>` +

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"database/sql"
@@ -15,11 +15,11 @@ func (this *WikiServer) routeView(w http.ResponseWriter, r *http.Request, articl
// If this was an old link, it might not be present.
// Redirect if possible
if len(articleTitle) > 0 && articleTitle[len(articleTitle)-1] == '/' {
this.serveRedirect(w, this.opts.ExpectBaseURL+"view/"+url.QueryEscape(articleTitle[0:len(articleTitle)-1]))
this.serveRedirect(w, this.opts.ExpectBaseURL+"view/"+url.PathEscape(articleTitle[0:len(articleTitle)-1]))
return
}
this.serveErrorHTMLMessage(w, this.noSuchArticleError(articleTitle))
this.serveNoSuchArticle(w, articleTitle)
return
}
this.serveErrorMessage(w, err)

View File

@@ -1,4 +1,4 @@
package yatwiki3
package yatwiki
import (
"regexp"

File diff suppressed because one or more lines are too long