diff --git a/config/config.example.yml b/config/config.example.yml index b564a91d..0f089d99 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -296,8 +296,8 @@ https_only: false #admins: [""] ## -## Force Authentication Backend -## If not provided falls back to the type query parameter +## List of Enabled Authentication Backend +## If not provided falls back to enabling all ## ## Supported Values: ## - invidious @@ -306,21 +306,27 @@ https_only: false ## - ldap (Not implemented !) ## - saml (Not implemented !) ## -## Default: nil +## Default: ["invidious","google","oauth"] ## -# auth_type: oauth +# auth_type: ["oauth"] ## ## OAuth Configuration ## +## Notes: +## - Supports multiple OAuth backends +## - Requires external_port and domain to be configured +## +## Default: [] +## # oauth: -# host: oauth.example.net -# auth_uri: /oauth/authorize -# token_uri: /oauth/token -# info_uri: /oauth/userinfo -# client_id: CLIENT_ID -# client_secret: CLIENT_SECRET -# redirect_uri: https://invidious.example.net/login/oauth +# - host: oauth.example.net +# auth_uri: /oauth/authorize/ +# token_uri: /oauth/token/ +# info_uri: /oauth/userinfo/ +# client_id: CLIENT_ID +# client_secret: CLIENT_SECRET +# redirect_uri: https://invidious.example.net/login/oauth # ----------------------------- diff --git a/src/invidious/config.cr b/src/invidious/config.cr index 0cc43ca3..361c7450 100644 --- a/src/invidious/config.cr +++ b/src/invidious/config.cr @@ -17,7 +17,6 @@ struct OAuthConfig property info_uri : String property client_id : String property client_secret : String - property redirect_uri : String end struct ConfigPreferences @@ -135,8 +134,8 @@ class Config # Use quic transport for youtube api property use_quic : Bool = false - property auth_type : String? = nil - property oauth : OAuthConfig? = nil + property auth_type : Array(String) = ["invidious", "google", "oauth"] of String + property oauth : Array(OAuthConfig) = [] of OAuthConfig # Saved cookies in "name1=value1; name2=value2..." format @[YAML::Field(converter: Preferences::StringToCookies)] diff --git a/src/invidious/helpers/oauth.cr b/src/invidious/helpers/oauth.cr index b5236e74..4dcc8963 100644 --- a/src/invidious/helpers/oauth.cr +++ b/src/invidious/helpers/oauth.cr @@ -1,30 +1,41 @@ -def oauth_get() - if oauth = CONFIG.oauth +def oauth_get(idx) + if HOST_URL == "" + raise Exception.new("Missing domain and port configuration") + end + if idx > CONFIG.oauth.size + raise Exception.new("Invalid OAuth Endpoint Index: " + idx.to_s) + end + + if oauth = CONFIG.oauth[idx] oauth_host = oauth.host oauth_auth_uri = oauth.auth_uri oauth_token_uri = oauth.token_uri oauth_info_uri = oauth.info_uri oauth_client_id = oauth.client_id - oauth_client_secret = oauth.client_secret - oauth_redirect_uri = oauth.redirect_uri - - OAuth2::Client.new(oauth_host, oauth_client_id, oauth_client_secret, - authorize_uri: oauth_auth_uri, token_uri: oauth_token_uri, - redirect_uri: oauth_redirect_uri) + oauth_client_secret = oauth.client_secret + oauth_redirect_uri = HOST_URL + "/login/oauth/" + idx.to_s + + OAuth2::Client.new(oauth_host, oauth_client_id, oauth_client_secret, + authorize_uri: oauth_auth_uri, token_uri: oauth_token_uri, + redirect_uri: oauth_redirect_uri) else raise Exception.new("Missing OAuth Config") end end -def oauth_auth(authorization_code) - oauth_get().get_access_token_using_authorization_code(authorization_code) +def oauth_auth(idx, authorization_code) + oauth_get(idx).get_access_token_using_authorization_code(authorization_code) end -def oauth_info(token) - if oauth = CONFIG.oauth +def oauth_info(idx, token) + if idx > CONFIG.oauth.size + raise Exception.new("Invalid OAuth Endpoint Index: " + idx.to_s) + end + + if oauth = CONFIG.oauth[idx] oauth_host = oauth.host oauth_info_uri = oauth.info_uri - + client = HTTP::Client.new(oauth_host, tls: true) token.authenticate(client) response = client.get oauth_info_uri diff --git a/src/invidious/routes/login.cr b/src/invidious/routes/login.cr index 60c56cbb..39c0c75d 100644 --- a/src/invidious/routes/login.cr +++ b/src/invidious/routes/login.cr @@ -21,10 +21,17 @@ module Invidious::Routes::Login account_type = env.params.query["type"]? account_type ||= "invidious" - if CONFIG.auth_type - account_type = CONFIG.auth_type + if CONFIG.auth_type.find { |i| i == account_type } == nil + if CONFIG.auth_type.size == 0 + account_type = "invidious" + else + account_type = CONFIG.auth_type[0] + end end + oauth = CONFIG.auth_type.find { |i| i == "oauth" } && (CONFIG.oauth.size > 0) + oauth_providers = CONFIG.oauth + captcha_type = env.params.query["captcha"]? captcha_type ||= "image" @@ -43,27 +50,25 @@ module Invidious::Routes::Login referer = get_referer(env, "/feed/subscriptions") authorization_code = env.params.query["code"]? + provider_idx = env.params.url["provider"].to_i if authorization_code begin - token = oauth_auth(authorization_code) - info = JSON.parse(oauth_info(token)) + token = oauth_auth(provider_idx, authorization_code) + info = JSON.parse(oauth_info(provider_idx, token)) + email = info["email"].as_s user = Invidious::Database::Users.select(email: email) if user sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) Invidious::Database::SessionIDs.insert(sid, email) env.response.cookies["SID"] = Invidious::User::Cookies.sid(CONFIG.domain, sid) - + if env.request.cookies["PREFS"]? cookie = env.request.cookies["PREFS"] cookie.expires = Time.utc(1990, 1, 1) env.response.cookies << cookie end else - if !CONFIG.registration_enabled - return error_template(400, "Registration has been disabled by administrator.") - end - sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) user, sid = create_user(sid, email) @@ -91,10 +96,10 @@ module Invidious::Routes::Login env.redirect referer rescue - return error_template(403, "Invalid Authorization Code"); + return error_template(403, "Invalid Authorization Code") end else - return error_template(403, "Missing Authorization Code"); + return error_template(403, "Missing Authorization Code") end end @@ -110,12 +115,18 @@ module Invidious::Routes::Login # https://stackoverflow.com/a/574698 email = env.params.body["email"]?.try &.downcase.byte_slice(0, 254) password = env.params.body["password"]? + oauth = CONFIG.auth_type.find { |i| i == "oauth" } && (CONFIG.oauth.size > 0) + oauth_providers = CONFIG.oauth account_type = env.params.query["type"]? account_type ||= "invidious" - if CONFIG.auth_type - account_type = CONFIG.auth_type + if CONFIG.auth_type.size == 0 + return error_template(401, "No authentication backend enabled.") + end + + if CONFIG.auth_type.find { |i| i == account_type } == nil + account_type = CONFIG.auth_type[0] end case account_type @@ -381,7 +392,8 @@ module Invidious::Routes::Login return error_template(500, error_message) end when "oauth" - env.redirect oauth_get().get_authorize_uri("openid email profile") + provider_idx = env.params.body["provider"].to_i + env.redirect oauth_get(provider_idx).get_authorize_uri("openid email profile") when "saml" return error_template(500, "Not implemented") when "ldap" diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index 00db08bb..9390b4ff 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -13,7 +13,7 @@ end macro define_user_routes # User login/out Invidious::Routing.get "/login", Invidious::Routes::Login, :login_page - Invidious::Routing.get "/login/oauth", Invidious::Routes::Login, :login_oauth + Invidious::Routing.get "/login/oauth/:provider", Invidious::Routes::Login, :login_oauth Invidious::Routing.post "/login", Invidious::Routes::Login, :login Invidious::Routing.post "/signout", Invidious::Routes::Login, :signout Invidious::Routing.get "/Captcha", Invidious::Routes::Login, :captcha diff --git a/src/invidious/users.cr b/src/invidious/users.cr index 1f786c79..3f5474cc 100644 --- a/src/invidious/users.cr +++ b/src/invidious/users.cr @@ -90,7 +90,6 @@ def create_user(sid, email) return user, sid end - def create_user(sid, email, password) password = Crypto::Bcrypt::Password.create(password, cost: 10) token = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) diff --git a/src/invidious/views/user/login.ecr b/src/invidious/views/user/login.ecr index 3cdcf6c6..0e166f79 100644 --- a/src/invidious/views/user/login.ecr +++ b/src/invidious/views/user/login.ecr @@ -46,6 +46,11 @@ <% when "oauth" %>
@@ -110,6 +115,9 @@ <%= translate(locale, "Sign In") %>/<%= translate(locale, "Register") %> <% end %> + <% if oauth %> + OAuth + <% end %> <% end %>