Switch to SQLite for activity tracking

This commit is contained in:
DaneEveritt
2022-07-10 16:51:11 -04:00
parent e1e7916790
commit 7bd11c1c28
16 changed files with 269 additions and 745 deletions

View File

@@ -1,13 +1,9 @@
package sftp
import (
"bytes"
"emperror.dev/errors"
"encoding/gob"
"github.com/apex/log"
"github.com/pterodactyl/wings/internal/database"
"github.com/xujiajun/nutsdb"
"regexp"
"github.com/pterodactyl/wings/server"
"time"
)
@@ -17,7 +13,6 @@ type eventHandler struct {
server string
}
type Event string
type FileAction struct {
// Entity is the targeted file or directory (depending on the event) that the action
// is being performed _against_, such as "/foo/test.txt". This will always be the full
@@ -29,53 +24,33 @@ type FileAction struct {
Target string
}
type EventRecord struct {
Event Event
Action FileAction
IP string
User string
Timestamp time.Time
}
// Log parses a SFTP specific file activity event and then passes it off to be stored
// in the normal activity database.
func (eh *eventHandler) Log(e server.Event, fa FileAction) error {
metadata := map[string]interface{}{
"files": []string{fa.Entity},
}
if fa.Target != "" {
metadata["files"] = []map[string]string{
{"from": fa.Entity, "to": fa.Target},
}
}
const (
EventWrite = Event("write")
EventCreate = Event("create")
EventCreateDirectory = Event("create-directory")
EventRename = Event("rename")
EventDelete = Event("delete")
)
var ipTrimRegex = regexp.MustCompile(`(:\d*)?$`)
// Log logs an event into the Wings bucket for SFTP activity which then allows a seperate
// cron to run and parse the events into a more manageable stream of event data to send
// back to the Panel instance.
func (eh *eventHandler) Log(e Event, fa FileAction) error {
r := EventRecord{
Event: e,
Action: fa,
IP: ipTrimRegex.ReplaceAllString(eh.ip, ""),
r := server.Activity{
User: eh.user,
Server: eh.server,
Event: e,
Metadata: metadata,
IP: eh.ip,
Timestamp: time.Now().UTC(),
}
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
if err := enc.Encode(r); err != nil {
return errors.Wrap(err, "sftp: failed to encode event")
}
return database.DB().Update(func(tx *nutsdb.Tx) error {
if err := tx.RPush(database.SftpActivityBucket, []byte(eh.server), buf.Bytes()); err != nil {
return errors.Wrap(err, "sftp: failed to push event to stack")
}
return nil
})
return errors.Wrap(r.Save(), "sftp: failed to store file event")
}
// MustLog is a wrapper around log that will trigger a fatal error and exit the application
// if an error is encountered during the logging of the event.
func (eh *eventHandler) MustLog(e Event, fa FileAction) {
func (eh *eventHandler) MustLog(e server.Event, fa FileAction) {
if err := eh.Log(e, fa); err != nil {
log.WithField("error", err).Fatal("sftp: failed to log event")
}

View File

@@ -130,9 +130,9 @@ func (h *Handler) Filewrite(request *sftp.Request) (io.WriterAt, error) {
// Chown may or may not have been called in the touch function, so always do
// it at this point to avoid the file being improperly owned.
_ = h.fs.Chown(request.Filepath)
event := EventWrite
event := server.ActivitySftpWrite
if permission == PermissionFileCreate {
event = EventCreate
event = server.ActivitySftpCreate
}
h.events.MustLog(event, FileAction{Entity: request.Filepath})
return f, nil
@@ -185,7 +185,7 @@ func (h *Handler) Filecmd(request *sftp.Request) error {
l.WithField("error", err).Error("failed to rename file")
return sftp.ErrSSHFxFailure
}
h.events.MustLog(EventRename, FileAction{Entity: request.Filepath, Target: request.Target})
h.events.MustLog(server.ActivitySftpRename, FileAction{Entity: request.Filepath, Target: request.Target})
break
// Handle deletion of a directory. This will properly delete all of the files and
// folders within that directory if it is not already empty (unlike a lot of SFTP
@@ -199,7 +199,7 @@ func (h *Handler) Filecmd(request *sftp.Request) error {
l.WithField("error", err).Error("failed to remove directory")
return sftp.ErrSSHFxFailure
}
h.events.MustLog(EventDelete, FileAction{Entity: request.Filepath})
h.events.MustLog(server.ActivitySftpDelete, FileAction{Entity: request.Filepath})
return sftp.ErrSSHFxOk
// Handle requests to create a new Directory.
case "Mkdir":
@@ -212,7 +212,7 @@ func (h *Handler) Filecmd(request *sftp.Request) error {
l.WithField("error", err).Error("failed to create directory")
return sftp.ErrSSHFxFailure
}
h.events.MustLog(EventCreateDirectory, FileAction{Entity: request.Filepath})
h.events.MustLog(server.ActivitySftpCreateDirectory, FileAction{Entity: request.Filepath})
break
// Support creating symlinks between files. The source and target must resolve within
// the server home directory.
@@ -245,7 +245,7 @@ func (h *Handler) Filecmd(request *sftp.Request) error {
l.WithField("error", err).Error("failed to remove a file")
return sftp.ErrSSHFxFailure
}
h.events.MustLog(EventDelete, FileAction{Entity: request.Filepath})
h.events.MustLog(server.ActivitySftpDelete, FileAction{Entity: request.Filepath})
return sftp.ErrSSHFxOk
default:
return sftp.ErrSSHFxOpUnsupported