Security pass (#11): no default JWT secret, CORS allow-list, Divan system emails
- appsettings: drop upstream's public JWT secret; API refuses to start outside Development without one - Cors:AllowedOrigins (compose: https://SITE_DOMAIN); unset = any origin for local dev - default admin/system/bot emails @divan.local instead of @ganjoor.net Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
e8cedaab8f
commit
e78fc9bd99
@ -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.
|
||||
|
||||
@ -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("DivanCorsPolicy",
|
||||
builder => builder.SetIsOriginAllowed(_ => true)
|
||||
// divan: Cors:AllowedOrigins (comma separated, e.g. https://divan.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)
|
||||
{
|
||||
// divan: 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();
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
},
|
||||
"RSecurityBackend": {
|
||||
"ApplicationName": "Divan",
|
||||
"FirstUserEmail": "admin@ganjoor.net"
|
||||
"FirstUserEmail": "admin@divan.local"
|
||||
},
|
||||
"BackgroundTaskQueue": {
|
||||
"MaxConcurrency": "1"
|
||||
@ -27,7 +27,7 @@
|
||||
}
|
||||
},
|
||||
"Security": {
|
||||
"Secret": "k4Fy7pDsc0LgXQ8PCCfZtwmju5Ed8asc",
|
||||
"Secret": "",
|
||||
"DefaultTokenExpirationInSeconds": "3600",
|
||||
"SessionIdleTimeoutInDays": "90"
|
||||
},
|
||||
@ -57,8 +57,8 @@
|
||||
"ShowAccountInfo": "False"
|
||||
},
|
||||
"Divan": {
|
||||
"SystemEmail": "sys@ganjoor.net",
|
||||
"DeleteUserEmail": "del@ganjoor.net",
|
||||
"SystemEmail": "sys@divan.local",
|
||||
"DeleteUserEmail": "del@divan.local",
|
||||
"SitemapLocation": "C:\\inetpub\\divan\\wwwroot\\sitemap.xml",
|
||||
"GDBStorage": "D:\\My Documents\\My Web Design\\divan\\www\\i\\android\\sgdb",
|
||||
"GDBStorageImageSource": "D:\\My Documents\\My Web Design\\divan\\www\\i\\android\\img",
|
||||
@ -75,7 +75,7 @@
|
||||
"RemoteUrl": "https://github.com/ganjoor/ganjoor-data.git",
|
||||
"Branch": "main",
|
||||
"CommitAuthorName": "Divan Export Bot",
|
||||
"CommitAuthorEmail": "bot@ganjoor.net",
|
||||
"CommitAuthorEmail": "bot@divan.local",
|
||||
"PushEnabled": "False",
|
||||
"GitUserName": "",
|
||||
"GitToken": "",
|
||||
|
||||
@ -25,6 +25,7 @@ services:
|
||||
RSecurityBackend__ApplicationName: Divan
|
||||
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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user