Example #1
0
        public static async Task EnterpriseNodeCommand(this IEnterpriseContext context, EnterpriseNodeOptions arguments)
        {
            if (string.IsNullOrEmpty(arguments.Command))
            {
                arguments.Command = "tree";
            }

            if (arguments.Force)
            {
                await context.Enterprise.PopulateEnterprise();
            }

            if (context.Enterprise.RootNode == null)
            {
                throw new Exception("Enterprise data: cannot get root node");
            }
            switch (arguments.Command.ToLowerInvariant())
            {
            case "tree":
            {
                context.PrintNodeTree(context.Enterprise.RootNode, "", true);
            }
            break;

            default:
                Console.WriteLine($"Unsupported command \"{arguments.Command}\": available commands \"tree\"");
                break;
            }
        }
Example #2
0
        public static async Task GetEnterpriseData(this IEnterpriseContext context, params string[] includes)
        {
            var requested = new HashSet <string>(includes);
            var rq        = new GetEnterpriseDataCommand
            {
                include = requested.ToArray()
            };
            var rs = await context.Enterprise.Auth.ExecuteAuthCommand <GetEnterpriseDataCommand, GetEnterpriseDataResponse>(rq);

            if (requested.Contains("devices_request_for_admin_approval"))
            {
                context.DeviceForAdminApprovals = rs.DeviceRequestForApproval != null?rs.DeviceRequestForApproval.ToArray() : new GetDeviceForAdminApproval[0];
            }
        }
Example #3
0
        public static void PrintNodeTree(this IEnterpriseContext context, EnterpriseNode eNode, string indent, bool last)
        {
            var isRoot = string.IsNullOrEmpty(indent);

            Console.WriteLine(indent + (isRoot ? "" : "+-- ") + eNode.DisplayName);
            indent += isRoot ? " " : (last ? "    " : "|   ");
            var subNodes = eNode.Subnodes
                           .Select(x => context.Enterprise.TryGetNode(x, out var node) ? node : null)
                           .Where(x => x != null)
                           .OrderBy(x => x.DisplayName ?? "")
                           .ToArray();

            for (var i = 0; i < subNodes.Length; i++)
            {
                context.PrintNodeTree(subNodes[i], indent, i == subNodes.Length - 1);
            }
        }
Example #4
0
        public static IEnumerable <string> GetNodePath(this IEnterpriseContext context, EnterpriseNode node)
        {
            while (true)
            {
                yield return(node.DisplayName);

                if (node.Id <= 0)
                {
                    yield break;
                }
                if (!context.Enterprise.TryGetNode(node.ParentNodeId, out var parent))
                {
                    yield break;
                }
                node = parent;
            }
        }
Example #5
0
        internal static async Task DenyAdminDeviceRequests(this IEnterpriseContext context, GetDeviceForAdminApproval[] devices)
        {
            var rq = new ApproveUserDevicesRequest();

            foreach (var device in devices)
            {
                var deviceRq = new ApproveUserDeviceRequest
                {
                    EnterpriseUserId     = device.EnterpriseUserId,
                    EncryptedDeviceToken = ByteString.CopyFrom(device.EncryptedDeviceToken.Base64UrlDecode()),
                    DenyApproval         = true,
                };
                rq.DeviceRequests.Add(deviceRq);
                if (rq.DeviceRequests.Count == 0)
                {
                    Console.WriteLine("No device to approve/deny");
                }
                else
                {
                    var rs = await context.Enterprise.Auth
                             .ExecuteAuthRest <ApproveUserDevicesRequest, ApproveUserDevicesResponse>("enterprise/approve_user_devices", rq);

                    if (rs.DeviceResponses?.Count > 0)
                    {
                        foreach (var approveRs in rs.DeviceResponses)
                        {
                            if (!approveRs.Failed)
                            {
                                continue;
                            }
                            if (context.Enterprise.TryGetUserById(approveRs.EnterpriseUserId, out var user))
                            {
                                Console.WriteLine($"Failed to approve {user.Email}: {approveRs.Message}");
                            }
                        }
                    }

                    context.DeviceForAdminApprovals = null;
                }
            }
        }
Example #6
0
        internal static async Task EnterpriseRegisterEcKey(this IEnterpriseContext context, CliCommands cli)
        {
            if (context.Enterprise.TreeKey == null)
            {
                Console.WriteLine("Cannot get tree key");
                return;
            }

            CryptoUtils.GenerateEcKey(out var privateKey, out var publicKey);
            var exportedPublicKey   = CryptoUtils.UnloadEcPublicKey(publicKey);
            var exportedPrivateKey  = CryptoUtils.UnloadEcPrivateKey(privateKey);
            var encryptedPrivateKey = CryptoUtils.EncryptAesV2(exportedPrivateKey, context.Enterprise.TreeKey);
            var request             = new EnterpriseKeyPairRequest
            {
                KeyType                       = KeyType.Ecc,
                EnterprisePublicKey           = ByteString.CopyFrom(exportedPublicKey),
                EncryptedEnterprisePrivateKey = ByteString.CopyFrom(encryptedPrivateKey),
            };

            await context.Enterprise.Auth.ExecuteAuthRest("enterprise/set_enterprise_key_pair", request);

            cli.Commands.Remove("enterprise-add-key");
        }
Example #7
0
        internal static async Task RunAuditEventsReport(this IEnterpriseContext context, AuditReportOptions options)
        {
            if (context.AuditEvents == null)
            {
                var auditEvents = await context.Enterprise.Auth.GetAvailableEvents();

                lock (context)
                {
                    context.AuditEvents = new ConcurrentDictionary <string, AuditEventType>();
                    foreach (var evt in auditEvents)
                    {
                        context.AuditEvents[evt.Name] = evt;
                    }
                }
            }

            var filter = new ReportFilter();

            if (!string.IsNullOrEmpty(options.Created))
            {
                filter.Created = ParseDateCreatedFilter(options.Created);
            }

            if (options.EventType != null && options.EventType.Any())
            {
                filter.EventTypes = options.EventType.ToArray();
            }

            if (!string.IsNullOrEmpty(options.Username))
            {
                filter.Username = options.Username;
            }

            if (!string.IsNullOrEmpty(options.RecordUid))
            {
                filter.RecordUid = options.RecordUid;
            }

            if (!string.IsNullOrEmpty(options.SharedFolderUid))
            {
                filter.SharedFolderUid = options.SharedFolderUid;
            }

            var rq = new GetAuditEventReportsCommand
            {
                Filter = filter,
                Limit  = options.Limit,
            };

            var rs = await context.Enterprise.Auth.ExecuteAuthCommand <GetAuditEventReportsCommand, GetAuditEventReportsResponse>(rq);

            var tab = new Tabulate(4)
            {
                DumpRowNo = true
            };

            tab.AddHeader("Created", "Username", "Event", "Message");
            tab.MaxColumnWidth = 100;
            foreach (var evt in rs.Events)
            {
                if (!evt.TryGetValue("audit_event_type", out var v))
                {
                    continue;
                }
                var eventName = v.ToString();
                if (!context.AuditEvents.TryGetValue(eventName, out var eventType))
                {
                    continue;
                }

                var message = eventType.SyslogMessage;
                do
                {
                    var match = Regex.Match(message, ParameterPattern);
                    if (!match.Success)
                    {
                        break;
                    }
                    if (match.Groups.Count != 2)
                    {
                        break;
                    }
                    var parameter = match.Groups[1].Value;
                    var value     = "";
                    if (evt.TryGetValue(parameter, out v))
                    {
                        value = v.ToString();
                    }

                    message = message.Remove(match.Groups[0].Index, match.Groups[0].Length);
                    message = message.Insert(match.Groups[0].Index, value);
                } while (true);
                var created = "";
                if (evt.TryGetValue("created", out v))
                {
                    created = v.ToString();
                    if (long.TryParse(created, out var epoch))
                    {
                        created = DateTimeOffset.FromUnixTimeSeconds(epoch).ToString("G");
                    }
                }
                var username = "";
                if (evt.TryGetValue("username", out v))
                {
                    username = v.ToString();
                }
                tab.AddRow(created, username, eventName, message);
            }
            tab.Dump();
        }
Example #8
0
        internal static async Task ApproveAdminDeviceRequests(this IEnterpriseContext context, GetDeviceForAdminApproval[] devices)
        {
            var dataKeys = new Dictionary <long, byte[]>();

            foreach (var device in devices)
            {
                if (!dataKeys.ContainsKey(device.EnterpriseUserId))
                {
                    dataKeys[device.EnterpriseUserId] = context.UserDataKeys.TryGetValue(device.EnterpriseUserId, out var dk) ? dk : null;
                }
            }

            var toLoad = dataKeys.Where(x => x.Value == null).Select(x => x.Key).ToArray();

            if (toLoad.Any() && context.EnterprisePrivateKey != null)
            {
                var dataKeyRq = new UserDataKeyRequest();
                dataKeyRq.EnterpriseUserId.AddRange(toLoad);
                var dataKeyRs = await context.Enterprise.Auth.ExecuteAuthRest <UserDataKeyRequest, EnterpriseUserDataKeys>("enterprise/get_enterprise_user_data_key", dataKeyRq);

                foreach (var key in dataKeyRs.Keys)
                {
                    if (key.UserEncryptedDataKey.IsEmpty)
                    {
                        continue;
                    }
                    try
                    {
                        var userDataKey = CryptoUtils.DecryptEc(key.UserEncryptedDataKey.ToByteArray(), context.EnterprisePrivateKey);
                        context.UserDataKeys[key.EnterpriseUserId] = userDataKey;
                        dataKeys[key.EnterpriseUserId]             = userDataKey;
                    }
                    catch (Exception e)
                    {
                        Debug.WriteLine($"Data key decrypt error: {e.Message}");
                    }
                }
            }

            var rq = new ApproveUserDevicesRequest();

            foreach (var device in devices)
            {
                if (!dataKeys.TryGetValue(device.EnterpriseUserId, out var dk))
                {
                    continue;
                }
                if (string.IsNullOrEmpty(device.DevicePublicKey))
                {
                    continue;
                }
                var devicePublicKey = CryptoUtils.LoadPublicEcKey(device.DevicePublicKey.Base64UrlDecode());

                try
                {
                    var deviceRq = new ApproveUserDeviceRequest
                    {
                        EnterpriseUserId       = device.EnterpriseUserId,
                        EncryptedDeviceToken   = ByteString.CopyFrom(device.EncryptedDeviceToken.Base64UrlDecode()),
                        EncryptedDeviceDataKey = ByteString.CopyFrom(CryptoUtils.EncryptEc(dk, devicePublicKey))
                    };
                    rq.DeviceRequests.Add(deviceRq);
                }
                catch (Exception e)
                {
                    Debug.WriteLine(e.Message);
                }
            }
            if (rq.DeviceRequests.Count == 0)
            {
                Console.WriteLine("No device to approve/deny");
            }
            else
            {
                var rs = await
                         context.Enterprise.Auth.ExecuteAuthRest <ApproveUserDevicesRequest, ApproveUserDevicesResponse>("enterprise/approve_user_devices", rq);

                if (rs.DeviceResponses?.Count > 0)
                {
                    foreach (var approveRs in rs.DeviceResponses)
                    {
                        if (!approveRs.Failed)
                        {
                            continue;
                        }

                        if (context.Enterprise.TryGetUserById(approveRs.EnterpriseUserId, out var user))
                        {
                            Console.WriteLine($"Failed to approve {user.Email}: {approveRs.Message}");
                        }
                    }
                }
                context.DeviceForAdminApprovals = null;
            }
        }
Example #9
0
        public static async Task EnterpriseDeviceCommand(this IEnterpriseContext context, EnterpriseDeviceOptions arguments)
        {
            if (arguments.AutoApprove.HasValue)
            {
                context.AutoApproveAdminRequests = arguments.AutoApprove.Value;
                Console.WriteLine($"Automatic Admin Device Approval is {(context.AutoApproveAdminRequests ? "ON" : "OFF")}");
            }

            if (string.IsNullOrEmpty(arguments.Command))
            {
                arguments.Command = "list";
            }

            if (arguments.Force || context.DeviceForAdminApprovals == null)
            {
                await context.GetEnterpriseData("devices_request_for_admin_approval");
            }

            if (context.DeviceForAdminApprovals == null || context.DeviceForAdminApprovals.Length == 0)
            {
                Console.WriteLine("There are no pending devices");
                return;
            }

            var cmd = arguments.Command.ToLowerInvariant();

            switch (cmd)
            {
            case "list":
                var tab = new Tabulate(4)
                {
                    DumpRowNo = false
                };
                Console.WriteLine();
                tab.AddHeader("Email", "Device ID", "Device Name", "Client Version");
                foreach (var device in context.DeviceForAdminApprovals)
                {
                    if (!context.Enterprise.TryGetUserById(device.EnterpriseUserId, out var user))
                    {
                        continue;
                    }

                    var deiceToken = device.EncryptedDeviceToken.Base64UrlDecode();
                    tab.AddRow(user.Email, deiceToken.TokenToString(), device.DeviceName, device.ClientVersion);
                }

                tab.Sort(1);
                tab.Dump();
                break;

            case "approve":
            case "deny":
                if (string.IsNullOrEmpty(arguments.Match))
                {
                    Console.WriteLine($"{arguments.Command} command requires device ID or user email parameter.");
                }
                else
                {
                    var devices = context.DeviceForAdminApprovals
                                  .Where(x =>
                    {
                        if (arguments.Match == "all")
                        {
                            return(true);
                        }
                        var deviceToken = x.EncryptedDeviceToken.Base64UrlDecode();
                        var deviceId    = deviceToken.TokenToString();
                        if (deviceId.StartsWith(arguments.Match))
                        {
                            return(true);
                        }

                        if (!context.Enterprise.TryGetUserById(x.EnterpriseUserId, out var user))
                        {
                            return(false);
                        }
                        return(user.Email == arguments.Match);
                    }).ToArray();

                    if (devices.Length > 0)
                    {
                        if (cmd == "approve")
                        {
                            await context.ApproveAdminDeviceRequests(devices);
                        }
                        else
                        {
                            await context.DenyAdminDeviceRequests(devices);
                        }
                    }
                    else
                    {
                        Console.WriteLine($"No device found matching {arguments.Match}");
                    }
                }

                break;
            }
        }
Example #10
0
        internal static async Task AppendEnterpriseCommands(this IEnterpriseContext context, CliCommands cli)
        {
            cli.Commands.Add("enterprise-sync-down",
                             new SimpleCommand
            {
                Order       = 60,
                Description = "Retrieve enterprise data",
                Action      = async _ => { await context.Enterprise.PopulateEnterprise(); },
            });

            cli.Commands.Add("enterprise-node",
                             new ParsableCommand <EnterpriseNodeOptions>
            {
                Order       = 61,
                Description = "Display node structure",
                Action      = async options => { await context.EnterpriseNodeCommand(options); },
            });

            cli.Commands.Add("enterprise-user",
                             new ParsableCommand <EnterpriseUserOptions>
            {
                Order       = 62,
                Description = "List Enterprise Users",
                Action      = async options => { await context.EnterpriseUserCommand(options); },
            });

            cli.Commands.Add("enterprise-team",
                             new ParsableCommand <EnterpriseTeamOptions>
            {
                Order       = 63,
                Description = "List Enterprise Teams",
                Action      = async options => { await context.EnterpriseTeamCommand(options); },
            });

            cli.Commands.Add("enterprise-device",
                             new ParsableCommand <EnterpriseDeviceOptions>
            {
                Order       = 64,
                Description = "Manage User Devices",
                Action      = async options => { await context.EnterpriseDeviceCommand(options); },
            });

            cli.Commands.Add("audit-report",
                             new ParsableCommand <AuditReportOptions>
            {
                Order       = 64,
                Description = "Run an audit trail report.",
                Action      = async options => { await context.RunAuditEventsReport(options); },
            });

            cli.CommandAliases["esd"] = "enterprise-sync-down";
            cli.CommandAliases["en"]  = "enterprise-node";
            cli.CommandAliases["eu"]  = "enterprise-user";
            cli.CommandAliases["et"]  = "enterprise-team";
            cli.CommandAliases["ed"]  = "enterprise-device";

            var entRq = new GetEnterpriseDataCommand
            {
                include = new[] { "keys" }
            };
            var entRs = await context.Enterprise.Auth.ExecuteAuthCommand <GetEnterpriseDataCommand, GetEnterpriseDataResponse>(entRq);

            if (string.IsNullOrEmpty(entRs.Keys?.EccEncryptedPrivateKey))
            {
                cli.Commands.Add("enterprise-add-key",
                                 new SimpleCommand
                {
                    Order       = 63,
                    Description = "Register ECC key pair",
                    Action      = async options => { await context.EnterpriseRegisterEcKey(cli); },
                });
            }
            else
            {
                var privateKeyData = CryptoUtils.DecryptAesV2(
                    entRs.Keys.EccEncryptedPrivateKey.Base64UrlDecode(), context.Enterprise.TreeKey);
                context.EnterprisePrivateKey = CryptoUtils.LoadPrivateEcKey(privateKeyData);
            }
        }
Example #11
0
        public static async Task EnterpriseTeamCommand(this IEnterpriseContext context, EnterpriseTeamOptions arguments)
        {
            if (arguments.Force)
            {
                await context.Enterprise.PopulateEnterprise();
            }

            if (string.IsNullOrEmpty(arguments.Command))
            {
                arguments.Command = "list";
            }
            if (string.CompareOrdinal(arguments.Command, "list") == 0)
            {
                var teams = context.Enterprise.Teams
                            .Where(x =>
                {
                    if (string.IsNullOrEmpty(arguments.Name))
                    {
                        return(true);
                    }
                    if (arguments.Name == x.Uid)
                    {
                        return(true);
                    }
                    var m = Regex.Match(x.Name, arguments.Name, RegexOptions.IgnoreCase);
                    return(m.Success);
                })
                            .ToArray();
                var tab = new Tabulate(7)
                {
                    DumpRowNo = true
                };
                tab.AddHeader("Team Name", "Team UID", "Node Name", "Restrict Edit", "Restrict Share", "Restrict View", "Users");
                foreach (var team in teams)
                {
                    EnterpriseNode node = null;
                    if (team.ParentNodeId > 0)
                    {
                        context.Enterprise.TryGetNode(team.ParentNodeId, out node);
                    }
                    else
                    {
                        node = context.Enterprise.RootNode;
                    }

                    tab.AddRow(team.Name,
                               team.Uid,
                               node != null ? node.DisplayName : "",
                               team.RestrictEdit ? "X" : "-",
                               team.RestrictSharing ? "X" : "-",
                               team.RestrictView ? "X" : "-",
                               team.Users.Count.ToString());
                }

                tab.Sort(1);
                tab.Dump();
            }
            else
            {
                var team = context.Enterprise.Teams
                           .FirstOrDefault(x =>
                {
                    if (string.IsNullOrEmpty(arguments.Name))
                    {
                        return(true);
                    }
                    if (arguments.Name == x.Uid)
                    {
                        return(true);
                    }
                    return(string.Compare(x.Name, arguments.Name, StringComparison.CurrentCultureIgnoreCase) == 0);
                });
                if (string.CompareOrdinal(arguments.Command, "delete") == 0)
                {
                    if (team == null)
                    {
                        Console.WriteLine($"Team \"{arguments.Name}\" not found");
                        return;
                    }

                    await context.Enterprise.DeleteTeam(team.Uid);
                }
                else if (string.CompareOrdinal(arguments.Command, "view") == 0)
                {
                    if (team == null)
                    {
                        Console.WriteLine($"Team \"{arguments.Name}\" not found");
                        return;
                    }

                    var tab = new Tabulate(2)
                    {
                        DumpRowNo = false
                    };
                    tab.SetColumnRightAlign(0, true);
                    tab.AddRow(" Team Name:", team.Name);
                    tab.AddRow(" Team UID:", team.Uid);
                    tab.AddRow(" Restrict Edit:", team.RestrictEdit ? "Yes" : "No");
                    tab.AddRow(" Restrict Share:", team.RestrictSharing ? "Yes" : "No");
                    tab.AddRow(" Restrict View:", team.RestrictView ? "Yes" : "No");
                    var users = team.Users
                                .Select(x => context.Enterprise.TryGetUserById(x, out var user) ? user.Email : null)
                                .Where(x => !string.IsNullOrEmpty(x))
                                .ToArray();
                    Array.Sort(users);
                    tab.AddRow(" Users:", users.Length > 0 ? users[0] : "");
                    for (var i = 1; i < users.Length; i++)
                    {
                        tab.AddRow("", users[i]);
                    }

                    if (context.Enterprise.TryGetNode(team.ParentNodeId, out var node))
                    {
                        var nodes = context.GetNodePath(node).ToArray();
                        Array.Reverse(nodes);
                        tab.AddRow(" Node:", string.Join(" -> ", nodes));
                    }

                    tab.Dump();
                }
                else if (string.CompareOrdinal(arguments.Command, "update") == 0 || string.CompareOrdinal(arguments.Command, "add") == 0)
                {
                    if (team == null)
                    {
                        if (string.CompareOrdinal(arguments.Command, "update") == 0 ||
                            string.CompareOrdinal(arguments.Command, "view") == 0)
                        {
                            Console.WriteLine($"Team \"{arguments.Name}\" not found");
                            return;
                        }

                        team = new EnterpriseTeam
                        {
                            ParentNodeId = context.Enterprise.RootNode.Id
                        };
                    }
                    else
                    {
                        if (string.CompareOrdinal(arguments.Command, "add") == 0)
                        {
                            Console.WriteLine($"Team with name \"{arguments.Name}\" already exists.\nDo you want to create a new one? Yes/No");
                            var answer = await Program.GetInputManager().ReadLine();

                            if (string.Compare("y", answer, StringComparison.InvariantCultureIgnoreCase) == 0)
                            {
                                answer = "yes";
                            }

                            if (string.Compare(answer, "yes", StringComparison.InvariantCultureIgnoreCase) != 0)
                            {
                                return;
                            }
                        }
                    }

                    team.Name = arguments.Name;
                    if (CliCommands.ParseBoolOption(arguments.RestrictEdit, out var b))
                    {
                        team.RestrictEdit = b;
                    }

                    if (CliCommands.ParseBoolOption(arguments.RestrictShare, out b))
                    {
                        team.RestrictSharing = b;
                    }

                    if (CliCommands.ParseBoolOption(arguments.RestrictView, out b))
                    {
                        team.RestrictView = b;
                    }

                    if (!string.IsNullOrEmpty(arguments.Node))
                    {
                        long?asId = null;
                        if (arguments.Node.All(char.IsDigit))
                        {
                            if (long.TryParse(arguments.Node, out var l))
                            {
                                asId = l;
                            }
                        }

                        var node = context.Enterprise.Nodes
                                   .FirstOrDefault(x =>
                        {
                            if (asId.HasValue && asId.Value == x.Id)
                            {
                                return(true);
                            }
                            return(string.Compare(x.DisplayName, arguments.Node, StringComparison.CurrentCultureIgnoreCase) == 0);
                        });
                        if (node != null)
                        {
                            team.ParentNodeId = node.Id;
                        }
                    }

                    await context.Enterprise.UpdateTeam(team);
                }
                else
                {
                    Console.WriteLine($"Unsupported command \"{arguments.Command}\". Valid commands are  \"list\", \"view\", \"add\", \"delete\", \"update\"");
                }
            }
        }
Example #12
0
        public static async Task EnterpriseUserCommand(this IEnterpriseContext context, EnterpriseUserOptions arguments)
        {
            if (string.IsNullOrEmpty(arguments.Command))
            {
                arguments.Command = "list";
            }

            if (arguments.Force)
            {
                await context.Enterprise.PopulateEnterprise();
            }

            if (string.Compare(arguments.Command, "list", StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                var users = context.Enterprise.Users
                            .Where(x =>
                {
                    if (string.IsNullOrEmpty(arguments.Name))
                    {
                        return(true);
                    }
                    var m = Regex.Match(x.Email, arguments.Name, RegexOptions.IgnoreCase);
                    if (m.Success)
                    {
                        return(true);
                    }
                    if (!string.IsNullOrEmpty(x.DisplayName))
                    {
                        m = Regex.Match(x.DisplayName, arguments.Name, RegexOptions.IgnoreCase);
                        if (m.Success)
                        {
                            return(true);
                        }
                    }

                    var status = x.UserStatus.ToString();
                    m          = Regex.Match(status, arguments.Name, RegexOptions.IgnoreCase);
                    return(m.Success);
                })
                            .ToArray();

                var tab = new Tabulate(4)
                {
                    DumpRowNo = true
                };
                tab.AddHeader("Email", "Display Name", "Status", "Teams");
                foreach (var user in users)
                {
                    tab.AddRow(user.Email, user.DisplayName, user.UserStatus.ToString(), user.Teams.Count);
                }

                tab.Sort(1);
                tab.Dump();
            }
            else if (string.Compare(arguments.Command, "view", StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                var user = context.Enterprise.Users
                           .FirstOrDefault(x =>
                {
                    if (string.Compare(x.DisplayName, arguments.Name, StringComparison.CurrentCultureIgnoreCase) == 0)
                    {
                        return(true);
                    }
                    if (x.Email.StartsWith(arguments.Name, StringComparison.InvariantCulture))
                    {
                        return(true);
                    }
                    return(false);
                });
                if (user == null)
                {
                    Console.WriteLine($"Enterprise user \"{arguments.Name}\" not found");
                    return;
                }
                var tab = new Tabulate(2)
                {
                    DumpRowNo = false
                };
                tab.SetColumnRightAlign(0, true);
                tab.AddRow(" User Email:", user.Email);
                tab.AddRow(" User Name:", user.DisplayName);
                tab.AddRow(" User ID:", user.Id.ToString());
                tab.AddRow(" Status:", user.UserStatus.ToString());

                var teams = user.Teams
                            .Select(x => context.Enterprise.TryGetTeam(x, out var team) ? team.Name : null)
                            .Where(x => !string.IsNullOrEmpty(x))
                            .ToArray();
                Array.Sort(teams);
                tab.AddRow(" Teams:", teams.Length > 0 ? teams[0] : "");
                for (var i = 1; i < teams.Length; i++)
                {
                    tab.AddRow("", teams[i]);
                }

                if (context.Enterprise.TryGetNode(user.ParentNodeId, out var node))
                {
                    var nodes = context.GetNodePath(node).ToArray();
                    Array.Reverse(nodes);
                    tab.AddRow(" Node:", string.Join(" -> ", nodes));
                }

                tab.Dump();
            }
            else if (string.Compare(arguments.Command, "team-add", StringComparison.InvariantCultureIgnoreCase) == 0 || string.Compare(arguments.Command, "team-remove", StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                var user = context.Enterprise.Users
                           .FirstOrDefault(x =>
                {
                    if (string.Compare(x.DisplayName, arguments.Name, StringComparison.CurrentCultureIgnoreCase) == 0)
                    {
                        return(true);
                    }
                    if (string.Compare(x.Email, arguments.Name, StringComparison.InvariantCulture) == 0)
                    {
                        return(true);
                    }
                    return(true);
                });
                if (user == null)
                {
                    Console.WriteLine($"Enterprise user \"{arguments.Name}\" not found");
                    return;
                }

                if (string.IsNullOrEmpty(arguments.Team))
                {
                    Console.WriteLine("Team name parameter is mandatory.");
                    return;
                }

                var team = context.Enterprise.Teams
                           .FirstOrDefault(x =>
                {
                    if (string.CompareOrdinal(x.Uid, arguments.Team) == 0)
                    {
                        return(true);
                    }
                    return(string.Compare(x.Name, arguments.Team, StringComparison.CurrentCultureIgnoreCase) == 0);
                });
                if (team == null)
                {
                    Console.WriteLine($"Team {arguments.Team} cannot be found.");
                    return;
                }

                if (string.Compare(arguments.Command, "team-add", StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    await context.Enterprise.AddUsersToTeams(new[] { user.Email }, new[] { team.Uid }, Console.WriteLine);
                }
                else
                {
                    await context.Enterprise.RemoveUsersFromTeams(new[] { user.Email }, new[] { team.Uid }, Console.WriteLine);
                }
            }
            else
            {
                Console.WriteLine($"Unsupported command \"{arguments.Command}\". Commands are \"list\", \"view\", \"team-add\", \"team-remove\"");
            }
        }