diff options
author | Daniel Baumann <daniel@debian.org> | 2024-10-18 20:33:49 +0200 |
---|---|---|
committer | Daniel Baumann <daniel@debian.org> | 2024-12-12 23:57:56 +0100 |
commit | e68b9d00a6e05b3a941f63ffb696f91e554ac5ec (patch) | |
tree | 97775d6c13b0f416af55314eb6a89ef792474615 /services/wiki/wiki_path.go | |
parent | Initial commit. (diff) | |
download | forgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.tar.xz forgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.zip |
Adding upstream version 9.0.3.
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to '')
-rw-r--r-- | services/wiki/wiki_path.go | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/services/wiki/wiki_path.go b/services/wiki/wiki_path.go new file mode 100644 index 0000000..74c7064 --- /dev/null +++ b/services/wiki/wiki_path.go @@ -0,0 +1,172 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package wiki + +import ( + "net/url" + "path" + "strings" + + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/git" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/convert" +) + +// To define the wiki related concepts: +// * Display Segment: the text what user see for a wiki page (aka, the title): +// - "Home Page" +// - "100% Free" +// - "2000-01-02 meeting" +// * Web Path: +// - "/wiki/Home-Page" +// - "/wiki/100%25+Free" +// - "/wiki/2000-01-02+meeting.-" +// - If a segment has a suffix "DashMarker(.-)", it means that there is no dash-space conversion for this segment. +// - If a WebPath is a "*.md" pattern, then use the unescaped value directly as GitPath, to make users can access the raw file. +// * Git Path (only space doesn't need to be escaped): +// - "/.wiki.git/Home-Page.md" +// - "/.wiki.git/100%25 Free.md" +// - "/.wiki.git/2000-01-02 meeting.-.md" +// TODO: support subdirectory in the future +// +// Although this package now has the ability to support subdirectory, but the route package doesn't: +// * Double-escaping problem: the URL "/wiki/abc%2Fdef" becomes "/wiki/abc/def" by ctx.Params, which is incorrect +// * This problem should have been 99% fixed, but it needs more tests. +// * The old wiki code's behavior is always using %2F, instead of subdirectory, so there are a lot of legacy "%2F" files in user wikis. + +type WebPath string + +var reservedWikiNames = []string{"_pages", "_new", "_edit", "raw"} + +func validateWebPath(name WebPath) error { + for _, s := range WebPathSegments(name) { + if util.SliceContainsString(reservedWikiNames, s) { + return repo_model.ErrWikiReservedName{Title: s} + } + } + return nil +} + +func hasDashMarker(s string) bool { + return strings.HasSuffix(s, ".-") +} + +func removeDashMarker(s string) string { + return strings.TrimSuffix(s, ".-") +} + +func addDashMarker(s string) string { + return s + ".-" +} + +func unescapeSegment(s string) (string, error) { + if hasDashMarker(s) { + s = removeDashMarker(s) + } else { + s = strings.ReplaceAll(s, "-", " ") + } + unescaped, err := url.QueryUnescape(s) + if err != nil { + return s, err // un-escaping failed, but it's still safe to return the original string, because it is only a title for end users + } + return unescaped, nil +} + +func escapeSegToWeb(s string, hadDashMarker bool) string { + if hadDashMarker || strings.Contains(s, "-") || strings.HasSuffix(s, ".md") { + s = addDashMarker(s) + } else { + s = strings.ReplaceAll(s, " ", "-") + } + s = url.QueryEscape(s) + return s +} + +func WebPathSegments(s WebPath) []string { + a := strings.Split(string(s), "/") + for i := range a { + a[i], _ = unescapeSegment(a[i]) + } + return a +} + +func WebPathToGitPath(s WebPath) string { + if strings.HasSuffix(string(s), ".md") { + ret, _ := url.PathUnescape(string(s)) + return util.PathJoinRelX(ret) + } + + a := strings.Split(string(s), "/") + for i := range a { + shouldAddDashMarker := hasDashMarker(a[i]) + a[i], _ = unescapeSegment(a[i]) + a[i] = escapeSegToWeb(a[i], shouldAddDashMarker) + a[i] = strings.ReplaceAll(a[i], "%20", " ") // space is safe to be kept in git path + a[i] = strings.ReplaceAll(a[i], "+", " ") + } + return strings.Join(a, "/") + ".md" +} + +func GitPathToWebPath(s string) (wp WebPath, err error) { + if !strings.HasSuffix(s, ".md") { + return "", repo_model.ErrWikiInvalidFileName{FileName: s} + } + s = strings.TrimSuffix(s, ".md") + a := strings.Split(s, "/") + for i := range a { + shouldAddDashMarker := hasDashMarker(a[i]) + if a[i], err = unescapeSegment(a[i]); err != nil { + return "", err + } + a[i] = escapeSegToWeb(a[i], shouldAddDashMarker) + } + return WebPath(strings.Join(a, "/")), nil +} + +func WebPathToUserTitle(s WebPath) (dir, display string) { + dir = path.Dir(string(s)) + display = path.Base(string(s)) + if strings.HasSuffix(display, ".md") { + display = strings.TrimSuffix(display, ".md") + display, _ = url.PathUnescape(display) + } + display, _ = unescapeSegment(display) + return dir, display +} + +func WebPathToURLPath(s WebPath) string { + return string(s) +} + +func WebPathFromRequest(s string) WebPath { + s = util.PathJoinRelX(s) + // The old wiki code's behavior is always using %2F, instead of subdirectory. + s = strings.ReplaceAll(s, "/", "%2F") + return WebPath(s) +} + +func UserTitleToWebPath(base, title string) WebPath { + // TODO: no support for subdirectory, because the old wiki code's behavior is always using %2F, instead of subdirectory. + // So we do not add the support for writing slashes in title at the moment. + title = strings.TrimSpace(title) + title = util.PathJoinRelX(base, escapeSegToWeb(title, false)) + if title == "" || title == "." { + title = "unnamed" + } + return WebPath(title) +} + +// ToWikiPageMetaData converts meta information to a WikiPageMetaData +func ToWikiPageMetaData(wikiName WebPath, lastCommit *git.Commit, repo *repo_model.Repository) *api.WikiPageMetaData { + subURL := string(wikiName) + _, title := WebPathToUserTitle(wikiName) + return &api.WikiPageMetaData{ + Title: title, + HTMLURL: util.URLJoin(repo.HTMLURL(), "wiki", subURL), + SubURL: subURL, + LastCommit: convert.ToWikiCommit(lastCommit), + } +} |