Exemplo n.º 1
0
        public static async Task <int> Run(
            int interval,
            bool pullOutlineServer,
            bool deployOutlineServer,
            bool generateOnlineConfig,
            bool regenerateOnlineConfig,
            CancellationToken cancellationToken = default)
        {
            if (interval < 60 || interval > int.MaxValue / 1000)
            {
                Console.WriteLine($"Interval can't be shorter than 60 seconds or longer than {int.MaxValue / 1000} seconds.");
                return(1);
            }

            try
            {
                while (true)
                {
                    var(users, loadUsersErrMsg) = await Users.LoadUsersAsync(cancellationToken);

                    if (loadUsersErrMsg is not null)
                    {
                        Console.WriteLine(loadUsersErrMsg);
                        return(1);
                    }

                    var(loadedNodes, loadNodesErrMsg) = await Nodes.LoadNodesAsync(cancellationToken);

                    if (loadNodesErrMsg is not null)
                    {
                        Console.WriteLine(loadNodesErrMsg);
                        return(1);
                    }
                    using var nodes = loadedNodes;

                    var(settings, loadSettingsErrMsg) = await Settings.LoadSettingsAsync(cancellationToken);

                    if (loadSettingsErrMsg is not null)
                    {
                        Console.WriteLine(loadSettingsErrMsg);
                        return(1);
                    }

                    if (pullOutlineServer)
                    {
                        var errMsgs = nodes.PullFromOutlineServerForAllGroups(users, true, cancellationToken);

                        await foreach (var errMsg in errMsgs)
                        {
                            Console.WriteLine(errMsg);
                        }

                        users.CalculateDataUsageForAllUsers(nodes);

                        Console.WriteLine("Pulled from Outline servers.");
                    }
                    if (deployOutlineServer)
                    {
                        var errMsgs = nodes.DeployAllOutlineServers(users, cancellationToken);

                        await foreach (var errMsg in errMsgs)
                        {
                            Console.WriteLine(errMsg);
                        }

                        Console.WriteLine("Deployed to Outline servers.");
                    }
                    if (generateOnlineConfig)
                    {
                        var errMsg = await SIP008StaticGen.GenerateAndSave(users, nodes, settings, cancellationToken);

                        if (errMsg is not null)
                        {
                            Console.Write(errMsg);
                        }

                        Console.WriteLine("Generated online config.");
                    }
                    if (regenerateOnlineConfig)
                    {
                        SIP008StaticGen.Remove(users, settings);

                        Console.WriteLine("Cleaned online config.");

                        var errMsg = await SIP008StaticGen.GenerateAndSave(users, nodes, settings, cancellationToken);

                        if (errMsg is not null)
                        {
                            Console.Write(errMsg);
                        }

                        Console.WriteLine("Generated online config.");
                    }

                    var saveUsersErrMsg = await Users.SaveUsersAsync(users, cancellationToken);

                    if (saveUsersErrMsg is not null)
                    {
                        Console.WriteLine(saveUsersErrMsg);
                        return(1);
                    }

                    var saveNodesErrMsg = await Nodes.SaveNodesAsync(nodes, cancellationToken);

                    if (saveNodesErrMsg is not null)
                    {
                        Console.WriteLine(saveNodesErrMsg);
                        return(1);
                    }

                    await Task.Delay(interval * 1000, cancellationToken);
                }
            }
            catch (OperationCanceledException) // Task.Delay() canceled
            {
            }
            catch (Exception ex) // other unhandled
            {
                Console.WriteLine($"An error occurred while executing one of the scheduled tasks: {ex.Message}");
                return(-1);
            }

            return(0);
        }
        public static async Task <int> Remove(string[] usernames, CancellationToken cancellationToken = default)
        {
            var commandResult = 0;

            var(users, loadUsersErrMsg) = await Users.LoadUsersAsync(cancellationToken);

            if (loadUsersErrMsg is not null)
            {
                Console.WriteLine(loadUsersErrMsg);
                return(1);
            }

            var(loadedNodes, loadNodesErrMsg) = await Nodes.LoadNodesAsync(cancellationToken);

            if (loadNodesErrMsg is not null)
            {
                Console.WriteLine(loadNodesErrMsg);
                return(1);
            }
            using var nodes = loadedNodes;

            var(settings, loadSettingsErrMsg) = await Settings.LoadSettingsAsync(cancellationToken);

            if (loadSettingsErrMsg is not null)
            {
                Console.WriteLine(loadSettingsErrMsg);
                return(1);
            }

            // Removing online config requires reading user entry.
            if (settings.OnlineConfigCleanOnUserRemoval)
            {
                SIP008StaticGen.Remove(users, settings, usernames);
            }

            // Remove user entry.
            foreach (var username in usernames)
            {
                if (users.UserDict.TryGetValue(username, out var user))
                {
                    // Clear group and node ownership.
                    var ownedGroupEntries = nodes.Groups.Where(x => x.Value.OwnerUuid == user.Uuid);
                    var ownedNodeEntries  = nodes.Groups.SelectMany(x => x.Value.NodeDict)
                                            .Where(x => x.Value.OwnerUuid == user.Uuid);

                    foreach (var groupEntry in ownedGroupEntries)
                    {
                        groupEntry.Value.OwnerUuid = null;
                        Console.WriteLine($"{username}: Disowned group {groupEntry.Key}.");
                    }

                    foreach (var nodeEntry in ownedNodeEntries)
                    {
                        nodeEntry.Value.OwnerUuid = null;
                        Console.WriteLine($"{username}: Disowned node {nodeEntry.Key}.");
                    }

                    _ = users.RemoveUser(username);
                    Console.WriteLine($"Removed user {username}.");
                }
                else
                {
                    commandResult--;
                    Console.WriteLine($"Error: User {username} doesn't exist.");
                }
            }

            var saveUsersErrMsg = await Users.SaveUsersAsync(users, cancellationToken);

            if (saveUsersErrMsg is not null)
            {
                Console.WriteLine(saveUsersErrMsg);
                return(1);
            }

            return(commandResult);
        }
        public async Task Save_Clean_OnlineConfig_ForAllUsers()
        {
            var settings  = new Settings();
            var directory = FileHelper.GetAbsolutePath(settings.OnlineConfigOutputDirectory);

            using var nodes = new Nodes();
            nodes.AddGroup("MyGroup");
            nodes.AddGroup("MyGroupWithPlugin");
            nodes.AddNodeToGroup("MyGroup", "MyNode", "github.com", 443);
            nodes.AddNodeToGroup("MyGroupWithPlugin", "MyNodeWithPlugin", "github.com", 443, "v2ray-plugin", "server;tls;host=github.com");
            var users = new Users();

            users.AddUser("root");
            users.AddUser("http");
            users.AddUser("nobody");
            users.AddCredentialToUser("root", "MyGroup", "Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTp5bWdoaVIjNzVUTnFwYQ");
            users.AddCredentialToUser("http", "MyGroupWithPlugin", "aes-256-gcm", "wLhN2STZ");
            var rootUser   = users.UserDict["root"];
            var httpUser   = users.UserDict["http"];
            var nobodyUser = users.UserDict["nobody"];

            // Disable delivery by group
            settings.OnlineConfigDeliverByGroup = false;
            // Save
            var genResult = await SIP008StaticGen.GenerateAndSave(users, nodes, settings);

            Assert.Null(genResult);
            Assert.True(Directory.Exists(directory));
            foreach (var user in users.UserDict.Values)
            {
                Assert.True(File.Exists($"{directory}/{user.Uuid}.json"));
            }

            // Clean
            SIP008StaticGen.Remove(users, settings);

            Assert.True(Directory.Exists(directory));
            foreach (var user in users.UserDict.Values)
            {
                Assert.False(File.Exists($"{directory}/{user.Uuid}.json"));
            }

            // Delete working directory.
            Directory.Delete(directory);

            // Enable delivery by group
            settings.OnlineConfigDeliverByGroup = true;
            // Save
            var genByGroupResult = await SIP008StaticGen.GenerateAndSave(users, nodes, settings);

            Assert.Null(genByGroupResult);
            Assert.True(Directory.Exists(directory));
            foreach (var user in users.UserDict.Values)
            {
                Assert.True(File.Exists($"{directory}/{user.Uuid}.json"));
            }
            Assert.True(Directory.Exists($"{directory}/{rootUser.Uuid}"));
            Assert.True(File.Exists($"{directory}/{rootUser.Uuid}/MyGroup.json"));
            Assert.False(File.Exists($"{directory}/{rootUser.Uuid}/MyGroupWithPlugin.json"));
            Assert.True(Directory.Exists($"{directory}/{httpUser.Uuid}"));
            Assert.False(File.Exists($"{directory}/{httpUser.Uuid}/MyGroup.json"));
            Assert.True(File.Exists($"{directory}/{httpUser.Uuid}/MyGroupWithPlugin.json"));
            Assert.False(Directory.Exists($"{directory}/{nobodyUser.Uuid}"));

            // Clean
            SIP008StaticGen.Remove(users, settings);

            Assert.True(Directory.Exists(directory));
            foreach (var user in users.UserDict.Values)
            {
                Assert.False(File.Exists($"{directory}/{user.Uuid}.json"));
            }
            Assert.False(Directory.Exists($"{directory}/{rootUser.Uuid}"));
            Assert.False(Directory.Exists($"{directory}/{httpUser.Uuid}"));
            Assert.False(Directory.Exists($"{directory}/{nobodyUser.Uuid}"));

            // Delete working directory.
            Directory.Delete(directory);
        }