1
0

config.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. package main
  2. import (
  3. "archive/zip"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "log"
  9. "net/http"
  10. "os"
  11. "path/filepath"
  12. "strconv"
  13. "strings"
  14. "time"
  15. "imuslab.com/zoraxy/mod/dynamicproxy"
  16. "imuslab.com/zoraxy/mod/utils"
  17. )
  18. /*
  19. Reverse Proxy Configs
  20. The following section handle
  21. the reverse proxy configs
  22. */
  23. type Record struct {
  24. ProxyType string
  25. Rootname string
  26. ProxyTarget string
  27. UseTLS bool
  28. SkipTlsValidation bool
  29. RequireBasicAuth bool
  30. BasicAuthCredentials []*dynamicproxy.BasicAuthCredentials
  31. }
  32. func SaveReverseProxyConfig(proxyConfigRecord *Record) error {
  33. //TODO: Make this accept new def types
  34. os.MkdirAll("./conf/proxy/", 0775)
  35. filename := getFilenameFromRootName(proxyConfigRecord.Rootname)
  36. //Generate record
  37. thisRecord := proxyConfigRecord
  38. //Write to file
  39. js, _ := json.MarshalIndent(thisRecord, "", " ")
  40. return ioutil.WriteFile(filepath.Join("./conf/proxy/", filename), js, 0775)
  41. }
  42. func RemoveReverseProxyConfig(rootname string) error {
  43. filename := getFilenameFromRootName(rootname)
  44. removePendingFile := strings.ReplaceAll(filepath.Join("./conf/proxy/", filename), "\\", "/")
  45. log.Println("Config Removed: ", removePendingFile)
  46. if utils.FileExists(removePendingFile) {
  47. err := os.Remove(removePendingFile)
  48. if err != nil {
  49. log.Println(err.Error())
  50. return err
  51. }
  52. }
  53. //File already gone
  54. return nil
  55. }
  56. // Return ptype, rootname and proxyTarget, error if any
  57. func LoadReverseProxyConfig(filename string) (*Record, error) {
  58. thisRecord := Record{}
  59. configContent, err := ioutil.ReadFile(filename)
  60. if err != nil {
  61. return &thisRecord, err
  62. }
  63. //Unmarshal the content into config
  64. err = json.Unmarshal(configContent, &thisRecord)
  65. if err != nil {
  66. return &thisRecord, err
  67. }
  68. //Return it
  69. return &thisRecord, nil
  70. }
  71. func getFilenameFromRootName(rootname string) string {
  72. //Generate a filename for this rootname
  73. filename := strings.ReplaceAll(rootname, ".", "_")
  74. filename = strings.ReplaceAll(filename, "/", "-")
  75. filename = filename + ".config"
  76. return filename
  77. }
  78. /*
  79. Importer and Exporter of Zoraxy proxy config
  80. */
  81. func ExportConfigAsZip(w http.ResponseWriter, r *http.Request) {
  82. // Specify the folder path to be zipped
  83. folderPath := "./conf/"
  84. // Set the Content-Type header to indicate it's a zip file
  85. w.Header().Set("Content-Type", "application/zip")
  86. // Set the Content-Disposition header to specify the file name
  87. w.Header().Set("Content-Disposition", "attachment; filename=\"config.zip\"")
  88. // Create a zip writer
  89. zipWriter := zip.NewWriter(w)
  90. defer zipWriter.Close()
  91. // Walk through the folder and add files to the zip
  92. err := filepath.Walk(folderPath, func(filePath string, fileInfo os.FileInfo, err error) error {
  93. if err != nil {
  94. return err
  95. }
  96. if folderPath == filePath {
  97. //Skip root folder
  98. return nil
  99. }
  100. // Create a new file in the zip
  101. if !utils.IsDir(filePath) {
  102. zipFile, err := zipWriter.Create(filePath)
  103. if err != nil {
  104. return err
  105. }
  106. // Open the file on disk
  107. file, err := os.Open(filePath)
  108. if err != nil {
  109. return err
  110. }
  111. defer file.Close()
  112. // Copy the file contents to the zip file
  113. _, err = io.Copy(zipFile, file)
  114. if err != nil {
  115. return err
  116. }
  117. }
  118. return nil
  119. })
  120. if err != nil {
  121. // Handle the error and send an HTTP response with the error message
  122. http.Error(w, fmt.Sprintf("Failed to zip folder: %v", err), http.StatusInternalServerError)
  123. return
  124. }
  125. }
  126. func ImportConfigFromZip(w http.ResponseWriter, r *http.Request) {
  127. // Check if the request is a POST with a file upload
  128. if r.Method != http.MethodPost {
  129. http.Error(w, "Invalid request method", http.StatusBadRequest)
  130. return
  131. }
  132. // Max file size limit (10 MB in this example)
  133. r.ParseMultipartForm(10 << 20)
  134. // Get the uploaded file
  135. file, handler, err := r.FormFile("file")
  136. if err != nil {
  137. http.Error(w, "Failed to retrieve uploaded file", http.StatusInternalServerError)
  138. return
  139. }
  140. defer file.Close()
  141. if filepath.Ext(handler.Filename) != ".zip" {
  142. http.Error(w, "Upload file is not a zip file", http.StatusInternalServerError)
  143. return
  144. }
  145. // Create the target directory to unzip the files
  146. targetDir := "./conf"
  147. if utils.FileExists(targetDir) {
  148. //Backup the old config to old
  149. os.Rename("./conf", "./conf.old_"+strconv.Itoa(int(time.Now().Unix())))
  150. }
  151. err = os.MkdirAll(targetDir, os.ModePerm)
  152. if err != nil {
  153. http.Error(w, fmt.Sprintf("Failed to create target directory: %v", err), http.StatusInternalServerError)
  154. return
  155. }
  156. // Open the zip file
  157. zipReader, err := zip.NewReader(file, handler.Size)
  158. if err != nil {
  159. http.Error(w, fmt.Sprintf("Failed to open zip file: %v", err), http.StatusInternalServerError)
  160. return
  161. }
  162. // Extract each file from the zip archive
  163. for _, zipFile := range zipReader.File {
  164. // Open the file in the zip archive
  165. rc, err := zipFile.Open()
  166. if err != nil {
  167. http.Error(w, fmt.Sprintf("Failed to open file in zip: %v", err), http.StatusInternalServerError)
  168. return
  169. }
  170. defer rc.Close()
  171. // Create the corresponding file on disk
  172. zipFile.Name = strings.ReplaceAll(zipFile.Name, "../", "")
  173. fmt.Println("Restoring: " + strings.ReplaceAll(zipFile.Name, "\\", "/"))
  174. if !strings.HasPrefix(strings.ReplaceAll(zipFile.Name, "\\", "/"), "conf/") {
  175. //Malformed zip file.
  176. http.Error(w, fmt.Sprintf("Invalid zip file structure or version too old"), http.StatusInternalServerError)
  177. return
  178. }
  179. //Check if parent dir exists
  180. if !utils.FileExists(filepath.Dir(zipFile.Name)) {
  181. os.MkdirAll(filepath.Dir(zipFile.Name), 0775)
  182. }
  183. //Create the file
  184. newFile, err := os.Create(zipFile.Name)
  185. if err != nil {
  186. http.Error(w, fmt.Sprintf("Failed to create file: %v", err), http.StatusInternalServerError)
  187. return
  188. }
  189. defer newFile.Close()
  190. // Copy the file contents from the zip to the new file
  191. _, err = io.Copy(newFile, rc)
  192. if err != nil {
  193. http.Error(w, fmt.Sprintf("Failed to extract file from zip: %v", err), http.StatusInternalServerError)
  194. return
  195. }
  196. }
  197. // Send a success response
  198. w.WriteHeader(http.StatusOK)
  199. fmt.Fprintln(w, "Configuration restored")
  200. }