Add authentication API

This commit is contained in:
Omar Roth
2019-04-18 16:23:50 -05:00
parent 301871aec6
commit 2a6c81a89d
17 changed files with 715 additions and 144 deletions

View File

@@ -0,0 +1,78 @@
<% content_for "header" do %>
<title><%= translate(locale, "Token") %> - Invidious</title>
<% end %>
<% if env.get? "access_token" %>
<div class="pure-g h-box">
<div class="pure-u-1-3">
<h3>
<%= translate(locale, "Token") %>
</h3>
</div>
<div class="pure-u-1-3" style="text-align:center">
<h3>
<a href="/token_manager"><%= translate(locale, "Token manager") %></a>
</h3>
</div>
<div class="pure-u-1-3" style="text-align:right">
<h3>
<a href="/preferences"><%= translate(locale, "Preferences") %></a>
</h3>
</div>
</div>
<div class="h-box">
<h4 style="padding-left:0.5em">
<code><%= env.get "access_token" %></code>
</h4>
</div>
<% else %>
<div class="h-box">
<form class="pure-form pure-form-aligned" action="/authorize_token" method="post">
<% if callback_url %>
<legend><%= translate(locale, "Authorize token for `x`?", "#{callback_url.scheme}://#{callback_url.host}") %></legend>
<% else %>
<legend><%= translate(locale, "Authorize token?") %></legend>
<% end %>
<div class="pure-g">
<div class="pure-u-1">
<ul>
<% scopes.each do |scope| %>
<li><%= scope %></li>
<% end %>
</ul>
</div>
</div>
<div class="pure-g">
<div class="pure-u-1-2">
<button type="submit" name="submit" value="clear_watch_history" class="pure-button pure-button-primary">
<%= translate(locale, "Yes") %>
</button>
</div>
<div class="pure-u-1-2">
<% if callback_url %>
<a class="pure-button" href="<%= callback_url %>">
<% else %>
<a class="pure-button" href="/">
<% end %>
<%= translate(locale, "No") %>
</a>
</div>
</div>
<% scopes.each_with_index do |scope, i| %>
<input type="hidden" name="scopes[<%= i %>]" value="<%= scope %>">
<% end %>
<% if callback_url %>
<input type="hidden" name="callbackUrl" value="<%= callback_url %>">
<% end %>
<% if expire %>
<input type="hidden" name="expire" value="<%= expire %>">
<% end %>
<input type="hidden" name="csrf_token" value="<%= URI.escape(csrf_token) %>">
</form>
</div>
<% end %>

View File

@@ -19,6 +19,6 @@
</div>
</div>
<input type="hidden" name="token" value="<%= URI.escape(token) %>">
<input type="hidden" name="csrf_token" value="<%= URI.escape(csrf_token) %>">
</form>
</div>

View File

@@ -86,7 +86,7 @@
<img class="thumbnail" src="/vi/<%= item.id %>/mqdefault.jpg"/>
<% if env.get? "show_watched" %>
<form onsubmit="return false;" action="/watch_ajax?action_mark_watched=1&id=<%= item.id %>&referer=<%= env.get("current_page") %>" method="post">
<input type="hidden" name="token" value="<%= URI.escape(env.get?("token").try &.as(String) || "") %>">
<input type="hidden" name="csrf_token" value="<%= URI.escape(env.get?("csrf_token").try &.as(String) || "") %>">
<p class="watched">
<a onclick="mark_watched(this)" data-id="<%= item.id %>" href="#">
<button type="submit" style="all:unset">

View File

@@ -2,7 +2,7 @@
<% if subscriptions.includes? ucid %>
<p>
<form onsubmit="return false;" action="/subscription_ajax?action_remove_subscriptions=1&c=<%= ucid %>&referer=<%= env.get("current_page") %>" method="post">
<input type="hidden" name="token" value="<%= URI.escape(env.get?("token").try &.as(String) || "") %>">
<input type="hidden" name="csrf_token" value="<%= URI.escape(env.get?("csrf_token").try &.as(String) || "") %>">
<a id="subscribe" onclick="unsubscribe()" class="pure-button pure-button-primary" href="#">
<b><input style="all:unset" type="submit" value="<%= translate(locale, "Unsubscribe") %> | <%= sub_count_text %>"></b>
</a>
@@ -11,7 +11,7 @@
<% else %>
<p>
<form onsubmit="return false;" action="/subscription_ajax?action_create_subscription_to_channel=1&c=<%= ucid %>&referer=<%= env.get("current_page") %>" method="post">
<input type="hidden" name="token" value="<%= URI.escape(env.get?("token").try &.as(String) || "") %>">
<input type="hidden" name="csrf_token" value="<%= URI.escape(env.get?("csrf_token").try &.as(String) || "") %>">
<a id="subscribe" onclick="subscribe()" class="pure-button pure-button-primary" href="#">
<b><input style="all:unset" type="submit" value="<%= translate(locale, "Subscribe") %> | <%= sub_count_text %>"></b>
</a>

View File

@@ -17,7 +17,7 @@ function subscribe(timeouts = 0) {
xhr.timeout = 20000;
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("token=<%= URI.escape(env.get?("token").try &.as(String) || "") %>");
xhr.send("csrf_token=<%= URI.escape(env.get?("csrf_token").try &.as(String) || "") %>");
var fallback = subscribe_button.innerHTML;
subscribe_button.onclick = unsubscribe;
@@ -53,7 +53,7 @@ function unsubscribe(timeouts = 0) {
xhr.timeout = 20000;
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("token=<%= URI.escape(env.get?("token").try &.as(String) || "") %>");
xhr.send("csrf_token=<%= URI.escape(env.get?("csrf_token").try &.as(String) || "") %>");
var fallback = subscribe_button.innerHTML;
subscribe_button.onclick = subscribe;

View File

@@ -19,6 +19,6 @@
</div>
</div>
<input type="hidden" name="token" value="<%= URI.escape(token) %>">
<input type="hidden" name="csrf_token" value="<%= URI.escape(csrf_token) %>">
</form>
</div>

View File

@@ -29,7 +29,7 @@
<div class="thumbnail">
<img class="thumbnail" src="/vi/<%= item %>/mqdefault.jpg"/>
<form onsubmit="return false;" action="/watch_ajax?action_mark_unwatched=1&id=<%= item %>&referer=<%= env.get("current_page") %>" method="post">
<input type="hidden" name="token" value="<%= URI.escape(env.get?("token").try &.as(String) || "") %>">
<input type="hidden" name="csrf_token" value="<%= URI.escape(env.get?("csrf_token").try &.as(String) || "") %>">
<p class="watched">
<a onclick="mark_unwatched(this)" data-id="<%= item %>" href="#">
<button type="submit" style="all:unset">
@@ -61,7 +61,7 @@ function mark_unwatched(target) {
xhr.timeout = 20000;
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("token=<%= URI.escape(env.get?("token").try &.as(String) || "") %>");
xhr.send("csrf_token=<%= URI.escape(env.get?("csrf_token").try &.as(String) || "") %>");
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {

View File

@@ -216,6 +216,10 @@ function update_value(element) {
<a href="/subscription_manager"><%= translate(locale, "Manage subscriptions") %></a>
</div>
<div class="pure-control-group">
<a href="/token_manager"><%= translate(locale, "Manage tokens") %></a>
</div>
<div class="pure-control-group">
<a href="/feed/history"><%= translate(locale, "Watch history") %></a>
</div>

View File

@@ -8,12 +8,12 @@
<a href="/feed/subscriptions"><%= translate(locale, "`x` subscriptions", %(<span id="count">#{subscriptions.size}</span>)) %></a>
</h3>
</div>
<div class="pure-u-1-3" style="text-align:center;">
<div class="pure-u-1-3" style="text-align:center">
<h3>
<a href="/feed/history"><%= translate(locale, "Watch history") %></a>
</h3>
</div>
<div class="pure-u-1-3" style="text-align:right;">
<div class="pure-u-1-3" style="text-align:right">
<h3>
<a href="/data_control?referer=<%= referer %>"><%= translate(locale, "Import/Export") %></a>
</h3>
@@ -22,17 +22,17 @@
<% subscriptions.each do |channel| %>
<div class="h-box">
<div class="pure-g<% if channel.deleted %> deleted <% end%>">
<div class="pure-g<% if channel.deleted %> deleted <% end %>">
<div class="pure-u-2-5">
<h3 style="padding-left: 0.5em">
<h3 style="padding-left:0.5em">
<a href="/channel/<%= channel.id %>"><%= channel.author %></a>
</h3>
</div>
<div class="pure-u-2-5"></div>
<div class="pure-u-1-5" style="text-align: right;">
<h3 style="padding-right: 0.5em">
<form onsubmit="return false;" action="/subscription_ajax?action_remove_subscriptions=1&c=<%= channel.id %>&referer=<%= env.get("current_page") %>" method="post">
<input type="hidden" name="token" value="<%= URI.escape(env.get?("token").try &.as(String) || "") %>">
<div class="pure-u-1-5" style="text-align:right">
<h3 style="padding-right:0.5em">
<form onsubmit="return false" action="/subscription_ajax?action_remove_subscriptions=1&c=<%= channel.id %>&referer=<%= env.get("current_page") %>" method="post">
<input type="hidden" name="csrf_token" value="<%= URI.escape(env.get?("csrf_token").try &.as(String) || "") %>">
<a onclick="remove_subscription(this)" data-ucid="<%= channel.id %>" href="#">
<input style="all:unset" type="submit" value="<%= translate(locale, "unsubscribe") %>">
</a>
@@ -60,7 +60,7 @@ function remove_subscription(target) {
xhr.timeout = 20000;
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("token=<%= URI.escape(env.get?("token").try &.as(String) || "") %>");
xhr.send("csrf_token=<%= URI.escape(env.get?("csrf_token").try &.as(String) || "") %>");
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {

View File

@@ -62,7 +62,7 @@ function mark_watched(target) {
xhr.timeout = 20000;
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("token=<%= URI.escape(env.get?("token").try &.as(String) || "") %>");
xhr.send("csrf_token=<%= URI.escape(env.get?("csrf_token").try &.as(String) || "") %>");
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {

View File

@@ -70,7 +70,7 @@
</div>
<div class="pure-u-1-4">
<form action="/signout?referer=<%= env.get?("current_page") %>" method="post">
<input type="hidden" name="token" value="<%= URI.escape(env.get?("token").try &.as(String) || "") %>">
<input type="hidden" name="csrf_token" value="<%= URI.escape(env.get?("csrf_token").try &.as(String) || "") %>">
<a class="pure-menu-heading" href="#">
<input style="all:unset" type="submit" value="<%= translate(locale, "Sign out") %>">
</a>

View File

@@ -0,0 +1,72 @@
<% content_for "header" do %>
<title><%= translate(locale, "Token manager") %> - Invidious</title>
<% end %>
<div class="pure-g h-box">
<div class="pure-u-1-3">
<h3>
<%= translate(locale, "`x` tokens", %(<span id="count">#{tokens.size}</span>)) %>
</h3>
</div>
<div class="pure-u-1-3"></div>
<div class="pure-u-1-3" style="text-align:right">
<h3>
<a href="/preferences?referer=<%= referer %>"><%= translate(locale, "Preferences") %></a>
</h3>
</div>
</div>
<% tokens.each do |token| %>
<div class="h-box">
<div class="pure-g<% if token[:session] == sid %> deleted <% end %>">
<div class="pure-u-3-5">
<h4 style="padding-left:0.5em">
<code><%= token[:session] %></code>
</h4>
</div>
<div class="pure-u-1-5" style="text-align:center">
<h4><%= translate(locale, "`x` ago", recode_date(token[:issued], locale)) %></h4>
</div>
<div class="pure-u-1-5" style="text-align:right">
<h3 style="padding-right:0.5em">
<form onsubmit="return false" action="/token_ajax?action_revoke_token=1&session=<%= token[:session] %>&referer=<%= env.get("current_page") %>" method="post">
<input type="hidden" name="csrf_token" value="<%= URI.escape(env.get?("csrf_token").try &.as(String) || "") %>">
<a onclick="revoke_token(this)" data-session="<%= token[:session] %>" href="#">
<input style="all:unset" type="submit" value="<%= translate(locale, "revoke") %>">
</a>
</form>
</h3>
</div>
</div>
<% if tokens[-1].try &.[:session]? != token[:session] %>
<hr>
<% end %>
</div>
<% end %>
<script>
function revoke_token(target) {
var row = target.parentNode.parentNode.parentNode.parentNode.parentNode;
row.style.display = "none";
var count = document.getElementById("count")
count.innerText = count.innerText - 1;
var url = "/token_ajax?action_revoke_token=1&redirect=false&referer=<%= env.get("current_page") %>&session=" + target.getAttribute("data-session");
var xhr = new XMLHttpRequest();
xhr.responseType = "json";
xhr.timeout = 20000;
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("csrf_token=<%= URI.escape(env.get?("csrf_token").try &.as(String) || "") %>");
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status != 200) {
count.innerText = count.innerText - 1 + 2;
row.style.display = "";
}
}
}
}
</script>