github.com/adacta-ru/mattermost-server/v6@v6.0.0/app/audit.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package app 5 6 import ( 7 "errors" 8 "fmt" 9 "net/http" 10 "os/user" 11 12 "github.com/hashicorp/go-multierror" 13 "github.com/adacta-ru/mattermost-server/v6/audit" 14 "github.com/adacta-ru/mattermost-server/v6/config" 15 "github.com/adacta-ru/mattermost-server/v6/mlog" 16 "github.com/adacta-ru/mattermost-server/v6/model" 17 "github.com/adacta-ru/mattermost-server/v6/store" 18 ) 19 20 const ( 21 RestLevelID = 240 22 RestContentLevelID = 241 23 RestPermsLevelID = 242 24 CLILevelID = 243 25 ) 26 27 var ( 28 LevelAPI = mlog.LvlAuditAPI 29 LevelContent = mlog.LvlAuditContent 30 LevelPerms = mlog.LvlAuditPerms 31 LevelCLI = mlog.LvlAuditCLI 32 ) 33 34 func (a *App) GetAudits(userId string, limit int) (model.Audits, *model.AppError) { 35 audits, err := a.Srv().Store.Audit().Get(userId, 0, limit) 36 if err != nil { 37 var outErr *store.ErrOutOfBounds 38 switch { 39 case errors.As(err, &outErr): 40 return nil, model.NewAppError("GetAudits", "app.audit.get.limit.app_error", nil, err.Error(), http.StatusBadRequest) 41 default: 42 return nil, model.NewAppError("GetAudits", "app.audit.get.finding.app_error", nil, err.Error(), http.StatusInternalServerError) 43 } 44 } 45 return audits, nil 46 } 47 48 func (a *App) GetAuditsPage(userId string, page int, perPage int) (model.Audits, *model.AppError) { 49 audits, err := a.Srv().Store.Audit().Get(userId, page*perPage, perPage) 50 if err != nil { 51 var outErr *store.ErrOutOfBounds 52 switch { 53 case errors.As(err, &outErr): 54 return nil, model.NewAppError("GetAuditsPage", "app.audit.get.limit.app_error", nil, err.Error(), http.StatusBadRequest) 55 default: 56 return nil, model.NewAppError("GetAuditsPage", "app.audit.get.finding.app_error", nil, err.Error(), http.StatusInternalServerError) 57 } 58 } 59 return audits, nil 60 } 61 62 // LogAuditRec logs an audit record using default LvlAuditCLI. 63 func (a *App) LogAuditRec(rec *audit.Record, err error) { 64 a.LogAuditRecWithLevel(rec, mlog.LvlAuditCLI, err) 65 } 66 67 // LogAuditRecWithLevel logs an audit record using specified Level. 68 func (a *App) LogAuditRecWithLevel(rec *audit.Record, level mlog.LogLevel, err error) { 69 if rec == nil { 70 return 71 } 72 if err != nil { 73 if appErr, ok := err.(*model.AppError); ok { 74 rec.AddMeta("err", appErr.Error()) 75 rec.AddMeta("code", appErr.StatusCode) 76 } else { 77 rec.AddMeta("err", err) 78 } 79 rec.Fail() 80 } 81 a.Srv().Audit.LogRecord(level, *rec) 82 } 83 84 // MakeAuditRecord creates a audit record pre-populated with defaults. 85 func (a *App) MakeAuditRecord(event string, initialStatus string) *audit.Record { 86 var userID string 87 user, err := user.Current() 88 if err == nil { 89 userID = fmt.Sprintf("%s:%s", user.Uid, user.Username) 90 } 91 92 rec := &audit.Record{ 93 APIPath: "", 94 Event: event, 95 Status: initialStatus, 96 UserID: userID, 97 SessionID: "", 98 Client: fmt.Sprintf("server %s-%s", model.BuildNumber, model.BuildHash), 99 IPAddress: "", 100 Meta: audit.Meta{audit.KeyClusterID: a.GetClusterId()}, 101 } 102 rec.AddMetaTypeConverter(model.AuditModelTypeConv) 103 104 return rec 105 } 106 107 func (s *Server) configureAudit(adt *audit.Audit, bAllowAdvancedLogging bool) error { 108 var errs error 109 110 adt.OnQueueFull = s.onAuditTargetQueueFull 111 adt.OnError = s.onAuditError 112 113 // Configure target for rotating file output (E0, E10) 114 if *s.Config().ExperimentalAuditSettings.FileEnabled { 115 opts := audit.FileOptions{ 116 Filename: *s.Config().ExperimentalAuditSettings.FileName, 117 MaxSize: *s.Config().ExperimentalAuditSettings.FileMaxSizeMB, 118 MaxAge: *s.Config().ExperimentalAuditSettings.FileMaxAgeDays, 119 MaxBackups: *s.Config().ExperimentalAuditSettings.FileMaxBackups, 120 Compress: *s.Config().ExperimentalAuditSettings.FileCompress, 121 } 122 123 maxQueueSize := *s.Config().ExperimentalAuditSettings.FileMaxQueueSize 124 if maxQueueSize <= 0 { 125 maxQueueSize = audit.DefMaxQueueSize 126 } 127 128 filter := adt.MakeFilter(LevelAPI, LevelContent, LevelPerms, LevelCLI) 129 formatter := adt.MakeJSONFormatter() 130 formatter.DisableTimestamp = false 131 target, err := audit.NewFileTarget(filter, formatter, opts, maxQueueSize) 132 if err != nil { 133 errs = multierror.Append(err) 134 } else { 135 mlog.Debug("File audit target created successfully", mlog.String("filename", opts.Filename)) 136 adt.AddTarget(target) 137 } 138 } 139 140 // Advanced logging for audit requires license. 141 dsn := *s.Config().ExperimentalAuditSettings.AdvancedLoggingConfig 142 if !bAllowAdvancedLogging || dsn == "" { 143 return errs 144 } 145 isJson := config.IsJsonMap(dsn) 146 cfg, err := config.NewLogConfigSrc(dsn, isJson, s.configStore) 147 if err != nil { 148 errs = multierror.Append(fmt.Errorf("invalid config for audit, %w", err)) 149 return errs 150 } 151 if !isJson { 152 mlog.Debug("Loaded audit configuration", mlog.String("filename", dsn)) 153 } 154 155 for name, t := range cfg.Get() { 156 if len(t.Levels) == 0 { 157 t.Levels = mlog.MLvlAuditAll 158 } 159 target, err := mlog.NewLogrTarget(name, t) 160 if err != nil { 161 errs = multierror.Append(err) 162 continue 163 } 164 if target != nil { 165 adt.AddTarget(target) 166 } 167 } 168 return errs 169 } 170 171 func (s *Server) onAuditTargetQueueFull(qname string, maxQSize int) bool { 172 mlog.Error("Audit queue full, dropping record.", mlog.String("qname", qname), mlog.Int("queueSize", maxQSize)) 173 return true // drop it 174 } 175 176 func (s *Server) onAuditError(err error) { 177 mlog.Error("Audit Error", mlog.Err(err)) 178 }