mirror of https://github.com/iv-org/invidious.git
Add support for Google login verification
This commit is contained in:
parent
d034fecc89
commit
6215259565
154
src/invidious.cr
154
src/invidious.cr
|
@ -892,6 +892,7 @@ get "/login" do |env|
|
||||||
|
|
||||||
tfa = env.params.query["tfa"]?
|
tfa = env.params.query["tfa"]?
|
||||||
tfa ||= false
|
tfa ||= false
|
||||||
|
prompt = ""
|
||||||
|
|
||||||
templated "login"
|
templated "login"
|
||||||
end
|
end
|
||||||
|
@ -989,15 +990,22 @@ post "/login" do |env|
|
||||||
next templated "error"
|
next templated "error"
|
||||||
end
|
end
|
||||||
|
|
||||||
if challenge_results[0][-1]?.try &.[0].as_a?.try &.[0][2]?.try &.== "TWO_STEP_VERIFICATION"
|
prompt_type = challenge_results[0][-1]?.try &.[0].as_a?.try &.[0][2]?
|
||||||
traceback << "User has 2FA.<br/>"
|
if {"TWO_STEP_VERIFICATION", "LOGIN_CHALLENGE"}.includes? prompt_type
|
||||||
|
traceback << "Handling prompt #{prompt_type}.<br/>"
|
||||||
|
case prompt_type
|
||||||
|
when "TWO_STEP_VERIFICATION"
|
||||||
|
prompt_type = 2
|
||||||
|
when "LOGIN_CHALLENGE"
|
||||||
|
prompt_type = 4
|
||||||
|
end
|
||||||
|
|
||||||
# Prefer Authenticator app and SMS over unsupported protocols
|
# Prefer Authenticator app and SMS over unsupported protocols
|
||||||
if challenge_results[0][-1][0][0][8] != 6 && challenge_results[0][-1][0][0][8] != 9
|
if !{6, 9, 12, 15}.includes?(challenge_results[0][-1][0][0][8]) && prompt_type == 4
|
||||||
tfa = challenge_results[0][-1][0].as_a.select { |auth_type| auth_type[8] == 6 || auth_type[8] == 9 }[0]
|
tfa = challenge_results[0][-1][0].as_a.select { |auth_type| {6, 9, 12, 15}.includes? auth_type[8] }[0]
|
||||||
|
|
||||||
traceback << "Selecting challenge #{tfa[8]}..."
|
traceback << "Selecting challenge #{tfa[8]}..."
|
||||||
select_challenge = {2, nil, nil, nil, {tfa[8]}}.to_json
|
select_challenge = {prompt_type, nil, nil, nil, {tfa[8]}}.to_json
|
||||||
|
|
||||||
tl = challenge_results[1][2]
|
tl = challenge_results[1][2]
|
||||||
|
|
||||||
|
@ -1011,62 +1019,84 @@ post "/login" do |env|
|
||||||
tfa = challenge_results[0][-1][0][0]
|
tfa = challenge_results[0][-1][0][0]
|
||||||
end
|
end
|
||||||
|
|
||||||
if tfa[2] == "TWO_STEP_VERIFICATION"
|
if tfa[5] == "QUOTA_EXCEEDED"
|
||||||
if tfa[5] == "QUOTA_EXCEEDED"
|
error_message = translate(locale, "Quota exceeded, try again in a few hours")
|
||||||
error_message = translate(locale, "Quota exceeded, try again in a few hours")
|
env.response.status_code = 423
|
||||||
env.response.status_code = 423
|
next templated "error"
|
||||||
next templated "error"
|
|
||||||
end
|
|
||||||
|
|
||||||
if !tfa_code
|
|
||||||
account_type = "google"
|
|
||||||
captcha_type = "image"
|
|
||||||
tfa = true
|
|
||||||
captcha = nil
|
|
||||||
next templated "login"
|
|
||||||
end
|
|
||||||
|
|
||||||
tl = challenge_results[1][2]
|
|
||||||
|
|
||||||
request_type = tfa[8]
|
|
||||||
case request_type
|
|
||||||
when 6
|
|
||||||
# Authenticator app
|
|
||||||
tfa_req = {
|
|
||||||
user_hash, nil, 2, nil,
|
|
||||||
{6, nil, nil, nil, nil,
|
|
||||||
{tfa_code, false},
|
|
||||||
},
|
|
||||||
}.to_json
|
|
||||||
when 9
|
|
||||||
# Voice or text message
|
|
||||||
tfa_req = {
|
|
||||||
user_hash, nil, 2, nil,
|
|
||||||
{9, nil, nil, nil, nil, nil, nil, nil,
|
|
||||||
{nil, tfa_code, false, 2},
|
|
||||||
},
|
|
||||||
}.to_json
|
|
||||||
else
|
|
||||||
error_message = translate(locale, "Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.")
|
|
||||||
env.response.status_code = 500
|
|
||||||
next templated "error"
|
|
||||||
end
|
|
||||||
|
|
||||||
traceback << "Submitting challenge..."
|
|
||||||
|
|
||||||
response = client.post("/_/signin/challenge?hl=en&TL=#{tl}", headers, login_req(tfa_req))
|
|
||||||
headers = response.cookies.add_request_headers(headers)
|
|
||||||
challenge_results = JSON.parse(response.body[5..-1])
|
|
||||||
|
|
||||||
if (challenge_results[0][-1]?.try &.[5] == "INCORRECT_ANSWER_ENTERED") ||
|
|
||||||
(challenge_results[0][-1]?.try &.[5] == "INVALID_INPUT")
|
|
||||||
error_message = translate(locale, "Invalid TFA code")
|
|
||||||
env.response.status_code = 401
|
|
||||||
next templated "error"
|
|
||||||
end
|
|
||||||
|
|
||||||
traceback << "done.<br/>"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if !tfa_code
|
||||||
|
account_type = "google"
|
||||||
|
captcha_type = "image"
|
||||||
|
|
||||||
|
case tfa[8]
|
||||||
|
when 6, 9
|
||||||
|
prompt = "Google verification code"
|
||||||
|
when 12
|
||||||
|
prompt = "Login verification, recovery email: #{tfa[-1][tfa[-1].as_h.keys[0]][0]}"
|
||||||
|
when 15
|
||||||
|
prompt = "Login verification, security question: #{tfa[-1][tfa[-1].as_h.keys[0]][0]}"
|
||||||
|
else
|
||||||
|
prompt = "Google verification code"
|
||||||
|
end
|
||||||
|
|
||||||
|
tfa = true
|
||||||
|
captcha = nil
|
||||||
|
next templated "login"
|
||||||
|
end
|
||||||
|
|
||||||
|
tl = challenge_results[1][2]
|
||||||
|
|
||||||
|
request_type = tfa[8]
|
||||||
|
case request_type
|
||||||
|
when 6 # Authenticator app
|
||||||
|
tfa_req = {
|
||||||
|
user_hash, nil, 2, nil,
|
||||||
|
{6, nil, nil, nil, nil,
|
||||||
|
{tfa_code, false},
|
||||||
|
},
|
||||||
|
}.to_json
|
||||||
|
when 9 # Voice or text message
|
||||||
|
tfa_req = {
|
||||||
|
user_hash, nil, 2, nil,
|
||||||
|
{9, nil, nil, nil, nil, nil, nil, nil,
|
||||||
|
{nil, tfa_code, false, 2},
|
||||||
|
},
|
||||||
|
}.to_json
|
||||||
|
when 12 # Recovery email
|
||||||
|
tfa_req = {
|
||||||
|
user_hash, nil, 4, nil,
|
||||||
|
{12, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
||||||
|
{tfa_code},
|
||||||
|
},
|
||||||
|
}.to_json
|
||||||
|
when 15 # Security question
|
||||||
|
tfa_req = {
|
||||||
|
user_hash, nil, 5, nil,
|
||||||
|
{15, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
||||||
|
{tfa_code},
|
||||||
|
},
|
||||||
|
}.to_json
|
||||||
|
else
|
||||||
|
error_message = translate(locale, "Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.")
|
||||||
|
env.response.status_code = 500
|
||||||
|
next templated "error"
|
||||||
|
end
|
||||||
|
|
||||||
|
traceback << "Submitting challenge..."
|
||||||
|
|
||||||
|
response = client.post("/_/signin/challenge?hl=en&TL=#{tl}", headers, login_req(tfa_req))
|
||||||
|
headers = response.cookies.add_request_headers(headers)
|
||||||
|
challenge_results = JSON.parse(response.body[5..-1])
|
||||||
|
|
||||||
|
if (challenge_results[0][-1]?.try &.[5] == "INCORRECT_ANSWER_ENTERED") ||
|
||||||
|
(challenge_results[0][-1]?.try &.[5] == "INVALID_INPUT")
|
||||||
|
error_message = translate(locale, "Invalid TFA code")
|
||||||
|
env.response.status_code = 401
|
||||||
|
next templated "error"
|
||||||
|
end
|
||||||
|
|
||||||
|
traceback << "done.<br/>"
|
||||||
end
|
end
|
||||||
|
|
||||||
traceback << "Logging in..."
|
traceback << "Logging in..."
|
||||||
|
@ -1080,8 +1110,7 @@ post "/login" do |env|
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: Occasionally there will be a second page after login confirming
|
# TODO: Occasionally there will be a second page after login confirming
|
||||||
# the user's phone number, which we will likely choke on.
|
# the user's phone number ("/b/0/SmsAuthInterstitial"), which we currently choke on.
|
||||||
# if location.includes? "SmsAuthInterstitial"
|
|
||||||
|
|
||||||
login = client.get(location, headers)
|
login = client.get(location, headers)
|
||||||
headers = login.cookies.add_request_headers(headers)
|
headers = login.cookies.add_request_headers(headers)
|
||||||
|
@ -1225,6 +1254,7 @@ post "/login" do |env|
|
||||||
|
|
||||||
account_type = "invidious"
|
account_type = "invidious"
|
||||||
tfa = false
|
tfa = false
|
||||||
|
prompt = ""
|
||||||
|
|
||||||
if captcha_type == "image"
|
if captcha_type == "image"
|
||||||
captcha = generate_captcha(HMAC_KEY, PG_DB)
|
captcha = generate_captcha(HMAC_KEY, PG_DB)
|
||||||
|
|
|
@ -102,8 +102,8 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% if tfa %>
|
<% if tfa %>
|
||||||
<label for="tfa"><%= translate(locale, "Google verification code") %> :</label>
|
<label for="tfa"><%= translate(locale, prompt) %> :</label>
|
||||||
<input required class="pure-input-1" name="tfa" type="text" placeholder="<%= translate(locale, "Google verification code") %>">
|
<input required class="pure-input-1" name="tfa" type="text" placeholder="<%= translate(locale, prompt) %>">
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<button type="submit" class="pure-button pure-button-primary"><%= translate(locale, "Sign In") %></button>
|
<button type="submit" class="pure-button pure-button-primary"><%= translate(locale, "Sign In") %></button>
|
||||||
|
|
Loading…
Reference in New Issue