/// <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})"); }
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); }
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)); }
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)); }
/// <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(); } }
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; }
/// <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}.")); }
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"); }
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()); }
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); }
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; }
/// <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}")); }
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)); }
/// <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)); }
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; } } }
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"); } }
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; } } }