diff --git a/models/asymkey/gpg_key_common.go b/models/asymkey/gpg_key_common.go index b02be2851a..9c015582f1 100644 --- a/models/asymkey/gpg_key_common.go +++ b/models/asymkey/gpg_key_common.go @@ -134,3 +134,13 @@ func extractSignature(s string) (*packet.Signature, error) { } return sig, nil } + +func tryGetKeyIDFromSignature(sig *packet.Signature) string { + if sig.IssuerKeyId != nil && (*sig.IssuerKeyId) != 0 { + return fmt.Sprintf("%016X", *sig.IssuerKeyId) + } + if sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) > 0 { + return fmt.Sprintf("%016X", sig.IssuerFingerprint[12:20]) + } + return "" +} diff --git a/models/asymkey/gpg_key_object_verification.go b/models/asymkey/gpg_key_object_verification.go index cbae280c6a..67764ffc58 100644 --- a/models/asymkey/gpg_key_object_verification.go +++ b/models/asymkey/gpg_key_object_verification.go @@ -123,13 +123,7 @@ func ParseObjectWithSignature(ctx context.Context, c *GitObject) *ObjectVerifica } } - keyID := "" - if sig.IssuerKeyId != nil && (*sig.IssuerKeyId) != 0 { - keyID = fmt.Sprintf("%X", *sig.IssuerKeyId) - } - if keyID == "" && sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) > 0 { - keyID = fmt.Sprintf("%X", sig.IssuerFingerprint[12:20]) - } + keyID := tryGetKeyIDFromSignature(sig) defaultReason := NoKeyFound // First check if the sig has a keyID and if so just look at that diff --git a/models/asymkey/gpg_key_test.go b/models/asymkey/gpg_key_test.go index dee74bc281..d3fbb01d82 100644 --- a/models/asymkey/gpg_key_test.go +++ b/models/asymkey/gpg_key_test.go @@ -11,7 +11,9 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" + "github.com/keybase/go-crypto/openpgp/packet" "github.com/stretchr/testify/assert" ) @@ -391,3 +393,13 @@ epiDVQ== assert.Equal(t, time.Unix(1586105389, 0), expire) } } + +func TestTryGetKeyIDFromSignature(t *testing.T) { + assert.Empty(t, tryGetKeyIDFromSignature(&packet.Signature{})) + assert.Equal(t, "038D1A3EADDBEA9C", tryGetKeyIDFromSignature(&packet.Signature{ + IssuerKeyId: util.ToPointer(uint64(0x38D1A3EADDBEA9C)), + })) + assert.Equal(t, "038D1A3EADDBEA9C", tryGetKeyIDFromSignature(&packet.Signature{ + IssuerFingerprint: []uint8{0xb, 0x23, 0x24, 0xc7, 0xe6, 0xfe, 0x4f, 0x3a, 0x6, 0x26, 0xc1, 0x21, 0x3, 0x8d, 0x1a, 0x3e, 0xad, 0xdb, 0xea, 0x9c}, + })) +} diff --git a/models/asymkey/gpg_key_verify.go b/models/asymkey/gpg_key_verify.go index 4cf46ab556..01812a2d54 100644 --- a/models/asymkey/gpg_key_verify.go +++ b/models/asymkey/gpg_key_verify.go @@ -46,6 +46,10 @@ func VerifyGPGKey(ctx context.Context, ownerID int64, keyID, token, signature st return "", ErrGPGKeyNotExist{} } + if err := key.LoadSubKeys(ctx); err != nil { + return "", err + } + sig, err := extractSignature(signature) if err != nil { return "", ErrGPGInvalidTokenSignature{ diff --git a/modules/git/commit_convert_gogit.go b/modules/git/commit_convert_gogit.go index abf65bf008..c413465656 100644 --- a/modules/git/commit_convert_gogit.go +++ b/modules/git/commit_convert_gogit.go @@ -47,6 +47,12 @@ func convertPGPSignature(c *object.Commit) *ObjectSignature { return nil } + if c.Encoding != "" && c.Encoding != "UTF-8" { + if _, err = fmt.Fprintf(&w, "\nencoding %s\n", c.Encoding); err != nil { + return nil + } + } + if _, err = fmt.Fprintf(&w, "\n\n%s", c.Message); err != nil { return nil } diff --git a/modules/git/commit_reader.go b/modules/git/commit_reader.go index bf7412aa1d..49159cc418 100644 --- a/modules/git/commit_reader.go +++ b/modules/git/commit_reader.go @@ -84,6 +84,8 @@ readLoop: commit.Committer = &Signature{} commit.Committer.Decode(data) _, _ = payloadSB.Write(line) + case "encoding": + _, _ = payloadSB.Write(line) case "gpgsig": fallthrough case "gpgsig-sha256": // FIXME: no intertop, so only 1 exists at present. diff --git a/modules/git/commit_test.go b/modules/git/commit_test.go index 2de6feeb31..01c628fb80 100644 --- a/modules/git/commit_test.go +++ b/modules/git/commit_test.go @@ -125,6 +125,73 @@ empty commit`, commitFromReader.Signature.Payload) assert.EqualValues(t, commitFromReader, commitFromReader2) } +func TestCommitWithEncodingFromReader(t *testing.T) { + commitString := `feaf4ba6bc635fec442f46ddd4512416ec43c2c2 commit 1074 +tree ca3fad42080dd1a6d291b75acdfc46e5b9b307e5 +parent 47b24e7ab977ed31c5a39989d570847d6d0052af +author KN4CK3R 1711702962 +0100 +committer KN4CK3R 1711702962 +0100 +encoding ISO-8859-1 +gpgsig -----BEGIN PGP SIGNATURE----- + + iQGzBAABCgAdFiEE9HRrbqvYxPT8PXbefPSEkrowAa8FAmYGg7IACgkQfPSEkrow + Aa9olwv+P0HhtCM6CRvlUmPaqswRsDPNR4i66xyXGiSxdI9V5oJL7HLiQIM7KrFR + gizKa2COiGtugv8fE+TKqXKaJx6uJUJEjaBd8E9Af9PrAzjWj+A84lU6/PgPS8hq + zOfZraLOEWRH4tZcS+u2yFLu3ez2Wqh1xW5LNy7xqEedMXEFD1HwSJ0+pjacNkzr + frp6Asyt7xRI6YmgFJZJoRsS3Ktr6rtKeRL2IErSQQyorOqj6gKrglhrhfG/114j + FKB1v4or0WZ1DE8iP2SJZ3n+/K1IuWAINh7MVdb7PndfBPEa+IL+ucNk5uzEE8Jd + G8smGxXUeFEt2cP1dj2W8EgAxuA9sTnH9dqI5aRqy5ifDjuya7Emm8sdOUvtGdmn + SONRzusmu5n3DgV956REL7x62h7JuqmBz/12HZkr0z0zgXkcZ04q08pSJATX5N1F + yN+tWxTsWg+zhDk96d5Esdo9JMjcFvPv0eioo30GAERaz1hoD7zCMT4jgUFTQwgz + jw4YcO5u + =r3UU + -----END PGP SIGNATURE----- + +ISO-8859-1` + + sha := &Sha1Hash{0xfe, 0xaf, 0x4b, 0xa6, 0xbc, 0x63, 0x5f, 0xec, 0x44, 0x2f, 0x46, 0xdd, 0xd4, 0x51, 0x24, 0x16, 0xec, 0x43, 0xc2, 0xc2} + gitRepo, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo1_bare")) + assert.NoError(t, err) + assert.NotNil(t, gitRepo) + defer gitRepo.Close() + + commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString)) + assert.NoError(t, err) + if !assert.NotNil(t, commitFromReader) { + return + } + assert.EqualValues(t, sha, commitFromReader.ID) + assert.EqualValues(t, `-----BEGIN PGP SIGNATURE----- + +iQGzBAABCgAdFiEE9HRrbqvYxPT8PXbefPSEkrowAa8FAmYGg7IACgkQfPSEkrow +Aa9olwv+P0HhtCM6CRvlUmPaqswRsDPNR4i66xyXGiSxdI9V5oJL7HLiQIM7KrFR +gizKa2COiGtugv8fE+TKqXKaJx6uJUJEjaBd8E9Af9PrAzjWj+A84lU6/PgPS8hq +zOfZraLOEWRH4tZcS+u2yFLu3ez2Wqh1xW5LNy7xqEedMXEFD1HwSJ0+pjacNkzr +frp6Asyt7xRI6YmgFJZJoRsS3Ktr6rtKeRL2IErSQQyorOqj6gKrglhrhfG/114j +FKB1v4or0WZ1DE8iP2SJZ3n+/K1IuWAINh7MVdb7PndfBPEa+IL+ucNk5uzEE8Jd +G8smGxXUeFEt2cP1dj2W8EgAxuA9sTnH9dqI5aRqy5ifDjuya7Emm8sdOUvtGdmn +SONRzusmu5n3DgV956REL7x62h7JuqmBz/12HZkr0z0zgXkcZ04q08pSJATX5N1F +yN+tWxTsWg+zhDk96d5Esdo9JMjcFvPv0eioo30GAERaz1hoD7zCMT4jgUFTQwgz +jw4YcO5u +=r3UU +-----END PGP SIGNATURE----- +`, commitFromReader.Signature.Signature) + assert.EqualValues(t, `tree ca3fad42080dd1a6d291b75acdfc46e5b9b307e5 +parent 47b24e7ab977ed31c5a39989d570847d6d0052af +author KN4CK3R 1711702962 +0100 +committer KN4CK3R 1711702962 +0100 +encoding ISO-8859-1 + +ISO-8859-1`, commitFromReader.Signature.Payload) + assert.EqualValues(t, "KN4CK3R ", commitFromReader.Author.String()) + + commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n")) + assert.NoError(t, err) + commitFromReader.CommitMessage += "\n\n" + commitFromReader.Signature.Payload += "\n\n" + assert.EqualValues(t, commitFromReader, commitFromReader2) +} + func TestHasPreviousCommit(t *testing.T) { bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") diff --git a/modules/lfs/filesystem_client.go b/modules/lfs/filesystem_client.go index 3503a9effc..71bef5c899 100644 --- a/modules/lfs/filesystem_client.go +++ b/modules/lfs/filesystem_client.go @@ -44,7 +44,7 @@ func (c *FilesystemClient) Download(ctx context.Context, objects []Pointer, call if err != nil { return err } - + defer f.Close() if err := callback(p, f, nil); err != nil { return err } @@ -75,7 +75,7 @@ func (c *FilesystemClient) Upload(ctx context.Context, objects []Pointer, callba if err != nil { return err } - + defer f.Close() _, err = io.Copy(f, content) return err diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index ddb6814cd9..3e1d75b291 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -505,9 +505,17 @@ func TestMathBlock(t *testing.T) { `\(a\) \(b\)`, `

a b

` + nl, }, + { + `$a$.`, + `

a.

` + nl, + }, + { + `.$a$`, + `

.$a$

` + nl, + }, { `$a a$b b$`, - `

a a$b b

` + nl, + `

$a a$b b$

` + nl, }, { `a a$b b`, @@ -515,7 +523,15 @@ func TestMathBlock(t *testing.T) { }, { `a$b $a a$b b$`, - `

a$b a a$b b

` + nl, + `

a$b $a a$b b$

` + nl, + }, + { + "a$x$", + `

a$x$

` + nl, + }, + { + "$x$a", + `

$x$a

` + nl, }, { "$$a$$", diff --git a/modules/markup/markdown/math/inline_parser.go b/modules/markup/markdown/math/inline_parser.go index 0ac25c2b2a..862234e69b 100644 --- a/modules/markup/markdown/math/inline_parser.go +++ b/modules/markup/markdown/math/inline_parser.go @@ -41,9 +41,12 @@ func (parser *inlineParser) Trigger() []byte { return parser.start[0:1] } +func isPunctuation(b byte) bool { + return b == '.' || b == '!' || b == '?' || b == ',' || b == ';' || b == ':' +} + func isAlphanumeric(b byte) bool { - // Github only cares about 0-9A-Za-z - return (b >= '0' && b <= '9') || (b >= 'A' && b <= 'Z') || (b >= 'a' && b <= 'z') + return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9') } // Parse parses the current line and returns a result of parsing. @@ -56,7 +59,7 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser. } precedingCharacter := block.PrecendingCharacter() - if precedingCharacter < 256 && isAlphanumeric(byte(precedingCharacter)) { + if precedingCharacter < 256 && (isAlphanumeric(byte(precedingCharacter)) || isPunctuation(byte(precedingCharacter))) { // need to exclude things like `a$` from being considered a start return nil } @@ -75,14 +78,19 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser. ender += pos // Now we want to check the character at the end of our parser section - // that is ender + len(parser.end) + // that is ender + len(parser.end) and check if char before ender is '\' pos = ender + len(parser.end) if len(line) <= pos { break } - if !isAlphanumeric(line[pos]) { + suceedingCharacter := line[pos] + if !isPunctuation(suceedingCharacter) && !(suceedingCharacter == ' ') { + return nil + } + if line[ender-1] != '\\' { break } + // move the pointer onwards ender += len(parser.end) } diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index bee605dd70..562c3eb64c 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -11,6 +11,7 @@ import ( "strings" "time" + actions_model "code.gitea.io/gitea/models/actions" activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" @@ -30,6 +31,7 @@ import ( "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + actions_service "code.gitea.io/gitea/services/actions" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/issue" @@ -1027,6 +1029,9 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err) return err } + if err := actions_model.CleanRepoScheduleTasks(ctx, repo); err != nil { + log.Error("CleanRepoScheduleTasks for archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err) + } log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) } else { if err := repo_model.SetArchiveRepoState(ctx, repo, *opts.Archived); err != nil { @@ -1034,6 +1039,11 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err) return err } + if ctx.Repo.Repository.UnitEnabled(ctx, unit_model.TypeActions) { + if err := actions_service.DetectAndHandleSchedules(ctx, repo); err != nil { + log.Error("DetectAndHandleSchedules for un-archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err) + } + } log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) } } diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index 00af58b44d..e2c6a9902e 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -13,6 +13,7 @@ import ( "time" "code.gitea.io/gitea/models" + actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" @@ -29,6 +30,7 @@ import ( "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/web" + actions_service "code.gitea.io/gitea/services/actions" asymkey_service "code.gitea.io/gitea/services/asymkey" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" @@ -929,6 +931,10 @@ func SettingsPost(ctx *context.Context) { return } + if err := actions_model.CleanRepoScheduleTasks(ctx, repo); err != nil { + log.Error("CleanRepoScheduleTasks for archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err) + } + ctx.Flash.Success(ctx.Tr("repo.settings.archive.success")) log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) @@ -947,6 +953,12 @@ func SettingsPost(ctx *context.Context) { return } + if ctx.Repo.Repository.UnitEnabled(ctx, unit_model.TypeActions) { + if err := actions_service.DetectAndHandleSchedules(ctx, repo); err != nil { + log.Error("DetectAndHandleSchedules for un-archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err) + } + } + ctx.Flash.Success(ctx.Tr("repo.settings.unarchive.success")) log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index 5e01de2ca0..0df7533496 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -119,7 +119,7 @@ func notify(ctx context.Context, input *notifyInput) error { log.Debug("ignore executing %v for event %v whose doer is %v", getMethod(ctx), input.Event, input.Doer.Name) return nil } - if input.Repo.IsEmpty { + if input.Repo.IsEmpty || input.Repo.IsArchived { return nil } if unit_model.TypeActions.UnitGlobalDisabled() { @@ -536,7 +536,7 @@ func handleSchedules( // DetectAndHandleSchedules detects the schedule workflows on the default branch and create schedule tasks func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository) error { - if repo.IsEmpty { + if repo.IsEmpty || repo.IsArchived { return nil } diff --git a/services/actions/schedule_tasks.go b/services/actions/schedule_tasks.go index 59862fd0d8..e4e56e5122 100644 --- a/services/actions/schedule_tasks.go +++ b/services/actions/schedule_tasks.go @@ -66,6 +66,11 @@ func startTasks(ctx context.Context) error { } } + if row.Repo.IsArchived { + // Skip if the repo is archived + continue + } + cfg, err := row.Repo.GetUnit(ctx, unit.TypeActions) if err != nil { if repo_model.IsErrUnitTypeNotExist(err) { diff --git a/services/pull/pull.go b/services/pull/pull.go index fb4b88309a..3d0d38f488 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -967,12 +967,12 @@ func GetPullCommits(ctx *gitea_context.Context, issue *issues_model.Issue) ([]Co for _, commit := range prInfo.Commits { var committerOrAuthorName string var commitTime time.Time - if commit.Committer != nil { - committerOrAuthorName = commit.Committer.Name - commitTime = commit.Committer.When - } else { + if commit.Author != nil { committerOrAuthorName = commit.Author.Name commitTime = commit.Author.When + } else { + committerOrAuthorName = commit.Committer.Name + commitTime = commit.Committer.When } commits = append(commits, CommitInfo{ diff --git a/templates/admin/config_settings.tmpl b/templates/admin/config_settings.tmpl index d7fb022274..02ab5fd0fb 100644 --- a/templates/admin/config_settings.tmpl +++ b/templates/admin/config_settings.tmpl @@ -7,14 +7,14 @@
{{ctx.Locale.Tr "admin.config.disable_gravatar"}}
- +
{{ctx.Locale.Tr "admin.config.enable_federated_avatar"}}
- +
diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 8a8664f147..75a0005e56 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -24,7 +24,7 @@ {{end}} {{if and .Permission.IsAdmin (not .Repository.IsArchived)}} -
+