2021-07-29 05:24:42 +00:00
|
|
|
import 'package:hive/hive.dart';
|
|
|
|
import 'package:selfprivacy/config/hive_config.dart';
|
2022-04-03 19:54:18 +00:00
|
|
|
import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart';
|
2022-05-14 02:54:40 +00:00
|
|
|
import 'package:selfprivacy/logic/models/hive/user.dart';
|
2022-03-03 17:38:30 +00:00
|
|
|
|
|
|
|
import '../../api_maps/server.dart';
|
|
|
|
|
2020-12-03 16:52:53 +00:00
|
|
|
export 'package:provider/provider.dart';
|
|
|
|
|
|
|
|
part 'users_state.dart';
|
|
|
|
|
2022-05-17 13:31:34 +00:00
|
|
|
class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
|
2022-05-17 20:08:28 +00:00
|
|
|
UsersCubit(ServerInstallationCubit serverInstallationCubit)
|
2022-04-03 19:54:18 +00:00
|
|
|
: super(
|
2022-05-17 20:08:28 +00:00
|
|
|
serverInstallationCubit,
|
2022-05-24 18:55:39 +00:00
|
|
|
const UsersState(
|
2022-04-03 19:54:18 +00:00
|
|
|
<User>[], User(login: 'root'), User(login: 'loading...')));
|
2022-05-18 08:27:36 +00:00
|
|
|
Box<User> box = Hive.box<User>(BNames.usersBox);
|
|
|
|
Box serverInstallationBox = Hive.box(BNames.serverInstallationBox);
|
2020-12-03 16:52:53 +00:00
|
|
|
|
2022-03-03 17:38:30 +00:00
|
|
|
final api = ServerApi();
|
2021-12-06 18:31:19 +00:00
|
|
|
|
2022-05-24 18:55:39 +00:00
|
|
|
@override
|
2022-03-03 17:38:30 +00:00
|
|
|
Future<void> load() async {
|
2022-05-17 20:08:28 +00:00
|
|
|
if (serverInstallationCubit.state is ServerInstallationFinished) {
|
2022-04-03 19:54:18 +00:00
|
|
|
var loadedUsers = box.values.toList();
|
2022-05-17 20:08:28 +00:00
|
|
|
final primaryUser = serverInstallationBox.get(BNames.rootUser,
|
2022-05-24 18:55:39 +00:00
|
|
|
defaultValue: const User(login: 'loading...'));
|
2022-04-03 19:54:18 +00:00
|
|
|
List<String> rootKeys = [
|
2022-05-17 20:08:28 +00:00
|
|
|
...serverInstallationBox.get(BNames.rootKeys, defaultValue: [])
|
2022-04-03 19:54:18 +00:00
|
|
|
];
|
|
|
|
if (loadedUsers.isNotEmpty) {
|
|
|
|
emit(UsersState(
|
|
|
|
loadedUsers, User(login: 'root', sshKeys: rootKeys), primaryUser));
|
|
|
|
}
|
2022-03-03 17:38:30 +00:00
|
|
|
|
2022-04-03 19:54:18 +00:00
|
|
|
final usersFromServer = await api.getUsersList();
|
|
|
|
if (usersFromServer.isSuccess) {
|
|
|
|
final updatedList =
|
|
|
|
mergeLocalAndServerUsers(loadedUsers, usersFromServer.data);
|
|
|
|
emit(UsersState(
|
|
|
|
updatedList, User(login: 'root', sshKeys: rootKeys), primaryUser));
|
|
|
|
}
|
2022-03-03 17:38:30 +00:00
|
|
|
|
2022-04-03 19:54:18 +00:00
|
|
|
final usersWithSshKeys = await loadSshKeys(state.users);
|
|
|
|
// Update the users it the box
|
|
|
|
box.clear();
|
|
|
|
box.addAll(usersWithSshKeys);
|
2022-03-03 17:38:30 +00:00
|
|
|
|
2022-04-03 19:54:18 +00:00
|
|
|
final rootUserWithSshKeys = (await loadSshKeys([state.rootUser])).first;
|
2022-05-17 20:08:28 +00:00
|
|
|
serverInstallationBox.put(BNames.rootKeys, rootUserWithSshKeys.sshKeys);
|
2022-04-03 19:54:18 +00:00
|
|
|
final primaryUserWithSshKeys =
|
|
|
|
(await loadSshKeys([state.primaryUser])).first;
|
2022-05-17 20:08:28 +00:00
|
|
|
serverInstallationBox.put(BNames.rootUser, primaryUserWithSshKeys);
|
2022-04-03 19:54:18 +00:00
|
|
|
emit(UsersState(
|
|
|
|
usersWithSshKeys, rootUserWithSshKeys, primaryUserWithSshKeys));
|
|
|
|
}
|
2022-03-03 17:38:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
List<User> mergeLocalAndServerUsers(
|
|
|
|
List<User> localUsers, List<String> serverUsers) {
|
|
|
|
// If local user not exists on server, add it with isFoundOnServer = false
|
|
|
|
// If server user not exists on local, add it
|
|
|
|
|
|
|
|
List<User> mergedUsers = [];
|
|
|
|
List<String> serverUsersCopy = List.from(serverUsers);
|
|
|
|
|
|
|
|
for (var localUser in localUsers) {
|
|
|
|
if (serverUsersCopy.contains(localUser.login)) {
|
|
|
|
mergedUsers.add(User(
|
|
|
|
login: localUser.login,
|
|
|
|
isFoundOnServer: true,
|
|
|
|
password: localUser.password,
|
|
|
|
sshKeys: localUser.sshKeys,
|
|
|
|
));
|
|
|
|
serverUsersCopy.remove(localUser.login);
|
|
|
|
} else {
|
|
|
|
mergedUsers.add(User(
|
|
|
|
login: localUser.login,
|
|
|
|
isFoundOnServer: false,
|
|
|
|
password: localUser.password,
|
|
|
|
note: localUser.note,
|
|
|
|
));
|
|
|
|
}
|
2021-07-29 05:24:42 +00:00
|
|
|
}
|
2022-03-03 17:38:30 +00:00
|
|
|
|
|
|
|
for (var serverUser in serverUsersCopy) {
|
|
|
|
mergedUsers.add(User(
|
|
|
|
login: serverUser,
|
|
|
|
isFoundOnServer: true,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
return mergedUsers;
|
2021-07-29 05:24:42 +00:00
|
|
|
}
|
2020-12-03 16:52:53 +00:00
|
|
|
|
2022-03-03 17:38:30 +00:00
|
|
|
Future<List<User>> loadSshKeys(List<User> users) async {
|
|
|
|
List<User> updatedUsers = [];
|
2021-07-29 05:24:42 +00:00
|
|
|
|
2022-03-03 17:38:30 +00:00
|
|
|
for (var user in users) {
|
|
|
|
if (user.isFoundOnServer ||
|
|
|
|
user.login == 'root' ||
|
|
|
|
user.login == state.primaryUser.login) {
|
|
|
|
final sshKeys = await api.getUserSshKeys(user);
|
|
|
|
print('sshKeys for $user: ${sshKeys.data}');
|
|
|
|
if (sshKeys.isSuccess) {
|
|
|
|
updatedUsers.add(User(
|
|
|
|
login: user.login,
|
|
|
|
isFoundOnServer: true,
|
|
|
|
password: user.password,
|
|
|
|
sshKeys: sshKeys.data,
|
|
|
|
note: user.note,
|
|
|
|
));
|
|
|
|
} else {
|
|
|
|
updatedUsers.add(User(
|
|
|
|
login: user.login,
|
|
|
|
isFoundOnServer: true,
|
|
|
|
password: user.password,
|
|
|
|
note: user.note,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
updatedUsers.add(User(
|
|
|
|
login: user.login,
|
|
|
|
isFoundOnServer: false,
|
|
|
|
password: user.password,
|
|
|
|
note: user.note,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return updatedUsers;
|
2020-12-03 16:52:53 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 17:38:30 +00:00
|
|
|
Future<void> refresh() async {
|
2022-03-23 14:07:52 +00:00
|
|
|
List<User> updatedUsers = List<User>.from(state.users);
|
2022-03-03 17:38:30 +00:00
|
|
|
final usersFromServer = await api.getUsersList();
|
|
|
|
if (usersFromServer.isSuccess) {
|
|
|
|
updatedUsers =
|
2022-03-23 14:07:52 +00:00
|
|
|
mergeLocalAndServerUsers(updatedUsers, usersFromServer.data);
|
2022-03-03 17:38:30 +00:00
|
|
|
}
|
|
|
|
final usersWithSshKeys = await loadSshKeys(updatedUsers);
|
|
|
|
box.clear();
|
|
|
|
box.addAll(usersWithSshKeys);
|
|
|
|
final rootUserWithSshKeys = (await loadSshKeys([state.rootUser])).first;
|
2022-05-17 20:08:28 +00:00
|
|
|
serverInstallationBox.put(BNames.rootKeys, rootUserWithSshKeys.sshKeys);
|
2022-03-03 17:38:30 +00:00
|
|
|
final primaryUserWithSshKeys =
|
|
|
|
(await loadSshKeys([state.primaryUser])).first;
|
2022-05-17 20:08:28 +00:00
|
|
|
serverInstallationBox.put(BNames.rootUser, primaryUserWithSshKeys);
|
2022-03-03 17:38:30 +00:00
|
|
|
emit(UsersState(
|
|
|
|
usersWithSshKeys, rootUserWithSshKeys, primaryUserWithSshKeys));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> createUser(User user) async {
|
|
|
|
// If user exists on server, do nothing
|
|
|
|
if (state.users.any((u) => u.login == user.login && u.isFoundOnServer)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// If user is root or primary user, do nothing
|
|
|
|
if (user.login == 'root' || user.login == state.primaryUser.login) {
|
|
|
|
return;
|
|
|
|
}
|
2022-05-02 11:56:46 +00:00
|
|
|
// If API returned error, do nothing
|
2022-03-03 17:38:30 +00:00
|
|
|
final result = await api.createUser(user);
|
2022-05-02 11:56:46 +00:00
|
|
|
if (!result.isSuccess) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-03-23 14:07:52 +00:00
|
|
|
var loadedUsers = List<User>.from(state.users);
|
|
|
|
loadedUsers.add(result.data);
|
|
|
|
await box.clear();
|
|
|
|
await box.addAll(loadedUsers);
|
|
|
|
emit(state.copyWith(users: loadedUsers));
|
2022-03-03 17:38:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> deleteUser(User user) async {
|
|
|
|
// If user is primary or root, don't delete
|
|
|
|
if (user.login == state.primaryUser.login || user.login == 'root') {
|
|
|
|
return;
|
|
|
|
}
|
2022-03-23 14:07:52 +00:00
|
|
|
var loadedUsers = List<User>.from(state.users);
|
2022-03-03 17:38:30 +00:00
|
|
|
final result = await api.deleteUser(user);
|
|
|
|
if (result) {
|
2022-03-23 14:07:52 +00:00
|
|
|
loadedUsers.removeWhere((u) => u.login == user.login);
|
|
|
|
await box.clear();
|
|
|
|
await box.addAll(loadedUsers);
|
|
|
|
emit(state.copyWith(users: loadedUsers));
|
2022-03-03 17:38:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> addSshKey(User user, String publicKey) async {
|
|
|
|
// If adding root key, use api.addRootSshKey
|
|
|
|
// Otherwise, use api.addUserSshKey
|
|
|
|
if (user.login == 'root') {
|
|
|
|
final result = await api.addRootSshKey(publicKey);
|
|
|
|
if (result.isSuccess) {
|
|
|
|
// Add ssh key to the array of root keys
|
2022-05-17 20:08:28 +00:00
|
|
|
final rootKeys = serverInstallationBox
|
|
|
|
.get(BNames.rootKeys, defaultValue: []) as List<String>;
|
2022-03-03 17:38:30 +00:00
|
|
|
rootKeys.add(publicKey);
|
2022-05-17 20:08:28 +00:00
|
|
|
serverInstallationBox.put(BNames.rootKeys, rootKeys);
|
2022-03-03 17:38:30 +00:00
|
|
|
emit(state.copyWith(
|
|
|
|
rootUser: User(
|
|
|
|
login: state.rootUser.login,
|
|
|
|
isFoundOnServer: true,
|
|
|
|
password: state.rootUser.password,
|
|
|
|
sshKeys: rootKeys,
|
|
|
|
note: state.rootUser.note,
|
|
|
|
),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
final result = await api.addUserSshKey(user, publicKey);
|
|
|
|
if (result.isSuccess) {
|
|
|
|
// If it is primary user, update primary user
|
|
|
|
if (user.login == state.primaryUser.login) {
|
2022-03-23 14:07:52 +00:00
|
|
|
List<String> primaryUserKeys =
|
|
|
|
List<String>.from(state.primaryUser.sshKeys);
|
2022-03-03 17:38:30 +00:00
|
|
|
primaryUserKeys.add(publicKey);
|
|
|
|
final updatedUser = User(
|
|
|
|
login: state.primaryUser.login,
|
|
|
|
isFoundOnServer: true,
|
|
|
|
password: state.primaryUser.password,
|
|
|
|
sshKeys: primaryUserKeys,
|
|
|
|
note: state.primaryUser.note,
|
|
|
|
);
|
2022-05-17 20:08:28 +00:00
|
|
|
serverInstallationBox.put(BNames.rootUser, updatedUser);
|
2022-03-03 17:38:30 +00:00
|
|
|
emit(state.copyWith(
|
|
|
|
primaryUser: updatedUser,
|
|
|
|
));
|
|
|
|
} else {
|
|
|
|
// If it is not primary user, update user
|
2022-03-23 14:07:52 +00:00
|
|
|
List<String> userKeys = List<String>.from(user.sshKeys);
|
2022-03-03 17:38:30 +00:00
|
|
|
userKeys.add(publicKey);
|
|
|
|
final updatedUser = User(
|
|
|
|
login: user.login,
|
|
|
|
isFoundOnServer: true,
|
|
|
|
password: user.password,
|
|
|
|
sshKeys: userKeys,
|
|
|
|
note: user.note,
|
|
|
|
);
|
|
|
|
await box.putAt(box.values.toList().indexOf(user), updatedUser);
|
|
|
|
emit(state.copyWith(
|
|
|
|
users: box.values.toList(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> deleteSshKey(User user, String publicKey) async {
|
|
|
|
// All keys are deleted via api.deleteUserSshKey
|
|
|
|
|
|
|
|
final result = await api.deleteUserSshKey(user, publicKey);
|
|
|
|
if (result.isSuccess) {
|
|
|
|
// If it is root user, delete key from root keys
|
|
|
|
// If it is primary user, update primary user
|
|
|
|
// If it is not primary user, update user
|
|
|
|
|
|
|
|
if (user.login == 'root') {
|
2022-05-17 20:08:28 +00:00
|
|
|
final rootKeys = serverInstallationBox
|
|
|
|
.get(BNames.rootKeys, defaultValue: []) as List<String>;
|
2022-03-03 17:38:30 +00:00
|
|
|
rootKeys.remove(publicKey);
|
2022-05-17 20:08:28 +00:00
|
|
|
serverInstallationBox.put(BNames.rootKeys, rootKeys);
|
2022-03-03 17:38:30 +00:00
|
|
|
emit(state.copyWith(
|
|
|
|
rootUser: User(
|
|
|
|
login: state.rootUser.login,
|
|
|
|
isFoundOnServer: true,
|
|
|
|
password: state.rootUser.password,
|
|
|
|
sshKeys: rootKeys,
|
|
|
|
note: state.rootUser.note,
|
|
|
|
),
|
|
|
|
));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (user.login == state.primaryUser.login) {
|
2022-03-23 14:07:52 +00:00
|
|
|
List<String> primaryUserKeys =
|
|
|
|
List<String>.from(state.primaryUser.sshKeys);
|
2022-03-03 17:38:30 +00:00
|
|
|
primaryUserKeys.remove(publicKey);
|
|
|
|
final updatedUser = User(
|
|
|
|
login: state.primaryUser.login,
|
|
|
|
isFoundOnServer: true,
|
|
|
|
password: state.primaryUser.password,
|
|
|
|
sshKeys: primaryUserKeys,
|
|
|
|
note: state.primaryUser.note,
|
|
|
|
);
|
2022-05-17 20:08:28 +00:00
|
|
|
serverInstallationBox.put(BNames.rootUser, updatedUser);
|
2022-03-03 17:38:30 +00:00
|
|
|
emit(state.copyWith(
|
|
|
|
primaryUser: updatedUser,
|
|
|
|
));
|
|
|
|
return;
|
|
|
|
}
|
2022-03-23 14:07:52 +00:00
|
|
|
List<String> userKeys = List<String>.from(user.sshKeys);
|
2022-03-03 17:38:30 +00:00
|
|
|
userKeys.remove(publicKey);
|
|
|
|
final updatedUser = User(
|
|
|
|
login: user.login,
|
|
|
|
isFoundOnServer: true,
|
|
|
|
password: user.password,
|
|
|
|
sshKeys: userKeys,
|
|
|
|
note: user.note,
|
|
|
|
);
|
|
|
|
await box.putAt(box.values.toList().indexOf(user), updatedUser);
|
|
|
|
emit(state.copyWith(
|
|
|
|
users: box.values.toList(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
2020-12-03 16:52:53 +00:00
|
|
|
|
2022-04-03 19:54:18 +00:00
|
|
|
@override
|
|
|
|
void clear() async {
|
2022-05-24 18:55:39 +00:00
|
|
|
emit(const UsersState(
|
|
|
|
<User>[], User(login: 'root'), User(login: 'loading...')));
|
2022-04-03 19:54:18 +00:00
|
|
|
}
|
2020-12-03 16:52:53 +00:00
|
|
|
}
|