Skip to content

Commit

Permalink
Fix import bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
Robert-Stackflow committed Sep 4, 2024
1 parent bddbf12 commit 087ff0e
Show file tree
Hide file tree
Showing 30 changed files with 379 additions and 192 deletions.
Binary file added assets/auth/ic_2fas.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/auth/ic_aegis.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/auth/ic_andotp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/auth/ic_authenticatorplus.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/auth/ic_authenticatorpro.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/auth/ic_authy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/auth/ic_bitwarden.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/auth/ic_blizzard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/auth/ic_enteauth.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/auth/ic_freeotp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/auth/ic_freeotpplus.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/auth/ic_googleauthenticator.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/auth/ic_lastpass.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/auth/ic_steam.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/auth/ic_totpauthenticator.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/auth/ic_winauth.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions assets/auth/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#遍历文件夹下的json文件,对于每个json文件生成对应的代码
#如对于gift_dark.json,对应代码行为static const String giftDark = "assets/lottie/gift_dark.json"
#生成所有json文件对应的代码,并写入到文件中
import os

def to_camel_case(snake_str):
"""将蛇形命名(下划线分隔)转换为驼峰命名(首字母小写)"""
components = snake_str.split('_')
return components[0].lower() + ''.join(x.title() for x in components[1:])

def generate_code_for_json_files(folder_path, output_file):
# 初始化一个列表来存储所有的代码行
code_lines = []

# 遍历文件夹下的所有文件
for root, _, files in os.walk(folder_path):
for file in files:
if file.endswith(".png"):
# 提取文件名(不包括扩展名)
base_name = os.path.splitext(file)[0]
# 将文件名转换为驼峰命名
variable_name = to_camel_case(base_name)
# 生成代码行
code_line = f'static const String {variable_name} = "assets/auth/{file}";'
# 将代码行添加到列表中
code_lines.append(code_line)

# 将所有代码行写入到输出文件中
with open(output_file, 'w') as f:
for line in code_lines:
f.write(line + '\n')

# 使用示例
folder_path = './' # 替换为你的文件夹路径
output_file = './code.txt' # 替换为你的输出文件路径
generate_code_for_json_files(folder_path, output_file)
133 changes: 0 additions & 133 deletions lib/Screens/Token/import_export_token_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -327,139 +327,6 @@ class _ImportExportTokenScreenState extends State<ImportExportTokenScreen>
},
),
const SizedBox(height: 10),
ItemBuilder.buildCaptionItem(
context: context, title: S.current.importFromThirdParty),
ItemBuilder.buildEntryItem(
context: context,
title: S.current.importFromGoogleAuthenticator,
description: S.current.importFromGoogleAuthenticatorTip,
onTap: () async {
if (ResponsiveUtil.isMobile()) {
BottomSheetBuilder.showBottomSheet(
rootContext,
enableDrag: false,
responsive: true,
(context) => const AddBottomSheet(onlyShowScanner: true),
);
}
},
),
ItemBuilder.buildEntryItem(
context: context,
title: S.current.importFrom2FAS,
description: S.current.importFrom2FASTip,
onTap: () async {
FilePickerResult? result = await FileUtil.pickFiles(
dialogTitle: S.current.importFrom2FASTitle,
type: FileType.custom,
allowedExtensions: ['2fas'],
lockParentWindow: true,
);
if (result != null) {
TwoFASTokenImporter().importFromPath(result.files.single.path!);
}
},
),
ItemBuilder.buildEntryItem(
context: context,
title: S.current.importFromAegis,
description: S.current.importFromAegisTip,
onTap: () async {
FilePickerResult? result = await FileUtil.pickFiles(
dialogTitle: S.current.importFromAegisTitle,
type: FileType.custom,
allowedExtensions: ['json'],
lockParentWindow: true,
);
if (result != null) {
AegisTokenImporter().importFromPath(result.files.single.path!);
}
},
),
// ItemBuilder.buildEntryItem(
// context: context,
// title: S.current.importFromFreeOTP,
// description: S.current.importFromFreeOTPTip,
// onTap: () async {
// FilePickerResult? result = await FileUtil.pickFiles(
// dialogTitle: S.current.importFromFreeOTPTitle,
// type: FileType.custom,
// allowedExtensions: ['xml'],
// lockParentWindow: true,
// );
// if (result != null) {
// FreeOTPTokenImporter().importFromPath(result.files.single.path!);
// }
// },
// ),
ItemBuilder.buildEntryItem(
context: context,
title: S.current.importFromFreeOTPPlus,
description: S.current.importFromFreeOTPPlusTip,
onTap: () async {
FilePickerResult? result = await FileUtil.pickFiles(
dialogTitle: S.current.importFromFreeOTPPlusTitle,
type: FileType.custom,
allowedExtensions: ['json'],
lockParentWindow: true,
);
if (result != null) {
FreeOTPPlusTokenImporter()
.importFromPath(result.files.single.path!);
}
},
),
ItemBuilder.buildEntryItem(
context: context,
title: S.current.importFromEnteAuth,
description: S.current.importFromEnteAuthTip,
onTap: () async {
FilePickerResult? result = await FileUtil.pickFiles(
dialogTitle: S.current.importFromEnteAuthTitle,
type: FileType.custom,
allowedExtensions: ['txt'],
lockParentWindow: true,
);
if (result != null) {
EnteAuthTokenImporter()
.importFromPath(result.files.single.path!);
}
},
),
ItemBuilder.buildEntryItem(
context: context,
title: S.current.importFromAndOTP,
description: S.current.importFromAndOTPTip,
onTap: () async {
FilePickerResult? result = await FileUtil.pickFiles(
dialogTitle: S.current.importFromAndOTPTitle,
type: FileType.custom,
allowedExtensions: ['json', 'aes'],
lockParentWindow: true,
);
if (result != null) {
AndOTPTokenImporter().importFromPath(result.files.single.path!);
}
},
),
ItemBuilder.buildEntryItem(
context: context,
bottomRadius: true,
title: S.current.importFromBitwarden,
description: S.current.importFromBitwardenTip,
onTap: () async {
FilePickerResult? result = await FileUtil.pickFiles(
dialogTitle: S.current.importFromBitwardenTitle,
type: FileType.custom,
allowedExtensions: ['json', 'csv'],
lockParentWindow: true,
);
if (result != null) {
BitwardenTokenImporter().importFromPath(result.files.single.path!);
}
},
),
const SizedBox(height: 10),
ItemBuilder.buildCaptionItem(
context: context, title: S.current.exportToThirdParty),
ItemBuilder.buildEntryItem(
Expand Down
18 changes: 18 additions & 0 deletions lib/Screens/main_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import '../Utils/itoast.dart';
import '../Utils/lottie_util.dart';
import '../Utils/route_util.dart';
import '../Utils/utils.dart';
import '../Widgets/BottomSheet/bottom_sheet_builder.dart';
import '../Widgets/BottomSheet/import_from_third_party_bottom_sheet.dart';
import '../Widgets/Custom/loading_icon.dart';
import '../Widgets/Dialog/custom_dialog.dart';
import '../Widgets/General/EasyRefresh/easy_refresh.dart';
Expand Down Expand Up @@ -646,6 +648,22 @@ class MainScreenState extends State<MainScreen>
},
),
const SizedBox(height: 4),
ItemBuilder.buildIconTextButton(
context,
quarterTurns: quarterTurns,
text: S.current.importFromThirdParty,
fontSizeDelta: -2,
showText: false,
direction: Axis.vertical,
icon: const Icon(Icons.apps_rounded),
onTap: () async {
RouteUtil.pushDialogRoute(
context,
const ImportFromThirdPartyBottomSheet(),
);
},
),
const SizedBox(height: 4),
if (provider.canShowCloudBackupButton &&
provider.showCloudBackupButton)
ItemBuilder.buildIconTextButton(
Expand Down
108 changes: 53 additions & 55 deletions lib/TokenUtils/ThirdParty/enteauth_importer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import 'package:cloudotp/Widgets/Dialog/progress_dialog.dart';
import 'package:ente_crypto_dart/ente_crypto_dart.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:pointycastle/export.dart';

import '../../Utils/ilogger.dart';
import '../../Utils/itoast.dart';
Expand Down Expand Up @@ -94,16 +93,16 @@ class EnteAuthTokenImporter implements BaseTokenImporter {
static const int KeyLength = 32;
static const int DerivationParallelism = 1;

static dynamic decrypt(String password, KdfParams param, String data,
String header) async {
final derivedKey = await CryptoUtil.deriveKey(
utf8.encode(password),
CryptoUtil.base642bin(param.salt),
param.memLimit,
param.opsLimit,
);
Uint8List? decryptedContent;
static dynamic decrypt(
String password, KdfParams param, String data, String header) async {
try {
final derivedKey = await CryptoUtil.deriveKey(
utf8.encode(password),
CryptoUtil.base642bin(param.salt),
param.memLimit,
param.opsLimit,
);
Uint8List? decryptedContent;
decryptedContent = await CryptoUtil.decryptData(
CryptoUtil.base642bin(data),
derivedKey,
Expand All @@ -120,26 +119,24 @@ class EnteAuthTokenImporter implements BaseTokenImporter {
List<TokenCategory> categories = [];
List<TokenCategoryBinding> bindings = [];
List<String> uniqueTags =
toImportTokens.expand((element) => element.tags).toSet().toList();
toImportTokens.expand((element) => element.tags).toSet().toList();
categories.addAll(uniqueTags
.map((e) => TokenCategory.title(title: e))
.where((element) => !categories.contains(element)));
for (var token in toImportTokens) {
bindings.addAll(token.tags.map((e) =>
TokenCategoryBinding(
bindings.addAll(token.tags.map((e) => TokenCategoryBinding(
tokenUid: token.uid,
categoryUid:
categories
.firstWhere((element) => element.title == e)
.uid,
categories.firstWhere((element) => element.title == e).uid,
)));
}
await BaseTokenImporter.importResult(
ImporterResult(toImportTokens, categories, bindings));
}

@override
Future<void> importFromPath(String path, {
Future<void> importFromPath(
String path, {
bool showLoading = true,
}) async {
late ProgressDialog dialog;
Expand All @@ -163,7 +160,7 @@ class EnteAuthTokenImporter implements BaseTokenImporter {
}
if (showLoading) dialog.dismiss();
InputValidateAsyncController validateAsyncController =
InputValidateAsyncController(
InputValidateAsyncController(
listen: false,
validator: (text) async {
if (text.isEmpty) {
Expand All @@ -172,25 +169,27 @@ class EnteAuthTokenImporter implements BaseTokenImporter {
if (showLoading) {
dialog.show(msg: S.current.importing, showProgress: false);
}
var res = await compute(
(receiveMessage) async {
return await decrypt(
receiveMessage["password"] as String,
KdfParams.fromJson(
receiveMessage["params"] as Map<String, dynamic>),
receiveMessage["data"] as String,
receiveMessage["header"] as String);
},
{
'data': backup.encryptedData,
"params": backup.kdfParams.toJson(),
'header': backup.encryptedNonce,
'password': text,
},
);
// var res = await compute(
// (receiveMessage) async {
// return await decrypt(
// receiveMessage["password"] as String,
// KdfParams.fromJson(
// receiveMessage["params"] as Map<String, dynamic>),
// receiveMessage["data"] as String,
// receiveMessage["header"] as String);
// },
// {
// 'data': backup.encryptedData,
// "params": backup.kdfParams.toJson(),
// 'header': backup.encryptedNonce,
// 'password': text,
// },
// );
var res = await decrypt(text, backup.kdfParams, backup.encryptedData,
backup.encryptedNonce);
if (res[0] == DecryptResult.success) {
List<OtpToken> tokens =
await ImportTokenUtil.importText(res[1], showToast: false);
await ImportTokenUtil.importText(res[1], showToast: false);
await import(tokens);
if (showLoading) {
dialog.dismiss();
Expand All @@ -209,29 +208,28 @@ class EnteAuthTokenImporter implements BaseTokenImporter {
rootContext,
responsive: true,
useWideLandscape: true,
(context) =>
InputBottomSheet(
validator: (value) {
if (value.isEmpty) {
return S.current.autoBackupPasswordCannotBeEmpty;
}
return null;
},
checkSyncValidator: false,
validateAsyncController: validateAsyncController,
title: S.current.inputImportPasswordTitle,
message: S.current.inputImportPasswordTip,
hint: S.current.inputImportPasswordHint,
inputFormatters: [
RegexInputFormatter.onlyNumberAndLetterAndSymbol,
],
tailingType: InputItemTailingType.password,
onValidConfirm: (password) async {},
),
(context) => InputBottomSheet(
validator: (value) {
if (value.isEmpty) {
return S.current.autoBackupPasswordCannotBeEmpty;
}
return null;
},
checkSyncValidator: false,
validateAsyncController: validateAsyncController,
title: S.current.inputImportPasswordTitle,
message: S.current.inputImportPasswordTip,
hint: S.current.inputImportPasswordHint,
inputFormatters: [
RegexInputFormatter.onlyNumberAndLetterAndSymbol,
],
tailingType: InputItemTailingType.password,
onValidConfirm: (password) async {},
),
);
} catch (e) {
List<OtpToken> tokens =
await ImportTokenUtil.importText(content, showToast: false);
await ImportTokenUtil.importText(content, showToast: false);
await import(tokens);
}
}
Expand Down
Empty file.
Loading

0 comments on commit 087ff0e

Please sign in to comment.