From 91967e6ce381f4e3959aef45d17f4f996e06e6f7 Mon Sep 17 00:00:00 2001 From: lollipopkit Date: Fri, 4 Aug 2023 21:46:44 +0800 Subject: [PATCH] #87 new: auto ask add system key (~/.ssh/id_rsa) --- .dart_tool/flutter_gen/gen_l10n/l10n.dart | 6 ++ .dart_tool/flutter_gen/gen_l10n/l10n_de.dart | 3 + .dart_tool/flutter_gen/gen_l10n/l10n_en.dart | 3 + .dart_tool/flutter_gen/gen_l10n/l10n_id.dart | 3 + .dart_tool/flutter_gen/gen_l10n/l10n_zh.dart | 6 ++ lib/core/utils/misc.dart | 13 ++-- lib/core/utils/server.dart | 6 +- lib/data/model/server/private_key_info.dart | 35 ++++------- lib/data/model/server/private_key_info.g.dart | 8 +-- lib/data/provider/private_key.dart | 24 ++++---- lib/data/store/private_key.dart | 12 ---- lib/l10n/app_de.arb | 1 + lib/l10n/app_en.arb | 1 + lib/l10n/app_id.arb | 1 + lib/l10n/app_zh.arb | 1 + lib/l10n/app_zh_tw.arb | 1 + lib/view/page/private_key/edit.dart | 13 ++-- lib/view/page/private_key/list.dart | 60 +++++++++++++++++-- lib/view/page/server/edit.dart | 8 +-- 19 files changed, 129 insertions(+), 76 deletions(-) diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n.dart b/.dart_tool/flutter_gen/gen_l10n/l10n.dart index 0fae9f5d..af7b7d6c 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n.dart @@ -128,6 +128,12 @@ abstract class S { /// **'Add private key'** String get addPrivateKey; + /// No description provided for @addSystemPrivateKeyTip. + /// + /// In en, this message translates to: + /// **'Currently don\'t have any private key, do you add the one that comes with the system (~/.ssh/id_rsa)?'** + String get addSystemPrivateKeyTip; + /// No description provided for @added2List. /// /// In en, this message translates to: diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart index 20a3d2f2..ca8ef5cb 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart @@ -19,6 +19,9 @@ class SDe extends S { @override String get addPrivateKey => 'Private key hinzufügen'; + @override + String get addSystemPrivateKeyTip => 'Derzeit haben Sie keinen privaten Schlüssel, fügen Sie den Schlüssel hinzu, der mit dem System geliefert wird (~/.ssh/id_rsa)?'; + @override String get added2List => 'Zur Aufgabenliste hinzugefügt'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart index 6ba8b34f..17c64967 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart @@ -19,6 +19,9 @@ class SEn extends S { @override String get addPrivateKey => 'Add private key'; + @override + String get addSystemPrivateKeyTip => 'Currently don\'t have any private key, do you add the one that comes with the system (~/.ssh/id_rsa)?'; + @override String get added2List => 'Added to task list'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_id.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_id.dart index 209fef27..c8636714 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_id.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_id.dart @@ -19,6 +19,9 @@ class SId extends S { @override String get addPrivateKey => 'Tambahkan kunci pribadi'; + @override + String get addSystemPrivateKeyTip => 'Saat ini tidak memiliki kunci privat, apakah Anda menambahkan kunci yang disertakan dengan sistem (~/.ssh/id_rsa)?'; + @override String get added2List => 'Ditambahkan ke Daftar Tugas'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart index c9fb5c62..192901d7 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart @@ -19,6 +19,9 @@ class SZh extends S { @override String get addPrivateKey => '添加一个私钥'; + @override + String get addSystemPrivateKeyTip => '当前没有任何私钥,是否添加系统自带的(~/.ssh/id_rsa)?'; + @override String get added2List => '已添加至任务列表'; @@ -701,6 +704,9 @@ class SZhTw extends SZh { @override String get addPrivateKey => '新增一個私鑰'; + @override + String get addSystemPrivateKeyTip => '當前沒有任何私鑰,是否添加系統自帶的(~/.ssh/id_rsa)?'; + @override String get added2List => '已添加至任務列表'; diff --git a/lib/core/utils/misc.dart b/lib/core/utils/misc.dart index 865ad65c..ba3dc00d 100644 --- a/lib/core/utils/misc.dart +++ b/lib/core/utils/misc.dart @@ -77,13 +77,12 @@ String pathJoin(String path1, String path2) { return path1 + (path1.endsWith('/') ? '' : '/') + path2; } -String getHome() { - String? home = ""; - Map envVars = Platform.environment; - if (isMacOS ||isLinux) { - home = envVars['HOME']; +String? getHomeDir() { + final envVars = Platform.environment; + if (isMacOS || isLinux) { + return envVars['HOME']; } else if (isWindows) { - home = envVars['UserProfile']; + return envVars['UserProfile']; } - return home??""; + return null; } diff --git a/lib/core/utils/server.dart b/lib/core/utils/server.dart index 92a976b0..0519ad57 100644 --- a/lib/core/utils/server.dart +++ b/lib/core/utils/server.dart @@ -32,14 +32,14 @@ enum GenSSHClientStatus { } String getPrivateKey(String id) { - final key = locator().get(id); - if (key == null) { + final pki = locator().get(id); + if (pki == null) { throw SSHErr( type: SSHErrType.noPrivateKey, message: 'key [$id] not found', ); } - return key.privateKey; + return pki.key; } Future genClient( diff --git a/lib/data/model/server/private_key_info.dart b/lib/data/model/server/private_key_info.dart index 077eb0b9..bd21cb5c 100644 --- a/lib/data/model/server/private_key_info.dart +++ b/lib/data/model/server/private_key_info.dart @@ -1,6 +1,3 @@ -import 'dart:io'; -import 'package:toolbox/core/utils/misc.dart' show getHome, pathJoin; -import 'package:toolbox/data/model/app/error.dart'; import 'package:hive_flutter/hive_flutter.dart'; part 'private_key_info.g.dart'; @@ -10,37 +7,25 @@ class PrivateKeyInfo { @HiveField(0) late String id; @HiveField(1) - late String privateKey; + late String key; + @Deprecated('Never use this field') @HiveField(2) late String password; - PrivateKeyInfo( - this.id, - this.privateKey, - this.password, - ); + PrivateKeyInfo({ + required this.id, + required this.key, + }); + PrivateKeyInfo.fromJson(Map json) { id = json["id"].toString(); - privateKey = json["private_key"].toString(); - password = json["password"].toString(); + key = json["private_key"].toString(); } + Map toJson() { final Map data = {}; data["id"] = id; - data["private_key"] = privateKey; - data["password"] = password; + data["private_key"] = key; return data; } } - -class SystemPrivateKeyInfo extends PrivateKeyInfo { - SystemPrivateKeyInfo() : super("System private key", "", ""); - - Future getKey() async { - File idRsaFile = File(pathJoin(getHome(), ".ssh/id_rsa")); - if (!await idRsaFile.exists()) { - this.privateKey=""; - } - this.privateKey= await idRsaFile.readAsString(); - } -} diff --git a/lib/data/model/server/private_key_info.g.dart b/lib/data/model/server/private_key_info.g.dart index dc996803..18a68f98 100644 --- a/lib/data/model/server/private_key_info.g.dart +++ b/lib/data/model/server/private_key_info.g.dart @@ -17,9 +17,8 @@ class PrivateKeyInfoAdapter extends TypeAdapter { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return PrivateKeyInfo( - fields[0] as String, - fields[1] as String, - fields[2] as String, + id: fields[0] as String, + key: fields[1] as String, ); } @@ -30,8 +29,9 @@ class PrivateKeyInfoAdapter extends TypeAdapter { ..writeByte(0) ..write(obj.id) ..writeByte(1) - ..write(obj.privateKey) + ..write(obj.key) ..writeByte(2) + // ignore: deprecated_member_use_from_same_package ..write(obj.password); } diff --git a/lib/data/provider/private_key.dart b/lib/data/provider/private_key.dart index 43272c85..17c62e60 100644 --- a/lib/data/provider/private_key.dart +++ b/lib/data/provider/private_key.dart @@ -4,29 +4,33 @@ import 'package:toolbox/data/store/private_key.dart'; import 'package:toolbox/locator.dart'; class PrivateKeyProvider extends BusyProvider { - List get infos => _infos; + List get pkis => _pkis; final _store = locator(); - late List _infos; + late List _pkis; void loadData() { - _infos = _store.fetch(); + _pkis = _store.fetch(); } - void addInfo(PrivateKeyInfo info) { - _infos.add(info); + void add(PrivateKeyInfo info) { + _pkis.add(info); _store.put(info); notifyListeners(); } - void delInfo(PrivateKeyInfo info) { - _infos.removeWhere((e) => e.id == info.id); + void delete(PrivateKeyInfo info) { + _pkis.removeWhere((e) => e.id == info.id); _store.delete(info); notifyListeners(); } - void updateInfo(PrivateKeyInfo old, PrivateKeyInfo newInfo) { - final idx = _infos.indexWhere((e) => e.id == old.id); - _infos[idx] = newInfo; + void update(PrivateKeyInfo old, PrivateKeyInfo newInfo) { + final idx = _pkis.indexWhere((e) => e.id == old.id); + if (idx == -1) { + _pkis.add(newInfo); + } else { + _pkis[idx] = newInfo; + } _store.put(newInfo); notifyListeners(); } diff --git a/lib/data/store/private_key.dart b/lib/data/store/private_key.dart index 0a01dd2b..a693e2d6 100644 --- a/lib/data/store/private_key.dart +++ b/lib/data/store/private_key.dart @@ -1,10 +1,7 @@ -import 'dart:async'; import 'package:toolbox/core/persistant_store.dart'; import 'package:toolbox/data/model/server/private_key_info.dart'; -import 'package:toolbox/core/utils/platform.dart'; class PrivateKeyStore extends PersistentStore { - late SystemPrivateKeyInfo systemPrivateKeyInfo; void put(PrivateKeyInfo info) { box.put(info.id, info); } @@ -18,19 +15,10 @@ class PrivateKeyStore extends PersistentStore { ps.add(s); } } - if (isLinux || isMacOS) { - SystemPrivateKeyInfo sysPk = SystemPrivateKeyInfo(); - unawaited(sysPk.getKey()); - systemPrivateKeyInfo = sysPk; - ps.add(sysPk); - } return ps; } PrivateKeyInfo? get(String? id) { - if (id == "System private key") { - return this.systemPrivateKeyInfo; - } if (id == null) return null; return box.get(id); } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 2c917eeb..77ae86f4 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -5,6 +5,7 @@ "add": "Neu", "addAServer": "Server hinzufügen", "addPrivateKey": "Private key hinzufügen", + "addSystemPrivateKeyTip": "Derzeit haben Sie keinen privaten Schlüssel, fügen Sie den Schlüssel hinzu, der mit dem System geliefert wird (~/.ssh/id_rsa)?", "added2List": "Zur Aufgabenliste hinzugefügt", "all": "Alle", "alreadyLastDir": "Bereits im letzten Verzeichnis.", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 1d1a7147..e11b1686 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -5,6 +5,7 @@ "add": "Add", "addAServer": "add a server", "addPrivateKey": "Add private key", + "addSystemPrivateKeyTip": "Currently don't have any private key, do you add the one that comes with the system (~/.ssh/id_rsa)?", "added2List": "Added to task list", "all": "All", "alreadyLastDir": "Already in last directory.", diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index 994150aa..41e02b64 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -5,6 +5,7 @@ "add": "Menambahkan", "addAServer": "tambahkan server", "addPrivateKey": "Tambahkan kunci pribadi", + "addSystemPrivateKeyTip": "Saat ini tidak memiliki kunci privat, apakah Anda menambahkan kunci yang disertakan dengan sistem (~/.ssh/id_rsa)?", "added2List": "Ditambahkan ke Daftar Tugas", "all": "Semua", "alreadyLastDir": "Sudah di direktori terakhir.", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 1ff79be6..aeb67145 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -5,6 +5,7 @@ "add": "新增", "addAServer": "添加服务器", "addPrivateKey": "添加一个私钥", + "addSystemPrivateKeyTip": "当前没有任何私钥,是否添加系统自带的(~/.ssh/id_rsa)?", "added2List": "已添加至任务列表", "all": "所有", "alreadyLastDir": "已经是最上层目录了", diff --git a/lib/l10n/app_zh_tw.arb b/lib/l10n/app_zh_tw.arb index 5ea4d23d..c33fed48 100644 --- a/lib/l10n/app_zh_tw.arb +++ b/lib/l10n/app_zh_tw.arb @@ -5,6 +5,7 @@ "add": "新增", "addAServer": "新增服務器", "addPrivateKey": "新增一個私鑰", + "addSystemPrivateKeyTip": "當前沒有任何私鑰,是否添加系統自帶的(~/.ssh/id_rsa)?", "added2List": "已添加至任務列表", "all": "所有", "alreadyLastDir": "已經是最上層目錄了", diff --git a/lib/view/page/private_key/edit.dart b/lib/view/page/private_key/edit.dart index d8507687..442ff1bf 100644 --- a/lib/view/page/private_key/edit.dart +++ b/lib/view/page/private_key/edit.dart @@ -74,7 +74,7 @@ class _PrivateKeyEditPageState extends State IconButton( tooltip: _s.delete, onPressed: () { - _provider.delInfo(widget.info!); + _provider.delete(widget.info!); context.pop(); }, icon: const Icon(Icons.delete)) @@ -100,9 +100,9 @@ class _PrivateKeyEditPageState extends State setState(() { _loading = centerSizedLoading; }); - final info = PrivateKeyInfo(name, key, ''); + final info = PrivateKeyInfo(id: name, key: key); try { - info.privateKey = await compute(decyptPem, [key, pwd]); + info.key = await compute(decyptPem, [key, pwd]); } catch (e) { showSnackBar(context, Text(e.toString())); rethrow; @@ -112,9 +112,9 @@ class _PrivateKeyEditPageState extends State }); } if (widget.info != null) { - _provider.updateInfo(widget.info!, info); + _provider.update(widget.info!, info); } else { - _provider.addInfo(info); + _provider.add(info); } context.pop(); }, @@ -194,8 +194,7 @@ class _PrivateKeyEditPageState extends State Future afterFirstLayout(BuildContext context) async { if (widget.info != null) { _nameController.text = widget.info!.id; - _keyController.text = widget.info!.privateKey; - _pwdController.text = widget.info!.password; + _keyController.text = widget.info!.key; } else { final clipdata = ((await Clipboard.getData(_format))?.text ?? '').trim(); if (clipdata.startsWith('-----BEGIN') && clipdata.endsWith('-----')) { diff --git a/lib/view/page/private_key/list.dart b/lib/view/page/private_key/list.dart index 4a0b3f4e..14989a41 100644 --- a/lib/view/page/private_key/list.dart +++ b/lib/view/page/private_key/list.dart @@ -1,8 +1,17 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:provider/provider.dart'; +import 'package:toolbox/core/extension/navigator.dart'; +import 'package:toolbox/core/utils/ui.dart'; +import 'package:toolbox/data/store/private_key.dart'; +import 'package:toolbox/locator.dart'; import '../../../core/route.dart'; +import '../../../core/utils/misc.dart'; +import '../../../core/utils/platform.dart'; +import '../../../data/model/server/private_key_info.dart'; import '../../../data/provider/private_key.dart'; import '../../../data/res/ui.dart'; import 'edit.dart'; @@ -24,6 +33,13 @@ class _PrivateKeyListState extends State { _s = S.of(context)!; } + @override + void initState() { + super.initState(); + + autoAddSystemPriavteKey(); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -44,21 +60,21 @@ class _PrivateKeyListState extends State { Widget _buildBody() { return Consumer( builder: (_, key, __) { - if (key.infos.isEmpty) { + if (key.pkis.isEmpty) { return Center( child: Text(_s.noSavedPrivateKey), ); } return ListView.builder( padding: const EdgeInsets.all(13), - itemCount: key.infos.length, + itemCount: key.pkis.length, itemBuilder: (context, idx) { return RoundRectCard( ListTile( - title: Text(key.infos[idx].id), + title: Text(key.pkis[idx].id), trailing: TextButton( onPressed: () => AppRoute( - PrivateKeyEditPage(info: key.infos[idx]), + PrivateKeyEditPage(info: key.pkis[idx]), 'private key edit page', ).go(context), child: Text(_s.edit), @@ -70,4 +86,40 @@ class _PrivateKeyListState extends State { }, ); } + + void autoAddSystemPriavteKey() { + final store = locator(); + // Only trigger on desktop platform and no private key saved + if (isDesktop && store.box.keys.isEmpty) { + final home = getHomeDir(); + if (home == null) return; + final idRsaFile = File(pathJoin(home, '.ssh/id_rsa')); + if (!idRsaFile.existsSync()) return; + final sysPk = PrivateKeyInfo( + id: 'system', + key: idRsaFile.readAsStringSync(), + ); + showRoundDialog( + context: context, + title: Text(_s.attention), + child: Text(_s.addSystemPrivateKeyTip), + actions: [ + TextButton( + onPressed: () { + context.pop(); + AppRoute( + PrivateKeyEditPage(info: sysPk), + 'private key edit page', + ).go(context); + }, + child: Text(_s.ok), + ), + TextButton( + onPressed: () => Navigator.pop(context), + child: Text(_s.cancel), + ), + ], + ); + } + } } diff --git a/lib/view/page/server/edit.dart b/lib/view/page/server/edit.dart index 628e1704..2b4ccc5f 100644 --- a/lib/view/page/server/edit.dart +++ b/lib/view/page/server/edit.dart @@ -200,17 +200,17 @@ class _ServerEditPageState extends State with AfterLayoutMixin { Widget _buildKeyAuth() { return Consumer( builder: (_, key, __) { - for (var item in key.infos) { + for (var item in key.pkis) { if (item.id == widget.spi?.pubKeyId) { - _pubKeyIndex ??= key.infos.indexOf(item); + _pubKeyIndex ??= key.pkis.indexOf(item); } } - final tiles = key.infos + final tiles = key.pkis .map( (e) => ListTile( contentPadding: EdgeInsets.zero, title: Text(e.id, textAlign: TextAlign.start), - trailing: _buildRadio(key.infos.indexOf(e), e), + trailing: _buildRadio(key.pkis.indexOf(e), e), ), ) .toList();