vikunja/pkg/audit/entry.go

128 lines
4.6 KiB
Go

// Vikunja is a to-do list application to facilitate your life.
// Copyright 2018-present Vikunja and contributors. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package audit
import "time"
// Entry is one audit log record. It only references actors and targets by
// opaque ID — no names, emails or content — so GDPR erasure is satisfied by
// deleting the referenced row.
type Entry struct {
EventID string `json:"event_id"` // UUIDv7
Timestamp time.Time `json:"timestamp"`
Actor Actor `json:"actor"`
Source Source `json:"source"`
Action string `json:"action"`
Target Target `json:"target"`
Outcome string `json:"outcome"`
Reason string `json:"reason,omitempty"`
RequestID string `json:"request_id,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
type actorType string
type targetType string
// Actor is the principal which performed the audited action.
type Actor struct {
Type actorType `json:"type"`
ID int64 `json:"id,omitempty"`
}
// Source describes where the action originated from.
type Source struct {
Type string `json:"type"`
IP string `json:"ip,omitempty"`
UserAgent string `json:"user_agent,omitempty"`
}
// Target is the resource the audited action was performed on.
type Target struct {
Type targetType `json:"type"`
ID int64 `json:"id,omitempty"`
}
// Outcome values for an Entry.
const (
OutcomeSuccess = "success"
OutcomeFailure = "failure"
)
// Source types for an Entry.
const (
SourceHTTP = "http"
SourceSystem = "system"
)
// The action catalog. Every audited action is listed here.
const (
ActionLoginSucceeded = "auth.login.succeeded"
ActionLoginFailed = "auth.login.failed"
ActionLogout = "auth.logout"
ActionAPITokenIssued = "auth.api_token.issued"
ActionAPITokenRevoked = "auth.api_token.revoked"
ActionAPITokenUsed = "auth.api_token.used"
ActionUserCreated = "user.created"
ActionTaskCreated = "task.created"
ActionTaskUpdated = "task.updated"
ActionTaskDeleted = "task.deleted"
ActionTaskAssigneeAdded = "task.assignee.added"
ActionTaskAssigneeRemoved = "task.assignee.removed"
ActionTaskCommentCreated = "task.comment.created"
ActionTaskCommentUpdated = "task.comment.updated"
ActionTaskCommentDeleted = "task.comment.deleted"
ActionTaskAttachmentCreated = "task.attachment.created"
ActionTaskAttachmentDeleted = "task.attachment.deleted"
ActionTaskRelationCreated = "task.relation.created"
ActionTaskRelationDeleted = "task.relation.deleted"
ActionProjectCreated = "project.created"
ActionProjectUpdated = "project.updated"
ActionProjectDeleted = "project.deleted"
ActionProjectSharedWithUser = "project.shared.user"
ActionProjectSharedWithTeam = "project.shared.team"
ActionTeamCreated = "team.created"
ActionTeamDeleted = "team.deleted"
ActionTeamMemberAdded = "team.member.added"
ActionTeamMemberRemoved = "team.member.removed"
)
// The type strings are unexported; these constructors are the only way to
// build an Actor or Target, so a mismatched type/ID pair can't be expressed.
func UserActor(id int64) Actor { return Actor{Type: "user", ID: id} }
func LinkShareActor(id int64) Actor { return Actor{Type: "link_share", ID: id} }
func SystemActor() Actor { return Actor{Type: "system"} }
// ActorFromDoerID maps a doer ID to an actor. Link shares are disguised as
// users with negative IDs throughout the event payloads.
func ActorFromDoerID(id int64) Actor {
if id < 0 {
return LinkShareActor(-id)
}
return UserActor(id)
}
func TaskTarget(id int64) Target { return Target{Type: "task", ID: id} }
func ProjectTarget(id int64) Target { return Target{Type: "project", ID: id} }
func UserTarget(id int64) Target { return Target{Type: "user", ID: id} }
func TeamTarget(id int64) Target { return Target{Type: "team", ID: id} }
func APITokenTarget(id int64) Target { return Target{Type: "api_token", ID: id} }