diff --git a/apprelays.js b/apprelays.js index 6eff5b07..d02ba1ce 100644 --- a/apprelays.js +++ b/apprelays.js @@ -823,7 +823,6 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user obj.uploadHandle = handle; try { obj.ws.send(Buffer.from(JSON.stringify({ action: 'uploadstart', reqid: obj.uploadReqid }))) } catch (ex) { } } - }); break; } @@ -854,6 +853,52 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user } break; } + case 'download': { + if (obj.sftp == null) return; + switch (msg.sub) { + case 'start': { + var requestedPath = msg.path; + if (requestedPath.startsWith('/') == false) { requestedPath = '/' + requestedPath; } + obj.downloadFullpath = requestedPath; + obj.downloadId = msg.id; + obj.downloadPosition = 0; + obj.downloadBuffer = Buffer.alloc(16384); + obj.sftp.open(obj.downloadFullpath, 'r', function (err, handle) { + if (err != null) { + try { obj.ws.send(Buffer.from(JSON.stringify({ action: 'download', sub: 'cancel', id: obj.downloadId }))) } catch (ex) { } + } else { + obj.downloadHandle = handle; + // MeshServerLogEx((cmd.ask == 'coredump') ? 104 : 49, [cmd.path], 'Download: \"' + cmd.path + '\"', this.httprequest); + try { obj.ws.send(JSON.stringify({ action: 'download', sub: 'start', id: obj.downloadId })) } catch (ex) { } + } + }); + break; + } + case 'startack': { + if ((obj.downloadHandle == null) || (obj.downloadId != msg.id)) break; + obj.downloadPendingBlockCount = (typeof msg.ack == 'number') ? msg.ack : 8; + uploadNextBlock(); + break; + } + case 'ack': { + if ((obj.downloadHandle == null) || (obj.downloadId != msg.id)) break; + if (obj.downloadPendingBlockCount == 0) { obj.downloadPendingBlockCount = 1; uploadNextBlock(); } + break; + } + case 'stop': { + if ((obj.downloadHandle == null) || (obj.downloadId != msg.id)) break; + if (obj.downloadHandle != null) { obj.sftp.close(obj.downloadHandle, function () { }); } + delete obj.downloadId; + delete obj.downloadBuffer; + delete obj.downloadHandle; + delete obj.downloadFullpath; + delete obj.downloadPosition; + delete obj.downloadPendingBlockCount; + break; + } + } + break; + } case 'sshauth': { if (obj.sshClient != null) return; @@ -876,6 +921,35 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user } catch (ex) { console.log(ex); obj.close(); } }); + function uploadNextBlock() { + if (obj.downloadBuffer == null) return; + obj.sftp.read(obj.downloadHandle, obj.downloadBuffer, 4, obj.downloadBuffer.length - 4, obj.downloadPosition, function (err, len, buf) { + obj.downloadPendingBlockCount--; + if (obj.downloadBuffer == null) return; + if (err != null) { + try { obj.ws.send(Buffer.from(JSON.stringify({ action: 'download', sub: 'cancel', id: obj.downloadId }))) } catch (ex) { } + } else { + obj.downloadPosition += len; + if (len < (obj.downloadBuffer.length - 4)) { + obj.downloadBuffer.writeInt32BE(0x01000001, 0) + if (len > 0) { try { obj.ws.send(obj.downloadBuffer.slice(0, len + 4)); } catch (ex) { console.log(ex); } } + } else { + obj.downloadBuffer.writeInt32BE(0x01000000, 0); + try { obj.ws.send(obj.downloadBuffer.slice(0, len + 4)); } catch (ex) { console.log(ex); } + if (obj.downloadPendingBlockCount > 0) { uploadNextBlock(); } + return; + } + } + if (obj.downloadHandle != null) { obj.sftp.close(obj.downloadHandle, function () { }); } + delete obj.downloadId; + delete obj.downloadBuffer; + delete obj.downloadHandle; + delete obj.downloadFullpath; + delete obj.downloadPosition; + delete obj.downloadPendingBlockCount; + }); + } + // If error, do nothing ws.on('error', function (err) { parent.parent.debug('relay', 'SSH: Browser websocket error: ' + err); obj.close(); }); diff --git a/public/scripts/agent-redir-ws-0.1.1.js b/public/scripts/agent-redir-ws-0.1.1.js index 61278b53..f27919dc 100644 --- a/public/scripts/agent-redir-ws-0.1.1.js +++ b/public/scripts/agent-redir-ws-0.1.1.js @@ -214,7 +214,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort, au } else { // Process large data block var bb = new Blob([new Uint8Array(e.data)]), f = new FileReader(); f.onload = function (e) { obj.m.ProcessData(e.target.result); }; - f.readAsText(bb); + f.readAsBinaryString(bb); } } } diff --git a/views/default.handlebars b/views/default.handlebars index 7f41a3a4..781e65ff 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -9138,12 +9138,15 @@ } else { var link = shortname; if (f.s > 0) { - // Local link - //link = '' + shortname + ''; - // Server link - //link = '' + shortname + ''; - // Server link - link = '' + shortname + ''; + if (filesNode.mtype == 3) { + // Local link + link = '' + shortname + ''; + } else { + // Server link + //link = '' + shortname + ''; + // Server link + link = '' + shortname + ''; + } } h = '