1// Copyright 2013 The go-github AUTHORS. All rights reserved. 2// 3// Use of this source code is governed by a BSD-style 4// license that can be found in the LICENSE file. 5 6// apps.go contains functions for accessing data about applications installed 7// on a GitHub organization. 8 9package scrape 10 11import ( 12 "bytes" 13 "encoding/json" 14 "errors" 15 "net/http" 16 "strconv" 17 "strings" 18 19 "github.com/PuerkitoBio/goquery" 20 "github.com/google/go-github/v28/github" 21) 22 23// AppRestrictionsEnabled returns whether the specified organization has 24// restricted third-party application access. 25func (c *Client) AppRestrictionsEnabled(org string) (bool, error) { 26 doc, err := c.get("/organizations/%s/settings/oauth_application_policy", org) 27 if err != nil { 28 return false, err 29 } 30 31 s := doc.Find(".oauth-application-whitelist svg").First() 32 if s.Length() == 0 { 33 return false, errors.New("unable to find expected markup") 34 } 35 36 if s.HasClass("octicon-check") { 37 return true, nil 38 } 39 if s.HasClass("octicon-alert") { 40 return false, nil 41 } 42 43 return false, errors.New("unable to find expected markup") 44} 45 46// ListOAuthApps lists the reviewed OAuth Applications for the 47// specified organization (whether approved or denied). 48func (c *Client) ListOAuthApps(org string) ([]OAuthApp, error) { 49 doc, err := c.get("/organizations/%s/settings/oauth_application_policy", org) 50 if err != nil { 51 return nil, err 52 } 53 54 var apps []OAuthApp 55 doc.Find(".oauth-application-whitelist ul > li").Each(func(i int, s *goquery.Selection) { 56 var app OAuthApp 57 app.Name = s.Find(".request-info strong").First().Text() 58 app.Description = s.Find(".request-info .application-description").Text() 59 60 if editURL, ok := s.Find(".request-indicator a.edit-link").Attr("href"); ok { 61 app.ID = intFromLastPathSegment(editURL) 62 } 63 64 if r := s.Find(".request-indicator .requestor"); r.Length() > 0 { 65 app.State = OAuthAppRequested 66 app.RequestedBy = r.Text() 67 if editURL, ok := s.Find(".request-indicator a").Last().Attr("href"); ok { 68 app.ID = intFromLastPathSegment(editURL) 69 } 70 } else if r := s.Find(".request-indicator .approved-request"); r.Length() > 0 { 71 app.State = OAuthAppApproved 72 } else if r := s.Find(".request-indicator .denied-request"); r.Length() > 0 { 73 app.State = OAuthAppDenied 74 } 75 apps = append(apps, app) 76 }) 77 78 return apps, nil 79} 80 81func intFromLastPathSegment(s string) int { 82 seg := strings.Split(s, "/") 83 if len(seg) > 0 { 84 i, _ := strconv.Atoi(seg[len(seg)-1]) 85 return i 86 } 87 return 0 88} 89 90// OAuthAppReviewState indicates the current state of a requested OAuth Application. 91type OAuthAppReviewState int 92 93const ( 94 // OAuthAppRequested indicates access has been requested, but not reviewed 95 OAuthAppRequested OAuthAppReviewState = iota + 1 96 // OAuthAppApproved indicates access has been approved 97 OAuthAppApproved 98 // OAuthAppDenied indicates access has been denied 99 OAuthAppDenied 100) 101 102// OAuthApp represents an OAuth application that has been reviewed for access to organization data. 103type OAuthApp struct { 104 ID int 105 Name string 106 Description string 107 State OAuthAppReviewState 108 RequestedBy string 109} 110 111// AppManifest represents a GitHub App manifest, used for preconfiguring 112// GitHub App configuration. 113type AppManifest struct { 114 // The name of the GitHub App. 115 Name *string `json:"name,omitempty"` 116 //Required. The homepage of your GitHub App. 117 URL *string `json:"url,omitempty"` 118 // Required. The configuration of the GitHub App's webhook. 119 HookAttributes map[string]string `json:"hook_attributes,omitempty"` 120 // The full URL to redirect to after the person installs the GitHub App. 121 RedirectURL *string `json:"redirect_url,omitempty"` 122 // A description of the GitHub App. 123 Description *string `json:"description,omitempty"` 124 // Set to true when your GitHub App is available to the public or false when 125 // it is only accessible to the owner of the app. 126 Public *bool `json:"public,omitempty"` 127 // The list of events the GitHub App subscribes to. 128 DefaultEvents []string `json:"default_events,omitempty"` 129 // The set of permissions needed by the GitHub App. 130 DefaultPermissions *github.InstallationPermissions `json:"default_permissions,omitempty"` 131} 132 133// CreateApp creates a new GitHub App with the given manifest configuration. 134func (c *Client) CreateApp(m *AppManifest) (*http.Response, error) { 135 u, err := c.baseURL.Parse("/settings/apps/new") 136 if err != nil { 137 return nil, err 138 } 139 140 body, err := json.Marshal(map[string]*AppManifest{"manifest": m}) 141 if err != nil { 142 return nil, err 143 } 144 145 return c.Client.Post(u.String(), "json", bytes.NewReader(body)) 146} 147