add all oauth scopes to mysql (untested, kind of dumb)
This commit is contained in:
1 parent
24701aa9a8
commit
9693bf7704
9 files changed
+225
-43
No files matched your search
@@ -55,30 +55,163 @@ CREATE TABLE twitch_oauth_tokens(
|
||||
-- subsequent time will bump by one. Mostly for debugging.
|
||||
refresh_count INT(10) UNSIGNED DEFAULT 0,
|
||||
|
||||
-- ========== OAUTH SCOPES ==========
|
||||
-- ======================================================
|
||||
-- ==================== OAUTH SCOPES ====================
|
||||
-- ======================================================
|
||||
|
||||
-- TODO: Probably could have stored this in a bitfield. Ugh.
|
||||
|
||||
-- "analytics:read:extensions"
|
||||
-- "View analytics data for the Twitch Extensions owned by the authenticated account."
|
||||
has_analytics_read_extensions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- scope: "analytics:read:games"
|
||||
-- "View analytics data for the games owned by the authenticated account."
|
||||
has_analytics_read_games BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "bits:read"
|
||||
-- "View Bits information for a channel."
|
||||
has_bits_read BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:edit:commercial"
|
||||
-- "Run commercials on a channel."
|
||||
has_channel_edit_commercial BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:manage:broadcast"
|
||||
-- "Manage a channel's broadcast configuration, including updating channel configuration and managing stream markers and stream tags."
|
||||
has_channel_manage_broadcast BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:manage:extensions"
|
||||
-- "Manage a channel's Extension configuration, including activating Extensions."
|
||||
has_channel_manage_extensions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:manage:polls"
|
||||
-- "Manage a channel's polls."
|
||||
has_channel_manage_polls BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:manage:predictions"
|
||||
-- "Manage of channel's Channel Points Predictions"
|
||||
has_channel_manage_predictions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:manage:redemptions"
|
||||
-- "Manage Channel Points custom rewards and their redemptions on a channel."
|
||||
has_channel_manage_redemptions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:manage:schedule"
|
||||
-- "Manage a channel's stream schedule."
|
||||
has_channel_manage_schedule BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:manage:videos"
|
||||
-- "Manage a channel's videos, including deleting videos."
|
||||
has_channel_manage_videos BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:moderate"
|
||||
-- "Perform moderation actions in a channel. The user requesting the scope must be a moderator in the channel."
|
||||
has_channel_moderate BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:editors"
|
||||
-- "View a list of users with the editor role for a channel."
|
||||
has_channel_read_editors BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:goals"
|
||||
-- "View Creator Goals for a channel."
|
||||
has_channel_read_goals BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:hype_train"
|
||||
-- "View Hype Train information for a channel."
|
||||
has_channel_read_hype_train BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:polls"
|
||||
-- "View a channel's polls."
|
||||
has_channel_read_polls BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:predictions"
|
||||
-- "View a channel's Channel Points Predictions."
|
||||
has_channel_read_predictions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:redemptions"
|
||||
-- "View Channel Points custom rewards and their redemptions on a channel."
|
||||
-- eg. PubSub subscribe to `channel-points-channel-v1.<channel_id>` (channel points spends)
|
||||
has_channel_read_redemptions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:stream_key"
|
||||
-- "View an authorized user's stream key."
|
||||
has_channel_read_stream_key BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:subscriptions"
|
||||
-- "View a list of all subscribers to a channel and check if a user is subscribed to a channel."
|
||||
-- eg. Enumerate list of subscribers for a channel
|
||||
-- eg. PubSub subscribe to `channel-subscribe-events-v1.<channel ID>` (subscribe, resubscribe, gift)
|
||||
has_channel_read_subscriptions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "channel:read:redemptions"
|
||||
-- "View Channel Points custom rewards and their redemptions on a channel."
|
||||
-- eg. PubSub subscribe to `channel-points-channel-v1.<channel_id>` (channel points spends)
|
||||
has_channel_read_redemptions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
-- "channel_subscriptions"
|
||||
-- "\\[DEPRECATED\\] Read all subscribers to your channel."
|
||||
has_channel_subscriptions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "chat:edit"
|
||||
-- "Send live stream chat and rooms messages."
|
||||
has_chat_edit BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "chat:read"
|
||||
-- "View live stream chat and rooms messages."
|
||||
has_chat_read BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "clips:edit"
|
||||
-- "Manage Clips for a channel."
|
||||
has_clips_edit BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "moderation:read"
|
||||
-- "View a channel's moderation data including Moderators, Bans, Timeouts, and Automod settings."
|
||||
has_moderation_read BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "moderator:manage:automod"
|
||||
-- "Manage messages held for review by AutoMod in channels where you are a moderator."
|
||||
has_moderator_manage_auto_mod BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:edit"
|
||||
-- "Manage a user object."
|
||||
has_user_edit BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:edit:broadcast"
|
||||
-- "Edit your channel's broadcast configuration, including extension configuration. (This scope implies user:read:broadcast capability.)"
|
||||
has_user_edit_broadcast BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:edit:follows"
|
||||
-- "Edit a user's follows."
|
||||
has_user_edit_follows BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:manage:blocked_users"
|
||||
-- "Manage the block list of a user."
|
||||
has_user_manage_blocked_users BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:read:blocked_users"
|
||||
-- "View the block list of a user."
|
||||
has_user_read_blocked_users BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:read:broadcast"
|
||||
-- "View a user's broadcasting configuration, including Extension configurations."
|
||||
has_user_read_broadcast BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:read:email"
|
||||
-- "Read an authorized user's email address."
|
||||
has_user_read_email BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:read:follows"
|
||||
-- "View the list of channels a user follows."
|
||||
-- eg. We can use this to see if a Twitch user follows us.
|
||||
has_user_read_follows BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "user:read:subscriptions"
|
||||
-- "View if an authorized user is subscribed to specific channels."
|
||||
has_user_read_subscriptions BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- THERE ARE MORE SCOPES... PERHAPS WE SHOULD ADD THEM?
|
||||
-- "whispers:edit"
|
||||
-- "Send whisper messages."
|
||||
has_whispers_edit BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- "whispers:read"
|
||||
-- "View your whisper messages."
|
||||
has_whispers_read BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- ========== SECURITY ==========
|
||||
|
||||
|
||||
@@ -38,10 +38,13 @@ pub struct TwitchOauthTokenInsertBuilder {
|
||||
/// Number of times we've refreshed the token
|
||||
refresh_count: u32,
|
||||
|
||||
// ===== OAuth Scopes =====
|
||||
|
||||
has_bits_read: bool,
|
||||
has_channel_read_subscriptions: bool,
|
||||
has_channel_read_redemptions: bool,
|
||||
has_user_read_follows: bool,
|
||||
has_channel_read_subscriptions: bool,
|
||||
has_chat_edit: bool,
|
||||
has_chat_read: bool,
|
||||
}
|
||||
|
||||
impl TwitchOauthTokenInsertBuilder {
|
||||
@@ -58,7 +61,8 @@ impl TwitchOauthTokenInsertBuilder {
|
||||
has_bits_read: false,
|
||||
has_channel_read_subscriptions: false,
|
||||
has_channel_read_redemptions: false,
|
||||
has_user_read_follows: false,
|
||||
has_chat_edit: false,
|
||||
has_chat_read: false,
|
||||
refresh_count: 0,
|
||||
}
|
||||
}
|
||||
@@ -93,23 +97,28 @@ impl TwitchOauthTokenInsertBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_has_bits_read(mut self, has_bits_read: bool) -> Self {
|
||||
self.has_bits_read = has_bits_read;
|
||||
pub fn has_bits_read(mut self, value: bool) -> Self {
|
||||
self.has_bits_read = value;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn has_channel_read_subscriptions(mut self, channel_read_subscriptions: bool) -> Self {
|
||||
self.has_channel_read_subscriptions = channel_read_subscriptions;
|
||||
pub fn has_channel_read_redemptions(mut self, value: bool) -> Self {
|
||||
self.has_channel_read_redemptions = value;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn has_channel_read_redemptions(mut self, channel_read_redemptions: bool) -> Self {
|
||||
self.has_channel_read_redemptions = channel_read_redemptions;
|
||||
pub fn has_channel_read_subscriptions(mut self, value: bool) -> Self {
|
||||
self.has_channel_read_subscriptions = value;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn has_user_read_follows(mut self, has_user_read_follows: bool) -> Self {
|
||||
self.has_user_read_follows = has_user_read_follows;
|
||||
pub fn has_chat_edit(mut self, value: bool) -> Self {
|
||||
self.has_chat_edit = value;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn has_chat_read(mut self, value: bool) -> Self {
|
||||
self.has_chat_read = value;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -131,9 +140,10 @@ SET
|
||||
token_type = ?,
|
||||
expires_in_seconds = ?,
|
||||
has_bits_read = ?,
|
||||
has_channel_read_subscriptions = ?,
|
||||
has_channel_read_redemptions= ?,
|
||||
has_user_read_follows = ?,
|
||||
has_channel_read_subscriptions = ?,
|
||||
has_chat_edit = ?,
|
||||
has_chat_read = ?,
|
||||
ip_address_creation = ?,
|
||||
expires_at = DATE_ADD(NOW(), INTERVAL ? SECOND)
|
||||
"#,
|
||||
@@ -147,9 +157,10 @@ SET
|
||||
self.token_type.clone(),
|
||||
expires_in_seconds,
|
||||
self.has_bits_read.clone(),
|
||||
self.has_channel_read_subscriptions.clone(),
|
||||
self.has_channel_read_redemptions.clone(),
|
||||
self.has_user_read_follows.clone(),
|
||||
self.has_channel_read_subscriptions.clone(),
|
||||
self.has_chat_edit.clone(),
|
||||
self.has_chat_read.clone(),
|
||||
self.maybe_ip_address_creation.clone(),
|
||||
expires_in_seconds,
|
||||
)
|
||||
@@ -168,9 +179,10 @@ SET
|
||||
token_type = ?,
|
||||
expires_in_seconds = NULL,
|
||||
has_bits_read = ?,
|
||||
has_channel_read_subscriptions = ?,
|
||||
has_channel_read_redemptions= ?,
|
||||
has_user_read_follows = ?,
|
||||
has_channel_read_subscriptions = ?,
|
||||
has_chat_edit = ?,
|
||||
has_chat_read = ?,
|
||||
ip_address_creation = ?,
|
||||
expires_at = NULL
|
||||
"#,
|
||||
@@ -183,9 +195,10 @@ SET
|
||||
self.refresh_count,
|
||||
self.token_type.clone(),
|
||||
self.has_bits_read.clone(),
|
||||
self.has_channel_read_subscriptions.clone(),
|
||||
self.has_channel_read_redemptions.clone(),
|
||||
self.has_user_read_follows.clone(),
|
||||
self.has_channel_read_subscriptions.clone(),
|
||||
self.has_chat_edit.clone(),
|
||||
self.has_chat_read.clone(),
|
||||
self.maybe_ip_address_creation.clone(),
|
||||
)
|
||||
};
|
||||
|
||||
@@ -14,13 +14,53 @@ pub fn get_oauth_token_builder(
|
||||
let client_id = ClientId::new(client_id);
|
||||
let client_secret = ClientSecret::new(client_secret);
|
||||
|
||||
/*
|
||||
- AnalyticsReadExtensions, scope: "analytics:read:extensions", doc: "View analytics data for the Twitch Extensions owned by the authenticated account.";
|
||||
- AnalyticsReadGames, scope: "analytics:read:games", doc: "View analytics data for the games owned by the authenticated account.";
|
||||
[YES] BitsRead, scope: "bits:read", doc: "View Bits information for a channel.";
|
||||
- ChannelEditCommercial, scope: "channel:edit:commercial", doc: "Run commercials on a channel.";
|
||||
- ChannelManageBroadcast, scope: "channel:manage:broadcast", doc: "Manage a channel’s broadcast configuration, including updating channel configuration and managing stream markers and stream tags.";
|
||||
- ChannelManageExtensions, scope: "channel:manage:extensions", doc: "Manage a channel’s Extension configuration, including activating Extensions.";
|
||||
(?) ChannelManagePolls, scope: "channel:manage:polls", doc: "Manage a channel’s polls.";
|
||||
(?) ChannelManagePredictions, scope: "channel:manage:predictions", doc: "Manage of channel’s Channel Points Predictions";
|
||||
- ChannelManageRedemptions, scope: "channel:manage:redemptions", doc: "Manage Channel Points custom rewards and their redemptions on a channel.";
|
||||
- ChannelManageSchedule, scope: "channel:manage:schedule", doc: "Manage a channel’s stream schedule.";
|
||||
- ChannelManageVideos, scope: "channel:manage:videos", doc: "Manage a channel’s videos, including deleting videos.";
|
||||
- ChannelModerate, scope: "channel:moderate", doc: "Perform moderation actions in a channel. The user requesting the scope must be a moderator in the channel.";
|
||||
- ChannelReadEditors, scope: "channel:read:editors", doc: "View a list of users with the editor role for a channel.";
|
||||
- ChannelReadGoals, scope: "channel:read:goals", doc: "View Creator Goals for a channel.";
|
||||
- ChannelReadHypeTrain, scope: "channel:read:hype_train", doc: "View Hype Train information for a channel.";
|
||||
(?) ChannelReadPolls, scope: "channel:read:polls", doc: "View a channel’s polls.";
|
||||
(?) ChannelReadPredictions, scope: "channel:read:predictions", doc: "View a channel’s Channel Points Predictions.";
|
||||
+ ChannelReadRedemptions, scope: "channel:read:redemptions", doc: "View Channel Points custom rewards and their redemptions on a channel.";
|
||||
- ChannelReadStreamKey, scope: "channel:read:stream_key", doc: "View an authorized user’s stream key.";
|
||||
+ ChannelReadSubscriptions, scope: "channel:read:subscriptions", doc: "View a list of all subscribers to a channel and check if a user is subscribed to a channel.";
|
||||
- ChannelSubscriptions, scope: "channel_subscriptions", doc: "\\[DEPRECATED\\] Read all subscribers to your channel.";
|
||||
[YES] ChatEdit, scope: "chat:edit", doc: "Send live stream chat and rooms messages.";
|
||||
[YES] ChatRead, scope: "chat:read", doc: "View live stream chat and rooms messages.";
|
||||
(?) ClipsEdit, scope: "clips:edit", doc: "Manage Clips for a channel.";
|
||||
(?) ModerationRead, scope: "moderation:read", doc: "View a channel’s moderation data including Moderators, Bans, Timeouts, and Automod settings.";
|
||||
(?) ModeratorManageAutoMod, scope: "moderator:manage:automod", doc: "Manage messages held for review by AutoMod in channels where you are a moderator.";
|
||||
- UserEdit, scope: "user:edit", doc: "Manage a user object.";
|
||||
- UserEditBroadcast, scope: "user:edit:broadcast", doc: "Edit your channel's broadcast configuration, including extension configuration. (This scope implies user:read:broadcast capability.)";
|
||||
- UserEditFollows, scope: "user:edit:follows", doc: "Edit a user’s follows.";
|
||||
- UserManageBlockedUsers, scope: "user:manage:blocked_users", doc: "Manage the block list of a user.";
|
||||
- UserReadBlockedUsers, scope: "user:read:blocked_users", doc: "View the block list of a user.";
|
||||
- UserReadBroadcast, scope: "user:read:broadcast", doc: "View a user’s broadcasting configuration, including Extension configurations.";
|
||||
- UserReadEmail, scope: "user:read:email", doc: "Read an authorized user’s email address.";
|
||||
- UserReadFollows, scope: "user:read:follows", doc: "View the list of channels a user follows.";
|
||||
(?) UserReadSubscriptions, scope: "user:read:subscriptions", doc: "View if an authorized user is subscribed to specific channels.";
|
||||
- WhispersEdit, scope: "whispers:edit", doc: "Send whisper messages.";
|
||||
- WhispersRead, scope: "whispers:read", doc: "View your whisper messages.";
|
||||
*/
|
||||
|
||||
UserTokenBuilder::new(client_id, client_secret, redirect_url.clone())
|
||||
.set_scopes(vec![
|
||||
Scope::BitsRead, // Using bits to cheer (cost money, larger streams)
|
||||
Scope::ChannelReadRedemptions, // Channel points redeemed (free points, smaller streams)
|
||||
Scope::ChannelReadSubscriptions,
|
||||
Scope::ChatEdit,
|
||||
Scope::ChatRead,
|
||||
Scope::ChannelReadSubscriptions, // List subscribing (paying) users
|
||||
Scope::ChatEdit, // IRC send
|
||||
Scope::ChatRead, // IRC read
|
||||
])
|
||||
.force_verify(force_verify)
|
||||
}
|
||||
@@ -86,10 +86,6 @@ async fn main() -> AnyhowResult<()> {
|
||||
let website_homepage_redirect =
|
||||
easyenv::get_env_string_or_default("WEBSITE_HOMEPAGE_REDIRECT", "https://vo.codes/");
|
||||
|
||||
let oauth_redirect_url = easyenv::get_env_string_or_default(
|
||||
"TWITCH_OAUTH_REDIRECT_URL",
|
||||
"http://localhost:54321/twitch/oauth_redirect");
|
||||
|
||||
let db_connection_string =
|
||||
easyenv::get_env_string_or_default(
|
||||
"MYSQL_URL",
|
||||
@@ -126,7 +122,6 @@ async fn main() -> AnyhowResult<()> {
|
||||
twitch_oauth_secrets: TwitchOauthSecrets {
|
||||
client_id: twitch_secrets.app_client_id.clone(),
|
||||
client_secret: twitch_secrets.app_client_secret.clone(),
|
||||
redirect_url: oauth_redirect_url,
|
||||
},
|
||||
hostname: server_hostname,
|
||||
backends: BackendsConfig {
|
||||
|
||||
@@ -38,5 +38,4 @@ pub struct EnvConfig {
|
||||
pub struct TwitchOauthSecrets {
|
||||
pub client_id: String,
|
||||
pub client_secret: String,
|
||||
pub redirect_url: String,
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
pub mod oauth_begin;
|
||||
pub mod oauth_begin_json;
|
||||
pub mod oauth_begin_redirect;
|
||||
pub mod oauth_end;
|
||||
+1
-1
@@ -46,7 +46,7 @@ impl ResponseError for OauthBeginEnrollError {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn oauth_begin_enroll(
|
||||
pub async fn oauth_begin_enroll_json(
|
||||
http_request: HttpRequest,
|
||||
server_state: web::Data<Arc<ServerState>>
|
||||
) -> Result<HttpResponse, OauthBeginEnrollError> {
|
||||
@@ -144,10 +144,12 @@ pub async fn oauth_end_enroll_from_redirect(
|
||||
TwitchOauthTokenInsertBuilder::new(&user_id, &twitch_username, &auth_token)
|
||||
.set_expires_in_seconds(Some(expires_seconds))
|
||||
.set_refresh_token(refresh_token.as_deref())
|
||||
.set_ip_address_creation(Some(&ip_address));
|
||||
//.set_user_token()
|
||||
//.set_token_type()
|
||||
//.set_has_bits_read(true) ...
|
||||
.set_ip_address_creation(Some(&ip_address))
|
||||
.has_bits_read(true)
|
||||
.has_channel_read_redemptions(true)
|
||||
.has_channel_read_subscriptions(true)
|
||||
.has_chat_edit(true)
|
||||
.has_chat_read(true);
|
||||
|
||||
let result = insert_builder.insert(&server_state.mysql_pool)
|
||||
.await
|
||||
|
||||
@@ -43,7 +43,7 @@ use crate::http_server::endpoints::tts::get_tts_model_use_count::get_tts_model_u
|
||||
use crate::http_server::endpoints::tts::get_tts_result::get_tts_inference_result_handler;
|
||||
use crate::http_server::endpoints::tts::get_tts_upload_model_job_status::get_tts_upload_model_job_status_handler;
|
||||
use crate::http_server::endpoints::tts::list_tts_models::list_tts_models_handler;
|
||||
use crate::http_server::endpoints::twitch::oauth_begin::oauth_begin_enroll;
|
||||
use crate::http_server::endpoints::twitch::oauth_begin_json::oauth_begin_enroll_json;
|
||||
use crate::http_server::endpoints::twitch::oauth_begin_redirect::oauth_begin_enroll_redirect;
|
||||
use crate::http_server::endpoints::twitch::oauth_end::oauth_end_enroll_from_redirect;
|
||||
use crate::http_server::endpoints::users::create_account::create_account_handler;
|
||||
@@ -539,8 +539,8 @@ fn add_twitch_oauth_routes<T, B> (app: App<T, B>) -> App<T, B>
|
||||
>,
|
||||
{
|
||||
app.service(web::scope("/twitch")
|
||||
.service(web::resource("/oauth_enroll")
|
||||
.route(web::get().to(oauth_begin_enroll))
|
||||
.service(web::resource("/oauth_enroll_json")
|
||||
.route(web::get().to(oauth_begin_enroll_json))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
.service(web::resource("/oauth_enroll_redirect")
|
||||
|
||||
Reference in new issue
Block a user