Skip to content

Commit

Permalink
Merge pull request Yubico#1389 from Yubico/test/passkey-tests
Browse files Browse the repository at this point in the history
Test/passkey tests
  • Loading branch information
jokkon authored Feb 12, 2024
2 parents b6dcef0 + 903e2eb commit 7318c8b
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 0 deletions.
4 changes: 4 additions & 0 deletions dart_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@ tags:

# Management tests
management:
timeout: none

# Passkey tests
passkey:
timeout: none
96 changes: 96 additions & 0 deletions integration_test/passkey_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright (C) 2023 Yubico.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

@Tags(['desktop', 'passkey'])
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:yubico_authenticator/fido/keys.dart';

import 'utils/passkey_test_util.dart';
import 'utils/test_util.dart';

void main() {
var binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;

group('Passkey PIN tests', () {
const simplePin = '1111';
const fidoPin1 = '947344';
const fidoPin2 = '478178';

/// Sadly these tests are built on each other to save reset-dance
appTest('Reset Fido2 1/2', (WidgetTester tester) async {
await tester.resetFido2();
});
group('Set/change pin', () {
appTest('Set simplePin', (WidgetTester tester) async {
// OBS: This will not work if there is pin complexity requirements
await tester.configurePasskey();

await tester.tap(find.byKey(managePinAction).hitTestable());
await tester.shortWait();

await tester.enterText(find.byKey(newPin), simplePin);
await tester.shortWait();
await tester.enterText(find.byKey(confirmPin), simplePin);
await tester.shortWait();

await tester.tap(find.byKey(saveButton).hitTestable());
await tester.shortWait();

/// TODO: deal with error messages from fips keys
/// TODO: make sure that the outcome of this test is a set state, right now it differs between FIPS and non-FIPS keys.
});
appTest('Change to fidoPin1', (WidgetTester tester) async {
await tester.configurePasskey();

await tester.tap(find.byKey(managePinAction).hitTestable());
await tester.shortWait();

await tester.enterText(find.byKey(currentPin), simplePin);
await tester.shortWait();
await tester.enterText(find.byKey(newPin), fidoPin1);
await tester.shortWait();
await tester.enterText(find.byKey(confirmPin), fidoPin1);
await tester.shortWait();

await tester.tap(find.byKey(saveButton).hitTestable());
await tester.shortWait();
});
appTest('Change to fidoPin2', (WidgetTester tester) async {
await tester.configurePasskey();

await tester.tap(find.byKey(managePinAction));
await tester.shortWait();

await tester.enterText(find.byKey(currentPin), fidoPin1);
await tester.shortWait();
await tester.enterText(find.byKey(newPin), fidoPin2);
await tester.shortWait();
await tester.enterText(find.byKey(confirmPin), fidoPin2);
await tester.shortWait();

await tester.tap(find.byKey(saveButton).hitTestable());
await tester.shortWait();
});
});
appTest('Reset Fido2 2/2', (WidgetTester tester) async {
await tester.resetFido2();
});
});
}
66 changes: 66 additions & 0 deletions integration_test/utils/passkey_test_util.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2023 Yubico.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import 'package:flutter_test/flutter_test.dart';
import 'package:yubico_authenticator/app/views/keys.dart';

import 'test_util.dart';

const fido2DanceLongWaitMs = 15000;

extension Fido2Functions on WidgetTester {
Future<void> fido2DanceWait() async {
await pump(const Duration(milliseconds: fido2DanceLongWaitMs));
}

/// Open the PIV Configuration
Future<void> configurePasskey() async {
// 1. open PIV view
await tap(find.byKey(fidoPasskeysAppDrawer).hitTestable());
await shortWait();
await tap(find.byKey(actionsIconButtonKey).hitTestable());
await shortWait();
}

/// Factory reset Fido2 application
Future<void> resetFido2() async {
final targetKey = approvedKeys[0]; // only reset approved keys!

/// 1. make sure we are using approved key
await switchToKey(targetKey);
await shortWait();

/// 2. open the key menu
await tapPopupMenu(targetKey);
await shortWait();
await tap(find.byKey(yubikeyFactoryResetMenuButton).hitTestable());
await longWait();

/// 3. then toggle 'Fido2' in the 'Factory reset' reset_dialog.dart
await tap(find.byKey(factoryResetPickResetFido2));
await longWait();

/// 4. Click reset TextButton: done
await tap(find.byKey(factoryResetReset));
await fido2DanceWait();

/// 5. Click the 'Close' button
await tap(find.text('Close').hitTestable());
await shortWait();

/// TODO 6. Verify Resetedness
}
}
7 changes: 7 additions & 0 deletions lib/fido/keys.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ const _fingerprintAction = '$_prefix.fingerprint.actions';
// Key actions
const managePinAction = Key('$_keyAction.manage_pin');
const addFingerprintAction = Key('$_keyAction.add_fingerprint');
const newPin = Key('$_keyAction.new_pin');
const confirmPin = Key('$_keyAction.confirm_pin');
const currentPin = Key('$_keyAction.current_pin');

// pin entry
const pinEntry = Key('$_keyAction.pin_entry');
const unlockFido2WithPin = Key('$_keyAction.unlock_fido2_with_pin');

// Credential actions
const editCredentialAction = Key('$_credentialAction.edit');
Expand Down
5 changes: 5 additions & 0 deletions lib/fido/views/pin_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import '../../desktop/models.dart';
import '../../widgets/app_input_decoration.dart';
import '../../widgets/app_text_form_field.dart';
import '../../widgets/responsive_dialog.dart';
import '../keys.dart';
import '../models.dart';
import '../state.dart';

Expand Down Expand Up @@ -67,6 +68,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
actions: [
TextButton(
onPressed: isValid ? _submit : null,
key: saveButton,
child: Text(l10n.s_save),
),
],
Expand All @@ -78,6 +80,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
if (hasPin) ...[
Text(l10n.p_enter_current_pin_or_reset_no_puk),
AppTextFormField(
key: currentPin,
initialValue: _currentPin,
autofocus: true,
obscureText: _isObscureCurrent,
Expand Down Expand Up @@ -112,6 +115,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
Text(l10n.p_enter_new_fido2_pin(minPinLength)),
// TODO: Set max characters based on UTF-8 bytes
AppTextFormField(
key: newPin,
initialValue: _newPin,
autofocus: !hasPin,
obscureText: _isObscureNew,
Expand Down Expand Up @@ -142,6 +146,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
},
),
AppTextFormField(
key: confirmPin,
initialValue: _confirmPin,
obscureText: _isObscureConfirm,
autofillHints: const [AutofillHints.password],
Expand Down
3 changes: 3 additions & 0 deletions lib/fido/views/pin_entry_form.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../app/models.dart';
import '../../widgets/app_input_decoration.dart';
import '../../widgets/app_text_field.dart';
import '../keys.dart';
import '../models.dart';
import '../state.dart';

Expand Down Expand Up @@ -85,6 +86,7 @@ class _PinEntryFormState extends ConsumerState<PinEntryForm> {
Padding(
padding: const EdgeInsets.only(top: 16.0, bottom: 4.0),
child: AppTextField(
key: pinEntry,
autofocus: true,
obscureText: _isObscure,
autofillHints: const [AutofillHints.password],
Expand Down Expand Up @@ -130,6 +132,7 @@ class _PinEntryFormState extends ConsumerState<PinEntryForm> {
contentPadding: const EdgeInsets.symmetric(horizontal: 0),
minLeadingWidth: 0,
trailing: FilledButton.icon(
key: unlockFido2WithPin,
icon: const Icon(Icons.lock_open),
label: Text(l10n.s_unlock),
onPressed:
Expand Down

0 comments on commit 7318c8b

Please sign in to comment.