mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
CW1272 tails, linux generic fixes (#2630)
* fix: linux/tails fixes, sqlite fix on linux * add sqlite deps * fix: old/new dir migration from .local * fix: tails path, local/share old names for compatibility * Update cw_core/lib/db/sqlite.dart Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com> * fix: close icon on desktop [skip ci] --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com> Co-authored-by: Konstiantin Ullrich <konstantin@cakewallet.com>
This commit is contained in:
co-authored by
Konstantin Ullrich
Omar Hatem
Konstiantin Ullrich
parent
c613e59cf4
commit
a7734c5c44
@@ -5,6 +5,7 @@ import 'dart:isolate';
|
||||
|
||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:cw_core/hardware/hardware_wallet_service.dart';
|
||||
import 'package:cw_core/root_dir.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
@@ -374,7 +375,7 @@ abstract class ElectrumWalletBase
|
||||
runningIsolate.kill(priority: Isolate.immediate);
|
||||
}
|
||||
|
||||
final appDir = await getApplicationSupportDirectory();
|
||||
final appDir = await getAppDir();
|
||||
String debugLogPath = "${appDir.path}/logs/debug.log";
|
||||
|
||||
final receivePort = ReceivePort();
|
||||
|
||||
@@ -1084,6 +1084,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.9.0"
|
||||
sqlite3_flutter_libs:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqlite3_flutter_libs
|
||||
sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.40"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
||||
|
||||
late Database db;
|
||||
|
||||
Future<void> initDb({String? pathOverride}) async {
|
||||
if (Platform.isLinux || Platform.isWindows) {
|
||||
databaseFactory = databaseFactoryFfi;
|
||||
}
|
||||
db = await openDatabase(
|
||||
pathOverride ?? "cake.db",
|
||||
version: 1,
|
||||
|
||||
+100
-6
@@ -1,11 +1,76 @@
|
||||
import 'dart:io';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
String? _rootDirPath;
|
||||
|
||||
void setRootDirFromEnv() => _rootDirPath = Platform.environment['CAKE_WALLET_DIR'];
|
||||
const String _tailsData = '/live/persistence/TailsData_unlocked/Persistent';
|
||||
|
||||
Future<Directory> getAppDir({String appName = 'cake_wallet'}) async {
|
||||
bool get isNonAmnesticTails {
|
||||
try {
|
||||
final os = File("/etc/os-release").readAsLinesSync();
|
||||
for (var line in os) {
|
||||
if (!line.startsWith("ID=")) continue;
|
||||
if (!line.contains("tails")) continue;
|
||||
return Directory(_tailsData).existsSync();
|
||||
}
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool showNotice = true;
|
||||
|
||||
void setRootDirFromEnv() =>
|
||||
_rootDirPath = Platform.environment['CAKE_WALLET_DIR'];
|
||||
|
||||
void copyDirectory(Directory source, Directory destination) {
|
||||
source.listSync(recursive: false).forEach((var entity) {
|
||||
if (entity is Directory) {
|
||||
var newDirectory = Directory(p.join(destination.absolute.path, p.basename(entity.path)));
|
||||
newDirectory.createSync(recursive: true);
|
||||
copyDirectory(entity.absolute, newDirectory);
|
||||
} else if (entity is File) {
|
||||
destination.createSync(recursive: true);
|
||||
entity.copySync(p.join(destination.path, p.basename(entity.path)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> linuxSymlinkSharedPreferences() async {
|
||||
if (!Platform.isLinux) return; // nuh-uh
|
||||
final dataHome = Platform.environment["XDG_DATA_HOME"] ?? p.join(Platform.environment["HOME"] ?? "", ".local", "share");
|
||||
var cakeNames = ['com.example.cake_wallet', 'cake_wallet'];
|
||||
for (String name in cakeNames) {
|
||||
final oldPath = p.join(dataHome, name);
|
||||
final newPath = p.join((await getAppDir()).path, "_local_share");
|
||||
final oldDir = Directory(oldPath);
|
||||
final oldLink = Link(oldPath);
|
||||
final newDir = Directory(newPath);
|
||||
if (oldDir.existsSync()) {
|
||||
if (oldLink.existsSync()) {
|
||||
printV("not creating, link exists");
|
||||
} else {
|
||||
if (newDir.existsSync()) {
|
||||
newDir.renameSync("${newPath}_${DateTime.now().millisecondsSinceEpoch~/1000}");
|
||||
}
|
||||
copyDirectory(oldDir, newDir);
|
||||
oldDir.deleteSync(recursive: true);
|
||||
}
|
||||
}
|
||||
if (!oldLink.existsSync()) {
|
||||
oldLink.create(newPath, recursive: true);
|
||||
}
|
||||
if (!newDir.existsSync()) {
|
||||
newDir.createSync(recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<Directory> getAppDir() async {
|
||||
const String appName = 'cake_wallet';
|
||||
Directory dir;
|
||||
|
||||
if (_rootDirPath != null && _rootDirPath!.isNotEmpty) {
|
||||
@@ -15,16 +80,45 @@ Future<Directory> getAppDir({String appName = 'cake_wallet'}) async {
|
||||
if (Platform.isWindows) {
|
||||
dir = await getApplicationSupportDirectory();
|
||||
} else if (Platform.isLinux) {
|
||||
String appDirPath;
|
||||
|
||||
String? appDirPath;
|
||||
try {
|
||||
dir = await getApplicationDocumentsDirectory();
|
||||
appDirPath = '${dir.path}/$appName';
|
||||
} catch (e) {
|
||||
appDirPath = '/home/${Platform.environment['USER']}/.$appName';
|
||||
appDirPath = null;
|
||||
}
|
||||
// App will try to use last entry in here, so {distro,package}-specific paths can be
|
||||
// be put as one of last items (tails - I'm looking at you), and other paths can be
|
||||
// added in the order of preference
|
||||
// Which currently is $HOME/.config/$appName - as this is the most standard directory
|
||||
// for storing things that users in general back-up
|
||||
var linuxAppPath = [
|
||||
if (appDirPath != null) appDirPath, // old preferred
|
||||
p.join('/home', Platform.environment['USER']??"null", appName), // old fallback
|
||||
if (Platform.environment['HOME'] != null) p.join(Platform.environment['HOME']!, ".$appName"), // old fallback but using HOME
|
||||
if (Platform.environment['HOME'] != null) p.join(Platform.environment['HOME']!, '.config', appName), // old fallback but using HOME
|
||||
if (isNonAmnesticTails) p.join(_tailsData, ".$appName") // tails (if persistance is enabled)
|
||||
];
|
||||
|
||||
String preferredPath = linuxAppPath.last;
|
||||
|
||||
preferredLoop:
|
||||
for (String notSoPreferredPath in linuxAppPath) {
|
||||
if (notSoPreferredPath == linuxAppPath.last) continue;
|
||||
bool useThisOne = Directory(notSoPreferredPath).existsSync();
|
||||
if (useThisOne) {
|
||||
if (showNotice) {
|
||||
showNotice = false;
|
||||
printV("Not using $preferredPath because $notSoPreferredPath exists, falling back for backwards compatibility");
|
||||
printV("Can't see your wallet? Check\n - ${linuxAppPath.join("\n - ")}\n and move directory that to $preferredPath");
|
||||
printV("Or use CAKE_WALLET_DIR=/path/to/app/ ${Platform.executable}");
|
||||
}
|
||||
preferredPath = notSoPreferredPath;
|
||||
break preferredLoop;
|
||||
}
|
||||
}
|
||||
|
||||
dir = Directory.fromUri(Uri.file(appDirPath));
|
||||
dir = Directory.fromUri(Uri.file(preferredPath));
|
||||
await dir.create(recursive: true);
|
||||
} else {
|
||||
dir = await getApplicationDocumentsDirectory();
|
||||
|
||||
@@ -31,16 +31,17 @@ abstract class CakeTorInstance {
|
||||
final uri = Uri.tryParse(socksServer);
|
||||
if (uri != null) {
|
||||
return CakeTorSocks(uri.port);
|
||||
} else {
|
||||
final uri = Uri.tryParse("socks5://$socksServer");
|
||||
if (uri != null) {
|
||||
return CakeTorSocks(uri.port);
|
||||
}
|
||||
}
|
||||
}
|
||||
final os = File("/etc/os-release").readAsLinesSync();
|
||||
for (var line in os) {
|
||||
if (!line.startsWith("ID=")) continue;
|
||||
if (!line.contains("tails")) continue;
|
||||
return CakeTorSocks(9150);
|
||||
}
|
||||
} catch (e) {
|
||||
printV("Failed to identify linux version - /etc/os-release missing");
|
||||
printV(
|
||||
"Failed to identify linux version - no SOCKS_SERVER variable found or malformed",
|
||||
);
|
||||
}
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -730,6 +730,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.9.0"
|
||||
sqlite3_flutter_libs:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sqlite3_flutter_libs
|
||||
sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.40"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -46,6 +46,7 @@ dependencies:
|
||||
ref: cake-update-v2
|
||||
sqflite: ^2.4.1
|
||||
sqflite_common_ffi: ^2.3.4+4
|
||||
sqlite3_flutter_libs: 0.5.40
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@@ -63,7 +64,7 @@ dependency_overrides:
|
||||
|
||||
# The following section is specific to Flutter.
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
uses-material-design: true
|
||||
|
||||
# To add assets to your package, add an assets section, like this:
|
||||
# assets:
|
||||
|
||||
@@ -761,6 +761,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.9.0"
|
||||
sqlite3_flutter_libs:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqlite3_flutter_libs
|
||||
sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.40"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -874,6 +874,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.9.0"
|
||||
sqlite3_flutter_libs:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqlite3_flutter_libs
|
||||
sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.40"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -21,7 +21,6 @@ Future<void> main() async {
|
||||
late File moneroCBinary;
|
||||
|
||||
setUpAll(() async {
|
||||
databaseFactory = databaseFactoryFfi;
|
||||
await initDb(pathOverride: './test/data/db');
|
||||
Hive.init('./test/data/db');
|
||||
PathProviderPlatform.instance = MockPathProviderPlatform();
|
||||
|
||||
@@ -879,6 +879,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.9.0"
|
||||
sqlite3_flutter_libs:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqlite3_flutter_libs
|
||||
sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.40"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -778,6 +778,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.9.0"
|
||||
sqlite3_flutter_libs:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqlite3_flutter_libs
|
||||
sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.40"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -775,6 +775,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.9.0"
|
||||
sqlite3_flutter_libs:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqlite3_flutter_libs
|
||||
sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.40"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -14,6 +14,7 @@ RETRY_COUNT=${RETRY_COUNT:-1}
|
||||
DATA_DIRS=(
|
||||
"$HOME/.local/share/com.example.cake_wallet"
|
||||
"$HOME/Documents/cake_wallet"
|
||||
"$HOME/.config/cake_wallet"
|
||||
)
|
||||
|
||||
# Global state
|
||||
@@ -46,7 +47,7 @@ format_duration() {
|
||||
local hours=$((seconds / 3600))
|
||||
local minutes=$(((seconds % 3600) / 60))
|
||||
local secs=$((seconds % 60))
|
||||
|
||||
|
||||
if (( hours > 0 )); then
|
||||
echo "${hours}h ${minutes}m ${secs}s"
|
||||
elif (( minutes > 0 )); then
|
||||
@@ -92,7 +93,7 @@ run_test() {
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
test_durations+=("$duration")
|
||||
|
||||
|
||||
log "✅ Test passed: $test_name ($(format_duration $duration))"
|
||||
passed_tests+=("$test_name")
|
||||
return 0
|
||||
@@ -101,9 +102,9 @@ run_test() {
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
test_durations+=("$duration")
|
||||
|
||||
|
||||
log "❌ Test failed: $test_name ($(format_duration $duration))"
|
||||
|
||||
|
||||
if (( retry_count < RETRY_COUNT )); then
|
||||
log "Retrying test: $test_name"
|
||||
retry_count=$((retry_count + 1))
|
||||
@@ -125,7 +126,7 @@ main() {
|
||||
while IFS= read -r -d $'\0' file; do
|
||||
targets+=("$file")
|
||||
done < <(find integration_test/test_suites -name "*.dart" -type f -print0)
|
||||
|
||||
|
||||
if [[ $? -ne 0 ]]; then
|
||||
error "Failed to find test files"
|
||||
exit 1
|
||||
@@ -140,7 +141,7 @@ main() {
|
||||
|
||||
# Record overall start time
|
||||
local overall_start_time=$(date +%s)
|
||||
|
||||
|
||||
# Run tests sequentially
|
||||
for target in "${targets[@]}"; do
|
||||
run_test "$target"
|
||||
@@ -156,7 +157,7 @@ main() {
|
||||
echo "Passed: ${#passed_tests[@]}"
|
||||
echo "Failed: ${#failed_tests[@]}"
|
||||
echo "Total duration: $(format_duration $total_duration)"
|
||||
|
||||
|
||||
if (( ${#passed_tests[@]} > 0 )); then
|
||||
echo -e "\n✅ Passed Tests:"
|
||||
for i in $(seq 0 $((${#passed_tests[@]} - 1))); do
|
||||
|
||||
@@ -96,6 +96,12 @@ Future<void> runAppWithZone({Key? topLevelKey}) async {
|
||||
} catch (e) {
|
||||
printV("Failed to initialize tor: $e");
|
||||
}
|
||||
|
||||
try {
|
||||
await linuxSymlinkSharedPreferences();
|
||||
} catch (e) {
|
||||
printV("Failed to symlink linux preferences: $e");
|
||||
}
|
||||
|
||||
await initializeAppAtRoot();
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||
final zanoIcon = Image.asset('assets/images/crypto/zano.webp', height: 24, width: 24);
|
||||
final decredIcon = Image.asset('assets/images/crypto/decred.webp', height: 24, width: 24);
|
||||
final dogeIcon = Image.asset('assets/images/crypto/dogecoin.webp', height: 24, width: 24);
|
||||
final nonWalletTypeIcon = Image.asset('assets/images/close.webp', height: 24, width: 24);
|
||||
final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
|
||||
|
||||
Image _newWalletImage(BuildContext context) => Image.asset(
|
||||
'assets/images/new_wallet.png',
|
||||
|
||||
Reference in New Issue
Block a user