166 lines
4.7 KiB
Dart
Executable File
166 lines
4.7 KiB
Dart
Executable File
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
import 'package:injectable/injectable.dart';
|
|
import 'package:jwt_decoder/jwt_decoder.dart';
|
|
import 'package:pocketbase/pocketbase.dart';
|
|
import 'package:uae_stat/domain/entities/preferences_entity.dart';
|
|
import 'package:uae_stat/domain/entities/session_entity.dart';
|
|
import 'package:uae_stat/domain/repos/t_auth_repo.dart';
|
|
import 'package:uae_stat/domain/use_cases/auth_use_case.dart';
|
|
import 'package:uae_stat/infrastructure/services/pocketbase_service.dart';
|
|
|
|
@dev
|
|
@prod
|
|
@Injectable(as: TAuthRepo)
|
|
class PAuthRepo implements TAuthRepo {
|
|
@override
|
|
Future<SessionEntity?> fetchLocallyStored() async {
|
|
final se = await _LocalAuthRepo.fetchLocallyStored();
|
|
if (se == null) return null;
|
|
PocketBaseService.authStore.save(
|
|
se.token,
|
|
RecordModel.fromJson(se.modelJson),
|
|
);
|
|
return se;
|
|
}
|
|
|
|
SessionEntity _sessionEntityFromPocketbaseRecord(RecordAuth ra) {
|
|
final decodedToken = JwtDecoder.decode(ra.token);
|
|
final expInSeconds = decodedToken['exp'];
|
|
final expInMilliseconds = expInSeconds * 1000;
|
|
final expiresOn = DateTime.fromMillisecondsSinceEpoch(expInMilliseconds);
|
|
final se = SessionEntity(
|
|
id: ra.record!.id,
|
|
expiresOn: expiresOn,
|
|
token: ra.token,
|
|
modelJson: ra.record!.toJson(),
|
|
);
|
|
return se;
|
|
}
|
|
|
|
@override
|
|
Future<SessionEntity> fetchRefreshedSession() async {
|
|
final user = await PocketBaseService.users.authRefresh().timeout(Duration(seconds: 5));
|
|
final se = _sessionEntityFromPocketbaseRecord(user);
|
|
await _LocalAuthRepo.storeLocally(se);
|
|
return se;
|
|
}
|
|
|
|
@override
|
|
Future<SessionEntity> login(String email, String pw) async {
|
|
late final RecordAuth user;
|
|
|
|
try {
|
|
user = await PocketBaseService.users.authWithPassword(
|
|
email,
|
|
pw,
|
|
);
|
|
} on ClientException catch (err) {
|
|
final message = err.response['message'];
|
|
final isWrongEmailPw = message == 'Failed to authenticate.';
|
|
if (isWrongEmailPw) throw LoginError.invalidEmailPw;
|
|
rethrow;
|
|
}
|
|
final isVerified = user.record!.getBoolValue('verified');
|
|
if (!isVerified) throw LoginError.emailAddressNotVerified;
|
|
final se = _sessionEntityFromPocketbaseRecord(user);
|
|
await _LocalAuthRepo.storeLocally(se);
|
|
return se;
|
|
}
|
|
|
|
@override
|
|
Future<SessionEntity> googleAndAppleAuthencation(token) async {
|
|
late final RecordAuth user;
|
|
try {
|
|
user = token;
|
|
} on ClientException catch (err) {
|
|
final message = err.response['message'];
|
|
final isWrongEmailPw = message == 'Failed to authenticate.';
|
|
if (isWrongEmailPw) throw LoginError.invalidEmailPw;
|
|
rethrow;
|
|
}
|
|
final isVerified = user.record!.getBoolValue('verified');
|
|
if (!isVerified) throw LoginError.emailAddressNotVerified;
|
|
final se = _sessionEntityFromPocketbaseRecord(user);
|
|
await _LocalAuthRepo.storeLocally(se);
|
|
return se;
|
|
}
|
|
|
|
@override
|
|
Future<void> logout() {
|
|
PocketBaseService.authStore.clear();
|
|
return _LocalAuthRepo.clear();
|
|
}
|
|
|
|
/// throws [RegisterError]
|
|
@override
|
|
Future<void> register({
|
|
required String name,
|
|
required String email,
|
|
required String pw,
|
|
required PreferencesEntity preferences,
|
|
}) async {
|
|
try {
|
|
await PocketBaseService.users.create(
|
|
body: {
|
|
'email': email,
|
|
'password': pw,
|
|
'passwordConfirm': pw,
|
|
'name': name,
|
|
...preferences.toJson(),
|
|
},
|
|
);
|
|
} catch (err) {
|
|
if (err is ClientException) {
|
|
if (err.response['data']['email']['message'] ==
|
|
'The email is invalid or already in use.') {
|
|
throw RegisterError.emailAlreadyInUse;
|
|
}
|
|
}
|
|
}
|
|
PocketBaseService.users.requestVerification(email);
|
|
}
|
|
|
|
@override
|
|
Future<void> requestEmailVerification(
|
|
String email,
|
|
) =>
|
|
PocketBaseService.users.requestVerification(email);
|
|
|
|
@override
|
|
Future<void> requestPwReset(
|
|
String email,
|
|
) =>
|
|
PocketBaseService.users.requestPasswordReset(
|
|
email,
|
|
);
|
|
|
|
@override
|
|
bool didSessionExpire() => PocketBaseService.authStore.isValid;
|
|
}
|
|
|
|
abstract class _LocalAuthRepo {
|
|
static const _key = 'session';
|
|
static const _storage = FlutterSecureStorage();
|
|
|
|
static Future<SessionEntity?> fetchLocallyStored() async {
|
|
final e = await _storage.read(key: _key);
|
|
if (e == null) return null;
|
|
final se = SessionEntity.fromJson(e);
|
|
if (se.freshness == SessionFreshness.expired) {
|
|
await clear();
|
|
return null;
|
|
}
|
|
return se;
|
|
}
|
|
|
|
static Future<void> storeLocally(
|
|
SessionEntity se,
|
|
) =>
|
|
_storage.write(
|
|
key: _key,
|
|
value: se.toJson(),
|
|
);
|
|
|
|
static Future<void> clear() => _storage.delete(key: _key);
|
|
}
|