Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ec8d519
feat(auth): PasswordPolicy Support
MichaelVerdon Jun 19, 2025
55e8400
feat: license headers and impl start
MichaelVerdon Jun 19, 2025
1823649
feat: Password Policy Logic finished
MichaelVerdon Jun 20, 2025
226fcde
feat: add unit tests
MichaelVerdon Jun 20, 2025
5ab2b37
feat: expose method
MichaelVerdon Jun 20, 2025
1d23e57
fix: rename method
MichaelVerdon Jun 20, 2025
928f5e2
chore: refactor, make explicit as possible
MichaelVerdon Jun 20, 2025
8060d70
feat: add e2e
MichaelVerdon Jun 26, 2025
21c9ad1
feat: change field types
MichaelVerdon Jun 26, 2025
7d8d60f
chore: add license headers
MichaelVerdon Jun 26, 2025
c21b3bc
chore: fix analyze
MichaelVerdon Jun 26, 2025
70b7e49
chore: format-ci
MichaelVerdon Jun 26, 2025
1be1baa
chore: remove duplicate
MichaelVerdon Jun 26, 2025
b0ef9e2
chore: undo accidental deletion
MichaelVerdon Jun 26, 2025
9936e46
chore: fix analyze
MichaelVerdon Jun 26, 2025
9c8554d
fix: expose apis
MichaelVerdon Jun 26, 2025
de5e14d
chore: formatting
MichaelVerdon Jun 26, 2025
0555134
chore: sort dependencies alphabeticaly
MichaelVerdon Jun 26, 2025
b13f33e
chore: more e2e tests
MichaelVerdon Jun 26, 2025
03e3f8d
chore: refactor
MichaelVerdon Jul 17, 2025
0b78622
chore: refactor
MichaelVerdon Jul 17, 2025
69391a1
chore: refactor
MichaelVerdon Jul 17, 2025
87899f8
chore: fix
MichaelVerdon Jul 18, 2025
0e68d2b
chore: create internals
MichaelVerdon Jul 21, 2025
fa7c0c2
chore: run format
MichaelVerdon Jul 21, 2025
27f3476
fix: shift into platform_interface
MichaelVerdon Jul 24, 2025
15705e1
fix: readd method
MichaelVerdon Jul 24, 2025
18c5d51
fix: pass apikey through method instead
MichaelVerdon Jul 24, 2025
cfb5190
format: melos run format
MichaelVerdon Jul 24, 2025
3cd99e1
chore: remove import
MichaelVerdon Jul 24, 2025
4871d79
chore: keep internals internal
MichaelVerdon Jul 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: add unit tests
  • Loading branch information
MichaelVerdon committed Jul 18, 2025
commit 226fcde27e626b4a6eb7a25da9eef246b584b2a0
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,21 @@ class PasswordPolicyImpl {
customStrengthOptions['requireSymbols'] = responseOptions['containsNonAlphanumericCharacter'];
}

enforcementState = policy['enforcementState'] == 'ENFORCEMENT_STATE_UNSPECIFIED'
? 'OFF'
: policy['enforcementState'];

allowedNonAlphanumericCharacters = responseOptions['allowedNonAlphanumericCharacters'] ?? [];
// Handle both 'enforcementState' and 'enforcement' field names
final enforcement = policy['enforcementState'] ?? policy['enforcement'];
enforcementState = enforcement == 'ENFORCEMENT_STATE_UNSPECIFIED'
? 'OFF'
: (enforcement ?? 'OFF');

// allowedNonAlphanumericCharacters can be at top level or in customStrengthOptions
allowedNonAlphanumericCharacters = List<String>.from(
policy['allowedNonAlphanumericCharacters'] ??
responseOptions['allowedNonAlphanumericCharacters'] ??
[]
);

forceUpgradeOnSignin = policy['forceUpgradeOnSignin'] ?? false;
schemaVersion = policy['schemaVersion'];
schemaVersion = policy['schemaVersion'] ?? 1; // Default to 1 if not provided
}

Map<String,dynamic> isPasswordValid(String password) {
Expand Down
59 changes: 59 additions & 0 deletions packages/firebase_auth/firebase_auth/test/firebase_auth_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import '../lib/src/password_policy/password_policy_impl.dart';

import './mock.dart';

Expand All @@ -37,6 +38,25 @@ void main() {
const String kMockOobCode = 'oobcode';
const String kMockURL = 'http://www.example.com';
const String kMockHost = 'www.example.com';
const String kMockValidPassword = 'Password123!'; // For password policy impl testing
const String kMockInvalidPassword = 'Pa1!';
const String kMockInvalidPassword2 = 'password123!';
const String kMockInvalidPassword3 = 'PASSWORD123!';
const String kMockInvalidPassword4 = 'password!';
const String kMockInvalidPassword5 = 'Password123';
const Map<String, dynamic> kMockPasswordPolicy = {
'customStrengthOptions': {
'minPasswordLength': 6,
'maxPasswordLength': 12,
'containsLowercaseCharacter': true,
'containsUppercaseCharacter': true,
'containsNumericCharacter': true,
'containsNonAlphanumericCharacter': true,
},
'allowedNonAlphanumericCharacters': ['!'],
'schemaVersion': 1,
'enforcement': 'OFF',
};
const int kMockPort = 31337;

final TestAuthProvider testAuthProvider = TestAuthProvider();
Expand Down Expand Up @@ -767,6 +787,45 @@ void main() {
});
});

group('passwordPolicy', () {
test('passwordPolicy should be initialized with correct parameters', () async {
PasswordPolicyImpl passwordPolicy = PasswordPolicyImpl(kMockPasswordPolicy);
expect(passwordPolicy.policy, equals(kMockPasswordPolicy));
});

PasswordPolicyImpl passwordPolicy = PasswordPolicyImpl(kMockPasswordPolicy);

test('should return true for valid password', () async {
final status = passwordPolicy.isPasswordValid(kMockValidPassword);
expect(status['status'], isTrue);
});

test('should return false for invalid password that is too short', () async {
final status = passwordPolicy.isPasswordValid(kMockInvalidPassword);
expect(status['status'], isFalse);
});

test('should return false for invalid password with no capital characters', () async {
final status = passwordPolicy.isPasswordValid(kMockInvalidPassword2);
expect(status['status'], isFalse);
});

test('should return false for invalid password with no lowercase characters', () async {
final status = passwordPolicy.isPasswordValid(kMockInvalidPassword3);
expect(status['status'], isFalse);
});

test('should return false for invalid password with no numbers', () async {
final status = passwordPolicy.isPasswordValid(kMockInvalidPassword4);
expect(status['status'], isFalse);
});

test('should return false for invalid password with no symbols', () async {
final status = passwordPolicy.isPasswordValid(kMockInvalidPassword5);
expect(status['status'], isFalse);
});
});

test('toString()', () async {
expect(
auth.toString(),
Expand Down