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