diff options
| author | Omar Roth <omarroth@hotmail.com> | 2018-03-16 11:40:29 -0500 |
|---|---|---|
| committer | Omar Roth <omarroth@hotmail.com> | 2018-03-16 11:40:29 -0500 |
| commit | d8372aa83e910159f9639532023d9bb4d84a1054 (patch) | |
| tree | 2cba355c0f286b342d45b3f1cf21c588ee5f40be | |
| parent | e8013c6d5cacc2e57e37bf4692d6a3e1f5526eb8 (diff) | |
| download | invidious-d8372aa83e910159f9639532023d9bb4d84a1054.tar.gz invidious-d8372aa83e910159f9639532023d9bb4d84a1054.tar.bz2 invidious-d8372aa83e910159f9639532023d9bb4d84a1054.zip | |
Add login page
| -rw-r--r-- | src/helpers.cr | 18 | ||||
| -rw-r--r-- | src/invidious.cr | 82 | ||||
| -rw-r--r-- | src/views/layout.ecr | 5 | ||||
| -rw-r--r-- | src/views/login.ecr | 25 |
4 files changed, 129 insertions, 1 deletions
diff --git a/src/helpers.cr b/src/helpers.cr index fa4e6449..f6b1e52b 100644 --- a/src/helpers.cr +++ b/src/helpers.cr @@ -405,3 +405,21 @@ def fill_links(html, scheme, host) html = html.to_xml end + +def login_req(login_form, f_req) + data = { + "pstMsg" => "1", + "checkConnection" => "youtube", + "checkedDomains" => "youtube", + "hl" => "en", + "deviceinfo" => %q([null,null,null,[],null,"US",null,null,[],"GlifWebSignIn",null,[null,null,[]]]), + "f.req" => f_req, + "flowName" => "GlifWebSignIn", + "flowEntry" => "ServiceLogin", + } + + data = data.merge(login_form) + # pp data + + return HTTP::Params.encode(data) +end diff --git a/src/invidious.cr b/src/invidious.cr index 8549cd45..62d73cef 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -71,6 +71,7 @@ PG_URL = URI.new( PG_DB = DB.open PG_URL YT_URL = URI.parse("https://www.youtube.com") REDDIT_URL = URI.parse("https://api.reddit.com") +LOGIN_URL = URI.parse("https://accounts.google.com") youtube_pool = Deque.new(pool_size) do make_client(YT_URL) @@ -330,6 +331,87 @@ get "/search" do |env| templated "search" end +get "/login" do |env| + templated "login" +end + +# See https://github.com/rg3/youtube-dl/blob/master/youtube_dl/extractor/youtube.py#L79 +post "/login" do |env| + email = env.params.body["email"]? + password = env.params.body["password"]? + remember = env.params.body["remember"]? || "false" + + begin + client = make_client(LOGIN_URL) + headers = HTTP::Headers.new + login_page = client.get("/ServiceLogin") + headers = login_page.cookies.add_request_headers(headers) + + login_page = XML.parse_html(login_page.body) + + inputs = {} of String => String + login_page.xpath_nodes(%q(//input[@type="submit"])).each do |node| + name = node["id"]? || node["name"]? + name ||= "" + value = node["value"]? + value ||= "" + + if name != "" && value != "" + inputs[name] = value + end + end + + login_page.xpath_nodes(%q(//input[@type="hidden"])).each do |node| + name = node["id"]? || node["name"]? + name ||= "" + value = node["value"]? + value ||= "" + + if name != "" && value != "" + inputs[name] = value + end + end + + lookup_req = %(["#{email}","#{inputs["session-state"]}",[],null,"US",null,null,2,false,true,[null,null,[2,1,null,1,"https://accounts.google.com/ServiceLogin?passive=true&continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Fnext%3D%252F%26action_handle_signin%3Dtrue%26hl%3Den%26app%3Ddesktop%26feature%3Dsign_in_button&hl=en&service=youtube&uilel=3&requestPath=%2FServiceLogin&Page=PasswordSeparationSignIn",null,[],4,[]],1,[null,null,[]],null,null,null,true],"#{email}"]) + + headers["Content-Type"] = "application/x-www-form-urlencoded;charset=utf-8" + headers["Google-Accounts-XSRF"] = "1" + + lookup_results = client.post("/_/signin/sl/lookup", headers, login_req(inputs, lookup_req)) + headers = lookup_results.cookies.add_request_headers(headers) + + lookup_results = lookup_results.body + lookup_results = lookup_results[5..-1] + lookup_results = JSON.parse(lookup_results) + + user_hash = lookup_results[0][2] + + challenge_req = %([#{user_hash},null,1,null,[1,null,null,null,[#{password},null,true]],[null,null,[2,1,null,1,"https://accounts.google.com/ServiceLogin?passive=true&continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Fnext%3D%252F%26action_handle_signin%3Dtrue%26hl%3Den%26app%3Ddesktop%26feature%3Dsign_in_button&hl=en&service=youtube&uilel=3&requestPath=%2FServiceLogin&Page=PasswordSeparationSignIn", null,[],4],1,[null,null,[]],null,null,null,true]]) + + challenge_results = client.post("/_/signin/sl/challenge", headers, login_req(inputs, challenge_req)) + headers = challenge_results.cookies.add_request_headers(headers) + + challenge_results = challenge_results.body + challenge_results = challenge_results[5..-1] + challenge_results = JSON.parse(challenge_results) + + login_res = challenge_results[0][13][2].to_s + + login = client.get(login_res, headers) + headers = login.cookies.add_request_headers(headers) + + login = client.get(login.headers["Location"], headers) + headers = login.cookies.add_request_headers(headers) + + # We are now logged in + + env.redirect "/" + rescue ex + error_message = "Login failed" + next templated "error" + end +end + get "/redirect" do |env| if env.params.query["q"]? env.redirect env.params.query["q"] diff --git a/src/views/layout.ecr b/src/views/layout.ecr index 81a3be40..f419ec58 100644 --- a/src/views/layout.ecr +++ b/src/views/layout.ecr @@ -19,11 +19,14 @@ <div class="pure-u-1 pure-u-md-1-5"> <a href="/" class="pure-menu-heading">Invidious</a> </div> - <div class="pure-u-1 pure-u-md-4-5"> + <div class="pure-u-1 pure-u-md-3-5"> <form class="pure-form" action="/search" method="get"> <input type="search" style="width:100%;" name="q" placeholder="search" value="<%= env.params.query["q"]? %>"> </form> </div> + <div class="pure-u-1 pure-u-md-1-5"> + <a href="/login" class="pure-menu-heading">Login</a> + </div> </div> <%= content %> <center class="h-box"> diff --git a/src/views/login.ecr b/src/views/login.ecr new file mode 100644 index 00000000..c19a91a4 --- /dev/null +++ b/src/views/login.ecr @@ -0,0 +1,25 @@ +<div class="pure-g"> + <div class="pure-u-1 pure-u-md-1-5"></div> + <div class="pure-u-1 pure-u-md-3-5"> + <div class="h-box"> + <form class="pure-form pure-form-stacked" action="/login" method="post"> + <fieldset> + <legend>Login for Google</legend> + + <label for="email">Email</label> + <input class="pure-input-1" name="email" type="email" placeholder="Email"> + + <label for="password">Password</label> + <input class="pure-input-1" name="password" type="password" placeholder="Password"> + + <label for="remember" class="pure-checkbox"> + <input id="remember" name="remember" type="checkbox"> Remember me + </label> + + <button type="submit" class="pure-button pure-button-primary">Sign in</button> + </fieldset> + </form> + </div> + </div> + <div class="pure-u-1 pure-u-md-1-5"></div> +</div>
\ No newline at end of file |
