Remote web console.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

server.js 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. let http = require("http");
  2. let fs = require("fs");
  3. let crypto = require("crypto");
  4. let urllib = require("url");
  5. let ws = require("ws");
  6. let mime = require('mime-types')
  7. let port = process.env.PORT || 8080;
  8. let host = process.env.HOSTNAME || "127.0.0.1";
  9. let sessions = {};
  10. class Session {
  11. constructor(id) {
  12. this.id = id;
  13. this.masterPoll = null;
  14. this.timeout = null;
  15. this.resetTimeout();
  16. this.master = null;
  17. this.target = null;
  18. }
  19. resetTimeout() {
  20. if (this.timeout)
  21. clearTimeout(this.timeout);
  22. this.timeout = setTimeout(() => {
  23. console.log(`${this.id}: No activity for 5m, deleting session.`);
  24. sessions[this.id] = null;
  25. }, 5 * 60 * 1000);
  26. }
  27. onMaster(conn) {
  28. this.master = conn;
  29. this.sendTargetMessage({ type: "master-connect" });
  30. if (this.target)
  31. this.sendMasterMessage({ type: "target-connect" });
  32. conn.on("message", msg => {
  33. console.log(`${this.id}: Message from master: ${msg}`);
  34. this.resetTimeout();
  35. this.onMasterMessage(JSON.parse(msg));
  36. });
  37. conn.on("close", () => {
  38. this.master = null;
  39. this.sendTargetMessage({ type: "master-disconnect" });
  40. });
  41. }
  42. onTarget(conn) {
  43. this.target = conn;
  44. this.sendMasterMessage({ type: "target-connect" });
  45. if (this.master)
  46. this.sendTargetMessage({ type: "master-connect" });
  47. conn.on("message", msg => {
  48. console.log(`${this.id}: Message from target: ${msg}`);
  49. this.resetTimeout();
  50. this.onTargetMessage(JSON.parse(msg));
  51. });
  52. conn.on("close", () => {
  53. this.target = null;
  54. this.sendMasterMessage({ type: "target-disconnect" });
  55. });
  56. }
  57. onMasterMessage(msg) {
  58. console.log(`${this.id}: Forwarding from master:`, msg);
  59. this.sendTargetMessage(msg);
  60. }
  61. onTargetMessage(msg) {
  62. console.log(`${this.id}: Forwarding from target:`, msg);
  63. this.sendMasterMessage(msg);
  64. }
  65. sendMasterMessage(msg) {
  66. if (this.master)
  67. this.master.send(JSON.stringify(msg));
  68. }
  69. sendTargetMessage(msg) {
  70. if (this.target)
  71. this.target.send(JSON.stringify(msg));
  72. }
  73. }
  74. function createSession() {
  75. let id = crypto.randomBytes(16).toString("hex");
  76. sessions[id] = new Session(id);
  77. return id;
  78. }
  79. function sendFile(path, res) {
  80. let url = urllib.parse(path);
  81. let rs = fs.createReadStream(`web${url.pathname}`);
  82. rs.once("error", err => {
  83. if (err.code == "EISDIR") {
  84. if (url.pathname[url.pathname.length - 1] == "/") {
  85. return sendFile(`${url.pathname}index.html`, res);
  86. } else {
  87. res.writeHead(302, { location: `${url.pathname}/` });
  88. res.end();
  89. return;
  90. }
  91. }
  92. res.writeHead(400);
  93. res.end(err.toString());
  94. });
  95. rs.on("open", () => {
  96. res.writeHead(200, {
  97. "Content-Type": mime.lookup(url.pathname),
  98. });
  99. });
  100. rs.pipe(res);
  101. }
  102. let server = http.createServer((req, res) => {
  103. if (req.method == "GET" || req.method == "HEAD") {
  104. sendFile(req.url, res);
  105. } else if (req.method == "POST" && req.url == "/create") {
  106. let id = createSession(res);
  107. res.writeHead(302, {
  108. location: `/console/?${id}`,
  109. });
  110. res.end("Redirecting...");
  111. }
  112. });
  113. server.listen(port, host);
  114. console.log(`Listening to ${host}:${port}`);
  115. let wss = new ws.Server({ server });
  116. wss.on("connection", conn => {
  117. conn.on("message", function onMessage(msg) {
  118. let obj;
  119. try {
  120. obj = JSON.parse(msg);
  121. } catch (err) {
  122. console.log("Received invalid message");
  123. conn.send(JSON.stringify({
  124. type: "identify-response",
  125. err: "Invalid JSON",
  126. }));
  127. return;
  128. }
  129. if (obj.type != "identify-target" && obj.type != "identify-master") {
  130. conn.send(JSON.stringify({
  131. type: "identify-response",
  132. err: "Not identified",
  133. }));
  134. return;
  135. }
  136. if (!obj.id) {
  137. conn.send(JSON.stringify({
  138. type: "identify-response",
  139. err: "Empty session ID",
  140. }));
  141. return;
  142. }
  143. let sess = sessions[obj.id];
  144. if (sess == null) {
  145. conn.send(JSON.stringify({
  146. type: "identify-response",
  147. err: "Invalid session ID",
  148. }));
  149. return;
  150. }
  151. conn.send(JSON.stringify({ type: "identify-response", err: null }));
  152. conn.off("message", onMessage);
  153. if (obj.type == "identify-master")
  154. sess.onMaster(conn);
  155. else
  156. sess.onTarget(conn);
  157. });
  158. });