Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
78cb09deda | |||
|
0f35cb5a2a | ||
|
0b3d6c399c | ||
|
f98a1b851c | ||
|
e75594f7a6 | ||
a1c0b3a02e | |||
6624f257d3 | |||
|
35db5a373b | ||
5043ad54c7 | |||
727435743a | |||
|
829b807a91 | ||
874cdcc974 |
37
CHANGELOG.md
37
CHANGELOG.md
@ -4,14 +4,26 @@ This changelog goes through all the changes that have been made in each release
|
||||
without substantial changes to our git log; to see the highlights of what has
|
||||
been added to each release, please refer to the [blog](https://blog.gitea.com).
|
||||
|
||||
## [1.21.7](https://github.com/go-gitea/gitea/releases/tag/1.21.7) - 2024-02-26
|
||||
|
||||
* ENHANCEMENTS
|
||||
* Users with `read` permission of pull requests can be assigned too (#27263) (#29372)
|
||||
* BUGFIXES
|
||||
* Do not double close reader (#29354) (#29370)
|
||||
* Display friendly error message (#29105) (#29363)
|
||||
* Fix project counter in organization/individual profile (#28068) (#29361)
|
||||
* Fix validity of the FROM email address not being checked (#29347) (#29360)
|
||||
* Fix tarball/zipball download bug (#29342) (#29352)
|
||||
* DOCS
|
||||
* Docker Tag Information in Docs (#29047) (#29362)
|
||||
* MISC
|
||||
* Enforce maxlength in frontend (#29389) (#29396)
|
||||
|
||||
## [1.21.6](https://github.com/go-gitea/gitea/releases/tag/v1.21.6) - 2024-02-22
|
||||
|
||||
* SECURITY
|
||||
* Fix XSS vulnerabilities (#29336)
|
||||
* Use general token signing secret (#29205) (#29325)
|
||||
* API
|
||||
* Refactor issue template parsing and fix API endpoint (#29069) (#29140)
|
||||
* Fix swift packages not resolving (#29095) (#29102)
|
||||
* ENHANCEMENTS
|
||||
* Refactor git version functions and check compatibility (#29155) (#29157)
|
||||
* Improve user experience for outdated comments (#29050) (#29086)
|
||||
@ -19,7 +31,11 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
|
||||
* Wrap contained tags and branches again (#29021) (#29026)
|
||||
* Fix incorrect button CSS usages (#29015) (#29023)
|
||||
* Strip trailing newline in markdown code copy (#29019) (#29022)
|
||||
* Implement some action notifier functions (#29173) (#29308)
|
||||
* Load outdated comments when (un)resolving conversation on PR timeline (#29203) (#29221)
|
||||
* BUGFIXES
|
||||
* Refactor issue template parsing and fix API endpoint (#29069) (#29140)
|
||||
* Fix swift packages not resolving (#29095) (#29102)
|
||||
* Remove SSH workaround (#27893) (#29332)
|
||||
* Only log error when tag sync fails (#29295) (#29327)
|
||||
* Fix SSPI user creation (#28948) (#29323)
|
||||
@ -44,18 +60,15 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
|
||||
* Avoid showing unnecessary JS errors when there are elements with different origin on the page (#29081) (#29089)
|
||||
* Fix gitea-origin-url with default ports (#29085) (#29088)
|
||||
* Fix orgmode link resolving (#29024) (#29076)
|
||||
* Fix: Elasticsearch: Request Entity Too Large #28117 (#29062) (#29075)
|
||||
* Fix Elasticsearh Request Entity Too Large #28117 (#29062) (#29075)
|
||||
* Do not render empty comments (#29039) (#29049)
|
||||
* Avoid sending update/delete release notice when it is draft (#29008) (#29025)
|
||||
* DOCS
|
||||
* Rm outdated docs from some languages (#27530) (#29208)
|
||||
* MISC
|
||||
* Implement some action notifier functions (#29173) (#29308)
|
||||
* Fix gitea-action user avatar broken on edited menu (#29190) (#29307)
|
||||
* Disallow merge when required checked are missing (#29143) (#29268)
|
||||
* Convert visibility to number (#29226) (#29244)
|
||||
* Load outdated comments when (un)resolving conversation on PR timeline (#29203) (#29221)
|
||||
* Fix incorrect link to swift doc and swift package-registry login command (#29096) (#29103)
|
||||
* Convert visibility to number (#29226) (#29244)
|
||||
* DOCS
|
||||
* Remove outdated docs from some languages (#27530) (#29208)
|
||||
* Fix typos in the documentation (#29048) (#29056)
|
||||
* Explained where create issue/PR template (#29035)
|
||||
|
||||
@ -174,7 +187,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
|
||||
* Fix Chinese translation of config cheat sheet[API] (#28472) (#28473)
|
||||
* Retry SSH key verification with additional CRLF if it failed (#28392) (#28464)
|
||||
|
||||
## [1.21.2](https://github.com/go-gitea/gitea/releases/tag/1.21.2) - 2023-12-12
|
||||
## [1.21.2](https://github.com/go-gitea/gitea/releases/tag/v1.21.2) - 2023-12-12
|
||||
|
||||
* SECURITY
|
||||
* Rebuild with recently released golang version
|
||||
@ -213,7 +226,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
|
||||
* Use full width for project boards (#28225) (#28245)
|
||||
* Enable system users search via the API (#28013) (#28018)
|
||||
|
||||
## [1.21.1](https://github.com/go-gitea/gitea/releases/tag/1.21.1) - 2023-11-26
|
||||
## [1.21.1](https://github.com/go-gitea/gitea/releases/tag/v1.21.1) - 2023-11-26
|
||||
|
||||
* SECURITY
|
||||
* Fix comment permissions (#28213) (#28216)
|
||||
|
@ -39,6 +39,16 @@ Images must follow this naming convention:
|
||||
|
||||
`{registry}/{owner}/{image}`
|
||||
|
||||
When building your docker image, using the naming convention above, this looks like:
|
||||
|
||||
```shell
|
||||
# build an image with tag
|
||||
docker build -t {registry}/{owner}/{image}:{tag} .
|
||||
# name an existing image with tag
|
||||
docker tag {some-existing-image}:{tag} {registry}/{owner}/{image}:{tag}
|
||||
```
|
||||
|
||||
where your registry is the domain of your gitea instance (e.g. gitea.example.com).
|
||||
For example, these are all valid image names for the owner `testuser`:
|
||||
|
||||
`gitea.example.com/testuser/myimage`
|
||||
|
@ -332,7 +332,6 @@ func HasAccessUnit(ctx context.Context, user *user_model.User, repo *repo_model.
|
||||
|
||||
// CanBeAssigned return true if user can be assigned to issue or pull requests in repo
|
||||
// Currently any write access (code, issues or pr's) is assignable, to match assignee list in user interface.
|
||||
// FIXME: user could send PullRequest also could be assigned???
|
||||
func CanBeAssigned(ctx context.Context, user *user_model.User, repo *repo_model.Repository, _ bool) (bool, error) {
|
||||
if user.IsOrganization() {
|
||||
return false, fmt.Errorf("Organization can't be added as assignee [user_id: %d, repo_id: %d]", user.ID, repo.ID)
|
||||
@ -341,7 +340,8 @@ func CanBeAssigned(ctx context.Context, user *user_model.User, repo *repo_model.
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return perm.CanAccessAny(perm_model.AccessModeWrite, unit.TypeCode, unit.TypeIssues, unit.TypePullRequests), nil
|
||||
return perm.CanAccessAny(perm_model.AccessModeWrite, unit.AllRepoUnitTypes...) ||
|
||||
perm.CanAccessAny(perm_model.AccessModeRead, unit.TypePullRequests), nil
|
||||
}
|
||||
|
||||
// HasAccess returns true if user has access to repo
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
@ -78,7 +79,8 @@ func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.Us
|
||||
if err = e.Table("team_user").
|
||||
Join("INNER", "team_repo", "`team_repo`.team_id = `team_user`.team_id").
|
||||
Join("INNER", "team_unit", "`team_unit`.team_id = `team_user`.team_id").
|
||||
Where("`team_repo`.repo_id = ? AND `team_unit`.access_mode >= ?", repo.ID, perm.AccessModeWrite).
|
||||
Where("`team_repo`.repo_id = ? AND (`team_unit`.access_mode >= ? OR (`team_unit`.access_mode = ? AND `team_unit`.`type` = ?))",
|
||||
repo.ID, perm.AccessModeWrite, perm.AccessModeRead, unit.TypePullRequests).
|
||||
Distinct("`team_user`.uid").
|
||||
Select("`team_user`.uid").
|
||||
Find(&additionalUserIDs); err != nil {
|
||||
|
@ -102,7 +102,17 @@ func (b *blobReader) Read(p []byte) (n int, err error) {
|
||||
|
||||
// Close implements io.Closer
|
||||
func (b *blobReader) Close() error {
|
||||
if b.rd == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
defer b.cancel()
|
||||
|
||||
return DiscardFull(b.rd, b.n+1)
|
||||
if err := DiscardFull(b.rd, b.n+1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b.rd = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -246,6 +246,7 @@ email_title = Email Settings
|
||||
smtp_addr = SMTP Host
|
||||
smtp_port = SMTP Port
|
||||
smtp_from = Send Email As
|
||||
smtp_from_invalid = The "Send Email As" address is invalid
|
||||
smtp_from_helper = Email address Gitea will use. Enter a plain email address or use the "Name" <email@example.com> format.
|
||||
mailer_user = SMTP Username
|
||||
mailer_password = SMTP Password
|
||||
|
@ -7,6 +7,7 @@ package install
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/mail"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@ -417,6 +418,11 @@ func SubmitInstall(ctx *context.Context) {
|
||||
}
|
||||
|
||||
if len(strings.TrimSpace(form.SMTPAddr)) > 0 {
|
||||
if _, err := mail.ParseAddress(form.SMTPFrom); err != nil {
|
||||
ctx.RenderWithErr(ctx.Tr("install.smtp_from_invalid"), tplInstall, &form)
|
||||
return
|
||||
}
|
||||
|
||||
cfg.Section("mailer").Key("ENABLED").SetValue("true")
|
||||
cfg.Section("mailer").Key("SMTP_ADDR").SetValue(form.SMTPAddr)
|
||||
cfg.Section("mailer").Key("SMTP_PORT").SetValue(form.SMTPPort)
|
||||
|
@ -61,17 +61,17 @@ func List(ctx *context.Context) {
|
||||
|
||||
var workflows []Workflow
|
||||
if empty, err := ctx.Repo.GitRepo.IsEmpty(); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
ctx.ServerError("IsEmpty", err)
|
||||
return
|
||||
} else if !empty {
|
||||
commit, err := ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
ctx.ServerError("GetBranchCommit", err)
|
||||
return
|
||||
}
|
||||
entries, err := actions.ListWorkflows(commit)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
ctx.ServerError("ListWorkflows", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ func List(ctx *context.Context) {
|
||||
workflow := Workflow{Entry: *entry}
|
||||
content, err := actions.GetContentFromEntry(entry)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
ctx.ServerError("GetContentFromEntry", err)
|
||||
return
|
||||
}
|
||||
wf, err := model.ReadWorkflow(bytes.NewReader(content))
|
||||
@ -173,7 +173,7 @@ func List(ctx *context.Context) {
|
||||
|
||||
runs, total, err := actions_model.FindRuns(ctx, opts)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
ctx.ServerError("FindAndCount", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -182,7 +182,7 @@ func List(ctx *context.Context) {
|
||||
}
|
||||
|
||||
if err := runs.LoadTriggerUser(ctx); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
ctx.ServerError("LoadTriggerUser", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -190,7 +190,7 @@ func List(ctx *context.Context) {
|
||||
|
||||
actors, err := actions_model.GetActors(ctx, ctx.Repo.Repository.ID)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
ctx.ServerError("GetActors", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["Actors"] = repo.MakeSelfOnTop(ctx.Doer, actors)
|
||||
|
@ -161,9 +161,6 @@ func editFile(ctx *context.Context, isNewFile bool) {
|
||||
}
|
||||
|
||||
d, _ := io.ReadAll(dataRc)
|
||||
if err := dataRc.Close(); err != nil {
|
||||
log.Error("Error whilst closing blob data: %v", err)
|
||||
}
|
||||
|
||||
buf = append(buf, d...)
|
||||
if content, err := charset.ToUTF8(buf, charset.ConvertOpts{KeepBOM: true}); err != nil {
|
||||
|
@ -6,6 +6,7 @@ package user
|
||||
import (
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
project_model "code.gitea.io/gitea/models/project"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
@ -125,5 +126,21 @@ func LoadHeaderCount(ctx *context.Context) error {
|
||||
}
|
||||
ctx.Data["RepoCount"] = repoCount
|
||||
|
||||
var projectType project_model.Type
|
||||
if ctx.ContextUser.IsOrganization() {
|
||||
projectType = project_model.TypeOrganization
|
||||
} else {
|
||||
projectType = project_model.TypeIndividual
|
||||
}
|
||||
projectCount, err := project_model.CountProjects(ctx, project_model.SearchOptions{
|
||||
OwnerID: ctx.ContextUser.ID,
|
||||
IsClosed: util.OptionalBoolOf(false),
|
||||
Type: projectType,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.Data["ProjectCount"] = projectCount
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ func isContainerPath(req *http.Request) bool {
|
||||
var (
|
||||
gitRawOrAttachPathRe = regexp.MustCompile(`^/[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+/(?:(?:git-(?:(?:upload)|(?:receive))-pack$)|(?:info/refs$)|(?:HEAD$)|(?:objects/)|(?:raw/)|(?:releases/download/)|(?:attachments/))`)
|
||||
lfsPathRe = regexp.MustCompile(`^/[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+/info/lfs/`)
|
||||
archivePathRe = regexp.MustCompile(`^/[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+/archive/`)
|
||||
)
|
||||
|
||||
func isGitRawOrAttachPath(req *http.Request) bool {
|
||||
@ -54,6 +55,10 @@ func isGitRawOrAttachOrLFSPath(req *http.Request) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func isArchivePath(req *http.Request) bool {
|
||||
return archivePathRe.MatchString(req.URL.Path)
|
||||
}
|
||||
|
||||
// handleSignIn clears existing session variables and stores new ones for the specified user object
|
||||
func handleSignIn(resp http.ResponseWriter, req *http.Request, sess SessionStore, user *user_model.User) {
|
||||
// We need to regenerate the session...
|
||||
|
@ -133,7 +133,7 @@ func (o *OAuth2) userIDFromToken(ctx context.Context, tokenSHA string, store Dat
|
||||
func (o *OAuth2) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) {
|
||||
// These paths are not API paths, but we still want to check for tokens because they maybe in the API returned URLs
|
||||
if !middleware.IsAPIPath(req) && !isAttachmentDownload(req) && !isAuthenticatedTokenRequest(req) &&
|
||||
!isGitRawOrAttachPath(req) {
|
||||
!isGitRawOrAttachPath(req) && !isArchivePath(req) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,9 @@
|
||||
{{if .CanReadProjects}}
|
||||
<a class="{{if .PageIsViewProjects}}active {{end}}item" href="{{$.Org.HomeLink}}/-/projects">
|
||||
{{svg "octicon-project-symlink"}} {{ctx.Locale.Tr "user.projects"}}
|
||||
{{if .ProjectCount}}
|
||||
<div class="ui small label">{{.ProjectCount}}</div>
|
||||
{{end}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{if and .IsPackageEnabled .CanReadPackages}}
|
||||
|
@ -13,7 +13,7 @@
|
||||
<a class="item" href="{{$.RepoLink}}/commit/{{PathEscape .Commit.ID.String}}.diff" download="{{ShortSha .Commit.ID.String}}.diff">{{ctx.Locale.Tr "repo.diff.download_diff"}}</a>
|
||||
{{end}}
|
||||
<a id="expand-files-btn" class="item">{{ctx.Locale.Tr "repo.pulls.expand_files"}}</a>
|
||||
<a id="collapse-files-btn"class="item">{{ctx.Locale.Tr "repo.pulls.collapse_files"}}</a>
|
||||
<a id="collapse-files-btn" class="item">{{ctx.Locale.Tr "repo.pulls.collapse_files"}}</a>
|
||||
{{if .Issue.Index}}
|
||||
{{if .ShowOutdatedComments}}
|
||||
<a class="item" href="?style={{if $.IsSplitStyle}}split{{else}}unified{{end}}&whitespace={{$.WhitespaceBehavior}}&show-outdated=false">
|
||||
|
@ -9,7 +9,7 @@
|
||||
{{ctx.Locale.Tr "repo.editor.commit_changes"}}
|
||||
{{- end}}</h3>
|
||||
<div class="field">
|
||||
<input name="commit_summary" placeholder="{{if .PageIsDelete}}{{ctx.Locale.Tr "repo.editor.delete" .TreePath}}{{else if .PageIsUpload}}{{ctx.Locale.Tr "repo.editor.upload_files_to_dir" .TreePath}}{{else if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.add_tmpl"}}{{else if .PageIsPatch}}{{ctx.Locale.Tr "repo.editor.patch"}}{{else}}{{ctx.Locale.Tr "repo.editor.update" .TreePath}}{{end}}" value="{{.commit_summary}}" autofocus>
|
||||
<input name="commit_summary" maxlength="100" placeholder="{{if .PageIsDelete}}{{ctx.Locale.Tr "repo.editor.delete" .TreePath}}{{else if .PageIsUpload}}{{ctx.Locale.Tr "repo.editor.upload_files_to_dir" .TreePath}}{{else if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.add_tmpl"}}{{else if .PageIsPatch}}{{ctx.Locale.Tr "repo.editor.patch"}}{{else}}{{ctx.Locale.Tr "repo.editor.update" .TreePath}}{{end}}" value="{{.commit_summary}}" autofocus>
|
||||
</div>
|
||||
<div class="field">
|
||||
<textarea name="commit_message" placeholder="{{ctx.Locale.Tr "repo.editor.commit_message_desc"}}" rows="5">{{.commit_message}}</textarea>
|
||||
@ -60,7 +60,7 @@
|
||||
<div class="quick-pull-branch-name {{if not (eq .commit_choice "commit-to-new-branch")}}gt-hidden{{end}}">
|
||||
<div class="new-branch-name-input field {{if .Err_NewBranchName}}error{{end}}">
|
||||
{{svg "octicon-git-branch"}}
|
||||
<input type="text" name="new_branch_name" value="{{.new_branch_name}}" class="input-contrast gt-mr-2 js-quick-pull-new-branch-name" placeholder="{{ctx.Locale.Tr "repo.editor.new_branch_name_desc"}}" {{if eq .commit_choice "commit-to-new-branch"}}required{{end}} title="{{ctx.Locale.Tr "repo.editor.new_branch_name"}}">
|
||||
<input type="text" name="new_branch_name" maxlength="100" value="{{.new_branch_name}}" class="input-contrast gt-mr-2 js-quick-pull-new-branch-name" placeholder="{{ctx.Locale.Tr "repo.editor.new_branch_name_desc"}}" {{if eq .commit_choice "commit-to-new-branch"}}required{{end}} title="{{ctx.Locale.Tr "repo.editor.new_branch_name"}}">
|
||||
<span class="text-muted js-quick-pull-normalization-info"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -15,7 +15,7 @@
|
||||
{{range $i, $v := .TreeNames}}
|
||||
<div class="breadcrumb-divider">/</div>
|
||||
{{if eq $i $l}}
|
||||
<input id="file-name" value="{{$v}}" placeholder="{{ctx.Locale.Tr "repo.editor.name_your_file"}}" data-editorconfig="{{$.EditorconfigJson}}" required autofocus>
|
||||
<input id="file-name" maxlength="500" value="{{$v}}" placeholder="{{ctx.Locale.Tr "repo.editor.name_your_file"}}" data-editorconfig="{{$.EditorconfigJson}}" required autofocus>
|
||||
<span data-tooltip-content="{{ctx.Locale.Tr "repo.editor.filename_help"}}">{{svg "octicon-info"}}</span>
|
||||
{{else}}
|
||||
<span class="section"><a href="{{$.BranchLink}}/{{index $.TreePaths $i | PathEscapeSegments}}">{{$v}}</a></span>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<a class="section" href="{{$.BranchLink}}">{{.BranchName}}</a>
|
||||
<span>{{ctx.Locale.Tr "repo.editor.or"}} <a href="{{$.BranchLink}}">{{ctx.Locale.Tr "repo.editor.cancel_lower"}}</a></span>
|
||||
<input type="hidden" id="tree_path" name="tree_path" value="" required>
|
||||
<input id="file-name" type="hidden" value="diff.patch">
|
||||
<input id="file-name" maxlength="500" type="hidden" value="diff.patch">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
|
@ -13,7 +13,7 @@
|
||||
{{range $i, $v := .TreeNames}}
|
||||
<div class="breadcrumb-divider">/</div>
|
||||
{{if eq $i $l}}
|
||||
<input type="text" id="file-name" value="{{$v}}" placeholder="{{ctx.Locale.Tr "repo.editor.add_subdir"}}" autofocus>
|
||||
<input type="text" id="file-name" maxlength="500" value="{{$v}}" placeholder="{{ctx.Locale.Tr "repo.editor.add_subdir"}}" autofocus>
|
||||
<span data-tooltip-content="{{ctx.Locale.Tr "repo.editor.filename_help"}}">{{svg "octicon-info"}}</span>
|
||||
{{else}}
|
||||
<span class="section"><a href="{{$.BranchLink}}/{{index $.TreePaths $i | PathEscapeSegments}}">{{$v}}</a></span>
|
||||
|
@ -13,6 +13,9 @@
|
||||
{{if or .ContextUser.IsIndividual (and .ContextUser.IsOrganization .CanReadProjects)}}
|
||||
<a href="{{.ContextUser.HomeLink}}/-/projects" class="{{if .PageIsViewProjects}}active {{end}}item">
|
||||
{{svg "octicon-project-symlink"}} {{ctx.Locale.Tr "user.projects"}}
|
||||
{{if .ProjectCount}}
|
||||
<div class="ui small label">{{.ProjectCount}}</div>
|
||||
{{end}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{if and .IsPackageEnabled (or .ContextUser.IsIndividual (and .ContextUser.IsOrganization .CanReadPackages))}}
|
||||
|
@ -5,7 +5,7 @@ package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"html"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@ -27,7 +27,7 @@ import (
|
||||
func TestXSSUserFullName(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
const fullName = `name & <script class="evil">alert('Oh no!');</script>`
|
||||
const fullName = `name & <script class="evil">alert('xss');</script>`
|
||||
|
||||
session := loginUser(t, user.Name)
|
||||
req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{
|
||||
@ -43,58 +43,55 @@ func TestXSSUserFullName(t *testing.T) {
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
assert.EqualValues(t, 0, htmlDoc.doc.Find("script.evil").Length())
|
||||
assert.EqualValues(t, fullName,
|
||||
htmlDoc.doc.Find("div.content").Find(".header.text.center").Text(),
|
||||
)
|
||||
htmlCode, err := htmlDoc.doc.Find("div.content").Find(".header.text.center").Html()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, html.EscapeString(fullName), htmlCode)
|
||||
}
|
||||
|
||||
func TestXSSWikiLastCommitInfo(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
// Prepare the environment.
|
||||
dstPath := t.TempDir()
|
||||
r := fmt.Sprintf("%suser2/repo1.wiki.git", u.String())
|
||||
u, err := url.Parse(r)
|
||||
cloneWikiURL, err := url.Parse(u.String() + "user2/repo1.wiki.git")
|
||||
assert.NoError(t, err)
|
||||
u.User = url.UserPassword("user2", userPassword)
|
||||
assert.NoError(t, git.CloneWithArgs(context.Background(), git.AllowLFSFiltersArgs(), u.String(), dstPath, git.CloneRepoOptions{}))
|
||||
cloneWikiURL.User = url.UserPassword("user2", userPassword)
|
||||
assert.NoError(t, git.CloneWithArgs(context.Background(), git.AllowLFSFiltersArgs(), cloneWikiURL.String(), dstPath, git.CloneRepoOptions{}))
|
||||
|
||||
// Use go-git here, because using git wouldn't work, it has code to remove
|
||||
// `<`, `>` and `\n` in user names. Even though this is permitted and
|
||||
// wouldn't result in a error by a Git server.
|
||||
gitRepo, err := gogit.PlainOpen(dstPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
w, err := gitRepo.Worktree()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
filename := filepath.Join(dstPath, "Home.md")
|
||||
err = os.WriteFile(filename, []byte("Oh, a XSS attack?"), 0o644)
|
||||
err = os.WriteFile(filename, []byte("dummy content"), 0o644)
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
return
|
||||
}
|
||||
|
||||
_, err = w.Add("Home.md")
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
return
|
||||
}
|
||||
|
||||
_, err = w.Commit("Yay XSS", &gogit.CommitOptions{
|
||||
_, err = w.Commit("dummy message", &gogit.CommitOptions{
|
||||
Author: &object.Signature{
|
||||
Name: `Gusted <script class="evil">alert('Oh no!');</script>`,
|
||||
Name: `foo<script class="evil">alert('xss');</script>bar`,
|
||||
Email: "valid@example.org",
|
||||
When: time.Date(2024, time.January, 31, 0, 0, 0, 0, time.UTC),
|
||||
When: time.Date(2001, time.January, 31, 0, 0, 0, 0, time.UTC),
|
||||
},
|
||||
})
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
return
|
||||
}
|
||||
|
||||
// Push.
|
||||
_, _, err = git.NewCommand(git.DefaultContext, "push").AddArguments(git.ToTrustedCmdArgs([]string{"origin", "master"})...).RunStdString(&git.RunOpts{Dir: dstPath})
|
||||
_, _, err = git.NewCommand(git.DefaultContext, "push").AddArguments("origin", "master").RunStdString(&git.RunOpts{Dir: dstPath})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check on page view.
|
||||
@ -106,7 +103,9 @@ func TestXSSWikiLastCommitInfo(t *testing.T) {
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
htmlDoc.AssertElement(t, "script.evil", false)
|
||||
assert.EqualValues(t, `Gusted edited this page 0001-01-01 00:00:00 +00:00`, strings.TrimSpace(htmlDoc.Find(".ui.sub.header").Text()))
|
||||
htmlCode, err := htmlDoc.Find(".ui.sub.header").Html()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, `foo<script class="evil">alert('xss');</script>bar edited this page <relative-time class="time-since" prefix="" tense="past" datetime="2001-01-31T00:00:00Z" data-tooltip-content="" data-tooltip-interactive="true">2001-01-31 00:00:00 +00:00</relative-time>`, strings.TrimSpace(htmlCode))
|
||||
})
|
||||
|
||||
// Check on revisions page.
|
||||
@ -118,7 +117,9 @@ func TestXSSWikiLastCommitInfo(t *testing.T) {
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
htmlDoc.AssertElement(t, "script.evil", false)
|
||||
assert.EqualValues(t, `Gusted edited this page 0001-01-01 00:00:00 +00:00`, strings.TrimSpace(htmlDoc.Find(".ui.sub.header").Text()))
|
||||
htmlCode, err := htmlDoc.Find(".ui.sub.header").Html()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, `foo<script class="evil">alert('xss');</script>bar edited this page <relative-time class="time-since" prefix="" tense="past" datetime="2001-01-31T00:00:00Z" data-tooltip-content="" data-tooltip-interactive="true">2001-01-31 00:00:00 +00:00</relative-time>`, strings.TrimSpace(htmlCode))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -2,13 +2,14 @@ import {encode, decode} from 'uint8-to-base64';
|
||||
|
||||
// transform /path/to/file.ext to file.ext
|
||||
export function basename(path = '') {
|
||||
return path ? path.replace(/^.*\//, '') : '';
|
||||
const lastSlashIndex = path.lastIndexOf('/');
|
||||
return lastSlashIndex < 0 ? path : path.substring(lastSlashIndex + 1);
|
||||
}
|
||||
|
||||
// transform /path/to/file.ext to .ext
|
||||
export function extname(path = '') {
|
||||
const [_, ext] = /.+(\.[^.]+)$/.exec(path) || [];
|
||||
return ext || '';
|
||||
const lastPointIndex = path.lastIndexOf('.');
|
||||
return lastPointIndex < 0 ? '' : path.substring(lastPointIndex);
|
||||
}
|
||||
|
||||
// test whether a variable is an object
|
||||
|
Reference in New Issue
Block a user