Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit2b24b51

Browse files
committed
CU-868f7n1u3 Adding in Countly for analytics. PW validation fix.
1 parent5312ac7 commit2b24b51

File tree

12 files changed

+328
-16
lines changed

12 files changed

+328
-16
lines changed

‎Core/Resgrid.Config/TelemetryConfig.cs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ public static class TelemetryConfig
1616
publicstaticstringAptabaseBigBoardApiKey="";
1717
publicstaticstringAptabaseDispatchApiKey="";
1818

19+
publicstaticstringCountlyUrl="";
20+
publicstaticstringCountlyWebKey="";
21+
1922
publicstaticstringGetAnalyticsKey()
2023
{
2124
if(ExporterType==TelemetryExporters.PostHog)
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
usingSystem;
2+
usingSystem.ComponentModel.DataAnnotations;
3+
usingSystem.Linq;
4+
5+
namespaceResgrid.Framework
6+
{
7+
/// <summary>
8+
/// Validation attribute for password complexity requirements
9+
/// </summary>
10+
[AttributeUsage(AttributeTargets.Property|AttributeTargets.Field)]
11+
publicsealedclassPasswordComplexityAttribute:ValidationAttribute
12+
{
13+
publicintMinLength{get;set;}=8;
14+
publicboolRequireUppercase{get;set;}=true;
15+
publicboolRequireLowercase{get;set;}=true;
16+
publicboolRequireDigit{get;set;}=true;
17+
publicboolRequireSpecialChar{get;set;}=false;
18+
19+
publicPasswordComplexityAttribute()
20+
{
21+
ErrorMessage="Password does not meet complexity requirements";
22+
}
23+
24+
publicoverrideboolIsValid(objectvalue)
25+
{
26+
if(valueis notstringpassword)
27+
{
28+
returnfalse;
29+
}
30+
31+
varresult=StringHelpers.VerifyPasswordComplexity(
32+
password,
33+
MinLength,
34+
RequireUppercase,
35+
RequireLowercase,
36+
RequireDigit,
37+
RequireSpecialChar);
38+
39+
returnresult.IsValid;
40+
}
41+
42+
protectedoverrideValidationResultIsValid(objectvalue,ValidationContextvalidationContext)
43+
{
44+
if(valueis notstringpassword)
45+
{
46+
returnnewValidationResult("Invalid password format");
47+
}
48+
49+
varresult=StringHelpers.VerifyPasswordComplexity(
50+
password,
51+
MinLength,
52+
RequireUppercase,
53+
RequireLowercase,
54+
RequireDigit,
55+
RequireSpecialChar);
56+
57+
if(result.IsValid)
58+
{
59+
returnValidationResult.Success;
60+
}
61+
62+
varerrorMessage=string.Join(", ",result.Errors);
63+
returnnewValidationResult(errorMessage,new[]{validationContext.MemberName});
64+
}
65+
}
66+
}

‎Core/Resgrid.Framework/StringHelpers.cs‎

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@
1212

1313
namespaceResgrid.Framework
1414
{
15+
/// <summary>
16+
/// Result of password complexity verification
17+
/// </summary>
18+
publicsealedrecordPasswordComplexityResult(
19+
boolIsValid,
20+
List<string>Errors);
21+
1522
publicstaticclassStringHelpers
1623
{
1724
/// <summary>
@@ -247,5 +254,79 @@ public static string SanitizeCoordinatesString(string source)
247254
returnresultStrBuilder.ToString();
248255
}
249256

257+
/// <summary>
258+
/// Verifies password complexity against security requirements
259+
/// </summary>
260+
/// <param name="password">The password to verify</param>
261+
/// <param name="minLength">Minimum password length (default: 8)</param>
262+
/// <param name="requireUppercase">Require at least one uppercase letter (default: true)</param>
263+
/// <param name="requireLowercase">Require at least one lowercase letter (default: true)</param>
264+
/// <param name="requireDigit">Require at least one digit (default: true)</param>
265+
/// <param name="requireSpecialChar">Require at least one special character (default: false)</param>
266+
/// <returns>PasswordComplexityResult indicating validity and any errors</returns>
267+
publicstaticPasswordComplexityResultVerifyPasswordComplexity(
268+
stringpassword,
269+
intminLength=8,
270+
boolrequireUppercase=true,
271+
boolrequireLowercase=true,
272+
boolrequireDigit=true,
273+
boolrequireSpecialChar=false)
274+
{
275+
varerrors=newList<string>();
276+
277+
if(string.IsNullOrWhiteSpace(password))
278+
{
279+
errors.Add("Password cannot be empty");
280+
returnnewPasswordComplexityResult(false,errors);
281+
}
282+
283+
// Check minimum length
284+
if(password.Length<minLength)
285+
{
286+
errors.Add($"Password must be at least{minLength} characters long");
287+
}
288+
289+
// Check for uppercase letter
290+
if(requireUppercase&&!password.Any(char.IsUpper))
291+
{
292+
errors.Add("Password must include an uppercase letter");
293+
}
294+
295+
// Check for lowercase letter
296+
if(requireLowercase&&!password.Any(char.IsLower))
297+
{
298+
errors.Add("Password must include a lowercase letter");
299+
}
300+
301+
// Check for digit
302+
if(requireDigit&&!password.Any(char.IsDigit))
303+
{
304+
errors.Add("Password must include a number (digit)");
305+
}
306+
307+
// Check for special character
308+
if(requireSpecialChar)
309+
{
310+
varspecialChars="!@#$%^&*()_+-=[]{}|;:,.<>?";
311+
if(!password.Any(c=>specialChars.Contains(c)))
312+
{
313+
errors.Add("Password must include a special character");
314+
}
315+
}
316+
317+
returnnewPasswordComplexityResult(errors.Count==0,errors);
318+
}
319+
320+
/// <summary>
321+
/// Validates password complexity using default Resgrid requirements
322+
/// </summary>
323+
/// <param name="password">The password to validate</param>
324+
/// <returns>True if password meets complexity requirements</returns>
325+
publicstaticboolIsValidPassword(stringpassword)
326+
{
327+
varresult=VerifyPasswordComplexity(password);
328+
returnresult.IsValid;
329+
}
330+
250331
}
251332
}

‎Core/Resgrid.Services/PushService.cs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public PushService(IPushLogsService pushLogsService, INotificationProvider notif
3535

3636
publicasyncTask<bool>Register(PushUripushUri)
3737
{
38-
if(pushUri==null||String.IsNullOrWhiteSpace(pushUri.DeviceId)||string.IsNullOrWhiteSpace(pushUri.PushLocation))
38+
if(pushUri==null||string.IsNullOrWhiteSpace(pushUri.DeviceId)||string.IsNullOrWhiteSpace(pushUri.PushLocation))
3939
returnfalse;
4040

4141
varcode=pushUri.PushLocation;
@@ -61,7 +61,7 @@ public async Task<bool> UnRegister(PushUri pushUri)
6161

6262
publicasyncTask<bool>RegisterUnit(PushUripushUri)
6363
{
64-
if(pushUri==null||!pushUri.UnitId.HasValue||string.IsNullOrWhiteSpace(pushUri.PushLocation))
64+
if(pushUri==null||!pushUri.UnitId.HasValue||string.IsNullOrWhiteSpace(pushUri.DeviceId)||string.IsNullOrWhiteSpace(pushUri.PushLocation))
6565
returnfalse;
6666

6767
varunitId=pushUri.UnitId.Value;
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
usingSystem;
2+
usingSystem.Linq;
3+
usingResgrid.Framework;
4+
5+
namespaceResgrid.Tests.Framework
6+
{
7+
/// <summary>
8+
/// Example usage and tests for password complexity verification
9+
/// </summary>
10+
publicstaticclassPasswordComplexityExamples
11+
{
12+
/// <summary>
13+
/// Demonstrates how to use the password complexity verification
14+
/// </summary>
15+
publicstaticvoidRunExamples()
16+
{
17+
// Test cases
18+
vartestPasswords=new[]
19+
{
20+
"abc123",// Too short, no uppercase
21+
"ABC123",// No lowercase
22+
"abcDEF",// No digits
23+
"Abc123",// Valid according to default requirements
24+
"Password123",// Valid
25+
"MyPassword1",// Valid
26+
"",// Empty
27+
"Abc123!@#"// Valid with special chars
28+
};
29+
30+
Console.WriteLine("Password Complexity Verification Examples:");
31+
Console.WriteLine("=========================================");
32+
33+
foreach(varpasswordintestPasswords)
34+
{
35+
varresult=StringHelpers.VerifyPasswordComplexity(password);
36+
Console.WriteLine($"Password: '{password}'");
37+
Console.WriteLine($"Valid:{result.IsValid}");
38+
if(!result.IsValid)
39+
{
40+
Console.WriteLine($"Errors:{string.Join(", ",result.Errors)}");
41+
}
42+
Console.WriteLine();
43+
}
44+
45+
// Test with custom requirements matching current RegisterViewModel
46+
Console.WriteLine("Resgrid Default Requirements:");
47+
Console.WriteLine("============================");
48+
49+
varresgridDefaults=new[]
50+
{
51+
"abc123",// Should fail
52+
"Password1",// Should pass
53+
"MySecurePass123"// Should pass
54+
};
55+
56+
foreach(varpasswordinresgridDefaults)
57+
{
58+
varresult=StringHelpers.VerifyPasswordComplexity(
59+
password,
60+
minLength:8,
61+
requireUppercase:true,
62+
requireLowercase:true,
63+
requireDigit:true,
64+
requireSpecialChar:false);
65+
66+
Console.WriteLine($"Password: '{password}'");
67+
Console.WriteLine($"Valid:{result.IsValid}");
68+
if(!result.IsValid)
69+
{
70+
Console.WriteLine($"Errors:{string.Join(", ",result.Errors)}");
71+
}
72+
Console.WriteLine();
73+
}
74+
}
75+
76+
/// <summary>
77+
/// Simple validation method for quick checks using Resgrid defaults
78+
/// </summary>
79+
publicstaticboolValidatePasswordForResgrid(stringpassword)
80+
{
81+
returnStringHelpers.VerifyPasswordComplexity(
82+
password,
83+
minLength:8,
84+
requireUppercase:true,
85+
requireLowercase:true,
86+
requireDigit:true,
87+
requireSpecialChar:false).IsValid;
88+
}
89+
}
90+
}

‎Web/Resgrid.Web/Areas/User/Models/AddPersonModel.cs‎

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
usingSystem;
1+
usingMicrosoft.AspNetCore.Mvc.Rendering;
2+
usingResgrid.Framework;
3+
usingResgrid.Model;
4+
usingResgrid.Model.Identity;
5+
usingSystem;
26
usingSystem.Collections.Generic;
37
usingSystem.ComponentModel.DataAnnotations;
4-
usingMicrosoft.AspNetCore.Mvc.Rendering;
5-
usingResgrid.Model.Identity;
6-
usingResgrid.Model;
78

89
namespaceResgrid.Web.Areas.User.Models
910
{
@@ -42,7 +43,13 @@ public class AddPersonModel: BaseUserModel
4243
[DataType(DataType.EmailAddress)]
4344
publicstringEmail{get;set;}
4445

45-
[StringLength(100,ErrorMessage="The {0} must be at least {2} characters long.",MinimumLength=6)]
46+
[StringLength(100,ErrorMessage="The password must be at least 8 characters long",MinimumLength=8)]
47+
[PasswordComplexity(
48+
MinLength=8,
49+
RequireUppercase=true,
50+
RequireLowercase=true,
51+
RequireDigit=true,
52+
RequireSpecialChar=false)]
4653
[DataType(DataType.Password)]
4754
[Display(Name="Password")]
4855
[Required]

‎Web/Resgrid.Web/Areas/User/Views/Shared/_UserLayout.cshtml‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,19 @@
5858
})
5959
</script>
6060
}
61+
62+
@if (!String.IsNullOrWhiteSpace(Resgrid.Config.TelemetryConfig.CountlyUrl)&&!String.IsNullOrWhiteSpace(Resgrid.Config.TelemetryConfig.CountlyWebKey))
63+
{
64+
<scripttype='text/javascript'src="~/lib/countly-sdk-web/lib/countly.min.js"></script>
65+
<scripttype='text/javascript'>
66+
if (Countly&&window["Countly"]) {
67+
Countly.init({
68+
app_key:"@Resgrid.Config.TelemetryConfig.CountlyWebKey",
69+
url:"@Resgrid.Config.TelemetryConfig.CountlyUrl"
70+
});
71+
}
72+
</script>
73+
}
6174
</head>
6275
<body>
6376
<!-- Wrapper-->

‎Web/Resgrid.Web/Models/AccountViewModels/LoginViewModel.cs‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ namespace Resgrid.Web.Models.AccountViewModels
55
publicclassLoginViewModel
66
{
77
[Required]
8-
publicstringUsername{get;set;}
8+
[StringLength(250,ErrorMessage="The username must be at least 2 characters long and contain only alphanumeric characters.",MinimumLength=2)]
9+
publicstringUsername{get;set;}
910

1011
[Required]
11-
[DataType(DataType.Password)]
12+
[StringLength(100,ErrorMessage="The password must be at least 8 characters long, include a number (digit) and an uppercase letter",MinimumLength=4)]
13+
[DataType(DataType.Password)]
1214
publicstringPassword{get;set;}
1315

1416
[Display(Name="Remember me?")]

‎Web/Resgrid.Web/Models/AccountViewModels/RegisterViewModel.cs‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
usingResgrid.WebCore.Models;
2+
usingResgrid.Framework;
23
usingSystem.Collections.Generic;
34
usingSystem.ComponentModel.DataAnnotations;
45

@@ -36,7 +37,13 @@ public class RegisterViewModel: GoogleReCaptchaModelBase
3637
publicstringEmail{get;set;}
3738

3839
[Required]
39-
[StringLength(100,ErrorMessage="The passowrd must be at least 8 characters long, include a number (digit) and an uppercase letter",MinimumLength=8)]
40+
[StringLength(100,ErrorMessage="The password must be at least 8 characters long",MinimumLength=8)]
41+
[PasswordComplexity(
42+
MinLength=8,
43+
RequireUppercase=true,
44+
RequireLowercase=true,
45+
RequireDigit=true,
46+
RequireSpecialChar=false)]
4047
[DataType(DataType.Password)]
4148
[Display(Name="Password")]
4249
publicstringPassword{get;set;}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp