• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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