mirror of
https://github.com/OliveTin/OliveTin
synced 2025-12-12 09:05:39 +00:00
@@ -2,6 +2,7 @@ package acl
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
config "github.com/OliveTin/OliveTin/internal/config"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
@@ -135,24 +136,21 @@ func getMetadataKeyOrEmpty(md metadata.MD, key string) string {
|
||||
|
||||
// UserFromContext tries to find a user from a grpc context
|
||||
func UserFromContext(ctx context.Context, cfg *config.Config) *AuthenticatedUser {
|
||||
ret := &AuthenticatedUser{}
|
||||
var ret *AuthenticatedUser
|
||||
|
||||
md, ok := metadata.FromIncomingContext(ctx)
|
||||
|
||||
if ok {
|
||||
ret = &AuthenticatedUser{}
|
||||
ret.Username = getMetadataKeyOrEmpty(md, "username")
|
||||
ret.Usergroup = getMetadataKeyOrEmpty(md, "usergroup")
|
||||
}
|
||||
|
||||
if ret.Username == "" {
|
||||
ret.Username = "guest"
|
||||
}
|
||||
|
||||
if ret.Usergroup == "" {
|
||||
ret.Usergroup = "guest"
|
||||
}
|
||||
|
||||
buildUserAcls(cfg, ret)
|
||||
}
|
||||
|
||||
if !ok || ret.Username == "" {
|
||||
ret = UserGuest(cfg)
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"username": ret.Username,
|
||||
@@ -162,6 +160,16 @@ func UserFromContext(ctx context.Context, cfg *config.Config) *AuthenticatedUser
|
||||
return ret
|
||||
}
|
||||
|
||||
func UserGuest(cfg *config.Config) *AuthenticatedUser {
|
||||
ret := &AuthenticatedUser{}
|
||||
ret.Username = "guest"
|
||||
ret.Usergroup = "guest"
|
||||
|
||||
buildUserAcls(cfg, ret)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func UserFromSystem(cfg *config.Config, username string) *AuthenticatedUser {
|
||||
ret := &AuthenticatedUser{
|
||||
Username: username,
|
||||
|
||||
@@ -84,6 +84,7 @@ type InternalLogEntry struct {
|
||||
ExecutionFinished bool
|
||||
ExecutionTrackingID string
|
||||
Process *os.Process
|
||||
Username string
|
||||
|
||||
/*
|
||||
The following 3 properties are obviously on Action normally, but it's useful
|
||||
@@ -182,6 +183,10 @@ func (e *Executor) SetLog(trackingID string, entry *InternalLogEntry) {
|
||||
|
||||
// ExecRequest processes an ExecutionRequest
|
||||
func (e *Executor) ExecRequest(req *ExecutionRequest) (*sync.WaitGroup, string) {
|
||||
if req.AuthenticatedUser == nil {
|
||||
req.AuthenticatedUser = acl.UserGuest(req.Cfg)
|
||||
}
|
||||
|
||||
req.executor = e
|
||||
req.logEntry = &InternalLogEntry{
|
||||
DatetimeStarted: time.Now(),
|
||||
@@ -193,6 +198,7 @@ func (e *Executor) ExecRequest(req *ExecutionRequest) (*sync.WaitGroup, string)
|
||||
ActionId: "",
|
||||
ActionTitle: "notfound",
|
||||
ActionIcon: "💩",
|
||||
Username: req.AuthenticatedUser.Username,
|
||||
}
|
||||
|
||||
_, isDuplicate := e.GetLog(req.TrackingID)
|
||||
|
||||
@@ -2,6 +2,7 @@ package grpcapi
|
||||
|
||||
import (
|
||||
ctx "context"
|
||||
|
||||
pb "github.com/OliveTin/OliveTin/gen/grpc"
|
||||
"github.com/google/uuid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -75,12 +76,14 @@ func (api *oliveTinAPI) StartAction(ctx ctx.Context, req *pb.StartActionRequest)
|
||||
return nil, status.Errorf(codes.NotFound, "Action not found.")
|
||||
}
|
||||
|
||||
authenticatedUser := acl.UserFromContext(ctx, cfg)
|
||||
|
||||
execReq := executor.ExecutionRequest{
|
||||
Action: pair.Action,
|
||||
EntityPrefix: pair.EntityPrefix,
|
||||
TrackingID: req.UniqueTrackingId,
|
||||
Arguments: args,
|
||||
AuthenticatedUser: acl.UserFromContext(ctx, cfg),
|
||||
AuthenticatedUser: authenticatedUser,
|
||||
Cfg: cfg,
|
||||
}
|
||||
|
||||
@@ -174,6 +177,7 @@ func internalLogEntryToPb(logEntry *executor.InternalLogEntry) *pb.LogEntry {
|
||||
ExecutionTrackingId: logEntry.ExecutionTrackingID,
|
||||
ExecutionStarted: logEntry.ExecutionStarted,
|
||||
ExecutionFinished: logEntry.ExecutionFinished,
|
||||
User: logEntry.Username,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ func exec(instant time.Time, action *config.Action, cfg *config.Config, ex *exec
|
||||
req := &executor.ExecutionRequest{
|
||||
Action: action,
|
||||
Cfg: cfg,
|
||||
Tags: []string{"calendar"},
|
||||
Tags: []string{},
|
||||
AuthenticatedUser: acl.UserFromSystem(cfg, "calendar"),
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ func scheduleAction(cfg *config.Config, scheduler *cron.Cron, cronline string, e
|
||||
req := &executor.ExecutionRequest{
|
||||
ActionTitle: action.Title,
|
||||
Cfg: cfg,
|
||||
Tags: []string{"cron"},
|
||||
Tags: []string{},
|
||||
AuthenticatedUser: acl.UserFromSystem(cfg, "cron"),
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ func scheduleExec(action *config.Action, cfg *config.Config, ex *executor.Execut
|
||||
req := &executor.ExecutionRequest{
|
||||
ActionTitle: action.Title,
|
||||
Cfg: cfg,
|
||||
Tags: []string{"fileindir"},
|
||||
Tags: []string{},
|
||||
Arguments: args,
|
||||
AuthenticatedUser: acl.UserFromSystem(cfg, "fileindir"),
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func Execute(cfg *config.Config, ex *executor.Executor) {
|
||||
user := acl.UserFromSystem(cfg, "startup-user")
|
||||
user := acl.UserFromSystem(cfg, "startup")
|
||||
|
||||
for _, action := range cfg.Actions {
|
||||
if action.ExecOnStartup {
|
||||
@@ -20,7 +20,7 @@ func Execute(cfg *config.Config, ex *executor.Executor) {
|
||||
ActionTitle: action.Title,
|
||||
Arguments: nil,
|
||||
Cfg: cfg,
|
||||
Tags: []string{"startup"},
|
||||
Tags: []string{},
|
||||
AuthenticatedUser: user,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
pb "github.com/OliveTin/OliveTin/gen/grpc"
|
||||
"github.com/OliveTin/OliveTin/internal/executor"
|
||||
ws "github.com/gorilla/websocket"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var upgrader = ws.Upgrader{
|
||||
@@ -95,9 +96,12 @@ func (WebsocketExecutionListener) OnExecutionFinished(logEntry *executor.Interna
|
||||
ExecutionTrackingId: logEntry.ExecutionTrackingID,
|
||||
ExecutionStarted: logEntry.ExecutionStarted,
|
||||
ExecutionFinished: logEntry.ExecutionFinished,
|
||||
User: logEntry.Username,
|
||||
},
|
||||
}
|
||||
|
||||
log.Infof("Execution finished: %v+v", evt.LogEntry)
|
||||
|
||||
broadcast(evt)
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
<tr title = "untitled">
|
||||
<th>Timestamp</th>
|
||||
<th>Action</th>
|
||||
<th>Tags</th>
|
||||
<th>Metadata</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@@ -2,6 +2,49 @@ import './ActionButton.js' // To define action-button
|
||||
import { ExecutionDialog } from './ExecutionDialog.js'
|
||||
import { ActionStatusDisplay } from './ActionStatusDisplay.js'
|
||||
|
||||
function createElement (tag, attributes) {
|
||||
const el = document.createElement(tag)
|
||||
|
||||
if (attributes !== null) {
|
||||
if (attributes.classNames !== undefined) {
|
||||
el.classList.add(...attributes.classNames)
|
||||
}
|
||||
|
||||
if (attributes.innerText !== undefined) {
|
||||
el.innerText = attributes.innerText
|
||||
}
|
||||
}
|
||||
|
||||
return el
|
||||
}
|
||||
|
||||
function createTag (val) {
|
||||
const domTag = createElement('span', {
|
||||
innerText: val,
|
||||
classNames: ['tag']
|
||||
})
|
||||
|
||||
return domTag
|
||||
}
|
||||
|
||||
function createAnnotation (key, val) {
|
||||
const domAnnotation = createElement('span', {
|
||||
classNames: ['annotation']
|
||||
})
|
||||
|
||||
domAnnotation.appendChild(createElement('span', {
|
||||
innerText: key,
|
||||
classNames: ['annotationKey']
|
||||
}))
|
||||
|
||||
domAnnotation.appendChild(createElement('span', {
|
||||
innerText: val,
|
||||
classNames: ['annotationValue']
|
||||
}))
|
||||
|
||||
return domAnnotation
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a weird function that just sets some globals.
|
||||
*/
|
||||
@@ -577,13 +620,12 @@ export function marshalLogsJsonToHtml (json) {
|
||||
}
|
||||
|
||||
for (const tag of logEntry.tags) {
|
||||
const domTag = document.createElement('span')
|
||||
domTag.classList.add('tag')
|
||||
domTag.innerText = tag
|
||||
|
||||
row.querySelector('.tags').append(domTag)
|
||||
row.querySelector('.tags').append(createTag(tag))
|
||||
}
|
||||
|
||||
console.log(logEntry)
|
||||
row.querySelector('.tags').append(createAnnotation('user', logEntry.user))
|
||||
|
||||
document.querySelector('#logTableBody').prepend(row)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,12 +457,34 @@ input.invalid {
|
||||
}
|
||||
|
||||
span.tag {
|
||||
background-color: lightgray;
|
||||
border-radius: 0.4em;
|
||||
padding: 0.4em;
|
||||
margin-top: .2em;
|
||||
margin-right: .2em;
|
||||
display: inline-block;
|
||||
background-color: lightgray;
|
||||
padding: .4em;
|
||||
color: black;
|
||||
}
|
||||
|
||||
span.annotation {
|
||||
display: inline-block;
|
||||
margin-top: .2em;
|
||||
margin-right: .2em;
|
||||
}
|
||||
|
||||
span.annotationKey {
|
||||
padding: 0.4em;
|
||||
border-radius: 0.4em 0 0 .4em;
|
||||
display: inline-block;
|
||||
background-color: lightgray;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
span.annotationValue {
|
||||
padding: 0.4em;
|
||||
border-radius: 0 .4em .4em 0;
|
||||
display: inline-block;
|
||||
background-color: lightgray;
|
||||
color: black;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user