summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOmar Roth <omarroth@hotmail.com>2018-03-16 11:40:29 -0500
committerOmar Roth <omarroth@hotmail.com>2018-03-16 11:40:29 -0500
commitd8372aa83e910159f9639532023d9bb4d84a1054 (patch)
tree2cba355c0f286b342d45b3f1cf21c588ee5f40be
parente8013c6d5cacc2e57e37bf4692d6a3e1f5526eb8 (diff)
downloadinvidious-d8372aa83e910159f9639532023d9bb4d84a1054.tar.gz
invidious-d8372aa83e910159f9639532023d9bb4d84a1054.tar.bz2
invidious-d8372aa83e910159f9639532023d9bb4d84a1054.zip
Add login page
-rw-r--r--src/helpers.cr18
-rw-r--r--src/invidious.cr82
-rw-r--r--src/views/layout.ecr5
-rw-r--r--src/views/login.ecr25
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