Skip to content

Commit be666b0

Browse files
zeripathlafriks
authored andcommitted
Trace Logging on Permission Denied & ColorFormat (#6618)
* Add log.ColorFormat and log.ColorFormatted Structs can now implement log.ColorFormatted to provide their own colored format when logged with `%-v` or additional flags. Signed-off-by: Andrew Thornton <[email protected]> * Add basic ColorFormat to repository and user Signed-off-by: Andrew Thornton <[email protected]> * Add basic ColorFormat to access and unit Signed-off-by: Andrew Thornton <[email protected]> * Add ColorFormat to permission and on trace log it Signed-off-by: Andrew Thornton <[email protected]> * Add log.NewColoredIDValue to make ID value coloring consistent Signed-off-by: Andrew Thornton <[email protected]> * formatting changes * Add some better tracing to permission denied for read issues/pulls Signed-off-by: Andrew Thornton <[email protected]> * Add Trace logging on permission denied Signed-off-by: Andrew Thornton <[email protected]> * Remove isTrace() check from deferred func * Adjust repo and allow logging of team * use FormatInt instead of Itoa * Add blank line Signed-off-by: Andrew Thornton <[email protected]> * Update access.go
1 parent b83114f commit be666b0

File tree

17 files changed

+418
-12
lines changed

17 files changed

+418
-12
lines changed

docs/content/doc/advanced/logging-documentation.en-us.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,17 @@ also set the `resetBytes` to the cached `resetBytes`.
362362
The `colorBytes` and `resetBytes` are not exported to prevent
363363
accidental overwriting of internal values.
364364

365+
## ColorFormat & ColorFormatted
366+
367+
Structs may implement the `log.ColorFormatted` interface by implementing the `ColorFormat(fmt.State)` function.
368+
369+
If a `log.ColorFormatted` struct is logged with `%-v` format, its `ColorFormat` will be used instead of the usual `%v`. The full `fmt.State` will be passed to allow implementers to look at additional flags.
370+
371+
In order to help implementers provide `ColorFormat` methods. There is a
372+
`log.ColorFprintf(...)` function in the log module that will wrap values in `log.ColoredValue` and recognise `%-v`.
373+
374+
In general it is recommended not to make the results of this function too verbose to help increase its versatility. Usually this should simply be an `ID`:`Name`. If you wish to make a more verbose result, it is recommended to use `%-+v` as your marker.
375+
365376
## Log Spoofing protection
366377

367378
In order to protect the logs from being spoofed with cleverly
@@ -392,5 +403,5 @@ func newNewoneLogService() {
392403
}
393404
```
394405

395-
You should then add `newOneLogService` to `NewServices()` in
406+
You should then add `newOneLogService` to `NewServices()` in
396407
`modules/setting/setting.go`

models/access.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
// Copyright 2014 The Gogs Authors. All rights reserved.
2+
// Copyright 2019 The Gitea Authors. All rights reserved.
23
// Use of this source code is governed by a MIT-style
34
// license that can be found in the LICENSE file.
45

56
package models
67

7-
import "fmt"
8+
import (
9+
"fmt"
10+
11+
"code.gitea.io/gitea/modules/log"
12+
)
813

914
// AccessMode specifies the users access mode
1015
type AccessMode int
@@ -37,6 +42,13 @@ func (mode AccessMode) String() string {
3742
}
3843
}
3944

45+
// ColorFormat provides a ColorFormatted version of this AccessMode
46+
func (mode AccessMode) ColorFormat(s fmt.State) {
47+
log.ColorFprintf(s, "%d:%s",
48+
log.NewColoredIDValue(mode),
49+
mode)
50+
}
51+
4052
// ParseAccessMode returns corresponding access mode to given permission string.
4153
func ParseAccessMode(permission string) AccessMode {
4254
switch permission {

models/org_team.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ type Team struct {
3434
Units []*TeamUnit `xorm:"-"`
3535
}
3636

37+
// ColorFormat provides a basic color format for a Team
38+
func (t *Team) ColorFormat(s fmt.State) {
39+
log.ColorFprintf(s, "%d:%s (OrgID: %d) %-v",
40+
log.NewColoredIDValue(t.ID),
41+
t.Name,
42+
log.NewColoredIDValue(t.OrgID),
43+
t.Authorize)
44+
45+
}
46+
3747
// GetUnits return a list of available units for a team
3848
func (t *Team) GetUnits() error {
3949
return t.getUnits(x)

models/repo.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"path/filepath"
1919
"regexp"
2020
"sort"
21+
"strconv"
2122
"strings"
2223
"time"
2324

@@ -210,6 +211,24 @@ type Repository struct {
210211
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
211212
}
212213

214+
// ColorFormat returns a colored string to represent this repo
215+
func (repo *Repository) ColorFormat(s fmt.State) {
216+
var ownerName interface{}
217+
218+
if repo.OwnerName != "" {
219+
ownerName = repo.OwnerName
220+
} else if repo.Owner != nil {
221+
ownerName = repo.Owner.Name
222+
} else {
223+
ownerName = log.NewColoredIDValue(strconv.FormatInt(repo.OwnerID, 10))
224+
}
225+
226+
log.ColorFprintf(s, "%d:%s/%s",
227+
log.NewColoredIDValue(repo.ID),
228+
ownerName,
229+
repo.Name)
230+
}
231+
213232
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
214233
func (repo *Repository) AfterLoad() {
215234
// FIXME: use models migration to solve all at once.

models/repo_permission.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44

55
package models
66

7+
import (
8+
"fmt"
9+
10+
"code.gitea.io/gitea/modules/log"
11+
)
12+
713
// Permission contains all the permissions related variables to a repository for a user
814
type Permission struct {
915
AccessMode AccessMode
@@ -90,12 +96,67 @@ func (p *Permission) CanWriteIssuesOrPulls(isPull bool) bool {
9096
return p.CanWrite(UnitTypeIssues)
9197
}
9298

99+
// ColorFormat writes a colored string for these Permissions
100+
func (p *Permission) ColorFormat(s fmt.State) {
101+
noColor := log.ColorBytes(log.Reset)
102+
103+
format := "AccessMode: %-v, %d Units, %d UnitsMode(s): [ "
104+
args := []interface{}{
105+
p.AccessMode,
106+
log.NewColoredValueBytes(len(p.Units), &noColor),
107+
log.NewColoredValueBytes(len(p.UnitsMode), &noColor),
108+
}
109+
if s.Flag('+') {
110+
for i, unit := range p.Units {
111+
config := ""
112+
if unit.Config != nil {
113+
configBytes, err := unit.Config.ToDB()
114+
config = string(configBytes)
115+
if err != nil {
116+
config = string(err.Error())
117+
}
118+
}
119+
format += "\nUnits[%d]: ID: %d RepoID: %d Type: %-v Config: %s"
120+
args = append(args,
121+
log.NewColoredValueBytes(i, &noColor),
122+
log.NewColoredIDValue(unit.ID),
123+
log.NewColoredIDValue(unit.RepoID),
124+
unit.Type,
125+
config)
126+
}
127+
for key, value := range p.UnitsMode {
128+
format += "\nUnitMode[%-v]: %-v"
129+
args = append(args,
130+
key,
131+
value)
132+
}
133+
} else {
134+
format += "..."
135+
}
136+
format += " ]"
137+
log.ColorFprintf(s, format, args...)
138+
}
139+
93140
// GetUserRepoPermission returns the user permissions to the repository
94141
func GetUserRepoPermission(repo *Repository, user *User) (Permission, error) {
95142
return getUserRepoPermission(x, repo, user)
96143
}
97144

98145
func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permission, err error) {
146+
if log.IsTrace() {
147+
defer func() {
148+
if user == nil {
149+
log.Trace("Permission Loaded for anonymous user in %-v:\nPermissions: %-+v",
150+
repo,
151+
perm)
152+
return
153+
}
154+
log.Trace("Permission Loaded for %-v in %-v:\nPermissions: %-+v",
155+
user,
156+
repo,
157+
perm)
158+
}()
159+
}
99160
// anonymous user visit private repo.
100161
// TODO: anonymous user visit public unit of private repo???
101162
if user == nil && repo.IsPrivate {

models/unit.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
package models
66

77
import (
8+
"fmt"
89
"strings"
10+
11+
"code.gitea.io/gitea/modules/log"
912
)
1013

1114
// UnitType is Unit's Type
@@ -22,6 +25,33 @@ const (
2225
UnitTypeExternalTracker // 7 ExternalTracker
2326
)
2427

28+
func (u UnitType) String() string {
29+
switch u {
30+
case UnitTypeCode:
31+
return "UnitTypeCode"
32+
case UnitTypeIssues:
33+
return "UnitTypeIssues"
34+
case UnitTypePullRequests:
35+
return "UnitTypePullRequests"
36+
case UnitTypeReleases:
37+
return "UnitTypeReleases"
38+
case UnitTypeUncyclo:
39+
return "UnitTypeUncyclo"
40+
case UnitTypeExternalUncyclo:
41+
return "UnitTypeExternalUncyclo"
42+
case UnitTypeExternalTracker:
43+
return "UnitTypeExternalTracker"
44+
}
45+
return fmt.Sprintf("Unknown UnitType %d", u)
46+
}
47+
48+
// ColorFormat provides a ColorFormatted version of this UnitType
49+
func (u UnitType) ColorFormat(s fmt.State) {
50+
log.ColorFprintf(s, "%d:%s",
51+
log.NewColoredIDValue(u),
52+
u)
53+
}
54+
2555
var (
2656
// allRepUnitTypes contains all the unit types
2757
allRepUnitTypes = []UnitType{

models/user.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,13 @@ type User struct {
146146
Theme string `xorm:"NOT NULL DEFAULT ''"`
147147
}
148148

149+
// ColorFormat writes a colored string to identify this struct
150+
func (u *User) ColorFormat(s fmt.State) {
151+
log.ColorFprintf(s, "%d:%s",
152+
log.NewColoredIDValue(u.ID),
153+
log.NewColoredValue(u.Name))
154+
}
155+
149156
// BeforeUpdate is invoked from XORM before updating this object.
150157
func (u *User) BeforeUpdate() {
151158
if u.MaxRepoCreation < -1 {

modules/context/permission.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ package context
66

77
import (
88
"code.gitea.io/gitea/models"
9+
"code.gitea.io/gitea/modules/log"
10+
911
macaron "gopkg.in/macaron.v1"
1012
)
1113

@@ -45,6 +47,22 @@ func RequireRepoWriterOr(unitTypes ...models.UnitType) macaron.Handler {
4547
func RequireRepoReader(unitType models.UnitType) macaron.Handler {
4648
return func(ctx *Context) {
4749
if !ctx.Repo.CanRead(unitType) {
50+
if log.IsTrace() {
51+
if ctx.IsSigned {
52+
log.Trace("Permission Denied: User %-v cannot read %-v in Repo %-v\n"+
53+
"User in Repo has Permissions: %-+v",
54+
ctx.User,
55+
unitType,
56+
ctx.Repo.Repository,
57+
ctx.Repo.Permission)
58+
} else {
59+
log.Trace("Permission Denied: Anonymous user cannot read %-v in Repo %-v\n"+
60+
"Anonymous user in Repo has Permissions: %-+v",
61+
unitType,
62+
ctx.Repo.Repository,
63+
ctx.Repo.Permission)
64+
}
65+
}
4866
ctx.NotFound(ctx.Req.RequestURI, nil)
4967
return
5068
}
@@ -59,6 +77,25 @@ func RequireRepoReaderOr(unitTypes ...models.UnitType) macaron.Handler {
5977
return
6078
}
6179
}
80+
if log.IsTrace() {
81+
var format string
82+
var args []interface{}
83+
if ctx.IsSigned {
84+
format = "Permission Denied: User %-v cannot read ["
85+
args = append(args, ctx.User)
86+
} else {
87+
format = "Permission Denied: Anonymous user cannot read ["
88+
}
89+
for _, unit := range unitTypes {
90+
format += "%-v, "
91+
args = append(args, unit)
92+
}
93+
94+
format = format[:len(format)-2] + "] in Repo %-v\n" +
95+
"User in Repo has Permissions: %-+v"
96+
args = append(args, ctx.Repo.Repository, ctx.Repo.Permission)
97+
log.Trace(format, args...)
98+
}
6299
ctx.NotFound(ctx.Req.RequestURI, nil)
63100
}
64101
}

0 commit comments

Comments
 (0)