github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/utils/api.go (about) 1 package utils 2 3 import ( 4 "crypto" 5 "crypto/rand" 6 "encoding/base64" 7 "fmt" 8 "html/template" 9 "net/http" 10 "net/url" 11 "path" 12 "strings" 13 14 "github.com/masterhung0112/hk_server/v5/model" 15 "github.com/masterhung0112/hk_server/v5/shared/i18n" 16 ) 17 18 func CheckOrigin(r *http.Request, allowedOrigins string) bool { 19 origin := r.Header.Get("Origin") 20 if origin == "" { 21 return true 22 } 23 24 if allowedOrigins == "*" { 25 return true 26 } 27 for _, allowed := range strings.Split(allowedOrigins, " ") { 28 if allowed == origin { 29 return true 30 } 31 } 32 return false 33 } 34 35 func OriginChecker(allowedOrigins string) func(*http.Request) bool { 36 return func(r *http.Request) bool { 37 return CheckOrigin(r, allowedOrigins) 38 } 39 } 40 41 func RenderWebAppError(config *model.Config, w http.ResponseWriter, r *http.Request, err *model.AppError, s crypto.Signer) { 42 RenderWebError(config, w, r, err.StatusCode, url.Values{ 43 "message": []string{err.Message}, 44 }, s) 45 } 46 47 func RenderWebError(config *model.Config, w http.ResponseWriter, r *http.Request, status int, params url.Values, s crypto.Signer) { 48 queryString := params.Encode() 49 50 subpath, _ := GetSubpathFromConfig(config) 51 52 h := crypto.SHA256 53 sum := h.New() 54 sum.Write([]byte(path.Join(subpath, "error") + "?" + queryString)) 55 signature, err := s.Sign(rand.Reader, sum.Sum(nil), h) 56 if err != nil { 57 http.Error(w, "", http.StatusInternalServerError) 58 return 59 } 60 destination := path.Join(subpath, "error") + "?" + queryString + "&s=" + base64.URLEncoding.EncodeToString(signature) 61 62 if status >= 300 && status < 400 { 63 http.Redirect(w, r, destination, status) 64 return 65 } 66 67 w.Header().Set("Content-Type", "text/html") 68 w.WriteHeader(status) 69 fmt.Fprintln(w, `<!DOCTYPE html><html><head></head>`) 70 fmt.Fprintln(w, `<body onload="window.location = '`+template.HTMLEscapeString(template.JSEscapeString(destination))+`'">`) 71 fmt.Fprintln(w, `<noscript><meta http-equiv="refresh" content="0; url=`+template.HTMLEscapeString(destination)+`"></noscript>`) 72 fmt.Fprintln(w, `<!-- web error message -->`) 73 fmt.Fprintln(w, `<a href="`+template.HTMLEscapeString(destination)+`" style="color: #c0c0c0;">...</a>`) 74 fmt.Fprintln(w, `</body></html>`) 75 } 76 77 func RenderMobileAuthComplete(w http.ResponseWriter, redirectURL string) { 78 var link = template.HTMLEscapeString(redirectURL) 79 RenderMobileMessage(w, ` 80 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="width: 64px; height: 64px; fill: #3c763d"> 81 <!-- Font Awesome Free 5.15.3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --> 82 <path stroke="green" d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z"/> 83 </svg> 84 <h2> `+i18n.T("api.oauth.auth_complete")+` </h2> 85 <p id="redirecting-message"> `+i18n.T("api.oauth.redirecting_back")+` </p> 86 <p id="close-tab-message" style="display: none"> `+i18n.T("api.oauth.close_browser")+` </p> 87 <p> `+i18n.T("api.oauth.click_redirect", model.StringInterface{"Link": link})+` </p> 88 <meta http-equiv="refresh" content="2; url=`+link+`"> 89 <script> 90 window.onload = function() { 91 setTimeout(function() { 92 document.getElementById('redirecting-message').style.display = 'none'; 93 document.getElementById('close-tab-message').style.display = 'block'; 94 }, 2000); 95 } 96 </script> 97 `) 98 } 99 100 func RenderMobileError(config *model.Config, w http.ResponseWriter, err *model.AppError, redirectURL string) { 101 var link = redirectURL 102 var invalidSchemes = map[string]bool{ 103 "data": true, 104 "javascript": true, 105 "vbscript": true, 106 } 107 u, redirectErr := url.Parse(redirectURL) 108 if redirectErr != nil || invalidSchemes[u.Scheme] { 109 link = *config.ServiceSettings.SiteURL 110 } 111 RenderMobileMessage(w, ` 112 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" style="width: 64px; height: 64px; fill: #ccc"> 113 <!-- Font Awesome Free 5.15.3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --> 114 <path d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"/> 115 </svg> 116 <h2> `+i18n.T("error")+` </h2> 117 <p> `+err.Message+` </p> 118 <a href="`+link+`"> 119 `+i18n.T("api.back_to_app", map[string]interface{}{"SiteName": config.TeamSettings.SiteName})+` 120 </a> 121 `) 122 } 123 124 func RenderMobileMessage(w http.ResponseWriter, message string) { 125 w.Header().Set("Content-Type", "text/html") 126 fmt.Fprintln(w, ` 127 <!DOCTYPE html> 128 <html> 129 <head> 130 <meta charset="utf-8"> 131 <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, user-scalable=yes, viewport-fit=cover"> 132 <style> 133 body { 134 color: #333; 135 background-color: #fff; 136 font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; 137 font-size: 14px; 138 line-height: 1.42857143; 139 } 140 a { 141 color: #337ab7; 142 text-decoration: none; 143 } 144 a:focus, a:hover { 145 color: #23527c; 146 text-decoration: underline; 147 } 148 h2 { 149 font-size: 30px; 150 margin: 20px 0 10px 0; 151 font-weight: 500; 152 line-height: 1.1 153 } 154 p { 155 margin: 0 0 10px; 156 } 157 .message-container { 158 color: #555; 159 display: table-cell; 160 padding: 5em 0; 161 text-align: left; 162 vertical-align: top; 163 } 164 </style> 165 </head> 166 <body> 167 <!-- mobile app message --> 168 <div class="message-container"> 169 `+message+` 170 </div> 171 </body> 172 </html> 173 `) 174 }