require "openssl/hmac" struct Invidious::User module Captcha extend self private TEXTCAPTCHA_URL = URI.parse("https://textcaptcha.com") def generate_image(key) second = Random::Secure.rand(12) second_angle = second * 30 second = second * 5 minute = Random::Secure.rand(12) minute_angle = minute * 30 minute = minute * 5 hour = Random::Secure.rand(12) hour_angle = hour * 30 + minute_angle.to_f / 12 if hour == 0 hour = 12 end clock_svg = <<-END_SVG 1 2 3 4 5 6 7 8 9 10 11 12 END_SVG image = "data:image/png;base64," image += Process.run(%(rsvg-convert -w 400 -h 400 -b none -f png), shell: true, input: IO::Memory.new(clock_svg), output: Process::Redirect::Pipe ) do |proc| Base64.strict_encode(proc.output.gets_to_end) end answer = "#{hour}:#{minute.to_s.rjust(2, '0')}:#{second.to_s.rjust(2, '0')}" answer = OpenSSL::HMAC.hexdigest(:sha256, key, answer) return { question: image, tokens: {generate_response(answer, {":login"}, key, use_nonce: true)}, } end def generate_text(key) response = make_client(TEXTCAPTCHA_URL, &.get("/github.com/iv.org/invidious.json").body) response = JSON.parse(response) tokens = response["a"].as_a.map do |answer| generate_response(answer.as_s, {":login"}, key, use_nonce: true) end return { question: response["q"].as_s, tokens: tokens, } end end end