diff --git a/README.md b/README.md index 970ca779..3dc1fedc 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ docker compose logs -f api # wait for "Application started" SQL Server needs about 2 GB of RAM. Use a plan with at least 4 GB in total. +Security defaults: the API refuses to start outside Development without `JWT_SECRET`; browsers may call the API only from `https://SITE_DOMAIN` (`Cors:AllowedOrigins`); public sign-up is off (`SIGNUP_ENABLED=False`) until SMTP (`SmptConfig__*`) is configured. + ### Load the data 1. Open `https://SITE_DOMAIN/login` and sign in with `ADMIN_EMAIL` and the password **`Test!123`**. The first login creates the admin account with that fixed password (RSecurityBackend's default; upstream's guide is wrong about this). **Change it right away** in the user panel. diff --git a/RMuseum/Startup.cs b/RMuseum/Startup.cs index f37102de..78e3f559 100644 --- a/RMuseum/Startup.cs +++ b/RMuseum/Startup.cs @@ -34,6 +34,7 @@ using RSecurityBackend.Services.Implementation; using RSecurityBackend.Utilities; using Swashbuckle.AspNetCore.Filters; using System; +using System.Linq; using System.IO; using System.Reflection; using System.Text; @@ -51,6 +52,10 @@ namespace RMuseum public IConfiguration Configuration { get; } + private string[] AllowedOrigins => (Configuration["Cors:AllowedOrigins"] ?? "") + .Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) + .Select(o => o.TrimEnd('/')).ToArray(); + // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { @@ -58,7 +63,9 @@ namespace RMuseum services.AddCors(options => { options.AddPolicy("DiwanCorsPolicy", - builder => builder.SetIsOriginAllowed(_ => true) + // diwan: Cors:AllowedOrigins (comma separated, e.g. https://diwan.example) restricts browsers; + // unset = any origin (local development) + builder => builder.SetIsOriginAllowed(origin => AllowedOrigins.Length == 0 || AllowedOrigins.Contains(origin.TrimEnd('/'), StringComparer.OrdinalIgnoreCase)) .AllowAnyMethod() .AllowAnyHeader() .WithExposedHeaders("paging-headers", "audio-upload-enabled", "items-count") @@ -353,6 +360,9 @@ namespace RMuseum // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { + // diwan: never run outside Development with a missing JWT signing secret (upstream shipped a public default) + if (!env.IsDevelopment() && string.IsNullOrWhiteSpace(Configuration["Security:Secret"])) + throw new InvalidOperationException("Security:Secret is not set (env Security__Secret). Refusing to start."); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); diff --git a/RMuseum/appsettings.json b/RMuseum/appsettings.json index aeb8ae42..14487706 100644 --- a/RMuseum/appsettings.json +++ b/RMuseum/appsettings.json @@ -4,7 +4,7 @@ }, "RSecurityBackend": { "ApplicationName": "Diwan", - "FirstUserEmail": "admin@ganjoor.net" + "FirstUserEmail": "admin@diwan.local" }, "BackgroundTaskQueue": { "MaxConcurrency": "1" @@ -27,7 +27,7 @@ } }, "Security": { - "Secret": "k4Fy7pDsc0LgXQ8PCCfZtwmju5Ed8asc", + "Secret": "", "DefaultTokenExpirationInSeconds": "3600", "SessionIdleTimeoutInDays": "90" }, @@ -57,8 +57,8 @@ "ShowAccountInfo": "False" }, "Diwan": { - "SystemEmail": "sys@ganjoor.net", - "DeleteUserEmail": "del@ganjoor.net", + "SystemEmail": "sys@diwan.local", + "DeleteUserEmail": "del@diwan.local", "SitemapLocation": "C:\\inetpub\\diwan\\wwwroot\\sitemap.xml", "GDBStorage": "D:\\My Documents\\My Web Design\\diwan\\www\\i\\android\\sgdb", "GDBStorageImageSource": "D:\\My Documents\\My Web Design\\diwan\\www\\i\\android\\img", @@ -75,7 +75,7 @@ "RemoteUrl": "https://github.com/ganjoor/ganjoor-data.git", "Branch": "main", "CommitAuthorName": "Diwan Export Bot", - "CommitAuthorEmail": "bot@ganjoor.net", + "CommitAuthorEmail": "bot@diwan.local", "PushEnabled": "False", "GitUserName": "", "GitToken": "", diff --git a/docker-compose.yml b/docker-compose.yml index 5f2babf5..fb449c71 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,6 +25,7 @@ services: RSecurityBackend__ApplicationName: Diwan RSecurityBackend__FirstUserEmail: ${ADMIN_EMAIL:?set in .env} SignUp__Enabled: ${SIGNUP_ENABLED:-False} + Cors__AllowedOrigins: https://${SITE_DOMAIN} # only the site may call the API from browsers WebServiceUrl: https://${API_DOMAIN} # Linux paths for upstream's Windows defaults PictureFileService__StoragePath: /data/museum