Merge pull request #4 from Sea-Haven-Industries/fix/remove-hardcoded-secrets

fix(security): remove hardcoded secrets from source
This commit is contained in:
Adam Moussa 2026-06-05 12:00:30 -04:00 • committed by GitHub
commit 047ad23c81
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 118 additions and 40 deletions

34
.env.example Normal file
View file

@ -0,0 +1,34 @@
# Sea Haven Industries — shoc-backend required configuration
#
# This file documents the secrets that used to be hardcoded in appsettings*.json
# and source files. Copy the values into one of the supported configuration sources;
# do NOT commit real values.
#
# .NET resolves configuration in this order (later wins):
# 1. appsettings.json / appsettings.{Environment}.json (committed — placeholders only)
# 2. User Secrets (local dev): dotnet user-secrets set "Key:Sub" "value"
# 3. Environment variables (use "__" as the section separator)
#
# Environment-variable form is shown below. In AWS Elastic Beanstalk these map to
# environment properties; locally you can export them or use dotnet user-secrets.
#
# AWS credentials for the S3 client are NOT listed here on purpose: UploadFileHp now
# uses the AWS SDK default credential chain (env AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY,
# the shared profile/SSO, or the EC2/ECS instance role). Prefer an instance role in prod.
# --- SQL Server connection string (Api.SeaHavenIndustries + SeaHavenIndustries) ---
ConnectionStrings__DefaultConnection=Server=<host>;Initial Catalog=<db>;User Id=<user>;Password=<password>;MultipleActiveResultSets=true
# --- SendGrid (transactional email) ---
SendGrid__ApiKey=SG.xxxxxxxxxxxxxxxxxxxxxx
# --- JWT signing secret (Api.SeaHavenIndustries) ---
JWT__Secret=<a-long-random-secret>
# --- Google Maps / Places API key (SeaHavenIndustries Blazor app) ---
GoogleMaps__ApiKey=AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# --- AWS S3 (optional; prefer instance role / SSO over static keys) ---
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=
# AWS_REGION=us-east-2

View file

@ -27,19 +27,19 @@ namespace Api.SeaHavenIndustries.Helper
//mail.Body = body;
//mail.IsBodyHtml = true;
//SmtpClient smtp = new SmtpClient("mail.codevoir.com");
//NetworkCredential Credentials = new NetworkCredential("infoesquall@codevoir.com", "Abc123!@#");
//NetworkCredential Credentials = new NetworkCredential("<smtp-user>", "<smtp-password>");
//smtp.UseDefaultCredentials = false;
//smtp.Credentials = Credentials;
//smtp.Port = 8889; //25 alternative port number is 8889
//smtp.EnableSsl = false;
//smtp.Send(mail);
//var apiKey = Environment.GetEnvironmentVariable("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\r\n");
//var apiKey1 = Environment.GetEnvironmentVariable("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");
//var apiKey = Environment.GetEnvironmentVariable("<SENDGRID_API_KEY>\r\n");
//var apiKey1 = Environment.GetEnvironmentVariable("<SENDGRID_API_KEY>");
// var apiKey2 = Environment.GetEnvironmentVariable("SENDGRID_API_KEY");
var apiKey = _configuration.GetValue<string>("SendGrid:ApiKey");
//var apiKey = "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";
//var apiKey = "<SENDGRID_API_KEY>";
var client = new SendGridClient(apiKey);
var from = new EmailAddress("tech@seahavenind.com", "Sea haven Industries");
//var subject = "Sending with SendGrid is Fun";
@ -65,7 +65,7 @@ namespace Api.SeaHavenIndustries.Helper
var apiKey = _configuration.GetValue<string>("SendGrid:ApiKey");
//var apiKey = "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";
//var apiKey = "<SENDGRID_API_KEY>";
var client = new SendGridClient(apiKey);
var from = new EmailAddress("tech@seahavenind.com", "Sea haven Industries");
//var subject = "Sending with SendGrid is Fun";

View file

@ -2,11 +2,10 @@
"ConnectionStrings": {
//"DefaultConnection": "Server=DESKTOP-64LC14O\SQLEXPRESS;Database=SeahavenIndustries;TrustServerCertificate=True;Trusted_Connection=True;MultipleActiveResultSets=true",
// Test database
//"DefaultConnection": "Server=SQL5112.site4now.net;Initial Catalog=db_a7141e_seahavenindustries;User Id=db_a7141e_seahavenindustries_admin;Password=Abc123!@#;MultipleActiveResultSets=true"
//Client Database
"DefaultConnection": "Server=SQL5112.site4now.net;Initial Catalog=db_a7141e_seahavenindustry;User Id=db_a7141e_seahavenindustry_admin;Password=Abc123!@#;MultipleActiveResultSets=true"
// Provide the real value via environment variable ConnectionStrings__DefaultConnection or user-secrets.
// Do NOT commit credentials. This file is committed, so keep only the placeholder here.
"DefaultConnection": "${CONNECTION_STRING}"
},
"Logging": {
"LogLevel": {
@ -15,12 +14,14 @@
}
},
"SendGrid": {
"ApiKey": "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"
// Provide the real value via environment variable SendGrid__ApiKey or user-secrets.
"ApiKey": "${SENDGRID_API_KEY}"
},
"AllowedHosts": "*",
"JWT": {
"ValidAudience": "http://localhost:4200",
"ValidIssuer": "http://localhost:7195",
"Secret": "JWTAuthenticationHIGHsecuredPasswordVVVp1OH7Xzyr"
// Provide the real value via environment variable JWT__Secret or user-secrets.
"Secret": "${JWT_SECRET}"
}
}

View file

@ -1,6 +1,8 @@
{
"ConnectionStrings": {
"DefaultConnection": "Server=SQL5112.site4now.net;Initial Catalog=db_a7141e_seahavenindustry;User Id=db_a7141e_seahavenindustry_admin;Password=Abc123!@#;MultipleActiveResultSets=true"
// Provide the real value via environment variable ConnectionStrings__DefaultConnection
// (e.g. Elastic Beanstalk environment property) or the instance secret store. Do NOT commit credentials.
"DefaultConnection": "${CONNECTION_STRING}"
},
"Logging": {
"LogLevel": {
@ -9,12 +11,14 @@
}
},
"SendGrid": {
"ApiKey": "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"
// Provide the real value via environment variable SendGrid__ApiKey or the instance secret store.
"ApiKey": "${SENDGRID_API_KEY}"
},
"AllowedHosts": "*",
"JWT": {
"ValidAudience": "http://console.seahavenind.com",
"ValidIssuer": "http://console.seahavenind.com",
"Secret": "JWTAuthenticationHIGHsecuredPasswordVVVp1OH7Xzyr"
// Provide the real value via environment variable JWT__Secret or the instance secret store.
"Secret": "${JWT_SECRET}"
}
}

View file

@ -2,11 +2,10 @@
"ConnectionStrings": {
//"DefaultConnection": "Server=DESKTOP-64LC14O\SQLEXPRESS;Database=SeahavenIndustries;TrustServerCertificate=True;Trusted_Connection=True;MultipleActiveResultSets=true",
// Test database
//"DefaultConnection": "Server=SQL5112.site4now.net;Initial Catalog=db_a7141e_seahavenindustries;User Id=db_a7141e_seahavenindustries_admin;Password=Abc123!@#;MultipleActiveResultSets=true"
//Client Database
"DefaultConnection": "Server=SQL5112.site4now.net;Initial Catalog=db_a7141e_seahavenindustry;User Id=db_a7141e_seahavenindustry_admin;Password=Abc123!@#;MultipleActiveResultSets=true"
// Provide the real value via environment variable ConnectionStrings__DefaultConnection,
// user-secrets, or appsettings.Development.json (which is gitignored). Do NOT commit credentials.
"DefaultConnection": "${CONNECTION_STRING}"
},
"Logging": {
"LogLevel": {
@ -15,12 +14,14 @@
}
},
"SendGrid": {
"ApiKey": "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"
// Provide the real value via environment variable SendGrid__ApiKey or user-secrets.
"ApiKey": "${SENDGRID_API_KEY}"
},
"AllowedHosts": "*",
"JWT": {
"ValidAudience": "http://localhost:4200",
"ValidIssuer": "http://localhost:7195",
"Secret": "JWTAuthenticationHIGHsecuredPasswordVVVp1OH7Xzyr"
// Provide the real value via environment variable JWT__Secret or user-secrets.
"Secret": "${JWT_SECRET}"
}
}

View file

@ -529,3 +529,36 @@ See these files for complete examples:
- **Asset**: `AssetController.cs`, `AssetService.cs`, `AssetDataService.cs`
All follow the same Clean Architecture pattern!
---
## 🔐 Configuration & Secrets
No secrets are stored in source. The committed `appsettings*.json` files hold only
`${PLACEHOLDER}` tokens; real values must be supplied at runtime through one of the
standard .NET configuration sources (later sources win):
1. `appsettings.json` / `appsettings.{Environment}.json` — committed, placeholders only.
2. **User Secrets** (local dev): `dotnet user-secrets set "Section:Key" "value"`.
3. **Environment variables** — use `__` (double underscore) as the section separator.
In AWS Elastic Beanstalk these are the environment properties.
See `.env.example` in the repo root for the full list. Required values:
| Setting | Env-var form | Used by | Notes |
|---|---|---|---|
| `ConnectionStrings:DefaultConnection` | `ConnectionStrings__DefaultConnection` | Both projects | SQL Server connection string |
| `SendGrid:ApiKey` | `SendGrid__ApiKey` | Both projects | Transactional email |
| `JWT:Secret` | `JWT__Secret` | `Api.SeaHavenIndustries` | JWT signing key |
| `GoogleMaps:ApiKey` | `GoogleMaps__ApiKey` | `SeaHavenIndustries` (Blazor) | Maps/Places; read in `App.razor` + `Home.razor` |
### AWS credentials
`UploadFileHp` (S3 uploads) uses the **AWS SDK default credential chain** — it no longer
hardcodes access keys. Credentials resolve from `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`
env vars, the shared profile/SSO, or (preferred in production) the EC2/ECS instance role.
The region comes from `AddDefaultAWSOptions` in `Program.cs`.
> ⚠️ The secrets previously committed to this repo (DB password, SendGrid key, JWT secret,
> Google Maps keys, AWS access key) should be considered compromised and **rotated**.

View file

@ -1,4 +1,5 @@
<!DOCTYPE html>
@inject IConfiguration Configuration
<!DOCTYPE html>
<html lang="en">
<head>
@ -17,7 +18,7 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" integrity="sha512-Kc323vGBEqzTmouAECnVceyQqyqdsSiqLQISBL29aUW4U/M7pSPA/gEUZQqv1cwx4OnYxTxve5UMg5GT6L4JJg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<!-- Material Icons -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons+Round" rel="stylesheet">
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDK_mNMt1b3zwmykVLauDUjnoz8DhuLI70&v=3&libraries=places"></script>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=@Configuration["GoogleMaps:ApiKey"]&v=3&libraries=places"></script>
<link rel="stylesheet" href="_content/Radzen.Blazor/css/default-base.css">
<!-- JS File -->

View file

@ -298,7 +298,7 @@
</div>
</div>
<div class="col-12 px-5 mb-4">
<RadzenGoogleMap ApiKey="AIzaSyBYwcFy_LS_UpdCIv7KZJUVhj9kMyPFdmk" @ref=map style="height: 400px" Options=@(new Dictionary<string, object> { { "disableDoubleClickZoom", true } })
<RadzenGoogleMap ApiKey="@Configuration["GoogleMaps:ApiKey"]" @ref=map style="height: 400px" Options=@(new Dictionary<string, object> { { "disableDoubleClickZoom", true } })
Zoom=@zoom Center=@(new GoogleMapPosition() { Lat = 42.6977, Lng = 23.3219 }) MapClick=@OnMapClick>
<Markers>
@foreach (var itm in setmappins)
@ -341,6 +341,7 @@
@inject IAccountRepository _aservice;
@inject ISettingsRepository _Seservice;
@inject HttpClient Http
@inject IConfiguration Configuration
@code {
private IEnumerable<ApplicationUser>? users { get; set; }
@ -508,7 +509,7 @@
}
private async Task<(double Latitude, double Longitude)> GetLatLng(string placeId)
{
const string apiKey = "AIzaSyBYwcFy_LS_UpdCIv7KZJUVhj9kMyPFdmk"; // Replace with your API key
var apiKey = Configuration["GoogleMaps:ApiKey"]; // Injected from configuration (env var GoogleMaps__ApiKey / user-secrets)
//var apiUrl = $"https://places.googleapis.com/v1/places/{placeId}";
var apiUrl = $"https://maps.googleapis.com/maps/api/place/autocomplete/json?input=Vict&language=pt_BR&types=%28cities%29&key={apiKey}";
// var apiUrl = $"https://places.googleapis.com/v1/places/{placeId}?fields=id,displayName&key={apiKey}";

View file

@ -31,19 +31,19 @@ namespace SeaHavenIndustries.Helper
//mail.Body = body;
//mail.IsBodyHtml = true;
//SmtpClient smtp = new SmtpClient("mail.codevoir.com");
//NetworkCredential Credentials = new NetworkCredential("infoesquall@codevoir.com", "Abc123!@#");
//NetworkCredential Credentials = new NetworkCredential("<smtp-user>", "<smtp-password>");
//smtp.UseDefaultCredentials = false;
//smtp.Credentials = Credentials;
//smtp.Port = 8889; //25 alternative port number is 8889
//smtp.EnableSsl = false;
//smtp.Send(mail);
//var apiKey = Environment.GetEnvironmentVariable("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\r\n");
//var apiKey1 = Environment.GetEnvironmentVariable("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");
//var apiKey = Environment.GetEnvironmentVariable("<SENDGRID_API_KEY>\r\n");
//var apiKey1 = Environment.GetEnvironmentVariable("<SENDGRID_API_KEY>");
// var apiKey2 = Environment.GetEnvironmentVariable("SENDGRID_API_KEY");
var apiKey = _configuration.GetValue<string>("SendGrid:ApiKey");
//var apiKey = "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";
//var apiKey = "<SENDGRID_API_KEY>";
var client = new SendGridClient(apiKey);
var from = new EmailAddress("tech@seahavenind.com", "Sea haven Industries");
//var subject = "Sending with SendGrid is Fun";
@ -69,7 +69,7 @@ namespace SeaHavenIndustries.Helper
var apiKey = _configuration.GetValue<string>("SendGrid:ApiKey");
//var apiKey = "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";
//var apiKey = "<SENDGRID_API_KEY>";
var client = new SendGridClient(apiKey);
var from = new EmailAddress("tech@seahavenind.com", "Sea haven Industries");
//var subject = "Sending with SendGrid is Fun";

View file

@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Components.Forms;
using SeaHavenIndustries.ViewModel;
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.Runtime;
namespace SeaHavenIndustries.Helper
{
@ -16,13 +15,13 @@ namespace SeaHavenIndustries.Helper
public UploadFileHp(IWebHostEnvironment hosting, IHttpContextAccessor httpContextAccessor, IAmazonS3 s3Client)
{
_hosting = hosting;
_httpContextAccessor = httpContextAccessor;
var awsCredentials = new BasicAWSCredentials("AKIAUY6EP2OAGEFSEP4W", "7xF+1RoO0pqyAWu/Lt9zP3z5HvHS/UjcCx2KbDbc");
_s3Client = new AmazonS3Client(awsCredentials, Amazon.RegionEndpoint.USEast2);
// Use the IAmazonS3 client supplied by DI (registered via AddAWSService<IAmazonS3>()).
// It resolves credentials through the AWS SDK default credential chain
// (environment variables, shared profile/SSO, or the EC2/ECS instance role) and the
// region from AddDefaultAWSOptions in Program.cs. Do NOT hardcode access keys here.
_s3Client = s3Client;
}
//public async Task<UploadResponseVm> UploadFiles(IBrowserFile file, string? path)

View file

@ -2,11 +2,10 @@
"ConnectionStrings": {
//"DefaultConnection": "Server=.;Database=SeahavenIndustries;TrustServerCertificate=True;Trusted_Connection=True;MultipleActiveResultSets=true",
//"DefaultConnection": "Server=.\\SqlExpress;Database=SeahavenIndustries;TrustServerCertificate=True;Trusted_Connection=True;MultipleActiveResultSets=true",
// Test database
//"DefaultConnection": "Server=SQL5112.site4now.net;Initial Catalog=db_a7141e_seahavenindustries;User Id=db_a7141e_seahavenindustries_admin;Password=Abc123!@#;MultipleActiveResultSets=true",
//Client Database
"DefaultConnection": "Server=SQL5112.site4now.net;Initial Catalog=db_a7141e_seahavenindustry;User Id=db_a7141e_seahavenindustry_admin;Password=Abc123!@#;MultipleActiveResultSets=true",
// Provide the real value via environment variable ConnectionStrings__DefaultConnection,
// user-secrets, or appsettings.Development.json (which is gitignored). Do NOT commit credentials.
"DefaultConnection": "${CONNECTION_STRING}",
"excelconnection": "Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='Excel 8.0;HDR=YES'"
},
"Logging": {
@ -16,7 +15,12 @@
}
},
"SendGrid": {
"ApiKey": "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"
// Provide the real value via environment variable SendGrid__ApiKey or user-secrets.
"ApiKey": "${SENDGRID_API_KEY}"
},
"GoogleMaps": {
// Provide the real value via environment variable GoogleMaps__ApiKey or user-secrets.
"ApiKey": "${GOOGLE_MAPS_API_KEY}"
},
"AllowedHosts": "*"
}