コード例 #1
0
        public async Task CanAuthenticateUsingFluentAPI()
        {
            var handlerMock = new Mock <HttpMessageHandler>();

            handlerMock
            .Protected()
            .Setup <Task <HttpResponseMessage> >(
                "SendAsync",
                ItExpr.IsAny <HttpRequestMessage>(),
                ItExpr.IsAny <CancellationToken>()
                )
            .ReturnsAsync(new HttpResponseMessage()
            {
                StatusCode = HttpStatusCode.OK,
                Content    = new StringContent("{\"access_token\": \"deadbeef\",\"expires_in\": 1000,\"token_type\": \"bearer\"}"),
            })
            .Verifiable();

            var authenticated = Twitch.Authenticate()
                                .FromAppCredentials("test", "test")
                                .WithScope(TwitchConstants.TwitchOAuthScopes.ChatRead)
                                .WithHttpMessageHandler(handlerMock.Object)
                                .Build();

            var message = new HttpRequestMessage();
            await authenticated.AuthenticateMessageAsync(message);

            Assert.Equal("Bearer", message.Headers.Authorization.Scheme);
            Assert.Equal("deadbeef", message.Headers.Authorization.Parameter);
        }
コード例 #2
0
        async Task IChannelGrain.Activate(string userToken)
        {
            var userAuthenticated = Twitch.Authenticate()
                                    .FromOAuthToken(userToken)
                                    .Build();
            var userClient = TwitchAPIClient.CreateFromBase(_appClient, userAuthenticated);
            var validated  = await userClient.ValidateToken();

            if (validated == null || validated.UserId != _channelId || validated.ExpiresIn == 0)
            {
                throw new ArgumentException("Could not validate token");
            }
            _userClient = userClient;

            var channelInfoTask = _userClient.GetChannelInfoAsync(_channelId);
            List <HelixChannelModerator> moderators = new List <HelixChannelModerator>();
            var editorsTask = _userClient.GetHelixChannelEditorsAsync(_channelId);

            await foreach (var moderator in _userClient.EnumerateChannelModeratorsAsync(_channelId))
            {
                moderators.Add(moderator);
            }
            _channelState.State.BroadcasterToken = userToken;
            _channelState.State.Editors          = (await editorsTask).ToList();
            _channelState.State.Moderators       = moderators.ToList();
            await _channelState.WriteStateAsync();

            var editorsTasks = _channelState.State.Editors.Select(editor =>
                                                                  GrainFactory.GetGrain <IUserGrain>(editor.UserId).SetRole(new UserRole
            {
                Role        = ChannelRole.Editor,
                ChannelId   = _channelId,
                ChannelName = _channelInfo.BroadcasterName,
            })
                                                                  );

            var modsTasks = _channelState.State.Moderators.Select(moderator =>
                                                                  GrainFactory.GetGrain <IUserGrain>(moderator.UserId).SetRole(new UserRole
            {
                Role        = ChannelRole.Moderator,
                ChannelId   = _channelId,
                ChannelName = _channelInfo.BroadcasterName,
            })
                                                                  );

            await Task.WhenAll(editorsTasks);

            await Task.WhenAll(modsTasks);

            _channelInfo = await channelInfoTask;
            await RegisterEventSubSubscriptions(CancellationToken.None);
        }
コード例 #3
0
        static async Task Main(string[] args)
        {
            IConfiguration configuration = null;
            var            builder       = new HostBuilder()
                                           .ConfigureLogging(configure =>
            {
                configure.AddConsole();
                configure.SetMinimumLevel(LogLevel.Information);
            })
                                           .ConfigureAppConfiguration(configure =>
            {
                configure.AddUserSecrets <Program>();
                configure.AddEnvironmentVariables();
                configuration = configure.Build();
            })
                                           .ConfigureServices((hostContext, services) =>
            {
                // Configure services
                services.AddHttpClient();
                services.Configure <TwitchApplicationOptions>(configuration.GetSection("twitch"));
                services.Configure <AzureGameLocalizationStoreOptions>(configuration.GetSection("loc:azure"));
                services.AddTransient <TwitchAPIClient>();
                services.AddTransient <IGDBClient>();
                services.AddSingleton <IMemoryCache, MemoryCache>();
                services.AddSingleton <SteamStoreClient>();
                services.AddSingleton <IAuthenticated>(s =>
                                                       Twitch.Authenticate()
                                                       .FromAppCredentials(
                                                           s.GetService <IOptions <TwitchApplicationOptions> >().Value.ClientId,
                                                           s.GetService <IOptions <TwitchApplicationOptions> >().Value.ClientSecret)
                                                       .Build()
                                                       );
                services.AddTransient <IGameLocalizationStore>(services =>
                {
                    var options = services.GetRequiredService <IOptions <AzureGameLocalizationStoreOptions> >();
                    if (string.IsNullOrEmpty(options.Value.StorageConnectionString) || string.IsNullOrEmpty(options.Value.TableName))
                    {
                        return(null);
                    }
                    return(services.GetRequiredService <AzureStorageGameLocalizationStore>());
                });
                services.AddSingleton <AzureStorageGameLocalizationStore>();
            })
                                           .UseConsoleLifetime();

            await builder.RunCommandLineApplicationAsync <Tool>(args);
        }
コード例 #4
0
        static async Task Main(string[] args)
        {
            IConfiguration configuration = null;
            var            builder       = new HostBuilder()
                                           .ConfigureLogging(configure =>
            {
                configure.AddConsole();
            })
                                           .ConfigureAppConfiguration(configure =>
            {
                configure.AddJsonFile("appsettings.json", true);
#if DEBUG
                configure.AddJsonFile("appsettings.Debug.json", true);
#endif
                configure.AddEnvironmentVariables();
                configure.AddUserSecrets <Program>();
                configuration = configure.Build();
            })
                                           .ConfigureServices((hostContext, services) =>
            {
                // Load channels and command configuration from static json file, and inject
                var channelsConfig = new ConfigurationBuilder().AddJsonFile("channels.json").Build();
                IEnumerable <ChannelOptions> channelOptions = new List <ChannelOptions>();
                channelsConfig.GetSection("channels").Bind(channelOptions);
                services.AddTransient <IEnumerable <ChannelOptions> >((_) => channelOptions);

                // Configure services
                services.AddHttpClient();
                services.Configure <TwitchApplicationOptions>(configuration.GetSection("twitch"));
                services.Configure <TwitchChatClientOptions>(configuration.GetSection("twitch").GetSection("IrcOptions"));
                services.AddSingleton <IMessageProcessor, TracingMessageProcessor>();
                services.AddTransient <TwitchChatClient>();
                services.AddTransient <TwitchAPIClient>();
                services.AddTransient <IGDBClient>();
                services.AddSingleton <IMemoryCache, MemoryCache>();
                services.AddSingleton <SteamStoreClient>();
                services.AddSingleton <IGameLocalizationStore, EmbeddedGameLocalizationDb>();
                services.AddTransient <ITwitchCategoryProvider>(s => s.GetRequiredService <PollingTwitchCategoryProvider>());
                services.AddScoped <PollingTwitchCategoryProvider>();
                services.AddSingleton <IAuthenticated>(s =>
                                                       Twitch.Authenticate()
                                                       .FromAppCredentials(
                                                           s.GetService <IOptions <TwitchApplicationOptions> >().Value.ClientId,
                                                           s.GetService <IOptions <TwitchApplicationOptions> >().Value.ClientSecret)
                                                       .Build()
                                                       );
                services.AddSingleton <IBotAuthenticated>(s =>
                                                          Twitch.AuthenticateBot()
                                                          .FromOAuthToken(
                                                              s.GetService <IOptions <TwitchApplicationOptions> >().Value.IrcOptions.OAuthToken)
                                                          .Build()
                                                          );
                services.AddTransient <ITwitchChatClientBuilder>(s =>
                                                                 TwitchChatClientBuilder.Create()
                                                                 .WithOAuthToken(s.GetRequiredService <IOptions <TwitchApplicationOptions> >().Value.IrcOptions.OAuthToken)
                                                                 .WithLoggerFactory(s.GetRequiredService <ILoggerFactory>())
                                                                 );

                // Configure commands
                services.AddCommand <GameSynopsisCommand>("GameSynopsis");
                services.AddCommand <TracingMessageProcessor>("MessageTracer");

                // Add hosted chatbot service
                services.AddSingleton <TwitchChatBot>();
                services.AddHostedService <TwitchChatBot>(s => s.GetRequiredService <TwitchChatBot>());
                services.AddHostedService(services => services.GetRequiredService <PollingTwitchCategoryProvider>());
            })
                                           .UseConsoleLifetime();

            var host = builder.Build();


            var categoryProvider = host.Services.GetRequiredService <PollingTwitchCategoryProvider>();

            categoryProvider.CheckAndSchedule("miekyld");

            var twitchBot = host.Services.GetRequiredService <TwitchChatBot>();

            twitchBot.SetChannel("158511925");
            await twitchBot.RegisterMessageProcessor <GameSynopsisCommand>(new CommandOptions
            {
                Aliases    = new string[] { "jeu", "game" },
                Parameters = new Dictionary <string, string>
                {
                    { "AsReply", bool.TrueString },
                }
            });

            categoryProvider.OnUpdate += async(sender, gameinfo) =>
            {
                var context = new ProcessorContext
                {
                    CategoryId  = gameinfo.TwitchCategoryId,
                    ChannelId   = "158511925",
                    ChannelName = gameinfo.Name,
                    Language    = gameinfo.Language,
                };
                await twitchBot.UpdateContext(context);
            };


            await host.RunAsync();
        }
コード例 #5
0
        void BuildSiloHost()
        {
            var instrumentationKey           = _configuration.GetValue <string>("ApplicationInsights:InstrumentationKey");
            var hostname                     = _configuration.GetValue <string>("HOSTNAME");
            var azureStorageConnectionString = _configuration.GetValue <string>("Storage:AzureStorageConnectionString");
            var redisClusteringUrl           = _configuration.GetValue <string>("REDIS_URL");

            var builder = new SiloHostBuilder()
                          .ConfigureLogging(loggingBuilder =>
            {
                if (!string.IsNullOrEmpty(instrumentationKey))
                {
                    loggingBuilder.AddApplicationInsights(instrumentationKey);
                }
                loggingBuilder.AddConsole();
            })
                          // Configure ClusterId and ServiceId
                          .Configure <ClusterOptions>(options =>
            {
                options.ClusterId = "dev";
                options.ServiceId = "TwitchServices";
            })
                          .AddStartupTask <LoadConfigurationStartupTask>()
                          .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(ChannelGrain).Assembly).WithReferences())
                          // Configure connectivity
                          .ConfigureEndpoints(hostname: hostname, siloPort: 11111, gatewayPort: 30000);

            if (!string.IsNullOrEmpty(azureStorageConnectionString))
            {
                builder.AddAzureTableGrainStorage("profileStore", (AzureTableStorageOptions options) =>
                {
                    options.ConnectionString = azureStorageConnectionString;
                    options.TableName        = "profiles";
                    options.UseJson          = true;
                    options.IndentJson       = false;
                });
                builder.AddAzureTableGrainStorage("channelStore", (AzureTableStorageOptions options) =>
                {
                    options.ConnectionString = azureStorageConnectionString;
                    options.TableName        = "channels";
                    options.UseJson          = true;
                    options.IndentJson       = false;
                });
                builder.AddAzureTableGrainStorage("botSettingsStore", (AzureTableStorageOptions options) =>
                {
                    options.ConnectionString = azureStorageConnectionString;
                    options.TableName        = "botsettings";
                    options.UseJson          = true;
                    options.IndentJson       = false;
                });
                builder.AddCustomCategoriesStorage("customCategoriesStore", (CustomCategoriesStorageOptions options) =>
                {
                    options.ConnectionString = azureStorageConnectionString;
                    options.TableName        = "customcategories";
                });
            }
            else
            {
                builder.AddMemoryGrainStorage("profileStore");
                builder.AddMemoryGrainStorage("channelStore");
                builder.AddMemoryGrainStorage("botSettingsStore");
                builder.AddMemoryGrainStorage("customCategoriesStore");
            }

            if (!string.IsNullOrEmpty(redisClusteringUrl))
            {
                // Use redis clustering when available
                builder.UseRedisClustering(redisClusteringUrl);
            }
            else
            {
                // Use localhost clustering for a single local silo
                builder.UseLocalhostClustering(11111, 30000, null, "TwitchServices", "dev");
            }

            // Temp

            builder.ConfigureServices((context, services) =>
            {
                // Load channels and command configuration from static json file, and inject
                var channelsConfig = new ConfigurationBuilder().AddJsonFile("channels.json").Build();
                IEnumerable <ChannelOptions> channelOptions = new List <ChannelOptions>();
                channelsConfig.GetSection("channels").Bind(channelOptions);
                services.AddTransient <IEnumerable <ChannelOptions> >((_) => channelOptions);

                // Configure services
                services.AddHttpClient();
                services.Configure <TwitchApplicationOptions>(_configuration.GetSection("twitch"));
                services.Configure <TwitchChatClientOptions>(_configuration.GetSection("twitch").GetSection("IrcOptions"));
                services.Configure <AzureGameLocalizationStoreOptions>(_configuration.GetSection("loc:azure"));
                services.AddSingleton <IMessageProcessor, TracingMessageProcessor>();
                services.AddTransient <TwitchChatClient>();
                services.AddTransient <TwitchAPIClient>();
                services.AddTransient <IGDBClient>();
                services.AddSingleton <IMemoryCache, MemoryCache>();
                services.AddSingleton <SteamStoreClient>();
                services.AddSingleton <IAuthenticated>(s =>
                                                       Twitch.Authenticate()
                                                       .FromAppCredentials(
                                                           s.GetService <IOptions <TwitchApplicationOptions> >().Value.ClientId,
                                                           s.GetService <IOptions <TwitchApplicationOptions> >().Value.ClientSecret)
                                                       .Build()
                                                       );
                services.AddTransient <ITwitchCategoryProvider, GrainTwitchCategoryProvider>();
                services.AddSingleton <IGameLocalizationStore, AzureStorageGameLocalizationStore>();
                services.PostConfigure <TwitchChatClientOptions>(options =>
                {
                    var oauth = Twitch.Authenticate()
                                .FromOAuthToken(options.OAuthToken)
                                .Build();
                    var loggerFactory = new LoggerFactory();
                    using (var httpClient = new HttpClient())
                        using (var apiClient = TwitchAPIClient.Create(oauth))
                        {
                            options.TokenInfo = apiClient.ValidateToken().Result;
                        }
                });

                // Configure commands
                services.AddCommand <GameSynopsisCommand>("GameSynopsis");
                services.AddCommand <TracingMessageProcessor>("Logger");
                services.AddCommand <ResponseCommandProcessor>("Response");
            });
            _siloHost = builder.Build();
        }
コード例 #6
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo {
                    Title = "BlipBloopWeb", Version = "v1"
                });
            });
            services.AddApplicationInsightsTelemetry();

            services.AddTransient <IClientBuilder>(services =>
            {
                var builder = new ClientBuilder()
                              // Clustering information
                              .Configure <ClusterOptions>(options =>
                {
                    options.ClusterId = "dev";
                    options.ServiceId = "TwitchServices";
                })
                              .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(IChannelGrain).Assembly));

                var redisClusteringUrl = Configuration.GetValue <string>("REDIS_URL");
                if (!string.IsNullOrEmpty(redisClusteringUrl))
                {
                    builder.UseRedisClustering(redisClusteringUrl);
                }
                else
                {
                    builder.UseLocalhostClustering();
                }
                return(builder);
            });
            services.AddSingleton <IClientProvider, GrainClientProvider>();

            // Load config, mainly the EventSub secret used for registration
            services.Configure <EventSubOptions>(Configuration.GetSection("twitch:EventSub"));
            // Add the EventSub handler instance to DI
            services.AddEventSub();
            // Register an EventSub event Handler for channel.update events
            services.AddEventSubHandler <TwitchEventSubChannelUpdateEvent>(async(context, eventSub) =>
            {
                context.Logger.LogInformation("Received a channel update for {channelName}, streaming {category} - {text}", eventSub.BroadcasterUserName, eventSub.CategoryName, eventSub.Title);

                var grainClientProvider = context.Services.GetRequiredService <IClientProvider>();
                var grainClient         = await grainClientProvider.GetConnectedClient();
                var helixInfo           = new HelixChannelInfo
                {
                    BroadcasterId       = eventSub.BroadcasterUserId,
                    BroadcasterName     = eventSub.BroadcasterUserName,
                    BroadcasterLanguage = eventSub.Language,
                    GameId   = eventSub.CategoryId,
                    GameName = eventSub.CategoryName,
                    Title    = eventSub.Title,
                };
                var channelGrain = grainClient.GetGrain <IChannelGrain>(helixInfo.BroadcasterId);
                await channelGrain.OnChannelUpdate(helixInfo);
            });

            var twitchOptions = Configuration.GetSection("twitch").Get <TwitchApplicationOptions>();

            services.AddTransient <IAuthenticated>(services =>
                                                   Twitch.Authenticate()
                                                   .FromAppCredentials(twitchOptions.ClientId, twitchOptions.ClientSecret)
                                                   .Build());
            services.AddSingleton <TwitchAPIClient>();
            services.Configure <AzureGameLocalizationStoreOptions>(Configuration.GetSection("loc:azure"));
            services.AddSingleton <IGameLocalizationStore, AzureStorageGameLocalizationStore>();
            services.AddHttpClient();

            Action <TwitchConstants.TwitchOAuthScopes[], string, OpenIdConnectOptions> configureTwitchOpenId = (scopes, callbackPath, options) =>
            {
                options.Authority = "https://id.twitch.tv/oauth2";
                //options.MetadataAddress = "https://id.twitch.tv/oauth2/.well-known/openid-configuration";
                options.ClientId     = twitchOptions.ClientId;
                options.ClientSecret = twitchOptions.ClientSecret;
                options.ResponseType = "token id_token";
                options.ResponseMode = "form_post";
                options.CallbackPath = callbackPath;
                options.Events.OnRedirectToIdentityProvider = (context) =>
                {
                    context.ProtocolMessage.RedirectUri = context.ProtocolMessage.RedirectUri + "-fragment";
                    return(Task.CompletedTask);
                };
                options.Events.OnTokenValidated = (context) =>
                {
                    ClaimsIdentity identity = context.Principal.Identity as ClaimsIdentity;
                    identity.AddClaim(new Claim("access_token", context.ProtocolMessage.AccessToken));
                    identity.AddClaim(new Claim("id_token", context.ProtocolMessage.IdToken));

                    foreach (var scope in scopes)
                    {
                        identity.AddClaim(new Claim("scope", TwitchConstants.ScopesValues[scope]));
                    }

                    return(Task.CompletedTask);
                };
                options.Scope.Remove("profile");

                foreach (var scope in scopes)
                {
                    options.Scope.Add(TwitchConstants.ScopesValues[scope]);
                }
            };

            // Identity
            services
            .AddAuthentication(options =>
            {
                options.DefaultScheme          = "cookie";
                options.DefaultChallengeScheme = "twitch";
            })
            .AddCookie("cookie", options =>
            {
                options.Events.OnRedirectToLogin = context =>
                {
                    if (context.Request.Path.StartsWithSegments("/api"))
                    {
                        context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                    }
                    else
                    {
                        context.Response.Redirect(context.RedirectUri);
                    }

                    return(Task.CompletedTask);
                };
            })
            .AddOpenIdConnect("twitch", "Twitch", options => configureTwitchOpenId(new TwitchConstants.TwitchOAuthScopes[] {
                TwitchConstants.TwitchOAuthScopes.ChannelReadEditors,
                TwitchConstants.TwitchOAuthScopes.ModerationRead,
                TwitchConstants.TwitchOAuthScopes.UserReadBlockedUsers,
                TwitchConstants.TwitchOAuthScopes.UserReadBroadcast,
                TwitchConstants.TwitchOAuthScopes.UserReadSubscriptions,
                TwitchConstants.TwitchOAuthScopes.ChatRead,
            }, "/signin-oidc", options))
            .AddOpenIdConnect("twitchBot", "Twitch - Bot Account", options => configureTwitchOpenId(new TwitchConstants.TwitchOAuthScopes[] {
                TwitchConstants.TwitchOAuthScopes.ChannelReadEditors,
                TwitchConstants.TwitchOAuthScopes.ModerationRead,
                TwitchConstants.TwitchOAuthScopes.UserReadBlockedUsers,
                TwitchConstants.TwitchOAuthScopes.UserReadBroadcast,
                TwitchConstants.TwitchOAuthScopes.ChatRead,
                TwitchConstants.TwitchOAuthScopes.ChatEdit,
                TwitchConstants.TwitchOAuthScopes.UserEditFollows,
            }, "/signin-oidc-bot", options));

            services.AddRazorPages();
            services.AddServerSideBlazor();
            services.AddMudServices();
            services.AddAuthorizationCore();
        }