package handlers import ( "encoding/json" "github.com/statping/statping/types/core" "github.com/statping/statping/types/errors" "github.com/statping/statping/utils" "golang.org/x/oauth2" "golang.org/x/oauth2/github" "net/http" "strings" "time" ) func githubOAuth(r *http.Request) (*oAuth, error) { auth := core.App.OAuth code := r.URL.Query().Get("code") config := &oauth2.Config{ ClientID: auth.GithubClientID, ClientSecret: auth.GithubClientSecret, Endpoint: github.Endpoint, RedirectURL: core.App.Domain + basePath + "oauth/github", } gg, err := config.Exchange(r.Context(), code) if err != nil { return nil, err } if !gg.Valid() { return nil, errors.New("oauth token is not valid") } user, err := returnGithubUser(gg.AccessToken) if err != nil { return nil, err } orgs, err := returnGithubOrganizations(gg.AccessToken, user.Login) if err != nil { return nil, err } if !validateGithub(user, orgs) { return nil, errors.New("github user is not allowed to login") } return &oAuth{ Token: gg, Username: strings.ToLower(user.Name), Email: strings.ToLower(user.Email), }, nil } func returnGithubUser(token string) (githubUser, error) { headers := []string{ "Accept=application/vnd.github.machine-man-preview+json", "Authorization=token " + token, } resp, _, err := utils.HttpRequest("https://api.github.com/user", "GET", nil, headers, nil, 10*time.Second, true, nil) if err != nil { return githubUser{}, err } var user githubUser if err := json.Unmarshal(resp, &user); err != nil { return githubUser{}, err } return user, nil } func returnGithubOrganizations(token, username string) ([]githubOrgs, error) { headers := []string{ "Accept=application/vnd.github.machine-man-preview+json", "Authorization=token " + token, } resp, _, err := utils.HttpRequest("https://api.github.com/users/"+username+"/orgs", "GET", nil, headers, nil, 10*time.Second, true, nil) if err != nil { return nil, err } var orgs []githubOrgs if err := json.Unmarshal(resp, &orgs); err != nil { return nil, err } return orgs, nil } func validateGithub(ghUser githubUser, orgs []githubOrgs) bool { auth := core.App.OAuth if auth.GithubUsers == "" && auth.GithubOrgs == "" { return true } if auth.GithubUsers != "" { users := strings.Split(auth.GithubUsers, ",") for _, u := range users { if strings.ToLower(ghUser.Login) == strings.ToLower(u) { return true } } } if auth.GithubOrgs != "" { orgsAllowed := strings.Split(auth.GithubOrgs, ",") for _, o := range orgsAllowed { for _, org := range orgs { if strings.ToLower(o) == strings.ToLower(org.Login) { return true } } } } return false } type githubOrgs struct { Login string `json:"login"` ID int `json:"id"` NodeID string `json:"node_id"` URL string `json:"url"` ReposURL string `json:"repos_url"` EventsURL string `json:"events_url"` HooksURL string `json:"hooks_url"` IssuesURL string `json:"issues_url"` MembersURL string `json:"members_url"` PublicMembersURL string `json:"public_members_url"` AvatarURL string `json:"avatar_url"` Description string `json:"description"` } type githubUser struct { Login string `json:"login"` ID int `json:"id"` NodeID string `json:"node_id"` AvatarURL string `json:"avatar_url"` GravatarID string `json:"gravatar_id"` URL string `json:"url"` HTMLURL string `json:"html_url"` FollowersURL string `json:"followers_url"` FollowingURL string `json:"following_url"` GistsURL string `json:"gists_url"` StarredURL string `json:"starred_url"` SubscriptionsURL string `json:"subscriptions_url"` OrganizationsURL string `json:"organizations_url"` ReposURL string `json:"repos_url"` EventsURL string `json:"events_url"` ReceivedEventsURL string `json:"received_events_url"` Type string `json:"type"` SiteAdmin bool `json:"site_admin"` Name string `json:"name"` Company string `json:"company"` Blog string `json:"blog"` Location string `json:"location"` Email string `json:"email"` Hireable bool `json:"hireable"` Bio string `json:"bio"` TwitterUsername string `json:"twitter_username"` PublicRepos int `json:"public_repos"` PublicGists int `json:"public_gists"` Followers int `json:"followers"` Following int `json:"following"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` PrivateGists int `json:"private_gists"` TotalPrivateRepos int `json:"total_private_repos"` OwnedPrivateRepos int `json:"owned_private_repos"` DiskUsage int `json:"disk_usage"` Collaborators int `json:"collaborators"` TwoFactorAuthentication bool `json:"two_factor_authentication"` Plan struct { Name string `json:"name"` Space int `json:"space"` PrivateRepos int `json:"private_repos"` Collaborators int `json:"collaborators"` } `json:"plan"` }