public static async Task PopulateUserPublicKeys(this EnterpriseData enterprise, IDictionary <string, byte[]> publicKeys, Action <string> warnings = null) { var toLoad = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase); toLoad.UnionWith(publicKeys.Keys); toLoad.ExceptWith(enterprise.UserPublicKeyCache.Keys); if (toLoad.Count > 0) { var publicKeyRq = new PublicKeysCommand { keyOwners = toLoad.ToArray() }; var publicKeyRs = await enterprise.Auth.ExecuteAuthCommand <PublicKeysCommand, PublicKeysResponse>(publicKeyRq); if (publicKeyRs.publicKeys != null) { foreach (var key in publicKeyRs.publicKeys) { if (!string.IsNullOrEmpty(key.publicKey)) { enterprise.UserPublicKeyCache[key.keyOwner] = key.publicKey.Base64UrlDecode(); } else { warnings?.Invoke($"User \'{key.keyOwner}\': Public key error ({key.resultCode}): {key.message}"); enterprise.UserPublicKeyCache[key.keyOwner] = null; } } } } foreach (var email in publicKeys.Keys.ToArray()) { if (enterprise.UserPublicKeyCache.TryGetValue(email, out var pk)) { publicKeys[email] = pk; } } }
/// <summary> /// Adds (if needed) user or team to the shared folder and set user access permissions. /// </summary> /// <param name="sharedFolderUid">Shared Folder UID.</param> /// <param name="userId">User email or Team UID.</param> /// <param name="userType">Type of <see cref="userId"/> parameter.</param> /// <param name="options">Shared Folder User Permissions.</param> /// <returns>Awaitable task.</returns> /// <remarks> /// If <seealso cref="options"/> parameter is <c>null</c> then user gets default user permissions when added./> /// </remarks> /// <exception cref="Authentication.KeeperApiException"></exception> /// <seealso cref="IVaultSharedFolder.PutUserToSharedFolder"/> public async Task PutUserToSharedFolder(string sharedFolderUid, string userId, UserType userType, ISharedFolderUserOptions options) { var sharedFolder = this.GetSharedFolder(sharedFolderUid); var perm = this.ResolveSharedFolderAccessPath(Auth.Username, sharedFolderUid, true); if (perm == null) { throw new VaultException("You don't have permission to manage users."); } var request = new SharedFolderUpdateCommand { pt = Auth.AuthContext.SessionToken.Base64UrlEncode(), operation = "update", shared_folder_uid = sharedFolder.Uid, from_team_uid = perm.UserType == UserType.Team ? perm.UserId : null, name = CryptoUtils.EncryptAesV1(Encoding.UTF8.GetBytes(sharedFolder.Name), sharedFolder.SharedFolderKey).Base64UrlEncode(), forceUpdate = true, }; if (userType == UserType.User) { if (sharedFolder.UsersPermissions.Any(x => x.UserType == UserType.User && x.UserId == userId)) { request.updateUsers = new[] { new SharedFolderUpdateUser { Username = userId, ManageUsers = options?.ManageUsers, ManageRecords = options?.ManageRecords, } }; } else { var pkRq = new PublicKeysCommand { keyOwners = new[] { userId }, }; var pkRs = await Auth.ExecuteAuthCommand <PublicKeysCommand, PublicKeysResponse>(pkRq); if (pkRs.publicKeys == null || pkRs.publicKeys.Length == 0) { throw new VaultException($"Cannot get public key of user: {userId}"); } var pk = pkRs.publicKeys[0]; if (!string.IsNullOrEmpty(pk.resultCode)) { throw new KeeperApiException(pk.resultCode, pk.message); } var publicKey = CryptoUtils.LoadPublicKey(pk.publicKey.Base64UrlDecode()); request.addUsers = new[] { new SharedFolderUpdateUser { Username = userId, ManageUsers = options?.ManageUsers, ManageRecords = options?.ManageRecords, SharedFolderKey = CryptoUtils.EncryptRsa(sharedFolder.SharedFolderKey, publicKey).Base64UrlEncode(), } }; } } else { if (sharedFolder.UsersPermissions.Any(x => x.UserType == UserType.Team && x.UserId == userId)) { request.updateTeams = new[] { new SharedFolderUpdateTeam { TeamUid = userId, ManageUsers = options?.ManageUsers, ManageRecords = options?.ManageRecords, } }; } else { string encryptedSharedFolderKey; if (TryGetTeam(userId, out var team)) { encryptedSharedFolderKey = CryptoUtils.EncryptAesV1(sharedFolder.SharedFolderKey, team.TeamKey).Base64UrlEncode(); } else { var tkRq = new TeamGetKeysCommand { teams = new[] { userId }, }; var tkRs = await Auth.ExecuteAuthCommand <TeamGetKeysCommand, TeamGetKeysResponse>(tkRq); if (tkRs.keys == null || tkRs.keys.Length == 0) { throw new VaultException($"Cannot get public key of team: {userId}"); } var tk = tkRs.keys[0]; if (!string.IsNullOrEmpty(tk.resultCode)) { throw new KeeperApiException(tk.resultCode, tk.message); } var tpk = CryptoUtils.LoadPublicKey(tk.key.Base64UrlDecode()); encryptedSharedFolderKey = CryptoUtils.EncryptRsa(sharedFolder.SharedFolderKey, tpk).Base64UrlEncode(); } request.addTeams = new[] { new SharedFolderUpdateTeam { TeamUid = userId, ManageUsers = options?.ManageUsers, ManageRecords = options?.ManageRecords, SharedFolderKey = encryptedSharedFolderKey, } }; } } var response = await Auth.ExecuteAuthCommand <SharedFolderUpdateCommand, SharedFolderUpdateResponse>(request); foreach (var arr in (new[] { response.addUsers, response.updateUsers })) { var failed = arr?.FirstOrDefault(x => x.Status != "success"); if (failed != null) { throw new VaultException($"Put \"{failed.Username}\" to Shared Folder \"{sharedFolder.Name}\" error: {failed.Status}"); } } foreach (var arr in (new[] { response.addTeams, response.updateTeams })) { var failed = arr?.FirstOrDefault(x => x.Status != "success"); if (failed != null) { throw new VaultException($"Put Team Uid \"{failed.TeamUid}\" to Shared Folder \"{sharedFolder.Name}\" error: {failed.Status}"); } } await ScheduleSyncDown(TimeSpan.FromSeconds(0)); }