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