summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/content/doc/features/comparison.en-us.md2
-rw-r--r--models/gpg_key.go43
-rw-r--r--models/repo_collaboration.go20
-rw-r--r--options/locale/locale_en-US.ini2
-rw-r--r--routers/private/hook.go2
-rw-r--r--routers/repo/commit.go14
-rw-r--r--routers/repo/compare.go2
-rw-r--r--routers/repo/pull.go2
-rw-r--r--routers/repo/view.go9
-rw-r--r--routers/repo/wiki.go2
-rw-r--r--templates/repo/commit_page.tmpl71
-rw-r--r--templates/repo/commits_list.tmpl32
-rw-r--r--templates/repo/view_list.tmpl27
-rw-r--r--web_src/less/_base.less12
-rw-r--r--web_src/less/_repository.less183
-rw-r--r--web_src/less/themes/theme-arc-green.less63
16 files changed, 416 insertions, 70 deletions
diff --git a/docs/content/doc/features/comparison.en-us.md b/docs/content/doc/features/comparison.en-us.md
index 21731b20fd..dab1ee7eaf 100644
--- a/docs/content/doc/features/comparison.en-us.md
+++ b/docs/content/doc/features/comparison.en-us.md
@@ -60,7 +60,7 @@ _Symbols used in table:_
| Git LFS 2.0 | ✓ | ✘ | ✓ | ✓ | ✓ | ⁄ | ✓ |
| Group Milestones | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
| Granular user roles (Code, Issues, Wiki etc) | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
-| Verified Committer | ✘ | ✘ | ? | ✓ | ✓ | ✓ | ✘ |
+| Verified Committer | ⁄ | ✘ | ? | ✓ | ✓ | ✓ | ✘ |
| GPG Signed Commits | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Reject unsigned commits | [✓](https://github.com/go-gitea/gitea/pull/9708) | ✘ | ✓ | ✓ | ✓ | ✘ | ✓ |
| Repository Activity page | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
diff --git a/models/gpg_key.go b/models/gpg_key.go
index 643aa6822c..a32312a12d 100644
--- a/models/gpg_key.go
+++ b/models/gpg_key.go
@@ -374,6 +374,7 @@ type CommitVerification struct {
CommittingUser *User
SigningEmail string
SigningKey *GPGKey
+ TrustStatus string
}
// SignCommit represents a commit with validation of signature.
@@ -759,18 +760,54 @@ func verifyWithGPGSettings(gpgSettings *git.GPGSettings, sig *packet.Signature,
}
// ParseCommitsWithSignature checks if signaute of commits are corresponding to users gpg keys.
-func ParseCommitsWithSignature(oldCommits *list.List) *list.List {
+func ParseCommitsWithSignature(oldCommits *list.List, repository *Repository) *list.List {
var (
newCommits = list.New()
e = oldCommits.Front()
)
+ memberMap := map[int64]bool{}
+
for e != nil {
c := e.Value.(UserCommit)
- newCommits.PushBack(SignCommit{
+ signCommit := SignCommit{
UserCommit: &c,
Verification: ParseCommitWithSignature(c.Commit),
- })
+ }
+
+ _ = CalculateTrustStatus(signCommit.Verification, repository, &memberMap)
+
+ newCommits.PushBack(signCommit)
e = e.Next()
}
return newCommits
}
+
+// CalculateTrustStatus will calculate the TrustStatus for a commit verification within a repository
+func CalculateTrustStatus(verification *CommitVerification, repository *Repository, memberMap *map[int64]bool) (err error) {
+ if verification.Verified {
+ verification.TrustStatus = "trusted"
+ if verification.SigningUser.ID != 0 {
+ var isMember bool
+ if memberMap != nil {
+ var has bool
+ isMember, has = (*memberMap)[verification.SigningUser.ID]
+ if !has {
+ isMember, err = repository.IsOwnerMemberCollaborator(verification.SigningUser.ID)
+ (*memberMap)[verification.SigningUser.ID] = isMember
+ }
+ } else {
+ isMember, err = repository.IsOwnerMemberCollaborator(verification.SigningUser.ID)
+ }
+
+ if !isMember {
+ verification.TrustStatus = "untrusted"
+ if verification.CommittingUser.ID != verification.SigningUser.ID {
+ // The committing user and the signing user are not the same and are not the default key
+ // This should be marked as questionable unless the signing user is a collaborator/team member etc.
+ verification.TrustStatus = "unmatched"
+ }
+ }
+ }
+ }
+ return
+}
diff --git a/models/repo_collaboration.go b/models/repo_collaboration.go
index 8c6ef36230..85bc99f320 100644
--- a/models/repo_collaboration.go
+++ b/models/repo_collaboration.go
@@ -210,3 +210,23 @@ func (repo *Repository) getRepoTeams(e Engine) (teams []*Team, err error) {
func (repo *Repository) GetRepoTeams() ([]*Team, error) {
return repo.getRepoTeams(x)
}
+
+// IsOwnerMemberCollaborator checks if a provided user is the owner, a collaborator or a member of a team in a repository
+func (repo *Repository) IsOwnerMemberCollaborator(userID int64) (bool, error) {
+ if repo.OwnerID == userID {
+ return true, nil
+ }
+ teamMember, err := x.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 = ?", repo.ID).
+ And("team_unit.`type` = ?", UnitTypeCode).
+ And("team_user.uid = ?", userID).Table("team_user").Exist(&TeamUser{})
+ if err != nil {
+ return false, err
+ }
+ if teamMember {
+ return true, nil
+ }
+
+ return x.Get(&Collaboration{RepoID: repo.ID, UserID: userID})
+}
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index cbe8aaad7a..4a38dc62c1 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -809,6 +809,8 @@ commits.date = Date
commits.older = Older
commits.newer = Newer
commits.signed_by = Signed by
+commits.signed_by_untrusted_user = Signed by untrusted user
+commits.signed_by_untrusted_user_unmatched = Signed by untrusted user who does not match committer
commits.gpg_key_id = GPG Key ID
ext_issues = Ext. Issues
diff --git a/routers/private/hook.go b/routers/private/hook.go
index 44e82ebe6c..1d8cb4b48e 100644
--- a/routers/private/hook.go
+++ b/routers/private/hook.go
@@ -90,10 +90,8 @@ func readAndVerifyCommit(sha string, repo *git.Repository, env []string) error {
if err != nil {
return err
}
- log.Info("have commit %s", commit.ID.String())
verification := models.ParseCommitWithSignature(commit)
if !verification.Verified {
- log.Info("unverified commit %s", commit.ID.String())
cancel()
return &errUnverifiedCommit{
commit.ID.String(),
diff --git a/routers/repo/commit.go b/routers/repo/commit.go
index b2fa2790bc..2767986fda 100644
--- a/routers/repo/commit.go
+++ b/routers/repo/commit.go
@@ -70,7 +70,7 @@ func Commits(ctx *context.Context) {
return
}
commits = models.ValidateCommitsWithEmails(commits)
- commits = models.ParseCommitsWithSignature(commits)
+ commits = models.ParseCommitsWithSignature(commits, ctx.Repo.Repository)
commits = models.ParseCommitsWithStatus(commits, ctx.Repo.Repository)
ctx.Data["Commits"] = commits
@@ -139,7 +139,7 @@ func SearchCommits(ctx *context.Context) {
return
}
commits = models.ValidateCommitsWithEmails(commits)
- commits = models.ParseCommitsWithSignature(commits)
+ commits = models.ParseCommitsWithSignature(commits, ctx.Repo.Repository)
commits = models.ParseCommitsWithStatus(commits, ctx.Repo.Repository)
ctx.Data["Commits"] = commits
@@ -185,7 +185,7 @@ func FileHistory(ctx *context.Context) {
return
}
commits = models.ValidateCommitsWithEmails(commits)
- commits = models.ParseCommitsWithSignature(commits)
+ commits = models.ParseCommitsWithSignature(commits, ctx.Repo.Repository)
commits = models.ParseCommitsWithStatus(commits, ctx.Repo.Repository)
ctx.Data["Commits"] = commits
@@ -269,12 +269,18 @@ func Diff(ctx *context.Context) {
setPathsCompareContext(ctx, parentCommit, commit, headTarget)
ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitID)
ctx.Data["Commit"] = commit
- ctx.Data["Verification"] = models.ParseCommitWithSignature(commit)
+ verification := models.ParseCommitWithSignature(commit)
+ ctx.Data["Verification"] = verification
ctx.Data["Author"] = models.ValidateCommitWithEmail(commit)
ctx.Data["Diff"] = diff
ctx.Data["Parents"] = parents
ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
+ if err := models.CalculateTrustStatus(verification, ctx.Repo.Repository, nil); err != nil {
+ ctx.ServerError("CalculateTrustStatus", err)
+ return
+ }
+
note := &git.Note{}
err = git.GetNote(ctx.Repo.GitRepo, commitID, note)
if err == nil {
diff --git a/routers/repo/compare.go b/routers/repo/compare.go
index 833b7d9182..d7fddc4558 100644
--- a/routers/repo/compare.go
+++ b/routers/repo/compare.go
@@ -316,7 +316,7 @@ func PrepareCompareDiff(
}
compareInfo.Commits = models.ValidateCommitsWithEmails(compareInfo.Commits)
- compareInfo.Commits = models.ParseCommitsWithSignature(compareInfo.Commits)
+ compareInfo.Commits = models.ParseCommitsWithSignature(compareInfo.Commits, headRepo)
compareInfo.Commits = models.ParseCommitsWithStatus(compareInfo.Commits, headRepo)
ctx.Data["Commits"] = compareInfo.Commits
ctx.Data["CommitCount"] = compareInfo.Commits.Len()
diff --git a/routers/repo/pull.go b/routers/repo/pull.go
index 11c376be7e..92538945b0 100644
--- a/routers/repo/pull.go
+++ b/routers/repo/pull.go
@@ -495,7 +495,7 @@ func ViewPullCommits(ctx *context.Context) {
ctx.Data["Reponame"] = ctx.Repo.Repository.Name
commits = prInfo.Commits
commits = models.ValidateCommitsWithEmails(commits)
- commits = models.ParseCommitsWithSignature(commits)
+ commits = models.ParseCommitsWithSignature(commits, ctx.Repo.Repository)
commits = models.ParseCommitsWithStatus(commits, ctx.Repo.Repository)
ctx.Data["Commits"] = commits
ctx.Data["CommitCount"] = commits.Len()
diff --git a/routers/repo/view.go b/routers/repo/view.go
index 8364b1636b..5bcf4dae3b 100644
--- a/routers/repo/view.go
+++ b/routers/repo/view.go
@@ -333,7 +333,14 @@ func renderDirectory(ctx *context.Context, treeLink string) {
// Show latest commit info of repository in table header,
// or of directory if not in root directory.
ctx.Data["LatestCommit"] = latestCommit
- ctx.Data["LatestCommitVerification"] = models.ParseCommitWithSignature(latestCommit)
+ verification := models.ParseCommitWithSignature(latestCommit)
+
+ if err := models.CalculateTrustStatus(verification, ctx.Repo.Repository, nil); err != nil {
+ ctx.ServerError("CalculateTrustStatus", err)
+ return
+ }
+ ctx.Data["LatestCommitVerification"] = verification
+
ctx.Data["LatestCommitUser"] = models.ValidateCommitWithEmail(latestCommit)
statuses, err := models.GetLatestCommitStatus(ctx.Repo.Repository, ctx.Repo.Commit.ID.String(), 0)
diff --git a/routers/repo/wiki.go b/routers/repo/wiki.go
index f18625a599..a01498fb0a 100644
--- a/routers/repo/wiki.go
+++ b/routers/repo/wiki.go
@@ -284,7 +284,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
return nil, nil
}
commitsHistory = models.ValidateCommitsWithEmails(commitsHistory)
- commitsHistory = models.ParseCommitsWithSignature(commitsHistory)
+ commitsHistory = models.ParseCommitsWithSignature(commitsHistory, ctx.Repo.Repository)
ctx.Data["Commits"] = commitsHistory
diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl
index 0c3430c6ac..1cfd0944d5 100644
--- a/templates/repo/commit_page.tmpl
+++ b/templates/repo/commit_page.tmpl
@@ -2,7 +2,22 @@
<div class="repository diff">
{{template "repo/header" .}}
<div class="ui container {{if .IsSplitStyle}}fluid padded{{end}}">
- <div class="ui top attached info clearing segment {{if .Commit.Signature}} isSigned {{if .Verification.Verified }} isVerified {{end}}{{end}}">
+ {{$class := ""}}
+ {{if .Commit.Signature}}
+ {{$class = (printf "%s%s" $class " isSigned")}}
+ {{if .Verification.Verified}}
+ {{if eq .Verification.TrustStatus "trusted"}}
+ {{$class = (printf "%s%s" $class " isVerified")}}
+ {{else if eq .Verification.TrustStatus "untrusted"}}
+ {{$class = (printf "%s%s" $class " isVerifiedUntrusted")}}
+ {{else}}
+ {{$class = (printf "%s%s" $class " isVerifiedUnmatched")}}
+ {{end}}
+ {{else if .Verification.Warning}}
+ {{$class = (printf "%s%s" $class " isWarning")}}
+ {{end}}
+ {{end}}
+ <div class="ui top attached info clearing segment {{$class}}">
<a class="ui floated right blue tiny button" href="{{EscapePound .SourcePath}}">
{{.i18n.Tr "repo.diff.browse_source"}}
</a>
@@ -12,15 +27,15 @@
{{end}}
<span class="text grey">{{svg "octicon-git-branch" 16}}{{.BranchName}}</span>
</div>
- <div class="ui attached info segment {{if .Commit.Signature}} isSigned {{if .Verification.Verified }} isVerified {{end}}{{end}}">
+ <div class="ui attached info segment {{$class}}">
<div class="ui stackable grid">
<div class="nine wide column">
{{if .Author}}
<img class="ui avatar image" src="{{.Author.RelAvatarLink}}" />
{{if .Author.FullName}}
- <a href="{{.Author.HomeLink}}"><strong>{{.Author.FullName}}</strong></a> {{if .IsSigned}}<{{.Commit.Author.Email}}>{{end}}
+ <a href="{{.Author.HomeLink}}"><strong>{{.Author.FullName}}</strong> {{if .IsSigned}}&lt;{{.Commit.Author.Email}}&gt;{{end}}</a>
{{else}}
- <a href="{{.Author.HomeLink}}"><strong>{{.Commit.Author.Name}}</strong></a> {{if .IsSigned}}<{{.Commit.Author.Email}}>{{end}}
+ <a href="{{.Author.HomeLink}}"><strong>{{.Commit.Author.Name}}</strong> {{if .IsSigned}}&lt;{{.Commit.Author.Email}}&gt;{{end}}</a>
{{end}}
{{else}}
<img class="ui avatar image" src="{{AvatarLink .Commit.Author.Email}}" />
@@ -30,7 +45,7 @@
<span> </span>
{{if ne .Verification.CommittingUser.ID 0}}
<img class="ui avatar image" src="{{.Verification.CommittingUser.RelAvatarLink}}" />
- <a href="{{.Verification.CommittingUser.HomeLink}}"><strong>{{.Commit.Committer.Name}}</strong></a> <{{.Commit.Committer.Email}}>
+ <a href="{{.Verification.CommittingUser.HomeLink}}"><strong>{{.Commit.Committer.Name}}</strong> &lt;{{.Commit.Committer.Email}}&gt;</a>
{{else}}
<img class="ui avatar image" src="{{AvatarLink .Commit.Committer.Email}}" />
<strong>{{.Commit.Committer.Name}}</strong>
@@ -58,40 +73,42 @@
</div><!-- end grid -->
</div>
{{if .Commit.Signature}}
- {{if .Verification.Verified }}
- <div class="ui bottom attached positive message">
+ <div class="ui bottom attached message {{$class}}">
+ {{if .Verification.Verified }}
{{if ne .Verification.SigningUser.ID 0}}
- <i class="green lock icon"></i>
- <span>{{.i18n.Tr "repo.commits.signed_by"}}:</span>
+ <i class="lock icon"></i>
+ {{if eq .Verification.TrustStatus "trusted"}}
+ <span class="ui text">{{.i18n.Tr "repo.commits.signed_by"}}:</span>
+ {{else if eq .Verification.TrustStatus "untrusted"}}
+ <span class="ui text">{{.i18n.Tr "repo.commits.signed_by_untrusted_user"}}:</span>
+ {{else}}
+ <span class="ui text">{{.i18n.Tr "repo.commits.signed_by_untrusted_user_unmatched"}}:</span>
+ {{end}}
<img class="ui avatar image" src="{{.Verification.SigningUser.RelAvatarLink}}" />
- <a href="{{.Verification.SigningUser.HomeLink}}"><strong>{{.Verification.SigningUser.Name}}</strong></a> <{{.Verification.SigningEmail}}>
- <span class="pull-right"><span>{{.i18n.Tr "repo.commits.gpg_key_id"}}:</span> {{.Verification.SigningKey.KeyID}}</span>
+ <a href="{{.Verification.SigningUser.HomeLink}}"><strong>{{.Verification.SigningUser.Name}}</strong> <{{.Verification.SigningEmail}}></a>
+ <span class="pull-right"><span class="ui text">{{.i18n.Tr "repo.commits.gpg_key_id"}}:</span> {{.Verification.SigningKey.KeyID}}</span>
{{else}}
<i class="icons" title="{{.i18n.Tr "gpg.default_key"}}">
- <i class="green lock icon"></i>
+ <i class="lock icon"></i>
<i class="tiny inverted cog icon centerlock"></i>
</i>
- <span>{{.i18n.Tr "repo.commits.signed_by"}}:</span>
+ <span class="ui text">{{.i18n.Tr "repo.commits.signed_by"}}:</span>
<img class="ui avatar image" src="{{AvatarLink .Verification.SigningEmail}}" />
<strong>{{.Verification.SigningUser.Name}}</strong> <{{.Verification.SigningEmail}}>
- <span class="pull-right"><span>{{.i18n.Tr "repo.commits.gpg_key_id"}}:</span> <i class="cogs icon" title="{{.i18n.Tr "gpg.default_key"}}"></i>{{.Verification.SigningKey.KeyID}}</span>
+ <span class="pull-right"><span class="ui text">{{.i18n.Tr "repo.commits.gpg_key_id"}}:</span> <i class="cogs icon" title="{{.i18n.Tr "gpg.default_key"}}"></i>{{.Verification.SigningKey.KeyID}}</span>
{{end}}
- </div>
- {{else if .Verification.Warning}}
- <div class="ui bottom attached message">
- <i class="red unlock icon"></i>
- <span class="red text">{{.i18n.Tr .Verification.Reason}}</span>
- <span class="pull-right"><span class="red text">{{.i18n.Tr "repo.commits.gpg_key_id"}}:</span> <i class="red warning icon"></i>{{.Verification.SigningKey.KeyID}}</span>
- </div>
- {{else}}
- <div class="ui bottom attached message">
- <i class="grey unlock icon"></i>
+ {{else if .Verification.Warning}}
+ <i class="unlock icon"></i>
+ <span class="ui text">{{.i18n.Tr .Verification.Reason}}</span>
+ <span class="pull-right"><span class="ui text">{{.i18n.Tr "repo.commits.gpg_key_id"}}:</span> <i class="warning icon"></i>{{.Verification.SigningKey.KeyID}}</span>
+ {{else}}
+ <i class="unlock icon"></i>
{{.i18n.Tr .Verification.Reason}}
{{if and .Verification.SigningKey (ne .Verification.SigningKey.KeyID "")}}
- <span class="pull-right"><span class="red text">{{.i18n.Tr "repo.commits.gpg_key_id"}}:</span> <i class="red warning icon"></i>{{.Verification.SigningKey.KeyID}}</span>
+ <span class="pull-right"><span class="ui text">{{.i18n.Tr "repo.commits.gpg_key_id"}}:</span> <i class="warning icon"></i>{{.Verification.SigningKey.KeyID}}</span>
{{end}}
- </div>
- {{end}}
+ {{end}}
+ </div>
{{end}}
{{if .Note}}
<div class="ui top attached info segment message git-notes">
diff --git a/templates/repo/commits_list.tmpl b/templates/repo/commits_list.tmpl
index 01096f2085..5dc12c642b 100644
--- a/templates/repo/commits_list.tmpl
+++ b/templates/repo/commits_list.tmpl
@@ -28,7 +28,13 @@
{{if .Signature}}
{{$class = (printf "%s%s" $class " isSigned")}}
{{if .Verification.Verified}}
- {{$class = (printf "%s%s" $class " isVerified")}}
+ {{if eq .Verification.TrustStatus "trusted"}}
+ {{$class = (printf "%s%s" $class " isVerified")}}
+ {{else if eq .Verification.TrustStatus "untrusted"}}
+ {{$class = (printf "%s%s" $class " isVerifiedUntrusted")}}
+ {{else}}
+ {{$class = (printf "%s%s" $class " isVerifiedUnmatched")}}
+ {{end}}
{{else if .Verification.Warning}}
{{$class = (printf "%s%s" $class " isWarning")}}
{{end}}
@@ -38,20 +44,22 @@
{{else}}
<span class="{{$class}}">
{{end}}
- {{ShortSha .ID.String}}
+ <span class="shortsha">{{ShortSha .ID.String}}</span>
{{if .Signature}}
<div class="ui detail icon button">
{{if .Verification.Verified}}
- {{if ne .Verification.SigningUser.ID 0}}
- <i title="{{.Verification.Reason}}" class="lock green icon"></i>
- {{else}}
- <i title="{{.Verification.Reason}}" class="icons">
- <i class="green lock icon"></i>
- <i class="tiny inverted cog icon centerlock"></i>
- </i>
- {{end}}
- {{else if .Verification.Warning}}
- <i title="{{$.i18n.Tr .Verification.Reason}}" class="red unlock icon"></i>
+ <div title="{{if eq .Verification.TrustStatus "trusted"}}{{else if eq .Verification.TrustStatus "untrusted"}}{{$.i18n.Tr "repo.commits.signed_by_untrusted_user"}}: {{else}}{{$.i18n.Tr "repo.commits.signed_by_untrusted_user_unmatched"}}: {{end}}{{.Verification.Reason}}">
+ {{if ne .Verification.SigningUser.ID 0}}
+ <i class="lock icon"></i>
+ <img class="ui signature avatar image" src="{{.Verification.SigningUser.RelAvatarLink}}" />
+ {{else}}
+ <i title="{{.Verification.Reason}}" class="icons">
+ <i class="lock icon"></i>
+ <i class="tiny inverted cog icon centerlock"></i>
+ </i>
+ <img class="ui signature avatar image" src="{{AvatarLink .Verification.SigningEmail}}" />
+ {{end}}
+ </div>
{{else}}
<i title="{{$.i18n.Tr .Verification.Reason}}" class="unlock icon"></i>
{{end}}
diff --git a/templates/repo/view_list.tmpl b/templates/repo/view_list.tmpl
index e8163787f5..c296eb7bee 100644
--- a/templates/repo/view_list.tmpl
+++ b/templates/repo/view_list.tmpl
@@ -15,16 +15,27 @@
<strong>{{.LatestCommit.Author.Name}}</strong>
{{end}}
{{end}}
- <a rel="nofollow" class="ui sha label {{if .LatestCommit.Signature}} isSigned {{if .LatestCommitVerification.Verified }} isVerified {{end}}{{end}}" href="{{.RepoLink}}/commit/{{.LatestCommit.ID}}">
- {{ShortSha .LatestCommit.ID.String}}
+ <a rel="nofollow" class="ui sha label {{if .LatestCommit.Signature}} isSigned {{if .LatestCommitVerification.Verified }} isVerified{{if eq .LatestCommitVerification.TrustStatus "trusted"}}{{else if eq .LatestCommitVerification.TrustStatus "untrusted"}}Untrusted{{else}}Unmatched{{end}}{{else if .LatestCommitVerification.Warning}} isWarning{{end}}{{end}}" href="{{.RepoLink}}/commit/{{.LatestCommit.ID}}">
+ <span class="shortsha">{{ShortSha .LatestCommit.ID.String}}</span>
{{if .LatestCommit.Signature}}
- <div class="ui detail icon button">
- {{if .LatestCommitVerification.Verified}}
- <i title="{{.LatestCommitVerification.Reason}}" class="lock green icon"></i>
- {{else}}
+ {{if .LatestCommitVerification.Verified}}
+ <div class="ui detail icon button" title="{{if eq .LatestCommitVerification.TrustStatus "trusted"}}{{else if eq .LatestCommitVerification.TrustStatus "untrusted"}}{{.i18n.Tr "repo.commits.signed_by_untrusted_user"}}: {{else}}{{.i18n.Tr "repo.commits.signed_by_untrusted_user_unmatched"}}: {{end}}{{.LatestCommitVerification.Reason}}">
+ {{if ne .LatestCommitVerification.SigningUser.ID 0}}
+ <i class="lock icon"></i>
+ <img class="ui signature avatar image" src="{{.LatestCommitVerification.SigningUser.RelAvatarLink}}" />
+ {{else}}
+ <i title="{{.LatestCommitVerification.Reason}}" class="icons">
+ <i class="lock icon"></i>
+ <i class="tiny inverted cog icon centerlock"></i>
+ </i>
+ <img class="ui signature avatar image" src="{{AvatarLink .LatestCommitVerification.SigningEmail}}" />
+ {{end}}
+ </div>
+ {{else}}
+ <div class="ui detail icon button">
<i title="{{$.i18n.Tr .LatestCommitVerification.Reason}}" class="unlock icon"></i>
- {{end}}
- </div>
+ </div>
+ {{end}}
{{end}}
</a>
{{template "repo/commit_status" .LatestCommitStatus}}
diff --git a/web_src/less/_base.less b/web_src/less/_base.less
index 3b40abe208..1df0124542 100644
--- a/web_src/less/_base.less
+++ b/web_src/less/_base.less
@@ -443,6 +443,10 @@ code,
color: #fbbd08 !important;
}
+ &.orange {
+ color: #f2711c !important;
+ }
+
&.gold {
color: #a1882b !important;
}
@@ -640,6 +644,10 @@ code,
background-color: #fbbf09 !important;
}
+ &.orange {
+ background-color: #f2711c !important;
+ }
+
&.gold {
background-color: #a1882b !important;
}
@@ -691,6 +699,10 @@ code,
border-color: #fbbd08 !important;
}
+ &.orange {
+ border-color: #f2711c !important;
+ }
+
&.gold {
border-color: #a1882b !important;
}
diff --git a/web_src/less/_repository.less b/web_src/less/_repository.less
index 7618a4d763..503ef1debd 100644
--- a/web_src/less/_repository.less
+++ b/web_src/less/_repository.less
@@ -1234,7 +1234,7 @@
text-align: center;
}
- width: 140px;
+ width: 175px;
}
}
@@ -1255,21 +1255,49 @@
#repo-files-table .sha.label {
border: 1px solid #bbbbbb;
+ .ui.signature.avatar {
+ height: 16px;
+ margin-bottom: 0;
+ width: auto;
+ }
+
.detail.icon {
background: #fafafa;
margin: -6px -10px -4px 0;
- padding: 5px 3px 5px 6px;
+ padding: 5px 4px 5px 6px;
border-left: 1px solid #bbbbbb;
+ border-top: 0;
+ border-right: 0;
+ border-bottom: 0;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
+
+ img {
+ margin-right: 0;
+ }
+
+ > div {
+ display: inline-flex;
+ align-items: center;
+ }
}
&.isSigned.isWarning {
border: 1px solid #db2828;
background: fade(#db2828, 10%);
+ .shortsha {
+ display: inline-block;
+ padding-top: 1px;
+ }
+
.detail.icon {
- border-left: 1px solid fade(#db2828, 50%);
+ border-left: 1px solid #db2828;
+ color: #db2828;
+ }
+
+ &:hover {
+ background: fade(#db2828, 30%) !important;
}
}
@@ -1277,14 +1305,58 @@
border: 1px solid #21ba45;
background: fade(#21ba45, 10%);
+ .shortsha {
+ display: inline-block;
+ padding-top: 1px;
+ }
+
.detail.icon {
border-left: 1px solid #21ba45;
+ color: #21ba45;
}
&:hover {
background: fade(#21ba45, 30%) !important;
}
}
+
+ &.isSigned.isVerifiedUntrusted {
+ border: 1px solid #fbbd08;
+ background: fade(#fbbd08, 10%);
+
+ .shortsha {
+ display: inline-block;
+ padding-top: 1px;
+ }
+
+ .detail.icon {
+ border-left: 1px solid #fbbd08;
+ color: #fbbd08;
+ }
+
+ &:hover {
+ background: fade(#fbbd08, 30%) !important;
+ }
+ }
+
+ &.isSigned.isVerifiedUnmatched {
+ border: 1px solid #f2711c;
+ background: fade(#f2711c, 10%);
+
+ .shortsha {
+ display: inline-block;
+ padding-top: 1px;
+ }
+
+ .detail.icon {
+ border-left: 1px solid #f2711c;
+ color: #f2711c;
+ }
+
+ &:hover {
+ background: fade(#f2711c, 30%) !important;
+ }
+ }
}
.diff-detail-box {
@@ -1893,21 +1965,114 @@
}
}
- .ui.attached.isSigned.isVerified {
- &:not(.positive) {
- border-left: 1px solid #a3c293;
- border-right: 1px solid #a3c293;
+ .ui.attached.isSigned.isWarning {
+ border-left: 1px solid #c29393;
+ border-right: 1px solid #c29393;
+
+ &.top,
+ &.message {
+ border-top: 1px solid #c29393;
}
- &.top:not(.positive) {
+ &.message {
+ box-shadow: none;
+ background-color: #fff5f5;
+ color: #d95c5c;
+
+ .ui.text {
+ color: #d64444;
+ }
+ }
+
+ &:last-child,
+ &.bottom {
+ border-bottom: 1px solid #c29393;
+ }
+ }
+
+ .ui.attached.isSigned:not(.isWarning) .pull-right {
+ padding-top: 5px;
+ }
+
+ .ui.attached.isSigned.isVerified {
+ border-left: 1px solid #a3c293;
+ border-right: 1px solid #a3c293;
+
+ &.top,
+ &.message {
border-top: 1px solid #a3c293;
}
- &:not(.positive):last-child {
+ &.message {
+ box-shadow: none;
+ background-color: #fcfff5;
+ color: #6cc644;
+
+ .pull-right {
+ color: #000;
+ }
+
+ .ui.text {
+ color: #21ba45;
+ }
+ }
+
+ &:last-child,
+ &.bottom {
border-bottom: 1px solid #a3c293;
}
}
+ .ui.attached.isSigned.isVerifiedUntrusted {
+ border-left: 1px solid #c2c193;
+ border-right: 1px solid #c2c193;
+
+ &.top,
+ &.message {
+ border-top: 1px solid #c2c193;
+ }
+
+ &.message {
+ box-shadow: none;
+ background-color: #fffff5;
+ color: #fbbd08;
+
+ .ui.text {
+ color: #d2ab00;
+ }
+ }
+
+ &:last-child,
+ &.bottom {
+ border-bottom: 1px solid #c2c193;
+ }
+ }
+
+ .ui.attached.isSigned.isVerifiedUnmatched {
+ border-left: 1px solid #c2a893;
+ border-right: 1px solid #c2a893;
+
+ &.top,
+ &.message {
+ border-top: 1px solid #c2a893;
+ }
+
+ &.message {
+ box-shadow: none;
+ background-color: #fffaf5;
+ color: #f2711c;
+
+ .ui.text {
+ color: #ee5f00;
+ }
+ }
+
+ &:last-child,
+ &.bottom {
+ border-bottom: 1px solid #c2a893;
+ }
+ }
+
.ui.segment.sub-menu {
padding: 7px;
line-height: 0;
diff --git a/web_src/less/themes/theme-arc-green.less b/web_src/less/themes/theme-arc-green.less
index a6f58e85d2..fdae5ecdc1 100644
--- a/web_src/less/themes/theme-arc-green.less
+++ b/web_src/less/themes/theme-arc-green.less
@@ -1156,6 +1156,64 @@ a.ui.labels .label:hover {
border-left-color: #888;
}
+.repository .ui.attached.message.isSigned.isVerified {
+ background-color: #394829;
+ color: #9e9e9e;
+
+ &.message {
+ color: #87ab63;
+ .ui.text {
+ color: #9e9e9e;
+ }
+ .pull-right {
+ color: #87ab63;
+ }
+ }
+}
+
+.repository .ui.attached.message.isSigned.isVerifiedUntrusted {
+ background-color: #4a3903;
+ color: #9e9e9e;
+ &.message {
+ color: #c2c193;
+ .ui.text {
+ color: #9e9e9e;
+ }
+ .pull-right,
+ a {
+ color: #c2c193;
+ }
+ }
+}
+
+.repository .ui.attached.message.isSigned.isVerifiedUnmatched {
+ background-color: #4e3321;
+ color: #9e9e9e;
+ &.message {
+ color: #c2a893;
+ .ui.text {
+ color: #9e9e9e;
+ }
+ .pull-right,
+ a {
+ color: #c2a893;
+ }
+ }
+}
+
+.repository .ui.attached.message.isSigned.isWarning {
+ background-color: rgba(80, 23, 17, .6);
+ &.message {
+ color: #d07d7d;
+ .ui.text {
+ color: #d07d7d;
+ }
+ .pull-right {
+ color: #9e9e9e;
+ }
+ }
+}
+
.repository .label.list .item {
border-bottom: 1px dashed #4c505c;
}
@@ -1166,6 +1224,11 @@ a.ui.labels .label:hover {
color: #87ab63 !important;
}
+.ui.text.yellow,
+.yellow.icon.icon.icon {
+ color: #e4ac07 !important;
+}
+
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),