Add option for user to delete their account
This commit is contained in:
parent
f988123820
commit
b9c29bf537
|
@ -896,6 +896,7 @@ post "/login" do |env|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# TODO: Update this with using the same method for /clear_watch_history to prevent CSRF
|
||||||
get "/signout" do |env|
|
get "/signout" do |env|
|
||||||
referer = get_referer(env)
|
referer = get_referer(env)
|
||||||
|
|
||||||
|
@ -910,7 +911,7 @@ get "/signout" do |env|
|
||||||
end
|
end
|
||||||
|
|
||||||
env.request.cookies.add_response_headers(env.response.headers)
|
env.request.cookies.add_response_headers(env.response.headers)
|
||||||
env.redirect URI.unescape(referer)
|
env.redirect referer
|
||||||
end
|
end
|
||||||
|
|
||||||
get "/preferences" do |env|
|
get "/preferences" do |env|
|
||||||
|
@ -1402,14 +1403,83 @@ get "/subscription_ajax" do |env|
|
||||||
env.redirect referer
|
env.redirect referer
|
||||||
end
|
end
|
||||||
|
|
||||||
get "/clear_watch_history" do |env|
|
get "/delete_account" do |env|
|
||||||
user = env.get? "user"
|
user = env.get? "user"
|
||||||
|
|
||||||
referer = get_referer(env)
|
referer = get_referer(env)
|
||||||
|
|
||||||
if user
|
if user
|
||||||
user = user.as(User)
|
user = user.as(User)
|
||||||
|
|
||||||
|
challenge, token = create_response(user.email, "delete_account", HMAC_KEY)
|
||||||
|
|
||||||
|
templated "delete_account"
|
||||||
|
else
|
||||||
|
env.redirect referer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
post "/delete_account" do |env|
|
||||||
|
user = env.get? "user"
|
||||||
|
referer = get_referer(env)
|
||||||
|
|
||||||
|
if user
|
||||||
|
user = user.as(User)
|
||||||
|
|
||||||
|
challenge = env.params.body["challenge"]?
|
||||||
|
token = env.params.body["token"]?
|
||||||
|
|
||||||
|
begin
|
||||||
|
validate_response(challenge, token, "delete_account", HMAC_KEY)
|
||||||
|
rescue ex
|
||||||
|
error_message = ex.message
|
||||||
|
next templated "error"
|
||||||
|
end
|
||||||
|
|
||||||
|
view_name = "subscriptions_#{sha256(user.email)[0..7]}"
|
||||||
|
PG_DB.exec("DROP MATERIALIZED VIEW #{view_name}")
|
||||||
|
PG_DB.exec("DELETE FROM users * WHERE email = $1", user.email)
|
||||||
|
|
||||||
|
env.request.cookies.each do |cookie|
|
||||||
|
cookie.expires = Time.new(1990, 1, 1)
|
||||||
|
end
|
||||||
|
env.request.cookies.add_response_headers(env.response.headers)
|
||||||
|
end
|
||||||
|
|
||||||
|
env.redirect referer
|
||||||
|
end
|
||||||
|
|
||||||
|
get "/clear_watch_history" do |env|
|
||||||
|
user = env.get? "user"
|
||||||
|
referer = get_referer(env)
|
||||||
|
|
||||||
|
if user
|
||||||
|
user = user.as(User)
|
||||||
|
|
||||||
|
challenge, token = create_response(user.email, "clear_watch_history", HMAC_KEY)
|
||||||
|
|
||||||
|
templated "clear_watch_history"
|
||||||
|
else
|
||||||
|
env.redirect referer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
post "/clear_watch_history" do |env|
|
||||||
|
user = env.get? "user"
|
||||||
|
referer = get_referer(env)
|
||||||
|
|
||||||
|
if user
|
||||||
|
user = user.as(User)
|
||||||
|
|
||||||
|
challenge = env.params.body["challenge"]?
|
||||||
|
token = env.params.body["token"]?
|
||||||
|
|
||||||
|
begin
|
||||||
|
validate_response(challenge, token, "clear_watch_history", HMAC_KEY)
|
||||||
|
rescue ex
|
||||||
|
error_message = ex.message
|
||||||
|
next templated "error"
|
||||||
|
end
|
||||||
|
|
||||||
PG_DB.exec("UPDATE users SET watched = '{}' WHERE email = $1", user.email)
|
PG_DB.exec("UPDATE users SET watched = '{}' WHERE email = $1", user.email)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -389,3 +389,51 @@ def extract_items(nodeset, ucid = nil)
|
||||||
|
|
||||||
return items
|
return items
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def create_response(user_id, operation, key)
|
||||||
|
nonce = Random::Secure.hex(4)
|
||||||
|
expire = Time.now + 6.hours
|
||||||
|
|
||||||
|
challenge = "#{expire.to_unix}-#{nonce}-#{user_id}-#{operation}"
|
||||||
|
token = OpenSSL::HMAC.digest(:sha256, key, challenge)
|
||||||
|
|
||||||
|
challenge = Base64.urlsafe_encode(challenge)
|
||||||
|
token = Base64.urlsafe_encode(token)
|
||||||
|
|
||||||
|
return challenge, token
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_response(challenge, token, action, key)
|
||||||
|
if !challenge
|
||||||
|
raise "Hidden field \"challenge\" is a required field"
|
||||||
|
end
|
||||||
|
|
||||||
|
if !token
|
||||||
|
raise "Hidden field \"token\" is a required field"
|
||||||
|
end
|
||||||
|
|
||||||
|
challenge = Base64.decode_string(challenge)
|
||||||
|
if challenge.split("-").size == 4
|
||||||
|
expire, nonce, user_id, operation = challenge.split("-")
|
||||||
|
|
||||||
|
expire = expire.to_i?
|
||||||
|
expire ||= 0
|
||||||
|
else
|
||||||
|
raise "Invalid challenge"
|
||||||
|
end
|
||||||
|
|
||||||
|
challenge = OpenSSL::HMAC.digest(:sha256, HMAC_KEY, challenge)
|
||||||
|
challenge = Base64.urlsafe_encode(challenge)
|
||||||
|
|
||||||
|
if challenge != token
|
||||||
|
raise "Invalid token"
|
||||||
|
end
|
||||||
|
|
||||||
|
if operation != action
|
||||||
|
raise "Invalid token"
|
||||||
|
end
|
||||||
|
|
||||||
|
if expire < Time.now.to_unix
|
||||||
|
raise "Token is expired, please try again"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
17
src/invidious/views/clear_watch_history.ecr
Normal file
17
src/invidious/views/clear_watch_history.ecr
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<div class="h-box">
|
||||||
|
<form class="pure-form pure-form-aligned" action="/clear_watch_history?referer=<%= URI.escape(referer) %>" method="post">
|
||||||
|
<legend>Clear watch history?</legend>
|
||||||
|
|
||||||
|
<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">Yes</button>
|
||||||
|
</div>
|
||||||
|
<div class="pure-u-1-2">
|
||||||
|
<a class="pure-button" href="<%= referer %>">No</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="hidden" name="token" value="<%= token %>">
|
||||||
|
<input type="hidden" name="challenge" value="<%= challenge %>">
|
||||||
|
</form>
|
||||||
|
</div>
|
17
src/invidious/views/delete_account.ecr
Normal file
17
src/invidious/views/delete_account.ecr
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<div class="h-box">
|
||||||
|
<form class="pure-form pure-form-aligned" action="/delete_account?referer=<%= URI.escape(referer) %>" method="post">
|
||||||
|
<legend>Delete account?</legend>
|
||||||
|
|
||||||
|
<div class="pure-g">
|
||||||
|
<div class="pure-u-1-2">
|
||||||
|
<button type="submit" name="submit" value="delete_account" class="pure-button pure-button-primary">Yes</button>
|
||||||
|
</div>
|
||||||
|
<div class="pure-u-1-2">
|
||||||
|
<a class="pure-button" href="<%= referer %>">No</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="hidden" name="token" value="<%= token %>">
|
||||||
|
<input type="hidden" name="challenge" value="<%= challenge %>">
|
||||||
|
</form>
|
||||||
|
</div>
|
|
@ -150,17 +150,21 @@ function update_value(element) {
|
||||||
<legend>Data preferences</legend>
|
<legend>Data preferences</legend>
|
||||||
|
|
||||||
<div class="pure-control-group">
|
<div class="pure-control-group">
|
||||||
<a href="/clear_watch_history?referer=<%= referer %>">Clear watch history</a>
|
<a href="/clear_watch_history?referer=<%= URI.escape(referer) %>">Clear watch history</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pure-control-group">
|
<div class="pure-control-group">
|
||||||
<a href="/data_control?referer=<%= referer %>">Import/Export data</a>
|
<a href="/data_control?referer=<%= URI.escape(referer) %>">Import/Export data</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pure-control-group">
|
<div class="pure-control-group">
|
||||||
<a href="/subscription_manager">Manage subscriptions</a>
|
<a href="/subscription_manager">Manage subscriptions</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-control-group">
|
||||||
|
<a href="/delete_account?referer=<%= URI.escape(referer) %>">Delete account</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="pure-controls">
|
<div class="pure-controls">
|
||||||
<button type="submit" class="pure-button pure-button-primary">Save preferences</button>
|
<button type="submit" class="pure-button pure-button-primary">Save preferences</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue