Skip to content

Commit 9a67d37

Browse files
authored
Merge pull request #283 from Resgrid/develop
Develop
2 parents f509d38 + 743d0f0 commit 9a67d37

229 files changed

Lines changed: 19165 additions & 590 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Core/Resgrid.Config/SecurityConfig.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,22 @@ public static class SecurityConfig
1313
/// </summary>
1414
public static Dictionary<string, string> SystemLoginCredentials = new Dictionary<string, string>()
1515
{
16-
16+
1717
};
18+
19+
// ── Encryption ───────────────────────────────────────────────────────────────
20+
21+
/// <summary>AES-256 master key used by IEncryptionService for system-wide encryption.</summary>
22+
public static string EncryptionKey = "CHANGEME_32CHAR_MASTER_KEY_HERE!";
23+
24+
/// <summary>Salt value used with PBKDF2 key derivation.</summary>
25+
public static string EncryptionSaltValue = "CHANGEME_SALT_VALUE_HERE";
26+
27+
/// <summary>
28+
/// Number of PBKDF2-HMAC-SHA256 iterations used when deriving AES-256 encryption keys.
29+
/// OWASP recommends a minimum of 600,000 iterations for PBKDF2-HMAC-SHA256 (as of 2023).
30+
/// Increase this value over time as hardware capabilities improve.
31+
/// </summary>
32+
public static int Pbkdf2Iterations = 600000;
1833
}
1934
}

Core/Resgrid.Config/ServiceBusConfig.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Resgrid.Config
1+
namespace Resgrid.Config
22
{
33
/// <summary>
44
/// Service Bus specific values for both Azure and NATS
@@ -17,6 +17,7 @@ public static class ServiceBusConfig
1717
public static string UnitLoactionQueueName = "unitlocationtest";
1818
public static string PersonnelLoactionQueueName = "personnellocationtest";
1919
public static string SecurityRefreshQueueName = "securityrefreshtest";
20+
public static string WorkflowQueueName = "workflowqueuetest";
2021
#else
2122
public static string CallBroadcastQueueName = "callbroadcast";
2223
public static string MessageBroadcastQueueName = "messagebroadcast";
@@ -29,6 +30,7 @@ public static class ServiceBusConfig
2930
public static string UnitLoactionQueueName = "unitlocation";
3031
public static string PersonnelLoactionQueueName = "personnellocation";
3132
public static string SecurityRefreshQueueName = "securityrefresh";
33+
public static string WorkflowQueueName = "workflowqueue";
3234
#endif
3335

3436
#region Azure Service Bus Values
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
namespace Resgrid.Config
2+
{
3+
/// <summary>
4+
/// Configuration settings for TOTP-based two-factor authentication.
5+
/// All values can be overridden via the standard config file or environment variables
6+
/// (e.g. RESGRID:TwoFactorConfig:DefaultRecoveryCodeCount).
7+
/// </summary>
8+
public static class TwoFactorConfig
9+
{
10+
// ── Recovery Codes ────────────────────────────────────────────────────────────
11+
12+
/// <summary>Number of recovery codes generated when a user enrolls in 2FA.</summary>
13+
public static int DefaultRecoveryCodeCount = 10;
14+
15+
/// <summary>
16+
/// UI warning threshold: show a warning to the user when their remaining
17+
/// recovery code count falls to this value or below.
18+
/// </summary>
19+
public static int RecoveryCodeWarningThreshold = 3;
20+
21+
// ── Step-Up Verification ──────────────────────────────────────────────────────
22+
23+
/// <summary>
24+
/// Number of minutes a successful step-up 2FA verification remains valid before
25+
/// the user is re-prompted when accessing a sensitive admin operation.
26+
/// </summary>
27+
public static int StepUpVerificationWindowMinutes = 15;
28+
29+
// ── TOTP Settings ─────────────────────────────────────────────────────────────
30+
31+
/// <summary>
32+
/// Issuer name embedded in the otpauth:// URI shown in QR codes.
33+
/// This is the label that appears in authenticator apps (e.g. Google Authenticator,
34+
/// Microsoft Authenticator, Authy).
35+
/// </summary>
36+
public static string TotpIssuerName = "Resgrid";
37+
}
38+
}
39+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
namespace Resgrid.Config
2+
{
3+
/// <summary>
4+
/// Configuration settings for contact method verification (email, mobile, home number).
5+
/// All values can be overridden via the standard config file or environment variables
6+
/// (e.g. RESGRID:VerificationConfig:VerificationCodeExpiryMinutes).
7+
/// </summary>
8+
public static class VerificationConfig
9+
{
10+
// ── Code Lifecycle ────────────────────────────────────────────────────────────
11+
12+
/// <summary>Number of minutes a verification code remains valid before expiring.</summary>
13+
public static int VerificationCodeExpiryMinutes = 30;
14+
15+
/// <summary>Number of numeric digits in a generated verification code.</summary>
16+
public static int VerificationCodeLength = 6;
17+
18+
// ── Attempt / Send Rate Limits ────────────────────────────────────────────────
19+
20+
/// <summary>Maximum number of confirmation attempts allowed per contact method per calendar day (UTC).</summary>
21+
public static int MaxVerificationAttemptsPerDay = 5;
22+
23+
/// <summary>Maximum number of verification code send requests allowed per contact method per hour.</summary>
24+
public static int MaxVerificationSendsPerHour = 3;
25+
26+
// ── reCAPTCHA v3 ─────────────────────────────────────────────────────────────
27+
28+
/// <summary>
29+
/// Minimum reCAPTCHA v3 score (0.0–1.0) required to pass bot-detection on the API
30+
/// department-registration endpoint. Requests scoring below this threshold are rejected.
31+
/// </summary>
32+
public static decimal RecaptchaMinimumScore = 0.5m;
33+
}
34+
}
35+
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
namespace Resgrid.Config
2+
{
3+
public static class WorkflowConfig
4+
{
5+
6+
/// <summary>Default maximum number of retry attempts for a failed workflow action execution.</summary>
7+
public static int DefaultMaxRetryCount = 3;
8+
9+
/// <summary>Hard ceiling on MaxRetryCount a user may configure — prevents infinite retry abuse.</summary>
10+
public static int MaxAllowedRetryCount = 5;
11+
12+
/// <summary>Base seconds for exponential back-off: delay = RetryBackoffBaseSeconds * 2^(attempt-1)</summary>
13+
public static int RetryBackoffBaseSeconds = 5;
14+
15+
/// <summary>Maximum concurrent workflow executions processed by a single worker instance.</summary>
16+
public static int MaxConcurrentWorkflows = 5;
17+
18+
// ── Rate Limiting ────────────────────────────────────────────────────────────
19+
20+
/// <summary>Maximum workflow enqueue operations allowed per department per minute (paid plans).</summary>
21+
public static int RateLimitPerDepartmentPerMinute = 60;
22+
23+
/// <summary>Aggressive rate limit for free-plan departments — cannot be bypassed by exempt event types.</summary>
24+
public static int FreePlanRateLimitPerDepartmentPerMinute = 5;
25+
26+
/// <summary>Maximum workflow runs a free-plan department may enqueue in a single calendar day (UTC).</summary>
27+
public static int FreePlanDailyRunLimit = 50;
28+
29+
// ── Workflow and Step Caps ───────────────────────────────────────────────────
30+
31+
/// <summary>Maximum number of workflows a paid-plan department may create.</summary>
32+
public static int MaxWorkflowsPerDepartment = 28;
33+
34+
/// <summary>Maximum number of steps per workflow for paid-plan departments.</summary>
35+
public static int MaxStepsPerWorkflow = 20;
36+
37+
/// <summary>Maximum number of workflows a free-plan department may create.</summary>
38+
public static int FreeMaxWorkflowsPerDepartment = 3;
39+
40+
/// <summary>Maximum number of steps per workflow for free-plan departments.</summary>
41+
public static int FreeMaxStepsPerWorkflow = 5;
42+
43+
// ── Per-Action Daily Send Limits ─────────────────────────────────────────────
44+
45+
/// <summary>Maximum emails a department may send per workflow step per day (paid plans).</summary>
46+
public static int MaxDailyEmailSendsPerDepartment = 500;
47+
48+
/// <summary>Maximum SMS messages a department may send per workflow step per day (paid plans).</summary>
49+
public static int MaxDailySmsPerDepartment = 200;
50+
51+
/// <summary>Maximum emails a free-plan department may send via workflows per day.</summary>
52+
public static int FreeMaxDailyEmailSendsPerDepartment = 10;
53+
54+
/// <summary>Maximum SMS messages a free-plan department may send via workflows per day.</summary>
55+
public static int FreeMaxDailySmsPerDepartment = 5;
56+
57+
// ── Recipient Caps ───────────────────────────────────────────────────────────
58+
59+
/// <summary>Maximum email recipients (To + Cc combined) for paid-plan workflow steps.</summary>
60+
public static int MaxEmailRecipients = 10;
61+
62+
/// <summary>Maximum SMS recipients for paid-plan workflow steps.</summary>
63+
public static int MaxSmsRecipients = 5;
64+
65+
// ── Template Size Limits ─────────────────────────────────────────────────────
66+
67+
/// <summary>Maximum length in characters for an OutputTemplate stored on a WorkflowStep (64 KB).</summary>
68+
public static int MaxOutputTemplateLength = 65536;
69+
70+
/// <summary>Maximum length in characters of rendered template content passed to an executor (256 KB).</summary>
71+
public static int MaxRenderedContentLength = 262144;
72+
73+
// ── Scriban Sandbox Limits ───────────────────────────────────────────────────
74+
75+
/// <summary>Maximum number of loop iterations in a Scriban template.</summary>
76+
public static int ScribanLoopLimit = 500;
77+
78+
/// <summary>Maximum recursion depth in a Scriban template.</summary>
79+
public static int ScribanRecursionLimit = 50;
80+
}
81+
}
82+

Core/Resgrid.Localization/Areas/User/Home/EditProfile.en.resx

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,4 +375,40 @@
375375
<data name="UserTypeLabel" xml:space="preserve">
376376
<value>User Type</value>
377377
</data>
378-
</root>
378+
<data name="EmailNotVerifiedWarning" xml:space="preserve">
379+
<value>Your email address has not been verified. Verify it to ensure you receive dispatches and notifications.</value>
380+
</data>
381+
<data name="MobileNotVerifiedWarning" xml:space="preserve">
382+
<value>Your mobile number has not been verified. Verify it to ensure you receive SMS dispatches and notifications.</value>
383+
</data>
384+
<data name="HomeNotVerifiedWarning" xml:space="preserve">
385+
<value>Your home number has not been verified. Verify it to ensure you receive voice call dispatches.</value>
386+
</data>
387+
<data name="GrandfatheredEmailWarning" xml:space="preserve">
388+
<value>We recommend verifying your email address to ensure uninterrupted delivery of dispatches and notifications.</value>
389+
</data>
390+
<data name="GrandfatheredMobileWarning" xml:space="preserve">
391+
<value>We recommend verifying your mobile number to ensure uninterrupted delivery of SMS dispatches and notifications.</value>
392+
</data>
393+
<data name="GrandfatheredHomeWarning" xml:space="preserve">
394+
<value>We recommend verifying your home number to ensure uninterrupted delivery of voice call dispatches.</value>
395+
</data>
396+
<data name="VerifyButtonLabel" xml:space="preserve">
397+
<value>Verify</value>
398+
</data>
399+
<data name="VerificationCodePlaceholder" xml:space="preserve">
400+
<value>Enter verification code</value>
401+
</data>
402+
<data name="VerificationCodeSent" xml:space="preserve">
403+
<value>A verification code has been sent.</value>
404+
</data>
405+
<data name="VerificationSuccessful" xml:space="preserve">
406+
<value>Verification successful.</value>
407+
</data>
408+
<data name="VerificationFailed" xml:space="preserve">
409+
<value>Verification failed. Please check the code and try again.</value>
410+
</data>
411+
<data name="VerificationRateLimited" xml:space="preserve">
412+
<value>Too many verification attempts. Please try again later.</value>
413+
</data>
414+
</root>

Core/Resgrid.Localization/Areas/User/Home/EditProfile.es.resx

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,4 +369,40 @@
369369
<data name="UserTypeLabel" xml:space="preserve">
370370
<value>Tipo de usuario</value>
371371
</data>
372-
</root>
372+
<data name="EmailNotVerifiedWarning" xml:space="preserve">
373+
<value>Su dirección de correo electrónico no ha sido verificada. Verifíquela para asegurarse de recibir despachos y notificaciones.</value>
374+
</data>
375+
<data name="MobileNotVerifiedWarning" xml:space="preserve">
376+
<value>Su número de móvil no ha sido verificado. Verifíquelo para asegurarse de recibir despachos y notificaciones por SMS.</value>
377+
</data>
378+
<data name="HomeNotVerifiedWarning" xml:space="preserve">
379+
<value>Su número de teléfono fijo no ha sido verificado. Verifíquelo para asegurarse de recibir despachos por llamada de voz.</value>
380+
</data>
381+
<data name="GrandfatheredEmailWarning" xml:space="preserve">
382+
<value>Recomendamos verificar su dirección de correo electrónico para garantizar la entrega ininterrumpida de despachos y notificaciones.</value>
383+
</data>
384+
<data name="GrandfatheredMobileWarning" xml:space="preserve">
385+
<value>Recomendamos verificar su número de móvil para garantizar la entrega ininterrumpida de despachos y notificaciones por SMS.</value>
386+
</data>
387+
<data name="GrandfatheredHomeWarning" xml:space="preserve">
388+
<value>Recomendamos verificar su número de teléfono fijo para garantizar la entrega ininterrumpida de despachos por llamada de voz.</value>
389+
</data>
390+
<data name="VerifyButtonLabel" xml:space="preserve">
391+
<value>Verificar</value>
392+
</data>
393+
<data name="VerificationCodePlaceholder" xml:space="preserve">
394+
<value>Ingrese el código de verificación</value>
395+
</data>
396+
<data name="VerificationCodeSent" xml:space="preserve">
397+
<value>Se ha enviado un código de verificación.</value>
398+
</data>
399+
<data name="VerificationSuccessful" xml:space="preserve">
400+
<value>Verificación exitosa.</value>
401+
</data>
402+
<data name="VerificationFailed" xml:space="preserve">
403+
<value>Error de verificación. Por favor verifique el código e inténtelo de nuevo.</value>
404+
</data>
405+
<data name="VerificationRateLimited" xml:space="preserve">
406+
<value>Demasiados intentos de verificación. Por favor inténtelo más tarde.</value>
407+
</data>
408+
</root>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Resgrid.Localization.Areas.User.Security
6+
{
7+
public class Security
8+
{
9+
}
10+
}
11+

0 commit comments

Comments
 (0)