package main import ( // "context" "log" // "time" "os" "fmt" "flag" "regexp" "bytes" "strconv" "encoding/json" "crypto/tls" "net/http" "html/template" "path/filepath" "github.com/gorilla/mux" "github.com/sethvargo/go-password/password" ) // { // "request_id": "540486b5-80b6-4250-1ba3-ec562984c58c", // "lease_id": "", // "renewable": false, // "lease_duration": 0, // "data": { // "user": "password" // }, // "wrap_info": null, // "warnings": null, // "auth": null, // "mount_type": "system" // } // var ( Debug bool TemplateDir string TemplateFile string ActionAddress string VaultAddress string Data string ListenPort string TlsEnable bool TlsCertFile string TlsKeyFile string ) type TemplateData struct { URL string TEXT string } type UnwrappedData struct { Rerquest_id string `json: "request_id"` Lease_id string `json: "lease_id"` Renewable bool `json: "renewable"` Lease_daration int `json:"lease_duration"` Data map[string]string `json: "data"` Wrap_info string `json: "wrap_info"` Warnings string `json: "warnings"` Auth string `json: "auth"` Mount_type string `json: "mount_type"` Error string `json: "errors"` } func vaultDataWrap(vaultAddr string, vaultToken string, vaultSecretName string) string { customTransport := &(*http.DefaultTransport.(*http.Transport)) customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} client := &http.Client{Transport: customTransport} // client := &http.Client{} req, _ := http.NewRequest("POST", vaultAddr, nil) req.Header.Add("Accept", "application/json") req.Header.Add("X-Vault-Token", vaultToken) resp, err := client.Do(req) if err != nil { log.Println("Errored when sending request to the Vault server") } var result map[string]interface{} json.NewDecoder(resp.Body).Decode(&result) secret := result["data"].(map[string]interface{})["data"].(map[string]interface{})[vaultSecretName] log.Println(result) return fmt.Sprint(secret) } func vaultDataUnWrap(vaultAddr string, vaultWrapToken string) map[string]string { log.Printf("Vault address: %s ", vaultAddr) customTransport := &(*http.DefaultTransport.(*http.Transport)) customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} client := &http.Client{Transport: customTransport} // client := &http.Client{} log.Println(vaultAddr, vaultWrapToken) req, _ := http.NewRequest("POST", vaultAddr, nil) req.Header.Add("Accept", "application/json") req.Header.Add("X-Vault-Token", vaultWrapToken) resp, err := client.Do(req) if err != nil { log.Println("Errored when sending request to the Vault server", err) } log.Println(resp) var result UnwrappedData json.NewDecoder(resp.Body).Decode(&result) secret := result.Data if Debug { log.Println(result) log.Println(secret) } // fmt.Sprint(secret) for v, k := range secret { log.Println(k, v) } return secret } func ParseTemplate(templateFileName string, data interface{}) (body string, err error) { body = "" t, err := template.ParseFiles(templateFileName) if err != nil { log.Println("Ошибка преобразования html шаблона", templateFileName, err) return } buf := new(bytes.Buffer) if err = t.Execute(buf, data); err != nil { log.Println("Ошибка преобразования html шаблона", templateFileName, err) body = "" } else { body = buf.String() } return } func getStaticPage(w http.ResponseWriter, r *http.Request) { var ( templateData TemplateData ) template := filepath.Join(TemplateDir, TemplateFile) // templateData.UUID = uuid templateData.URL = ActionAddress + ":" + ListenPort templateData.TEXT = Data // templateData.URL = FishingUrl + "/" + arrUsers[i].messageUUID if body, err := ParseTemplate(template, templateData); err == nil { w.Write([]byte(body)) } } // hvs.CAES - 95 // s.Dj7kZS - 26 func getDataFromHtmlForm(w http.ResponseWriter, r *http.Request) { r.ParseForm() token := r.FormValue("input_token") vaultPath := VaultAddress + "/v1/sys/wrapping/unwrap" // fmt.Fprintln(w, r.URL.RawQuery) // log.Println(w, r.URL.RawQuery) if Debug { log.Printf("Текст для расшифровки: %s ", token) log.Printf("Адрес сервера Hashicorp Vault: %s ", vaultPath) } // Проверка текста на соответствие шаблону re := regexp.MustCompile(`^(hvs|s)\.[\w\-\_]+`) if Debug { fmt.Println(re.Match([]byte(token))) } if token != "" && re.Match([]byte(token)) { b := new(bytes.Buffer) for key, value := range vaultDataUnWrap(vaultPath, token) { fmt.Fprintf(b, "%s: %s\n", key, value) } Data = b.String() if Debug { log.Println(Data) } } else { Data = "Введите токен" } getStaticPage(w, r) // http.Redirect(w, r, "http://"+r.Host, http.StatusMovedPermanently) } func genPassword(w http.ResponseWriter, r *http.Request) { // params := mux.Vars(r) // passLength := params["passLength"] r.ParseForm() passLength := r.FormValue("passlength") if Debug { log.Printf(r.FormValue("passlength"), passLength) } if len(passLength) == 0 { passLength = "32" } // w.Write([]byte("Длина пароля " + passLength + "/n")) passwordLength, err := strconv.Atoi(passLength) if passwordLength > 1024 { log.Printf("Oversized password length") Data = "Превышена длина пароля" getStaticPage(w, r) return } if err != nil { log.Println(err) } res, err := password.Generate(passwordLength, 10, 5, false, true) if err != nil { log.Println(err) } if Debug { log.Printf(res) } Data = res // w.Write([]byte(res)) getStaticPage(w, r) } func genPasswordDefault(w http.ResponseWriter, r *http.Request) { res, err := password.Generate(64, 10, 5, false, false) if err != nil { log.Fatal(err) } log.Printf(res) // w.Write([]byte(res)) Data = res // w.Write([]byte(res)) getStaticPage(w, r) } func main() { var ( logFile string ) flag.BoolVar(&Debug, "debug", false, "Вывод отладочных сообщений в консоль") flag.StringVar(&logFile, "log-file", "vault-unwrap.log", "Путь до лог-файла ") flag.StringVar(&TemplateDir, "template-dir", "html-template", "Каталог с шаблонами") flag.StringVar(&TemplateFile, "template-file", "index.html", "Файл-шаблон для ВЭБ-странцы") flag.StringVar(&VaultAddress, "vault-url", "", "Адрес сервера Hashicorp Vault (https://host.name:8200)") flag.StringVar(&ActionAddress, "action-address", "", "Адрес данного сервиса (host.name)") flag.StringVar(&ListenPort, "listen-port", "8080", "Номер порта сервиса") flag.StringVar(&TlsCertFile, "tls-cert", "", "TLS сертификат (файл)") flag.StringVar(&TlsKeyFile, "tls-key", "", "TLS ключ (файл)") flag.BoolVar(&TlsEnable, "tls", false, "Использовать SSL/TLS") flag.Parse() if os.Getenv("logFile") != "" { logFile = os.Getenv("logFile") } fLog, err := os.OpenFile(logFile, os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666) if err != nil { log.Fatalf("error opening file: %v", err) } defer fLog.Close() if Debug { log.SetOutput(os.Stdout) } else { log.SetOutput(fLog) } if os.Getenv("VAULT_ADDRESS") == "" && VaultAddress == "" { log.Println("Send error: make sure environment variables `VAULT_ADDRESS` was set") } else if os.Getenv("VAULT_ADDRESS") != "" && VaultAddress == "" { VaultAddress = os.Getenv("VAULT_ADDRESS") } if Debug { log.Printf("Адрес сервера Hashicorp Vault: %s ", VaultAddress) } rtr := mux.NewRouter() rtr.HandleFunc("/unwrap", getDataFromHtmlForm) rtr.HandleFunc("/genpassword/{passLength:[0-9]+}", genPassword) rtr.HandleFunc("/genpassword", genPassword) rtr.HandleFunc("/", getDataFromHtmlForm) rtr.PathPrefix("/").Handler(http.FileServer(http.Dir("./static"))) http.Handle("/", rtr) if os.Getenv("LISTEN_PORT") != "" { ListenPort = os.Getenv("LISTEN_PORT") } else { if TlsEnable && ListenPort == ""{ ListenPort = "8443" } } listenAddr := ":" + ListenPort log.Println("Listening...") if TlsEnable { ActionAddress = "https://" + ActionAddress if Debug { log.Printf("Адрес сервиса: %s%s ", ActionAddress, listenAddr) } log.Fatal(http.ListenAndServeTLS(listenAddr, TlsCertFile, TlsKeyFile, nil)) } else { ActionAddress = "http://" + ActionAddress if Debug { log.Printf("Адрес сервиса: %s%s ", ActionAddress, listenAddr) } http.ListenAndServe(listenAddr, nil) } }