531 lines
14 KiB
Go
531 lines
14 KiB
Go
package main
|
|
|
|
import (
|
|
"APIServer/cnf"
|
|
"APIServer/ews"
|
|
"encoding/json"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
_ "net/http/pprof"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"text/template"
|
|
"time"
|
|
|
|
"github.com/chai2010/winsvc"
|
|
_ "github.com/go-sql-driver/mysql"
|
|
"github.com/natefinch/lumberjack"
|
|
uuid "github.com/satori/go.uuid"
|
|
yaml "gopkg.in/yaml.v2"
|
|
)
|
|
|
|
var cfg = cnf.Cfg{}
|
|
var svc string = "apisvr"
|
|
var vsn bool = false
|
|
var ver string = ""
|
|
var logger *log.Logger
|
|
var flagIns bool = false
|
|
var flagRmv bool = false
|
|
var flagRun bool = false
|
|
var flagTer bool = false
|
|
var flagRst bool = false
|
|
|
|
func init() {
|
|
flag.BoolVar(&flagIns, "i", false, "Install Service")
|
|
flag.BoolVar(&flagRmv, "u", false, "Uninstall Service")
|
|
flag.BoolVar(&flagRun, "s", false, "Start Service")
|
|
flag.BoolVar(&flagTer, "t", false, "Stop Service")
|
|
flag.BoolVar(&flagRst, "r", false, "Restart Service")
|
|
flag.BoolVar(&vsn, "v", false, "Show Program Version")
|
|
flag.Parse()
|
|
|
|
logger = log.New(&lumberjack.Logger{
|
|
Filename: strings.TrimSuffix(os.Args[0], ".exe") + ".log",
|
|
MaxAge: 30,
|
|
MaxSize: 10,
|
|
MaxBackups: 100,
|
|
LocalTime: true,
|
|
}, "", log.Ldate|log.Ltime|log.Lmicroseconds)
|
|
}
|
|
|
|
func main() {
|
|
if vsn {
|
|
showVersion()
|
|
os.Exit(0)
|
|
}
|
|
|
|
self := strings.TrimSuffix(os.Args[0], ".exe")
|
|
file := self + ".yml"
|
|
src, err := os.ReadFile(file)
|
|
if err != nil {
|
|
log.Printf("[ERR] %s\r\n", err.Error())
|
|
logger.Printf("[ERR] %s\r\n", err.Error())
|
|
os.Exit(1)
|
|
}
|
|
err = yaml.Unmarshal(src, &cfg)
|
|
if err != nil {
|
|
log.Printf("[ERR] %s\r\n", err.Error())
|
|
logger.Printf("[ERR] %s\r\n", err.Error())
|
|
os.Exit(1)
|
|
}
|
|
|
|
cwd, err := winsvc.GetAppPath()
|
|
if err != nil {
|
|
log.Printf("[ERR] %s\r\n", err.Error())
|
|
logger.Printf("[ERR] %s\r\n", err.Error())
|
|
os.Exit(1)
|
|
}
|
|
err = os.Chdir(filepath.Dir(cwd))
|
|
if err != nil {
|
|
log.Printf("[ERR] %s\r\n", err.Error())
|
|
logger.Printf("[ERR] %s\r\n", err.Error())
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Install Service
|
|
if flagIns {
|
|
err := winsvc.InstallService(cwd, svc, "API Server")
|
|
if err != nil {
|
|
log.Printf("[ERR] Install Service Failed: %s\r\n", err.Error())
|
|
logger.Printf("[ERR] Install Service Failed: %s\r\n", err.Error())
|
|
os.Exit(1)
|
|
}
|
|
log.Printf("[MSG] Install Service Successfully.\r\n")
|
|
logger.Printf("[MSG] Install Service Successfully.\r\n")
|
|
return
|
|
}
|
|
|
|
// Uninstall Service
|
|
if flagRmv {
|
|
err := winsvc.RemoveService(svc)
|
|
if err != nil {
|
|
log.Printf("[ERR] Uninstall Service Failed: %s\r\n", err.Error())
|
|
logger.Printf("[ERR] Uninstall Service Failed: %s\r\n", err.Error())
|
|
os.Exit(1)
|
|
}
|
|
log.Printf("[MSG] Uninstall Service Successfully.\r\n")
|
|
logger.Printf("[MSG] Uninstall Service Successfully.\r\n")
|
|
return
|
|
}
|
|
|
|
// Start Service
|
|
if flagRun {
|
|
err := winsvc.StartService(svc)
|
|
if err != nil {
|
|
log.Printf("[ERR] Start Service Failed: %s\r\n", err.Error())
|
|
logger.Printf("[ERR] Start Service Failed: %s\r\n", err.Error())
|
|
os.Exit(1)
|
|
}
|
|
log.Printf("[MSG] Service Started.\r\n")
|
|
logger.Printf("[MSG] Service Started.\r\n")
|
|
return
|
|
}
|
|
|
|
// Stop Service
|
|
if flagTer {
|
|
err := winsvc.StopService(svc)
|
|
if err != nil {
|
|
log.Printf("[ERR] Stop Service Failed: %s\r\n", err.Error())
|
|
logger.Printf("[ERR] Stop Service Failed: %s\r\n", err.Error())
|
|
os.Exit(1)
|
|
}
|
|
log.Printf("[MSG] Service Stop.\r\n")
|
|
logger.Printf("[MSG] Service Stop.\r\n")
|
|
return
|
|
}
|
|
|
|
// Restart Service
|
|
if flagRst {
|
|
err := winsvc.StopService(svc)
|
|
if err != nil {
|
|
log.Printf("[ERR] Stop Service Failed: %s\r\n", err.Error())
|
|
logger.Printf("[ERR] Stop Service Failed: %s\r\n", err.Error())
|
|
os.Exit(1)
|
|
}
|
|
log.Printf("[MSG] Service Stop.\r\n")
|
|
logger.Printf("[MSG] Service Stop.\r\n")
|
|
|
|
time.Sleep(time.Second * 1)
|
|
err = winsvc.StartService(svc)
|
|
if err != nil {
|
|
log.Printf("[ERR] Start Service Failed: %s\r\n", err.Error())
|
|
logger.Printf("[ERR] Start Service Failed: %s\r\n", err.Error())
|
|
os.Exit(1)
|
|
}
|
|
log.Printf("[MSG] Service Started.\r\n")
|
|
logger.Printf("[MSG] Service Started.\r\n")
|
|
return
|
|
}
|
|
|
|
if !winsvc.InServiceMode() {
|
|
err := winsvc.RunAsService(svc, startSvc, stopSvc, false)
|
|
if err != nil {
|
|
log.Printf("[ERR] Run As Service Failed: %s\r\n", err.Error())
|
|
logger.Printf("[ERR] Run As Service Failed: %s\r\n", err.Error())
|
|
os.Exit(1)
|
|
}
|
|
log.Printf("[MSG] Run As Service ...\r\n")
|
|
logger.Printf("[MSG] Run As Service ...\r\n")
|
|
}
|
|
}
|
|
|
|
func startSvc() {
|
|
log.Printf("[MSG] Starting Service ...\r\n")
|
|
logger.Printf("[MSG] Starting Service ...\r\n")
|
|
http.HandleFunc("/", handleIndex)
|
|
http.HandleFunc("/request/", handleRequest)
|
|
http.HandleFunc("/fileinfo/", handleFileInfo)
|
|
http.HandleFunc("/setuutinfo/", handleSetUutInfo)
|
|
http.HandleFunc("/getuutinfo/", handleGetUutInfo)
|
|
logger.Printf("[MSG] Starting HTTP Server On Port: %s\r\n", cfg.Settings.ListenPort)
|
|
err := http.ListenAndServe(":"+cfg.Settings.ListenPort, nil)
|
|
if err != nil {
|
|
logger.Printf("%s\r\n", err.Error())
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func stopSvc() {
|
|
log.Printf("[MSG] Stopping Service ...\r\n")
|
|
logger.Printf("[MSG] Stopping Service ...\r\n")
|
|
os.Exit(0)
|
|
}
|
|
|
|
func handleIndex(w http.ResponseWriter, r *http.Request) {
|
|
defer r.Body.Close()
|
|
if r.RequestURI == "/favicon.ico" {
|
|
return
|
|
}
|
|
if r.Method != http.MethodGet {
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
fmt.Fprintf(w, "MethodNotAllowed: %v\r\n", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
tpl, err := template.ParseFiles("./Index.html")
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
fmt.Fprintf(w, "ErrMsg: %v\r\n", err)
|
|
return
|
|
}
|
|
err = tpl.Execute(w, nil)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
fmt.Fprintf(w, "ErrMsg: %v\r\n", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func handleRequest(w http.ResponseWriter, r *http.Request) {
|
|
defer r.Body.Close()
|
|
if r.RequestURI == "/favicon.ico" {
|
|
return
|
|
}
|
|
if r.Method != http.MethodPost {
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
fmt.Fprintf(w, "MethodNotAllowed: %v\r\n", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
reqID := uuid.NewV4().String()
|
|
logger.Printf("RequestID: %s; Addr: %s; URI: %s\r\n", reqID, r.RemoteAddr, r.RequestURI)
|
|
|
|
if err := r.ParseForm(); err != nil {
|
|
logger.Printf("RequestID: %s; ErrMsg: %s\r\n", reqID, err.Error())
|
|
return
|
|
}
|
|
|
|
var params []string
|
|
if len(r.Form) > 0 {
|
|
logger.Printf("RequestID: %s; Form: %#v\r\n", reqID, r.Form)
|
|
for k, v := range r.Form {
|
|
if cfg.Settings.ParamCheck {
|
|
if !chkParams(k) {
|
|
continue
|
|
}
|
|
if !chkParams(v[0]) {
|
|
continue
|
|
}
|
|
}
|
|
params = append(params, fmt.Sprintf("%s:%s", k, strings.ReplaceAll(v[0], " ", "_")))
|
|
}
|
|
}
|
|
|
|
logger.Printf("RequestID: %s; Params: %#v\r\n", reqID, params)
|
|
resp := runCommand(cfg.Settings.HookScript, params, reqID)
|
|
fmt.Fprintf(w, "%s\r\n", resp)
|
|
}
|
|
|
|
func handleFileInfo(w http.ResponseWriter, r *http.Request) {
|
|
defer r.Body.Close()
|
|
if r.RequestURI == "/favicon.ico" {
|
|
return
|
|
}
|
|
|
|
reqID := uuid.NewV4().String()
|
|
logger.Printf("RequestID: %s; Addr: %s; URI: %s\r\n", reqID, r.RemoteAddr, r.RequestURI)
|
|
|
|
if err := r.ParseForm(); err != nil {
|
|
logger.Printf("RequestID: %s; ErrMsg: %s\r\n", reqID, err.Error())
|
|
return
|
|
}
|
|
|
|
var path string = ""
|
|
if len(r.Form) > 0 {
|
|
for k, v := range r.Form {
|
|
if cfg.Settings.ParamCheck {
|
|
if !chkParams(k) {
|
|
continue
|
|
}
|
|
if !chkParams(v[0]) {
|
|
continue
|
|
}
|
|
}
|
|
if k == "path" {
|
|
path = v[0]
|
|
}
|
|
}
|
|
}
|
|
|
|
if path == "" {
|
|
fmt.Fprintf(w, "%v", http.StatusBadRequest)
|
|
return
|
|
}
|
|
_, err := os.Stat(path)
|
|
if err != nil {
|
|
fmt.Fprintf(w, "%v", http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
type FileInfo struct {
|
|
FileName string `json:"FileName"`
|
|
FileSize int64 `json:"FileSize"`
|
|
LastModified string `json:"LastModified"`
|
|
//MD5Hash string `json:"MD5Hash"`
|
|
}
|
|
type FileList struct {
|
|
FileList []FileInfo `json:"FileList"`
|
|
}
|
|
|
|
var infoList []FileInfo
|
|
err = filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
|
|
if !info.IsDir() {
|
|
var fileInfo FileInfo
|
|
fileInfo.FileName = info.Name()
|
|
fileInfo.FileSize = info.Size()
|
|
fileInfo.LastModified = info.ModTime().Format("2006-01-02 15:04:05")
|
|
//fileInfo.MD5Hash = fileMD5(path)
|
|
infoList = append(infoList, fileInfo)
|
|
}
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
fmt.Fprintf(w, "%s", err.Error())
|
|
return
|
|
}
|
|
|
|
fileList := FileList{infoList}
|
|
jsonObj, err := json.MarshalIndent(fileList, "", " ")
|
|
if err != nil {
|
|
fmt.Fprintf(w, "%s", err.Error())
|
|
return
|
|
}
|
|
fmt.Fprintf(w, "%s", string(jsonObj))
|
|
}
|
|
|
|
func handleSetUutInfo(w http.ResponseWriter, r *http.Request) {
|
|
defer r.Body.Close()
|
|
if r.RequestURI == "/favicon.ico" {
|
|
return
|
|
}
|
|
|
|
var err error
|
|
host := ""
|
|
if cfg.Settings.HostMode == 0 {
|
|
host = strings.Split(r.Host, ":")[0]
|
|
}
|
|
if cfg.Settings.HostMode == 1 {
|
|
host, err = os.Hostname()
|
|
if err != nil {
|
|
host = "hostname"
|
|
}
|
|
}
|
|
|
|
addr := strings.Split(r.RemoteAddr, ":")[0]
|
|
uri := r.RequestURI
|
|
rst := map[string]string{"RESULT": ""}
|
|
|
|
if r.Method != http.MethodPost {
|
|
rst["RESULT"] = "NG"
|
|
rst["ErrMsg"] = fmt.Sprintf("MethodNotAllowed: %v", http.StatusMethodNotAllowed)
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
fmt.Fprintf(w, "%v", strings.ReplaceAll(fmt.Sprintf("%#v", rst), "map[string]string", ""))
|
|
return
|
|
}
|
|
|
|
params, err := parseReqParams(r)
|
|
if err != nil {
|
|
logger.Printf("[ERR] %s; %s; %#v; %s\r\n", r.RemoteAddr, r.RequestURI, params, rst["ErrMsg"])
|
|
rst["RESULT"] = "NG"
|
|
rst["ErrMsg"] = err.Error()
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
fmt.Fprintf(w, "%v", strings.ReplaceAll(fmt.Sprintf("%#v", rst), "map[string]string", ""))
|
|
return
|
|
}
|
|
|
|
if cfg.Settings.LogRequest {
|
|
logger.Printf("[MSG] %s; %s; Request: %#v\r\n", addr, uri, params)
|
|
}
|
|
ews := new(ews.EWS)
|
|
rst = ews.SetUutInfo(cfg, logger, host, addr, uri, params)
|
|
if cfg.Settings.LogResponse {
|
|
logger.Printf("[MSG] %s; %s; Response: %#v\r\n", addr, uri, rst)
|
|
}
|
|
|
|
if rst["RESULT"] != "OK" {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
} else {
|
|
w.WriteHeader(http.StatusOK)
|
|
}
|
|
fmt.Fprintf(w, "%v", strings.ReplaceAll(fmt.Sprintf("%#v", rst), "map[string]string", ""))
|
|
}
|
|
|
|
func handleGetUutInfo(w http.ResponseWriter, r *http.Request) {
|
|
defer r.Body.Close()
|
|
if r.RequestURI == "/favicon.ico" {
|
|
return
|
|
}
|
|
host := strings.Split(r.Host, ":")[0]
|
|
addr := strings.Split(r.RemoteAddr, ":")[0]
|
|
uri := r.RequestURI
|
|
rst := map[string]string{"RESULT": ""}
|
|
|
|
if err := r.ParseForm(); err != nil {
|
|
logger.Printf("[ERR] %s; %s; %s\r\n", r.RemoteAddr, r.RequestURI, err.Error())
|
|
rst["RESULT"] = "NG"
|
|
rst["ErrMsg"] = err.Error()
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
fmt.Fprintf(w, "%v", strings.ReplaceAll(fmt.Sprintf("%#v", rst), "map[string]string", ""))
|
|
return
|
|
}
|
|
|
|
params, err := parseReqParams(r)
|
|
if err != nil {
|
|
logger.Printf("[ERR] %s; %s; %#v; %s\r\n", r.RemoteAddr, r.RequestURI, params, rst["ErrMsg"])
|
|
rst["RESULT"] = "NG"
|
|
rst["ErrMsg"] = err.Error()
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
fmt.Fprintf(w, "%v", strings.ReplaceAll(fmt.Sprintf("%#v", rst), "map[string]string", ""))
|
|
return
|
|
}
|
|
|
|
if cfg.Settings.LogRequest {
|
|
logger.Printf("[MSG] %s; %s; Request: %#v\r\n", addr, uri, params)
|
|
}
|
|
ews := new(ews.EWS)
|
|
|
|
switch params["ACTION"] {
|
|
case "QueryByFilter":
|
|
rst = ews.GetUutInfo(cfg, logger, host, addr, uri, params)
|
|
case "GetIssueReport":
|
|
rst = ews.GetIssueReport(cfg, logger, host, addr, uri, params)
|
|
case "GetOfflineReport":
|
|
rst = ews.GetOfflineReport(cfg, logger, host, addr, uri, params)
|
|
default:
|
|
rst = ews.GetUutInfo(cfg, logger, host, addr, uri, params)
|
|
}
|
|
|
|
if cfg.Settings.LogResponse {
|
|
logger.Printf("[MSG] %s; %s; Response: Length=%d\r\n", addr, uri, len(rst["ErrMsg"]))
|
|
}
|
|
|
|
if rst["RESULT"] != "OK" {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
} else {
|
|
w.WriteHeader(http.StatusOK)
|
|
}
|
|
fmt.Fprintf(w, "%v", rst["ErrMsg"])
|
|
}
|
|
|
|
func parseReqParams(r *http.Request) (map[string]string, error) {
|
|
params := make(map[string]string, 0)
|
|
if err := r.ParseForm(); err != nil {
|
|
logger.Printf("[ERR] %s; %s; %s\r\n", r.RemoteAddr, r.RequestURI, err.Error())
|
|
return params, err
|
|
}
|
|
if len(r.Form) > 0 {
|
|
for k, v := range r.Form {
|
|
params[strings.ToUpper(strings.TrimSpace(k))] = strings.TrimSpace(v[0])
|
|
}
|
|
}
|
|
return params, nil
|
|
}
|
|
|
|
/* func fileMD5(filePath string) string {
|
|
file, err := os.Open(filePath)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
hash := md5.New()
|
|
_, err = io.Copy(hash, file)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return hex.EncodeToString(hash.Sum(nil))
|
|
} */
|
|
|
|
func chkParams(arg string) bool {
|
|
if strings.Contains(arg, ";") ||
|
|
strings.Contains(arg, "|") ||
|
|
strings.Contains(arg, "&") ||
|
|
strings.Contains(arg, ">") ||
|
|
strings.Contains(arg, "<") ||
|
|
strings.Contains(arg, "(") ||
|
|
strings.Contains(arg, ")") {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func runCommand(cmdStr string, argStr []string, requestID string) string {
|
|
cmd := exec.Command(cmdStr, argStr...)
|
|
if errors.Is(cmd.Err, exec.ErrDot) {
|
|
cmd.Err = nil
|
|
}
|
|
std, err := cmd.StdoutPipe()
|
|
if err != nil {
|
|
logger.Printf("RequestID: %s; ErrMsg: %s\r\n", requestID, err.Error())
|
|
return err.Error()
|
|
}
|
|
defer std.Close()
|
|
err = cmd.Start()
|
|
if err != nil {
|
|
logger.Printf("RequestID: %s; ErrMsg: %s\r\n", requestID, err.Error())
|
|
return err.Error()
|
|
}
|
|
ret, err := io.ReadAll(std)
|
|
if err != nil {
|
|
logger.Printf("RequestID: %s; ErrMsg: %s\r\n", requestID, err.Error())
|
|
return err.Error()
|
|
}
|
|
err = cmd.Wait()
|
|
if err != nil {
|
|
logger.Printf("RequestID: %s; ErrMsg: %s\r\n", requestID, err.Error())
|
|
return err.Error()
|
|
}
|
|
//fmt.Printf("\r\n%s\r\n\r\n", string(ret))
|
|
//logger.Printf("RequestID: %s; Result: \r\n%s\r\n\r\n", requestID, string(ret))
|
|
return string(ret)
|
|
}
|
|
|
|
func showVersion() {
|
|
fmt.Printf("%s\r\nVersion: %s\r\n", os.Args[0], ver)
|
|
}
|