diff --git a/client/src/components/files.vue b/client/src/components/files.vue index d663b31a..6dc82cf1 100644 --- a/client/src/components/files.vue +++ b/client/src/components/files.vue @@ -134,7 +134,7 @@ } refresh() { - console.log('refresh') + this.$accessor.files.refresh() } download(item: any) { diff --git a/client/src/neko/base.ts b/client/src/neko/base.ts index 31ec8add..dc767b5b 100644 --- a/client/src/neko/base.ts +++ b/client/src/neko/base.ts @@ -187,6 +187,14 @@ export abstract class BaseClient extends EventEmitter { this._ws!.send(JSON.stringify({ event, ...payload })) } + public refreshFiles() { + if (!this.connected) { + this.emit('warn', 'attempting to refresh files while disconnected') + } + this.emit('debug', `sending event '${EVENT.FILETRANSFER.REFRESH}'`) + this._ws!.send(JSON.stringify({ event: EVENT.FILETRANSFER.REFRESH })) + } + public async createPeer(lite: boolean, servers: RTCIceServer[]) { this.emit('debug', `creating peer`) if (!this.socketOpen) { diff --git a/client/src/neko/events.ts b/client/src/neko/events.ts index b6c6cbde..d12046a0 100644 --- a/client/src/neko/events.ts +++ b/client/src/neko/events.ts @@ -43,7 +43,8 @@ export const EVENT = { DISABLE: 'filetransfer/disable', UNPRIVENABLE: 'filetransfer/unprivenable', UNPRIVDISABLE: 'filetransfer/unprivdisable', - LIST: 'filetransfer/list' + LIST: 'filetransfer/list', + REFRESH: 'filetransfer/refresh' }, SCREEN: { CONFIGURATIONS: 'screen/configurations', @@ -106,6 +107,7 @@ export type FileTransferEvents = | typeof EVENT.FILETRANSFER.UNPRIVENABLE | typeof EVENT.FILETRANSFER.UNPRIVDISABLE | typeof EVENT.FILETRANSFER.LIST + | typeof EVENT.FILETRANSFER.REFRESH export type ScreenEvents = typeof EVENT.SCREEN.CONFIGURATIONS | typeof EVENT.SCREEN.RESOLUTION | typeof EVENT.SCREEN.SET diff --git a/client/src/store/files.ts b/client/src/store/files.ts index ce57a6ee..9c8ce065 100644 --- a/client/src/store/files.ts +++ b/client/src/store/files.ts @@ -30,6 +30,13 @@ export const actions = actionTree( setFileList(store, files: FileListItem[]) { accessor.files._setFileList(files) + }, + + refresh(store) { + if (!accessor.connected) { + return + } + $client.refreshFiles() } } ) diff --git a/server/internal/types/event/events.go b/server/internal/types/event/events.go index e6bf8b5d..8c5e12ff 100644 --- a/server/internal/types/event/events.go +++ b/server/internal/types/event/events.go @@ -40,6 +40,7 @@ const ( FILETRANSFER_UNPRIVENABLE = "filetransfer/unprivenable" FILETRANSFER_UNPRIVDISABLE = "filetransfer/unprivdisable" FILETRANSFER_LIST = "filetransfer/list" + FILETRANSFER_REFRESH = "filetransfer/refresh" ) const ( diff --git a/server/internal/websocket/handler/files.go b/server/internal/websocket/handler/files.go new file mode 100644 index 00000000..cda7ec83 --- /dev/null +++ b/server/internal/websocket/handler/files.go @@ -0,0 +1,26 @@ +package handler + +import ( + "errors" + "m1k1o/neko/internal/types" + "m1k1o/neko/internal/types/event" + "m1k1o/neko/internal/types/message" + "m1k1o/neko/internal/utils" +) + +func (h *MessageHandler) refresh(session types.Session) error { + if !(h.state.FileTransferEnabled() && session.Admin() || h.state.UnprivFileTransferEnabled()) { + return errors.New(session.Member().Name + " tried to refresh file list when they can't") + } + + files, err := utils.ListFiles(h.state.FileTransferPath()) + if err != nil { + return err + } + return session.Send( + message.FileList{ + Event: event.FILETRANSFER_LIST, + Cwd: h.state.FileTransferPath(), + Files: *files, + }) +} diff --git a/server/internal/websocket/handler/handler.go b/server/internal/websocket/handler/handler.go index b2b529cb..004a4b46 100644 --- a/server/internal/websocket/handler/handler.go +++ b/server/internal/websocket/handler/handler.go @@ -126,6 +126,10 @@ func (h *MessageHandler) Message(id string, raw []byte) error { return h.chatEmote(id, session, payload) }), "%s failed", header.Event) + // File Transfer Events + case event.FILETRANSFER_REFRESH: + return errors.Wrapf(h.refresh(session), "%s failed", header.Event) + // Screen Events case event.SCREEN_RESOLUTION: return errors.Wrapf(h.screenResolution(id, session), "%s failed", header.Event) diff --git a/server/internal/websocket/state/state.go b/server/internal/websocket/state/state.go index 3b38797f..1c2719cc 100644 --- a/server/internal/websocket/state/state.go +++ b/server/internal/websocket/state/state.go @@ -3,12 +3,20 @@ package state type State struct { banned map[string]string // IP -> session ID (that banned it) locked map[string]string // resource name -> session ID (that locked it) + + fileTransferEnabled bool // admins can transfer files + fileTransferUnprivEnabled bool // all users can transfer files + fileTransferPath string // path where files are located } -func New() *State { +func New(fileTransferEnabled bool, fileTransferUnprivEnabled bool, fileTransferPath string) *State { return &State{ banned: make(map[string]string), locked: make(map[string]string), + + fileTransferEnabled: fileTransferEnabled, + fileTransferUnprivEnabled: fileTransferUnprivEnabled, + fileTransferPath: fileTransferPath, } } @@ -59,3 +67,17 @@ func (s *State) GetLocked(resource string) (string, bool) { func (s *State) AllLocked() map[string]string { return s.locked } + +// File Transfer + +func (s *State) FileTransferEnabled() bool { + return s.fileTransferEnabled +} + +func (s *State) UnprivFileTransferEnabled() bool { + return s.fileTransferUnprivEnabled +} + +func (s *State) FileTransferPath() string { + return s.fileTransferPath +} diff --git a/server/internal/websocket/websocket.go b/server/internal/websocket/websocket.go index ade10beb..23c42bd6 100644 --- a/server/internal/websocket/websocket.go +++ b/server/internal/websocket/websocket.go @@ -26,7 +26,7 @@ const CONTROL_PROTECTION_SESSION = "by_control_protection" func New(sessions types.SessionManager, desktop types.DesktopManager, capture types.CaptureManager, webrtc types.WebRTCManager, conf *config.WebSocket) *WebSocketHandler { logger := log.With().Str("module", "websocket").Logger() - state := state.New() + state := state.New(conf.FileTransfer, conf.UnprivFileTransfer, conf.FileTransferPath) // if control protection is enabled if conf.ControlProtection {