Browse Source

improve PIN check when PIN is none

pull/18/head
Sun 4 years ago
parent
commit
64a375edd7
  1. 5
      lib/account.dart
  2. 10
      lib/apps/device/page.dart
  3. 1
      lib/l10n/localizations.dart
  4. 2
      lib/l10n/localizations_en.dart
  5. 2
      lib/l10n/localizations_zh.dart
  6. 6
      lib/pages/account_generate.dart
  7. 4
      lib/pages/account_quick.dart
  8. 4
      lib/pages/account_restore.dart
  9. 26
      lib/pages/home.dart
  10. 40
      lib/pages/setting/profile.dart
  11. 48
      lib/provider.dart
  12. 101
      lib/security.dart
  13. 18
      lib/utils/logined_cache.dart
  14. 46
      lib/widgets/show_pin.dart
  15. 2
      src/apps/wallet/models.rs
  16. 6
      src/rpc.rs

5
lib/account.dart

@ -126,15 +126,14 @@ extension LanguageExtension on Language { @@ -126,15 +126,14 @@ extension LanguageExtension on Language {
class Account {
String gid = '';
String name = '';
String lock = '';
Uint8List? avatar;
bool online = false;
bool hasNew = false;
String pin = '';
Account(String gid, String name, [String lock = "", String avatar = "", bool online = false]) {
Account(String gid, String name, [String avatar = "", bool online = false]) {
this.gid = gid;
this.name = name;
this.lock = lock;
this.updateAvatar(avatar);
this.online = online;
this.hasNew = false;

10
lib/apps/device/page.dart

@ -207,18 +207,20 @@ class _DevicesPageState extends State<DevicesPage> { @@ -207,18 +207,20 @@ class _DevicesPageState extends State<DevicesPage> {
Icons.security_rounded,
lang.verifyPin,
PinWords(
hashPin: account.lock,
callback: (_key, _hash) async {
gid: account.gid,
callback: (key) async {
Navigator.of(context).pop();
_showQrCode(
account.name,
account.gid,
Global.addr,
account.lock,
key,
color,
lang,
);
}));
}),
0.0
);
}
},
itemBuilder: (context) {

1
lib/l10n/localizations.dart

@ -98,6 +98,7 @@ abstract class AppLocalizations { @@ -98,6 +98,7 @@ abstract class AppLocalizations {
String get waiting;
String get notExist;
String get skip;
String get none;
String get register;
String get gallery;
String get link;

2
lib/l10n/localizations_en.dart

@ -121,6 +121,8 @@ class AppLocalizationsEn extends AppLocalizations { @@ -121,6 +121,8 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get skip => 'Skip';
@override
String get none => 'None';
@override
String get register => 'Register';
@override
String get gallery => 'Gallery';

2
lib/l10n/localizations_zh.dart

@ -121,6 +121,8 @@ class AppLocalizationsZh extends AppLocalizations { @@ -121,6 +121,8 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get skip => '跳过';
@override
String get none => '';
@override
String get register => '注册';
@override
String get gallery => '图库';

6
lib/pages/account_generate.dart

@ -102,9 +102,9 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> { @@ -102,9 +102,9 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> {
if (res.isOk) {
// save this User
final account = Account(res.params[0], name, lock, avatar);
final account = Account(res.params[0], name, avatar);
Provider.of<AccountProvider>(context, listen: false).addAccount(account);
Provider.of<AccountProvider>(context, listen: false).addAccount(account, lock);
Provider.of<DeviceProvider>(context, listen: false).updateActived();
Provider.of<ChatProvider>(context, listen: false).updateActived();
Provider.of<GroupChatProvider>(context, listen: false).updateActived();
@ -117,7 +117,7 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> { @@ -117,7 +117,7 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> {
print(res.error);
}
}),
20.0,
0.0
);
}

4
lib/pages/account_quick.dart

@ -144,9 +144,9 @@ class _AccountQuickPageState extends State<AccountQuickPage> { @@ -144,9 +144,9 @@ class _AccountQuickPageState extends State<AccountQuickPage> {
if (res.isOk) {
// save this User
final account = Account(res.params[0], name, lock, avatar);
final account = Account(res.params[0], name, avatar);
Provider.of<AccountProvider>(context, listen: false).addAccount(account);
Provider.of<AccountProvider>(context, listen: false).addAccount(account, lock);
Provider.of<DeviceProvider>(context, listen: false).updateActived();
Provider.of<ChatProvider>(context, listen: false).updateActived();
Provider.of<GroupChatProvider>(context, listen: false).updateActived();

4
lib/pages/account_restore.dart

@ -410,7 +410,7 @@ class _AccountRestorePageState extends State<AccountRestorePage> { @@ -410,7 +410,7 @@ class _AccountRestorePageState extends State<AccountRestorePage> {
// save this User
final account = Account(res.params[0], this._name, lock);
Provider.of<AccountProvider>(context, listen: false).addAccount(account);
Provider.of<AccountProvider>(context, listen: false).addAccount(account, lock);
Provider.of<DeviceProvider>(context, listen: false).updateActived();
Provider.of<ChatProvider>(context, listen: false).updateActived();
Provider.of<GroupChatProvider>(context, listen: false).updateActived();
@ -421,7 +421,7 @@ class _AccountRestorePageState extends State<AccountRestorePage> { @@ -421,7 +421,7 @@ class _AccountRestorePageState extends State<AccountRestorePage> {
print(res.error);
}
}),
20.0,
0.0
);
}
}

26
lib/pages/home.dart

@ -326,7 +326,7 @@ class DrawerWidget extends StatelessWidget { @@ -326,7 +326,7 @@ class DrawerWidget extends StatelessWidget {
? () {
Navigator.of(context).pop();
Provider.of<AccountProvider>(context, listen: false)
.updateActivedAccount(account.gid);
.updateActivedAccount(account.gid, account.pin);
Provider.of<DeviceProvider>(context, listen: false)
.updateActived();
Provider.of<ChatProvider>(context, listen: false)
@ -354,17 +354,19 @@ class DrawerWidget extends StatelessWidget { @@ -354,17 +354,19 @@ class DrawerWidget extends StatelessWidget {
onChanged: (value) {
if (value) {
showShadowDialog(
context,
Icons.security_rounded,
lang.verifyPin,
PinWords(
hashPin: account.lock,
callback: (key, hash) async {
Navigator.of(context).pop();
Provider.of<AccountProvider>(context,
listen: false)
.onlineAccount(account.gid, hash);
}));
context,
Icons.security_rounded,
lang.verifyPin,
PinWords(
gid: account.gid,
callback: (key) async {
Navigator.of(context).pop();
Provider.of<AccountProvider>(context,
listen: false)
.onlineAccount(account.gid, key);
}),
0.0,
);
} else {
Provider.of<AccountProvider>(context, listen: false)
.offlineAccount(account.gid);

40
lib/pages/setting/profile.dart

@ -177,9 +177,9 @@ class _ProfileDetailState extends State<ProfileDetail> { @@ -177,9 +177,9 @@ class _ProfileDetailState extends State<ProfileDetail> {
size: 20.0, color: color.primary),
const SizedBox(width: 20.0),
TextButton(
onPressed: () => _pinCheck(account.lock,
() => _changePin(context, account.gid, account.lock, lang.setPin),
lang.verifyPin,
onPressed: () => _pinCheck(account.gid,
(key) => _changePin(context, account.gid, key, lang.setPin),
lang.verifyPin, color
),
child: Text(lang.change + ' PIN'),
),
@ -200,8 +200,8 @@ class _ProfileDetailState extends State<ProfileDetail> { @@ -200,8 +200,8 @@ class _ProfileDetailState extends State<ProfileDetail> {
child: Text(lang.hide + ' ' + lang.mnemonic),
)
: TextButton(
onPressed: () => _pinCheck(account.lock,
() => _showMnemonic(account.gid, account.lock), lang.verifyPin),
onPressed: () => _pinCheck(account.gid,
(key) => _showMnemonic(account.gid, key), lang.verifyPin, color),
child: Text(lang.show + ' ' + lang.mnemonic),
),
]),
@ -260,7 +260,7 @@ class _ProfileDetailState extends State<ProfileDetail> { @@ -260,7 +260,7 @@ class _ProfileDetailState extends State<ProfileDetail> {
print(res.error);
}
}),
20.0, // height.
0.0, // height.
);
}
@ -278,20 +278,18 @@ class _ProfileDetailState extends State<ProfileDetail> { @@ -278,20 +278,18 @@ class _ProfileDetailState extends State<ProfileDetail> {
}
}
_pinCheck(String hash, Function callback, String title) {
if (hash.length > 0) {
showShadowDialog(
context,
Icons.security_rounded,
title,
PinWords(
hashPin: hash,
callback: (_) async {
Navigator.of(context).pop();
callback();
}));
} else {
callback();
}
_pinCheck(String gid, Function callback, String title, color) {
showShadowDialog(
context,
Icons.security_rounded,
title,
PinWords(
gid: gid,
callback: (key) async {
Navigator.of(context).pop();
callback(key);
}),
0.0,
);
}
}

48
lib/provider.dart

@ -63,49 +63,44 @@ class AccountProvider extends ChangeNotifier { @@ -63,49 +63,44 @@ class AccountProvider extends ChangeNotifier {
rpc.addListener('session-lost', _sessionLost, false);
}
/// when security load accounts from rpc.
initAccounts(Map<String, Account> accounts) {
this.accounts = accounts;
initLogined(this.accounts.values.toList());
}
/// when security load accounts from cache.
autoAccounts(String gid, Map<String, Account> accounts) {
autoAccounts(String gid, String pin, Map<String, Account> accounts) {
Global.changeGid(gid);
this.activedAccountId = gid;
this.accounts = accounts;
this.activedAccountId = gid;
this.activedAccount.online = true;
rpc.send('session-list', []);
this.activedAccount.pin = pin;
rpc.send('session-list', []);
new Future.delayed(Duration(seconds: DEFAULT_ONLINE_INIT),
() => rpc.send('account-online', [gid]));
// online other keep-online account.
this.accounts.forEach((k, v) {
if (k != gid && v.online) {
rpc.send('account-login', [v.gid, v.lock]);
new Future.delayed(Duration(seconds: DEFAULT_ONLINE_INIT),
() => rpc.send('account-online', [v.gid]));
}
});
initLogined(gid, this.accounts.values.toList());
}
/// when security add account.
addAccount(Account account) {
addAccount(Account account, String pin) {
Global.changeGid(account.gid);
this.activedAccountId = account.gid;
this.accounts[account.gid] = account;
this.activedAccountId = account.gid;
this.activedAccount.online = true;
this.activedAccount.pin = pin;
rpc.send('session-list', []);
updateLogined(account);
}
updateActivedAccount(String gid) {
updateActivedAccount(String gid, String pin) {
Global.changeGid(gid);
this.clearActivedAccount();
this.activedAccountId = gid;
this.activedAccount.online = true;
this.activedAccount.pin = pin;
this.activedAccount.hasNew = false;
this.coreShowWidget = DefaultCoreShow();
// load sessions.
@ -136,11 +131,11 @@ class AccountProvider extends ChangeNotifier { @@ -136,11 +131,11 @@ class AccountProvider extends ChangeNotifier {
clearLogined();
}
onlineAccount(String gid, String lock) {
onlineAccount(String gid, String pin) {
this.accounts[gid]!.online = true;
updateLogined(this.accounts[gid]!);
this.accounts[gid]!.pin = pin;
rpc.send('account-login', [gid, lock]);
rpc.send('account-login', [gid, pin]);
new Future.delayed(Duration(seconds: DEFAULT_ONLINE_DELAY),
() => rpc.send('account-online', [gid]));
@ -149,7 +144,7 @@ class AccountProvider extends ChangeNotifier { @@ -149,7 +144,7 @@ class AccountProvider extends ChangeNotifier {
offlineAccount(String gid) {
this.accounts[gid]!.online = false;
updateLogined(this.accounts[gid]!);
this.accounts[gid]!.pin = '';
if (gid == this.activedAccountId) {
this.clearActivedAccount();
@ -177,9 +172,8 @@ class AccountProvider extends ChangeNotifier { @@ -177,9 +172,8 @@ class AccountProvider extends ChangeNotifier {
notifyListeners();
}
accountPin(String lock) {
this.activedAccount.lock = lock;
updateLogined(this.activedAccount);
accountPin(String pin) {
this.activedAccount.pin = pin;
notifyListeners();
}

101
lib/security.dart

@ -35,7 +35,6 @@ class _SecurityPageState extends State<SecurityPage> { @@ -35,7 +35,6 @@ class _SecurityPageState extends State<SecurityPage> {
bool _accountsLoaded = false;
String _selectedUserId = '';
String _selectedUserLock = '';
SystemUiOverlayStyle style = SystemUiOverlayStyle.dark;
@ -166,6 +165,14 @@ class _SecurityPageState extends State<SecurityPage> { @@ -166,6 +165,14 @@ class _SecurityPageState extends State<SecurityPage> {
);
}
_handleLogined(String mainId, String mainPin, Map<String, Account> accounts) {
Provider.of<AccountProvider>(context, listen: false).autoAccounts(mainId, mainPin, accounts);
Provider.of<DeviceProvider>(context, listen: false).updateActived();
Provider.of<ChatProvider>(context, listen: false).updateActived();
Provider.of<GroupChatProvider>(context, listen: false).updateActived();
Navigator.of(context).pushNamedAndRemoveUntil("/", (Route<dynamic> route) => false);
}
void loadAccounts() async {
// init rpc.
if (!rpc.isLinked()) {
@ -180,25 +187,28 @@ class _SecurityPageState extends State<SecurityPage> { @@ -180,25 +187,28 @@ class _SecurityPageState extends State<SecurityPage> {
if (loginedAccounts.length != 0) {
print("INFO: START LOGINED USE CACHE");
final mainAccount = loginedAccounts[0];
final res = await httpPost(Global.httpRpc, 'account-login', [mainAccount.gid, mainAccount.lock]);
Map<String, Account> accounts = {};
loginedAccounts.forEach((account) {
accounts[account.gid] = account;
});
final res = await httpPost(Global.httpRpc, 'account-login', [mainAccount.gid, ""]);
if (res.isOk) {
Map<String, Account> accounts = {};
loginedAccounts.forEach((account) {
accounts[account.gid] = account;
});
Provider.of<AccountProvider>(context, listen: false).autoAccounts(mainAccount.gid, accounts);
Provider.of<DeviceProvider>(context, listen: false).updateActived();
Provider.of<ChatProvider>(context, listen: false).updateActived();
Provider.of<GroupChatProvider>(context, listen: false).updateActived();
Navigator.of(context).pushNamedAndRemoveUntil("/", (Route<dynamic> route) => false);
_handleLogined(mainAccount.gid, "", accounts);
return;
} else {
// TODO tostor error
print(res.error);
await clearLogined();
showShadowDialog(
context,
Icons.security_rounded,
"PIN",
PinWords(
gid: mainAccount.gid,
callback: (key) async {
Navigator.of(context).pop();
_handleLogined(mainAccount.gid, key, accounts);
return;
}),
0.0
);
}
}
@ -207,19 +217,16 @@ class _SecurityPageState extends State<SecurityPage> { @@ -207,19 +217,16 @@ class _SecurityPageState extends State<SecurityPage> {
if (res.isOk) {
this._accounts.clear();
res.params.forEach((param) {
this._accounts[param[0]] = Account(param[0], param[1], param[2], param[3]);
this._accounts[param[0]] = Account(param[0], param[1], param[2]);
});
Provider.of<AccountProvider>(context, listen: false).initAccounts(this._accounts);
if (this._accounts.length > 0) {
final accountId = this._accounts.keys.first;
this._selectedUserId = this._accounts[accountId]!.gid;
this._selectedUserLock = this._accounts[accountId]!.lock;
this._accountsLoaded = true;
}
} else {
// TODO tostor error
print(res.error);
toast(context, res.error);
}
setState(() {
@ -228,48 +235,27 @@ class _SecurityPageState extends State<SecurityPage> { @@ -228,48 +235,27 @@ class _SecurityPageState extends State<SecurityPage> {
}
void _verifyAfter(String lock) async {
final res = await httpPost(Global.httpRpc, 'account-login',
[this._selectedUserId, lock]);
final res = await httpPost(Global.httpRpc, 'account-login', [this._selectedUserId, lock]);
if (res.isOk) {
final mainAccount = this._accounts[this._selectedUserId]!;
Provider.of<AccountProvider>(context, listen: false).updateActivedAccount(mainAccount.gid);
Provider.of<DeviceProvider>(context, listen: false).updateActived();
Provider.of<ChatProvider>(context, listen: false).updateActived();
Provider.of<GroupChatProvider>(context, listen: false).updateActived();
Navigator.of(context).pushNamedAndRemoveUntil("/", (Route<dynamic> route) => false);
_handleLogined(this._selectedUserId, lock, this._accounts);
} else {
// TODO tostor error
toast(context, res.error);
}
}
void loginAction(String title, color, lang) {
if (this._selectedUserLock.length == 0) {
_verifyAfter('');
} else {
showShadowDialog(
context,
Icons.security_rounded,
title,
PinWords(
hashPin: this._selectedUserLock,
callback: (pinWords) async {
Navigator.of(context).pop();
_verifyAfter(pinWords);
}),
40.0,
InkWell(
onTap: () => _verifyAfter(''),
child: Container(
child: Icon(
Icons.arrow_forward,
color: color.primary,
)))
);
}
showShadowDialog(
context,
Icons.security_rounded,
title,
PinWords(
gid: this._selectedUserId,
callback: (pinWords) async {
Navigator.of(context).pop();
_verifyAfter(pinWords);
}),
0.0,
);
}
Widget loginForm(ColorScheme color, AppLocalizations lang) {
@ -293,7 +279,6 @@ class _SecurityPageState extends State<SecurityPage> { @@ -293,7 +279,6 @@ class _SecurityPageState extends State<SecurityPage> {
if (gid != null) {
setState(() {
this._selectedUserId = gid;
this._selectedUserLock = this._accounts[gid]!.lock;
});
}
},

18
lib/utils/logined_cache.dart

@ -16,9 +16,8 @@ Future<List<Account>> getLogined() async { @@ -16,9 +16,8 @@ Future<List<Account>> getLogined() async {
accounts.add(Account(
fields[0], // gid
fields[1], // name
fields[2], // lock
fields[3], // avatar
fields[4] == "1", // online
fields[2], // avatar
false,
));
} else {
prefs.remove(id);
@ -29,7 +28,7 @@ Future<List<Account>> getLogined() async { @@ -29,7 +28,7 @@ Future<List<Account>> getLogined() async {
return accounts;
}
initLogined(List<Account> accounts) async {
initLogined(String gid, List<Account> accounts) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final ids = prefs.getStringList(LOGINED_CACHE_NAME);
if (ids != null) {
@ -38,17 +37,18 @@ initLogined(List<Account> accounts) async { @@ -38,17 +37,18 @@ initLogined(List<Account> accounts) async {
});
}
List<String> newIds = [];
List<String> newIds = [gid];
accounts.forEach((account) {
final List<String> fields = [
account.gid,
account.name,
account.lock,
account.encodeAvatar(),
account.online ? "1" : "0",
];
newIds.add(account.gid);
if (account.gid != gid) {
newIds.add(account.gid);
}
prefs.setStringList(account.gid, fields);
});
@ -72,9 +72,7 @@ updateLogined(Account account) async { @@ -72,9 +72,7 @@ updateLogined(Account account) async {
final List<String> fields = [
account.gid,
account.name,
account.lock,
account.encodeAvatar(),
account.online ? "1" : "0",
];
prefs.setStringList(account.gid, fields);

46
lib/widgets/show_pin.dart

@ -57,9 +57,9 @@ Widget _keyboradInput(Color color, Color bg, String text, Function callback) { @@ -57,9 +57,9 @@ Widget _keyboradInput(Color color, Color bg, String text, Function callback) {
class PinWords extends StatefulWidget {
final Function callback;
final String hashPin;
final String gid;
PinWords({Key? key, required this.hashPin, required this.callback}) : super(key: key);
PinWords({Key? key, required this.gid, required this.callback}) : super(key: key);
@override
_PinWordsState createState() => _PinWordsState();
@ -72,14 +72,14 @@ class _PinWordsState extends State<PinWords> { @@ -72,14 +72,14 @@ class _PinWordsState extends State<PinWords> {
_checkPin() async {
bool check = false;
final res = await httpPost(Global.httpRpc, 'account-pin-check', [_pinWords]);
final res = await httpPost(Global.httpRpc, 'account-pin-check', [widget.gid, _pinWords]);
if (res.isOk) {
check = res.params[0];
} else {
print(res.error);
}
if (widget.hashPin != "" && !check) {
if (!check) {
setState(() {
_waiting = false;
_pinWords = '';
@ -96,6 +96,10 @@ class _PinWordsState extends State<PinWords> { @@ -96,6 +96,10 @@ class _PinWordsState extends State<PinWords> {
return;
}
if (_pinWords.length >= pinLength) {
return;
}
_isError = false;
_pinWords += text;
if (_pinWords.length < pinLength) {
@ -190,6 +194,25 @@ class _PinWordsState extends State<PinWords> { @@ -190,6 +194,25 @@ class _PinWordsState extends State<PinWords> {
),
),
]),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(lang.none, style: TextStyle(color: color.primary, fontStyle: FontStyle.italic)),
IconButton(
icon: Icon(Icons.skip_next, color: color.primary),
onPressed: () {
setState(() {
this._pinWords = '';
this._waiting = true;
});
_checkPin();
}
),
]
)
),
]);
}
}
@ -325,7 +348,20 @@ class _SetPinWordsState extends State<SetPinWords> { @@ -325,7 +348,20 @@ class _SetPinWordsState extends State<SetPinWords> {
size: 20.0, color: Colors.white)),
),
),
])
]),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(lang.none, style: TextStyle(color: color.primary, fontStyle: FontStyle.italic)),
IconButton(
icon: Icon(Icons.skip_next, color: color.primary),
onPressed: () => widget.callback(''),
),
]
)
),
]);
}
}

2
src/apps/wallet/models.rs

@ -220,7 +220,7 @@ impl Address { @@ -220,7 +220,7 @@ impl Address {
pub fn insert(&mut self, db: &DStorage) -> Result<()> {
let sql = format!(
"INSERT INTO addresses (chain, indx, name, address, secret) VALUES ({}, {}, '{}', '{}', '{}', '{}')",
"INSERT INTO addresses (chain, indx, name, address, secret, balance) VALUES ({}, {}, '{}', '{}', '{}', '{}')",
self.chain.to_i64(),
self.index,
self.name,

6
src/rpc.rs

@ -235,7 +235,6 @@ fn new_rpc_handler( @@ -235,7 +235,6 @@ fn new_rpc_handler(
users.push(vec![
gid.to_hex(),
user.name.clone(),
base64::encode(&user.lock),
base64::encode(&user.avatar),
]);
}
@ -352,8 +351,9 @@ fn new_rpc_handler( @@ -352,8 +351,9 @@ fn new_rpc_handler(
handler.add_method(
"account-pin-check",
|gid: GroupId, params: Vec<RpcParam>, state: Arc<RpcState>| async move {
let lock = params[0].as_str().ok_or(RpcError::ParseError)?;
|_gid: GroupId, params: Vec<RpcParam>, state: Arc<RpcState>| async move {
let gid = GroupId::from_hex(params[0].as_str().ok_or(RpcError::ParseError)?)?;
let lock = params[1].as_str().ok_or(RpcError::ParseError)?;
let res = state.group.read().await.check_lock(&gid, lock);
Ok(HandleResult::rpc(json!([res])))
},

Loading…
Cancel
Save