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.

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