mirror of
https://github.com/go-gitea/gitea.git
synced 2024-09-01 14:56:30 +00:00
Merge branch 'main' into pacman-packages
This commit is contained in:
commit
2685f1a307
@ -77,16 +77,21 @@ linters-settings:
|
||||
extra-rules: true
|
||||
lang-version: "1.20"
|
||||
depguard:
|
||||
list-type: denylist
|
||||
# Check the list against standard lib.
|
||||
include-go-root: true
|
||||
packages-with-error-message:
|
||||
- encoding/json: "use gitea's modules/json instead of encoding/json"
|
||||
- github.com/unknwon/com: "use gitea's util and replacements"
|
||||
- io/ioutil: "use os or io instead"
|
||||
- golang.org/x/exp: "it's experimental and unreliable."
|
||||
- code.gitea.io/gitea/modules/git/internal: "do not use the internal package, use AddXxx function instead"
|
||||
- gopkg.in/ini.v1: "do not use the ini package, use gitea's config system instead"
|
||||
rules:
|
||||
main:
|
||||
deny:
|
||||
- pkg: encoding/json
|
||||
desc: use gitea's modules/json instead of encoding/json
|
||||
- pkg: github.com/unknwon/com
|
||||
desc: use gitea's util and replacements
|
||||
- pkg: io/ioutil
|
||||
desc: use os or io instead
|
||||
- pkg: golang.org/x/exp
|
||||
desc: it's experimental and unreliable
|
||||
- pkg: code.gitea.io/gitea/modules/git/internal
|
||||
desc: do not use the internal package, use AddXxx function instead
|
||||
- pkg: gopkg.in/ini.v1
|
||||
desc: do not use the ini package, use gitea's config system instead
|
||||
|
||||
issues:
|
||||
max-issues-per-linter: 0
|
||||
|
10
Makefile
10
Makefile
@ -25,17 +25,17 @@ COMMA := ,
|
||||
|
||||
XGO_VERSION := go-1.20.x
|
||||
|
||||
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.43.0
|
||||
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.44.0
|
||||
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.7.0
|
||||
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.5.0
|
||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.52.2
|
||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.53.3
|
||||
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11
|
||||
MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4
|
||||
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.30.4
|
||||
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.30.5
|
||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0
|
||||
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@latest
|
||||
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@latest
|
||||
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v0.2.0
|
||||
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.6.25
|
||||
|
||||
DOCKER_IMAGE ?= gitea/gitea
|
||||
DOCKER_TAG ?= latest
|
||||
|
@ -343,7 +343,7 @@ func getIssueNotification(ctx context.Context, userID, issueID int64) (*Notifica
|
||||
// NotificationsForUser returns notifications for a given user and status
|
||||
func NotificationsForUser(ctx context.Context, user *user_model.User, statuses []NotificationStatus, page, perPage int) (notifications NotificationList, err error) {
|
||||
if len(statuses) == 0 {
|
||||
return
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sess := db.GetEngine(ctx).
|
||||
@ -372,16 +372,16 @@ func CountUnread(ctx context.Context, userID int64) int64 {
|
||||
// LoadAttributes load Repo Issue User and Comment if not loaded
|
||||
func (n *Notification) LoadAttributes(ctx context.Context) (err error) {
|
||||
if err = n.loadRepo(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
if err = n.loadIssue(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
if err = n.loadUser(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
if err = n.loadComment(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ func populateHash(hashFunc crypto.Hash, msg []byte) (hash.Hash, error) {
|
||||
func readArmoredSign(r io.Reader) (body io.Reader, err error) {
|
||||
block, err := armor.Decode(r)
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
if block.Type != openpgp.SignatureType {
|
||||
return nil, fmt.Errorf("expected '" + openpgp.SignatureType + "', got: " + block.Type)
|
||||
|
@ -749,7 +749,7 @@ func (c *Comment) LoadPushCommits(ctx context.Context) (err error) {
|
||||
|
||||
err = json.Unmarshal([]byte(c.Content), &data)
|
||||
if err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
c.IsForcePush = data.IsForcePush
|
||||
@ -925,7 +925,7 @@ func createIssueDependencyComment(ctx context.Context, doer *user_model.User, is
|
||||
cType = CommentTypeRemoveDependency
|
||||
}
|
||||
if err = issue.LoadRepo(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// Make two comments, one in each issue
|
||||
@ -937,7 +937,7 @@ func createIssueDependencyComment(ctx context.Context, doer *user_model.User, is
|
||||
DependentIssueID: dependentIssue.ID,
|
||||
}
|
||||
if _, err = CreateComment(ctx, opts); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
opts = &CreateCommentOptions{
|
||||
@ -1170,11 +1170,11 @@ func CreateAutoMergeComment(ctx context.Context, typ CommentType, pr *PullReques
|
||||
return nil, fmt.Errorf("comment type %d cannot be used to create an auto merge comment", typ)
|
||||
}
|
||||
if err = pr.LoadIssue(ctx); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = pr.LoadBaseRepo(ctx); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
comment, err = CreateComment(ctx, &CreateCommentOptions{
|
||||
|
@ -468,42 +468,38 @@ func (comments CommentList) loadReviews(ctx context.Context) error {
|
||||
// loadAttributes loads all attributes
|
||||
func (comments CommentList) loadAttributes(ctx context.Context) (err error) {
|
||||
if err = comments.LoadPosters(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
if err = comments.loadLabels(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
if err = comments.loadMilestones(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
if err = comments.loadOldMilestones(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
if err = comments.loadAssignees(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
if err = comments.LoadAttachments(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
if err = comments.loadReviews(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
if err = comments.LoadIssues(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
if err = comments.loadDependentIssues(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return nil
|
||||
return comments.loadDependentIssues(ctx)
|
||||
}
|
||||
|
||||
// LoadAttributes loads attributes of the comments, except for attachments and
|
||||
|
@ -222,8 +222,7 @@ func (issue *Issue) LoadPoster(ctx context.Context) (err error) {
|
||||
if !user_model.IsErrUserNotExist(err) {
|
||||
return fmt.Errorf("getUserByID.(poster) [%d]: %w", issue.PosterID, err)
|
||||
}
|
||||
err = nil
|
||||
return
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
@ -316,27 +315,27 @@ func (issue *Issue) LoadMilestone(ctx context.Context) (err error) {
|
||||
// LoadAttributes loads the attribute of this issue.
|
||||
func (issue *Issue) LoadAttributes(ctx context.Context) (err error) {
|
||||
if err = issue.LoadRepo(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
if err = issue.LoadPoster(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
if err = issue.LoadLabels(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
if err = issue.LoadMilestone(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
if err = issue.LoadProject(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
if err = issue.LoadAssignees(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
if err = issue.LoadPullRequest(ctx); err != nil && !IsErrPullRequestNotExist(err) {
|
||||
|
@ -39,7 +39,7 @@ func newIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *user_m
|
||||
}
|
||||
|
||||
if err = issue.LoadRepo(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
opts := &CreateCommentOptions{
|
||||
@ -168,7 +168,7 @@ func deleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *use
|
||||
}
|
||||
|
||||
if err = issue.LoadRepo(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
opts := &CreateCommentOptions{
|
||||
|
@ -538,10 +538,10 @@ func FindAndUpdateIssueMentions(ctx context.Context, issue *Issue, doer *user_mo
|
||||
// don't have access to reading it. Teams are expanded into their users, but organizations are ignored.
|
||||
func ResolveIssueMentionsByVisibility(ctx context.Context, issue *Issue, doer *user_model.User, mentions []string) (users []*user_model.User, err error) {
|
||||
if len(mentions) == 0 {
|
||||
return
|
||||
return nil, nil
|
||||
}
|
||||
if err = issue.LoadRepo(ctx); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resolved := make(map[string]bool, 10)
|
||||
@ -635,7 +635,7 @@ func ResolveIssueMentionsByVisibility(ctx context.Context, issue *Issue, doer *u
|
||||
}
|
||||
}
|
||||
if len(mentionUsers) == 0 {
|
||||
return
|
||||
return users, err
|
||||
}
|
||||
|
||||
if users == nil {
|
||||
@ -702,66 +702,66 @@ func DeleteIssuesByRepoID(ctx context.Context, repoID int64) (attachmentPaths []
|
||||
// Delete content histories
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&ContentHistory{}); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Delete comments and attachments
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&Comment{}); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Dependencies for issues in this repository
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&IssueDependency{}); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Delete dependencies for issues in other repositories
|
||||
if _, err = sess.In("dependency_id", deleteCond).
|
||||
Delete(&IssueDependency{}); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&IssueUser{}); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&Reaction{}); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&IssueWatch{}); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&Stopwatch{}); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&TrackedTime{}); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&project_model.ProjectIssue{}); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = sess.In("dependent_issue_id", deleteCond).
|
||||
Delete(&Comment{}); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var attachments []*repo_model.Attachment
|
||||
if err = sess.In("issue_id", deleteCond).
|
||||
Find(&attachments); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for j := range attachments {
|
||||
@ -770,11 +770,11 @@ func DeleteIssuesByRepoID(ctx context.Context, repoID int64) (attachmentPaths []
|
||||
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&repo_model.Attachment{}); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = db.DeleteByBean(ctx, &Issue{RepoID: repoID}); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return attachmentPaths, err
|
||||
|
@ -136,10 +136,10 @@ func init() {
|
||||
// LoadCodeComments loads CodeComments
|
||||
func (r *Review) LoadCodeComments(ctx context.Context) (err error) {
|
||||
if r.CodeComments != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
if err = r.loadIssue(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
r.CodeComments, err = fetchCodeCommentsByReview(ctx, r.Issue, nil, r, false)
|
||||
return err
|
||||
@ -147,7 +147,7 @@ func (r *Review) LoadCodeComments(ctx context.Context) (err error) {
|
||||
|
||||
func (r *Review) loadIssue(ctx context.Context) (err error) {
|
||||
if r.Issue != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
r.Issue, err = GetIssueByID(ctx, r.IssueID)
|
||||
return err
|
||||
@ -156,7 +156,7 @@ func (r *Review) loadIssue(ctx context.Context) (err error) {
|
||||
// LoadReviewer loads reviewer
|
||||
func (r *Review) LoadReviewer(ctx context.Context) (err error) {
|
||||
if r.ReviewerID == 0 || r.Reviewer != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
r.Reviewer, err = user_model.GetPossibleUserByID(ctx, r.ReviewerID)
|
||||
return err
|
||||
@ -186,7 +186,7 @@ func LoadReviewers(ctx context.Context, reviews []*Review) (err error) {
|
||||
// LoadReviewerTeam loads reviewer team
|
||||
func (r *Review) LoadReviewerTeam(ctx context.Context) (err error) {
|
||||
if r.ReviewerTeamID == 0 || r.ReviewerTeam != nil {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
r.ReviewerTeam, err = organization.GetTeamByID(ctx, r.ReviewerTeamID)
|
||||
@ -196,16 +196,16 @@ func (r *Review) LoadReviewerTeam(ctx context.Context) (err error) {
|
||||
// LoadAttributes loads all attributes except CodeComments
|
||||
func (r *Review) LoadAttributes(ctx context.Context) (err error) {
|
||||
if err = r.loadIssue(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
if err = r.LoadCodeComments(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
if err = r.LoadReviewer(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
if err = r.LoadReviewerTeam(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -302,7 +302,7 @@ func DeleteTime(t *TrackedTime) error {
|
||||
func deleteTimes(ctx context.Context, opts FindTrackedTimesOptions) (removedTime int64, err error) {
|
||||
removedTime, err = GetTrackedSeconds(ctx, opts)
|
||||
if err != nil || removedTime == 0 {
|
||||
return
|
||||
return removedTime, err
|
||||
}
|
||||
|
||||
_, err = opts.toSession(db.GetEngine(ctx)).Table("tracked_time").Cols("deleted").Update(&TrackedTime{Deleted: true})
|
||||
|
@ -78,14 +78,14 @@ func RecalculateUserEmptyPWD(x *xorm.Engine) (err error) {
|
||||
for start := 0; ; start += batchSize {
|
||||
users := make([]*User, 0, batchSize)
|
||||
if err = sess.Limit(batchSize, start).Where(builder.Neq{"passwd": ""}, 0).Find(&users); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
if len(users) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if err = sess.Begin(); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
@ -100,7 +100,7 @@ func RecalculateUserEmptyPWD(x *xorm.Engine) (err error) {
|
||||
}
|
||||
|
||||
if err = sess.Commit(); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,11 +5,18 @@ package packages
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"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/structs"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
// ErrPackageBlobNotExist indicates a package blob not exist error
|
||||
@ -98,3 +105,42 @@ func GetTotalUnreferencedBlobSize(ctx context.Context) (int64, error) {
|
||||
Where("package_file.id IS NULL").
|
||||
SumInt(&PackageBlob{}, "size")
|
||||
}
|
||||
|
||||
// IsBlobAccessibleForUser tests if the user has access to the blob
|
||||
func IsBlobAccessibleForUser(ctx context.Context, blobID int64, user *user_model.User) (bool, error) {
|
||||
if user.IsAdmin {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
maxTeamAuthorize := builder.
|
||||
Select("max(team.authorize)").
|
||||
From("team").
|
||||
InnerJoin("team_user", "team_user.team_id = team.id").
|
||||
Where(builder.Eq{"team_user.uid": user.ID}.And(builder.Expr("team_user.org_id = `user`.id")))
|
||||
|
||||
maxTeamUnitAccessMode := builder.
|
||||
Select("max(team_unit.access_mode)").
|
||||
From("team").
|
||||
InnerJoin("team_user", "team_user.team_id = team.id").
|
||||
InnerJoin("team_unit", "team_unit.team_id = team.id").
|
||||
Where(builder.Eq{"team_user.uid": user.ID, "team_unit.type": unit.TypePackages}.And(builder.Expr("team_user.org_id = `user`.id")))
|
||||
|
||||
cond := builder.Eq{"package_blob.id": blobID}.And(
|
||||
// owner = user
|
||||
builder.Eq{"`user`.id": user.ID}.
|
||||
// user can see owner
|
||||
Or(builder.Eq{"`user`.visibility": structs.VisibleTypePublic}.Or(builder.Eq{"`user`.visibility": structs.VisibleTypeLimited})).
|
||||
// owner is an organization and user has access to it
|
||||
Or(builder.Eq{"`user`.type": user_model.UserTypeOrganization}.
|
||||
And(builder.Lte{strconv.Itoa(int(perm.AccessModeRead)): maxTeamAuthorize}.Or(builder.Lte{strconv.Itoa(int(perm.AccessModeRead)): maxTeamUnitAccessMode}))),
|
||||
)
|
||||
|
||||
return db.GetEngine(ctx).
|
||||
Table("package_blob").
|
||||
Join("INNER", "package_file", "package_file.blob_id = package_blob.id").
|
||||
Join("INNER", "package_version", "package_version.id = package_file.version_id").
|
||||
Join("INNER", "package", "package.id = package_version.package_id").
|
||||
Join("INNER", "user", "`user`.id = package.owner_id").
|
||||
Where(cond).
|
||||
Exist(&PackageBlob{})
|
||||
}
|
||||
|
@ -628,14 +628,14 @@ func DoctorUserStarNum() (err error) {
|
||||
for start := 0; ; start += batchSize {
|
||||
users := make([]user_model.User, 0, batchSize)
|
||||
if err = db.GetEngine(db.DefaultContext).Limit(batchSize, start).Where("type = ?", 0).Cols("id").Find(&users); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
if len(users) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if err = updateUserStarNumbers(users); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,19 +63,19 @@ type Client struct {
|
||||
// NewClient function
|
||||
func NewClient(user *user_model.User, pubID string) (c *Client, err error) {
|
||||
if err = containsRequiredHTTPHeaders(http.MethodGet, setting.Federation.GetHeaders); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
} else if err = containsRequiredHTTPHeaders(http.MethodPost, setting.Federation.PostHeaders); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
priv, err := GetPrivateKey(user)
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
privPem, _ := pem.Decode([]byte(priv))
|
||||
privParsed, err := x509.ParsePKCS1PrivateKey(privPem.Bytes)
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c = &Client{
|
||||
@ -99,14 +99,14 @@ func (c *Client) NewRequest(b []byte, to string) (req *http.Request, err error)
|
||||
buf := bytes.NewBuffer(b)
|
||||
req, err = http.NewRequest(http.MethodPost, to, buf)
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Add("Content-Type", ActivityStreamsContentType)
|
||||
req.Header.Add("Date", CurrentTime())
|
||||
req.Header.Add("User-Agent", "Gitea/"+setting.AppVer)
|
||||
signer, _, err := httpsig.NewSigner(c.algs, c.digestAlg, c.postHeaders, httpsig.Signature, httpsigExpirationTime)
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
err = signer.SignRequest(c.priv, c.pubID, req, b)
|
||||
return req, err
|
||||
@ -116,7 +116,7 @@ func (c *Client) NewRequest(b []byte, to string) (req *http.Request, err error)
|
||||
func (c *Client) Post(b []byte, to string) (resp *http.Response, err error) {
|
||||
var req *http.Request
|
||||
if req, err = c.NewRequest(b, to); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
resp, err = c.client.Do(req)
|
||||
return resp, err
|
||||
|
@ -15,22 +15,22 @@ func GetKeyPair(user *user_model.User) (pub, priv string, err error) {
|
||||
var settings map[string]*user_model.Setting
|
||||
settings, err = user_model.GetSettings(user.ID, []string{user_model.UserActivityPubPrivPem, user_model.UserActivityPubPubPem})
|
||||
if err != nil {
|
||||
return
|
||||
return pub, priv, err
|
||||
} else if len(settings) == 0 {
|
||||
if priv, pub, err = util.GenerateKeyPair(rsaBits); err != nil {
|
||||
return
|
||||
return pub, priv, err
|
||||
}
|
||||
if err = user_model.SetUserSetting(user.ID, user_model.UserActivityPubPrivPem, priv); err != nil {
|
||||
return
|
||||
return pub, priv, err
|
||||
}
|
||||
if err = user_model.SetUserSetting(user.ID, user_model.UserActivityPubPubPem, pub); err != nil {
|
||||
return
|
||||
return pub, priv, err
|
||||
}
|
||||
return
|
||||
return pub, priv, err
|
||||
} else {
|
||||
priv = settings[user_model.UserActivityPubPrivPem].SettingValue
|
||||
pub = settings[user_model.UserActivityPubPubPem].SettingValue
|
||||
return
|
||||
return pub, priv, err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,7 +294,7 @@ func ReferencesGitRepo(allowEmpty ...bool) func(ctx *APIContext) (cancel context
|
||||
return func(ctx *APIContext) (cancel context.CancelFunc) {
|
||||
// Empty repository does not have reference information.
|
||||
if ctx.Repo.Repository.IsEmpty && !(len(allowEmpty) != 0 && allowEmpty[0]) {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// For API calls.
|
||||
@ -303,7 +303,7 @@ func ReferencesGitRepo(allowEmpty ...bool) func(ctx *APIContext) (cancel context
|
||||
gitRepo, err := git.OpenRepository(ctx, repoPath)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "RepoRef Invalid repo "+repoPath, err)
|
||||
return
|
||||
return cancel
|
||||
}
|
||||
ctx.Repo.GitRepo = gitRepo
|
||||
// We opened it, we should close it
|
||||
|
@ -148,27 +148,25 @@ func CatFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufi
|
||||
func ReadBatchLine(rd *bufio.Reader) (sha []byte, typ string, size int64, err error) {
|
||||
typ, err = rd.ReadString('\n')
|
||||
if err != nil {
|
||||
return
|
||||
return sha, typ, size, err
|
||||
}
|
||||
if len(typ) == 1 {
|
||||
typ, err = rd.ReadString('\n')
|
||||
if err != nil {
|
||||
return
|
||||
return sha, typ, size, err
|
||||
}
|
||||
}
|
||||
idx := strings.IndexByte(typ, ' ')
|
||||
if idx < 0 {
|
||||
log.Debug("missing space typ: %s", typ)
|
||||
err = ErrNotExist{ID: string(sha)}
|
||||
return
|
||||
return sha, typ, size, ErrNotExist{ID: string(sha)}
|
||||
}
|
||||
sha = []byte(typ[:idx])
|
||||
typ = typ[idx+1:]
|
||||
|
||||
idx = strings.IndexByte(typ, ' ')
|
||||
if idx < 0 {
|
||||
err = ErrNotExist{ID: string(sha)}
|
||||
return
|
||||
return sha, typ, size, ErrNotExist{ID: string(sha)}
|
||||
}
|
||||
|
||||
sizeStr := typ[idx+1 : len(typ)-1]
|
||||
@ -285,14 +283,12 @@ func ParseTreeLine(rd *bufio.Reader, modeBuf, fnameBuf, shaBuf []byte) (mode, fn
|
||||
// Read the Mode & fname
|
||||
readBytes, err = rd.ReadSlice('\x00')
|
||||
if err != nil {
|
||||
return
|
||||
return mode, fname, sha, n, err
|
||||
}
|
||||
idx := bytes.IndexByte(readBytes, ' ')
|
||||
if idx < 0 {
|
||||
log.Debug("missing space in readBytes ParseTreeLine: %s", readBytes)
|
||||
|
||||
err = &ErrNotExist{}
|
||||
return
|
||||
return mode, fname, sha, n, &ErrNotExist{}
|
||||
}
|
||||
|
||||
n += idx + 1
|
||||
@ -319,7 +315,7 @@ func ParseTreeLine(rd *bufio.Reader, modeBuf, fnameBuf, shaBuf []byte) (mode, fn
|
||||
}
|
||||
n += len(fnameBuf)
|
||||
if err != nil {
|
||||
return
|
||||
return mode, fname, sha, n, err
|
||||
}
|
||||
fnameBuf = fnameBuf[:len(fnameBuf)-1]
|
||||
fname = fnameBuf
|
||||
@ -331,7 +327,7 @@ func ParseTreeLine(rd *bufio.Reader, modeBuf, fnameBuf, shaBuf []byte) (mode, fn
|
||||
read, err = rd.Read(shaBuf[idx:20])
|
||||
n += read
|
||||
if err != nil {
|
||||
return
|
||||
return mode, fname, sha, n, err
|
||||
}
|
||||
idx += read
|
||||
}
|
||||
|
@ -435,7 +435,7 @@ func (c *Commit) GetBranchName() (string, error) {
|
||||
// LoadBranchName load branch name for commit
|
||||
func (c *Commit) LoadBranchName() (err error) {
|
||||
if len(c.Branch) != 0 {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
c.Branch, err = c.GetBranchName()
|
||||
|
@ -171,7 +171,7 @@ func InitFull(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
if err = InitSimple(ctx); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// when git works with gnupg (commit signing), there should be a stable home for gnupg commands
|
||||
|
@ -87,7 +87,7 @@ func (repo *Repository) CatFileBatchCheck(ctx context.Context) (WriteCloserError
|
||||
// Close this repository, in particular close the underlying gogitStorage if this is not nil
|
||||
func (repo *Repository) Close() (err error) {
|
||||
if repo == nil {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
if repo.batchCancel != nil {
|
||||
repo.batchCancel()
|
||||
|
@ -48,7 +48,7 @@ func (repo *Repository) readTreeToIndex(id SHA1, indexFilename ...string) error
|
||||
func (repo *Repository) ReadTreeToTemporaryIndex(treeish string) (filename, tmpDir string, cancel context.CancelFunc, err error) {
|
||||
tmpDir, err = os.MkdirTemp("", "index")
|
||||
if err != nil {
|
||||
return
|
||||
return filename, tmpDir, cancel, err
|
||||
}
|
||||
|
||||
filename = filepath.Join(tmpDir, ".tmp-index")
|
||||
|
@ -43,12 +43,13 @@ func (s *Signature) Decode(b []byte) {
|
||||
//
|
||||
// but without the "author " at the beginning (this method should)
|
||||
// be used for author and committer.
|
||||
// FIXME: there are a lot of "return sig, err" (but the err is also nil), that's the old behavior, to avoid breaking
|
||||
func newSignatureFromCommitline(line []byte) (sig *Signature, err error) {
|
||||
sig = new(Signature)
|
||||
emailStart := bytes.LastIndexByte(line, '<')
|
||||
emailEnd := bytes.LastIndexByte(line, '>')
|
||||
if emailStart == -1 || emailEnd == -1 || emailEnd < emailStart {
|
||||
return
|
||||
return sig, err
|
||||
}
|
||||
|
||||
if emailStart > 0 { // Empty name has already occurred, even if it shouldn't
|
||||
@ -58,7 +59,7 @@ func newSignatureFromCommitline(line []byte) (sig *Signature, err error) {
|
||||
|
||||
hasTime := emailEnd+2 < len(line)
|
||||
if !hasTime {
|
||||
return
|
||||
return sig, err
|
||||
}
|
||||
|
||||
// Check date format.
|
||||
@ -66,7 +67,7 @@ func newSignatureFromCommitline(line []byte) (sig *Signature, err error) {
|
||||
if firstChar >= 48 && firstChar <= 57 {
|
||||
idx := bytes.IndexByte(line[emailEnd+2:], ' ')
|
||||
if idx < 0 {
|
||||
return
|
||||
return sig, err
|
||||
}
|
||||
|
||||
timestring := string(line[emailEnd+2 : emailEnd+2+idx])
|
||||
@ -75,14 +76,14 @@ func newSignatureFromCommitline(line []byte) (sig *Signature, err error) {
|
||||
|
||||
idx += emailEnd + 3
|
||||
if idx >= len(line) || idx+5 > len(line) {
|
||||
return
|
||||
return sig, err
|
||||
}
|
||||
|
||||
timezone := string(line[idx : idx+5])
|
||||
tzhours, err1 := strconv.ParseInt(timezone[0:3], 10, 64)
|
||||
tzmins, err2 := strconv.ParseInt(timezone[3:], 10, 64)
|
||||
if err1 != nil || err2 != nil {
|
||||
return
|
||||
return sig, err
|
||||
}
|
||||
if tzhours < 0 {
|
||||
tzmins *= -1
|
||||
@ -92,7 +93,7 @@ func newSignatureFromCommitline(line []byte) (sig *Signature, err error) {
|
||||
} else {
|
||||
sig.When, err = time.Parse(GitTimeLayout, string(line[emailEnd+2:]))
|
||||
if err != nil {
|
||||
return
|
||||
return sig, err
|
||||
}
|
||||
}
|
||||
return sig, err
|
||||
|
@ -71,7 +71,7 @@ func valToTimeDuration(vs []string) (result time.Duration) {
|
||||
result = time.Duration(val)
|
||||
}
|
||||
if err == nil {
|
||||
return
|
||||
return result
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
@ -93,7 +93,7 @@ func (q *WorkerPoolQueue[T]) GetQueueItemNumber() int {
|
||||
|
||||
func (q *WorkerPoolQueue[T]) FlushWithContext(ctx context.Context, timeout time.Duration) (err error) {
|
||||
if q.isBaseQueueDummy() {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Debug("Try to flush queue %q with timeout %v", q.GetName(), timeout)
|
||||
|
@ -50,7 +50,9 @@ func NewRoute() *Route {
|
||||
// Use supports two middlewares
|
||||
func (r *Route) Use(middlewares ...any) {
|
||||
for _, m := range middlewares {
|
||||
r.R.Use(toHandlerProvider(m))
|
||||
if m != nil {
|
||||
r.R.Use(toHandlerProvider(m))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,15 +81,23 @@ func (r *Route) getPattern(pattern string) string {
|
||||
}
|
||||
|
||||
func (r *Route) wrapMiddlewareAndHandler(h []any) ([]func(http.Handler) http.Handler, http.HandlerFunc) {
|
||||
handlerProviders := make([]func(http.Handler) http.Handler, 0, len(r.curMiddlewares)+len(h))
|
||||
handlerProviders := make([]func(http.Handler) http.Handler, 0, len(r.curMiddlewares)+len(h)+1)
|
||||
for _, m := range r.curMiddlewares {
|
||||
handlerProviders = append(handlerProviders, toHandlerProvider(m))
|
||||
if m != nil {
|
||||
handlerProviders = append(handlerProviders, toHandlerProvider(m))
|
||||
}
|
||||
}
|
||||
for _, m := range h {
|
||||
handlerProviders = append(handlerProviders, toHandlerProvider(m))
|
||||
if h != nil {
|
||||
handlerProviders = append(handlerProviders, toHandlerProvider(m))
|
||||
}
|
||||
}
|
||||
middlewares := handlerProviders[:len(handlerProviders)-1]
|
||||
handlerFunc := handlerProviders[len(handlerProviders)-1](nil).ServeHTTP
|
||||
mockPoint := RouteMockPoint(MockAfterMiddlewares)
|
||||
if mockPoint != nil {
|
||||
middlewares = append(middlewares, mockPoint)
|
||||
}
|
||||
return middlewares, handlerFunc
|
||||
}
|
||||
|
||||
|
61
modules/web/routemock.go
Normal file
61
modules/web/routemock.go
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
// MockAfterMiddlewares is a general mock point, it's between middlewares and the handler
|
||||
const MockAfterMiddlewares = "MockAfterMiddlewares"
|
||||
|
||||
var routeMockPoints = map[string]func(next http.Handler) http.Handler{}
|
||||
|
||||
// RouteMockPoint registers a mock point as a middleware for testing, example:
|
||||
//
|
||||
// r.Use(web.RouteMockPoint("my-mock-point-1"))
|
||||
// r.Get("/foo", middleware2, web.RouteMockPoint("my-mock-point-2"), middleware2, handler)
|
||||
//
|
||||
// Then use web.RouteMock to mock the route execution.
|
||||
// It only takes effect in testing mode (setting.IsInTesting == true).
|
||||
func RouteMockPoint(pointName string) func(next http.Handler) http.Handler {
|
||||
if !setting.IsInTesting {
|
||||
return nil
|
||||
}
|
||||
routeMockPoints[pointName] = nil
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if h := routeMockPoints[pointName]; h != nil {
|
||||
h(next).ServeHTTP(w, r)
|
||||
} else {
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// RouteMock uses the registered mock point to mock the route execution, example:
|
||||
//
|
||||
// defer web.RouteMockReset()
|
||||
// web.RouteMock(web.MockAfterMiddlewares, func(ctx *context.Context) {
|
||||
// ctx.WriteResponse(...)
|
||||
// }
|
||||
//
|
||||
// Then the mock function will be executed as a middleware at the mock point.
|
||||
// It only takes effect in testing mode (setting.IsInTesting == true).
|
||||
func RouteMock(pointName string, h any) {
|
||||
if _, ok := routeMockPoints[pointName]; !ok {
|
||||
panic("route mock point not found: " + pointName)
|
||||
}
|
||||
routeMockPoints[pointName] = toHandlerProvider(h)
|
||||
}
|
||||
|
||||
// RouteMockReset resets all mock points (no mock anymore)
|
||||
func RouteMockReset() {
|
||||
for k := range routeMockPoints {
|
||||
routeMockPoints[k] = nil // keep the keys because RouteMock will check the keys to make sure no misspelling
|
||||
}
|
||||
}
|
70
modules/web/routemock_test.go
Normal file
70
modules/web/routemock_test.go
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRouteMock(t *testing.T) {
|
||||
setting.IsInTesting = true
|
||||
|
||||
r := NewRoute()
|
||||
middleware1 := func(resp http.ResponseWriter, req *http.Request) {
|
||||
resp.Header().Set("X-Test-Middleware1", "m1")
|
||||
}
|
||||
middleware2 := func(resp http.ResponseWriter, req *http.Request) {
|
||||
resp.Header().Set("X-Test-Middleware2", "m2")
|
||||
}
|
||||
handler := func(resp http.ResponseWriter, req *http.Request) {
|
||||
resp.Header().Set("X-Test-Handler", "h")
|
||||
}
|
||||
r.Get("/foo", middleware1, RouteMockPoint("mock-point"), middleware2, handler)
|
||||
|
||||
// normal request
|
||||
recorder := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "http://localhost:8000/foo", nil)
|
||||
assert.NoError(t, err)
|
||||
r.ServeHTTP(recorder, req)
|
||||
assert.Len(t, recorder.Header(), 3)
|
||||
assert.EqualValues(t, "m1", recorder.Header().Get("X-Test-Middleware1"))
|
||||
assert.EqualValues(t, "m2", recorder.Header().Get("X-Test-Middleware2"))
|
||||
assert.EqualValues(t, "h", recorder.Header().Get("X-Test-Handler"))
|
||||
RouteMockReset()
|
||||
|
||||
// mock at "mock-point"
|
||||
RouteMock("mock-point", func(resp http.ResponseWriter, req *http.Request) {
|
||||
resp.Header().Set("X-Test-MockPoint", "a")
|
||||
resp.WriteHeader(http.StatusOK)
|
||||
})
|
||||
recorder = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "http://localhost:8000/foo", nil)
|
||||
assert.NoError(t, err)
|
||||
r.ServeHTTP(recorder, req)
|
||||
assert.Len(t, recorder.Header(), 2)
|
||||
assert.EqualValues(t, "m1", recorder.Header().Get("X-Test-Middleware1"))
|
||||
assert.EqualValues(t, "a", recorder.Header().Get("X-Test-MockPoint"))
|
||||
RouteMockReset()
|
||||
|
||||
// mock at MockAfterMiddlewares
|
||||
RouteMock(MockAfterMiddlewares, func(resp http.ResponseWriter, req *http.Request) {
|
||||
resp.Header().Set("X-Test-MockPoint", "b")
|
||||
resp.WriteHeader(http.StatusOK)
|
||||
})
|
||||
recorder = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "http://localhost:8000/foo", nil)
|
||||
assert.NoError(t, err)
|
||||
r.ServeHTTP(recorder, req)
|
||||
assert.Len(t, recorder.Header(), 3)
|
||||
assert.EqualValues(t, "m1", recorder.Header().Get("X-Test-Middleware1"))
|
||||
assert.EqualValues(t, "m2", recorder.Header().Get("X-Test-Middleware2"))
|
||||
assert.EqualValues(t, "b", recorder.Header().Get("X-Test-MockPoint"))
|
||||
RouteMockReset()
|
||||
}
|
6
package-lock.json
generated
6
package-lock.json
generated
@ -41,6 +41,7 @@
|
||||
"sortablejs": "1.15.0",
|
||||
"swagger-ui-dist": "5.1.0",
|
||||
"throttle-debounce": "5.0.0",
|
||||
"tinycolor2": "1.6.0",
|
||||
"tippy.js": "6.3.7",
|
||||
"toastify-js": "1.12.0",
|
||||
"tributejs": "5.1.3",
|
||||
@ -10265,6 +10266,11 @@
|
||||
"integrity": "sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tinycolor2": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
|
||||
"integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="
|
||||
},
|
||||
"node_modules/tinypool": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.6.0.tgz",
|
||||
|
@ -40,6 +40,7 @@
|
||||
"sortablejs": "1.15.0",
|
||||
"swagger-ui-dist": "5.1.0",
|
||||
"throttle-debounce": "5.0.0",
|
||||
"tinycolor2": "1.6.0",
|
||||
"tippy.js": "6.3.7",
|
||||
"toastify-js": "1.12.0",
|
||||
"tributejs": "5.1.3",
|
||||
|
@ -203,17 +203,25 @@ func InitiateUploadBlob(ctx *context.Context) {
|
||||
Digest: mount,
|
||||
})
|
||||
if blob != nil {
|
||||
if err := mountBlob(&packages_service.PackageInfo{Owner: ctx.Package.Owner, Name: image}, blob.Blob); err != nil {
|
||||
accessible, err := packages_model.IsBlobAccessibleForUser(ctx, blob.Blob.ID, ctx.Doer)
|
||||
if err != nil {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
setResponseHeaders(ctx.Resp, &containerHeaders{
|
||||
Location: fmt.Sprintf("/v2/%s/%s/blobs/%s", ctx.Package.Owner.LowerName, image, mount),
|
||||
ContentDigest: mount,
|
||||
Status: http.StatusCreated,
|
||||
})
|
||||
return
|
||||
if accessible {
|
||||
if err := mountBlob(&packages_service.PackageInfo{Owner: ctx.Package.Owner, Name: image}, blob.Blob); err != nil {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
setResponseHeaders(ctx.Resp, &containerHeaders{
|
||||
Location: fmt.Sprintf("/v2/%s/%s/blobs/%s", ctx.Package.Owner.LowerName, image, mount),
|
||||
ContentDigest: mount,
|
||||
Status: http.StatusCreated,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,19 +25,16 @@ func getPublicKeyFromResponse(b []byte, keyID *url.URL) (p crypto.PublicKey, err
|
||||
person := ap.PersonNew(ap.IRI(keyID.String()))
|
||||
err = person.UnmarshalJSON(b)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("ActivityStreams type cannot be converted to one known to have publicKey property: %w", err)
|
||||
return
|
||||
return nil, fmt.Errorf("ActivityStreams type cannot be converted to one known to have publicKey property: %w", err)
|
||||
}
|
||||
pubKey := person.PublicKey
|
||||
if pubKey.ID.String() != keyID.String() {
|
||||
err = fmt.Errorf("cannot find publicKey with id: %s in %s", keyID, string(b))
|
||||
return
|
||||
return nil, fmt.Errorf("cannot find publicKey with id: %s in %s", keyID, string(b))
|
||||
}
|
||||
pubKeyPem := pubKey.PublicKeyPem
|
||||
block, _ := pem.Decode([]byte(pubKeyPem))
|
||||
if block == nil || block.Type != "PUBLIC KEY" {
|
||||
err = fmt.Errorf("could not decode publicKeyPem to PUBLIC KEY pem block type")
|
||||
return
|
||||
return nil, fmt.Errorf("could not decode publicKeyPem to PUBLIC KEY pem block type")
|
||||
}
|
||||
p, err = x509.ParsePKIXPublicKey(block.Bytes)
|
||||
return p, err
|
||||
@ -49,13 +46,12 @@ func fetch(iri *url.URL) (b []byte, err error) {
|
||||
req.Header("User-Agent", "Gitea/"+setting.AppVer)
|
||||
resp, err := req.Response()
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
err = fmt.Errorf("url IRI fetch [%s] failed with status (%d): %s", iri, resp.StatusCode, resp.Status)
|
||||
return
|
||||
return nil, fmt.Errorf("url IRI fetch [%s] failed with status (%d): %s", iri, resp.StatusCode, resp.Status)
|
||||
}
|
||||
b, err = io.ReadAll(io.LimitReader(resp.Body, setting.Federation.MaxSize))
|
||||
return b, err
|
||||
@ -67,21 +63,21 @@ func verifyHTTPSignatures(ctx *gitea_context.APIContext) (authenticated bool, er
|
||||
// 1. Figure out what key we need to verify
|
||||
v, err := httpsig.NewVerifier(r)
|
||||
if err != nil {
|
||||
return
|
||||
return false, err
|
||||
}
|
||||
ID := v.KeyId()
|
||||
idIRI, err := url.Parse(ID)
|
||||
if err != nil {
|
||||
return
|
||||
return false, err
|
||||
}
|
||||
// 2. Fetch the public key of the other actor
|
||||
b, err := fetch(idIRI)
|
||||
if err != nil {
|
||||
return
|
||||
return false, err
|
||||
}
|
||||
pubKey, err := getPublicKeyFromResponse(b, idIRI)
|
||||
if err != nil {
|
||||
return
|
||||
return false, err
|
||||
}
|
||||
// 3. Verify the other actor's key
|
||||
algo := httpsig.Algorithm(setting.Federation.Algorithms[0])
|
||||
|
@ -71,7 +71,7 @@ func runMigrateTask(t *admin_model.Task) (err error) {
|
||||
}()
|
||||
|
||||
if err = t.LoadRepo(); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// if repository is ready, then just finish the task
|
||||
@ -80,16 +80,16 @@ func runMigrateTask(t *admin_model.Task) (err error) {
|
||||
}
|
||||
|
||||
if err = t.LoadDoer(); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
if err = t.LoadOwner(); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
var opts *migration.MigrateOptions
|
||||
opts, err = t.MigrateConfig()
|
||||
if err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
opts.MigrateToRepoID = t.RepoID
|
||||
@ -101,7 +101,7 @@ func runMigrateTask(t *admin_model.Task) (err error) {
|
||||
t.StartTime = timeutil.TimeStampNow()
|
||||
t.Status = structs.TaskStatusRunning
|
||||
if err = t.UpdateCols("start_time", "status"); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// check whether the task should be canceled, this goroutine is also managed by process manager
|
||||
@ -133,12 +133,11 @@ func runMigrateTask(t *admin_model.Task) (err error) {
|
||||
|
||||
if err == nil {
|
||||
log.Trace("Repository migrated [%d]: %s/%s", t.Repo.ID, t.Owner.Name, t.Repo.Name)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
if repo_model.IsErrRepoAlreadyExist(err) {
|
||||
err = errors.New("the repository name is already used")
|
||||
return
|
||||
return errors.New("the repository name is already used")
|
||||
}
|
||||
|
||||
// remoteAddr may contain credentials, so we sanitize it
|
||||
|
@ -34,6 +34,7 @@ func TestPackageContainer(t *testing.T) {
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadPackage)
|
||||
privateUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 31})
|
||||
|
||||
has := func(l packages_model.PackagePropertyList, name string) bool {
|
||||
for _, pp := range l {
|
||||
@ -262,7 +263,16 @@ func TestPackageContainer(t *testing.T) {
|
||||
t.Run("UploadBlob/Mount", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads?mount=%s", url, unknownDigest))
|
||||
privateBlobDigest := "sha256:6ccce4863b70f258d691f59609d31b4502e1ba5199942d3bc5d35d17a4ce771d"
|
||||
req := NewRequestWithBody(t, "POST", fmt.Sprintf("%sv2/%s/%s/blobs/uploads?digest=%s", setting.AppURL, privateUser.Name, image, privateBlobDigest), strings.NewReader("gitea"))
|
||||
req = AddBasicAuthHeader(req, privateUser.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
req = NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads?mount=%s", url, unknownDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusAccepted)
|
||||
|
||||
req = NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads?mount=%s", url, privateBlobDigest))
|
||||
addTokenAuthHeader(req, userToken)
|
||||
MakeRequest(t, req, http.StatusAccepted)
|
||||
|
||||
|
@ -26,7 +26,8 @@
|
||||
<script>
|
||||
import $ from 'jquery';
|
||||
import {SvgIcon} from '../svg.js';
|
||||
import {useLightTextOnBackground, hexToRGBColor} from '../utils/color.js';
|
||||
import {useLightTextOnBackground} from '../utils/color.js';
|
||||
import tinycolor from 'tinycolor2';
|
||||
|
||||
const {appSubUrl, i18n} = window.config;
|
||||
|
||||
@ -77,7 +78,7 @@ export default {
|
||||
labels() {
|
||||
return this.issue.labels.map((label) => {
|
||||
let textColor;
|
||||
const [r, g, b] = hexToRGBColor(label.color);
|
||||
const {r, g, b} = tinycolor(label.color).toRgb();
|
||||
if (useLightTextOnBackground(r, g, b)) {
|
||||
textColor = '#eeeeee';
|
||||
} else {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import tinycolor from 'tinycolor2';
|
||||
import {basename, extname, isObject, isDarkTheme} from '../utils.js';
|
||||
import {onInputDebounce} from '../utils/dom.js';
|
||||
|
||||
@ -69,33 +70,34 @@ export async function createMonaco(textarea, filename, editorOpts) {
|
||||
textarea.parentNode.append(container);
|
||||
|
||||
// https://github.com/microsoft/monaco-editor/issues/2427
|
||||
// also, monaco can only parse 6-digit hex colors, so we convert the colors to that format
|
||||
const styles = window.getComputedStyle(document.documentElement);
|
||||
const getProp = (name) => styles.getPropertyValue(name).trim();
|
||||
const getColor = (name) => tinycolor(styles.getPropertyValue(name).trim()).toString('hex6');
|
||||
|
||||
monaco.editor.defineTheme('gitea', {
|
||||
base: isDarkTheme() ? 'vs-dark' : 'vs',
|
||||
inherit: true,
|
||||
rules: [
|
||||
{
|
||||
background: getProp('--color-code-bg'),
|
||||
background: getColor('--color-code-bg'),
|
||||
}
|
||||
],
|
||||
colors: {
|
||||
'editor.background': getProp('--color-code-bg'),
|
||||
'editor.foreground': getProp('--color-text'),
|
||||
'editor.inactiveSelectionBackground': getProp('--color-primary-light-4'),
|
||||
'editor.lineHighlightBackground': getProp('--color-editor-line-highlight'),
|
||||
'editor.selectionBackground': getProp('--color-primary-light-3'),
|
||||
'editor.selectionForeground': getProp('--color-primary-light-3'),
|
||||
'editorLineNumber.background': getProp('--color-code-bg'),
|
||||
'editorLineNumber.foreground': getProp('--color-secondary-dark-6'),
|
||||
'editorWidget.background': getProp('--color-body'),
|
||||
'editorWidget.border': getProp('--color-secondary'),
|
||||
'input.background': getProp('--color-input-background'),
|
||||
'input.border': getProp('--color-input-border'),
|
||||
'input.foreground': getProp('--color-input-text'),
|
||||
'scrollbar.shadow': getProp('--color-shadow'),
|
||||
'progressBar.background': getProp('--color-primary'),
|
||||
'editor.background': getColor('--color-code-bg'),
|
||||
'editor.foreground': getColor('--color-text'),
|
||||
'editor.inactiveSelectionBackground': getColor('--color-primary-light-4'),
|
||||
'editor.lineHighlightBackground': getColor('--color-editor-line-highlight'),
|
||||
'editor.selectionBackground': getColor('--color-primary-light-3'),
|
||||
'editor.selectionForeground': getColor('--color-primary-light-3'),
|
||||
'editorLineNumber.background': getColor('--color-code-bg'),
|
||||
'editorLineNumber.foreground': getColor('--color-secondary-dark-6'),
|
||||
'editorWidget.background': getColor('--color-body'),
|
||||
'editorWidget.border': getColor('--color-secondary'),
|
||||
'input.background': getColor('--color-input-background'),
|
||||
'input.border': getColor('--color-input-border'),
|
||||
'input.foreground': getColor('--color-input-text'),
|
||||
'scrollbar.shadow': getColor('--color-shadow'),
|
||||
'progressBar.background': getColor('--color-primary'),
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import $ from 'jquery';
|
||||
import {useLightTextOnBackground, hexToRGBColor} from '../utils/color.js';
|
||||
import {useLightTextOnBackground} from '../utils/color.js';
|
||||
import tinycolor from 'tinycolor2';
|
||||
|
||||
const {csrfToken} = window.config;
|
||||
|
||||
@ -210,7 +211,7 @@ export function initRepoProject() {
|
||||
}
|
||||
|
||||
function setLabelColor(label, color) {
|
||||
const [r, g, b] = hexToRGBColor(color);
|
||||
const {r, g, b} = tinycolor(color).toRgb();
|
||||
if (useLightTextOnBackground(r, g, b)) {
|
||||
label.removeClass('dark-label').addClass('light-label');
|
||||
} else {
|
||||
|
@ -13,27 +13,6 @@ function getLuminance(r, g, b) {
|
||||
return 0.2126 * R + 0.7152 * G + 0.0722 * B;
|
||||
}
|
||||
|
||||
// Get color as RGB values in 0..255 range from the hex color string (with or without #)
|
||||
export function hexToRGBColor(backgroundColorStr) {
|
||||
let backgroundColor = backgroundColorStr;
|
||||
if (backgroundColorStr[0] === '#') {
|
||||
backgroundColor = backgroundColorStr.substring(1);
|
||||
}
|
||||
// only support transfer of rgb, rgba, rrggbb and rrggbbaa
|
||||
// if not in these formats, use default values 0, 0, 0
|
||||
if (![3, 4, 6, 8].includes(backgroundColor.length)) {
|
||||
return [0, 0, 0];
|
||||
}
|
||||
if ([3, 4].includes(backgroundColor.length)) {
|
||||
const [r, g, b] = backgroundColor;
|
||||
backgroundColor = `${r}${r}${g}${g}${b}${b}`;
|
||||
}
|
||||
const r = parseInt(backgroundColor.substring(0, 2), 16);
|
||||
const g = parseInt(backgroundColor.substring(2, 4), 16);
|
||||
const b = parseInt(backgroundColor.substring(4, 6), 16);
|
||||
return [r, g, b];
|
||||
}
|
||||
|
||||
// Reference from: https://firsching.ch/github_labels.html
|
||||
// In the future WCAG 3 APCA may be a better solution.
|
||||
// Check if text should use light color based on RGB of background
|
||||
|
@ -1,17 +1,5 @@
|
||||
import {test, expect} from 'vitest';
|
||||
import {hexToRGBColor, useLightTextOnBackground} from './color.js';
|
||||
|
||||
test('hexToRGBColor', () => {
|
||||
expect(hexToRGBColor('2b8685')).toEqual([43, 134, 133]);
|
||||
expect(hexToRGBColor('1e1')).toEqual([17, 238, 17]);
|
||||
expect(hexToRGBColor('#1e1')).toEqual([17, 238, 17]);
|
||||
expect(hexToRGBColor('1e16')).toEqual([17, 238, 17]);
|
||||
expect(hexToRGBColor('3bb6b3')).toEqual([59, 182, 179]);
|
||||
expect(hexToRGBColor('#3bb6b399')).toEqual([59, 182, 179]);
|
||||
expect(hexToRGBColor('#0')).toEqual([0, 0, 0]);
|
||||
expect(hexToRGBColor('#00000')).toEqual([0, 0, 0]);
|
||||
expect(hexToRGBColor('#1234567')).toEqual([0, 0, 0]);
|
||||
});
|
||||
import {useLightTextOnBackground} from './color.js';
|
||||
|
||||
test('useLightTextOnBackground', () => {
|
||||
expect(useLightTextOnBackground(215, 58, 74)).toBe(true);
|
||||
|
Loading…
Reference in New Issue
Block a user