github.com/aldelo/common@v1.5.1/wrapper/gin/ginhelper.go (about)

     1  package gin
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	util "github.com/aldelo/common"
     7  	"github.com/aldelo/common/rest"
     8  	"github.com/gin-gonic/gin"
     9  )
    10  
    11  // ResponseBodyWriterInterceptor struct contains response body writer interceptor
    12  type ResponseBodyWriterInterceptor struct {
    13  	gin.ResponseWriter
    14  	RespBody *bytes.Buffer
    15  }
    16  
    17  func (r ResponseBodyWriterInterceptor) Write(b []byte) (int, error) {
    18  	r.RespBody.Write(b)
    19  	return r.ResponseWriter.Write(b)
    20  }
    21  
    22  func (r ResponseBodyWriterInterceptor) WriteString(s string) (int, error) {
    23  	r.RespBody.WriteString(s)
    24  	return r.ResponseWriter.WriteString(s)
    25  }
    26  
    27  // ReCAPTCHAResponseIFace interface
    28  type ReCAPTCHAResponseIFace interface {
    29  	GetReCAPTCHAResponse() string
    30  }
    31  
    32  // BindPostDataFailed will return a 412 response to caller via gin context
    33  func BindPostDataFailed(c *gin.Context) {
    34  	if c != nil {
    35  		c.String(412, func() string{
    36  			rawBody, _ := c.GetRawData()
    37  			return fmt.Sprintf(`{"errortype":"bind-post-data","error":"%s"}`, "Bind Post Data to Struct Failed: " + string(rawBody))
    38  		}())
    39  	}
    40  }
    41  
    42  // VerifyGoogleReCAPTCHAv2Failed will return a 412 response to caller via gin context
    43  func VerifyGoogleReCAPTCHAv2Failed(c *gin.Context, errInfo string) {
    44  	if c != nil {
    45  		c.String(412, func() string{
    46  			return fmt.Sprintf(`{"errortype":"verify-google-recaptcha-v2","error":"%s"}`, errInfo)
    47  		}())
    48  	}
    49  }
    50  
    51  // MarshalQueryParametersFailed will return a 412 response to caller via gin context
    52  func MarshalQueryParametersFailed(c *gin.Context, errInfo string) {
    53  	if c != nil {
    54  		c.String(412, func() string{
    55  			return fmt.Sprintf(`{"errortype":"marshal-query-parameters","error":"%s"}`, errInfo)
    56  		}())
    57  	}
    58  }
    59  
    60  // ActionServerFailed will return a 500 response to caller via gin context
    61  func ActionServerFailed(c *gin.Context, errInfo string) {
    62  	if c != nil {
    63  		c.String(500, func() string{
    64  			return fmt.Sprintf(`{"errortype":"action-server-failed","error":"%s"}`, errInfo)
    65  		}())
    66  	}
    67  }
    68  
    69  // ActionStatusNotOK will return a 404 response to caller via gin context
    70  func ActionStatusNotOK(c *gin.Context, errInfo string) {
    71  	if c != nil {
    72  		c.String(404, func() string{
    73  			return fmt.Sprintf(`{"errortype":"action-status-not-ok","error":"%s"}`, errInfo)
    74  		}())
    75  	}
    76  }
    77  
    78  // VerifyGoogleReCAPTCHAv2 is a helper for use gin web server,
    79  // it will verify the given recaptcha response with the recaptcha secret pass in from gin context,
    80  // and if verify successful, nil is returned
    81  func VerifyGoogleReCAPTCHAv2(c *gin.Context, recaptchaResponse string, recaptchaRequired bool) (err error) {
    82  	if c == nil {
    83  		return fmt.Errorf("Verify Google ReCAPTCHA v2 Requires GIN Context")
    84  	}
    85  
    86  	if !recaptchaRequired {
    87  		if util.LenTrim(recaptchaResponse) == 0 {
    88  			return nil
    89  		}
    90  	} else {
    91  		if util.LenTrim(recaptchaResponse) == 0 {
    92  			return fmt.Errorf("Google ReCAPTCHA v2 Verification is Required")
    93  		}
    94  	}
    95  
    96  	if key, ok := c.Get("google_recaptcha_secret"); ok {
    97  		if success, _, _, e := util.VerifyGoogleReCAPTCHAv2(recaptchaResponse, key.(string)); e != nil {
    98  			return e
    99  		} else {
   100  			if success {
   101  				return nil
   102  			} else {
   103  				return fmt.Errorf("Verify Google ReCAPTCHA v2 Result = Not Successful")
   104  			}
   105  		}
   106  	} else {
   107  		return nil
   108  	}
   109  }
   110  
   111  // HandleReCAPTCHAv2 is a helper to simplify handler prep code to bind and perform recaptcha service,
   112  // if false is returned, response is given to caller as failure, further processing stops
   113  // if true is returned, continue with handler code
   114  func HandleReCAPTCHAv2(c *gin.Context, bindingInputPtr interface{}) bool {
   115  	if c == nil {
   116  		return false
   117  	}
   118  
   119  	if bindingInputPtr == nil {
   120  		return false
   121  	}
   122  
   123  	if r, ok := bindingInputPtr.(ReCAPTCHAResponseIFace); !ok {
   124  		BindPostDataFailed(c)
   125  		return false
   126  	} else {
   127  		if e := VerifyGoogleReCAPTCHAv2(c, r.GetReCAPTCHAResponse(), true); e != nil {
   128  			VerifyGoogleReCAPTCHAv2Failed(c, e.Error())
   129  			return false
   130  		} else {
   131  			// recaptcha verify success
   132  			return true
   133  		}
   134  	}
   135  }
   136  
   137  // PostDataToHost will post data from struct pointer object via gin context to target host,
   138  // the tagName and excludeTagName is used for query parameters marshaling
   139  func PostDataToHost(c *gin.Context, structPtr interface{}, tagName string, excludeTagName string, postUrl string) {
   140  	if c != nil {
   141  		if structPtr == nil {
   142  			MarshalQueryParametersFailed(c, "Post Data Struct is Nil")
   143  		} else if util.LenTrim(postUrl) == 0 {
   144  			MarshalQueryParametersFailed(c, "Post Target URL is Required")
   145  		} else {
   146  			if util.LenTrim(tagName) == 0 {
   147  				tagName = "json"
   148  			}
   149  
   150  			if qp, e := util.MarshalStructToQueryParams(structPtr, tagName, excludeTagName); e != nil {
   151  				MarshalQueryParametersFailed(c, e.Error())
   152  			} else {
   153  				if status, resp, e := rest.POST(postUrl, nil, qp); e != nil {
   154  					ActionServerFailed(c, e.Error())
   155  				} else if status != 200 {
   156  					ActionStatusNotOK(c, resp)
   157  				} else {
   158  					// success
   159  					c.String(200, resp)
   160  				}
   161  			}
   162  		}
   163  	}
   164  }