Skip to content

Commit

Permalink
Merge pull request #35 from MaximeD/multiple_tokens
Browse files Browse the repository at this point in the history
ADD support for multiple OAuth tokens
  • Loading branch information
MaximeD committed Jan 25, 2015
2 parents 5104b10 + bbc3b11 commit d1b2dae
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 61 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# CHANGELOG

## 0.4.0 (2015/01/25)

Bugfix :

* FIX opening browser on multiple OS (thanx @ramtiga)
* ALLOW creating multiple tokens


## 0.3.0 (2014/06/06)

New functionalities:
Expand Down
147 changes: 86 additions & 61 deletions conf/oauth/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,91 +8,65 @@ import (
"io/ioutil"
"net/http"
"os"
"time"
)

var baseUrl string = "https://api.github.com/"
var authorizationUrl string = baseUrl + "authorizations"

func GetToken() (token string) {
// GetToken will query github api to create an authentication token for gost.
// This allows user to create gists on his behalf rather than anonymously.
// It returns the created token.
func GetToken() string {
client := &http.Client{}
var resp *http.Response
var authorizationResponseBody []byte
var twoFA string

// json structure
scopes := []string{"gist"}
authorization := OAuthJSON.GetSingleAuth{Scopes: scopes, Note: "gost", NoteUrl: "https://github.com/MaximeD"}
encodedJson, err := json.Marshal(authorization)
if err != nil {
fmt.Printf("%s\n", err)
}
username, password := askUserForCredentials()
authenticationJson := getAuthenticationJson(false)

resp := makeBasicAuthRequest(client, username, password, authenticationJson, twoFA)
defer resp.Body.Close()

// ask for user credentials
username, password := getCredentials()
// check for 2fa
if resp.StatusCode == 401 && resp.Header.Get("X-Github-Otp") != "" {
twoFA = askUserForTwoFA()
resp = makeBasicAuthRequest(client, username, password, authenticationJson, twoFA)
defer resp.Body.Close()
}

// make request
req := makeRequest(username, password, encodedJson)
// user might already have registered a token for this application
if resp.StatusCode == 422 {
authenticationJson = getAuthenticationJson(true)
resp = makeBasicAuthRequest(client, username, password, authenticationJson, twoFA)
defer resp.Body.Close()
}

// post json
resp, err = client.Do(req)
if err != nil {
fmt.Printf("%s\n", err)
if resp.StatusCode != 201 {
fmt.Println("Sorry but we could not authenticate you.")
fmt.Println("No gist were created...")
os.Exit(1)
}
authorizationResponseBody, err = ioutil.ReadAll(resp.Body)

authorizationResponseBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("%s\n", err)
os.Exit(1)
}

// check github response
if resp.StatusCode == 401 {
header := resp.Header

// user may have enable 2fa
if header.Get("X-Github-Otp") != "" {
fmt.Println("2-factor authentication code:")
var twoFA string
fmt.Scanln(&twoFA)

// make request
req := makeRequest(username, password, encodedJson)
req.Header.Add("X-Github-Otp", twoFA)

resp, err = client.Do(req)
if err != nil {
fmt.Printf("%s\n", err)
os.Exit(1)
}

authorizationResponseBody, err = ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("%s\n", err)
os.Exit(1)
}

// has authorization been created?
if resp.StatusCode != 201 {
fmt.Println("Sorry but we could not authenticate you")
os.Exit(1)
}
} else {
fmt.Println("Sorry but we could not authenticate you")
os.Exit(1)
}
}

var jsonRes OAuthJSON.GetSingleAuthResponse
err = json.Unmarshal(authorizationResponseBody, &jsonRes)
if err != nil {
fmt.Printf("%s\n", err)
os.Exit(1)
}

token = jsonRes.Token
return token
return jsonRes.Token
}

func getCredentials() (username string, password string) {
// askUserForCredentials will prompt the user to enter his username and password.
// It returns user's username and user's password.
func askUserForCredentials() (username string, password string) {
fmt.Println("GitHub username:")
fmt.Scanln(&username)
fmt.Println("GitHub password:")
Expand All @@ -101,14 +75,65 @@ func getCredentials() (username string, password string) {
return username, password
}

func makeRequest(username string, password string, encodedJson []byte) *http.Request {
jsonBody := bytes.NewBuffer(encodedJson)
// makeBasicAuthRequest will create a POST request to create a new authorization
// with basic auth enabled.
// See: https://developer.github.com/v3/oauth_authorizations/#create-a-new-authorization
// It takes user's username, user's password, marshalled json and 2fa code if user has enabled it.
// It returns a new Request.
func makeBasicAuthRequest(client *http.Client, username string, password string, marshalledJson []byte, twoFA string) *http.Response {
jsonBody := bytes.NewBuffer(marshalledJson)

req, err := http.NewRequest("POST", authorizationUrl, jsonBody)
if err != nil {
fmt.Printf("%s\n", err)
os.Exit(1)
}
req.SetBasicAuth(username, password)
if twoFA != "" {
req.Header.Add("X-GitHub-OTP", twoFA)
}

resp, err := client.Do(req)
if err != nil {
fmt.Printf("%s\n", err)
os.Exit(1)
}

return resp
}

// getAuthenticationJson creates a marshalled json to be used to create a new authorization.
// See: https://developer.github.com/v3/oauth_authorizations/#create-a-new-authorization
// It takes a boolean parameter telling if note should include a timestamp.
// You will need this in case user already has a token for this application and needs to create a new one.
// Otherwise github will return an empty token.
// It returns the marshalled json.
func getAuthenticationJson(withTimestamp bool) []byte {
description := "gost"

if withTimestamp {
fmt.Println("You already have a personal access token for gost, though I cannot find it on your computer...")
fmt.Println("I will create another access token for you.")
fmt.Println("(You can see them here https://github.com/settings/applications)")
description = fmt.Sprintf("%s (%s)", description, time.Now())
}

authorization := OAuthJSON.GetSingleAuth{Scopes: []string{"gist"}, Note: description, NoteUrl: "https://github.com/MaximeD/gost"}
marshalledJson, err := json.Marshal(authorization)
if err != nil {
fmt.Printf("%s\n", err)
}

return marshalledJson
}

// askUserForTwoFA will prompt user to enter his 2f-a code if GitHub requests one
// It returns the 2f-a code.
func askUserForTwoFA() string {
var twoFA string

fmt.Println("You have enabled two-factor authentication, please enter the code GitHub sent you:")
fmt.Scanln(&twoFA)

return req
return twoFA
}

0 comments on commit d1b2dae

Please sign in to comment.