mirror of
https://gitea.invidious.io/iv-org/invidious.git
synced 2024-08-15 00:53:41 +00:00
Add text CAPTCHA
This commit is contained in:
parent
ca4e8b800c
commit
26eb59e00d
2 changed files with 85 additions and 22 deletions
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
require "crypto/bcrypt/password"
|
require "crypto/bcrypt/password"
|
||||||
require "detect_language"
|
require "detect_language"
|
||||||
|
require "digest/md5"
|
||||||
require "kemal"
|
require "kemal"
|
||||||
require "openssl/hmac"
|
require "openssl/hmac"
|
||||||
require "option_parser"
|
require "option_parser"
|
||||||
|
@ -82,10 +83,11 @@ PG_URL = URI.new(
|
||||||
path: CONFIG.db[:dbname],
|
path: CONFIG.db[:dbname],
|
||||||
)
|
)
|
||||||
|
|
||||||
PG_DB = DB.open PG_URL
|
PG_DB = DB.open PG_URL
|
||||||
YT_URL = URI.parse("https://www.youtube.com")
|
YT_URL = URI.parse("https://www.youtube.com")
|
||||||
REDDIT_URL = URI.parse("https://www.reddit.com")
|
REDDIT_URL = URI.parse("https://www.reddit.com")
|
||||||
LOGIN_URL = URI.parse("https://accounts.google.com")
|
LOGIN_URL = URI.parse("https://accounts.google.com")
|
||||||
|
TEXTCAPTCHA_URL = URI.parse("http://textcaptcha.com/omarroth@hotmail.com.json")
|
||||||
|
|
||||||
crawl_threads.times do
|
crawl_threads.times do
|
||||||
spawn do
|
spawn do
|
||||||
|
@ -632,8 +634,25 @@ get "/login" do |env|
|
||||||
account_type = env.params.query["type"]?
|
account_type = env.params.query["type"]?
|
||||||
account_type ||= "invidious"
|
account_type ||= "invidious"
|
||||||
|
|
||||||
|
captcha_type = env.params.query["captcha"]?
|
||||||
|
captcha_type ||= "image"
|
||||||
|
|
||||||
if account_type == "invidious"
|
if account_type == "invidious"
|
||||||
captcha = generate_captcha(HMAC_KEY, PG_DB)
|
if captcha_type == "image"
|
||||||
|
captcha = generate_captcha(HMAC_KEY, PG_DB)
|
||||||
|
else
|
||||||
|
response = HTTP::Client.get(TEXTCAPTCHA_URL).body
|
||||||
|
response = JSON.parse(response)
|
||||||
|
|
||||||
|
tokens = response["a"].as_a.map do |answer|
|
||||||
|
create_response(answer.as_s, "sign_in", HMAC_KEY, PG_DB)
|
||||||
|
end
|
||||||
|
|
||||||
|
text_captcha = {
|
||||||
|
question: response["q"].as_s,
|
||||||
|
tokens: tokens,
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
tfa = env.params.query["tfa"]?
|
tfa = env.params.query["tfa"]?
|
||||||
|
@ -827,27 +846,55 @@ post "/login" do |env|
|
||||||
end
|
end
|
||||||
elsif account_type == "invidious"
|
elsif account_type == "invidious"
|
||||||
answer = env.params.body["answer"]?
|
answer = env.params.body["answer"]?
|
||||||
|
text_answer = env.params.body["text_answer"]?
|
||||||
|
|
||||||
if !answer
|
if answer
|
||||||
error_message = "CAPTCHA is a required field"
|
answer = answer.lstrip('0')
|
||||||
next templated "error"
|
answer = OpenSSL::HMAC.hexdigest(:sha256, HMAC_KEY, answer)
|
||||||
end
|
|
||||||
|
|
||||||
answer = answer.lstrip('0')
|
challenge = env.params.body["challenge"]?
|
||||||
answer = OpenSSL::HMAC.hexdigest(:sha256, HMAC_KEY, answer)
|
token = env.params.body["token"]?
|
||||||
|
|
||||||
challenge = env.params.body["challenge"]?
|
begin
|
||||||
token = env.params.body["token"]?
|
validate_response(challenge, token, answer, "sign_in", HMAC_KEY, PG_DB)
|
||||||
|
rescue ex
|
||||||
|
if ex.message == "Invalid user"
|
||||||
|
error_message = "Invalid answer"
|
||||||
|
else
|
||||||
|
error_message = ex.message
|
||||||
|
end
|
||||||
|
|
||||||
begin
|
next templated "error"
|
||||||
validate_response(challenge, token, answer, "sign_in", HMAC_KEY, PG_DB)
|
end
|
||||||
rescue ex
|
elsif text_answer
|
||||||
if ex.message && ex.message == "Invalid user"
|
text_answer = Digest::MD5.hexdigest(text_answer.downcase.strip)
|
||||||
error_message = "Invalid CAPTCHA response"
|
|
||||||
else
|
challenges = env.params.body.select { |k, v| k.match(/text_challenge\d+/) }
|
||||||
error_message = ex.message
|
tokens = env.params.body.select { |k, v| k.match(/text_token\d+/) }
|
||||||
|
|
||||||
|
found_valid_captcha = false
|
||||||
|
|
||||||
|
error_message = "Invalid CAPTCHA"
|
||||||
|
challenges.each_with_index do |challenge, i|
|
||||||
|
begin
|
||||||
|
challenge = challenge[1]
|
||||||
|
token = tokens[i][1]
|
||||||
|
validate_response(challenge, token, text_answer, "sign_in", HMAC_KEY, PG_DB)
|
||||||
|
found_valid_captcha = true
|
||||||
|
rescue ex
|
||||||
|
if ex.message == "Invalid user"
|
||||||
|
error_message = "Invalid answer"
|
||||||
|
else
|
||||||
|
error_message = ex.message
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if !found_valid_captcha
|
||||||
|
next templated "error"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error_message = "CAPTCHA is a required field"
|
||||||
next templated "error"
|
next templated "error"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -24,11 +24,27 @@
|
||||||
<label for="password">Password:</label>
|
<label for="password">Password:</label>
|
||||||
<input required class="pure-input-1" name="password" type="password" placeholder="Password">
|
<input required class="pure-input-1" name="password" type="password" placeholder="Password">
|
||||||
|
|
||||||
|
<% if captcha_type == "image" %>
|
||||||
<img style="width:100%" src='<%= captcha.not_nil![:image] %>'/>
|
<img style="width:100%" src='<%= captcha.not_nil![:image] %>'/>
|
||||||
<input type="hidden" name="token" value="<%= captcha.not_nil![:token] %>">
|
<input type="hidden" name="token" value="<%= captcha.not_nil![:token] %>">
|
||||||
<input type="hidden" name="challenge" value="<%= captcha.not_nil![:challenge] %>">
|
<input type="hidden" name="challenge" value="<%= captcha.not_nil![:challenge] %>">
|
||||||
<label for="answer">Time (h:mm):</label>
|
<input required type="text" name="answer" type="text" placeholder="h:mm">
|
||||||
<input required type="text" name="answer" type="text>" placeholder="hh:mm">
|
|
||||||
|
<label>
|
||||||
|
<a href="/login?referer=<%= URI.escape(referer) %>&type=invidious&captcha=text">Text CAPTCHA</a>
|
||||||
|
</label>
|
||||||
|
<% else %>
|
||||||
|
<% text_captcha.not_nil![:tokens].each_with_index do |token, i| %>
|
||||||
|
<input type="hidden" name="text_challenge<%= i %>" value="<%= token[0] %>">
|
||||||
|
<input type="hidden" name="text_token<%= i %>" value="<%= token[1] %>">
|
||||||
|
<% end %>
|
||||||
|
<label for="text_answer"><%= text_captcha.not_nil![:question] %></label>
|
||||||
|
<input required type="text" name="text_answer" type="text" placeholder="Answer">
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<a href="/login?referer=<%= URI.escape(referer) %>&type=invidious">Image CAPTCHA</a>
|
||||||
|
</label>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<button type="submit" name="action" value="signin" class="pure-button pure-button-primary">Sign In</button>
|
<button type="submit" name="action" value="signin" class="pure-button pure-button-primary">Sign In</button>
|
||||||
<button type="submit" name="action" value="register" class="pure-button pure-button-primary">Register</button>
|
<button type="submit" name="action" value="register" class="pure-button pure-button-primary">Register</button>
|
||||||
|
|
Loading…
Reference in a new issue