diff --git a/go.mod b/go.mod index c551bc32287bae5c4f526057afe31e160ebe9414..cbc40c24a35bd2ad6e4c087cfdd85026337c97c7 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module gitee.com/openeuler/ci-bot go 1.13 require ( - gitee.com/openeuler/go-gitee v0.0.0-20191223095123-af9962c05d46 + gitee.com/openeuler/go-gitee v0.0.0-20200115002700-1146e2471f99 github.com/antihax/optional v1.0.0 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/protobuf v1.3.2 // indirect diff --git a/go.sum b/go.sum index 71d0311f41320698426e7b2a1b09656bf38341ed..b564f8e682c50c15c43a6e733c41eec851eb40a7 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ gitee.com/openeuler/go-gitee v0.0.0-20191209072105-b1105b99c89c h1:i23w7TchKv3Mg gitee.com/openeuler/go-gitee v0.0.0-20191209072105-b1105b99c89c/go.mod h1:TQrS/LP/DFXLqM+lVrZd4nL2pbTrqiXABGT9PJepVTA= gitee.com/openeuler/go-gitee v0.0.0-20191223095123-af9962c05d46 h1:BHOFDsWPs9Tv1S4AopiJSyNkgs+fdTFx3Kls6BCbxuE= gitee.com/openeuler/go-gitee v0.0.0-20191223095123-af9962c05d46/go.mod h1:TQrS/LP/DFXLqM+lVrZd4nL2pbTrqiXABGT9PJepVTA= +gitee.com/openeuler/go-gitee v0.0.0-20200115002700-1146e2471f99 h1:am2TQ4rlTbJG590UzpiuOZYwNVxIgy09VHhIwX5fWBc= +gitee.com/openeuler/go-gitee v0.0.0-20200115002700-1146e2471f99/go.mod h1:TQrS/LP/DFXLqM+lVrZd4nL2pbTrqiXABGT9PJepVTA= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= @@ -119,6 +121,7 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 h1:pE8b58s1HRDMi8RDc79m0HISf9D4TzseP40cEA6IGfs= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/pkg/cibot/clahandler.go b/pkg/cibot/clahandler.go index ca5b210e3dd738af54f97b2a3b093515bd334af7..de7e86a8ce253cb941fe3f99aec285fa6f9d4644 100644 --- a/pkg/cibot/clahandler.go +++ b/pkg/cibot/clahandler.go @@ -8,7 +8,9 @@ import ( "net/http" "gitee.com/openeuler/ci-bot/pkg/cibot/database" + "gitee.com/openeuler/go-gitee/gitee" "github.com/golang/glog" + "golang.org/x/oauth2" ) type CLAHandler struct { @@ -25,6 +27,10 @@ type CLARequest struct { Email *string `json:"email,omitempty"` Telephone *string `json:"telephone,omitempty"` Fax *string `json:"fax,omitempty"` + Code *string `json:"code,omitempty"` + Lang *string `json:"lang,omitempty"` + Client *string `json:"client,omitempty"` + AccessKey string `json:"-"` } type CLAResult struct { @@ -34,12 +40,15 @@ type CLAResult struct { } const ( - ErrorCode_OK = 0 - ErrorCode_ServerHandleError = 1 - ErrorCode_EmailError = 2 - ErrorCode_TelephoneError = 3 + ErrorCode_OK = iota + ErrorCode_ServerHandleError + ErrorCode_EmailError + ErrorCode_TelephoneError + ErrorCode_EmailNotTheSameError ) +const COOKIE_KEY string = "cla-info" + // ServeHTTP validates an incoming cla request. func (s *CLAHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { glog.Info("received a cla request") @@ -72,6 +81,13 @@ func (s *CLAHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } + cookie, err := r.Cookie(COOKIE_KEY) + if err == nil { + clarequest.AccessKey = cookie.Value + } else { + glog.Infof("Get cookie err: %v", err) + } + glog.Infof("cla request content: %v", clarequest) s.HandleRequest(w, clarequest) } else if r.Method == "OPTIONS" { @@ -111,6 +127,69 @@ func (s *CLAHandler) HandleResult(w http.ResponseWriter, r CLAResult) { // HandleRequest handles the cla request func (s *CLAHandler) HandleRequest(w http.ResponseWriter, request CLARequest) { // build model object + if *request.Code == "" || *request.Client == "" || *request.Lang == "" { + s.HandleResult(w, CLAResult{ + IsSuccess: false, + Description: fmt.Sprintf("request parameter error"), + ErrorCode: ErrorCode_ServerHandleError, + }) + return + } + + accesskey := request.AccessKey + + if accesskey == "" { + token, err := GetToken(*request.Code, *request.Client, *request.Lang) + + if err != nil { + s.HandleResult(w, CLAResult{ + IsSuccess: false, + Description: fmt.Sprintf("request gitee user error: %v", err), + ErrorCode: ErrorCode_ServerHandleError, + }) + return + } + accesskey = token.AccessToken + glog.Infof("access key get successfully.") + + } + + cookie := http.Cookie{Name: COOKIE_KEY, Value: accesskey, Path: "/", MaxAge: 86400} + http.SetCookie(w, &cookie) + + emails, err := GetEmails(accesskey) + if err != nil { + s.HandleResult(w, CLAResult{ + IsSuccess: false, + Description: fmt.Sprintf("request parameter error: %v", err), + ErrorCode: ErrorCode_ServerHandleError, + }) + return + } + + + primaryEmail := "" + + for _, email := range emails { + if email.State == "confirmed" { + for _, t := range email.Scope { + if t == "primary" { + primaryEmail = email.Email + break + } + } + } + } + + if primaryEmail == "" || primaryEmail != *request.Email { + s.HandleResult(w, CLAResult{ + IsSuccess: false, + Description: "The email is not the same as gitee account email.", + ErrorCode: ErrorCode_EmailNotTheSameError, + }) + return + } + cds := database.CLADetails{ Type: request.Type, } @@ -210,3 +289,40 @@ func (s *CLAHandler) HandleRequest(w http.ResponseWriter, request CLARequest) { ErrorCode: ErrorCode_OK, }) } + +func GetUser(ak string) (gitee.User, error) { + + ctx2 := context.Background() + ts := oauth2.StaticTokenSource( + &oauth2.Token{AccessToken: ak}, + ) + + // configuration + giteeConf := gitee.NewConfiguration() + giteeConf.HTTPClient = oauth2.NewClient(ctx2, ts) + + // git client + giteeClient := gitee.NewAPIClient(giteeConf) + + user, _, err := giteeClient.UsersApi.GetV5User(ctx2, nil) + return user, err +} + +func GetEmails(ak string) ([]gitee.Email, error) { + ctx2 := context.Background() + ts := oauth2.StaticTokenSource( + &oauth2.Token{AccessToken: ak}, + ) + + // configuration + giteeConf := gitee.NewConfiguration() + giteeConf.HTTPClient = oauth2.NewClient(ctx2, ts) + + // git client + giteeClient := gitee.NewAPIClient(giteeConf) + + emails, _, err := giteeClient.EmailsApi.GetV5Emails(ctx2, nil) + return emails, err + + +} diff --git a/pkg/cibot/oauth.go b/pkg/cibot/oauth.go new file mode 100644 index 0000000000000000000000000000000000000000..8dde7dfacd06cca488ac88068dedbb0e61cc8ab8 --- /dev/null +++ b/pkg/cibot/oauth.go @@ -0,0 +1,51 @@ +package cibot + +import ( + "context" + "fmt" + "os" + "strings" + + "golang.org/x/oauth2" +) + +func GetToken(code, client, lang string) (*oauth2.Token, error) { + + url := os.Getenv("WEBSITE_URL") + if url == "" { + url = "https://openeuler.org" + } + + secret := os.Getenv("GITEE_OAUTH2_SECRET_EN") + + if lang == "zh" { + secret = os.Getenv("GITEE_OAUTH2_SECRET_ZH") + } + + if !strings.HasSuffix(url, "/") { + url = fmt.Sprintf("%s/", url) + } + + redirect := fmt.Sprintf("%s%s/cla.html", strings.Trim(url, " "), strings.Trim(lang, " ")) + + ctx := context.Background() + config := Setup(client, redirect, secret) + + return config.Exchange(ctx, code) + +} + +var Endpoint = oauth2.Endpoint{ + AuthURL: "https://gitee.com/oauth/authorize", + TokenURL: "https://gitee.com/oauth/token", +} + +func Setup(client, redirect, secret string) *oauth2.Config { + return &oauth2.Config{ + ClientID: client, + ClientSecret: secret, + Scopes: []string{"emails", "user_info"}, + Endpoint: Endpoint, + RedirectURL: redirect, + } +} diff --git a/vendor/gitee.com/openeuler/go-gitee/gitee/api_emails.go b/vendor/gitee.com/openeuler/go-gitee/gitee/api_emails.go new file mode 100644 index 0000000000000000000000000000000000000000..57500fbf1716ceb84a9bc8a488246eba2493f1c5 --- /dev/null +++ b/vendor/gitee.com/openeuler/go-gitee/gitee/api_emails.go @@ -0,0 +1,123 @@ +/* + * 码云 Open API + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: 5.3.2 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package gitee + +import ( + "context" + "github.com/antihax/optional" + "io/ioutil" + "net/http" + "net/url" + "strings" +) + +// Linger please +var ( + _ context.Context +) + +type EmailsApiService service + +/* +EmailsApiService 获取授权用户的所有邮箱 +获取授权用户的所有邮箱 + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param optional nil or *GetV5EmailsOpts - Optional Parameters: + * @param "AccessToken" (optional.String) - 用户授权码 + +@return []Email +*/ + +type GetV5EmailsOpts struct { + AccessToken optional.String +} + +func (a *EmailsApiService) GetV5Emails(ctx context.Context, localVarOptionals *GetV5EmailsOpts) ([]Email, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue []Email + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/v5/emails" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if localVarOptionals != nil && localVarOptionals.AccessToken.IsSet() { + localVarQueryParams.Add("access_token", parameterToString(localVarOptionals.AccessToken.Value(), "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json", "multipart/form-data"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + + if localVarHttpResponse.StatusCode == 200 { + var v []Email + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} diff --git a/vendor/gitee.com/openeuler/go-gitee/gitee/client.go b/vendor/gitee.com/openeuler/go-gitee/gitee/client.go index d6584c9a6f3e66b6974a0df6044961d2792dcdf6..bf6510ca824e2515aa6029999c6868ddb8a40a39 100644 --- a/vendor/gitee.com/openeuler/go-gitee/gitee/client.go +++ b/vendor/gitee.com/openeuler/go-gitee/gitee/client.go @@ -47,6 +47,8 @@ type APIClient struct { ActivityApi *ActivityApiService + EmailsApi *EmailsApiService + EnterprisesApi *EnterprisesApiService GistsApi *GistsApiService @@ -91,6 +93,7 @@ func NewAPIClient(cfg *Configuration) *APIClient { // API Services c.ActivityApi = (*ActivityApiService)(&c.common) + c.EmailsApi = (*EmailsApiService)(&c.common) c.EnterprisesApi = (*EnterprisesApiService)(&c.common) c.GistsApi = (*GistsApiService)(&c.common) c.GitDataApi = (*GitDataApiService)(&c.common) diff --git a/vendor/gitee.com/openeuler/go-gitee/gitee/model_email.go b/vendor/gitee.com/openeuler/go-gitee/gitee/model_email.go new file mode 100644 index 0000000000000000000000000000000000000000..40de10db1c61a91258faa5d0c3d09a07d8ea4cae --- /dev/null +++ b/vendor/gitee.com/openeuler/go-gitee/gitee/model_email.go @@ -0,0 +1,17 @@ +/* + * 码云 Open API + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * API version: 5.3.2 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package gitee + +// 获取授权用户的邮件地址 +type Email struct { + Email string `json:"email,omitempty"` + State string `json:"state,omitempty"` + Scope []string `json:"scope,omitempty"` +} diff --git a/vendor/modules.txt b/vendor/modules.txt index d96474d38a1a272feaf11d39a57436ae9feae5e8..b566291c3bf9502caa8cdadb87d7ab93fc0f183d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,4 +1,4 @@ -# gitee.com/openeuler/go-gitee v0.0.0-20191223095123-af9962c05d46 +# gitee.com/openeuler/go-gitee v0.0.0-20200115002700-1146e2471f99 gitee.com/openeuler/go-gitee/gitee # github.com/antihax/optional v1.0.0 github.com/antihax/optional @@ -16,19 +16,19 @@ github.com/jinzhu/inflection # github.com/spf13/pflag v1.0.5 github.com/spf13/pflag # golang.org/x/net v0.0.0-20190923162816-aa69164e4478 -golang.org/x/net/context/ctxhttp golang.org/x/net/context +golang.org/x/net/context/ctxhttp # golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 golang.org/x/oauth2 golang.org/x/oauth2/internal # google.golang.org/appengine v1.6.3 -google.golang.org/appengine/urlfetch google.golang.org/appengine/cloudsql google.golang.org/appengine/internal -google.golang.org/appengine/internal/urlfetch google.golang.org/appengine/internal/base google.golang.org/appengine/internal/datastore google.golang.org/appengine/internal/log google.golang.org/appengine/internal/remote_api +google.golang.org/appengine/internal/urlfetch +google.golang.org/appengine/urlfetch # gopkg.in/yaml.v2 v2.2.2 gopkg.in/yaml.v2