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  }