You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

authorizations.go 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. // Copyright 2015 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. package github
  6. import (
  7. "context"
  8. "fmt"
  9. )
  10. // Scope models a GitHub authorization scope.
  11. //
  12. // GitHub API docs: https://developer.github.com/v3/oauth/#scopes
  13. type Scope string
  14. // This is the set of scopes for GitHub API V3
  15. const (
  16. ScopeNone Scope = "(no scope)" // REVISIT: is this actually returned, or just a documentation artifact?
  17. ScopeUser Scope = "user"
  18. ScopeUserEmail Scope = "user:email"
  19. ScopeUserFollow Scope = "user:follow"
  20. ScopePublicRepo Scope = "public_repo"
  21. ScopeRepo Scope = "repo"
  22. ScopeRepoDeployment Scope = "repo_deployment"
  23. ScopeRepoStatus Scope = "repo:status"
  24. ScopeDeleteRepo Scope = "delete_repo"
  25. ScopeNotifications Scope = "notifications"
  26. ScopeGist Scope = "gist"
  27. ScopeReadRepoHook Scope = "read:repo_hook"
  28. ScopeWriteRepoHook Scope = "write:repo_hook"
  29. ScopeAdminRepoHook Scope = "admin:repo_hook"
  30. ScopeAdminOrgHook Scope = "admin:org_hook"
  31. ScopeReadOrg Scope = "read:org"
  32. ScopeWriteOrg Scope = "write:org"
  33. ScopeAdminOrg Scope = "admin:org"
  34. ScopeReadPublicKey Scope = "read:public_key"
  35. ScopeWritePublicKey Scope = "write:public_key"
  36. ScopeAdminPublicKey Scope = "admin:public_key"
  37. ScopeReadGPGKey Scope = "read:gpg_key"
  38. ScopeWriteGPGKey Scope = "write:gpg_key"
  39. ScopeAdminGPGKey Scope = "admin:gpg_key"
  40. )
  41. // AuthorizationsService handles communication with the authorization related
  42. // methods of the GitHub API.
  43. //
  44. // This service requires HTTP Basic Authentication; it cannot be accessed using
  45. // an OAuth token.
  46. //
  47. // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/
  48. type AuthorizationsService service
  49. // Authorization represents an individual GitHub authorization.
  50. type Authorization struct {
  51. ID *int64 `json:"id,omitempty"`
  52. URL *string `json:"url,omitempty"`
  53. Scopes []Scope `json:"scopes,omitempty"`
  54. Token *string `json:"token,omitempty"`
  55. TokenLastEight *string `json:"token_last_eight,omitempty"`
  56. HashedToken *string `json:"hashed_token,omitempty"`
  57. App *AuthorizationApp `json:"app,omitempty"`
  58. Note *string `json:"note,omitempty"`
  59. NoteURL *string `json:"note_url,omitempty"`
  60. UpdatedAt *Timestamp `json:"updated_at,omitempty"`
  61. CreatedAt *Timestamp `json:"created_at,omitempty"`
  62. Fingerprint *string `json:"fingerprint,omitempty"`
  63. // User is only populated by the Check and Reset methods.
  64. User *User `json:"user,omitempty"`
  65. }
  66. func (a Authorization) String() string {
  67. return Stringify(a)
  68. }
  69. // AuthorizationApp represents an individual GitHub app (in the context of authorization).
  70. type AuthorizationApp struct {
  71. URL *string `json:"url,omitempty"`
  72. Name *string `json:"name,omitempty"`
  73. ClientID *string `json:"client_id,omitempty"`
  74. }
  75. func (a AuthorizationApp) String() string {
  76. return Stringify(a)
  77. }
  78. // Grant represents an OAuth application that has been granted access to an account.
  79. type Grant struct {
  80. ID *int64 `json:"id,omitempty"`
  81. URL *string `json:"url,omitempty"`
  82. App *AuthorizationApp `json:"app,omitempty"`
  83. CreatedAt *Timestamp `json:"created_at,omitempty"`
  84. UpdatedAt *Timestamp `json:"updated_at,omitempty"`
  85. Scopes []string `json:"scopes,omitempty"`
  86. }
  87. func (g Grant) String() string {
  88. return Stringify(g)
  89. }
  90. // AuthorizationRequest represents a request to create an authorization.
  91. type AuthorizationRequest struct {
  92. Scopes []Scope `json:"scopes,omitempty"`
  93. Note *string `json:"note,omitempty"`
  94. NoteURL *string `json:"note_url,omitempty"`
  95. ClientID *string `json:"client_id,omitempty"`
  96. ClientSecret *string `json:"client_secret,omitempty"`
  97. Fingerprint *string `json:"fingerprint,omitempty"`
  98. }
  99. func (a AuthorizationRequest) String() string {
  100. return Stringify(a)
  101. }
  102. // AuthorizationUpdateRequest represents a request to update an authorization.
  103. //
  104. // Note that for any one update, you must only provide one of the "scopes"
  105. // fields. That is, you may provide only one of "Scopes", or "AddScopes", or
  106. // "RemoveScopes".
  107. //
  108. // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#update-an-existing-authorization
  109. type AuthorizationUpdateRequest struct {
  110. Scopes []string `json:"scopes,omitempty"`
  111. AddScopes []string `json:"add_scopes,omitempty"`
  112. RemoveScopes []string `json:"remove_scopes,omitempty"`
  113. Note *string `json:"note,omitempty"`
  114. NoteURL *string `json:"note_url,omitempty"`
  115. Fingerprint *string `json:"fingerprint,omitempty"`
  116. }
  117. func (a AuthorizationUpdateRequest) String() string {
  118. return Stringify(a)
  119. }
  120. // List the authorizations for the authenticated user.
  121. //
  122. // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#list-your-authorizations
  123. func (s *AuthorizationsService) List(ctx context.Context, opt *ListOptions) ([]*Authorization, *Response, error) {
  124. u := "authorizations"
  125. u, err := addOptions(u, opt)
  126. if err != nil {
  127. return nil, nil, err
  128. }
  129. req, err := s.client.NewRequest("GET", u, nil)
  130. if err != nil {
  131. return nil, nil, err
  132. }
  133. var auths []*Authorization
  134. resp, err := s.client.Do(ctx, req, &auths)
  135. if err != nil {
  136. return nil, resp, err
  137. }
  138. return auths, resp, nil
  139. }
  140. // Get a single authorization.
  141. //
  142. // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#get-a-single-authorization
  143. func (s *AuthorizationsService) Get(ctx context.Context, id int64) (*Authorization, *Response, error) {
  144. u := fmt.Sprintf("authorizations/%d", id)
  145. req, err := s.client.NewRequest("GET", u, nil)
  146. if err != nil {
  147. return nil, nil, err
  148. }
  149. a := new(Authorization)
  150. resp, err := s.client.Do(ctx, req, a)
  151. if err != nil {
  152. return nil, resp, err
  153. }
  154. return a, resp, nil
  155. }
  156. // Create a new authorization for the specified OAuth application.
  157. //
  158. // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#create-a-new-authorization
  159. func (s *AuthorizationsService) Create(ctx context.Context, auth *AuthorizationRequest) (*Authorization, *Response, error) {
  160. u := "authorizations"
  161. req, err := s.client.NewRequest("POST", u, auth)
  162. if err != nil {
  163. return nil, nil, err
  164. }
  165. a := new(Authorization)
  166. resp, err := s.client.Do(ctx, req, a)
  167. if err != nil {
  168. return nil, resp, err
  169. }
  170. return a, resp, nil
  171. }
  172. // GetOrCreateForApp creates a new authorization for the specified OAuth
  173. // application, only if an authorization for that application doesn’t already
  174. // exist for the user.
  175. //
  176. // If a new token is created, the HTTP status code will be "201 Created", and
  177. // the returned Authorization.Token field will be populated. If an existing
  178. // token is returned, the status code will be "200 OK" and the
  179. // Authorization.Token field will be empty.
  180. //
  181. // clientID is the OAuth Client ID with which to create the token.
  182. //
  183. // GitHub API docs:
  184. // https://developer.github.com/v3/oauth_authorizations/#get-or-create-an-authorization-for-a-specific-app
  185. // https://developer.github.com/v3/oauth_authorizations/#get-or-create-an-authorization-for-a-specific-app-and-fingerprint
  186. func (s *AuthorizationsService) GetOrCreateForApp(ctx context.Context, clientID string, auth *AuthorizationRequest) (*Authorization, *Response, error) {
  187. var u string
  188. if auth.Fingerprint == nil || *auth.Fingerprint == "" {
  189. u = fmt.Sprintf("authorizations/clients/%v", clientID)
  190. } else {
  191. u = fmt.Sprintf("authorizations/clients/%v/%v", clientID, *auth.Fingerprint)
  192. }
  193. req, err := s.client.NewRequest("PUT", u, auth)
  194. if err != nil {
  195. return nil, nil, err
  196. }
  197. a := new(Authorization)
  198. resp, err := s.client.Do(ctx, req, a)
  199. if err != nil {
  200. return nil, resp, err
  201. }
  202. return a, resp, nil
  203. }
  204. // Edit a single authorization.
  205. //
  206. // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#update-an-existing-authorization
  207. func (s *AuthorizationsService) Edit(ctx context.Context, id int64, auth *AuthorizationUpdateRequest) (*Authorization, *Response, error) {
  208. u := fmt.Sprintf("authorizations/%d", id)
  209. req, err := s.client.NewRequest("PATCH", u, auth)
  210. if err != nil {
  211. return nil, nil, err
  212. }
  213. a := new(Authorization)
  214. resp, err := s.client.Do(ctx, req, a)
  215. if err != nil {
  216. return nil, resp, err
  217. }
  218. return a, resp, nil
  219. }
  220. // Delete a single authorization.
  221. //
  222. // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#delete-an-authorization
  223. func (s *AuthorizationsService) Delete(ctx context.Context, id int64) (*Response, error) {
  224. u := fmt.Sprintf("authorizations/%d", id)
  225. req, err := s.client.NewRequest("DELETE", u, nil)
  226. if err != nil {
  227. return nil, err
  228. }
  229. return s.client.Do(ctx, req, nil)
  230. }
  231. // Check if an OAuth token is valid for a specific app.
  232. //
  233. // Note that this operation requires the use of BasicAuth, but where the
  234. // username is the OAuth application clientID, and the password is its
  235. // clientSecret. Invalid tokens will return a 404 Not Found.
  236. //
  237. // The returned Authorization.User field will be populated.
  238. //
  239. // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#check-an-authorization
  240. func (s *AuthorizationsService) Check(ctx context.Context, clientID string, token string) (*Authorization, *Response, error) {
  241. u := fmt.Sprintf("applications/%v/tokens/%v", clientID, token)
  242. req, err := s.client.NewRequest("GET", u, nil)
  243. if err != nil {
  244. return nil, nil, err
  245. }
  246. a := new(Authorization)
  247. resp, err := s.client.Do(ctx, req, a)
  248. if err != nil {
  249. return nil, resp, err
  250. }
  251. return a, resp, nil
  252. }
  253. // Reset is used to reset a valid OAuth token without end user involvement.
  254. // Applications must save the "token" property in the response, because changes
  255. // take effect immediately.
  256. //
  257. // Note that this operation requires the use of BasicAuth, but where the
  258. // username is the OAuth application clientID, and the password is its
  259. // clientSecret. Invalid tokens will return a 404 Not Found.
  260. //
  261. // The returned Authorization.User field will be populated.
  262. //
  263. // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#reset-an-authorization
  264. func (s *AuthorizationsService) Reset(ctx context.Context, clientID string, token string) (*Authorization, *Response, error) {
  265. u := fmt.Sprintf("applications/%v/tokens/%v", clientID, token)
  266. req, err := s.client.NewRequest("POST", u, nil)
  267. if err != nil {
  268. return nil, nil, err
  269. }
  270. a := new(Authorization)
  271. resp, err := s.client.Do(ctx, req, a)
  272. if err != nil {
  273. return nil, resp, err
  274. }
  275. return a, resp, nil
  276. }
  277. // Revoke an authorization for an application.
  278. //
  279. // Note that this operation requires the use of BasicAuth, but where the
  280. // username is the OAuth application clientID, and the password is its
  281. // clientSecret. Invalid tokens will return a 404 Not Found.
  282. //
  283. // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#revoke-an-authorization-for-an-application
  284. func (s *AuthorizationsService) Revoke(ctx context.Context, clientID string, token string) (*Response, error) {
  285. u := fmt.Sprintf("applications/%v/tokens/%v", clientID, token)
  286. req, err := s.client.NewRequest("DELETE", u, nil)
  287. if err != nil {
  288. return nil, err
  289. }
  290. return s.client.Do(ctx, req, nil)
  291. }
  292. // ListGrants lists the set of OAuth applications that have been granted
  293. // access to a user's account. This will return one entry for each application
  294. // that has been granted access to the account, regardless of the number of
  295. // tokens an application has generated for the user.
  296. //
  297. // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#list-your-grants
  298. func (s *AuthorizationsService) ListGrants(ctx context.Context, opt *ListOptions) ([]*Grant, *Response, error) {
  299. u, err := addOptions("applications/grants", opt)
  300. if err != nil {
  301. return nil, nil, err
  302. }
  303. req, err := s.client.NewRequest("GET", u, nil)
  304. if err != nil {
  305. return nil, nil, err
  306. }
  307. grants := []*Grant{}
  308. resp, err := s.client.Do(ctx, req, &grants)
  309. if err != nil {
  310. return nil, resp, err
  311. }
  312. return grants, resp, nil
  313. }
  314. // GetGrant gets a single OAuth application grant.
  315. //
  316. // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#get-a-single-grant
  317. func (s *AuthorizationsService) GetGrant(ctx context.Context, id int64) (*Grant, *Response, error) {
  318. u := fmt.Sprintf("applications/grants/%d", id)
  319. req, err := s.client.NewRequest("GET", u, nil)
  320. if err != nil {
  321. return nil, nil, err
  322. }
  323. grant := new(Grant)
  324. resp, err := s.client.Do(ctx, req, grant)
  325. if err != nil {
  326. return nil, resp, err
  327. }
  328. return grant, resp, nil
  329. }
  330. // DeleteGrant deletes an OAuth application grant. Deleting an application's
  331. // grant will also delete all OAuth tokens associated with the application for
  332. // the user.
  333. //
  334. // GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#delete-a-grant
  335. func (s *AuthorizationsService) DeleteGrant(ctx context.Context, id int64) (*Response, error) {
  336. u := fmt.Sprintf("applications/grants/%d", id)
  337. req, err := s.client.NewRequest("DELETE", u, nil)
  338. if err != nil {
  339. return nil, err
  340. }
  341. return s.client.Do(ctx, req, nil)
  342. }
  343. // CreateImpersonation creates an impersonation OAuth token.
  344. //
  345. // This requires admin permissions. With the returned Authorization.Token
  346. // you can e.g. create or delete a user's public SSH key. NOTE: creating a
  347. // new token automatically revokes an existing one.
  348. //
  349. // GitHub API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#create-an-impersonation-oauth-token
  350. func (s *AuthorizationsService) CreateImpersonation(ctx context.Context, username string, authReq *AuthorizationRequest) (*Authorization, *Response, error) {
  351. u := fmt.Sprintf("admin/users/%v/authorizations", username)
  352. req, err := s.client.NewRequest("POST", u, authReq)
  353. if err != nil {
  354. return nil, nil, err
  355. }
  356. a := new(Authorization)
  357. resp, err := s.client.Do(ctx, req, a)
  358. if err != nil {
  359. return nil, resp, err
  360. }
  361. return a, resp, nil
  362. }
  363. // DeleteImpersonation deletes an impersonation OAuth token.
  364. //
  365. // NOTE: there can be only one at a time.
  366. //
  367. // GitHub API docs: https://developer.github.com/enterprise/v3/enterprise-admin/users/#delete-an-impersonation-oauth-token
  368. func (s *AuthorizationsService) DeleteImpersonation(ctx context.Context, username string) (*Response, error) {
  369. u := fmt.Sprintf("admin/users/%v/authorizations", username)
  370. req, err := s.client.NewRequest("DELETE", u, nil)
  371. if err != nil {
  372. return nil, err
  373. }
  374. return s.client.Do(ctx, req, nil)
  375. }