diff --git a/audit/cmd/notifications/main.go b/audit/cmd/notifications/main.go new file mode 100644 index 000000000..64d0cdc08 --- /dev/null +++ b/audit/cmd/notifications/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "os" + + "github.com/owncloud/ocis/audit/pkg/command" + "github.com/owncloud/ocis/audit/pkg/config" +) + +func main() { + if err := command.Execute(config.DefaultConfig()); err != nil { + os.Exit(1) + } +} diff --git a/audit/pkg/channels/channels.go b/audit/pkg/channels/channels.go new file mode 100644 index 000000000..f13914da4 --- /dev/null +++ b/audit/pkg/channels/channels.go @@ -0,0 +1,105 @@ +// Package channels provides different communication channels to notify users. +package channels + +import ( + "context" + "net/smtp" + + gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" + groups "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1" + rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" + "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/owncloud/ocis/ocis-pkg/log" + "github.com/pkg/errors" +) + +// Channel defines the methods of a communication channel. +type Channel interface { + // SendMessage sends a message to users. + SendMessage(userIDs []string, msg string) error + // SendMessageToGroup sends a message to a group. + SendMessageToGroup(groupdID *groups.GroupId, msg string) error +} + +// NewMailChannel instantiates a new mail communication channel. +func NewMailChannel(cfg config.Config, logger log.Logger) (Channel, error) { + gc, err := pool.GetGatewayServiceClient(cfg.Notifications.RevaGateway) + if err != nil { + logger.Error().Err(err).Msg("could not get gateway client") + return nil, err + } + return Mail{ + gatewayClient: gc, + conf: cfg, + logger: logger, + }, nil +} + +// Mail is the communcation channel for email. +type Mail struct { + gatewayClient gateway.GatewayAPIClient + conf config.Config + logger log.Logger +} + +// SendMessage sends a message to all given users. +func (m Mail) SendMessage(userIDs []string, msg string) error { + to, err := m.getReceiverAddresses(userIDs) + if err != nil { + return err + } + body := []byte(msg) + + smtpConf := m.conf.Notifications.SMTP + auth := smtp.PlainAuth("", smtpConf.Sender, smtpConf.Password, smtpConf.Host) + if err := smtp.SendMail(smtpConf.Host+":"+smtpConf.Port, auth, smtpConf.Sender, to, body); err != nil { + return errors.Wrap(err, "could not send mail") + } + return nil +} + +// SendMessageToGroup sends a message to all members of the given group. +func (m Mail) SendMessageToGroup(groupID *groups.GroupId, msg string) error { + // TODO We need an authenticated context here... + res, err := m.gatewayClient.GetGroup(context.Background(), &groups.GetGroupRequest{GroupId: groupID}) + if err != nil { + return err + } + if res.Status.Code != rpc.Code_CODE_OK { + return errors.New("could not get group") + } + + members := make([]string, 0, len(res.Group.Members)) + for _, id := range res.Group.Members { + members = append(members, id.OpaqueId) + } + + return m.SendMessage(members, msg) +} + +func (m Mail) getReceiverAddresses(receivers []string) ([]string, error) { + addresses := make([]string, 0, len(receivers)) + for _, id := range receivers { + // Authenticate is too costly but at the moment our only option to get the user. + // We don't have an authenticated context so calling `GetUser` doesn't work. + res, err := m.gatewayClient.Authenticate(context.Background(), &gateway.AuthenticateRequest{ + Type: "machine", + ClientId: "userid:" + id, + ClientSecret: m.conf.Notifications.MachineAuthSecret, + }) + if err != nil { + return nil, err + } + if res.Status.Code != rpc.Code_CODE_OK { + m.logger.Error(). + Interface("status", res.Status). + Str("receiver_id", id). + Msg("could not get user") + continue + } + addresses = append(addresses, res.User.Mail) + } + + return addresses, nil +} diff --git a/audit/pkg/command/health.go b/audit/pkg/command/health.go new file mode 100644 index 000000000..7f2adb85b --- /dev/null +++ b/audit/pkg/command/health.go @@ -0,0 +1,18 @@ +package command + +import ( + "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/urfave/cli/v2" +) + +// Health is the entrypoint for the health command. +func Health(cfg *config.Config) *cli.Command { + return &cli.Command{ + Name: "health", + Usage: "Check health status", + Action: func(c *cli.Context) error { + // Not implemented + return nil + }, + } +} diff --git a/audit/pkg/command/root.go b/audit/pkg/command/root.go new file mode 100644 index 000000000..805d8cec3 --- /dev/null +++ b/audit/pkg/command/root.go @@ -0,0 +1,64 @@ +package command + +import ( + "context" + "os" + + "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/owncloud/ocis/ocis-pkg/clihelper" + ociscfg "github.com/owncloud/ocis/ocis-pkg/config" + "github.com/thejerf/suture/v4" + "github.com/urfave/cli/v2" +) + +// GetCommands provides all commands for this service +func GetCommands(cfg *config.Config) cli.Commands { + return []*cli.Command{ + // start this service + Server(cfg), + + // interaction with this service + + // infos about this service + Health(cfg), + Version(cfg), + } +} + +// Execute is the entry point for the notifications command. +func Execute(cfg *config.Config) error { + app := clihelper.DefaultApp(&cli.App{ + Name: "notifications", + Usage: "starts notifications service", + Commands: GetCommands(cfg), + }) + + cli.HelpFlag = &cli.BoolFlag{ + Name: "help,h", + Usage: "Show the help", + } + + return app.Run(os.Args) +} + +// SutureService allows for the notifications command to be embedded and supervised by a suture supervisor tree. +type SutureService struct { + cfg *config.Config +} + +// NewSutureService creates a new notifications.SutureService +func NewSutureService(cfg *ociscfg.Config) suture.Service { + cfg.Settings.Commons = cfg.Commons + return SutureService{ + cfg: cfg.Notifications, + } +} + +func (s SutureService) Serve(ctx context.Context) error { + s.cfg.Context = ctx + if err := Execute(s.cfg); err != nil { + return err + } + + return nil +} diff --git a/audit/pkg/command/server.go b/audit/pkg/command/server.go new file mode 100644 index 000000000..37bd6375f --- /dev/null +++ b/audit/pkg/command/server.go @@ -0,0 +1,50 @@ +package command + +import ( + "fmt" + + "github.com/asim/go-micro/plugins/events/nats/v4" + "github.com/cs3org/reva/v2/pkg/events" + "github.com/cs3org/reva/v2/pkg/events/server" + "github.com/owncloud/ocis/notifications/pkg/channels" + "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/owncloud/ocis/notifications/pkg/config/parser" + "github.com/owncloud/ocis/notifications/pkg/logging" + "github.com/owncloud/ocis/notifications/pkg/service" + "github.com/urfave/cli/v2" +) + +// Server is the entrypoint for the server command. +func Server(cfg *config.Config) *cli.Command { + return &cli.Command{ + Name: "server", + Usage: fmt.Sprintf("start %s extension without runtime (unsupervised mode)", cfg.Service.Name), + Category: "server", + Before: func(c *cli.Context) error { + return parser.ParseConfig(cfg) + }, + Action: func(c *cli.Context) error { + logger := logging.Configure(cfg.Service.Name, cfg.Log) + + evs := []events.Unmarshaller{ + events.ShareCreated{}, + } + + evtsCfg := cfg.Notifications.Events + client, err := server.NewNatsStream(nats.Address(evtsCfg.Endpoint), nats.ClusterID(evtsCfg.Cluster)) + if err != nil { + return err + } + evts, err := events.Consume(client, evtsCfg.ConsumerGroup, evs...) + if err != nil { + return err + } + channel, err := channels.NewMailChannel(*cfg, logger) + if err != nil { + return err + } + svc := service.NewEventsNotifier(evts, channel, logger) + return svc.Run() + }, + } +} diff --git a/audit/pkg/command/version.go b/audit/pkg/command/version.go new file mode 100644 index 000000000..f2d47a569 --- /dev/null +++ b/audit/pkg/command/version.go @@ -0,0 +1,19 @@ +package command + +import ( + "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/urfave/cli/v2" +) + +// Version prints the service versions of all running instances. +func Version(cfg *config.Config) *cli.Command { + return &cli.Command{ + Name: "version", + Usage: "print the version of this binary and the running extension instances", + Category: "info", + Action: func(c *cli.Context) error { + // not implemented + return nil + }, + } +} diff --git a/audit/pkg/config/config.go b/audit/pkg/config/config.go new file mode 100644 index 000000000..8ac7da5d8 --- /dev/null +++ b/audit/pkg/config/config.go @@ -0,0 +1,44 @@ +package config + +import ( + "context" + + "github.com/owncloud/ocis/ocis-pkg/shared" +) + +// Config combines all available configuration parts. +type Config struct { + *shared.Commons + + Service Service + + Log *Log `ocisConfig:"log"` + Debug Debug `ocisConfig:"debug"` + + Notifications Notifications `ocisConfig:"notifications"` + + Context context.Context +} + +// Notifications definces the config options for the notifications service. +type Notifications struct { + SMTP SMTP `ocisConfig:"SMTP"` + Events Events `ocisConfig:"events"` + RevaGateway string `ocisConfig:"reva_gateway" env:"REVA_GATEWAY;NOTIFICATIONS_REVA_GATEWAY"` + MachineAuthSecret string `ocisConfig:"machine_auth_api_key" env:"OCIS_MACHINE_AUTH_API_KEY;NOTIFICATIONS_MACHINE_AUTH_API_KEY"` +} + +// SMTP combines the smtp configuration options. +type SMTP struct { + Host string `ocisConfig:"smtp_host" env:"NOTIFICATIONS_SMTP_HOST"` + Port string `ocisConfig:"smtp_port" env:"NOTIFICATIONS_SMTP_PORT"` + Sender string `ocisConfig:"smtp_sender" env:"NOTIFICATIONS_SMTP_SENDER"` + Password string `ocisConfig:"smtp_password" env:"NOTIFICATIONS_SMTP_PASSWORD"` +} + +// Events combines the configuration options for the event bus. +type Events struct { + Endpoint string `ocisConfig:"events_endpoint" env:"NOTIFICATIONS_EVENTS_ENDPOINT"` + Cluster string `ocisConfig:"events_cluster" env:"NOTIFICATIONS_EVENTS_CLUSTER"` + ConsumerGroup string `ocisConfig:"events_group" env:"NOTIFICATIONS_EVENTS_GROUP"` +} diff --git a/audit/pkg/config/debug.go b/audit/pkg/config/debug.go new file mode 100644 index 000000000..da6d2d590 --- /dev/null +++ b/audit/pkg/config/debug.go @@ -0,0 +1,9 @@ +package config + +// Debug defines the available debug configuration. +type Debug struct { + Addr string `ocisConfig:"addr" env:"NOTIFICATIONS_DEBUG_ADDR"` + Token string `ocisConfig:"token" env:"NOTIFICATIONS_DEBUG_TOKEN"` + Pprof bool `ocisConfig:"pprof" env:"NOTIFICATIONS_DEBUG_PPROF"` + Zpages bool `ocisConfig:"zpages" env:"NOTIFICATIONS_DEBUG_ZPAGES"` +} diff --git a/audit/pkg/config/defaultconfig.go b/audit/pkg/config/defaultconfig.go new file mode 100644 index 000000000..d5fb6e349 --- /dev/null +++ b/audit/pkg/config/defaultconfig.go @@ -0,0 +1,27 @@ +package config + +// NOTE: Most of this configuration is not needed to keep it as simple as possible +// TODO: Clean up unneeded configuration + +func DefaultConfig() *Config { + return &Config{ + Service: Service{ + Name: "notifications", + }, + Notifications: Notifications{ + SMTP: SMTP{ + Host: "127.0.0.1", + Port: "1025", + Sender: "god@example.com", + Password: "godisdead", + }, + Events: Events{ + Endpoint: "127.0.0.1:9233", + Cluster: "test-cluster", + ConsumerGroup: "notifications", + }, + RevaGateway: "127.0.0.1:9142", + MachineAuthSecret: "change-me-please", + }, + } +} diff --git a/audit/pkg/config/log.go b/audit/pkg/config/log.go new file mode 100644 index 000000000..ddb4d391f --- /dev/null +++ b/audit/pkg/config/log.go @@ -0,0 +1,9 @@ +package config + +// Log defines the available log configuration. +type Log struct { + Level string `mapstructure:"level" env:"OCIS_LOG_LEVEL;NOTIFICATIONS_LOG_LEVEL"` + Pretty bool `mapstructure:"pretty" env:"OCIS_LOG_PRETTY;NOTIFICATIONS_LOG_PRETTY"` + Color bool `mapstructure:"color" env:"OCIS_LOG_COLOR;NOTIFICATIONS_LOG_COLOR"` + File string `mapstructure:"file" env:"OCIS_LOG_FILE;NOTIFICATIONS_LOG_FILE"` +} diff --git a/audit/pkg/config/parser/parse.go b/audit/pkg/config/parser/parse.go new file mode 100644 index 000000000..5bc4e6e57 --- /dev/null +++ b/audit/pkg/config/parser/parse.go @@ -0,0 +1,40 @@ +package parser + +import ( + "errors" + + "github.com/owncloud/ocis/notifications/pkg/config" + ociscfg "github.com/owncloud/ocis/ocis-pkg/config" + + "github.com/owncloud/ocis/ocis-pkg/config/envdecode" +) + +// ParseConfig loads accounts configuration from known paths. +func ParseConfig(cfg *config.Config) error { + _, err := ociscfg.BindSourcesToStructs(cfg.Service.Name, cfg) + if err != nil { + return err + } + + // provide with defaults for shared logging, since we need a valid destination address for BindEnv. + if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil { + cfg.Log = &config.Log{ + Level: cfg.Commons.Log.Level, + Pretty: cfg.Commons.Log.Pretty, + Color: cfg.Commons.Log.Color, + File: cfg.Commons.Log.File, + } + } else if cfg.Log == nil { + cfg.Log = &config.Log{} + } + + // load all env variables relevant to the config in the current context. + if err := envdecode.Decode(cfg); err != nil { + // no environment variable set for this config is an expected "error" + if !errors.Is(err, envdecode.ErrNoTargetFieldsAreSet) { + return err + } + } + + return nil +} diff --git a/audit/pkg/config/service.go b/audit/pkg/config/service.go new file mode 100644 index 000000000..f98aa3d27 --- /dev/null +++ b/audit/pkg/config/service.go @@ -0,0 +1,6 @@ +package config + +// Service defines the available service configuration. +type Service struct { + Name string +} diff --git a/audit/pkg/logging/logging.go b/audit/pkg/logging/logging.go new file mode 100644 index 000000000..039b0451c --- /dev/null +++ b/audit/pkg/logging/logging.go @@ -0,0 +1,17 @@ +package logging + +import ( + "github.com/owncloud/ocis/notifications/pkg/config" + "github.com/owncloud/ocis/ocis-pkg/log" +) + +// LoggerFromConfig initializes a service-specific logger instance. +func Configure(name string, cfg *config.Log) log.Logger { + return log.NewLogger( + log.Name(name), + log.Level(cfg.Level), + log.Pretty(cfg.Pretty), + log.Color(cfg.Color), + log.File(cfg.File), + ) +} diff --git a/audit/pkg/service/events.go b/audit/pkg/service/events.go new file mode 100644 index 000000000..7c8a05d23 --- /dev/null +++ b/audit/pkg/service/events.go @@ -0,0 +1,79 @@ +package svc + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/asim/go-micro/plugins/events/nats/v4" + "github.com/cs3org/reva/v2/pkg/events" + "github.com/cs3org/reva/v2/pkg/events/server" + "github.com/owncloud/ocis/audit/pkg/config" + "github.com/owncloud/ocis/audit/pkg/types" + "github.com/owncloud/ocis/ocis-pkg/log" +) + +func startConsumer(c config.Eventstream, log log.Logger) (<-chan interface{}, error) { + s, err := server.NewNatsStream(nats.Address(c.Address), nats.ClusterID(c.ClusterID)) + if err != nil { + return nil, err + } + + return events.Consume(s, "audit", events.ShareCreated{}) +} + +func startAuditLogger(c config.Auditlog, ch <-chan interface{}, log log.Logger) { + for { + i := <-ch + + var auditEvent interface{} + switch ev := i.(type) { + case events.ShareCreated: + auditEvent = types.ShareCreated(ev) + default: + log.Error().Interface("event", ev).Msg(fmt.Sprintf("can't handle event of type '%T'", ev)) + continue + + } + + b, err := marshal(auditEvent, c.Format) + if err != nil { + log.Error().Err(err).Msg("error marshaling the event") + continue + } + + if c.LogToConsole { + log.Info().Msg(string(b)) + } + + if c.LogToFile { + err := writeToFile(c.FilePath, b) + if err != nil { + log.Error().Err(err).Msg("error writing audit log file") + } + } + + } + +} + +func writeToFile(path string, ev []byte) error { + file, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer file.Close() + if _, err := fmt.Fprintln(file, string(ev)); err != nil { + return err + } + return nil +} + +func marshal(ev interface{}, format string) ([]byte, error) { + switch format { + default: + return nil, fmt.Errorf("unsupported format '%s'", format) + case "json": + return json.Marshal(ev) + } +} diff --git a/audit/pkg/service/instrument.go b/audit/pkg/service/instrument.go new file mode 100644 index 000000000..0ebd9af67 --- /dev/null +++ b/audit/pkg/service/instrument.go @@ -0,0 +1,21 @@ +package svc + +/* +// NewInstrument returns a service that instruments metrics. +func NewInstrument(next Service, metrics *metrics.Metrics) Service { + return instrument{ + next: next, + metrics: metrics, + } +} + +type instrument struct { + next Service + metrics *metrics.Metrics +} + +// ListenForEvents implements service interface +func (i instrument) ListenForEvents() { + i.next.ListenForEvents() +} +*/ diff --git a/audit/pkg/service/logging.go b/audit/pkg/service/logging.go new file mode 100644 index 000000000..355a8ba66 --- /dev/null +++ b/audit/pkg/service/logging.go @@ -0,0 +1,23 @@ +package svc + +import ( + "github.com/owncloud/ocis/ocis-pkg/log" +) + +// NewLogging returns a service that logs messages. +func NewLogging(next Service, logger log.Logger) Service { + return logging{ + next: next, + logger: logger, + } +} + +type logging struct { + next Service + logger log.Logger +} + +// ListenForEvents implements service interface +func (l logging) ListenForEvents() { + l.next.ListenForEvents() +} diff --git a/audit/pkg/service/option.go b/audit/pkg/service/option.go new file mode 100644 index 000000000..ecca7d139 --- /dev/null +++ b/audit/pkg/service/option.go @@ -0,0 +1,50 @@ +package svc + +import ( + "net/http" + + "github.com/owncloud/ocis/audit/pkg/config" + "github.com/owncloud/ocis/ocis-pkg/log" +) + +// Option defines a single option function. +type Option func(o *Options) + +// Options defines the available options for this package. +type Options struct { + Logger log.Logger + Config *config.Config + Middleware []func(http.Handler) http.Handler +} + +// newOptions initializes the available default options. +func newOptions(opts ...Option) Options { + opt := Options{} + + for _, o := range opts { + o(&opt) + } + + return opt +} + +// Logger provides a function to set the logger option. +func Logger(val log.Logger) Option { + return func(o *Options) { + o.Logger = val + } +} + +// Config provides a function to set the config option. +func Config(val *config.Config) Option { + return func(o *Options) { + o.Config = val + } +} + +// Middleware provides a function to set the middleware option. +func Middleware(val ...func(http.Handler) http.Handler) Option { + return func(o *Options) { + o.Middleware = val + } +} diff --git a/audit/pkg/service/service.go b/audit/pkg/service/service.go new file mode 100644 index 000000000..c115f030a --- /dev/null +++ b/audit/pkg/service/service.go @@ -0,0 +1,48 @@ +package svc + +import ( + "github.com/go-chi/chi" + "github.com/owncloud/ocis/audit/pkg/config" + "github.com/owncloud/ocis/ocis-pkg/log" +) + +// Service defines the extension handlers. +type Service interface { + ListenForEvents() +} + +// NewService returns a service implementation for Service. +func NewService(opts ...Option) Service { + options := newOptions(opts...) + + m := chi.NewMux() + m.Use(options.Middleware...) + + svc := Audit{ + logger: options.Logger, + config: options.Config, + mux: m, + } + + go svc.ListenForEvents() + return svc +} + +// Audit defines implements the business logic for Service. +type Audit struct { + logger log.Logger + config *config.Config + mux *chi.Mux +} + +// ListenForEvents hooks into event queue and logs interesting events +func (g Audit) ListenForEvents() { + log := g.logger + ch, err := startConsumer(g.config.Eventstream, log) + if err != nil { + log.Fatal().Err(err).Msg("can't listen for events") + return + } + + startAuditLogger(g.config.Auditlog, ch, log) +} diff --git a/audit/pkg/service/tracing.go b/audit/pkg/service/tracing.go new file mode 100644 index 000000000..87b5ac392 --- /dev/null +++ b/audit/pkg/service/tracing.go @@ -0,0 +1,17 @@ +package svc + +// NewTracing returns a service that instruments traces. +func NewTracing(next Service) Service { + return tracing{ + next: next, + } +} + +type tracing struct { + next Service +} + +// ListenForEvents implements service interface +func (t tracing) ListenForEvents() { + t.next.ListenForEvents() +} diff --git a/audit/pkg/types/conversion.go b/audit/pkg/types/conversion.go new file mode 100644 index 000000000..c4ab66f5e --- /dev/null +++ b/audit/pkg/types/conversion.go @@ -0,0 +1,79 @@ +package types + +import ( + "fmt" + "time" + + "github.com/cs3org/reva/v2/pkg/events" +) + +// actions +const ( + actionShareCreated = "file_shared" +) + +// messages +const ( + messageShareCreated = "user '%s' shared file '%s' with '%s'" +) + +// BasicAuditEvent creates an AuditEvent from given values +func BasicAuditEvent(uid string, ctime string, msg string, action string) AuditEvent { + return AuditEvent{ + User: uid, + Time: ctime, + App: "admin_audit", + Message: msg, + Action: action, + Level: 1, + + // NOTE: those values are not in the events and can therefore not be filled at the moment + RemoteAddr: "", + URL: "", + Method: "", + UserAgent: "", + CLI: false, + } +} + +// SharingAuditEvent creates an AuditEventSharing from given values +func SharingAuditEvent(fileid string, uid string, base AuditEvent) AuditEventSharing { + return AuditEventSharing{ + AuditEvent: base, + FileID: fileid, + Owner: uid, + + // NOTE: those values are not in the events and can therefore not be filled at the moment + ShareID: "", + Path: "", + } +} + +// ShareCreated converts a ShareCreated Event to an AuditEventShareCreated +func ShareCreated(ev events.ShareCreated) AuditEventShareCreated { + with := "" + typ := "" + if ev.GranteeUserID != nil && ev.GranteeUserID.OpaqueId != "" { + with = ev.GranteeUserID.OpaqueId + typ = "user" + } else if ev.GranteeGroupID != nil && ev.GranteeGroupID.OpaqueId != "" { + with = ev.GranteeGroupID.OpaqueId + typ = "group" + } + uid := ev.Sharer.OpaqueId + t := time.Unix(int64(ev.CTime.Seconds), int64(ev.CTime.Nanos)).Format(time.RFC3339) + base := BasicAuditEvent(uid, t, fmt.Sprintf(messageShareCreated, uid, ev.ItemID.OpaqueId, with), actionShareCreated) + return AuditEventShareCreated{ + AuditEventSharing: SharingAuditEvent(ev.ItemID.OpaqueId, uid, base), + ShareOwner: uid, + ShareWith: with, + ShareType: typ, + + // NOTE: those values are not in the events and can therefore not be filled at the moment + ItemType: "", + ExpirationDate: "", + SharePass: false, + Permissions: "", + ShareToken: "", + } +} diff --git a/audit/pkg/types/types.go b/audit/pkg/types/types.go new file mode 100644 index 000000000..cd07e994f --- /dev/null +++ b/audit/pkg/types/types.go @@ -0,0 +1,40 @@ +package types + +// AuditEvent is the basic audit event +type AuditEvent struct { + RemoteAddr string // the remote client IP + User string // the UID of the user performing the action. Or "IP x.x.x.x.", "cron", "CLI", "unknown" + URL string // the process request URI + Method string // the HTTP request method + UserAgent string // the HTTP request user agent + Time string // the time of the event eg: 2018-05-08T08:26:00+00:00 + App string // always 'admin_audit' + Message string // sentence explaining the action + Action string // unique action identifier eg: file_delete or public_link_created + CLI bool // if the action was performed from the CLI + Level int // the log level of the entry (usually 1 for audit events) +} + +// AuditEventSharing is the basic audit event for shares +type AuditEventSharing struct { + AuditEvent + + FileID string // The file identifier for the item shared. + Owner string // The UID of the owner of the shared item. + Path string // The path to the shared item. + ShareID string // The sharing identifier. (not available for public_link_accessed or when recipient unshares) +} + +// AuditEventShareCreated is the event logged when a share is created +type AuditEventShareCreated struct { + AuditEventSharing + + ItemType string // file or folder + ExpirationDate string // The text expiration date in format 'yyyy-mm-dd' + SharePass bool // If the share is password protected. + Permissions string // The permissions string eg: "READ" + ShareType string // group user or link + ShareWith string // The UID or GID of the share recipient. (not available for public link) + ShareOwner string // The UID of the share owner. + ShareToken string // For link shares the unique token, else null +} diff --git a/go.mod b/go.mod index 448427b68..538439d5c 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( github.com/cs3org/reva/v2 v2.0.0-20220304131900-b8be80d1ba81 github.com/disintegration/imaging v1.6.2 github.com/glauth/glauth/v2 v2.0.0-20211021011345-ef3151c28733 + github.com/go-chi/chi v4.0.2+incompatible github.com/go-chi/chi/v5 v5.0.7 github.com/go-chi/cors v1.2.0 github.com/go-chi/render v1.0.1 @@ -46,6 +47,7 @@ require ( github.com/mennanov/fieldmask-utils v0.5.0 github.com/mitchellh/mapstructure v1.4.3 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 + github.com/nats-io/nats-server/v2 v2.7.3 github.com/nats-io/nats-streaming-server v0.24.2 github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba @@ -208,7 +210,6 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mschoch/smat v0.2.0 // indirect github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296 // indirect - github.com/nats-io/nats-server/v2 v2.7.3 // indirect github.com/nats-io/nats.go v1.13.1-0.20220121202836-972a071d373d // indirect github.com/nats-io/nkeys v0.3.0 // indirect github.com/nats-io/nuid v1.0.1 // indirect