From a5b1f3066e62356bc59a2ca542358b620d6e0435 Mon Sep 17 00:00:00 2001 From: Kevin Squire Date: Sun, 27 Apr 2014 03:40:17 -0700 Subject: [PATCH 1/2] Enable github two-factor authentication; fixes #5252 --- base/pkg/github.jl | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/base/pkg/github.jl b/base/pkg/github.jl index 40a819e8b4186..79b3812c5e142 100644 --- a/base/pkg/github.jl +++ b/base/pkg/github.jl @@ -36,9 +36,14 @@ function curl(url::String, opts::Cmd=``) out, proc = open(`curl -i -s -S $opts $url`,"r") head = readline(out) status = int(split(head,r"\s+";limit=3)[2]) + header = (String=>String)[] for line in eachline(out) - ismatch(r"^\s*$",line) || continue - wait(proc); return status, readall(out) + if !ismatch(r"^\s*$",line) + (k,v) = split(line, r":\s*", 2) + header[k] = v + continue + end + wait(proc); return status, header, readall(out) end error("strangely formatted HTTP response") end @@ -55,20 +60,30 @@ end function token(user::String=user()) tokfile = Dir.path(".github","token") isfile(tokfile) && return strip(readchomp(tokfile)) - status, content = curl("https://api.github.com/authorizations",AUTH_DATA,`-u $user`) + status, header, content = curl("https://api.github.com/authorizations",AUTH_DATA,`-u $user`) + + # Check for two-factor authentication + if status == 401 && get(header, "X-GitHub-OTP", "") |> x->beginswith(x, "required") && isinteractive() + info("Two-factor authentication in use. Enter auth code. (You may have to re-enter your password.)") + print(STDERR, "Authentication code: ") + code = readline(STDIN) |> chomp + status, header, content = curl("https://api.github.com/authorizations",AUTH_DATA,`-H "X-GitHub-OTP: $code" -u $user`) + end + if status == 422 error_code = json().parse(content)["errors"][1]["code"] if error_code == "already_exists" - info("Retrieving existing GitHub token (you may have to enter you password again)") - status,content = curl("https://api.github.com/authorizations",`-u $user`) + info("Retrieving existing GitHub token. (You may have to re-enter your password.)") + status, header, content = curl("https://api.github.com/authorizations",`-u $user`) (status >= 400) && error("$status: $(json().parse(content)["message"])") for entry in json().parse(content) if entry["note"] == AUTH_NOTE tok = entry["token"] + break end end else - error("GitHub returned validation error (422): $error_code") + error("GitHub returned validation error (422): $error_code: $(json().parse(content)["message"])") end else (status != 401 && status != 403) || error("$status: $(json().parse(content)["message"])") @@ -81,7 +96,7 @@ end function req(resource::String, data, opts::Cmd=``) url = "https://api.github.com/$resource" - status, content = curl(url,data,`-u $(token()):x-oauth-basic $opts`) + status, header, content = curl(url,data,`-u $(token()):x-oauth-basic $opts`) response = json().parse(content) status, response end From e5eaf8099317cf7cf090bdf0878258a5aad5e057 Mon Sep 17 00:00:00 2001 From: Kevin Squire Date: Wed, 3 Sep 2014 01:07:51 -0700 Subject: [PATCH 2/2] Updates to two-factor authentication. --- base/pkg/github.jl | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/base/pkg/github.jl b/base/pkg/github.jl index 79b3812c5e142..28b9543a6d869 100644 --- a/base/pkg/github.jl +++ b/base/pkg/github.jl @@ -61,9 +61,11 @@ function token(user::String=user()) tokfile = Dir.path(".github","token") isfile(tokfile) && return strip(readchomp(tokfile)) status, header, content = curl("https://api.github.com/authorizations",AUTH_DATA,`-u $user`) + tfa = false # Check for two-factor authentication if status == 401 && get(header, "X-GitHub-OTP", "") |> x->beginswith(x, "required") && isinteractive() + tfa = true info("Two-factor authentication in use. Enter auth code. (You may have to re-enter your password.)") print(STDERR, "Authentication code: ") code = readline(STDIN) |> chomp @@ -73,8 +75,17 @@ function token(user::String=user()) if status == 422 error_code = json().parse(content)["errors"][1]["code"] if error_code == "already_exists" - info("Retrieving existing GitHub token. (You may have to re-enter your password.)") - status, header, content = curl("https://api.github.com/authorizations",`-u $user`) + if tfa + info("Retrieving existing GitHub token. (You may have to re-enter your password twice more.)") + status, header, content = curl("https://api.github.com/authorizations",AUTH_DATA,`-u $user`) + status != 401 && error("$status: $(json().parse(content)["message"])") + print(STDERR, "New authentication code: ") + code = readline(STDIN) |> chomp + status, header, content = curl("https://api.github.com/authorizations",`-H "X-GitHub-OTP: $code" -u $user`) + else + info("Retrieving existing GitHub token. (You may have to re-enter your password.)") + status, header, content = curl("https://api.github.com/authorizations", `-u $user`) + end (status >= 400) && error("$status: $(json().parse(content)["message"])") for entry in json().parse(content) if entry["note"] == AUTH_NOTE @@ -89,6 +100,7 @@ function token(user::String=user()) (status != 401 && status != 403) || error("$status: $(json().parse(content)["message"])") tok = json().parse(content)["token"] end + mkpath(dirname(tokfile)) open(io->println(io,tok),tokfile,"w") return tok