1// Copyright (C) 2022 Huawei Device Co., Ltd. 2// Licensed under the Apache License, Version 2.0 (the "License"); 3// you may not use this file except in compliance with the License. 4// You may obtain a copy of the License at 5// 6// http://www.apache.org/licenses/LICENSE-2.0 7// 8// Unless required by applicable law or agreed to in writing, software 9// distributed under the License is distributed on an "AS IS" BASIS, 10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11// See the License for the specific language governing permissions and 12// limitations under the License. 13 14package main 15 16//遇到报错请在当前目录下执行这个命令: go mod download golang.org/x/text 17import ( 18 "bufio" 19 "bytes" 20 "crypto" 21 "crypto/rand" 22 "crypto/rsa" 23 "crypto/tls" 24 "crypto/x509" 25 "crypto/x509/pkix" 26 "encoding/base64" 27 "encoding/json" 28 "encoding/pem" 29 "flag" 30 "fmt" 31 "io" 32 "io/fs" 33 "log" 34 "math/big" 35 "mime" 36 "net" 37 "net/http" 38 "net/http/cookiejar" 39 "os" 40 "os/exec" 41 "path" 42 "path/filepath" 43 "regexp" 44 "runtime" 45 "strconv" 46 "strings" 47 "time" 48) 49 50const HttpPort = 9000 51 52var exPath string 53var serveInfo string 54var hdcPublicKey string 55var hdcPrivateKey *rsa.PrivateKey 56 57// CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go 58// CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go 59func cors(fs http.Handler, version string) http.HandlerFunc { 60 return func(w http.ResponseWriter, r *http.Request) { 61 // return if you do not want the FileServer handle a specific request 62 r.Header.Add("Cross-Origin-Opener-Policy", "same-origin") 63 r.Header.Add("Cross-Origin-Embedder-Policy", "require-corp") 64 w.Header().Add("Cross-Origin-Opener-Policy", "same-origin") 65 w.Header().Add("Cross-Origin-Embedder-Policy", "require-corp") 66 w.Header().Set("Access-Control-Allow-Origin", "*") 67 w.Header().Set("Access-Control-Allow-Credentials", "true") 68 w.Header().Set("Access-Control-Allow-Headers", "x-requested-with, authorization, blade-auth") //* 69 w.Header().Set("Access-Control-Allow-Methods", "*") //* 70 w.Header().Set("Access-Control-Max-Age", "3600") 71 w.Header().Set("data-version", version) 72 w.Header().Set("Cache-Control", "no-cache") 73 w.Header().Set("Pragma", "no-cache") 74 fs.ServeHTTP(w, r) 75 } 76} 77 78func exist(path string) bool { 79 _, err := os.Stat(path) 80 if err != nil { 81 if os.IsExist(err) { 82 return true 83 } 84 return false 85 } 86 return true 87} 88 89func genSSL() { 90 if exist("cert/keyFile.key") || exist("cert/certFile.pem") { 91 fmt.Println("keyFile.key exists") 92 return 93 } 94 max := new(big.Int).Lsh(big.NewInt(1), 128) 95 serialNumber, _ := rand.Int(rand.Reader, max) 96 subject := pkix.Name{ 97 Organization: []string{"www.smartperf.com"}, 98 OrganizationalUnit: []string{"ITs"}, 99 CommonName: "www.smartperf.com", 100 } 101 certificate509 := x509.Certificate{ 102 SerialNumber: serialNumber, 103 Subject: subject, 104 NotBefore: time.Now(), 105 NotAfter: time.Now().AddDate(10, 0, 0), 106 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 107 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 108 IPAddresses: []net.IP{net.ParseIP("127.0.0.1")}, 109 } 110 chekDir("cert") 111 pk, _ := rsa.GenerateKey(rand.Reader, 1024) 112 derBytes, _ := x509.CreateCertificate(rand.Reader, &certificate509, &certificate509, &pk.PublicKey, pk) 113 certOut, _ := os.Create("cert/certFile.pem") 114 pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) 115 certOut.Close() 116 keyOut, _ := os.Create("cert/keyFile.key") 117 pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(pk)}) 118 keyOut.Close() 119} 120 121func genRsa() { 122 // generate hdc private key 123 privateKey, err := rsa.GenerateKey(rand.Reader, 3072) 124 if err != nil { 125 fmt.Println("Generate hdc rsa private key failed") 126 return 127 } 128 hdcPrivateKey = privateKey 129 130 // generate hdc public key 131 publicKey := &privateKey.PublicKey 132 pkixPublicKey, err := x509.MarshalPKIXPublicKey(publicKey) 133 if err != nil { 134 fmt.Println(err) 135 return 136 } 137 publicKeyBlock := &pem.Block{ 138 Type: "PUBLIC KEY", 139 140 Bytes: pkixPublicKey, 141 } 142 hdcPublicKey = string(pem.EncodeToMemory(publicKeyBlock)) 143} 144 145func main() { 146 port := HttpPort 147 isOpen := 1 148 flag.IntVar(&port, "p", HttpPort, "The port number used") 149 flag.IntVar(&isOpen, "o", 1, "Whether to immediately open the website in your browser; 1 is true; 0 is false") 150 flag.Parse() 151 if isOpen < 0 || isOpen > 1 { 152 fmt.Println("Error: -o must be 0 or 1") 153 return 154 } 155 checkPort(port) 156 genSSL() 157 genRsa() 158 exPath = getCurrentAbPath() 159 fmt.Println(exPath) 160 go func() { 161 version := "" 162 readVersion, versionErr := os.ReadFile(exPath + "/version.txt") 163 if versionErr != nil { 164 version = "" 165 } else { 166 version = string(readVersion) 167 } 168 readReqServerConfig() 169 mux := http.NewServeMux() 170 mime.TypeByExtension(".js") 171 mime.AddExtensionType(".js", "application/javascript") 172 log.Println(mime.TypeByExtension(".js")) 173 mux.HandleFunc("/logger", consoleHandler) 174 mux.Handle("/application/upload/", http.StripPrefix("/application/upload/", http.FileServer(http.Dir(filepath.FromSlash(exPath+"/upload"))))) 175 mux.HandleFunc("/application/download-file", downloadHandler) 176 mux.HandleFunc("/application/serverInfo", serverInfo) 177 mux.HandleFunc("/application/hdcPublicKey", getHdcPublicKey) 178 mux.HandleFunc("/application/encryptHdcMsg", encryptHdcMsg) 179 fs := http.FileServer(http.Dir(exPath + "/")) 180 mux.Handle("/application/", http.StripPrefix("/application/", cors(fs, version))) 181 go func() { 182 ser := &http.Server{ 183 Addr: fmt.Sprintf(":%d", port), 184 Handler: mux, 185 } 186 log.Println(fmt.Sprintf("HTTPS[%d]服务启动", port)) 187 err := ser.ListenAndServeTLS("cert/certFile.pem", "cert/keyFile.key") 188 CheckErr(err) 189 }() 190 go func() { 191 ser := &http.Server{ 192 Addr: fmt.Sprintf(":%d", port+1), 193 Handler: mux, 194 } 195 log.Println(fmt.Sprintf("HTTP[%d]服务启动", port)) 196 err := ser.ListenAndServe() 197 CheckErr(err) 198 }() 199 if isOpen == 1 { 200 open(fmt.Sprintf("https://localhost:%d/application", port)) 201 } 202 }() 203 select {} 204} 205 206func getPidByPort(portNumber int) int { 207 resPid := -1 208 var out bytes.Buffer 209 cmdRes := exec.Command("cmd", "/c", fmt.Sprintf("netstat -ano -p tcp | findstr %d", portNumber)) 210 cmdRes.Stdout = &out 211 cmdRes.Run() 212 cmdResStr := out.String() 213 findStr := regexp.MustCompile(`\s\d+\s`).FindAllString(cmdResStr, -1) 214 if len(findStr) > 0 { 215 pid, err := strconv.Atoi(strings.TrimSpace(findStr[0])) 216 if err != nil { 217 resPid = -1 218 } else { 219 resPid = pid 220 } 221 } 222 return resPid 223} 224 225type LoggerReq struct { 226 FileName string `json:"fileName"` 227 FileSize string `json:"fileSize"` 228} 229 230func consoleHandler(w http.ResponseWriter, r *http.Request) { 231 chekDir(exPath + "/logger") 232 var now = time.Now() 233 var fileName = fmt.Sprintf("%d-%d-%d", now.Year(), now.Month(), now.Day()) 234 dst, err := os.OpenFile(exPath+"/logger/"+fileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND|os.O_SYNC, 0666) 235 CheckErr(err) 236 contentType := r.Header["Content-Type"] 237 if len(contentType) > 0 { 238 contentTypeName := contentType[0] 239 if strings.HasPrefix(contentTypeName, "application/json") { 240 decoder := json.NewDecoder(r.Body) 241 var req LoggerReq 242 decoder.Decode(&req) 243 dst.WriteString(fmt.Sprintf("%s %s (%s M)\n", now.Format("2006-01-02 15:04:05"), req.FileName, req.FileSize)) 244 fmt.Fprintf(w, fmt.Sprintf("日志写入成功%s", exPath)) 245 } 246 } 247} 248 249func serverInfo(w http.ResponseWriter, r *http.Request) { 250 w.Header().Set("Access-Control-Allow-Origin", "*") 251 w.Header().Set("request_info", serveInfo) 252 w.WriteHeader(200) 253} 254 255func getHdcPublicKey(w http.ResponseWriter, r *http.Request) { 256 w.Header().Set("Access-Control-Allow-Origin", "*") 257 w.Header().Set("Content-Type", "text/json") 258 resp(&w)(true, 0, "success", map[string]interface{}{ 259 "publicKey": hdcPublicKey, 260 }) 261} 262 263func encryptHdcMsg(w http.ResponseWriter, r *http.Request) { 264 w.Header().Set("Access-Control-Allow-Origin", "*") 265 w.Header().Set("Content-Type", "text/json") 266 hdcMsg := r.URL.Query().Get("message") 267 if len(hdcMsg) == 0 { 268 resp(&w)(false, -1, "Invalid message", nil) 269 return 270 } 271 signatures, err := rsa.SignPKCS1v15(nil, hdcPrivateKey, crypto.Hash(0), []byte(hdcMsg)) 272 if err != nil { 273 resp(&w)(false, -1, "sign failed", nil) 274 } else { 275 resp(&w)(true, 0, "success", map[string]interface{}{ 276 "signatures": base64.StdEncoding.EncodeToString(signatures), 277 }) 278 } 279} 280 281func readReqServerConfig() string { 282 readServerConfig, serverConfigErr := os.ReadFile(exPath + "/server-config.txt") 283 if serverConfigErr != nil { 284 serveInfo = "" 285 } else { 286 serveInfo = string(readServerConfig) 287 } 288 return serveInfo 289} 290 291func mapToJson(m map[string]interface{}) (string, error) { 292 marshal, err := json.Marshal(m) 293 if err != nil { 294 return "", err 295 } 296 var str = string(marshal) 297 return str, nil 298} 299func jsonToMap(str string) (map[string]interface{}, error) { 300 var m = make(map[string]interface{}) 301 err := json.Unmarshal([]byte(str), &m) 302 if err != nil { 303 return nil, err 304 } 305 return m, nil 306} 307 308// MkDir 创建目录 309func MkDir(path string) { 310 dir := path[0:strings.LastIndex(path, string(os.PathSeparator))] //从文件路径获取目录 311 if _, err := os.Stat(dir); err != nil { //如果目录不存在,创建目录 312 os.MkdirAll(dir, os.ModePerm) 313 } 314} 315 316func resp(w *http.ResponseWriter) func(bool, int, string, map[string]interface{}) { 317 return func(success bool, code int, msg string, obj map[string]interface{}) { 318 toJson, err := mapToJson(map[string]interface{}{ 319 "success": success, 320 "code": code, 321 "msg": msg, 322 "data": obj, 323 }) 324 if err != nil { 325 errRes, _ := mapToJson(map[string]interface{}{ 326 "success": false, 327 "code": -1, 328 "msg": err.Error(), 329 }) 330 fmt.Fprintf(*w, errRes) 331 } else { 332 fmt.Fprintf(*w, toJson) 333 } 334 } 335} 336 337func get(url string) (*http.Response, error) { 338 jar, _ := cookiejar.New(nil) 339 c := &http.Client{ 340 Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, 341 CheckRedirect: nil, 342 Jar: jar, 343 Timeout: time.Duration(3600) * time.Second, 344 } 345 return c.Get(url) 346} 347 348func clearOverdueFile() { 349 MkDir(filepath.FromSlash(fmt.Sprintf("./upload/"))) 350 now := time.Now() 351 loc, err := time.LoadLocation("Asia/Shanghai") 352 if err != nil { 353 return 354 } 355 var checkDue = func(fileName string) bool { 356 f := getSuffixByUrl(fileName) 357 parseTime, err := time.ParseInLocation("20060102150405000", f.fileName, loc) 358 if err != nil { 359 return false 360 } 361 sub := now.Sub(parseTime) 362 if sub.Minutes() > 60 { //bigger than 60 min flag due 363 return true 364 } 365 return false 366 } 367 slash := filepath.FromSlash(fmt.Sprintf("./upload/")) 368 filepath.WalkDir(slash, func(path string, d fs.DirEntry, err error) error { 369 if checkDue(d.Name()) { 370 fmt.Println(now, "delete->", path, d.Name(), err) 371 os.Remove(path) 372 } 373 return nil 374 }) 375} 376func getSuffixByUrl(u string) struct { 377 fileName string 378 suffix string 379} { 380 lastIndex := strings.LastIndex(u, "/") 381 var f string 382 if lastIndex != -1 { 383 f = u[lastIndex:] 384 } else { 385 f = u 386 } 387 index := strings.LastIndex(f, ".") 388 if index != -1 { 389 return struct { 390 fileName string 391 suffix string 392 }{ 393 f[0:index], 394 f[index:], 395 } 396 } else { 397 return struct { 398 fileName string 399 suffix string 400 }{ 401 f, 402 "", 403 } 404 } 405} 406 407func downloadHandler(w http.ResponseWriter, r *http.Request) { 408 w.Header().Set("content-type", "text/json") 409 clearOverdueFile() 410 contentType := r.Header["Content-Type"] 411 if len(contentType) > 0 { 412 contentTypeName := contentType[0] 413 if strings.HasPrefix(contentTypeName, "application/x-www-form-urlencoded") { 414 url := r.PostFormValue("url") 415 res, err := get(url) 416 if err != nil { 417 resp(&w)(false, -1, err.Error(), nil) 418 return 419 } 420 pth := filepath.FromSlash(fmt.Sprintf("/upload/%s%s", time.Now().Format("20060102150405000"), getSuffixByUrl(url).suffix)) 421 MkDir("." + pth) 422 create, err := os.Create("." + pth) 423 if err != nil { 424 resp(&w)(false, -1, err.Error(), nil) 425 return 426 } 427 written, err := io.Copy(create, res.Body) 428 if err != nil { 429 resp(&w)(false, -1, err.Error(), nil) 430 return 431 } 432 fmt.Println(url, written) 433 pth = "/application" + pth 434 resp(&w)(true, 0, "success", map[string]interface{}{ 435 "url": pth, 436 "size": written, 437 }) 438 return 439 } 440 } 441 resp(&w)(false, -1, "请求方式错误", nil) 442} 443 444func SplitLines(s string) []string { 445 var lines []string 446 sc := bufio.NewScanner(strings.NewReader(s)) 447 for sc.Scan() { 448 lines = append(lines, sc.Text()) 449 } 450 return lines 451} 452 453func readFileFirstLine(path string) string { 454 file, err := os.Open(path) 455 if err != nil { 456 return "" 457 } 458 defer file.Close() 459 460 readFile := bufio.NewReader(file) 461 line, readErr := readFile.ReadString('\n') 462 if readErr != nil || io.EOF == err { 463 return "" 464 } 465 return line 466} 467 468func PathExists(path string) (bool, error) { 469 _, err := os.Stat(path) 470 if err == nil { 471 return true, nil 472 } 473 if os.IsNotExist(err) { 474 return false, nil 475 } 476 return false, err 477} 478 479func chekDir(path string) { 480 _, err := os.Stat(path) 481 if err != nil { 482 err := os.Mkdir(path, os.ModePerm) 483 if err != nil { 484 fmt.Printf("mkdir failed![%v]\n", err) 485 } else { 486 fmt.Printf("mkdir success!\n") 487 } 488 } 489} 490func CheckErr(err error) { 491 if err != nil { 492 log.Panicln(err) 493 } 494} 495 496func open(url string) error { 497 if isWindows() { 498 return openUrlWindows(url) 499 } else if isDarwin() { 500 return openUrlDarwin(url) 501 } else { 502 return openUrlOther(url) 503 } 504} 505 506func openUrlWindows(url string) error { 507 cmd := "cmd" 508 args := []string{"/c", "start", url} 509 return exec.Command(cmd, args...).Start() 510} 511func openUrlDarwin(url string) error { 512 var cmd = "open" 513 var args = []string{url} 514 return exec.Command(cmd, args...).Start() 515} 516func openUrlOther(url string) error { 517 var cmd = "xdg-open" 518 var args = []string{url} 519 return exec.Command(cmd, args...).Start() 520} 521 522func isWindows() bool { 523 return runtime.GOOS == "windows" 524} 525func isDarwin() bool { 526 return runtime.GOOS == "darwin" 527} 528 529func getCurrentAbPath() string { 530 dir := getExecutePath() 531 tmpDir, _ := filepath.EvalSymlinks(os.TempDir()) 532 if strings.Contains(dir, tmpDir) { 533 return getCallerPath() 534 } 535 return dir 536} 537 538func getCallerPath() string { 539 var pth string 540 _, fName, _, ok := runtime.Caller(0) 541 if ok { 542 pth = path.Dir(fName) 543 } 544 return pth 545} 546func getExecutePath() string { 547 pth, err := os.Executable() 548 if err != nil { 549 log.Fatal(err) 550 } 551 res, _ := filepath.EvalSymlinks(filepath.Dir(pth)) 552 return res 553} 554 555func checkPort(port int) { 556 if isWindows() { 557 pid := getPidByPort(port) 558 if pid != -1 { 559 res := exec.Command("cmd", "/c", fmt.Sprintf("taskkill /F /PID %d /T", pid)) 560 res.Run() 561 } 562 } 563} 564