1
0

main.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "log"
  6. "os"
  7. "os/signal"
  8. "syscall"
  9. _ "unsafe"
  10. "x-ui/config"
  11. "x-ui/database"
  12. "x-ui/logger"
  13. "x-ui/sub"
  14. "x-ui/util/crypto"
  15. "x-ui/web"
  16. "x-ui/web/global"
  17. "x-ui/web/service"
  18. "github.com/joho/godotenv"
  19. "github.com/op/go-logging"
  20. )
  21. func runWebServer() {
  22. log.Printf("Starting %v %v", config.GetName(), config.GetVersion())
  23. switch config.GetLogLevel() {
  24. case config.Debug:
  25. logger.InitLogger(logging.DEBUG)
  26. case config.Info:
  27. logger.InitLogger(logging.INFO)
  28. case config.Notice:
  29. logger.InitLogger(logging.NOTICE)
  30. case config.Warn:
  31. logger.InitLogger(logging.WARNING)
  32. case config.Error:
  33. logger.InitLogger(logging.ERROR)
  34. default:
  35. log.Fatalf("Unknown log level: %v", config.GetLogLevel())
  36. }
  37. godotenv.Load()
  38. err := database.InitDB(config.GetDBPath())
  39. if err != nil {
  40. log.Fatalf("Error initializing database: %v", err)
  41. }
  42. var server *web.Server
  43. server = web.NewServer()
  44. global.SetWebServer(server)
  45. err = server.Start()
  46. if err != nil {
  47. log.Fatalf("Error starting web server: %v", err)
  48. return
  49. }
  50. var subServer *sub.Server
  51. subServer = sub.NewServer()
  52. global.SetSubServer(subServer)
  53. err = subServer.Start()
  54. if err != nil {
  55. log.Fatalf("Error starting sub server: %v", err)
  56. return
  57. }
  58. sigCh := make(chan os.Signal, 1)
  59. // Trap shutdown signals
  60. signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGTERM)
  61. for {
  62. sig := <-sigCh
  63. switch sig {
  64. case syscall.SIGHUP:
  65. logger.Info("Received SIGHUP signal. Restarting servers...")
  66. err := server.Stop()
  67. if err != nil {
  68. logger.Debug("Error stopping web server:", err)
  69. }
  70. err = subServer.Stop()
  71. if err != nil {
  72. logger.Debug("Error stopping sub server:", err)
  73. }
  74. server = web.NewServer()
  75. global.SetWebServer(server)
  76. err = server.Start()
  77. if err != nil {
  78. log.Fatalf("Error restarting web server: %v", err)
  79. return
  80. }
  81. log.Println("Web server restarted successfully.")
  82. subServer = sub.NewServer()
  83. global.SetSubServer(subServer)
  84. err = subServer.Start()
  85. if err != nil {
  86. log.Fatalf("Error restarting sub server: %v", err)
  87. return
  88. }
  89. log.Println("Sub server restarted successfully.")
  90. default:
  91. server.Stop()
  92. subServer.Stop()
  93. log.Println("Shutting down servers.")
  94. return
  95. }
  96. }
  97. }
  98. func resetSetting() {
  99. err := database.InitDB(config.GetDBPath())
  100. if err != nil {
  101. fmt.Println("Failed to initialize database:", err)
  102. return
  103. }
  104. settingService := service.SettingService{}
  105. err = settingService.ResetSettings()
  106. if err != nil {
  107. fmt.Println("Failed to reset settings:", err)
  108. } else {
  109. fmt.Println("Settings successfully reset.")
  110. }
  111. }
  112. func showSetting(show bool) {
  113. if show {
  114. settingService := service.SettingService{}
  115. port, err := settingService.GetPort()
  116. if err != nil {
  117. fmt.Println("get current port failed, error info:", err)
  118. }
  119. webBasePath, err := settingService.GetBasePath()
  120. if err != nil {
  121. fmt.Println("get webBasePath failed, error info:", err)
  122. }
  123. certFile, err := settingService.GetCertFile()
  124. if err != nil {
  125. fmt.Println("get cert file failed, error info:", err)
  126. }
  127. keyFile, err := settingService.GetKeyFile()
  128. if err != nil {
  129. fmt.Println("get key file failed, error info:", err)
  130. }
  131. userService := service.UserService{}
  132. userModel, err := userService.GetFirstUser()
  133. if err != nil {
  134. fmt.Println("get current user info failed, error info:", err)
  135. }
  136. if userModel.Username == "" || userModel.Password == "" {
  137. fmt.Println("current username or password is empty")
  138. }
  139. fmt.Println("current panel settings as follows:")
  140. if certFile == "" || keyFile == "" {
  141. fmt.Println("Warning: Panel is not secure with SSL")
  142. } else {
  143. fmt.Println("Panel is secure with SSL")
  144. }
  145. hasDefaultCredential := func() bool {
  146. return userModel.Username == "admin" && crypto.CheckPasswordHash(userModel.Password, "admin")
  147. }()
  148. fmt.Println("hasDefaultCredential:", hasDefaultCredential)
  149. fmt.Println("port:", port)
  150. fmt.Println("webBasePath:", webBasePath)
  151. }
  152. }
  153. func updateTgbotEnableSts(status bool) {
  154. settingService := service.SettingService{}
  155. currentTgSts, err := settingService.GetTgbotEnabled()
  156. if err != nil {
  157. fmt.Println(err)
  158. return
  159. }
  160. logger.Infof("current enabletgbot status[%v],need update to status[%v]", currentTgSts, status)
  161. if currentTgSts != status {
  162. err := settingService.SetTgbotEnabled(status)
  163. if err != nil {
  164. fmt.Println(err)
  165. return
  166. } else {
  167. logger.Infof("SetTgbotEnabled[%v] success", status)
  168. }
  169. }
  170. }
  171. func updateTgbotSetting(tgBotToken string, tgBotChatid string, tgBotRuntime string) {
  172. err := database.InitDB(config.GetDBPath())
  173. if err != nil {
  174. fmt.Println("Error initializing database:", err)
  175. return
  176. }
  177. settingService := service.SettingService{}
  178. if tgBotToken != "" {
  179. err := settingService.SetTgBotToken(tgBotToken)
  180. if err != nil {
  181. fmt.Printf("Error setting Telegram bot token: %v\n", err)
  182. return
  183. }
  184. logger.Info("Successfully updated Telegram bot token.")
  185. }
  186. if tgBotRuntime != "" {
  187. err := settingService.SetTgbotRuntime(tgBotRuntime)
  188. if err != nil {
  189. fmt.Printf("Error setting Telegram bot runtime: %v\n", err)
  190. return
  191. }
  192. logger.Infof("Successfully updated Telegram bot runtime to [%s].", tgBotRuntime)
  193. }
  194. if tgBotChatid != "" {
  195. err := settingService.SetTgBotChatId(tgBotChatid)
  196. if err != nil {
  197. fmt.Printf("Error setting Telegram bot chat ID: %v\n", err)
  198. return
  199. }
  200. logger.Info("Successfully updated Telegram bot chat ID.")
  201. }
  202. }
  203. func updateSetting(port int, username string, password string, webBasePath string, listenIP string, resetTwoFactor bool) {
  204. err := database.InitDB(config.GetDBPath())
  205. if err != nil {
  206. fmt.Println("Database initialization failed:", err)
  207. return
  208. }
  209. settingService := service.SettingService{}
  210. userService := service.UserService{}
  211. if port > 0 {
  212. err := settingService.SetPort(port)
  213. if err != nil {
  214. fmt.Println("Failed to set port:", err)
  215. } else {
  216. fmt.Printf("Port set successfully: %v\n", port)
  217. }
  218. }
  219. if username != "" || password != "" {
  220. err := userService.UpdateFirstUser(username, password)
  221. if err != nil {
  222. fmt.Println("Failed to update username and password:", err)
  223. } else {
  224. fmt.Println("Username and password updated successfully")
  225. }
  226. }
  227. if webBasePath != "" {
  228. err := settingService.SetBasePath(webBasePath)
  229. if err != nil {
  230. fmt.Println("Failed to set base URI path:", err)
  231. } else {
  232. fmt.Println("Base URI path set successfully")
  233. }
  234. }
  235. if resetTwoFactor {
  236. err := settingService.SetTwoFactorEnable(false)
  237. if err != nil {
  238. fmt.Println("Failed to reset two-factor authentication:", err)
  239. } else {
  240. settingService.SetTwoFactorToken("")
  241. fmt.Println("Two-factor authentication reset successfully")
  242. }
  243. }
  244. if listenIP != "" {
  245. err := settingService.SetListen(listenIP)
  246. if err != nil {
  247. fmt.Println("Failed to set listen IP:", err)
  248. } else {
  249. fmt.Printf("listen %v set successfully", listenIP)
  250. }
  251. }
  252. }
  253. func updateCert(publicKey string, privateKey string) {
  254. err := database.InitDB(config.GetDBPath())
  255. if err != nil {
  256. fmt.Println(err)
  257. return
  258. }
  259. if (privateKey != "" && publicKey != "") || (privateKey == "" && publicKey == "") {
  260. settingService := service.SettingService{}
  261. err = settingService.SetCertFile(publicKey)
  262. if err != nil {
  263. fmt.Println("set certificate public key failed:", err)
  264. } else {
  265. fmt.Println("set certificate public key success")
  266. }
  267. err = settingService.SetKeyFile(privateKey)
  268. if err != nil {
  269. fmt.Println("set certificate private key failed:", err)
  270. } else {
  271. fmt.Println("set certificate private key success")
  272. }
  273. } else {
  274. fmt.Println("both public and private key should be entered.")
  275. }
  276. }
  277. func GetCertificate(getCert bool) {
  278. if getCert {
  279. settingService := service.SettingService{}
  280. certFile, err := settingService.GetCertFile()
  281. if err != nil {
  282. fmt.Println("get cert file failed, error info:", err)
  283. }
  284. keyFile, err := settingService.GetKeyFile()
  285. if err != nil {
  286. fmt.Println("get key file failed, error info:", err)
  287. }
  288. fmt.Println("cert:", certFile)
  289. fmt.Println("key:", keyFile)
  290. }
  291. }
  292. func GetListenIP(getListen bool) {
  293. if getListen {
  294. settingService := service.SettingService{}
  295. ListenIP, err := settingService.GetListen()
  296. if err != nil {
  297. log.Printf("Failed to retrieve listen IP: %v", err)
  298. return
  299. }
  300. fmt.Println("listenIP:", ListenIP)
  301. }
  302. }
  303. func migrateDb() {
  304. inboundService := service.InboundService{}
  305. err := database.InitDB(config.GetDBPath())
  306. if err != nil {
  307. log.Fatal(err)
  308. }
  309. fmt.Println("Start migrating database...")
  310. inboundService.MigrateDB()
  311. fmt.Println("Migration done!")
  312. }
  313. func main() {
  314. if len(os.Args) < 2 {
  315. runWebServer()
  316. return
  317. }
  318. var showVersion bool
  319. flag.BoolVar(&showVersion, "v", false, "show version")
  320. runCmd := flag.NewFlagSet("run", flag.ExitOnError)
  321. settingCmd := flag.NewFlagSet("setting", flag.ExitOnError)
  322. var port int
  323. var username string
  324. var password string
  325. var webBasePath string
  326. var listenIP string
  327. var getListen bool
  328. var webCertFile string
  329. var webKeyFile string
  330. var tgbottoken string
  331. var tgbotchatid string
  332. var enabletgbot bool
  333. var tgbotRuntime string
  334. var reset bool
  335. var show bool
  336. var getCert bool
  337. var resetTwoFactor bool
  338. settingCmd.BoolVar(&reset, "reset", false, "Reset all settings")
  339. settingCmd.BoolVar(&show, "show", false, "Display current settings")
  340. settingCmd.IntVar(&port, "port", 0, "Set panel port number")
  341. settingCmd.StringVar(&username, "username", "", "Set login username")
  342. settingCmd.StringVar(&password, "password", "", "Set login password")
  343. settingCmd.StringVar(&webBasePath, "webBasePath", "", "Set base path for Panel")
  344. settingCmd.StringVar(&listenIP, "listenIP", "", "set panel listenIP IP")
  345. settingCmd.BoolVar(&resetTwoFactor, "resetTwoFactor", false, "Reset two-factor authentication settings")
  346. settingCmd.BoolVar(&getListen, "getListen", false, "Display current panel listenIP IP")
  347. settingCmd.BoolVar(&getCert, "getCert", false, "Display current certificate settings")
  348. settingCmd.StringVar(&webCertFile, "webCert", "", "Set path to public key file for panel")
  349. settingCmd.StringVar(&webKeyFile, "webCertKey", "", "Set path to private key file for panel")
  350. settingCmd.StringVar(&tgbottoken, "tgbottoken", "", "Set token for Telegram bot")
  351. settingCmd.StringVar(&tgbotRuntime, "tgbotRuntime", "", "Set cron time for Telegram bot notifications")
  352. settingCmd.StringVar(&tgbotchatid, "tgbotchatid", "", "Set chat ID for Telegram bot notifications")
  353. settingCmd.BoolVar(&enabletgbot, "enabletgbot", false, "Enable notifications via Telegram bot")
  354. oldUsage := flag.Usage
  355. flag.Usage = func() {
  356. oldUsage()
  357. fmt.Println()
  358. fmt.Println("Commands:")
  359. fmt.Println(" run run web panel")
  360. fmt.Println(" migrate migrate form other/old x-ui")
  361. fmt.Println(" setting set settings")
  362. }
  363. flag.Parse()
  364. if showVersion {
  365. fmt.Println(config.GetVersion())
  366. return
  367. }
  368. switch os.Args[1] {
  369. case "run":
  370. err := runCmd.Parse(os.Args[2:])
  371. if err != nil {
  372. fmt.Println(err)
  373. return
  374. }
  375. runWebServer()
  376. case "migrate":
  377. migrateDb()
  378. case "setting":
  379. err := settingCmd.Parse(os.Args[2:])
  380. if err != nil {
  381. fmt.Println(err)
  382. return
  383. }
  384. if reset {
  385. resetSetting()
  386. } else {
  387. updateSetting(port, username, password, webBasePath, listenIP, resetTwoFactor)
  388. }
  389. if show {
  390. showSetting(show)
  391. }
  392. if getListen {
  393. GetListenIP(getListen)
  394. }
  395. if getCert {
  396. GetCertificate(getCert)
  397. }
  398. if (tgbottoken != "") || (tgbotchatid != "") || (tgbotRuntime != "") {
  399. updateTgbotSetting(tgbottoken, tgbotchatid, tgbotRuntime)
  400. }
  401. if enabletgbot {
  402. updateTgbotEnableSts(enabletgbot)
  403. }
  404. case "cert":
  405. err := settingCmd.Parse(os.Args[2:])
  406. if err != nil {
  407. fmt.Println(err)
  408. return
  409. }
  410. if reset {
  411. updateCert("", "")
  412. } else {
  413. updateCert(webCertFile, webKeyFile)
  414. }
  415. default:
  416. fmt.Println("Invalid subcommands")
  417. fmt.Println()
  418. runCmd.Usage()
  419. fmt.Println()
  420. settingCmd.Usage()
  421. }
  422. }