apply.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /**
  2. * @author oldj
  3. * @blog https://oldj.net
  4. *
  5. * try to apply hosts
  6. */
  7. 'use strict'
  8. const fs = require('fs')
  9. const path = require('path')
  10. const exec = require('child_process').exec
  11. const getPref = require('./actions/getPref')
  12. const getLang = require('./actions/getLang')
  13. const io = require('./io')
  14. const {sys_hosts_path, work_path} = require('./paths')
  15. const crypto = require('crypto')
  16. const md5File = require('md5-file')
  17. const applyAfter_Unix = require('./applyAfter_Unix')
  18. const platform = process.platform
  19. const svr = require('./svr')
  20. //const version = require('../version').version.join('.')
  21. let sudo_pswd = ''
  22. let lang = null
  23. function needPswd (str) {
  24. str = str.toLowerCase()
  25. console.log('---')
  26. console.log(str)
  27. let keys = [
  28. 'Permission denied'
  29. , 'incorrect password'
  30. , 'Password:Sorry, try again.'
  31. ]
  32. return !!keys.find(k => str.includes(k.toLowerCase()))
  33. }
  34. function apply_Unix (content, callback) {
  35. let tmp_fn = path.join(work_path, 'tmp.txt')
  36. if (typeof content !== 'string') {
  37. callback('bad content')
  38. return
  39. }
  40. io.pWriteFile(tmp_fn, content)
  41. .then(() => {
  42. let cmd
  43. if (!sudo_pswd) {
  44. cmd = [
  45. `cat "${tmp_fn}" > ${sys_hosts_path}`
  46. , `rm -rf ${tmp_fn}`
  47. ].join(' && ')
  48. } else {
  49. cmd = [
  50. `echo '${sudo_pswd}' | sudo -S chmod 777 ${sys_hosts_path}`
  51. , `cat "${tmp_fn}" > ${sys_hosts_path}`
  52. , `echo '${sudo_pswd}' | sudo -S chmod 644 ${sys_hosts_path}`
  53. // , 'rm -rf ' + tmp_fn
  54. ].join(' && ')
  55. }
  56. return cmd
  57. })
  58. .then(cmd => {
  59. //console.log('cmd: ' + cmd)
  60. exec(cmd, function (error, stdout, stderr) {
  61. // command output is in stdout
  62. if (!error) {
  63. callback()
  64. return
  65. }
  66. callback(!sudo_pswd || needPswd(stdout + stderr) ? 'need_sudo' : error)
  67. })
  68. })
  69. }
  70. function apply_Win32 (content, callback) {
  71. // todo 判断写入权限
  72. try {
  73. fs.writeFileSync(sys_hosts_path, content, 'utf-8')
  74. } catch (e) {
  75. console.log(e)
  76. let msg = e.message
  77. msg = `${msg}\n\n${lang.please_run_as_admin}`
  78. console.log(msg)
  79. svr.broadcast('alert', msg)
  80. return
  81. }
  82. // todo 刷新 DNS 缓存
  83. callback()
  84. }
  85. function tryToApply (content, callback) {
  86. if (platform !== 'win32') {
  87. // unix
  88. apply_Unix(content, (e) => {
  89. if (e) {
  90. callback(e)
  91. } else {
  92. applyAfter_Unix(sudo_pswd, callback)
  93. }
  94. })
  95. } else {
  96. // win32
  97. apply_Win32(content, callback)
  98. }
  99. }
  100. function wrapContent (cnt) {
  101. return `# SwitchHosts!
  102. ${cnt}`
  103. }
  104. module.exports = (cnt, pswd) => {
  105. if (pswd) {
  106. sudo_pswd = pswd
  107. }
  108. let pref
  109. cnt = wrapContent(cnt)
  110. return Promise.resolve()
  111. .then(() => {
  112. return getPref()
  113. .then(p => {
  114. pref = p
  115. return p.user_language || 'en'
  116. })
  117. .then(l => {
  118. return getLang(svr, l)
  119. })
  120. .then(v => lang = v || {})
  121. })
  122. .then(() => {
  123. return new Promise((resolve, reject) => {
  124. let file_md5 = md5File.sync(sys_hosts_path)
  125. let cnt_md5 = crypto.createHash('md5').update(cnt).digest('hex')
  126. if (file_md5 === cnt_md5) {
  127. // 文件相同
  128. resolve(true)
  129. return
  130. }
  131. tryToApply(cnt, e => e ? reject(e) : resolve())
  132. //reject('need_sudo')
  133. })
  134. })
  135. .then(eq => {
  136. // eq 为 true 表示新内容与系统 hosts 内容相同,hosts 没有变化,不需要执行自定义命令
  137. return eq ? null : new Promise((resolve, reject) => {
  138. let after_cmd = pref.after_cmd
  139. if (after_cmd) {
  140. // todo 传入当前应用的模块名作为参数
  141. exec(after_cmd, (error, stdout, stderr) => {
  142. // command output is in stdout
  143. if (error) {
  144. reject({title: 'After CMD Error', content: stderr})
  145. } else {
  146. resolve()
  147. }
  148. })
  149. } else {
  150. resolve()
  151. }
  152. })
  153. .catch(e => {
  154. console.log(e)
  155. svr.broadcast('err', e)
  156. })
  157. })
  158. }