Skip to content

Commit e8e6f5a

Browse files
Fix sqlcipher bugs
1 parent b2d21ae commit e8e6f5a

23 files changed

+441
-263
lines changed

lib/Database/database_manager.dart

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class DatabaseManager {
3333
if (lib != null) open.overrideForAll(() => lib!);
3434
});
3535
static DatabaseFactory _currentDbFactory = cipherDbFactory;
36-
static bool _isSqlcipherLoaded = false;
36+
static bool isDatabaseEncrypted = false;
3737

3838
static bool get initialized => _database != null;
3939

@@ -46,26 +46,24 @@ class DatabaseManager {
4646

4747
static Future<void> initDataBase(String password) async {
4848
if (_database == null) {
49-
_currentDbFactory = cipherDbFactory;
5049
String path = join(await FileUtil.getDatabaseDir(), _dbName);
5150
File file = File(path);
52-
bool isEncrypted = false;
5351
if (file.existsSync()) {
5452
final stream = file.openRead(0, _unencrypedFileHeader.length);
5553
String content = String.fromCharCodes(await stream.fold<List<int>>(
5654
[], (previous, element) => previous..addAll(element)));
5755
if (content == _unencrypedFileHeader) {
58-
isEncrypted = false;
56+
isDatabaseEncrypted = false;
5957
_currentDbFactory = dbFactory;
6058
ILogger.info(
6159
"Database is an unencrypted SQLite database. File header is $content");
6260
} else {
63-
isEncrypted = true;
61+
isDatabaseEncrypted = true;
6462
_currentDbFactory = cipherDbFactory;
6563
ILogger.info("Database is an encrypted SQLite database.");
6664
}
6765
} else {
68-
isEncrypted = true;
66+
isDatabaseEncrypted = true;
6967
_currentDbFactory = cipherDbFactory;
7068
password = await HiveUtil.regeneratePassword();
7169
ILogger.info("Database not exist and new password is $password");
@@ -78,7 +76,7 @@ class DatabaseManager {
7876
version: _dbVersion,
7977
singleInstance: true,
8078
onConfigure: (db) async {
81-
_onConfigure(db, password, isEncrypted);
79+
_onConfigure(db, password);
8280
},
8381
onUpgrade: _onUpgrade,
8482
onCreate: _onCreate,
@@ -90,18 +88,32 @@ class DatabaseManager {
9088

9189
static Future<bool> changePassword(String password) async {
9290
if (_database != null) {
93-
List<Map<String, Object?>> res =
94-
await _database!.rawQuery("PRAGMA rekey='$password'");
95-
if (res.isNotEmpty) {
96-
return true;
91+
if (isDatabaseEncrypted) {
92+
List<Map<String, Object?>> res =
93+
await _database!.rawQuery("PRAGMA rekey='$password'");
94+
ILogger.info("Change database password result is $res");
95+
if (res.isNotEmpty) {
96+
return true;
97+
}
98+
} else {
99+
try {
100+
await _database!.rawQuery(
101+
"ATTACH DATABASE 'encrypted.db' AS tmp KEY '$password'");
102+
await _database!.rawQuery("SELECT sqlcipher_export('tmp')");
103+
await _database!.rawQuery("DETACH DATABASE tmp");
104+
return true;
105+
} catch (e) {
106+
ILogger.error("Failed to change database password", e);
107+
return false;
108+
}
97109
}
110+
return false;
98111
}
99112
return false;
100113
}
101114

102-
static Future<void> _onConfigure(
103-
Database db, String password, bool isEncrypted) async {
104-
if (isEncrypted) {
115+
static Future<void> _onConfigure(Database db, String password) async {
116+
if (isDatabaseEncrypted) {
105117
List<Map<String, Object?>> res =
106118
await db.rawQuery("PRAGMA KEY='$password'");
107119
if (res.isNotEmpty) {
@@ -248,12 +260,10 @@ class DatabaseManager {
248260
lib = DynamicLibrary.open('/usr/lib/libsqlite3.dylib');
249261
}
250262
if (Platform.isWindows) {
251-
lib = DynamicLibrary.open('sqlcipher.dll');
263+
lib = DynamicLibrary.open('sqlite_sqlcipher.dll');
252264
}
253-
_isSqlcipherLoaded = true;
254265
return lib;
255266
} catch (e) {
256-
_isSqlcipherLoaded = false;
257267
return null;
258268
}
259269
}

lib/Resources/fonts.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import "package:cloudotp/Utils/Tuple/tuple.dart";
22
import "package:cloudotp/Utils/responsive_util.dart";
33
import "package:flutter/cupertino.dart";
44

5+
import "../Utils/app_provider.dart";
56
import "../Utils/font_util.dart";
67
import "../Utils/hive_util.dart";
78
import "../Utils/itoast.dart";
@@ -117,8 +118,11 @@ enum FontEnum {
117118
await HiveUtil.put(HiveUtil.fontFamilyKey, item.index);
118119
await FontEnum.downloadFont(
119120
context: context,
121+
showToast: false,
120122
onFinished: (value) {
121123
dialog.dismiss();
124+
appProvider.darkTheme = appProvider.darkTheme;
125+
appProvider.lightTheme = appProvider.lightTheme;
122126
if (autoRestartApp) {
123127
ResponsiveUtil.restartApp(context);
124128
}

lib/Screens/Lock/database_decrypt_screen.dart

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import '../../Utils/ilogger.dart';
1515
import '../../Utils/responsive_util.dart';
1616
import '../../Utils/uri_util.dart';
1717
import '../../Widgets/Item/input_item.dart';
18-
import '../../Widgets/Window/window_caption.dart';
1918
import '../../generated/l10n.dart';
2019
import '../main_screen.dart';
2120

@@ -31,6 +30,22 @@ class DatabaseDecryptScreenState extends State<DatabaseDecryptScreen>
3130
final FocusNode _focusNode = FocusNode();
3231
late InputValidateAsyncController validateAsyncController;
3332
GlobalKey<FormState> formKey = GlobalKey<FormState>();
33+
bool _isMaximized = false;
34+
bool _isStayOnTop = false;
35+
36+
@override
37+
void onWindowMaximize() {
38+
setState(() {
39+
_isMaximized = true;
40+
});
41+
}
42+
43+
@override
44+
void onWindowUnmaximize() {
45+
setState(() {
46+
_isMaximized = false;
47+
});
48+
}
3449

3550
@override
3651
Future<void> onWindowResized() async {
@@ -82,17 +97,33 @@ class DatabaseDecryptScreenState extends State<DatabaseDecryptScreen>
8297
Widget build(BuildContext context) {
8398
return MyScaffold(
8499
backgroundColor: MyTheme.getBackground(context),
100+
appBar: ResponsiveUtil.isDesktop()
101+
? PreferredSize(
102+
preferredSize: const Size(0, 82),
103+
child: ItemBuilder.buildWindowTitle(
104+
context,
105+
forceClose: true,
106+
backgroundColor: MyTheme.getBackground(context),
107+
isStayOnTop: _isStayOnTop,
108+
isMaximized: _isMaximized,
109+
onStayOnTopTap: () {
110+
setState(() {
111+
_isStayOnTop = !_isStayOnTop;
112+
windowManager.setAlwaysOnTop(_isStayOnTop);
113+
});
114+
},
115+
),
116+
)
117+
: null,
118+
bottomNavigationBar: Container(
119+
height: 82,
120+
color: MyTheme.getBackground(context),
121+
),
85122
body: SafeArea(
86123
right: false,
87-
child: Stack(
88-
children: [
89-
if (ResponsiveUtil.isDesktop()) const WindowMoveHandle(),
90-
Center(
91-
child: DatabaseManager.lib != null
92-
? _buildBody()
93-
: _buildFailedBody(),
94-
),
95-
],
124+
child: Center(
125+
child:
126+
DatabaseManager.lib != null ? _buildBody() : _buildFailedBody(),
96127
),
97128
),
98129
);
@@ -173,13 +204,23 @@ class DatabaseDecryptScreenState extends State<DatabaseDecryptScreen>
173204
mainAxisSize: MainAxisSize.min,
174205
mainAxisAlignment: MainAxisAlignment.center,
175206
children: [
176-
Text(S.current.loadSqlcipherFailed,
177-
style: Theme.of(context).textTheme.titleLarge),
207+
IgnorePointer(
208+
child: Text(
209+
S.current.loadSqlcipherFailed,
210+
textAlign: TextAlign.center,
211+
style: Theme.of(context).textTheme.titleLarge,
212+
),
213+
),
178214
const SizedBox(height: 30),
179-
SizedBox(
180-
width: min(MediaQuery.sizeOf(context).width - 40, 500),
181-
child: Text(S.current.loadSqlcipherFailedMessage,
182-
style: Theme.of(context).textTheme.titleMedium),
215+
IgnorePointer(
216+
child: SizedBox(
217+
width: min(MediaQuery.sizeOf(context).width - 40, 500),
218+
child: Text(
219+
S.current.loadSqlcipherFailedMessage,
220+
textAlign: TextAlign.center,
221+
style: Theme.of(context).textTheme.titleMedium,
222+
),
223+
),
183224
),
184225
const SizedBox(height: 30),
185226
ItemBuilder.buildRoundButton(

lib/Screens/Lock/pin_verify_screen.dart

Lines changed: 86 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import 'package:cloudotp/Utils/route_util.dart';
44
import 'package:cloudotp/Utils/utils.dart';
55
import 'package:cloudotp/Widgets/General/Unlock/gesture_notifier.dart';
66
import 'package:cloudotp/Widgets/General/Unlock/gesture_unlock_view.dart';
7-
import 'package:cloudotp/Widgets/Window/window_caption.dart';
87
import 'package:flutter/material.dart';
98
import 'package:window_manager/window_manager.dart';
109

10+
import '../../Resources/theme.dart';
1111
import '../../Utils/hive_util.dart';
1212
import '../../Utils/responsive_util.dart';
1313
import '../../Widgets/Item/item_builder.dart';
@@ -40,6 +40,22 @@ class PinVerifyScreenState extends State<PinVerifyScreen> with WindowListener {
4040
late final GestureNotifier _notifier = GestureNotifier(
4141
status: GestureStatus.verify, gestureText: S.current.verifyGestureLock);
4242
final GlobalKey<GestureState> _gestureUnlockView = GlobalKey();
43+
bool _isMaximized = false;
44+
bool _isStayOnTop = false;
45+
46+
@override
47+
void onWindowMaximize() {
48+
setState(() {
49+
_isMaximized = true;
50+
});
51+
}
52+
53+
@override
54+
void onWindowUnmaximize() {
55+
setState(() {
56+
_isMaximized = false;
57+
});
58+
}
4359

4460
@override
4561
Future<void> onWindowResized() async {
@@ -86,63 +102,81 @@ class PinVerifyScreenState extends State<PinVerifyScreen> with WindowListener {
86102
@override
87103
Widget build(BuildContext context) {
88104
return Scaffold(
105+
backgroundColor: MyTheme.getBackground(context),
106+
appBar: ResponsiveUtil.isDesktop() && widget.jumpToMain
107+
? PreferredSize(
108+
preferredSize: const Size(0, 82),
109+
child: ItemBuilder.buildWindowTitle(
110+
context,
111+
forceClose: true,
112+
backgroundColor: MyTheme.getBackground(context),
113+
isStayOnTop: _isStayOnTop,
114+
isMaximized: _isMaximized,
115+
onStayOnTopTap: () {
116+
setState(() {
117+
_isStayOnTop = !_isStayOnTop;
118+
windowManager.setAlwaysOnTop(_isStayOnTop);
119+
});
120+
},
121+
),
122+
)
123+
: null,
124+
bottomNavigationBar: Container(
125+
height: widget.jumpToMain ? 82 : 0,
126+
color: MyTheme.getBackground(context),
127+
),
89128
body: SafeArea(
90129
right: false,
91-
child: Stack(
92-
children: [
93-
if (ResponsiveUtil.isDesktop()) const WindowMoveHandle(),
94-
Center(
95-
child: PopScope(
96-
canPop: !widget.isModal,
97-
child: Column(
98-
mainAxisSize: MainAxisSize.min,
99-
mainAxisAlignment: MainAxisAlignment.center,
100-
crossAxisAlignment: CrossAxisAlignment.center,
101-
children: [
102-
const SizedBox(height: 50),
103-
Text(
104-
_notifier.gestureText,
105-
style: Theme.of(context).textTheme.titleMedium,
106-
),
107-
const SizedBox(height: 30),
108-
Flexible(
109-
child: GestureUnlockView(
110-
key: _gestureUnlockView,
111-
size: min(MediaQuery.sizeOf(context).width, 400),
112-
padding: 60,
113-
roundSpace: 40,
114-
defaultColor: Colors.grey.withOpacity(0.5),
115-
selectedColor: Theme.of(context).primaryColor,
116-
failedColor: Colors.redAccent,
117-
disableColor: Colors.grey,
118-
solidRadiusRatio: 0.3,
119-
lineWidth: 2,
120-
touchRadiusRatio: 0.3,
121-
onCompleted: _gestureComplete,
122-
),
123-
),
124-
Visibility(
125-
visible: _isUseBiometric,
126-
child: GestureDetector(
127-
onTap: () {
128-
auth();
129-
},
130-
child: ItemBuilder.buildClickItem(
131-
Text(
132-
ResponsiveUtil.isWindows()
133-
? S.current.biometricVerifyPin
134-
: S.current.biometricVerifyFingerprint,
135-
style: Theme.of(context).textTheme.titleSmall,
136-
),
137-
),
130+
child: Center(
131+
child: PopScope(
132+
canPop: !widget.isModal,
133+
child: Column(
134+
mainAxisSize: MainAxisSize.min,
135+
mainAxisAlignment: MainAxisAlignment.center,
136+
crossAxisAlignment: CrossAxisAlignment.center,
137+
children: [
138+
const SizedBox(height: 50),
139+
Text(
140+
_notifier.gestureText,
141+
style: Theme.of(context).textTheme.titleMedium,
142+
),
143+
const SizedBox(height: 30),
144+
Flexible(
145+
child: GestureUnlockView(
146+
key: _gestureUnlockView,
147+
size: min(MediaQuery.sizeOf(context).width, 400),
148+
padding: 60,
149+
roundSpace: 40,
150+
defaultColor: Colors.grey.withOpacity(0.5),
151+
selectedColor: Theme.of(context).primaryColor,
152+
failedColor: Colors.redAccent,
153+
disableColor: Colors.grey,
154+
solidRadiusRatio: 0.3,
155+
lineWidth: 2,
156+
touchRadiusRatio: 0.3,
157+
onCompleted: _gestureComplete,
158+
),
159+
),
160+
Visibility(
161+
visible: _isUseBiometric,
162+
child: GestureDetector(
163+
onTap: () {
164+
auth();
165+
},
166+
child: ItemBuilder.buildClickItem(
167+
Text(
168+
ResponsiveUtil.isWindows()
169+
? S.current.biometricVerifyPin
170+
: S.current.biometricVerifyFingerprint,
171+
style: Theme.of(context).textTheme.titleSmall,
138172
),
139173
),
140-
const SizedBox(height: 50),
141-
],
174+
),
142175
),
143-
),
176+
const SizedBox(height: 50),
177+
],
144178
),
145-
],
179+
),
146180
),
147181
),
148182
);

0 commit comments

Comments
 (0)