Add reusable two-factor verification for login and money operations (#32)
This commit is contained in:
1 parent
b7a58b1a87
commit
fb40f860d2
41 files changed
+2439
-43
No files matched your search
@@ -1,14 +1,16 @@
|
||||
import 'package:sxchnge_analytics/sxchnge_analytics.dart';
|
||||
|
||||
import '../models/auth.dart';
|
||||
import '../models/two_factor.dart';
|
||||
import '../models/verification.dart';
|
||||
import 'contracts.dart';
|
||||
import 'guarded_login.dart';
|
||||
import 'verification.dart';
|
||||
|
||||
/// Decorates domain services, so widget rebuilds never produce analytics events.
|
||||
class InstrumentedAuthServices
|
||||
implements
|
||||
LoginService,
|
||||
PendingLoginService,
|
||||
SignupService,
|
||||
VerificationService,
|
||||
SimulationInfo {
|
||||
@@ -33,6 +35,7 @@ class InstrumentedAuthServices
|
||||
Future<T> Function() action,
|
||||
bool Function(T) simulated, {
|
||||
bool terminal = false,
|
||||
bool Function(T)? terminalWhen,
|
||||
bool onboarding = false,
|
||||
bool simulation = false,
|
||||
}) async {
|
||||
@@ -47,7 +50,7 @@ class InstrumentedAuthServices
|
||||
recorder.finish(
|
||||
operation,
|
||||
simulated: simulated(result),
|
||||
terminal: terminal,
|
||||
terminal: terminalWhen?.call(result) ?? terminal,
|
||||
);
|
||||
return result;
|
||||
} catch (error) {
|
||||
@@ -57,12 +60,17 @@ class InstrumentedAuthServices
|
||||
AuthError.emailInUse => JourneyFailure.emailInUse,
|
||||
AuthError.unavailable => JourneyFailure.unavailable,
|
||||
AuthError.unexpected => JourneyFailure.unexpected,
|
||||
AuthError.factorLocked ||
|
||||
AuthError.factorCooldown => JourneyFailure.unavailable,
|
||||
AuthError.factorRequired => JourneyFailure.invalid,
|
||||
},
|
||||
VerificationException(code: final code) => switch (code) {
|
||||
VerificationError.expired => JourneyFailure.expired,
|
||||
VerificationError.invalid => JourneyFailure.invalid,
|
||||
VerificationError.internal => JourneyFailure.internal,
|
||||
},
|
||||
FactorException(code: FactorError.expired) => JourneyFailure.expired,
|
||||
FactorException() => JourneyFailure.unavailable,
|
||||
_ => JourneyFailure.unexpected,
|
||||
};
|
||||
recorder.finish(operation, failure: failure);
|
||||
@@ -79,6 +87,23 @@ class InstrumentedAuthServices
|
||||
JourneyStep.login,
|
||||
() => loginService.login(request),
|
||||
(r) => r.isSimulated,
|
||||
terminalWhen: (r) => r.challenge == null,
|
||||
simulation: _simulation(loginService),
|
||||
);
|
||||
@override
|
||||
Future<AuthResult> completeLogin(
|
||||
FactorChallenge challenge,
|
||||
FactorGrant grant,
|
||||
) => _run(
|
||||
JourneyKind.login,
|
||||
JourneyStep.login,
|
||||
() {
|
||||
final service = loginService;
|
||||
if (service is! PendingLoginService)
|
||||
throw const AuthException(AuthError.unavailable);
|
||||
return service.completeLogin(challenge, grant);
|
||||
},
|
||||
(r) => r.isSimulated,
|
||||
terminal: true,
|
||||
simulation: _simulation(loginService),
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user