fix(auth): remove all codes

This commit is contained in:
Prateek Sunal 2024-05-09 15:56:36 +05:30
parent 6496eea162
commit 5ef92e338d
8 changed files with 63 additions and 70 deletions

View file

@ -44,7 +44,7 @@ class Code {
this.err,
});
factory Code.withError(Object error) {
factory Code.withError(Object error, String rawData) {
return Code(
"",
"",
@ -54,7 +54,7 @@ class Code {
Algorithm.sha1,
Type.totp,
0,
"",
rawData,
err: error,
display: CodeDisplay(),
);
@ -143,7 +143,7 @@ class Code {
if (rawData.contains("#")) {
return Code.fromOTPAuthUrl(rawData.replaceAll("#", '%23'));
} else {
return Code.withError(e);
rethrow;
}
}
}
@ -258,11 +258,12 @@ class Code {
}
String get rawDataWithoutDisplay {
final updatedIssuer = jsonEncode(issuer);
final uri = Uri.parse(
"otpauth://${type.name}/$updatedIssuer:$account?algorithm=SHA1&digits=$digits&issuer=$updatedIssuer&period=30&secret=$secret",
return jsonEncode(
Uri.parse(
"$rawData&codeDisplay="
"${jsonEncode(display.toJson())}",
).toString(),
);
return uri.toString();
}
@override

View file

@ -1,13 +0,0 @@
import 'package:ente_auth/models/code.dart';
class AllCodes {
final List<Code> codes;
final AllCodesState state;
AllCodes({required this.codes, required this.state});
}
enum AllCodesState {
value,
error,
}

View file

@ -63,9 +63,9 @@ class CodeDisplayStore {
isCritical: true,
firstButtonOnTap: () async {
// traverse through all the codes and edit this tag's value
final relevantCodes = (await CodeStore.instance.getAllCodes())
.codes
.where((element) => element.display.tags.contains(tag));
final relevantCodes = (await CodeStore.instance.getAllCodes()).where(
(element) => !element.hasError && element.display.tags.contains(tag),
);
final tasks = <Future>[];
@ -99,9 +99,10 @@ class CodeDisplayStore {
Future<void> editTag(String previousTag, String updatedTag) async {
// traverse through all the codes and edit this tag's value
final relevantCodes = (await CodeStore.instance.getAllCodes())
.codes
.where((element) => element.display.tags.contains(previousTag));
final relevantCodes = (await CodeStore.instance.getAllCodes()).where(
(element) =>
!element.hasError && element.display.tags.contains(previousTag),
);
final tasks = <Future>[];

View file

@ -6,7 +6,6 @@ import 'package:ente_auth/core/event_bus.dart';
import 'package:ente_auth/events/codes_updated_event.dart';
import 'package:ente_auth/models/authenticator/entity_result.dart';
import 'package:ente_auth/models/code.dart';
import 'package:ente_auth/models/codes.dart';
import 'package:ente_auth/services/authenticator_service.dart';
import 'package:ente_auth/store/offline_authenticator_db.dart';
import 'package:logging/logging.dart';
@ -23,26 +22,25 @@ class CodeStore {
_authenticatorService = AuthenticatorService.instance;
}
Future<AllCodes> getAllCodes({AccountMode? accountMode}) async {
Future<List<Code>> getAllCodes({AccountMode? accountMode}) async {
final mode = accountMode ?? _authenticatorService.getAccountMode();
final List<EntityResult> entities =
await _authenticatorService.getEntities(mode);
final List<Code> codes = [];
bool hasError = false;
for (final entity in entities) {
final decodeJson = jsonDecode(entity.rawData);
late Code code;
if (decodeJson is String && decodeJson.startsWith('otpauth://')) {
code = Code.fromOTPAuthUrl(decodeJson);
} else {
code = Code.fromExportJson(decodeJson);
}
if (code.hasError) {
hasError = true;
try {
final decodeJson = jsonDecode(entity.rawData);
if (decodeJson is String && decodeJson.startsWith('otpauth://')) {
code = Code.fromOTPAuthUrl(decodeJson);
} else {
code = Code.fromExportJson(decodeJson);
}
} catch (e) {
code = Code.withError(e, entity.rawData);
_logger.severe("Could not parse code", code.err);
continue;
}
code.generatedID = entity.generatedID;
code.hasSynced = entity.hasSynced;
@ -64,10 +62,8 @@ class CodeStore {
secondCode.account,
);
});
return AllCodes(
codes: codes,
state: hasError ? AllCodesState.error : AllCodesState.value,
);
return codes;
}
Future<AddResult> addCode(
@ -79,7 +75,8 @@ class CodeStore {
final allCodes = await getAllCodes(accountMode: mode);
bool isExistingCode = false;
bool hasSameCode = false;
for (final existingCode in allCodes.codes) {
for (final existingCode in allCodes) {
if (existingCode.hasError) continue;
if (code.generatedID != null &&
existingCode.generatedID == code.generatedID) {
isExistingCode = true;
@ -138,7 +135,8 @@ class CodeStore {
List<Code> offlineCodes = (await CodeStore.instance
.getAllCodes(accountMode: AccountMode.offline))
.codes;
.where((element) => !element.hasError)
.toList();
if (offlineCodes.isEmpty) {
return;
}
@ -149,7 +147,8 @@ class CodeStore {
}
final List<Code> onlineCodes = (await CodeStore.instance
.getAllCodes(accountMode: AccountMode.online))
.codes;
.where((element) => !element.hasError)
.toList();
logger.info(
'importing ${offlineCodes.length} offline codes with ${onlineCodes.length} online codes',
);

View file

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:io';
import 'package:app_links/app_links.dart';
import 'package:collection/collection.dart';
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/core/event_bus.dart';
import 'package:ente_auth/ente_theme_data.dart';
@ -10,7 +11,6 @@ import 'package:ente_auth/events/icons_changed_event.dart';
import 'package:ente_auth/events/trigger_logout_event.dart';
import "package:ente_auth/l10n/l10n.dart";
import 'package:ente_auth/models/code.dart';
import 'package:ente_auth/models/codes.dart';
import 'package:ente_auth/onboarding/model/tag_enums.dart';
import 'package:ente_auth/onboarding/view/common/tag_chip.dart';
import 'package:ente_auth/onboarding/view/setup_enter_secret_key_page.dart';
@ -59,7 +59,7 @@ class _HomePageState extends State<HomePage> {
final FocusNode searchInputFocusNode = FocusNode();
bool _showSearchBox = false;
String _searchText = "";
AllCodes? _allCodes;
List<Code>? _allCodes;
List<String> tags = [];
List<Code> _filteredCodes = [];
StreamSubscription<CodesUpdatedEvent>? _streamSubscription;
@ -133,9 +133,10 @@ class _HomePageState extends State<HomePage> {
final List<Code> issuerMatch = [];
final List<Code> accountMatch = [];
for (final Code codeState in _allCodes!.codes) {
if (selectedTag != "" &&
!codeState.display.tags.contains(selectedTag)) {
for (final Code codeState in _allCodes!) {
if (codeState.hasError ||
selectedTag != "" &&
!codeState.display.tags.contains(selectedTag)) {
continue;
}
@ -148,11 +149,12 @@ class _HomePageState extends State<HomePage> {
_filteredCodes = issuerMatch;
_filteredCodes.addAll(accountMatch);
} else {
_filteredCodes = _allCodes?.codes
.where(
_filteredCodes = _allCodes
?.where(
(element) =>
selectedTag == "" ||
element.display.tags.contains(selectedTag),
!element.hasError &&
(selectedTag == "" ||
element.display.tags.contains(selectedTag)),
)
.toList() ??
[];
@ -182,7 +184,7 @@ class _HomePageState extends State<HomePage> {
if (code != null) {
await CodeStore.instance.addCode(code);
// Focus the new code by searching
if ((_allCodes?.codes.length ?? 0) > 2) {
if ((_allCodes?.where((e) => !e.hasError).length ?? 0) > 2) {
_focusNewCode(code);
}
}
@ -276,7 +278,7 @@ class _HomePageState extends State<HomePage> {
],
),
floatingActionButton: !_hasLoaded ||
(_allCodes?.codes.isEmpty ?? true) ||
(_allCodes?.isEmpty ?? true) ||
!PreferenceService.instance.hasShownCoachMark()
? null
: _getFab(),
@ -293,10 +295,14 @@ class _HomePageState extends State<HomePage> {
onManuallySetupTap: _redirectToManualEntryPage,
);
} else {
final anyCodeHasError =
_allCodes?.firstWhereOrNull((element) => element.hasError) != null;
final indexOffset = anyCodeHasError ? 1 : 0;
final list = Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (_allCodes?.state == AllCodesState.value)
if (!anyCodeHasError)
SizedBox(
height: 48,
child: ListView.separated(
@ -346,24 +352,21 @@ class _HomePageState extends State<HomePage> {
crossAxisCount: (MediaQuery.sizeOf(context).width ~/ 400)
.clamp(1, double.infinity)
.toInt(),
physics: _allCodes?.state == AllCodesState.value
? const AlwaysScrollableScrollPhysics()
: const NeverScrollableScrollPhysics(),
physics: const AlwaysScrollableScrollPhysics(),
padding: const EdgeInsets.only(bottom: 80),
itemBuilder: ((context, index) {
if (index == 0 && _allCodes?.state == AllCodesState.error) {
if (index == 0 && anyCodeHasError) {
return const CodeErrorWidget();
}
final newIndex =
index - (_allCodes?.state == AllCodesState.error ? 1 : 0);
final newIndex = index - indexOffset;
return ClipRect(
child: CodeWidget(
_filteredCodes[newIndex],
),
);
}),
itemCount: (_allCodes?.state == AllCodesState.error ? 1 : 0) +
_filteredCodes.length,
itemCount: _filteredCodes.length + indexOffset,
),
),
],

View file

@ -173,7 +173,8 @@ Future<void> _exportCodes(BuildContext context, String fileContent) async {
Future<String> _getAuthDataForExport() async {
final allCodes = await CodeStore.instance.getAllCodes();
String data = "";
for (final code in allCodes.codes) {
for (final code in allCodes) {
if (code.hasError) continue;
data += "${code.rawDataWithoutDisplay}\n";
}

View file

@ -108,8 +108,9 @@ class SettingsPage extends StatelessWidget {
await handleExportClick(context);
} else {
if (result.action == ButtonAction.second) {
bool hasCodes =
(await CodeStore.instance.getAllCodes()).codes.isNotEmpty;
bool hasCodes = (await CodeStore.instance.getAllCodes())
.where((element) => !element.hasError)
.isNotEmpty;
if (hasCodes) {
final hasAuthenticated = await LocalAuthenticationService
.instance

View file

@ -14,7 +14,7 @@ dependencies:
bip39: ^1.0.6 #done
bloc: ^8.1.2
clipboard: ^0.1.3
collection: # dart
collection: ^1.18.0 # dart
confetti: ^0.7.0
connectivity_plus: ^5.0.2
convert: ^3.1.1