Skip to content

Commit

Permalink
adding initial base logic
Browse files Browse the repository at this point in the history
  • Loading branch information
thelamer committed Feb 9, 2023
0 parents commit 8a779ff
Show file tree
Hide file tree
Showing 14 changed files with 708 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Kclient

ALPHA VERSION NO TOUCH
136 changes: 136 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// LinuxServer KasmVNC Client

//// Env variables ////
var CUSTOM_USER = process.env.CUSTOM_USER || 'abc';
var PASSWORD = process.env.PASSWORD || 'abc';
var SUBFOLDER = process.env.SUBFOLDER || '/';
var TITLE = process.env.TITLE || 'KasmVNC Client';
var FM_HOME = process.env.FM_HOME || '/config';

//// Application Variables ////
var socketIO = require('socket.io');
var express = require('express');
var ejs = require('ejs');
var app = require('express')();
var http = require('http').Server(app);
var bodyParser = require('body-parser');
var baseRouter = express.Router();
var fsw = require('fs').promises;
var fs = require('fs');


//// Server Paths Main ////
app.engine('html', require('ejs').renderFile);
app.engine('json', require('ejs').renderFile);
baseRouter.use('/public', express.static(__dirname + '/public'));
baseRouter.use('/vnc', express.static("/usr/share/kasmvnc/www/"));
baseRouter.get('/', function (req, res) {
res.render(__dirname + '/public/index.html', {title: TITLE});
});
baseRouter.get('/favicon.ico', function (req, res) {
res.sendFile(__dirname + '/public/favicon.ico');
});
baseRouter.get('/manifest.json', function (req, res) {
res.render(__dirname + '/public/manifest.json', {title: TITLE});
});

//// Web File Browser ////
// Send landing page
baseRouter.get('/files', function (req, res) {
res.sendFile( __dirname + '/public/filebrowser.html');
});
// Websocket comms //
io = socketIO(http, {path: SUBFOLDER + 'files/socket.io',maxHttpBufferSize: 200000000});
io.on('connection', async function (socket) {
let id = socket.id;

//// Functions ////

// Open default location
async function checkAuth(password) {
getFiles(FM_HOME);
}

// Emit to user
function send(command, data) {
io.sockets.to(id).emit(command, data);
}

// Get file list for directory
async function getFiles(directory) {
let items = await fsw.readdir(directory);
if (items.length > 0) {
let dirs = [];
let files = [];
for await (let item of items) {
let fullPath = directory + '/' + item;
if (fs.lstatSync(fullPath).isDirectory()) {
dirs.push(item);
} else {
files.push(item);
}
}
send('renderfiles', [dirs, files, directory]);
} else {
send('renderfiles', [[], [], directory]);
}
}

// Send file to client
async function downloadFile(file) {
let fileName = file.split('/').slice(-1)[0];
let data = await fsw.readFile(file);
send('sendfile', [data, fileName]);
}

// Write client sent file
async function uploadFile(res) {
let directory = res[0];
let filePath = res[1];
let data = res[2];
let render = res[3];
let dirArr = filePath.split('/');
let folder = filePath.replace(dirArr[dirArr.length - 1], '')
await fsw.mkdir(folder, { recursive: true });
await fsw.writeFile(filePath, Buffer.from(data));
if (render) {
getFiles(directory);
}
}

// Delete files
async function deleteFiles(res) {
let item = res[0];
let directory = res[1];
item = item.replace("|","'");
if (fs.lstatSync(item).isDirectory()) {
await fsw.rm(item, {recursive: true});
} else {
await fsw.unlink(item);
}
getFiles(directory);
}

// Create a folder
async function createFolder(res) {
let dir = res[0];
let directory = res[1];
if (!fs.existsSync(dir)){
await fsw.mkdir(dir);
}
getFiles(directory);
}

// Incoming socket requests
socket.on('open', checkAuth);
socket.on('getfiles', getFiles);
socket.on('downloadfile', downloadFile);
socket.on('uploadfile', uploadFile);
socket.on('deletefiles', deleteFiles);
socket.on('createfolder', createFolder);
});


// Spin up application on 6900
app.use(SUBFOLDER, baseRouter);
http.listen(6900);
31 changes: 31 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "kclient",
"version": "0.1.0",
"description": "Kclient is a wrapper for KasmVNC to add functionality to a containerized environment",
"main": "index.js",
"dependencies": {
"ejs": "^3.1.8",
"express": "^4.18.2",
"socket.io": "^4.6.0"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/linuxserver/kclient.git"
},
"keywords": [
"VNC",
"Webtop",
"VDI",
"Docker"
],
"author": "thelamer",
"license": "GPL-3.0-or-later",
"bugs": {
"url": "https://github.com/linuxserver/kclient/issues"
},
"homepage": "https://github.com/linuxserver/kclient#readme"
}
72 changes: 72 additions & 0 deletions public/css/filebrowser.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
html * {
font-family: Poppins,Helvetica !important;
color: white !important;
}

.hidden {
display: none;
}

.right {
float: right;
margin-right: 5px;
}

.directory, .file {
cursor: pointer;
}

button {
background-color: rgb(9 2 2 / 0.6);
border-radius: 5px;
border-style: inset;
border-color: rgb(255 255 255 / 0.6);
cursor: pointer;
margin: 5px;
}

.deleteButton {
margin: 0px !important;
float: right;
}

.fileTable {
border-collapse: collapse;
width: 100%;
margin-top: 10px;
}

td, th {
border: 2px solid #ddd;
padding: 8px;
}

tr:hover, button:hover {
background: rgba(255, 255, 255, 0.3)
}

#dropzone {
position: fixed; top: 0; left: 0;
z-index: 9999999999;
width: 100%; height: 100%;
background-color: rgba(0,0,0,0.5);
transition: visibility 175ms, opacity 175ms;
}

#loading {
display: inline-block;
width: 50px;
height: 50px;
border: 3px solid rgba(0,0,0,.3);
border-radius: 50%;
border-top-color: black;
animation: spin 1s ease-in-out infinite;
-webkit-animation: spin 1s ease-in-out infinite;
}

@keyframes spin {
to { -webkit-transform: rotate(360deg); }
}
@-webkit-keyframes spin {
to { -webkit-transform: rotate(360deg); }
}
2 changes: 2 additions & 0 deletions public/css/files.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
74 changes: 74 additions & 0 deletions public/css/kclient.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
.vnc {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
border: none;
margin: 0;
padding: 0;
overflow: hidden;
}

#files {
display: none;
position: absolute;
left: 20vw;
top: 50%;
transform: translateY(-50%);
width: 60vw;
height: 60vh;
z-index: 2;
background-color: rgb(9 2 2 / 0.6);
border-radius: 10px;
border-style: inset;
border-color: rgb(255 255 255 / 0.6);
}

#files_frame {
width: 100%;
height: 100%;
}

.close {
position: absolute;
background: DimGray;
top: -10px;
right: -10px;
cursor: pointer;
border-radius:50%;
border-style: inset;
border-color: rgb(255 255 255 / 0.6);
width: 20px;
height: 20px;
}

#lsbar {
position: absolute;
top: 0;
left: 0;
right: 0;
margin-left: auto;
margin-right: auto;
width: max-content;
display: none;
background-color: rgb(9 2 2 / 0.6);
border-radius: 0 0 10px 10px;
border-style: inset;
border-color: rgb(255 255 255 / 0.6);
}

.icons {
margin: 5px;
padding: 4px;
height: 4vh;
cursor: pointer;
border-radius: 3px;
filter: invert(100%) sepia(0%) saturate(0%) hue-rotate(82deg) brightness(105%) contrast(105%);
}

.icons:hover {
background: rgba(0, 0, 0, 0.3);
}
Binary file added public/favicon.ico
Binary file not shown.
20 changes: 20 additions & 0 deletions public/filebrowser.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="public/css/filebrowser.css">
<script type="text/javascript" src="public/js/jquery.min.js"></script>
<script src="files/socket.io/socket.io.js"></script>
<script type="text/javascript" src="public/js/filebrowser.js"></script>
</head>
<body>
<span id="buttons">
<input id="folderName" type="text" placeholder="Enter Directory Name"></input>
<button onclick="createFolder()">Create Folder</button>
<button onclick="$('#uploadInput').trigger( 'click' )">Upload Files</button>
<input class="hidden" id="uploadInput" type='file' onchange="upload(this);" multiple>
</span>
<div id="filebrowser"></div>
<div ondrop="dropFiles(event)" ondragover="allowDrop(event)" style="visibility:hidden;opacity:0" id="dropzone">
</div>
</body>
</html>
Binary file added public/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title><%- title -%></title>
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<link rel="apple-touch-icon" href="icon.png">
<link rel="manifest" href="manifest.json">
<link href="public/css/kclient.css" rel="stylesheet">
</head>
<body>
<!--KasmVNC Iframe-->
<iframe class="vnc" src="vnc/index.html?resize=remote&clipboard_up=true&clipboard_down=true&clipboard_seamless=true&show_control_bar=true"></iframe>
<!--LSIO Function Bar-->
<div id="lsbar">
<img class="icons" title="File Manager" src="public/css/files.svg" onclick="toggle('#files')"/>
</div>
<!--File Browser-->
<div id="files">
<iframe id="files_frame" name="files_frame" src="files" frameborder="0"></iframe>
<div class="close" onclick="closeToggle('#files')"></div>
</div>
<!--Main logic-->
<script src="public/js/jquery.min.js"></script>
<script src="public/js/kclient.js"></script>
</body>
</html>
Loading

0 comments on commit 8a779ff

Please sign in to comment.