Пример #1
0
    private static async Task UpdateMasterGames()
    {
        _awsRegion  = ConfigurationManager.AppSettings["awsRegion"] !;
        _betaBucket = ConfigurationManager.AppSettings["betaBucket"] !;
        _productionReadOnlyConnectionString = ConfigurationManager.AppSettings["productionConnectionString"] !;
        _betaConnectionString = ConfigurationManager.AppSettings["betaConnectionString"] !;

        DapperNodaTimeSetup.Register();

        MySQLFantasyCriticUserStore productionUserStore      = new MySQLFantasyCriticUserStore(_productionReadOnlyConnectionString, _clock);
        MySQLFantasyCriticUserStore betaUserStore            = new MySQLFantasyCriticUserStore(_betaConnectionString, _clock);
        MySQLMasterGameRepo         productionMasterGameRepo = new MySQLMasterGameRepo(_productionReadOnlyConnectionString, productionUserStore);
        MySQLMasterGameRepo         betaMasterGameRepo       = new MySQLMasterGameRepo(_betaConnectionString, betaUserStore);
        MySQLBetaCleaner            cleaner = new MySQLBetaCleaner(_betaConnectionString);
        AdminService betaAdminService       = GetAdminService();

        _logger.Info("Getting master games from production");
        var productionMasterGameTags = await productionMasterGameRepo.GetMasterGameTags();

        var productionMasterGames = await productionMasterGameRepo.GetMasterGames();

        var betaMasterGameTags = await betaMasterGameRepo.GetMasterGameTags();

        var betaMasterGames = await betaMasterGameRepo.GetMasterGames();

        IReadOnlyList <MasterGameHasTagEntity> productionGamesHaveTagEntities = await GetProductionGamesHaveTagEntities();

        await cleaner.UpdateMasterGames(productionMasterGameTags, productionMasterGames, betaMasterGameTags,
                                        betaMasterGames, productionGamesHaveTagEntities);

        await betaAdminService.RefreshCaches();
    }
Пример #2
0
    private static AdminService GetAdminService()
    {
        FantasyCriticUserManager userManager             = null !;
        IFantasyCriticUserStore  betaUserStore           = new MySQLFantasyCriticUserStore(_betaConnectionString, _clock);
        IMasterGameRepo          masterGameRepo          = new MySQLMasterGameRepo(_betaConnectionString, betaUserStore);
        IFantasyCriticRepo       fantasyCriticRepo       = new MySQLFantasyCriticRepo(_betaConnectionString, betaUserStore, masterGameRepo);
        InterLeagueService       interLeagueService      = new InterLeagueService(fantasyCriticRepo, masterGameRepo);
        LeagueMemberService      leagueMemberService     = new LeagueMemberService(null !, fantasyCriticRepo, _clock);
        GameAcquisitionService   gameAcquisitionService  = new GameAcquisitionService(fantasyCriticRepo, masterGameRepo, leagueMemberService, _clock);
        ActionProcessingService  actionProcessingService = new ActionProcessingService(gameAcquisitionService);
        FantasyCriticService     fantasyCriticService    = new FantasyCriticService(leagueMemberService, interLeagueService, fantasyCriticRepo, _clock);
        IOpenCriticService       openCriticService       = null !;
        IGGService         ggService         = null !;
        PatreonService     patreonService    = null !;
        IRDSManager        rdsManager        = null !;
        RoyaleService      royaleService     = null !;
        IHypeFactorService hypeFactorService = new LambdaHypeFactorService(_awsRegion, _betaBucket);

        AdminServiceConfiguration configuration = new AdminServiceConfiguration(true);
        var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
        var realHypeConstantsEnvironments = new List <string>()
        {
            "STAGING", "PRODUCTION"
        };

        if (environment is not null && realHypeConstantsEnvironments.Contains(environment.ToUpper()))
        {
            configuration = new AdminServiceConfiguration(false);
        }

        return(new AdminService(fantasyCriticService, userManager, fantasyCriticRepo, masterGameRepo, interLeagueService,
                                openCriticService, ggService, patreonService, _clock, rdsManager, royaleService, hypeFactorService, configuration, actionProcessingService));
    }
Пример #3
0
    private static async Task RefreshAndCleanDatabase()
    {
        var productionRDSName = ConfigurationManager.AppSettings["productionRDSName"] !;
        var betaRDSName       = ConfigurationManager.AppSettings["betaRDSName"] !;

        DapperNodaTimeSetup.Register();

        RDSRefresher rdsRefresher = new RDSRefresher(productionRDSName, betaRDSName);
        await rdsRefresher.CopySourceToDestination();

        MySQLFantasyCriticUserStore betaUserStore = new MySQLFantasyCriticUserStore(_betaConnectionString, _clock);
        MySQLBetaCleaner            cleaner       = new MySQLBetaCleaner(_betaConnectionString);

        _logger.Info("Cleaning emails/passwords for non-beta users");
        var allUsers = await betaUserStore.GetAllUsers();

        var betaUsers = await betaUserStore.GetUsersInRoleAsync("BetaTester", CancellationToken.None);

        await cleaner.CleanEmailsAndPasswords(allUsers, betaUsers);
    }
Пример #4
0
    public static WebApplication ConfigureServices(this WebApplicationBuilder builder)
    {
        var env = builder.Environment;

        if (env.IsDevelopment())
        {
            _logger.Info("Startup: Running in Development mode.");
        }
        else
        {
            _logger.Info("Startup: Running in Production mode.");
        }

        var    configuration   = builder.Configuration;
        var    services        = builder.Services;
        IClock clock           = NodaTime.SystemClock.Instance;
        var    rdsInstanceName = configuration["AWS:rdsInstanceName"];
        var    awsRegion       = configuration["AWS:region"];
        var    awsBucket       = configuration["AWS:bucket"];
        var    mailgunAPIKey   = configuration["Mailgun:apiKey"];
        var    baseAddress     = configuration["BaseAddress"];
        var    jwtSecret       = configuration["Authentication:JWTSecret"];
        var    duendeLicense   = configuration["IdentityServer:License"];

        var identityConfig = new IdentityConfig(baseAddress, configuration["IdentityServer:MainSecret"], configuration["IdentityServer:CertificateKey"]);

        // Add application services.
        services.AddHttpClient();
        services.AddTransient <IClock>(factory => clock);

        //MySQL Repos
        string connectionString = configuration.GetConnectionString("DefaultConnection");

        var userStore = new MySQLFantasyCriticUserStore(connectionString, clock);
        var roleStore = new MySQLFantasyCriticRoleStore(connectionString);

        services.AddScoped <IFantasyCriticUserStore>(factory => userStore);
        services.AddScoped <IFantasyCriticRoleStore>(factory => roleStore);
        services.AddScoped <RepositoryConfiguration>(factory => new RepositoryConfiguration(connectionString, clock));
        services.AddScoped <IUserStore <FantasyCriticUser>, MySQLFantasyCriticUserStore>(factory => userStore);
        services.AddScoped <IRoleStore <FantasyCriticRole>, MySQLFantasyCriticRoleStore>(factory => roleStore);

        services.AddScoped <IMasterGameRepo>(factory => new MySQLMasterGameRepo(connectionString, userStore));
        services.AddScoped <IFantasyCriticRepo>(factory => new MySQLFantasyCriticRepo(connectionString, userStore, new MySQLMasterGameRepo(connectionString, userStore)));
        services.AddScoped <IRoyaleRepo>(factory => new MySQLRoyaleRepo(connectionString, userStore, new MySQLMasterGameRepo(connectionString, userStore),
                                                                        new MySQLFantasyCriticRepo(connectionString, userStore, new MySQLMasterGameRepo(connectionString, userStore))));

        services.AddScoped <PatreonService>(factory => new PatreonService(
                                                configuration["PatreonService:AccessToken"],
                                                configuration["PatreonService:RefreshToken"],
                                                configuration["Authentication:Patreon:ClientId"],
                                                configuration["PatreonService:CampaignID"]
                                                ));

        services.AddScoped <EmailSendingServiceConfiguration>(_ => new EmailSendingServiceConfiguration(baseAddress, env.IsProduction()));

        services.AddScoped <IHypeFactorService>(factory => new LambdaHypeFactorService(awsRegion, awsBucket));
        services.AddScoped <IRDSManager>(factory => new RDSManager(rdsInstanceName));
        services.AddScoped <FantasyCriticUserManager>();
        services.AddScoped <FantasyCriticRoleManager>();
        services.AddScoped <GameAcquisitionService>();
        services.AddScoped <LeagueMemberService>();
        services.AddScoped <PublisherService>();
        services.AddScoped <InterLeagueService>();
        services.AddScoped <DraftService>();
        services.AddScoped <GameSearchingService>();
        services.AddScoped <ActionProcessingService>();
        services.AddScoped <FantasyCriticService>();
        services.AddScoped <RoyaleService>();
        services.AddScoped <EmailSendingService>();

        services.AddScoped <IEmailSender>(factory => new MailGunEmailSender("fantasycritic.games", mailgunAPIKey, "*****@*****.**", "Fantasy Critic"));

        AdminServiceConfiguration adminServiceConfiguration = new AdminServiceConfiguration(true);

        if (env.IsProduction() || env.IsStaging())
        {
            adminServiceConfiguration = new AdminServiceConfiguration(false);
        }
        services.AddScoped <AdminServiceConfiguration>(_ => adminServiceConfiguration);
        services.AddScoped <AdminService>();

        services.AddHttpClient <IOpenCriticService, OpenCriticService>(client =>
        {
            client.BaseAddress = new Uri("https://api.opencritic.com/api/");
        });
        services.AddHttpClient <IGGService, GGService>(client =>
        {
            client.BaseAddress = new Uri("https://api.ggapp.io/");
        });

        //Add scheduled tasks & scheduler
        services.AddSingleton <IScheduledTask, RefreshDataTask>();
        services.AddSingleton <IScheduledTask, TimeFlagsTask>();
        services.AddSingleton <IScheduledTask, PatreonUpdateTask>();
        services.AddSingleton <IScheduledTask, EmailSendingTask>();
        services.AddScheduler((sender, args) =>
        {
            args.SetObserved();
        });

        services.AddIdentity <FantasyCriticUser, FantasyCriticRole>(options =>
        {
            options.SignIn.RequireConfirmedAccount = false;
            var letters  = "abcdefghijklmnopqrstuvwxyz";
            var numbers  = "0123456789";
            var specials = "-._@+ ";
            options.User.AllowedUserNameCharacters = letters + letters.ToUpper() + numbers + specials;
        })
        .AddUserManager <FantasyCriticUserManager>()
        .AddRoleManager <FantasyCriticRoleManager>()
        .AddDefaultTokenProviders();

        var identityServerBuilder = services.AddIdentityServer(options =>
        {
            options.LicenseKey = duendeLicense;
            options.Events.RaiseErrorEvents       = true;
            options.Events.RaiseInformationEvents = true;
            options.Events.RaiseFailureEvents     = true;
            options.Events.RaiseSuccessEvents     = true;

            // see https://docs.duendesoftware.com/identityserver/v6/fundamentals/resources/
            options.EmitStaticAudienceClaim = true;
        })
                                    .AddPersistedGrantStore <MySQLPersistedGrantStore>()
                                    .AddInMemoryIdentityResources(IdentityConfig.IdentityResources)
                                    .AddInMemoryApiScopes(IdentityConfig.APIScopes)
                                    .AddInMemoryApiResources(IdentityConfig.APIResources)
                                    .AddInMemoryClients(identityConfig.Clients)
                                    .AddAspNetIdentity <FantasyCriticUser>();

        services.AddLocalApiAuthentication();

        if (env.IsDevelopment())
        {
            identityServerBuilder.AddDeveloperSigningCredential();
        }
        else
        {
            identityServerBuilder.AddSigningCredential($"CN={identityConfig.KeyName}");
        }

        services.AddAuthentication()
        .AddCookie(options =>
        {
            options.Cookie.Name       = "FantasyCriticCookie";
            options.LoginPath         = "/Identity/Account/Login";
            options.LogoutPath        = "/Identity/Account/Logout";
            options.ExpireTimeSpan    = TimeSpan.FromDays(30);
            options.SlidingExpiration = true;    // the cookie would be re-issued on any request half way through the ExpireTimeSpan
        })
        .AddGoogle(options =>
        {
            options.ClientId     = configuration["Authentication:Google:ClientId"];
            options.ClientSecret = configuration["Authentication:Google:ClientSecret"];
        })
        .AddMicrosoftAccount(microsoftOptions =>
        {
            microsoftOptions.AuthorizationEndpoint = "https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize";
            microsoftOptions.TokenEndpoint         = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token";
            microsoftOptions.ClientId     = configuration["Authentication:Microsoft:ClientId"];
            microsoftOptions.ClientSecret = configuration["Authentication:Microsoft:ClientSecret"];
        })
        .AddTwitch(options =>
        {
            options.ClientId     = configuration["Authentication:Twitch:ClientId"];
            options.ClientSecret = configuration["Authentication:Twitch:ClientSecret"];
        })
        .AddPatreon(options =>
        {
            options.ClientId     = configuration["Authentication:Patreon:ClientId"];
            options.ClientSecret = configuration["Authentication:Patreon:ClientSecret"];
        })
        .AddDiscord(options =>
        {
            options.ClientId     = configuration["Authentication:Discord:ClientId"];
            options.ClientSecret = configuration["Authentication:Discord:ClientSecret"];
        });

        builder.Services.ConfigureApplicationCookie(options =>
        {
            options.Events = SPACookieOptions.GetModifiedEvents(options.Events);
        });

        services.AddDataProtection()
        .PersistKeysToFileSystem(new DirectoryInfo(@"C:\FantasyCritic\Keys\"));

        services.AddHsts(options =>
        {
            options.Preload           = true;
            options.IncludeSubDomains = true;
            options.MaxAge            = TimeSpan.FromDays(60);
        });

        services.AddHttpsRedirection(options =>
        {
            options.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect;
            options.HttpsPort          = 443;
        });

        services.AddControllers()
        .AddNewtonsoftJson(options =>
        {
            options.SerializerSettings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
        });

        services.AddRazorPages();
        services.AddSignalR();

        // In production, the Vue files will be served from this directory
        services.AddSpaStaticFiles(staticFileOptions =>
        {
            staticFileOptions.RootPath = GetSPAPath(env);
        });

        return(builder.Build());
    }
Пример #5
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            _logger.LogInformation("Initializing services.");

            int    validMinutes = Convert.ToInt32(Configuration["Tokens:ValidMinutes"]);
            var    keyString    = Configuration["Tokens:Key"];
            var    issuer       = Configuration["Tokens:Issuer"];
            var    audience     = Configuration["Tokens:Audience"];
            IClock clock        = SystemClock.Instance;

            var rdsInstanceName = Configuration["AWS:rdsInstanceName"];

            // Add application services.

            var tokenService = new TokenService(keyString, issuer, audience, validMinutes);
            SendGridEmailSender sendGridEmailSender = new SendGridEmailSender();

            services.AddHttpClient();

            //Repository Setup. Uncomment either the MySQL section OR the fake repo section. Not both.
            //MySQL Repos
            string connectionString = Configuration.GetConnectionString("DefaultConnection");
            var    userStore        = new MySQLFantasyCriticUserStore(connectionString, clock);
            var    roleStore        = new MySQLFantasyCriticRoleStore(connectionString);

            services.AddScoped <IFantasyCriticUserStore>(factory => userStore);
            services.AddScoped <IFantasyCriticRoleStore>(factory => roleStore);
            services.AddScoped <IMasterGameRepo>(factory => new MySQLMasterGameRepo(connectionString, userStore));
            services.AddScoped <IFantasyCriticRepo>(factory => new MySQLFantasyCriticRepo(connectionString, userStore, new MySQLMasterGameRepo(connectionString, userStore)));
            services.AddScoped <IRoyaleRepo>(factory => new MySQLRoyaleRepo(connectionString, userStore, new MySQLMasterGameRepo(connectionString, userStore),
                                                                            new MySQLFantasyCriticRepo(connectionString, userStore, new MySQLMasterGameRepo(connectionString, userStore))));
            services.AddScoped <IUserStore <FantasyCriticUser> >(factory => userStore);
            services.AddScoped <IRoleStore <FantasyCriticRole> >(factory => roleStore);

            //Fake Repos (for testing without a database)
            //var userStore = new FakeFantasyCriticUserStore(clock);
            //var roleStore = new FakeFantasyCriticRoleStore();
            //services.AddScoped<IFantasyCriticUserStore>(factory => userStore);
            //services.AddScoped<IFantasyCriticRoleStore>(factory => roleStore);
            //services.AddScoped<IMasterGameRepo>(factory => new FakeMasterGameRepo(userStore));
            //services.AddScoped<IFantasyCriticRepo>(factory => new FakeFantasyCriticRepo(userStore, new FakeMasterGameRepo(userStore)));
            //services.AddScoped<IRoyaleRepo>(factory => new FakeRoyaleRepo(userStore, new FakeMasterGameRepo(userStore)));
            //services.AddScoped<IUserStore<FantasyCriticUser>>(factory => userStore);
            //services.AddScoped<IRoleStore<FantasyCriticRole>>(factory => roleStore);

            services.AddScoped <IRDSManager>(factory => new RDSManager(rdsInstanceName));
            services.AddScoped <FantasyCriticUserManager>();
            services.AddScoped <FantasyCriticRoleManager>();
            services.AddScoped <GameAcquisitionService>();
            services.AddScoped <LeagueMemberService>();
            services.AddScoped <PublisherService>();
            services.AddScoped <InterLeagueService>();
            services.AddScoped <DraftService>();
            services.AddScoped <GameSearchingService>();
            services.AddScoped <ActionProcessingService>();
            services.AddScoped <FantasyCriticService>();
            services.AddScoped <RoyaleService>();

            services.AddTransient <IEmailSender>(factory => sendGridEmailSender);
            services.AddTransient <ISMSSender, SMSSender>();
            services.AddTransient <ITokenService>(factory => tokenService);
            services.AddTransient <IClock>(factory => clock);
            services.AddHttpClient <IOpenCriticService, OpenCriticService>();

            services.AddHttpClient <IOpenCriticService, OpenCriticService>(client =>
            {
                client.BaseAddress = new Uri("https://api.opencritic.com/api/");
            });

            services.AddScoped <AdminService>();

            //Add scheduled tasks & scheduler
            services.AddSingleton <IScheduledTask, RefreshDataTask>();
            services.AddScheduler((sender, args) =>
            {
                _logger.LogError(args.Exception.Message);
                args.SetObserved();
            });

            services.AddIdentity <FantasyCriticUser, FantasyCriticRole>(options =>
            {
                options.Password.RequireDigit           = false;
                options.Password.RequiredLength         = 8;
                options.Password.RequireLowercase       = false;
                options.Password.RequireNonAlphanumeric = false;
                options.Password.RequireUppercase       = false;
            })
            .AddDefaultTokenProviders();

            services.ConfigureApplicationCookie(opt =>
            {
                opt.ExpireTimeSpan = TimeSpan.FromMinutes(validMinutes);
                opt.Events.OnRedirectToAccessDenied = ReplaceRedirector(HttpStatusCode.Forbidden, opt.Events.OnRedirectToAccessDenied);
                opt.Events.OnRedirectToLogin        = ReplaceRedirector(HttpStatusCode.Unauthorized, opt.Events.OnRedirectToLogin);
            });

            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(cfg =>
            {
                cfg.TokenValidationParameters = new TokenValidationParameters()
                {
                    ValidIssuer      = issuer,
                    ValidAudience    = audience,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(keyString))
                };

                // We have to hook the OnMessageReceived event in order to
                // allow the JWT authentication handler to read the access
                // token from the query string when a WebSocket or
                // Server-Sent Events request comes in.
                cfg.Events = new JwtBearerEvents
                {
                    OnMessageReceived = context =>
                    {
                        var accessToken = context.Request.Query["access_token"];

                        // If the request is for our hub...
                        var path = context.HttpContext.Request.Path;
                        if (!string.IsNullOrEmpty(accessToken) &&
                            (path.StartsWithSegments("/updatehub")))
                        {
                            // Read the token out of the query string
                            context.Token = accessToken;
                        }
                        return(Task.CompletedTask);
                    }
                };
            });

            services.AddHsts(options =>
            {
                options.Preload           = true;
                options.IncludeSubDomains = true;
                options.MaxAge            = TimeSpan.FromDays(60);
            });

            services.AddHttpsRedirection(options =>
            {
                options.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect;
                options.HttpsPort          = 443;
            });


            // Add framework services.
            services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
            .AddJsonOptions(options =>
            {
                options.SerializerSettings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
            });

            services.AddSignalR();
        }