Beispiel #1
0
        /// <summary>
        /// Adds a member to the server
        /// </summary>
        public async Task AddMemberAsync(User user, ValourDB db)
        {
            // Already a member
            if (await db.PlanetMembers.AnyAsync(x => x.User_Id == user.Id && x.Planet_Id == Id))
            {
                return;
            }

            ServerPlanetMember member = new ServerPlanetMember()
            {
                Id        = IdManager.Generate(),
                Nickname  = user.Username,
                Planet_Id = Id,
                User_Id   = user.Id
            };

            // Add to default planet role
            ServerPlanetRoleMember rolemember = new ServerPlanetRoleMember()
            {
                Id        = IdManager.Generate(),
                Planet_Id = Id,
                User_Id   = user.Id,
                Role_Id   = Default_Role_Id,
                Member_Id = member.Id
            };

            await db.PlanetMembers.AddAsync(member);

            await db.PlanetRoleMembers.AddAsync(rolemember);

            await db.SaveChangesAsync();

            Console.WriteLine($"User {user.Username} ({user.Id}) has joined {Name} ({Id})");
        }
Beispiel #2
0
    private static async Task CreateInvite(HttpContext ctx, ValourDB db, [FromHeader] string authorization)
    {
        var authToken = await ServerAuthToken.TryAuthorize(authorization, db);

        if (authToken == null)
        {
            await TokenInvalid(ctx); return;
        }

        ServerPlanetInvite in_invite = await JsonSerializer.DeserializeAsync <ServerPlanetInvite>(ctx.Request.Body);

        ServerPlanetMember member = await db.PlanetMembers.Include(x => x.Planet).FirstOrDefaultAsync(x => x.Planet_Id == in_invite.Planet_Id && x.User_Id == authToken.User_Id);

        if (member == null)
        {
            await Unauthorized("Member not found", ctx); return;
        }

        if (!await member.HasPermissionAsync(PlanetPermissions.Invite, db))
        {
            await Unauthorized("Member lacks PlanetPermissions.Invite", ctx);

            return;
        }

        // Ensure important fields are correct
        in_invite.Issuer_Id = authToken.User_Id;
        in_invite.Time      = DateTime.UtcNow;
        in_invite.Id        = IdManager.Generate();

        Random random = new();

        const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        string       code  = "";

        bool exists = false;

        do
        {
            code   = new string(Enumerable.Repeat(chars, 8).Select(s => s[random.Next(s.Length)]).ToArray());
            exists = await db.PlanetInvites.AnyAsync(x => x.Code == code);
        }while (!exists);

        in_invite.Code = code;

        if (in_invite.Hours < 1)
        {
            in_invite.Hours = null;
        }

        await db.PlanetInvites.AddAsync(in_invite);

        await db.SaveChangesAsync();

        ctx.Response.StatusCode = 201;
        await ctx.Response.WriteAsync(in_invite.Code);
    }
Beispiel #3
0
        public async Task <TaskResult> BanUser(ulong target_id, ulong planet_id, string reason, string token, uint time)
        {
            AuthToken authToken = await Context.AuthTokens.FindAsync(token);

            if (authToken == null)
            {
                return(new TaskResult(false, "Failed to authorize user."));
            }

            ServerPlanet planet = await ServerPlanet.FindAsync(planet_id);

            if (!(await planet.AuthorizedAsync(authToken, PlanetPermissions.Ban)))
            {
                return(new TaskResult(false, "You are not authorized to do this."));
            }

            ServerPlanetMember member = await Context.PlanetMembers.FirstOrDefaultAsync(x => x.Id == target_id &&
                                                                                        x.Planet_Id == planet_id);

            PlanetBan ban = new PlanetBan()
            {
                Id        = IdManager.Generate(),
                Reason    = reason,
                Planet_Id = planet_id,
                User_Id   = member.User_Id,
                Banner_Id = authToken.User_Id,
                Time      = DateTime.UtcNow,
                Permanent = false
            };

            if (time <= 0)
            {
                ban.Permanent = true;
            }
            else
            {
                ban.Minutes = time;
            }

            // Add channel to database
            await Context.PlanetBans.AddAsync(ban);

            List <ServerPlanetRoleMember> roles = await Task.Run(() => Context.PlanetRoleMembers.Where(x => x.Member_Id == target_id && x.Planet_Id == planet_id).ToList());

            foreach (ServerPlanetRoleMember role in roles)
            {
                Context.PlanetRoleMembers.Remove(role);
            }

            Context.PlanetMembers.Remove(member);
            await Context.SaveChangesAsync();

            return(new TaskResult(true, $"Successfully banned user {member.Nickname}"));
        }
        /// <summary>
        /// Creates a server and if successful returns a task result with the created
        /// planet's id
        /// </summary>
        public async Task <TaskResult <ulong> > CreateChannel(string name, ulong planet_id, ulong user_id, ulong parentid, string token)
        {
            TaskResult nameValid = ValidateName(name);

            if (!nameValid.Success)
            {
                return(new TaskResult <ulong>(false, nameValid.Message, 0));
            }

            AuthToken authToken = await Context.AuthTokens.FindAsync(token);

            // Return the same if the token is for the wrong user to prevent someone
            // from knowing if they cracked another user's token. This is basically
            // impossible to happen by chance but better safe than sorry in the case that
            // the literal impossible odds occur, more likely someone gets a stolen token
            // but is not aware of the owner but I'll shut up now - Spike
            if (authToken == null || authToken.User_Id != user_id)
            {
                return(new TaskResult <ulong>(false, "Failed to authorize user.", 0));
            }

            ServerPlanet planet = await ServerPlanet.FindAsync(planet_id);

            if (!(await planet.AuthorizedAsync(authToken, PlanetPermissions.ManageChannels)))
            {
                return(new TaskResult <ulong>(false, "You are not authorized to do this.", 0));
            }

            // User is verified and given channel info is valid by this point

            // Creates the channel channel

            PlanetChatChannel channel = new PlanetChatChannel()
            {
                Id            = IdManager.Generate(),
                Name          = name,
                Planet_Id     = planet_id,
                Parent_Id     = parentid,
                Message_Count = 0,
                Description   = "A chat channel",
                Position      = Convert.ToUInt16(Context.PlanetChatChannels.Count())
            };

            // Add channel to database
            await Context.PlanetChatChannels.AddAsync(channel);

            // Save changes to DB
            await Context.SaveChangesAsync();

            await PlanetHub.Current.Clients.Group($"p-{planet_id}").SendAsync("RefreshChannelList", "");

            // Return success
            return(new TaskResult <ulong>(true, "Successfully created channel.", channel.Id));
        }
Beispiel #5
0
        public async Task <TaskResult <PlanetInvite> > CreateInvite(ulong Planet_Id, string token, int hours)
        {
            AuthToken authToken = await Context.AuthTokens.FindAsync(token);

            if (authToken == null)
            {
                return(new TaskResult <PlanetInvite>(false, "Failed to authorize user.", null));
            }

            ServerPlanet planet = await ServerPlanet.FindAsync(Planet_Id);

            if (!(await planet.AuthorizedAsync(authToken, PlanetPermissions.Invite)))
            {
                return(new TaskResult <PlanetInvite>(false, "You are not authorized to do this.", null));
            }

            PlanetInvite invite = new PlanetInvite()
            {
                Id        = IdManager.Generate(),
                Planet_Id = Planet_Id,
                Issuer_Id = authToken.User_Id,
                Time      = DateTime.UtcNow,
                Hours     = hours
            };

            Random random = new Random();

            const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

            string code = new string(Enumerable.Repeat(chars, 8).Select(s => s[random.Next(s.Length)]).ToArray());

            PlanetInvite test = await Context.PlanetInvites.FirstOrDefaultAsync(x => x.Code == code);

            while (test != null)
            {
                code = new string(Enumerable.Repeat(chars, 8).Select(s => s[random.Next(s.Length)]).ToArray());
                test = await Context.PlanetInvites.Where(x => x.Code == code).FirstOrDefaultAsync();
            }

            invite.Code = code;

            if (hours == 0)
            {
                invite.Hours = null;
            }

            await Context.PlanetInvites.AddAsync(invite);

            await Context.SaveChangesAsync();

            return(new TaskResult <PlanetInvite>(true, $"Successfully created invite", invite));
        }
Beispiel #6
0
        /// <summary>
        /// Adds a member to the server
        /// </summary>
        public async Task AddMemberAsync(User user, ValourDB db = null)
        {
            // Setup db if none provided
            bool dbcreate = false;

            if (db == null)
            {
                db       = new ValourDB(ValourDB.DBOptions);
                dbcreate = true;
            }

            // Already a member
            if (await db.PlanetMembers.AnyAsync(x => x.User_Id == user.Id && x.Planet_Id == Id))
            {
                return;
            }

            ServerPlanetMember member = new ServerPlanetMember()
            {
                Id        = IdManager.Generate(),
                Nickname  = user.Username,
                Planet_Id = Id,
                User_Id   = user.Id
            };

            // Add to default planet role
            ServerPlanetRoleMember rolemember = new ServerPlanetRoleMember()
            {
                Id        = IdManager.Generate(),
                Planet_Id = Id,
                User_Id   = user.Id,
                Role_Id   = Default_Role_Id,
                Member_Id = member.Id
            };

            await db.PlanetMembers.AddAsync(member);

            await db.PlanetRoleMembers.AddAsync(rolemember);

            await db.SaveChangesAsync();

            Console.WriteLine($"User {user.Username} ({user.Id}) has joined {Name} ({Id})");

            // Clean up if created own db
            if (dbcreate)
            {
                await db.DisposeAsync();
            }
        }
Beispiel #7
0
        private static async Task AddRole(HttpContext ctx, ValourDB db,
                                          [FromHeader] string authorization)
        {
            AuthToken auth = await ServerAuthToken.TryAuthorize(authorization, db);

            if (auth is null)
            {
                await TokenInvalid(ctx); return;
            }

            ServerPlanetRole in_role = await JsonSerializer.DeserializeAsync <ServerPlanetRole>(ctx.Response.Body);

            ServerPlanetMember member = await db.PlanetMembers.FirstOrDefaultAsync(x => x.User_Id == auth.User_Id &&
                                                                                   x.Planet_Id == in_role.Planet_Id);

            if (member is null)
            {
                await Unauthorized("Member not found", ctx); return;
            }
            if (!auth.HasScope(UserPermissions.PlanetManagement))
            {
                await Unauthorized("Auth token lacks UserPermissions.PlanetManagement", ctx); return;
            }
            if (!await member.HasPermissionAsync(PlanetPermissions.ManageRoles, db))
            {
                await Unauthorized("Member lacks PlanetPermissions.ManageRoles", ctx); return;
            }


            // Ensure fields are correct
            in_role.Planet_Id = member.Planet_Id;
            in_role.Position  = (uint)await db.PlanetRoles.CountAsync(x => x.Planet_Id == in_role.Planet_Id);

            // Generate ID
            in_role.Id = IdManager.Generate();

            await db.PlanetRoles.AddAsync(in_role);

            await db.SaveChangesAsync();

            ctx.Response.StatusCode = 201;
            await ctx.Response.WriteAsJsonAsync(in_role.Id);

            return;
        }
Beispiel #8
0
        /// <summary>
        /// Creates the requested role
        /// </summary>
        public async Task <TaskResult> CreateRole([FromBody] ServerPlanetRole role, string token)
        {
            AuthToken authToken = await Context.AuthTokens.FindAsync(token);

            if (authToken == null)
            {
                return(new TaskResult(false, "Failed to authorize user."));
            }

            if (!Permission.HasPermission(authToken.Scope, UserPermissions.PlanetManagement))
            {
                return(new TaskResult(false, "You don't have planet management scope."));
            }

            ServerPlanetMember member = await Context.PlanetMembers.Include(x => x.User)
                                        .FirstOrDefaultAsync(x => x.User_Id == authToken.User_Id &&
                                                             x.Planet_Id == role.Planet_Id);

            if (member == null)
            {
                return(new TaskResult(false, "You're not in the planet!"));
            }

            if (!(await member.HasPermissionAsync(PlanetPermissions.ManageRoles)))
            {
                return(new TaskResult(false, "You don't have role management permissions!"));
            }

            // Set role id
            role.Id = IdManager.Generate();

            // Set to next open position
            role.Position = (uint)await Context.PlanetRoles.Where(x => x.Planet_Id == role.Planet_Id).CountAsync();

            await Context.PlanetRoles.AddAsync(role);

            await Context.SaveChangesAsync();

            await PlanetHub.NotifyRoleChange(role);

            return(new TaskResult(true, $"Role {role.Id} successfully added to position {role.Position}."));
        }
Beispiel #9
0
        private static async Task RegisterUser(HttpContext ctx, ValourDB db, string username, string email, string password, string referrer)
        {
            if (username != null)
            {
                username = username.TrimEnd();
            }

            // Prevent duplicates
            if (await db.Users.AnyAsync(x => x.Username.ToLower() == username.ToLower()))
            {
                await BadRequest("Username taken", ctx); return;
            }

            if (await db.UserEmails.AnyAsync(x => x.Email.ToLower() == email.ToLower()))
            {
                await BadRequest("Email taken", ctx); return;
            }

            // Test email
            TaskResult <string> emailResult = User.TestEmail(email);

            if (!emailResult.Success)
            {
                await BadRequest(emailResult.Message, ctx); return;
            }

            // This may fix broken email formatting
            email = emailResult.Data;

            // Test username
            TaskResult usernameResult = User.TestUsername(username);

            if (!usernameResult.Success)
            {
                await BadRequest(usernameResult.Message, ctx); return;
            }

            // Test password complexity
            TaskResult passwordResult = User.TestPasswordComplexity(password);

            // Enforce password tests
            if (!passwordResult.Success)
            {
                await BadRequest(passwordResult.Message, ctx); return;
            }


            // Manage referral
            Referral refer = null;

            if (!string.IsNullOrWhiteSpace(referrer))
            {
                User referUser = await db.Users.FirstOrDefaultAsync(x => x.Username.ToLower() == referrer.ToLower());

                if (referUser == null)
                {
                    await BadRequest($"Could not find referrer {referrer}", ctx); return;
                }

                refer = new Referral()
                {
                    Referrer_Id = referUser.Id
                };
            }

            // At this point the safety checks are complete

            // Generate random salt
            byte[] salt = new byte[32];
            PasswordManager.GenerateSalt(salt);

            // Generate password hash
            byte[] hash = PasswordManager.GetHashForPassword(password, salt);

            // Create user object
            ServerUser user = new ServerUser()
            {
                Id            = IdManager.Generate(),
                Username      = username,
                Join_DateTime = DateTime.UtcNow,
                Last_Active   = DateTime.UtcNow
            };

            // An error here would be really bad so we'll be careful and catch any exceptions
            try
            {
                await db.Users.AddAsync(user);

                await db.SaveChangesAsync();
            }
            catch (System.Exception e)
            {
                Console.WriteLine(e.Message);
                await BadRequest("A critical error occured adding the user.", ctx);

                return;
            }

            // Create email object
            UserEmail emailObj = new UserEmail()
            {
                Email    = email,
                Verified = false,
                User_Id  = user.Id
            };

            try
            {
                // Pray something doesnt break between these
                await db.UserEmails.AddAsync(emailObj);

                await db.SaveChangesAsync();
            }
            catch (System.Exception e)
            {
                Console.WriteLine(e.Message);
                await BadRequest("A critical error occured adding the email.", ctx);

                return;
            }

            Credential cred = new Credential()
            {
                Credential_Type = CredentialType.PASSWORD,
                Identifier      = email,
                Salt            = salt,
                Secret          = hash,
                User_Id         = user.Id // We need to find what the user's assigned ID is (auto-filled by EF)
            };

            // An error here would be really bad so we'll be careful and catch any exceptions
            try
            {
                await db.Credentials.AddAsync(cred);

                await db.SaveChangesAsync();
            }
            catch (System.Exception e)
            {
                Console.WriteLine(e.Message);
                await BadRequest("A critical error occured adding the credentials.", ctx);

                return;
            }

            string code = Guid.NewGuid().ToString();

            EmailConfirmCode emailConfirm = new EmailConfirmCode()
            {
                Code    = code,
                User_Id = user.Id
            };

            if (refer != null)
            {
                refer.User_Id = user.Id;
                await db.Referrals.AddAsync(refer);

                await db.SaveChangesAsync();
            }

            // An error here would be really bad so we'll be careful and catch any exceptions
            try
            {
                await db.EmailConfirmCodes.AddAsync(emailConfirm);

                await db.SaveChangesAsync();
            }
            catch (System.Exception e)
            {
                Console.WriteLine(e.Message);
                await BadRequest("A critical error occured adding the email confirmation code.", ctx);

                return;
            }

            // Send registration email
            string emsg = $@"<body>
                              <h2 style='font-family:Helvetica;'>
                                Welcome to Valour!
                              </h2>
                              <p style='font-family:Helvetica;>
                                To verify your new account, please use the following link: 
                              </p>
                              <p style='font-family:Helvetica;'>
                                <a href='https://valour.gg/VerifyEmail/{code}'>Verify</a>
                              </p>
                            </body>";

            string rawmsg = $"Welcome to Valour!\nTo verify your new account, please go to the following link:\nhttps://valour.gg/VerifyEmail/{code}";

            await EmailManager.SendEmailAsync(email, "Valour Registration", rawmsg, emsg);

            ctx.Response.StatusCode = 200;
            await ctx.Response.WriteAsync("Success");
        }
Beispiel #10
0
        private static async Task CreateCategory(HttpContext ctx, ValourDB db,
                                                 [FromHeader] string authorization)
        {
            ServerPlanetCategory category_data = await JsonSerializer.DeserializeAsync <ServerPlanetCategory>(ctx.Request.Body);

            if (category_data == null)
            {
                ctx.Response.StatusCode = 400;
                await ctx.Response.WriteAsync("Please include category in body");

                return;
            }

            if (string.IsNullOrWhiteSpace(category_data.Name))
            {
                ctx.Response.StatusCode = 400;
                await ctx.Response.WriteAsync("Please include a category name");

                return;
            }

            // Request parameter validation //

            TaskResult name_valid = ServerPlanetCategory.ValidateName(category_data.Name);

            if (!name_valid.Success)
            {
                ctx.Response.StatusCode = 400;
                await ctx.Response.WriteAsync($"Name is not valid [name: {category_data.Name}]");

                return;
            }

            // Request authorization //

            AuthToken auth = await ServerAuthToken.TryAuthorize(authorization, db);

            if (!auth.HasScope(UserPermissions.PlanetManagement))
            {
                ctx.Response.StatusCode = 401;
                await ctx.Response.WriteAsync("Token lacks UserPermissions.PlanetManagement scope");

                return;
            }

            ServerPlanet planet = await db.Planets.Include(x => x.Members.Where(x => x.User_Id == auth.User_Id))
                                  .FirstOrDefaultAsync(x => x.Id == category_data.Planet_Id);

            var member = planet.Members.FirstOrDefault();

            if (!await planet.HasPermissionAsync(member, PlanetPermissions.ManageChannels, db))
            {
                ctx.Response.StatusCode = 401;
                await ctx.Response.WriteAsync("Member lacks PlanetPermissions.ManageChannels node");

                return;
            }

            // Ensure parent category exists

            ulong?parent_id = null;

            ServerPlanetCategory parent = await db.PlanetCategories.FindAsync(category_data.Parent_Id);

            ushort child_count = 0;

            if (parent != null)
            {
                parent_id = parent.Id;

                if (parent.Planet_Id != planet.Id)
                {
                    ctx.Response.StatusCode = 400;
                    await ctx.Response.WriteAsync("Parent id does not match planet");

                    return;
                }

                child_count += (ushort)await db.PlanetChatChannels.CountAsync(x => x.Parent_Id == parent_id);

                child_count += (ushort)await db.PlanetCategories.CountAsync(x => x.Parent_Id == parent_id);
            }

            // Request action //

            // Creates the category

            ServerPlanetCategory category = new ServerPlanetCategory()
            {
                Id          = IdManager.Generate(),
                Name        = category_data.Name,
                Planet_Id   = category_data.Planet_Id,
                Parent_Id   = category_data.Parent_Id,
                Description = category_data.Description,
                Position    = child_count
            };

            // Add channel to database
            await db.PlanetCategories.AddAsync(category);

            // Save changes to DB
            await db.SaveChangesAsync();

            // Send channel refresh
            PlanetHub.NotifyCategoryChange(category);

            ctx.Response.StatusCode = 201;
            await ctx.Response.WriteAsync(category.Id.ToString());
        }
Beispiel #11
0
        private static async Task Create(HttpContext ctx, ValourDB db,
                                         [FromHeader] string authorization, [Required] string name,
                                         [Required] string image_url)
        {
            ServerAuthToken auth = await ServerAuthToken.TryAuthorize(authorization, db);

            if (auth == null)
            {
                ctx.Response.StatusCode = 401;
                await ctx.Response.WriteAsync($"Token is invalid [token: {authorization}]");

                return;
            }

            TaskResult nameValid = ServerPlanet.ValidateName(name);

            if (!nameValid.Success)
            {
                ctx.Response.StatusCode = 400;
                await ctx.Response.WriteAsync(nameValid.Message);

                return;
            }

            ServerUser user = await db.Users.FindAsync(auth.User_Id);

            if (!user.Valour_Staff)
            {
                var owned_planets = await db.Planets.CountAsync(x => x.Owner_Id == user.Id);

                if (owned_planets > MAX_OWNED_PLANETS)
                {
                    ctx.Response.StatusCode = 400;
                    await ctx.Response.WriteAsync("Max owned planets reached");

                    return;
                }
            }

            // Image handling via proxy
            ProxyResponse proxyResponse = await MPSManager.GetProxy(image_url);

            bool is_media = MPSManager.Media_Types.Contains(proxyResponse.Item.Mime_Type);

            if (proxyResponse.Item == null || !is_media)
            {
                image_url = "https://valour.gg/image.png";
            }
            else
            {
                image_url = proxyResponse.Item.Url;
            }

            ulong planet_id = IdManager.Generate();

            // Create general category
            ServerPlanetCategory category = new ServerPlanetCategory()
            {
                Id          = IdManager.Generate(),
                Name        = "General",
                Parent_Id   = null,
                Planet_Id   = planet_id,
                Description = "General category",
                Position    = 0
            };

            // Create general channel
            ServerPlanetChatChannel channel = new ServerPlanetChatChannel()
            {
                Id            = IdManager.Generate(),
                Planet_Id     = planet_id,
                Name          = "General",
                Message_Count = 0,
                Description   = "General chat channel",
                Parent_Id     = category.Id
            };

            // Create default role
            ServerPlanetRole defaultRole = new ServerPlanetRole()
            {
                Id          = IdManager.Generate(),
                Planet_Id   = planet_id,
                Position    = uint.MaxValue,
                Color_Blue  = 255,
                Color_Green = 255,
                Color_Red   = 255,
                Name        = "@everyone"
            };

            ServerPlanet planet = new ServerPlanet()
            {
                Id              = planet_id,
                Name            = name,
                Member_Count    = 1,
                Description     = "A Valour server.",
                Image_Url       = image_url,
                Public          = true,
                Owner_Id        = user.Id,
                Default_Role_Id = defaultRole.Id,
                Main_Channel_Id = channel.Id
            };

            // Add planet to database
            await db.Planets.AddAsync(planet);

            await db.SaveChangesAsync(); // We must do this first to prevent foreign key errors

            // Add category to database
            await db.PlanetCategories.AddAsync(category);

            // Add channel to database
            await db.PlanetChatChannels.AddAsync(channel);

            // Add default role to database
            await db.PlanetRoles.AddAsync(defaultRole);

            // Save changes
            await db.SaveChangesAsync();

            // Add owner to planet
            await planet.AddMemberAsync(user, db);

            ctx.Response.StatusCode = 200;
            await ctx.Response.WriteAsJsonAsync(planet.Id);
        }
Beispiel #12
0
        private static async Task AddRole(HttpContext ctx, ValourDB db, ulong planet_id,
                                          [FromHeader] string authorization)
        {
            AuthToken auth = await ServerAuthToken.TryAuthorize(authorization, db);

            if (auth is null)
            {
                Results.Unauthorized();
                return;
            }

            ServerPlanetMember member = await db.PlanetMembers.FirstOrDefaultAsync(x => x.Planet_Id == planet_id &&
                                                                                   x.User_Id == auth.User_Id);

            if (member == null)
            {
                ctx.Response.StatusCode = 403;
                await ctx.Response.WriteAsync($"Member not found");

                return;
            }

            if (!await member.HasPermissionAsync(PlanetPermissions.ManageRoles, db))
            {
                ctx.Response.StatusCode = 403;
                await ctx.Response.WriteAsync($"Member lacks PlanetPermissions.ManageRoles");

                return;
            }

            //string egg = await ctx.Request.ReadBodyStringAsync();

            ServerPlanetRole in_role =
                await JsonSerializer.DeserializeAsync <ServerPlanetRole>(ctx.Request.Body);

            if (in_role is null)
            {
                ctx.Response.StatusCode = 400;
                await ctx.Response.WriteAsync($"Include new role");

                return;
            }

            if (in_role.Planet_Id != planet_id)
            {
                ctx.Response.StatusCode = 400;
                await ctx.Response.WriteAsync($"Member planet does not match role planet");

                return;
            }

            // Set ID
            in_role.Id = IdManager.Generate();
            // Set planet id
            in_role.Planet_Id = planet_id;
            // Set position
            in_role.Position = (uint)await db.PlanetRoles.CountAsync(x => x.Planet_Id == planet_id);

            await db.PlanetRoles.AddAsync(in_role);

            await db.SaveChangesAsync();

            ctx.Response.StatusCode = 201;
            await ctx.Response.WriteAsJsonAsync(in_role.Id);

            return;
        }
Beispiel #13
0
        /// <summary>
        /// Sets whether or not a member is in a role
        /// </summary>
        public async Task <TaskResult> SetMemberRoleMembership(ulong role_id, ulong member_id, bool value, string token)
        {
            ServerAuthToken authToken = await Context.AuthTokens.FindAsync(token);

            if (authToken == null)
            {
                return(new TaskResult(false, "Failed to authorize user."));
            }

            // Oauth protection
            if (!Permission.HasPermission(authToken.Scope, UserPermissions.PlanetManagement))
            {
                return(new TaskResult(false, "You don't have planet management scope."));
            }

            // Retrieve role
            ServerPlanetRole role = await Context.PlanetRoles.Include(x => x.Planet)
                                    .FirstOrDefaultAsync(x => x.Id == role_id);

            if (role == null)
            {
                return(new TaskResult(false, $"Role {role_id} could not be found."));
            }

            ServerPlanetMember authMember = await Context.PlanetMembers.Include(x => x.RoleMembership)
                                            .ThenInclude(x => x.Role)
                                            .FirstOrDefaultAsync(x => x.User_Id == authToken.User_Id &&
                                                                 x.Planet_Id == role.Planet_Id);

            // If the authorizor is not in the planet
            if (authMember == null)
            {
                return(new TaskResult(false, $"You are not in the target planet!"));
            }

            // Get target member

            var targetMember = await Context.PlanetMembers.FindAsync(member_id);

            if (targetMember == null)
            {
                return(new TaskResult(false, $"Could not find member with id {member_id}"));
            }

            // Get auth primary role
            var primaryAuthRole = authMember.RoleMembership.OrderBy(x => x.Role.Position).FirstOrDefault();

            if (authMember.Planet_Id != authMember.Planet.Owner_Id && primaryAuthRole == null)
            {
                return(new TaskResult(false, $"Error: Issue retrieving primary role for authorizor"));
            }

            if (!(await authMember.HasPermissionAsync(PlanetPermissions.ManageRoles, Context)))
            {
                return(new TaskResult(false, $"You don't have permission to manage roles"));
            }

            // Ensure that the role being set is *lower* than their own role
            if (role.Planet.Owner_Id != authMember.User_Id &&
                role.Position <= primaryAuthRole.Role.Position)
            {
                return(new TaskResult(false, $"You cannot set roles that aren't below your own"));
            }

            // At this point, authorization should be complete

            // Add the role
            if (value)
            {
                // Ensure it isn't already there
                if (await Context.PlanetRoleMembers.AnyAsync(x => x.Member_Id == targetMember.Id &&
                                                             x.Role_Id == role.Id))
                {
                    return(new TaskResult(true, $"The user already has the role."));
                }

                ServerPlanetRoleMember roleMember = new ServerPlanetRoleMember()
                {
                    Id        = IdManager.Generate(),
                    Member_Id = targetMember.Id,
                    Role_Id   = role.Id,
                    User_Id   = targetMember.User_Id,
                    Planet_Id = targetMember.Planet_Id
                };

                await Context.PlanetRoleMembers.AddAsync(roleMember);
            }
            // Remove the role
            else
            {
                if (role.Id == authMember.Planet.Default_Role_Id)
                {
                    return(new TaskResult(false, $"Cannot remove the default role!"));
                }

                var currentRoleMember = await Context.PlanetRoleMembers.FirstOrDefaultAsync(x => x.Member_Id == targetMember.Id &&
                                                                                            x.Role_Id == role.Id);

                // Ensure the user actually has the role
                if (currentRoleMember == null)
                {
                    return(new TaskResult(true, $"The user doesn't have the role."));
                }

                Context.PlanetRoleMembers.Remove(currentRoleMember);
            }

            // Save changes
            await Context.SaveChangesAsync();

            // Send ping that the member was modified (new role)
            await PlanetHub.NotifyMemberChange(targetMember);

            return(new TaskResult(true, $"Successfully set role membership to {value}"));
        }
Beispiel #14
0
        public async Task <TaskResult <int> > TryBanMemberAsync(ServerPlanetMember member,
                                                                ServerPlanetMember target, string reason, uint?duration, ValourDB db)
        {
            if (member == null)
            {
                return(new TaskResult <int>(false, "Member not found", 404));
            }

            if (!await HasPermissionAsync(member, PlanetPermissions.Kick, db))
            {
                return(new TaskResult <int>(false, "Member lacks PlanetPermissions.View", 403));
            }

            if (target == null)
            {
                return(new TaskResult <int>(false, $"Target not found", 404));
            }

            if (member.Id == target.Id)
            {
                return(new TaskResult <int>(false, "You cannot ban yourself!", 400));
            }

            if (!await HasPermissionAsync(member, PlanetPermissions.Ban, db))
            {
                return(new TaskResult <int>(false, "Member lacks PlanetPermissions.Ban", 403));
            }

            if (await member.GetAuthorityAsync() <= await target.GetAuthorityAsync())
            {
                return(new TaskResult <int>(false, "You can only ban members with lower authority!", 403));
            }

            if (duration == 0)
            {
                duration = null;
            }

            // Add ban to database
            PlanetBan ban = new PlanetBan()
            {
                Id        = IdManager.Generate(),
                Reason    = reason,
                Time      = DateTime.UtcNow,
                Banner_Id = member.User_Id,
                User_Id   = target.User_Id,
                Planet_Id = member.Planet_Id,
                Minutes   = duration
            };

            await db.PlanetBans.AddAsync(ban);

            // Remove roles
            var roles = db.PlanetRoleMembers.Where(x => x.Member_Id == target.Id);

            foreach (ServerPlanetRoleMember role in roles)
            {
                db.PlanetRoleMembers.Remove(role);
            }

            // Remove member
            db.PlanetMembers.Remove(target);

            // Save changes
            await db.SaveChangesAsync();

            return(new TaskResult <int>(true, $"Successfully banned user", 200));
        }
Beispiel #15
0
        /// <summary>
        /// Creates a server and if successful returns a task result with the created
        /// planet's id
        /// </summary>
        public async Task <TaskResult <ulong> > CreatePlanet(string name, string image_url, string token)
        {
            TaskResult nameValid = ValidateName(name);

            if (!nameValid.Success)
            {
                return(new TaskResult <ulong>(false, nameValid.Message, 0));
            }

            AuthToken authToken = await Context.AuthTokens.FindAsync(token);

            if (authToken == null)
            {
                return(new TaskResult <ulong>(false, "Failed to authorize user.", 0));
            }

            User user = await Context.Users.FindAsync(authToken.User_Id);

            if (await Context.Planets.CountAsync(x => x.Owner_Id == user.Id) > MAX_OWNED_PLANETS - 1)
            {
                return(new TaskResult <ulong>(false, "You have hit your maximum planets!", 0));
            }

            // User is verified and given planet info is valid by this point
            // We don't actually need the user object which is cool

            // Use MSP for proxying image

            MSPResponse proxyResponse = await MSPManager.GetProxy(image_url);

            if (string.IsNullOrWhiteSpace(proxyResponse.Url) || !proxyResponse.Is_Media)
            {
                image_url = "https://valour.gg/image.png";
            }
            else
            {
                image_url = proxyResponse.Url;
            }

            ulong planet_id = IdManager.Generate();

            // Create general category
            PlanetCategory category = new PlanetCategory()
            {
                Id        = IdManager.Generate(),
                Name      = "General",
                Parent_Id = null,
                Planet_Id = planet_id,
                Position  = 0
            };

            // Create general channel
            PlanetChatChannel channel = new PlanetChatChannel()
            {
                Id            = IdManager.Generate(),
                Planet_Id     = planet_id,
                Name          = "General",
                Message_Count = 0,
                Description   = "General chat channel",
                Parent_Id     = category.Id
            };

            // Create default role
            ServerPlanetRole defaultRole = new ServerPlanetRole()
            {
                Id          = IdManager.Generate(),
                Planet_Id   = planet_id,
                Position    = uint.MaxValue,
                Color_Blue  = 255,
                Color_Green = 255,
                Color_Red   = 255,
                Name        = "@everyone"
            };

            ServerPlanet planet = new ServerPlanet()
            {
                Id              = planet_id,
                Name            = name,
                Member_Count    = 1,
                Description     = "A Valour server.",
                Image_Url       = image_url,
                Public          = true,
                Owner_Id        = user.Id,
                Default_Role_Id = defaultRole.Id,
                Main_Channel_Id = channel.Id
            };

            // Add planet to database
            await Context.Planets.AddAsync(planet);

            await Context.SaveChangesAsync(); // We must do this first to prevent foreign key errors

            // Add category to database
            await Context.PlanetCategories.AddAsync(category);

            // Add channel to database
            await Context.PlanetChatChannels.AddAsync(channel);

            // Add default role to database
            await Context.PlanetRoles.AddAsync(defaultRole);

            // Save changes
            await Context.SaveChangesAsync();

            // Add owner to planet
            await planet.AddMemberAsync(user);

            // Return success
            return(new TaskResult <ulong>(true, "Successfully created planet.", planet.Id));
        }
Beispiel #16
0
        private static async Task Channel(HttpContext ctx, ValourDB db, ulong channel_id,
                                          [FromHeader] string authorization)
        {
            AuthToken auth = await ServerAuthToken.TryAuthorize(authorization, db);

            if (auth == null)
            {
                await TokenInvalid(ctx); return;
            }

            switch (ctx.Request.Method)
            {
            case "GET":
            {
                ServerPlanetChatChannel channel = await db.PlanetChatChannels.Include(x => x.Planet)
                                                  .ThenInclude(x => x.Members.Where(x => x.User_Id == auth.User_Id))
                                                  .FirstOrDefaultAsync(x => x.Id == channel_id);

                if (channel == null)
                {
                    await NotFound("Channel not found", ctx); return;
                }

                var member = channel.Planet.Members.FirstOrDefault();

                if (member == null)
                {
                    await Unauthorized("Member not found", ctx); return;
                }

                if (!await channel.HasPermission(member, ChatChannelPermissions.View, db))
                {
                    await Unauthorized("Member lacks ChatChannelPermissions.View", ctx); return;
                }

                ctx.Response.StatusCode = 200;
                await ctx.Response.WriteAsJsonAsync((PlanetChatChannel)channel);

                return;
            }

            case "DELETE":
            {
                ServerPlanetChatChannel channel = await db.PlanetChatChannels.Include(x => x.Planet)
                                                  .ThenInclude(x => x.Members.Where(x => x.User_Id == auth.User_Id))
                                                  .FirstOrDefaultAsync(x => x.Id == channel_id);

                if (channel == null)
                {
                    await NotFound("Channel not found", ctx); return;
                }

                var member = channel.Planet.Members.FirstOrDefault();

                if (!auth.HasScope(UserPermissions.PlanetManagement))
                {
                    await Unauthorized("Token lacks UserPermissions.PlanetManagement", ctx); return;
                }

                TaskResult <int> result = await channel.TryDeleteAsync(member, db);

                ctx.Response.StatusCode = result.Data;
                await ctx.Response.WriteAsync(result.Message);

                return;
            }

            case "POST":
            {
                ServerPlanetChatChannel channel_data =
                    JsonSerializer.Deserialize <ServerPlanetChatChannel>(ctx.Request.Body);

                if (channel_data == null)
                {
                    ctx.Response.StatusCode = 400;
                    await ctx.Response.WriteAsync("Please include channel in body");

                    return;
                }

                if (string.IsNullOrWhiteSpace(channel_data.Name))
                {
                    ctx.Response.StatusCode = 400;
                    await ctx.Response.WriteAsync("Please include a channel name");

                    return;
                }

                // Request parameter validation //

                TaskResult name_valid = ServerPlanetChatChannel.ValidateName(channel_data.Name);

                if (!name_valid.Success)
                {
                    ctx.Response.StatusCode = 400;
                    await ctx.Response.WriteAsync($"Name is not valid [name: {channel_data.Name}]");

                    return;
                }

                // Request authorization //

                if (!auth.HasScope(UserPermissions.PlanetManagement))
                {
                    ctx.Response.StatusCode = 401;
                    await ctx.Response.WriteAsync("Token lacks UserPermissions.PlanetManagement scope");

                    return;
                }

                ServerPlanetMember member = await db.PlanetMembers
                                            .Include(x => x.Planet)
                                            .FirstOrDefaultAsync(x => x.Planet_Id == channel_data.Planet_Id && x.User_Id == auth.User_Id);

                if (!await member.HasPermissionAsync(PlanetPermissions.ManageChannels, db))
                {
                    ctx.Response.StatusCode = 401;
                    await ctx.Response.WriteAsync("Member lacks PlanetPermissions.ManageChannels node");

                    return;
                }

                // Ensure parent category exists

                ServerPlanetCategory parent = await db.PlanetCategories.FindAsync(channel_data.Parent_Id);

                if (parent == null)
                {
                    ctx.Response.StatusCode = 400;
                    await ctx.Response.WriteAsync("Could not find parent");

                    return;
                }

                if (parent.Planet_Id != member.Planet.Id)
                {
                    ctx.Response.StatusCode = 400;
                    await ctx.Response.WriteAsync("Parent id does not match planet");

                    return;
                }

                // Request action //

                // Creates the channel

                ushort child_count = 0;

                child_count += (ushort)await db.PlanetChatChannels.CountAsync(x => x.Parent_Id == channel_data.Parent_Id);

                child_count += (ushort)await db.PlanetCategories.CountAsync(x => x.Parent_Id == channel_data.Parent_Id);

                ServerPlanetChatChannel channel = new ServerPlanetChatChannel()
                {
                    Id            = IdManager.Generate(),
                    Name          = channel_data.Name,
                    Planet_Id     = channel_data.Planet_Id,
                    Parent_Id     = channel_data.Parent_Id,
                    Message_Count = 0,
                    Description   = channel_data.Description,
                    Position      = child_count
                };

                // Add channel to database
                await db.PlanetChatChannels.AddAsync(channel);

                // Save changes to DB
                await db.SaveChangesAsync();

                // Send channel refresh
                PlanetHub.NotifyChatChannelChange(channel);

                ctx.Response.StatusCode = 201;
                await ctx.Response.WriteAsync(channel.Id.ToString());

                return;
            }
            }
        }
Beispiel #17
0
    private static async Task SetChannelNode(HttpContext ctx, ValourDB db, [FromBody] ServerChatChannelPermissionsNode node,
        [FromHeader] string authorization)
    {
        var authToken = await ServerAuthToken.TryAuthorize(authorization, db);

        var member = await ServerPlanetMember.FindAsync(authToken.User_Id, node.Planet_Id, db);

        if (member is null) { await Unauthorized("Member not found", ctx); return; }

        if (!authToken.HasScope(UserPermissions.PlanetManagement)) { await Unauthorized("Token lacks UserPermissions.PlanetManagement", ctx); return; }

        var channel = await db.PlanetChatChannels.Include(x => x.Planet).FirstOrDefaultAsync(x => x.Id == node.Channel_Id);

        if (channel is null) { await NotFound("Channel not found", ctx); return; }


        if (await member.GetAuthorityAsync() < node.Role.GetAuthority())
        {
            await Unauthorized("Role has greater authority", ctx);
            return;
        }

        // Check global permission first
        if (!await channel.Planet.HasPermissionAsync(member, PlanetPermissions.ManageRoles, db))
        {
            await Unauthorized("Member lacks PlanetPermissions.ManageRoles", ctx);
            return;
        }

        // Check for channel-specific perm
        if (!await channel.HasPermission(member, ChatChannelPermissions.ManagePermissions, db))
        {
            await Unauthorized("Member lacks ChatChannelPermissions.ManagePermissions", ctx);
            return;
        }

        var old = await db.ChatChannelPermissionsNodes.Include(x => x.Role).Include(x => x.Planet).Include(x => x.Channel).FirstOrDefaultAsync(x => x.Id == node.Id);

        if (old is not null)
        {
            if (old.Planet_Id != node.Planet_Id || old.Role_Id != node.Role_Id)
            {
                await BadRequest("Id mismatch", ctx);
                return;
            }

            // Update
            db.ChatChannelPermissionsNodes.Update(node);
            await db.SaveChangesAsync();

            ctx.Response.StatusCode = 200;
            await ctx.Response.WriteAsync("Success");
        }
        else
        {
            node.Id = IdManager.Generate();
            node.Planet_Id = channel.Planet_Id;

            await db.ChatChannelPermissionsNodes.AddAsync(node);
            await db.SaveChangesAsync();

            ctx.Response.StatusCode = 201;
            await ctx.Response.WriteAsync("Success");
        }
    }
Beispiel #18
0
        private static async Task RoleMembership(HttpContext ctx, ValourDB db, ulong member_id,
                                                 [FromHeader] string authorization)
        {
            AuthToken auth = await ServerAuthToken.TryAuthorize(authorization, db);

            if (auth is null)
            {
                await TokenInvalid(ctx); return;
            }

            ServerPlanetMember target_member = await db.PlanetMembers
                                               .Include(x => x.Planet)
                                               .Include(x => x.RoleMembership)
                                               .FirstOrDefaultAsync(x => x.Id == member_id);


            if (target_member is null)
            {
                ctx.Response.StatusCode = 404;
                await ctx.Response.WriteAsync("Target member not found");

                return;
            }

            // Ensure auth user is member of planet
            ServerPlanetMember member = await db.PlanetMembers.FirstOrDefaultAsync(x => x.Planet_Id == target_member.Planet_Id &&
                                                                                   x.User_Id == auth.User_Id);

            if (member is null)
            {
                ctx.Response.StatusCode = 403;
                await ctx.Response.WriteAsync("Auth member not found");

                return;
            }

            switch (ctx.Request.Method)
            {
            case "GET":
            {
                ctx.Response.StatusCode = 200;
                await ctx.Response.WriteAsJsonAsync(target_member.RoleMembership);

                return;
            }

            case "POST":
            {
                if (!auth.HasScope(UserPermissions.PlanetManagement))
                {
                    ctx.Response.StatusCode = 403;
                    await ctx.Response.WriteAsync("Token lacks UserPermissions.PlanetManagement");

                    return;
                }

                if (!await member.HasPermissionAsync(PlanetPermissions.ManageRoles, db))
                {
                    ctx.Response.StatusCode = 403;
                    await ctx.Response.WriteAsync("Token lacks PlanetPermissions.ManageRoles");

                    return;
                }

                // Get body rolemember object
                var roleMember = await JsonSerializer.DeserializeAsync <ServerPlanetRoleMember>(ctx.Request.Body);

                if (roleMember is null)
                {
                    ctx.Response.StatusCode = 400;
                    await ctx.Response.WriteAsync("Include role member in body");

                    return;
                }

                PlanetRole role = await db.PlanetRoles.FindAsync(roleMember.Role_Id);

                if (role is null)
                {
                    ctx.Response.StatusCode = 400;
                    await ctx.Response.WriteAsync("Role not found");

                    return;
                }

                if (role.Planet_Id != member.Planet_Id || role.Planet_Id != target_member.Planet_Id)
                {
                    ctx.Response.StatusCode = 400;
                    await ctx.Response.WriteAsync("Planet id mismatch");

                    return;
                }

                var callerAuth = await member.GetAuthorityAsync();

                // Ensure role has less authority than user adding it
                if (role.GetAuthority() >= callerAuth)
                {
                    ctx.Response.StatusCode = 403;
                    await ctx.Response.WriteAsync("Can only add roles with lower authority than your own");

                    return;
                }

                // Ensure target member has less authority than caller
                if (await target_member.GetAuthorityAsync() >= callerAuth)
                {
                    ctx.Response.StatusCode = 403;
                    await ctx.Response.WriteAsync("Target has higher or equal authority");

                    return;
                }

                // Ensure things match properly
                roleMember.Member_Id = target_member.Id;
                roleMember.User_Id   = target_member.User_Id;
                roleMember.Planet_Id = target_member.Planet_Id;

                // Add id
                roleMember.Id = IdManager.Generate();

                await db.PlanetRoleMembers.AddAsync(roleMember);

                await db.SaveChangesAsync();

                ctx.Response.StatusCode = 201;
                await ctx.Response.WriteAsync(roleMember.Id.ToString());

                return;
            }
            }
        }