@@ -364,16 +364,30 @@ end
364364 Invidious ::Routing .get " /results" , Invidious ::Routes ::Search , :results
365365 Invidious ::Routing .get " /search" , Invidious ::Routes ::Search , :search
366366
367+ # User login/out
367368 Invidious ::Routing .get " /login" , Invidious ::Routes ::Login , :login_page
368369 Invidious ::Routing .post " /login" , Invidious ::Routes ::Login , :login
369370 Invidious ::Routing .post " /signout" , Invidious ::Routes ::Login , :signout
370371
372+ # User preferences
371373 Invidious ::Routing .get " /preferences" , Invidious ::Routes ::PreferencesRoute , :show
372374 Invidious ::Routing .post " /preferences" , Invidious ::Routes ::PreferencesRoute , :update
373375 Invidious ::Routing .get " /toggle_theme" , Invidious ::Routes ::PreferencesRoute , :toggle_theme
374376 Invidious ::Routing .get " /data_control" , Invidious ::Routes ::PreferencesRoute , :data_control
375377 Invidious ::Routing .post " /data_control" , Invidious ::Routes ::PreferencesRoute , :update_data_control
376378
379+ # User account management
380+ Invidious ::Routing .get " /change_password" , Invidious ::Routes ::Account , :get_change_password
381+ Invidious ::Routing .post " /change_password" , Invidious ::Routes ::Account , :post_change_password
382+ Invidious ::Routing .get " /delete_account" , Invidious ::Routes ::Account , :get_delete
383+ Invidious ::Routing .post " /delete_account" , Invidious ::Routes ::Account , :post_delete
384+ Invidious ::Routing .get " /clear_watch_history" , Invidious ::Routes ::Account , :get_clear_history
385+ Invidious ::Routing .post " /clear_watch_history" , Invidious ::Routes ::Account , :post_clear_history
386+ Invidious ::Routing .get " /authorize_token" , Invidious ::Routes ::Account , :get_authorize_token
387+ Invidious ::Routing .post " /authorize_token" , Invidious ::Routes ::Account , :post_authorize_token
388+ Invidious ::Routing .get " /token_manager" , Invidious ::Routes ::Account , :token_manager
389+ Invidious ::Routing .post " /token_ajax" , Invidious ::Routes ::Account , :token_ajax
390+
377391 # Feeds
378392 Invidious ::Routing .get " /view_all_playlists" , Invidious ::Routes ::Feeds , :view_all_playlists_redirect
379393 Invidious ::Routing .get " /feed/playlists" , Invidious ::Routes ::Feeds , :playlists
@@ -412,325 +426,6 @@ define_v1_api_routes()
412426define_api_manifest_routes()
413427define_video_playback_routes()
414428
415- get " /change_password" do |env |
416- locale = env.get(" preferences" ).as(Preferences ).locale
417-
418- user = env.get? " user"
419- sid = env.get? " sid"
420- referer = get_referer(env)
421-
422- if ! user
423- next env.redirect referer
424- end
425-
426- user = user.as(User )
427- sid = sid.as(String )
428- csrf_token = generate_response(sid, {" :change_password" }, HMAC_KEY )
429-
430- templated " change_password"
431- end
432-
433- post " /change_password" do |env |
434- locale = env.get(" preferences" ).as(Preferences ).locale
435-
436- user = env.get? " user"
437- sid = env.get? " sid"
438- referer = get_referer(env)
439-
440- if ! user
441- next env.redirect referer
442- end
443-
444- user = user.as(User )
445- sid = sid.as(String )
446- token = env.params.body[" csrf_token" ]?
447-
448- # We don't store passwords for Google accounts
449- if ! user.password
450- next error_template(400 , " Cannot change password for Google accounts" )
451- end
452-
453- begin
454- validate_request(token, sid, env.request, HMAC_KEY , locale)
455- rescue ex
456- next error_template(400 , ex)
457- end
458-
459- password = env.params.body[" password" ]?
460- if ! password
461- next error_template(401 , " Password is a required field" )
462- end
463-
464- new_passwords = env.params.body.select { |k , v | k.match(/^new_password\[\d +\] $/ ) }.map { |k , v | v }
465-
466- if new_passwords.size <= 1 || new_passwords.uniq.size != 1
467- next error_template(400 , " New passwords must match" )
468- end
469-
470- new_password = new_passwords.uniq[0 ]
471- if new_password.empty?
472- next error_template(401 , " Password cannot be empty" )
473- end
474-
475- if new_password.bytesize > 55
476- next error_template(400 , " Password cannot be longer than 55 characters" )
477- end
478-
479- if ! Crypto ::Bcrypt ::Password .new(user.password.not_nil!).verify(password.byte_slice(0 , 55 ))
480- next error_template(401 , " Incorrect password" )
481- end
482-
483- new_password = Crypto ::Bcrypt ::Password .create(new_password, cost: 10 )
484- Invidious ::Database ::Users .update_password(user, new_password.to_s)
485-
486- env.redirect referer
487- end
488-
489- get " /delete_account" do |env |
490- locale = env.get(" preferences" ).as(Preferences ).locale
491-
492- user = env.get? " user"
493- sid = env.get? " sid"
494- referer = get_referer(env)
495-
496- if ! user
497- next env.redirect referer
498- end
499-
500- user = user.as(User )
501- sid = sid.as(String )
502- csrf_token = generate_response(sid, {" :delete_account" }, HMAC_KEY )
503-
504- templated " delete_account"
505- end
506-
507- post " /delete_account" do |env |
508- locale = env.get(" preferences" ).as(Preferences ).locale
509-
510- user = env.get? " user"
511- sid = env.get? " sid"
512- referer = get_referer(env)
513-
514- if ! user
515- next env.redirect referer
516- end
517-
518- user = user.as(User )
519- sid = sid.as(String )
520- token = env.params.body[" csrf_token" ]?
521-
522- begin
523- validate_request(token, sid, env.request, HMAC_KEY , locale)
524- rescue ex
525- next error_template(400 , ex)
526- end
527-
528- view_name = " subscriptions_#{ sha256(user.email) } "
529- Invidious ::Database ::Users .delete(user)
530- Invidious ::Database ::SessionIDs .delete(email: user.email)
531- PG_DB .exec(" DROP MATERIALIZED VIEW #{ view_name } " )
532-
533- env.request.cookies.each do |cookie |
534- cookie.expires = Time .utc(1990 , 1 , 1 )
535- env.response.cookies << cookie
536- end
537-
538- env.redirect referer
539- end
540-
541- get " /clear_watch_history" do |env |
542- locale = env.get(" preferences" ).as(Preferences ).locale
543-
544- user = env.get? " user"
545- sid = env.get? " sid"
546- referer = get_referer(env)
547-
548- if ! user
549- next env.redirect referer
550- end
551-
552- user = user.as(User )
553- sid = sid.as(String )
554- csrf_token = generate_response(sid, {" :clear_watch_history" }, HMAC_KEY )
555-
556- templated " clear_watch_history"
557- end
558-
559- post " /clear_watch_history" do |env |
560- locale = env.get(" preferences" ).as(Preferences ).locale
561-
562- user = env.get? " user"
563- sid = env.get? " sid"
564- referer = get_referer(env)
565-
566- if ! user
567- next env.redirect referer
568- end
569-
570- user = user.as(User )
571- sid = sid.as(String )
572- token = env.params.body[" csrf_token" ]?
573-
574- begin
575- validate_request(token, sid, env.request, HMAC_KEY , locale)
576- rescue ex
577- next error_template(400 , ex)
578- end
579-
580- Invidious ::Database ::Users .clear_watch_history(user)
581- env.redirect referer
582- end
583-
584- get " /authorize_token" do |env |
585- locale = env.get(" preferences" ).as(Preferences ).locale
586-
587- user = env.get? " user"
588- sid = env.get? " sid"
589- referer = get_referer(env)
590-
591- if ! user
592- next env.redirect referer
593- end
594-
595- user = user.as(User )
596- sid = sid.as(String )
597- csrf_token = generate_response(sid, {" :authorize_token" }, HMAC_KEY )
598-
599- scopes = env.params.query[" scopes" ]?.try & .split(" ," )
600- scopes ||= [] of String
601-
602- callback_url = env.params.query[" callback_url" ]?
603- if callback_url
604- callback_url = URI .parse(callback_url)
605- end
606-
607- expire = env.params.query[" expire" ]?.try & .to_i?
608-
609- templated " authorize_token"
610- end
611-
612- post " /authorize_token" do |env |
613- locale = env.get(" preferences" ).as(Preferences ).locale
614-
615- user = env.get? " user"
616- sid = env.get? " sid"
617- referer = get_referer(env)
618-
619- if ! user
620- next env.redirect referer
621- end
622-
623- user = env.get(" user" ).as(User )
624- sid = sid.as(String )
625- token = env.params.body[" csrf_token" ]?
626-
627- begin
628- validate_request(token, sid, env.request, HMAC_KEY , locale)
629- rescue ex
630- next error_template(400 , ex)
631- end
632-
633- scopes = env.params.body.select { |k , v | k.match(/^scopes\[\d +\] $/ ) }.map { |k , v | v }
634- callback_url = env.params.body[" callbackUrl" ]?
635- expire = env.params.body[" expire" ]?.try & .to_i?
636-
637- access_token = generate_token(user.email, scopes, expire, HMAC_KEY )
638-
639- if callback_url
640- access_token = URI .encode_www_form(access_token)
641- url = URI .parse(callback_url)
642-
643- if url.query
644- query = HTTP ::Params .parse(url.query.not_nil!)
645- else
646- query = HTTP ::Params .new
647- end
648-
649- query[" token" ] = access_token
650- url.query = query.to_s
651-
652- env.redirect url.to_s
653- else
654- csrf_token = " "
655- env.set " access_token" , access_token
656- templated " authorize_token"
657- end
658- end
659-
660- get " /token_manager" do |env |
661- locale = env.get(" preferences" ).as(Preferences ).locale
662-
663- user = env.get? " user"
664- sid = env.get? " sid"
665- referer = get_referer(env, " /subscription_manager" )
666-
667- if ! user
668- next env.redirect referer
669- end
670-
671- user = user.as(User )
672- tokens = Invidious ::Database ::SessionIDs .select_all(user.email)
673-
674- templated " token_manager"
675- end
676-
677- post " /token_ajax" do |env |
678- locale = env.get(" preferences" ).as(Preferences ).locale
679-
680- user = env.get? " user"
681- sid = env.get? " sid"
682- referer = get_referer(env)
683-
684- redirect = env.params.query[" redirect" ]?
685- redirect ||= " true"
686- redirect = redirect == " true"
687-
688- if ! user
689- if redirect
690- next env.redirect referer
691- else
692- next error_json(403 , " No such user" )
693- end
694- end
695-
696- user = user.as(User )
697- sid = sid.as(String )
698- token = env.params.body[" csrf_token" ]?
699-
700- begin
701- validate_request(token, sid, env.request, HMAC_KEY , locale)
702- rescue ex
703- if redirect
704- next error_template(400 , ex)
705- else
706- next error_json(400 , ex)
707- end
708- end
709-
710- if env.params.query[" action_revoke_token" ]?
711- action = " action_revoke_token"
712- else
713- next env.redirect referer
714- end
715-
716- session = env.params.query[" session" ]?
717- session ||= " "
718-
719- case action
720- when .starts_with? " action_revoke_token"
721- Invidious ::Database ::SessionIDs .delete(sid: session, email: user.email)
722- else
723- next error_json(400 , " Unsupported action #{ action } " )
724- end
725-
726- if redirect
727- env.redirect referer
728- else
729- env.response.content_type = " application/json"
730- " {}"
731- end
732- end
733-
734429# Channels
735430
736431{" /channel/:ucid/live" , " /user/:user/live" , " /c/:user/live" }.each do |route |
0 commit comments