mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-11-22 00:12:09 +03:00
add PlatformException extension
This commit is contained in:
parent
1163ebb376
commit
fb7ce469ce
@ -26,8 +26,8 @@ import '../../app/logging.dart';
|
||||
import '../../app/models.dart';
|
||||
import '../../app/state.dart';
|
||||
import '../../app/views/user_interaction.dart';
|
||||
import '../../cancellation_exception.dart';
|
||||
import '../../core/models.dart';
|
||||
import '../../exception/platform_exception_decoder.dart';
|
||||
import '../../oath/models.dart';
|
||||
import '../../oath/state.dart';
|
||||
|
||||
@ -136,11 +136,8 @@ final addCredentialToAnyProvider =
|
||||
var result = jsonDecode(resultString);
|
||||
return OathCredential.fromJson(result['credential']);
|
||||
} on PlatformException catch (pe) {
|
||||
if (CancellationException.isCancellation(pe)) {
|
||||
throw CancellationException();
|
||||
}
|
||||
_log.error('Failed to add account.', pe);
|
||||
rethrow;
|
||||
throw pe.decode();
|
||||
}
|
||||
});
|
||||
|
||||
@ -216,10 +213,7 @@ class _AndroidCredentialListNotifier extends OathCredentialListNotifier {
|
||||
_log.debug('Calculate', resultJson);
|
||||
return OathCode.fromJson(jsonDecode(resultJson));
|
||||
} on PlatformException catch (pe) {
|
||||
if (CancellationException.isCancellation(pe)) {
|
||||
throw CancellationException();
|
||||
}
|
||||
rethrow;
|
||||
throw pe.decode();
|
||||
} finally {
|
||||
touchTimer?.cancel();
|
||||
controller?.close();
|
||||
@ -236,11 +230,8 @@ class _AndroidCredentialListNotifier extends OathCredentialListNotifier {
|
||||
var result = jsonDecode(resultString);
|
||||
return OathCredential.fromJson(result['credential']);
|
||||
} on PlatformException catch (pe) {
|
||||
if (CancellationException.isCancellation(pe)) {
|
||||
throw CancellationException();
|
||||
}
|
||||
_log.error('Failed to add account.', pe);
|
||||
rethrow;
|
||||
throw pe.decode();
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,10 +249,7 @@ class _AndroidCredentialListNotifier extends OathCredentialListNotifier {
|
||||
return OathCredential.fromJson(responseJson);
|
||||
} on PlatformException catch (pe) {
|
||||
_log.debug('Failed to execute renameOathCredential: ${pe.message}');
|
||||
if (CancellationException.isCancellation(pe)) {
|
||||
throw CancellationException();
|
||||
}
|
||||
rethrow;
|
||||
throw pe.decode();
|
||||
}
|
||||
}
|
||||
|
||||
@ -272,10 +260,7 @@ class _AndroidCredentialListNotifier extends OathCredentialListNotifier {
|
||||
.invokeMethod('deleteAccount', {'credentialId': credential.id});
|
||||
} on PlatformException catch (e) {
|
||||
_log.debug('Received exception: $e');
|
||||
if (CancellationException.isCancellation(e)) {
|
||||
throw CancellationException();
|
||||
}
|
||||
rethrow;
|
||||
throw e.decode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:yubico_authenticator/app/state.dart';
|
||||
import 'package:yubico_authenticator/cancellation_exception.dart';
|
||||
import 'package:yubico_authenticator/exception/cancellation_exception.dart';
|
||||
import 'package:yubico_authenticator/theme.dart';
|
||||
|
||||
import 'qr_scanner_view.dart';
|
||||
|
@ -17,7 +17,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../cancellation_exception.dart';
|
||||
import '../../exception/cancellation_exception.dart';
|
||||
import '../../core/state.dart';
|
||||
import '../../fido/views/fido_screen.dart';
|
||||
import '../../oath/models.dart';
|
||||
|
24
lib/exception/apdu_exception.dart
Normal file
24
lib/exception/apdu_exception.dart
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
class ApduException implements Exception {
|
||||
final int sw;
|
||||
final String message;
|
||||
final String? details;
|
||||
|
||||
ApduException(this.sw, this.message, this.details);
|
||||
}
|
||||
|
@ -14,12 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class CancellationException implements Exception {
|
||||
CancellationException();
|
||||
|
||||
static isCancellation(PlatformException pe) =>
|
||||
pe.code == 'CancellationException';
|
||||
|
||||
}
|
48
lib/exception/platform_exception_decoder.dart
Normal file
48
lib/exception/platform_exception_decoder.dart
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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/services.dart';
|
||||
|
||||
import 'apdu_exception.dart';
|
||||
import 'cancellation_exception.dart';
|
||||
|
||||
extension Decoder on PlatformException {
|
||||
bool _isCancellation() => code == 'CancellationException';
|
||||
|
||||
bool _isApduException() => code == 'ApduException';
|
||||
|
||||
Exception decode() {
|
||||
if (_isCancellation()) {
|
||||
return CancellationException();
|
||||
}
|
||||
|
||||
if (message != null && _isApduException()) {
|
||||
final regExp = RegExp(
|
||||
r'^com.yubico.yubikit.core.smartcard.ApduException: APDU error: 0x(.*)$');
|
||||
final firstMatch = regExp.firstMatch(message!);
|
||||
if (firstMatch != null) {
|
||||
final hexSw = firstMatch.group(1);
|
||||
final sw = int.tryParse(hexSw!, radix: 16);
|
||||
if (sw != null) {
|
||||
return ApduException(sw, 'SW: 0x$hexSw', details);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// original exception
|
||||
return this;
|
||||
}
|
||||
}
|
@ -25,7 +25,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../app/message.dart';
|
||||
import '../../app/models.dart';
|
||||
import '../../app/state.dart';
|
||||
import '../../cancellation_exception.dart';
|
||||
import '../../exception/cancellation_exception.dart';
|
||||
import '../../widgets/circle_timer.dart';
|
||||
import '../../widgets/custom_icons.dart';
|
||||
import '../models.dart';
|
||||
|
@ -20,7 +20,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../app/message.dart';
|
||||
import '../../app/shortcuts.dart';
|
||||
import '../../app/state.dart';
|
||||
import '../../cancellation_exception.dart';
|
||||
import '../../exception/cancellation_exception.dart';
|
||||
import '../../widgets/menu_list_tile.dart';
|
||||
import '../models.dart';
|
||||
import '../state.dart';
|
||||
|
@ -31,7 +31,8 @@ import '../../app/message.dart';
|
||||
import '../../app/models.dart';
|
||||
import '../../app/state.dart';
|
||||
import '../../app/views/user_interaction.dart';
|
||||
import '../../cancellation_exception.dart';
|
||||
import '../../exception/apdu_exception.dart';
|
||||
import '../../exception/cancellation_exception.dart';
|
||||
import '../../core/state.dart';
|
||||
import '../../desktop/models.dart';
|
||||
import '../../management/models.dart';
|
||||
@ -195,6 +196,8 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
// TODO: Make this cleaner than importing desktop specific RpcError.
|
||||
if (e is RpcError) {
|
||||
errorMessage = e.message;
|
||||
} else if (e is ApduException) {
|
||||
errorMessage = e.message;
|
||||
} else {
|
||||
errorMessage = e.toString();
|
||||
}
|
||||
|
@ -17,11 +17,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:yubico_authenticator/cancellation_exception.dart';
|
||||
|
||||
import '../../app/message.dart';
|
||||
import '../../app/models.dart';
|
||||
import '../../app/state.dart';
|
||||
import '../../exception/cancellation_exception.dart';
|
||||
import '../../widgets/responsive_dialog.dart';
|
||||
import '../models.dart';
|
||||
import '../state.dart';
|
||||
|
@ -22,7 +22,7 @@ import 'package:logging/logging.dart';
|
||||
import '../../app/logging.dart';
|
||||
import '../../app/message.dart';
|
||||
import '../../app/models.dart';
|
||||
import '../../cancellation_exception.dart';
|
||||
import '../../exception/cancellation_exception.dart';
|
||||
import '../../desktop/models.dart';
|
||||
import '../../widgets/responsive_dialog.dart';
|
||||
import '../../widgets/utf8_utils.dart';
|
||||
|
82
test/exception/platform_exception_decoder_test.dart
Normal file
82
test/exception/platform_exception_decoder_test.dart
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:yubico_authenticator/exception/apdu_exception.dart';
|
||||
import 'package:yubico_authenticator/exception/cancellation_exception.dart';
|
||||
import 'package:yubico_authenticator/exception/platform_exception_decoder.dart';
|
||||
|
||||
PlatformException mockApdu(String message) =>
|
||||
PlatformException(code: 'ApduException', message: message);
|
||||
|
||||
void main() {
|
||||
test('Recognize cancellation exception', () {
|
||||
final pe = PlatformException(
|
||||
code: 'CancellationException',
|
||||
message: null,
|
||||
details: null,
|
||||
stacktrace: null);
|
||||
|
||||
expect(pe.decode(), isA<CancellationException>());
|
||||
});
|
||||
|
||||
test('Recognize apdu exception', () {
|
||||
var pe = mockApdu(
|
||||
'com.yubico.yubikit.core.smartcard.ApduException: APDU error: 0x6f00');
|
||||
|
||||
expect(
|
||||
pe.decode(),
|
||||
const TypeMatcher<ApduException>()
|
||||
.having((ae) => ae.sw, 'SW', 28416)
|
||||
.having((ae) => ae.message, 'message', 'SW: 0x6f00'));
|
||||
|
||||
pe = mockApdu(
|
||||
'com.yubico.yubikit.core.smartcard.ApduException: APDU error: 0xIJKLMNO');
|
||||
|
||||
expect(pe.decode(), isNot(const TypeMatcher<ApduException>()));
|
||||
|
||||
pe = mockApdu(
|
||||
'com.yubico.yubikit.core.smartcard.ApduException: APDU error: 6f00');
|
||||
|
||||
expect(pe.decode(), isNot(const TypeMatcher<ApduException>()));
|
||||
|
||||
pe = mockApdu(
|
||||
'com.yubico.yubikit.core.smartcard.ApduException: APDU error:');
|
||||
|
||||
expect(pe.decode(), isNot(const TypeMatcher<ApduException>()));
|
||||
|
||||
pe = mockApdu('');
|
||||
|
||||
expect(pe.decode(), isNot(const TypeMatcher<ApduException>()));
|
||||
});
|
||||
|
||||
test('Rethrow', () {
|
||||
var pe = PlatformException(
|
||||
code: 'some code',
|
||||
message: 'some message',
|
||||
details: 'some details',
|
||||
stacktrace: 'and stacktrace');
|
||||
|
||||
expect(
|
||||
pe.decode(),
|
||||
const TypeMatcher<PlatformException>()
|
||||
.having((pe) => pe.code, 'code', 'some code')
|
||||
.having((pe) => pe.message, 'message', 'some message')
|
||||
.having((pe) => pe.details, 'details', 'some details')
|
||||
.having((pe) => pe.stacktrace, 'stacktrace', 'and stacktrace'));
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user