rest.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. package api
  2. import (
  3. "fmt"
  4. "net/http"
  5. "strings"
  6. "github.com/asaskevich/govalidator"
  7. "github.com/cad/ovpm/api/pb"
  8. "github.com/cad/ovpm/bundle"
  9. assetfs "github.com/elazarl/go-bindata-assetfs"
  10. "github.com/go-openapi/runtime/middleware"
  11. "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
  12. "github.com/sirupsen/logrus"
  13. "golang.org/x/net/context"
  14. "google.golang.org/grpc"
  15. )
  16. // NewRESTServer returns a new REST server.
  17. func NewRESTServer(grpcPort string) (http.Handler, context.CancelFunc, error) {
  18. mux := http.NewServeMux()
  19. ctx := context.Background()
  20. ctx, cancel := context.WithCancel(ctx)
  21. if !govalidator.IsNumeric(grpcPort) {
  22. return nil, cancel, fmt.Errorf("grpcPort should be numeric")
  23. }
  24. endPoint := fmt.Sprintf("localhost:%s", grpcPort)
  25. ctx = NewOriginTypeContext(ctx, OriginTypeREST)
  26. gmux := runtime.NewServeMux(runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{}))
  27. opts := []grpc.DialOption{grpc.WithInsecure()}
  28. err := pb.RegisterVPNServiceHandlerFromEndpoint(ctx, gmux, endPoint, opts)
  29. if err != nil {
  30. return nil, cancel, err
  31. }
  32. err = pb.RegisterUserServiceHandlerFromEndpoint(ctx, gmux, endPoint, opts)
  33. if err != nil {
  34. return nil, cancel, err
  35. }
  36. err = pb.RegisterNetworkServiceHandlerFromEndpoint(ctx, gmux, endPoint, opts)
  37. if err != nil {
  38. return nil, cancel, err
  39. }
  40. err = pb.RegisterAuthServiceHandlerFromEndpoint(ctx, gmux, endPoint, opts)
  41. if err != nil {
  42. return nil, cancel, err
  43. }
  44. mux.HandleFunc("/api/specs/", specsHandler)
  45. mware := middleware.Redoc(middleware.RedocOpts{
  46. BasePath: "/api/docs/",
  47. SpecURL: "/api/specs/user.swagger.json",
  48. Path: "user",
  49. }, gmux)
  50. mware = middleware.Redoc(middleware.RedocOpts{
  51. BasePath: "/api/docs/",
  52. SpecURL: "/api/specs/vpn.swagger.json",
  53. Path: "vpn",
  54. }, mware)
  55. mware = middleware.Redoc(middleware.RedocOpts{
  56. BasePath: "/api/docs/",
  57. SpecURL: "/api/specs/network.swagger.json",
  58. Path: "network",
  59. }, mware)
  60. mware = middleware.Redoc(middleware.RedocOpts{
  61. BasePath: "/api/docs/",
  62. SpecURL: "/api/specs/auth.swagger.json",
  63. Path: "auth",
  64. }, mware)
  65. mux.Handle("/api/", mware)
  66. mux.Handle("/", http.FileServer(
  67. &assetfs.AssetFS{Asset: bundle.Asset, AssetDir: bundle.AssetDir, Prefix: "bundle"}))
  68. return allowCORS(mux), cancel, nil
  69. }
  70. func specsHandler(w http.ResponseWriter, r *http.Request) {
  71. w.Header().Set("Content-Type", "application/json")
  72. switch r.URL.Path {
  73. case "/api/specs/user.swagger.json":
  74. userData, err := bundle.Asset("bundle/user.swagger.json")
  75. if err != nil {
  76. logrus.Warn(err)
  77. }
  78. w.Write(userData)
  79. case "/api/specs/network.swagger.json":
  80. networkData, err := bundle.Asset("bundle/network.swagger.json")
  81. if err != nil {
  82. logrus.Warn(err)
  83. }
  84. w.Write(networkData)
  85. case "/api/specs/vpn.swagger.json":
  86. vpnData, err := bundle.Asset("bundle/vpn.swagger.json")
  87. if err != nil {
  88. logrus.Warn(err)
  89. }
  90. w.Write(vpnData)
  91. case "/api/specs/auth.swagger.json":
  92. vpnData, err := bundle.Asset("bundle/auth.swagger.json")
  93. if err != nil {
  94. logrus.Warn(err)
  95. }
  96. w.Write(vpnData)
  97. }
  98. }
  99. func webuiHandler(w http.ResponseWriter, r *http.Request) {
  100. switch r.URL.Path {
  101. case "/bundle.js":
  102. userData, err := bundle.Asset("bundle/bundle.js")
  103. if err != nil {
  104. logrus.Warn(err)
  105. }
  106. w.Header().Set("Content-Type", "application/javascript")
  107. w.Write(userData)
  108. case "/js/mui.min.js":
  109. userData, err := bundle.Asset("bundle/js/mui.min.js")
  110. if err != nil {
  111. logrus.Warn(err)
  112. }
  113. w.Header().Set("Content-Type", "application/javascript")
  114. w.Write(userData)
  115. case "/css/bootstrap.min.css":
  116. userData, err := bundle.Asset("bundle/css/bootstrap.min.css")
  117. if err != nil {
  118. logrus.Warn(err)
  119. }
  120. w.Header().Set("Content-Type", "text/css")
  121. w.Write(userData)
  122. case "/css/mui.min.css":
  123. userData, err := bundle.Asset("bundle/css/mui.min.css")
  124. if err != nil {
  125. logrus.Warn(err)
  126. }
  127. w.Header().Set("Content-Type", "text/css")
  128. w.Write(userData)
  129. case "/fonts/glyphicons-halflings-regular.woff":
  130. userData, err := bundle.Asset("bundle/glyphicons-halflings-regular.woff")
  131. if err != nil {
  132. logrus.Warn(err)
  133. }
  134. w.Header().Set("Content-Type", "application/font-woff")
  135. w.Write(userData)
  136. default:
  137. networkData, err := bundle.Asset("bundle/index.html")
  138. if err != nil {
  139. logrus.Warn(err)
  140. }
  141. w.Write(networkData)
  142. }
  143. }
  144. func preflightHandler(w http.ResponseWriter, r *http.Request) {
  145. headers := []string{"Content-Type", "Accept", "Authorization"}
  146. w.Header().Set("Access-Control-Allow-Headers", strings.Join(headers, ","))
  147. methods := []string{"GET", "HEAD", "POST", "PUT", "DELETE"}
  148. w.Header().Set("Access-Control-Allow-Methods", strings.Join(methods, ","))
  149. w.Header().Set("Access-Control-Expose-Headers", "Access-Control-Allow-Origin")
  150. logrus.Debugf("rest: preflight request for %s", r.URL.Path)
  151. return
  152. }
  153. func allowCORS(h http.Handler) http.Handler {
  154. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  155. if origin := r.Header.Get("Origin"); origin != "" {
  156. w.Header().Set("Access-Control-Allow-Origin", origin)
  157. if r.Method == "OPTIONS" && r.Header.Get("Access-Control-Request-Method") != "" {
  158. preflightHandler(w, r)
  159. return
  160. }
  161. }
  162. h.ServeHTTP(w, r)
  163. })
  164. }