access.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. const CryptoJS = require("crypto-js");
  2. const { deflate, unzip } = require("zlib");
  3. const md5 = require("./md5.min.js");
  4. const axios = require("axios");
  5. const HtmlParser = require("node-html-parser");
  6. const https = require("https");
  7. const qs = require("qs");
  8. const fs = require("fs");
  9. const path = require("path");
  10. const { NodeSSH } = require("node-ssh");
  11. const SftpClient = require("ssh2-sftp-client");
  12. const { exec } = require("child_process");
  13. const { spawn } = require("child_process");
  14. const ProgressBar = require("progress");
  15. const Multiprogress = require("multi-progress");
  16. const config = require("./config.json");
  17. const servers = require("./servers.json");
  18. function encryptPasswd(sessionId, password) {
  19. var key = CryptoJS.enc.Hex.parse(md5(sessionId));
  20. var pdb = password;
  21. if (pdb && pdb != "") {
  22. var iv = CryptoJS.lib.WordArray.random(128 / 8);
  23. var pda = aesEncrypt(pdb, key, iv);
  24. return pda;
  25. }
  26. }
  27. function aesEncrypt(word, key, iv) {
  28. var encPrefix = "__RIS_ENC{";
  29. var encSuffix = "}";
  30. srcs = CryptoJS.enc.Utf8.parse(word);
  31. var encrypted = CryptoJS.AES.encrypt(srcs, key, {
  32. iv: iv,
  33. mode: CryptoJS.mode.CBC,
  34. padding: CryptoJS.pad.Pkcs7,
  35. });
  36. var hash = CryptoJS.HmacSHA256(
  37. encrypted.ciphertext.toString().toUpperCase(),
  38. key
  39. );
  40. return (
  41. encPrefix +
  42. encrypted.ciphertext.toString().toUpperCase() +
  43. "@" +
  44. iv.toString() +
  45. "@" +
  46. hash.toString() +
  47. encSuffix
  48. );
  49. }
  50. let sessionId;
  51. const instance = axios.create({
  52. httpsAgent: new https.Agent({
  53. rejectUnauthorized: false,
  54. }),
  55. withCredentials: true,
  56. maxRedirects: 0,
  57. });
  58. instance.interceptors.request.use(
  59. function (config) {
  60. config.headers = config.headers || {};
  61. config.headers.accept = config.headers.accept || "text/html";
  62. if (sessionId) {
  63. config.headers["Cookie"] = "SESSION=" + sessionId;
  64. }
  65. return config;
  66. },
  67. function (error) {
  68. return Promise.reject(error);
  69. }
  70. );
  71. const getSessionId = () => {
  72. return Promise.resolve()
  73. .then(() => {
  74. return instance.get(config.loginUrl);
  75. })
  76. .then((res) => {
  77. sessionId = res.headers["set-cookie"][0].match(/SESSION=(.*?);/)[1];
  78. const root = HtmlParser.parse(res.data);
  79. const csrf = root
  80. .querySelector("#loginForm [name=_csrf]")
  81. .getAttribute("value");
  82. return instance.post(
  83. config.loginUrl,
  84. qs.stringify({
  85. language: "zh_CN",
  86. _csrf: csrf,
  87. username: config.username,
  88. password: encryptPasswd(sessionId, config.password),
  89. captcha: "",
  90. captchaPage: "",
  91. })
  92. );
  93. })
  94. .then((res) => {
  95. console.log(res.headers);
  96. console.log(res.data);
  97. sessionId = res.headers["set-cookie"][0].match(/SESSION=(.*?);/)[1];
  98. })
  99. .catch((e) => {
  100. sessionId =
  101. e.response.headers["set-cookie"][0].match(/SESSION=(.*?);/)[1];
  102. fs.writeFileSync("sessionId", sessionId);
  103. console.log("login sessionId=" + sessionId);
  104. return Promise.resolve(sessionId);
  105. });
  106. };
  107. if (fs.existsSync("sessionId")) {
  108. sessionId = fs.readFileSync("sessionId").toString().trim();
  109. console.log("using exist sessionId: " + sessionId);
  110. }
  111. const checkSessionId = () => {
  112. if (!sessionId) {
  113. return Promise.reject();
  114. } else {
  115. return new Promise((resolve, reject) => {
  116. instance
  117. .get(config.checkAccessUrl, {
  118. headers: {
  119. accept: "application/json",
  120. },
  121. })
  122. .then((res) => {
  123. resolve();
  124. })
  125. .catch((e) => {
  126. console.error("sessionId expired");
  127. reject();
  128. });
  129. });
  130. }
  131. };
  132. const getAccess = (server) => {
  133. return instance
  134. .post(
  135. config.accessUrl,
  136. {
  137. misc: {
  138. resolution: "1159x897:maximize",
  139. isDualAuth: false,
  140. anyAccount: "admin",
  141. anyPassword: server.password,
  142. recheckCode: "",
  143. },
  144. sessRemark: "",
  145. account: "any",
  146. proto: "sftp",
  147. dev: server.id,
  148. },
  149. {
  150. headers: {
  151. accept: "application/json",
  152. },
  153. }
  154. )
  155. .then((res) => {
  156. return Promise.resolve(res.data);
  157. })
  158. .catch((e) => {
  159. console.log(e);
  160. if (e.response.status === 401) {
  161. sessionId = null;
  162. }
  163. return Promise.reject(e);
  164. });
  165. };
  166. const build = () => {
  167. return new Promise((resolve, reject) => {
  168. const ls = spawn("sh", ["build.sh"], { cwd: config.projectDir });
  169. ls.stdout.on("data", (data) => {
  170. process.stdout.write(data);
  171. });
  172. ls.stderr.on("data", (data) => {
  173. process.stderr.write(data);
  174. });
  175. ls.on("error", (error) => {
  176. console.log(`error: ${error.message}`);
  177. });
  178. ls.on("close", (code) => {
  179. console.log(`build finished with code ${code}`);
  180. resolve();
  181. });
  182. });
  183. };
  184. let multi = new Multiprogress(process.stdout);
  185. // build()
  186. Promise.resolve()
  187. .then(() => {
  188. return new Promise((resolve, reject) => {
  189. checkSessionId()
  190. .then(() => {
  191. resolve();
  192. })
  193. .catch(() => {
  194. sessionId = null;
  195. getSessionId().then(() => {
  196. resolve();
  197. });
  198. });
  199. });
  200. })
  201. .then(() => {
  202. upload(servers[0]);
  203. // upload(servers[5].id);
  204. // upload(servers[6].id);
  205. });
  206. const upload = async (server) => {
  207. let { url } = await getAccess(server);
  208. const buffer = Buffer.from(url.match(/accessclient:\/\/(.*)/)[1], "base64");
  209. let accessJson = await new Promise((resolve, reject) => {
  210. unzip(buffer, (err, buffer) => {
  211. if (err) {
  212. console.error("An error occurred:", err);
  213. process.exitCode = 1;
  214. }
  215. let accessJson = JSON.parse(buffer.toString());
  216. console.log(accessJson);
  217. resolve(accessJson);
  218. });
  219. });
  220. // let file = "/Users/drew/Desktop/building3.tar.gz";
  221. let file = path.resolve(config.projectDir, "build.tar.gz");
  222. let stat = fs.statSync(file);
  223. let bar = multi.newBar(" uploading [:bar] :rate/bps :percent :etas", {
  224. complete: "=",
  225. incomplete: " ",
  226. width: 20,
  227. total: stat.size,
  228. });
  229. return
  230. const ssh = new NodeSSH();
  231. await ssh.connect({
  232. host: accessJson.Host,
  233. username: accessJson.User,
  234. password: accessJson.PWD,
  235. });
  236. // await ssh.putFile(file, "/home/admin/build.tar.gz", null, {
  237. // concurrency: 1,
  238. // chunkSize: 3276800,
  239. // step: (total_transferred, chunk, total) => {
  240. // bar.tick(chunk);
  241. // },
  242. // });
  243. ssh.connection.sftp((err, sftp) => {
  244. if (err) throw err;
  245. let rs = fs.createReadStream(file);
  246. let ws = sftp.createWriteStream("/home/admin/build.tar.gz");
  247. rs.on("data", (buffer) => {
  248. bar.tick(buffer.length);
  249. });
  250. rs.on("close", () => {
  251. console.log("stream close");
  252. });
  253. rs.on("end", () => {
  254. console.log("stream end");
  255. });
  256. rs.pipe(ws);
  257. });
  258. // let sftp = new SftpClient();
  259. // await sftp.connect({
  260. // host: accessJson.Host,
  261. // username: accessJson.User,
  262. // password: accessJson.PWD,
  263. // });
  264. // await sftp.fastPut(file, "/home/admin/build.tar.gz", {
  265. // concurrency: 64, // integer. Number of concurrent reads
  266. // chunkSize: 32768, // integer. Size of each read in bytes
  267. // // mode: 0o755, // mixed. Integer or string representing the file mode to set
  268. // step: (total_transferred, chunk, total) => {
  269. // bar.tick(chunk);
  270. // },
  271. // });
  272. // console.log("finish");
  273. // sftp.end();
  274. // ssh = new NodeSSH();
  275. // await ssh.connect({
  276. // host: config.ip,
  277. // username: `${config.username}/${server.ip}/any`,
  278. // password: config.password,
  279. // });
  280. // let shell = await ssh.requestShell();
  281. // shell.on("close", () => {
  282. // console.log("Stream :: close");
  283. // });
  284. // shell.on("data", (data) => {
  285. // let str = data.toString();
  286. // process.stdout.write(data);
  287. // if (/^login\:/.test(str)) {
  288. // shell.write("admin\n");
  289. // }
  290. // if (/^admin@.*password:/.test(str)) {
  291. // shell.write(`${server.password}\n`);
  292. // setTimeout(() => {
  293. // shell.write("su root\n");
  294. // setTimeout(() => {
  295. // shell.write(`${server.password}\n`);
  296. // setTimeout(() => {
  297. // shell.write("./deploy.sh\n");
  298. // }, 100);
  299. // }, 100);
  300. // }, 100);
  301. // }
  302. // });
  303. };