示例#1
0
        /// <summary>
        /// This method gets called by the runtime. Use this method to add services to the container.
        /// </summary>
        /// <param name="services">Service collection.</param>
        public void ConfigureServices(IServiceCollection services)
        {
            // Global JSON options
            JsonSerializerConfig.Configure();

            // Http client factory registration.
            services.AddHttpClient();

            // Add message hub instance
            services.AddSingleton <IMessageHub, MessageHub>();

            // Device configuration from file
            services.AddSingleton <IGoogleDeviceRepository>(serviceProvider =>
            {
                var deviceConfigFile = Configuration.GetValue <string>("deviceConfigFile");
                return(new GoogleDeviceRepository(
                           serviceProvider.GetRequiredService <ILogger <GoogleDeviceRepository> >(),
                           serviceProvider.GetRequiredService <IMessageHub>(),
                           deviceConfigFile));
            });

            // Build state cache from configuration
            services.AddSingleton(serviceProvider =>
            {
                var topics = serviceProvider.GetService <IGoogleDeviceRepository>().GetAll()
                             .Where(device => !device.Disabled)
                             .SelectMany(device => device.Traits)
                             .Where(trait => trait.State != null)
                             .SelectMany(trait => trait.State.Values)
                             .Select(state => state.Topic)
                             .Distinct()
                             .Where(topic => topic != null);

                return(new StateCache(topics.ToDictionary(x => x, x => string.Empty)));
            });

            // Google Home Graph client
            services.AddSingleton <IHostedService, GoogleHomeGraphService>();
            services.AddSingleton(serviceProvider =>
            {
                ServiceAccount serviceAccount    = null;
                var googleHomeServiceAccountFile = Configuration.GetValue <string>("googleHomeGraph:serviceAccountFile");
                if (!string.IsNullOrEmpty(googleHomeServiceAccountFile) && File.Exists(googleHomeServiceAccountFile))
                {
                    var googleHomeServiceAccountFileContents = File.ReadAllText(googleHomeServiceAccountFile);
                    serviceAccount = JsonConvert.DeserializeObject <ServiceAccount>(googleHomeServiceAccountFileContents);
                }

                return(new GoogleHomeGraphClient(
                           serviceProvider.GetRequiredService <ILogger <GoogleHomeGraphClient> >(),
                           serviceProvider.GetRequiredService <IHttpClientFactory>().CreateClient(),
                           serviceAccount,
                           Configuration.GetValue <string>("googleHomeGraph:agentUserId")));
            });

            // Intent handlers
            services.AddTransient <SyncIntentHandler>();
            services.AddTransient <QueryIntentHandler>();
            services.AddTransient <ExecuteIntentHandler>();
            services.AddTransient <DisconnectIntentHandler>();

            // Setup MQTT hosted service
            services.AddSingleton <IHostedService, MqttService>(serviceProvider =>
            {
                var brokerSettings = new Core.BrokerSettings
                {
                    BrokerIp       = Configuration.GetValue <string>("mqtt:brokerIp"),
                    BrokerPort     = Configuration.GetValue <int>("mqtt:brokerPort"),
                    BrokerUsername = Configuration.GetValue <string>("mqtt:brokerUsername"),
                    BrokerPassword = Configuration.GetValue <string>("mqtt:brokerPassword"),
                    BrokerUseTls   = Configuration.GetValue <bool>("mqtt:brokerUseTls", false)
                };

                // TLS settings
                if (brokerSettings.BrokerUseTls)
                {
                    var brokerTlsSettings = new Core.BrokerTlsSettings
                    {
                        AllowUntrustedCertificates        = Configuration.GetValue <bool>("mqtt:brokerTlsSettings:allowUntrustedCertificates", false),
                        IgnoreCertificateChainErrors      = Configuration.GetValue <bool>("mqtt:brokerTlsSettings:ignoreCertificateChainErrors", false),
                        IgnoreCertificateRevocationErrors = Configuration.GetValue <bool>("mqtt:brokerTlsSettings:ignoreCertificateRevocationErrors", false)
                    };

                    switch (Configuration.GetValue <string>("mqtt:brokerTlsSettings:protocol", "1.2"))
                    {
                    case "1.0":
                        brokerTlsSettings.SslProtocol = System.Security.Authentication.SslProtocols.Tls;
                        break;

                    case "1.1":
                        brokerTlsSettings.SslProtocol = System.Security.Authentication.SslProtocols.Tls11;
                        break;

                    case "1.2":
                    default:
                        brokerTlsSettings.SslProtocol = System.Security.Authentication.SslProtocols.Tls12;
                        break;
                    }

                    var brokerTlsCertificatesSection = Configuration.GetSection("mqtt:brokerTlsSettings:certificates");
                    brokerTlsSettings.Certificates   = brokerTlsCertificatesSection.GetChildren()
                                                       .Select(x =>
                    {
                        var file       = x.GetValue <string>("file");
                        var passPhrase = x.GetValue <string>("passPhrase");

                        if (!File.Exists(file))
                        {
                            throw new FileNotFoundException($"Broker Certificate '{file}' is missing!");
                        }

                        return(!string.IsNullOrEmpty(passPhrase) ?
                               new X509Certificate2(file, passPhrase) :
                               new X509Certificate2(file));
                    }).ToList();

                    brokerSettings.BrokerTlsSettings = brokerTlsSettings;
                }

                return(new MqttService(
                           serviceProvider.GetRequiredService <ILogger <MqttService> >(),
                           serviceProvider.GetRequiredService <IMessageHub>(),
                           brokerSettings,
                           serviceProvider.GetRequiredService <IGoogleDeviceRepository>(),
                           serviceProvider.GetRequiredService <StateCache>(),
                           Configuration.GetValue <string>("mqtt:topicRoot", "google/home")));
            });

            // Setup token cleanup hosted service
            services.AddSingleton <IHostedService, TokenCleanupService>();
            services.AddTransient <TokenCleanup>();

            // MVC
            services
            .AddControllersWithViews()
            .AddNewtonsoftJson(opt =>
            {
                opt.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                opt.SerializerSettings.Converters.Add(new StringEnumConverter());
                opt.SerializerSettings.FloatParseHandling = FloatParseHandling.Decimal;
                opt.SerializerSettings.ContractResolver   = new CamelCasePropertyNamesContractResolver {
                    NamingStrategy = new CamelCaseNamingStrategy {
                        ProcessDictionaryKeys = false
                    }
                };
            });

            // Proxy header forwarding
            services.Configure <ForwardedHeadersOptions>(options =>
            {
                options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
                options.KnownNetworks.Clear();
                options.KnownProxies.Clear();
            });

            // Identity Server 4
            services.AddSingleton <IPersistedGrantStoreWithExpiration, PersistedGrantStore>();
            services.AddSingleton <IPersistedGrantStore>(serviceProvider => serviceProvider.GetRequiredService <IPersistedGrantStoreWithExpiration>());
            services.AddTransient <IRefreshTokenService>(serviceProvider => new GracefulRefreshTokenService(
                                                             serviceProvider.GetRequiredService <IRefreshTokenStore>(),
                                                             serviceProvider.GetRequiredService <IProfileService>(),
                                                             serviceProvider.GetRequiredService <ISystemClock>(),
                                                             serviceProvider.GetRequiredService <ILogger <GracefulRefreshTokenService> >(),
                                                             Configuration.GetValue("oauth:refreshTokenGracePeriod", 0)));

            var authority             = Configuration.GetValue <string>("oauth:authority");
            var identityServerBuilder = services
                                        .AddIdentityServer(options =>
            {
                options.IssuerUri = authority;
            })
                                        .AddInMemoryClients(Clients.Get(Configuration))
                                        .AddInMemoryIdentityResources(Resources.GetIdentityResources())
                                        .AddInMemoryApiScopes(Resources.GetApiScopes())
                                        .AddTestUsers(Users.Get(Configuration));

            // Get signing certificates
            var signingCertsSection = Configuration.GetSection("oauth:signingCerts");
            var signingCerts        = signingCertsSection.GetChildren()
                                      .Select(x => new SigningCertificate
            {
                File       = x.GetValue <string>("file"),
                PassPhrase = x.GetValue <string>("passPhrase")
            }).ToList();

            if (signingCerts.Any())
            {
                // Add primary cert
                var primarySigningCert = signingCerts.First();
                if (!File.Exists(primarySigningCert.File))
                {
                    throw new FileNotFoundException($"Signing Certificate '{primarySigningCert.File}' is missing!");
                }

                var cert = !string.IsNullOrEmpty(primarySigningCert.PassPhrase) ?
                           new X509Certificate2(primarySigningCert.File, primarySigningCert.PassPhrase) :
                           new X509Certificate2(primarySigningCert.File);

                identityServerBuilder.AddSigningCredential(cert);

                // Add any verification certs
                for (var i = 1; i < signingCerts.Count; i++)
                {
                    var oldSigningCert = signingCerts[i];
                    if (!File.Exists(oldSigningCert.File))
                    {
                        throw new FileNotFoundException($"Signing Certificate '{oldSigningCert.File}' is missing!");
                    }

                    var oldCert = !string.IsNullOrEmpty(oldSigningCert.PassPhrase) ?
                                  new X509Certificate2(oldSigningCert.File, oldSigningCert.PassPhrase) :
                                  new X509Certificate2(oldSigningCert.File);

                    identityServerBuilder.AddValidationKey(oldCert);
                }
            }
            else
            {
                identityServerBuilder.AddDeveloperSigningCredential(true, "config/tempkey.jwk");
            }

            // Turn on authorization via Cookie (signin, default) and Bearer (API)
            services
            .AddAuthentication(options =>
            {
                options.DefaultChallengeScheme    = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultSignInScheme       = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            })
            .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
            {
                options.LoginPath         = "/Account/Login";
                options.LogoutPath        = "/Account/Logout";
                options.ExpireTimeSpan    = TimeSpan.FromHours(1);
                options.SlidingExpiration = true;
            })
            .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
            {
                options.RequireHttpsMetadata = Configuration.GetValue <bool>("oauth:requireSSL");
                options.Authority            = authority;

                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateAudience = false
                };
            });
        }
示例#2
0
        /// <summary>
        /// Creates an <see cref="IHostBuilder"/>.
        /// </summary>
        /// <param name="config">External configuration.</param>
        /// <returns>A configured <see cref="IHostBuilder"/>.</returns>
        private static IHostBuilder CreateHostBuilder(IConfiguration config)
        {
            return(new HostBuilder()
                   .ConfigureAppConfiguration((hostContext, configuration) => configuration.AddConfiguration(config))
                   .ConfigureLogging((hostingContext, logging) => logging.AddSerilog())
                   .ConfigureServices((hostContext, services) =>
            {
                // Setup client
                services.AddScoped <Client>(serviceProvider =>
                {
                    return new Client(
                        config.GetValue <string>("ecobee:ecobeeAppKey"),
                        ReadTokenFileAsync,
                        WriteTokenFileAsync);
                });

                // Setup service instance
                services.AddScoped <IHostedService, EcobeeMqttService>(serviceProvider =>
                {
                    var brokerSettings = new Core.BrokerSettings
                    {
                        BrokerIp = config.GetValue <string>("mqtt:brokerIp"),
                        BrokerPort = config.GetValue <int>("mqtt:brokerPort"),
                        BrokerUsername = config.GetValue <string>("mqtt:brokerUsername"),
                        BrokerPassword = config.GetValue <string>("mqtt:brokerPassword"),
                        BrokerUseTls = config.GetValue <bool>("mqtt:brokerUseTls", false)
                    };

                    // TLS settings
                    if (brokerSettings.BrokerUseTls)
                    {
                        var brokerTlsSettings = new Core.BrokerTlsSettings
                        {
                            AllowUntrustedCertificates = config.GetValue <bool>("mqtt:brokerTlsSettings:allowUntrustedCertificates", false),
                            IgnoreCertificateChainErrors = config.GetValue <bool>("mqtt:brokerTlsSettings:ignoreCertificateChainErrors", false),
                            IgnoreCertificateRevocationErrors = config.GetValue <bool>("mqtt:brokerTlsSettings:ignoreCertificateRevocationErrors", false)
                        };

                        switch (config.GetValue <string>("mqtt:brokerTlsSettings:protocol", "1.2"))
                        {
                        case "1.0":
                            brokerTlsSettings.SslProtocol = System.Security.Authentication.SslProtocols.Tls;
                            break;

                        case "1.1":
                            brokerTlsSettings.SslProtocol = System.Security.Authentication.SslProtocols.Tls11;
                            break;

                        case "1.2":
                        default:
                            brokerTlsSettings.SslProtocol = System.Security.Authentication.SslProtocols.Tls12;
                            break;
                        }

                        var brokerTlsCertificatesSection = config.GetSection("mqtt:brokerTlsSettings:certificates");
                        brokerTlsSettings.Certificates = brokerTlsCertificatesSection.GetChildren()
                                                         .Select(x =>
                        {
                            var file = x.GetValue <string>("file");
                            var passPhrase = x.GetValue <string>("passPhrase");

                            if (!File.Exists(file))
                            {
                                throw new FileNotFoundException($"Broker Certificate '{file}' is missing!");
                            }

                            return !string.IsNullOrEmpty(passPhrase) ?
                            new X509Certificate2(file, passPhrase) :
                            new X509Certificate2(file);
                        }).ToList();

                        brokerSettings.BrokerTlsSettings = brokerTlsSettings;
                    }

                    string rootPath = config.GetValue <string>("mqtt:brokerRoot");
                    if (rootPath != null && rootPath.EndsWith('/'))
                    {
                        rootPath = rootPath.Substring(0, rootPath.Length - 1);
                    }
                    if (string.IsNullOrWhiteSpace(rootPath))
                    {
                        rootPath = null;
                    }

                    return new EcobeeMqttService(
                        serviceProvider.GetRequiredService <ILogger <EcobeeMqttService> >(),
                        serviceProvider.GetRequiredService <Client>(),
                        config.GetValue <string>("ecobee:ecobeeName"),
                        config.GetValue <int>("ecobee:refreshInterval"),
                        brokerSettings,
                        rootPath);
                });
            }));
        }
示例#3
0
        /// <summary>
        /// Creates an <see cref="IHostBuilder"/>.
        /// </summary>
        /// <param name="config">External configuration.</param>
        /// <returns>A configured <see cref="IHostBuilder"/>.</returns>
        private static IHostBuilder CreateHostBuilder(IConfiguration config)
        {
            return(new HostBuilder()
                   .ConfigureAppConfiguration((hostContext, configuration) => configuration.AddConfiguration(config))
                   .ConfigureLogging((hostingContext, logging) => logging.AddSerilog())
                   .ConfigureServices((hostContext, services) =>
            {
                // Setup client
                services.AddScoped <Client>(serviceProvider =>
                {
                    return new Client(
                        config.GetValue <string>("apex:apexHost"),
                        config.GetValue <string>("apex:apexUsername"),
                        config.GetValue <string>("apex:apexPassword"));
                });

                // Setup service instance
                services.AddScoped <IHostedService, ApexMqttService>(serviceProvider =>
                {
                    var brokerSettings = new Core.BrokerSettings
                    {
                        BrokerIp = config.GetValue <string>("mqtt:brokerIp"),
                        BrokerPort = config.GetValue <int>("mqtt:brokerPort", 1883),
                        BrokerUsername = config.GetValue <string>("mqtt:brokerUsername"),
                        BrokerPassword = config.GetValue <string>("mqtt:brokerPassword"),
                        BrokerUseTls = config.GetValue <bool>("mqtt:brokerUseTls", false)
                    };

                    // TLS settings
                    if (brokerSettings.BrokerUseTls)
                    {
                        var brokerTlsSettings = new Core.BrokerTlsSettings
                        {
                            AllowUntrustedCertificates = config.GetValue <bool>("mqtt:brokerTlsSettings:allowUntrustedCertificates"),
                            IgnoreCertificateChainErrors = config.GetValue <bool>("mqtt:brokerTlsSettings:ignoreCertificateChainErrors"),
                            IgnoreCertificateRevocationErrors = config.GetValue <bool>("mqtt:brokerTlsSettings:ignoreCertificateRevocationErrors")
                        };

                        switch (config.GetValue <string>("mqtt:brokerTlsSettings:protocol", "1.2"))
                        {
                        case "1.0":
                            brokerTlsSettings.SslProtocol = System.Security.Authentication.SslProtocols.Tls;
                            break;

                        case "1.1":
                            brokerTlsSettings.SslProtocol = System.Security.Authentication.SslProtocols.Tls11;
                            break;

                        case "1.2":
                        default:
                            brokerTlsSettings.SslProtocol = System.Security.Authentication.SslProtocols.Tls12;
                            break;
                        }

                        var brokerTlsCertificatesSection = config.GetSection("mqtt:brokerTlsSettings:certificates");
                        brokerTlsSettings.Certificates = brokerTlsCertificatesSection.GetChildren()
                                                         .Select(x =>
                        {
                            var file = x.GetValue <string>("file");
                            var passPhrase = x.GetValue <string>("passPhrase");

                            if (!File.Exists(file))
                            {
                                throw new FileNotFoundException($"Broker Certificate '{file}' is missing!");
                            }

                            return !string.IsNullOrEmpty(passPhrase) ?
                            new X509Certificate2(file, passPhrase) :
                            new X509Certificate2(file);
                        }).ToList();

                        brokerSettings.BrokerTlsSettings = brokerTlsSettings;
                    }

                    return new ApexMqttService(
                        serviceProvider.GetRequiredService <ILogger <ApexMqttService> >(),
                        serviceProvider.GetRequiredService <Client>(),
                        config.GetValue <string>("apex:apexName", "default"),
                        config.GetValue <int>("apex:refreshInterval", 30),
                        config.GetValue <bool>("apex:publishOnlyChangedValues", false),
                        brokerSettings);
                });
            }));
        }