Completed SSH file transfer.
Ylian Saint-Hilaire committed
May 24, 2021 at 18:13 UTC
6f67c94d01e22ef40407947eb5badb2f52ae7120
3 files changed
+85
-8
apprelays.js
+75
-1
@@ -823,7 +823,6 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
823
obj.uploadHandle = handle;
824
try { obj.ws.send(Buffer.from(JSON.stringify({ action: 'uploadstart', reqid: obj.uploadReqid }))) } catch (ex) { }
825
}
826
-
826
});
827
break;
828
}
@@ -854,6 +853,52 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
853
}
854
break;
855
}
856
+ case 'download': {
857
+ if (obj.sftp == null) return;
858
+ switch (msg.sub) {
859
+ case 'start': {
860
+ var requestedPath = msg.path;
861
+ if (requestedPath.startsWith('/') == false) { requestedPath = '/' + requestedPath; }
862
+ obj.downloadFullpath = requestedPath;
863
+ obj.downloadId = msg.id;
864
+ obj.downloadPosition = 0;
865
+ obj.downloadBuffer = Buffer.alloc(16384);
866
+ obj.sftp.open(obj.downloadFullpath, 'r', function (err, handle) {
867
+ if (err != null) {
868
+ try { obj.ws.send(Buffer.from(JSON.stringify({ action: 'download', sub: 'cancel', id: obj.downloadId }))) } catch (ex) { }
869
+ } else {
870
+ obj.downloadHandle = handle;
871
+ // MeshServerLogEx((cmd.ask == 'coredump') ? 104 : 49, [cmd.path], 'Download: \"' + cmd.path + '\"', this.httprequest);
872
+ try { obj.ws.send(JSON.stringify({ action: 'download', sub: 'start', id: obj.downloadId })) } catch (ex) { }
873
+ }
874
+ });
875
+ break;
876
+ }
877
+ case 'startack': {
878
+ if ((obj.downloadHandle == null) || (obj.downloadId != msg.id)) break;
879
+ obj.downloadPendingBlockCount = (typeof msg.ack == 'number') ? msg.ack : 8;
880
+ uploadNextBlock();
881
+ break;
882
+ }
883
+ case 'ack': {
884
+ if ((obj.downloadHandle == null) || (obj.downloadId != msg.id)) break;
885
+ if (obj.downloadPendingBlockCount == 0) { obj.downloadPendingBlockCount = 1; uploadNextBlock(); }
886
+ break;
887
+ }
888
+ case 'stop': {
889
+ if ((obj.downloadHandle == null) || (obj.downloadId != msg.id)) break;
890
+ if (obj.downloadHandle != null) { obj.sftp.close(obj.downloadHandle, function () { }); }
891
+ delete obj.downloadId;
892
+ delete obj.downloadBuffer;
893
+ delete obj.downloadHandle;
894
+ delete obj.downloadFullpath;
895
+ delete obj.downloadPosition;
896
+ delete obj.downloadPendingBlockCount;
897
+ break;
898
+ }
899
+ }
900
+ break;
901
+ }
902
case 'sshauth': {
903
if (obj.sshClient != null) return;
904
@@ -876,6 +921,35 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
921
} catch (ex) { console.log(ex); obj.close(); }
922
});
923
924
+ function uploadNextBlock() {
925
+ if (obj.downloadBuffer == null) return;
926
+ obj.sftp.read(obj.downloadHandle, obj.downloadBuffer, 4, obj.downloadBuffer.length - 4, obj.downloadPosition, function (err, len, buf) {
927
+ obj.downloadPendingBlockCount--;
928
+ if (obj.downloadBuffer == null) return;
929
+ if (err != null) {
930
+ try { obj.ws.send(Buffer.from(JSON.stringify({ action: 'download', sub: 'cancel', id: obj.downloadId }))) } catch (ex) { }
931
+ } else {
932
+ obj.downloadPosition += len;
933
+ if (len < (obj.downloadBuffer.length - 4)) {
934
+ obj.downloadBuffer.writeInt32BE(0x01000001, 0)
935
+ if (len > 0) { try { obj.ws.send(obj.downloadBuffer.slice(0, len + 4)); } catch (ex) { console.log(ex); } }
936
+ } else {
937
+ obj.downloadBuffer.writeInt32BE(0x01000000, 0);
938
+ try { obj.ws.send(obj.downloadBuffer.slice(0, len + 4)); } catch (ex) { console.log(ex); }
939
+ if (obj.downloadPendingBlockCount > 0) { uploadNextBlock(); }
940
+ return;
941
+ }
942
+ }
943
+ if (obj.downloadHandle != null) { obj.sftp.close(obj.downloadHandle, function () { }); }
944
+ delete obj.downloadId;
945
+ delete obj.downloadBuffer;
946
+ delete obj.downloadHandle;
947
+ delete obj.downloadFullpath;
948
+ delete obj.downloadPosition;
949
+ delete obj.downloadPendingBlockCount;
950
+ });
951
+ }
952
+
953
// If error, do nothing
954
ws.on('error', function (err) { parent.parent.debug('relay', 'SSH: Browser websocket error: ' + err); obj.close(); });
955
public/scripts/agent-redir-ws-0.1.1.js
+1
-1
@@ -214,7 +214,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort, au
214
} else { // Process large data block
215
var bb = new Blob([new Uint8Array(e.data)]), f = new FileReader();
216
f.onload = function (e) { obj.m.ProcessData(e.target.result); };
217
- f.readAsText(bb);
217
+ f.readAsBinaryString(bb);
218
}
219
}
220
}
views/default.handlebars
+9
-6
@@ -9138,12 +9138,15 @@
9138
} else {
9139
var link = shortname;
9140
if (f.s > 0) {
9141
- // Local link
9142
- //link = '<a href=# style=cursor:pointer onclick="return p13downloadfile(\'' + encodeURIComponentEx(newlinkpath + '/' + name) + '\',\'' + encodeURIComponentEx(name) + '\',' + f.s + ')">' + shortname + '</a>';
9143
- // Server link
9144
- //link = '<a href="devicefile.ashx?c=' + authCookie + '&m=' + currentNode.meshid.split('/')[2] + '&n=' + currentNode._id.split('/')[2] + '&f=' + encodeURIComponentEx(newlinkpath + '/' + name) + '" download="' + name + '" style=cursor:pointer>' + shortname + '</a>';
9145
- // Server link
9146
- link = '<a onclick=downloadFile("devicefile.ashx?c=' + authCookie + '&m=' + currentNode.meshid.split('/')[2] + '&n=' + currentNode._id.split('/')[2] + '&f=' + encodeURIComponentEx(newlinkpath + '/' + name) + '","' + encodeURIComponentEx(name) + '") style=cursor:pointer>' + shortname + '</a>';
9141
+ if (filesNode.mtype == 3) {
9142
+ // Local link
9143
+ link = '<a href=# style=cursor:pointer onclick="return p13downloadfile(\'' + encodeURIComponentEx(newlinkpath + '/' + name) + '\',\'' + encodeURIComponentEx(name) + '\',' + f.s + ')">' + shortname + '</a>';
9144
+ } else {
9145
+ // Server link
9146
+ //link = '<a href="devicefile.ashx?c=' + authCookie + '&m=' + currentNode.meshid.split('/')[2] + '&n=' + currentNode._id.split('/')[2] + '&f=' + encodeURIComponentEx(newlinkpath + '/' + name) + '" download="' + name + '" style=cursor:pointer>' + shortname + '</a>';
9147
+ // Server link
9148
+ link = '<a onclick=downloadFile("devicefile.ashx?c=' + authCookie + '&m=' + currentNode.meshid.split('/')[2] + '&n=' + currentNode._id.split('/')[2] + '&f=' + encodeURIComponentEx(newlinkpath + '/' + name) + '","' + encodeURIComponentEx(name) + '") style=cursor:pointer>' + shortname + '</a>';
9149
+ }
9150
}
9151
h = '<div id=fileEntry cmenu=filesContextMenu fileIndex=' + i + ' class=filelist file=3><input file=3 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'> <span class=fsize>' + fdatestr + '</span><span style=float:right>' + EscapeHtml(fsize) + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
9152
}