chore: check permissions for various clan requests (#1175)
All checks were successful
Build / build (18) (push) Successful in 45s
Build / build (20) (push) Successful in 1m4s
Build / build (22) (push) Successful in 41s
Build Docker image / docker (push) Successful in 51s

Reviewed-on: #1175
This commit is contained in:
Sainan 2025-03-14 07:09:28 -07:00
parent 236cccc137
commit 0facdd1af9
16 changed files with 216 additions and 58 deletions

View File

@ -1,14 +1,34 @@
import { getDojoClient, getGuildForRequestEx, removeDojoDeco, removeDojoRoom } from "@/src/services/guildService"; import {
getDojoClient,
getGuildForRequestEx,
hasAccessToDojo,
hasGuildPermission,
removeDojoDeco,
removeDojoRoom
} from "@/src/services/guildService";
import { getInventory } from "@/src/services/inventoryService"; import { getInventory } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService"; import { getAccountIdForRequest } from "@/src/services/loginService";
import { GuildPermission } from "@/src/types/guildTypes";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
export const abortDojoComponentController: RequestHandler = async (req, res) => { export const abortDojoComponentController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId, "GuildId LevelKeys");
const guild = await getGuildForRequestEx(req, inventory); const guild = await getGuildForRequestEx(req, inventory);
const request = JSON.parse(String(req.body)) as IAbortDojoComponentRequest; const request = JSON.parse(String(req.body)) as IAbortDojoComponentRequest;
if (
!hasAccessToDojo(inventory) ||
!(await hasGuildPermission(
guild,
accountId,
request.DecoId ? GuildPermission.Decorator : GuildPermission.Architect
))
) {
res.json({ DojoRequestStatus: -1 });
return;
}
if (request.DecoId) { if (request.DecoId) {
removeDojoDeco(guild, request.ComponentId, request.DecoId); removeDojoDeco(guild, request.ComponentId, request.DecoId);
} else { } else {

View File

@ -1,8 +1,17 @@
import { getDojoClient, getGuildForRequest } from "@/src/services/guildService"; import { getDojoClient, getGuildForRequestEx, hasAccessToDojo, hasGuildPermission } from "@/src/services/guildService";
import { getInventory } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { GuildPermission } from "@/src/types/guildTypes";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
export const abortDojoComponentDestructionController: RequestHandler = async (req, res) => { export const abortDojoComponentDestructionController: RequestHandler = async (req, res) => {
const guild = await getGuildForRequest(req); const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId, "GuildId LevelKeys");
const guild = await getGuildForRequestEx(req, inventory);
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Architect))) {
res.json({ DojoRequestStatus: -1 });
return;
}
const componentId = req.query.componentId as string; const componentId = req.query.componentId as string;
guild.DojoComponents.id(componentId)!.DestructionTime = undefined; guild.DojoComponents.id(componentId)!.DestructionTime = undefined;

View File

@ -1,11 +1,11 @@
import { Guild, GuildMember } from "@/src/models/guildModel"; import { Guild, GuildMember } from "@/src/models/guildModel";
import { Account } from "@/src/models/loginModel"; import { Account } from "@/src/models/loginModel";
import { fillInInventoryDataForGuildMember } from "@/src/services/guildService"; import { fillInInventoryDataForGuildMember, hasGuildPermission } from "@/src/services/guildService";
import { createMessage } from "@/src/services/inboxService"; import { createMessage } from "@/src/services/inboxService";
import { getInventory } from "@/src/services/inventoryService"; import { getInventory } from "@/src/services/inventoryService";
import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService"; import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
import { IOid } from "@/src/types/commonTypes"; import { IOid } from "@/src/types/commonTypes";
import { IGuildMemberClient } from "@/src/types/guildTypes"; import { GuildPermission, IGuildMemberClient } from "@/src/types/guildTypes";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
import { ExportFlavour } from "warframe-public-export-plus"; import { ExportFlavour } from "warframe-public-export-plus";
@ -19,7 +19,10 @@ export const addToGuildController: RequestHandler = async (req, res) => {
} }
const guild = (await Guild.findOne({ _id: payload.GuildId.$oid }, "Name"))!; const guild = (await Guild.findOne({ _id: payload.GuildId.$oid }, "Name"))!;
// TODO: Check sender is allowed to send invites for this guild. const senderAccount = await getAccountForRequest(req);
if (!(await hasGuildPermission(guild, senderAccount._id.toString(), GuildPermission.Recruiter))) {
res.status(400).json("Invalid permission");
}
if ( if (
await GuildMember.exists({ await GuildMember.exists({
@ -37,7 +40,6 @@ export const addToGuildController: RequestHandler = async (req, res) => {
status: 2 // outgoing invite status: 2 // outgoing invite
}); });
const senderAccount = await getAccountForRequest(req);
const senderInventory = await getInventory(senderAccount._id.toString(), "ActiveAvatarImageType"); const senderInventory = await getInventory(senderAccount._id.toString(), "ActiveAvatarImageType");
await createMessage(account._id.toString(), [ await createMessage(account._id.toString(), [
{ {

View File

@ -1,12 +1,19 @@
import { RequestHandler } from "express"; import { RequestHandler } from "express";
import { getDojoClient, getGuildForRequest } from "@/src/services/guildService"; import { getDojoClient, getGuildForRequestEx, hasAccessToDojo, hasGuildPermission } from "@/src/services/guildService";
import { logger } from "@/src/utils/logger"; import { logger } from "@/src/utils/logger";
import { IDojoComponentDatabase } from "@/src/types/guildTypes"; import { GuildPermission, IDojoComponentDatabase } from "@/src/types/guildTypes";
import { Types } from "mongoose"; import { Types } from "mongoose";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getInventory } from "@/src/services/inventoryService";
export const changeDojoRootController: RequestHandler = async (req, res) => { export const changeDojoRootController: RequestHandler = async (req, res) => {
const guild = await getGuildForRequest(req); const accountId = await getAccountIdForRequest(req);
// At this point, we know that a member of the guild is making this request. Assuming they are allowed to change the root. const inventory = await getInventory(accountId, "GuildId LevelKeys");
const guild = await getGuildForRequestEx(req, inventory);
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Architect))) {
res.json({ DojoRequestStatus: -1 });
return;
}
const idToNode: Record<string, INode> = {}; const idToNode: Record<string, INode> = {};
guild.DojoComponents.forEach(x => { guild.DojoComponents.forEach(x => {

View File

@ -1,28 +1,38 @@
import { GuildMember } from "@/src/models/guildModel"; import { GuildMember } from "@/src/models/guildModel";
import { getGuildForRequest, hasGuildPermissionEx } from "@/src/services/guildService";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { GuildPermission } from "@/src/types/guildTypes";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
export const changeGuildRankController: RequestHandler = async (req, res) => { export const changeGuildRankController: RequestHandler = async (req, res) => {
// TODO: Verify permissions const accountId = await getAccountIdForRequest(req);
const guildMember = (await GuildMember.findOne({ const member = (await GuildMember.findOne({
accountId: accountId,
guildId: req.query.guildId as string
}))!;
const newRank: number = parseInt(req.query.rankChange as string);
const guild = await getGuildForRequest(req);
if (newRank < member.rank || !hasGuildPermissionEx(guild, member, GuildPermission.Promoter)) {
res.status(400).json("Invalid permission");
return;
}
const target = (await GuildMember.findOne({
guildId: req.query.guildId as string, guildId: req.query.guildId as string,
accountId: req.query.targetId as string accountId: req.query.targetId as string
}))!; }))!;
guildMember.rank = parseInt(req.query.rankChange as string); target.rank = parseInt(req.query.rankChange as string);
await guildMember.save(); await target.save();
if (guildMember.rank == 0) { if (newRank == 0) {
// If we just promoted someone else to Founding Warlord, we need to demote ourselves to Warlord. // If we just promoted someone else to Founding Warlord, we need to demote ourselves to Warlord.
await GuildMember.findOneAndUpdate( member.rank = 1;
{ await member.save();
guildId: req.query.guildId as string,
accountId: req.query.accountId as string
},
{ rank: 1 }
);
} }
res.json({ res.json({
_id: req.query.targetId as string, _id: req.query.targetId as string,
Rank: guildMember.rank Rank: newRank
}); });
}; };

View File

@ -3,6 +3,7 @@ import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/invento
import { import {
getDojoClient, getDojoClient,
getGuildForRequestEx, getGuildForRequestEx,
hasAccessToDojo,
processDojoBuildMaterialsGathered, processDojoBuildMaterialsGathered,
scaleRequiredCount, scaleRequiredCount,
setDojoRoomLogFunded setDojoRoomLogFunded
@ -28,8 +29,12 @@ interface IContributeToDojoComponentRequest {
export const contributeToDojoComponentController: RequestHandler = async (req, res) => { export const contributeToDojoComponentController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
const guild = await getGuildForRequestEx(req, inventory);
// Any clan member should have permission to contribute although notably permission is denied if they have not crafted the dojo key and were simply invited in. // Any clan member should have permission to contribute although notably permission is denied if they have not crafted the dojo key and were simply invited in.
if (!hasAccessToDojo(inventory)) {
res.json({ DojoRequestStatus: -1 });
return;
}
const guild = await getGuildForRequestEx(req, inventory);
const request = JSON.parse(String(req.body)) as IContributeToDojoComponentRequest; const request = JSON.parse(String(req.body)) as IContributeToDojoComponentRequest;
const component = guild.DojoComponents.id(request.ComponentId)!; const component = guild.DojoComponents.id(request.ComponentId)!;

View File

@ -1,11 +1,16 @@
import { getGuildForRequest } from "@/src/services/guildService"; import { getGuildForRequest, hasGuildPermission } from "@/src/services/guildService";
import { IGuildRank } from "@/src/types/guildTypes"; import { getAccountIdForRequest } from "@/src/services/loginService";
import { GuildPermission, IGuildRank } from "@/src/types/guildTypes";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
export const customizeGuildRanksController: RequestHandler = async (req, res) => { export const customizeGuildRanksController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const guild = await getGuildForRequest(req); const guild = await getGuildForRequest(req);
const payload = JSON.parse(String(req.body)) as ICustomizeGuildRanksRequest; const payload = JSON.parse(String(req.body)) as ICustomizeGuildRanksRequest;
// TODO: Verify permissions if (!(await hasGuildPermission(guild, accountId, GuildPermission.Ruler))) {
res.status(400).json("Invalid permission");
return;
}
guild.Ranks = payload.GuildRanks; guild.Ranks = payload.GuildRanks;
await guild.save(); await guild.save();
res.end(); res.end();

View File

@ -1,8 +1,23 @@
import { getDojoClient, getGuildForRequest, removeDojoDeco } from "@/src/services/guildService"; import {
getDojoClient,
getGuildForRequestEx,
hasAccessToDojo,
hasGuildPermission,
removeDojoDeco
} from "@/src/services/guildService";
import { getInventory } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { GuildPermission } from "@/src/types/guildTypes";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
export const destroyDojoDecoController: RequestHandler = async (req, res) => { export const destroyDojoDecoController: RequestHandler = async (req, res) => {
const guild = await getGuildForRequest(req); const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId, "GuildId LevelKeys");
const guild = await getGuildForRequestEx(req, inventory);
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Decorator))) {
res.json({ DojoRequestStatus: -1 });
return;
}
const request = JSON.parse(String(req.body)) as IDestroyDojoDecoRequest; const request = JSON.parse(String(req.body)) as IDestroyDojoDecoRequest;
removeDojoDeco(guild, request.ComponentId, request.DecoId); removeDojoDeco(guild, request.ComponentId, request.DecoId);

View File

@ -1,4 +1,4 @@
import { getDojoClient, getGuildForRequestEx, scaleRequiredCount } from "@/src/services/guildService"; import { getDojoClient, getGuildForRequestEx, hasAccessToDojo, scaleRequiredCount } from "@/src/services/guildService";
import { getInventory, updateCurrency } from "@/src/services/inventoryService"; import { getInventory, updateCurrency } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService"; import { getAccountIdForRequest } from "@/src/services/loginService";
import { IDojoContributable } from "@/src/types/guildTypes"; import { IDojoContributable } from "@/src/types/guildTypes";
@ -17,6 +17,10 @@ interface IDojoComponentRushRequest {
export const dojoComponentRushController: RequestHandler = async (req, res) => { export const dojoComponentRushController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
if (!hasAccessToDojo(inventory)) {
res.json({ DojoRequestStatus: -1 });
return;
}
const guild = await getGuildForRequestEx(req, inventory); const guild = await getGuildForRequestEx(req, inventory);
const request = JSON.parse(String(req.body)) as IDojoComponentRushRequest; const request = JSON.parse(String(req.body)) as IDojoComponentRushRequest;
const component = guild.DojoComponents.id(request.ComponentId)!; const component = guild.DojoComponents.id(request.ComponentId)!;

View File

@ -1,5 +1,11 @@
import { RequestHandler } from "express"; import { RequestHandler } from "express";
import { getGuildForRequestEx, getGuildVault, scaleRequiredCount } from "@/src/services/guildService"; import {
getGuildForRequestEx,
getGuildVault,
hasAccessToDojo,
hasGuildPermission,
scaleRequiredCount
} from "@/src/services/guildService";
import { ExportDojoRecipes, IDojoResearch } from "warframe-public-export-plus"; import { ExportDojoRecipes, IDojoResearch } from "warframe-public-export-plus";
import { getAccountIdForRequest } from "@/src/services/loginService"; import { getAccountIdForRequest } from "@/src/services/loginService";
import { import {
@ -13,7 +19,7 @@ import {
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes"; import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
import { IInventoryChanges } from "@/src/types/purchaseTypes"; import { IInventoryChanges } from "@/src/types/purchaseTypes";
import { config } from "@/src/services/configService"; import { config } from "@/src/services/configService";
import { ITechProjectClient, ITechProjectDatabase } from "@/src/types/guildTypes"; import { GuildPermission, ITechProjectClient, ITechProjectDatabase } from "@/src/types/guildTypes";
import { TGuildDatabaseDocument } from "@/src/models/guildModel"; import { TGuildDatabaseDocument } from "@/src/models/guildModel";
import { toMongoDate } from "@/src/helpers/inventoryHelpers"; import { toMongoDate } from "@/src/helpers/inventoryHelpers";
@ -48,6 +54,10 @@ export const guildTechController: RequestHandler = async (req, res) => {
} }
res.json({ TechProjects: techProjects }); res.json({ TechProjects: techProjects });
} else if (action == "Start") { } else if (action == "Start") {
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Fabricator))) {
res.status(400).send("-1").end();
return;
}
const recipe = ExportDojoRecipes.research[data.RecipeType!]; const recipe = ExportDojoRecipes.research[data.RecipeType!];
guild.TechProjects ??= []; guild.TechProjects ??= [];
if (!guild.TechProjects.find(x => x.ItemType == data.RecipeType)) { if (!guild.TechProjects.find(x => x.ItemType == data.RecipeType)) {
@ -71,6 +81,10 @@ export const guildTechController: RequestHandler = async (req, res) => {
await guild.save(); await guild.save();
res.end(); res.end();
} else if (action == "Contribute") { } else if (action == "Contribute") {
if (!hasAccessToDojo(inventory)) {
res.status(400).send("-1").end();
return;
}
const contributions = data as IGuildTechContributeFields; const contributions = data as IGuildTechContributeFields;
const techProject = guild.TechProjects!.find(x => x.ItemType == contributions.RecipeType)!; const techProject = guild.TechProjects!.find(x => x.ItemType == contributions.RecipeType)!;
@ -133,9 +147,12 @@ export const guildTechController: RequestHandler = async (req, res) => {
Vault: getGuildVault(guild) Vault: getGuildVault(guild)
}); });
} else if (action == "Buy") { } else if (action == "Buy") {
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Fabricator))) {
res.status(400).send("-1").end();
return;
}
const purchase = data as IGuildTechBuyFields; const purchase = data as IGuildTechBuyFields;
const quantity = parseInt(data.Action.split(",")[1]); const quantity = parseInt(data.Action.split(",")[1]);
const inventory = await getInventory(accountId);
const recipeChanges = [ const recipeChanges = [
{ {
ItemType: purchase.RecipeType, ItemType: purchase.RecipeType,
@ -157,9 +174,12 @@ export const guildTechController: RequestHandler = async (req, res) => {
} }
}); });
} else if (action == "Fabricate") { } else if (action == "Fabricate") {
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Fabricator))) {
res.status(400).send("-1").end();
return;
}
const payload = data as IGuildTechFabricateRequest; const payload = data as IGuildTechFabricateRequest;
const recipe = ExportDojoRecipes.fabrications[payload.RecipeType]; const recipe = ExportDojoRecipes.fabrications[payload.RecipeType];
const inventory = await getInventory(accountId);
const inventoryChanges: IInventoryChanges = updateCurrency(inventory, recipe.price, false); const inventoryChanges: IInventoryChanges = updateCurrency(inventory, recipe.price, false);
inventoryChanges.MiscItems = recipe.ingredients.map(x => ({ inventoryChanges.MiscItems = recipe.ingredients.map(x => ({
ItemType: x.ItemType, ItemType: x.ItemType,

View File

@ -1,12 +1,20 @@
import { getDojoClient, getGuildForRequest } from "@/src/services/guildService"; import { getDojoClient, getGuildForRequestEx, hasAccessToDojo, hasGuildPermission } from "@/src/services/guildService";
import { getInventory } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { GuildPermission } from "@/src/types/guildTypes";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
import { Types } from "mongoose"; import { Types } from "mongoose";
import { ExportDojoRecipes } from "warframe-public-export-plus"; import { ExportDojoRecipes } from "warframe-public-export-plus";
export const placeDecoInComponentController: RequestHandler = async (req, res) => { export const placeDecoInComponentController: RequestHandler = async (req, res) => {
const guild = await getGuildForRequest(req); const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId, "GuildId LevelKeys");
const guild = await getGuildForRequestEx(req, inventory);
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Decorator))) {
res.json({ DojoRequestStatus: -1 });
return;
}
const request = JSON.parse(String(req.body)) as IPlaceDecoInComponentRequest; const request = JSON.parse(String(req.body)) as IPlaceDecoInComponentRequest;
// At this point, we know that a member of the guild is making this request. Assuming they are allowed to place decorations.
const component = guild.DojoComponents.id(request.ComponentId)!; const component = guild.DojoComponents.id(request.ComponentId)!;
if (component.DecoCapacity === undefined) { if (component.DecoCapacity === undefined) {

View File

@ -1,9 +1,18 @@
import { config } from "@/src/services/configService"; import { config } from "@/src/services/configService";
import { getDojoClient, getGuildForRequest } from "@/src/services/guildService"; import { getDojoClient, getGuildForRequestEx, hasAccessToDojo, hasGuildPermission } from "@/src/services/guildService";
import { getInventory } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { GuildPermission } from "@/src/types/guildTypes";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
export const queueDojoComponentDestructionController: RequestHandler = async (req, res) => { export const queueDojoComponentDestructionController: RequestHandler = async (req, res) => {
const guild = await getGuildForRequest(req); const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId, "GuildId LevelKeys");
const guild = await getGuildForRequestEx(req, inventory);
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Architect))) {
res.json({ DojoRequestStatus: -1 });
return;
}
const componentId = req.query.componentId as string; const componentId = req.query.componentId as string;
guild.DojoComponents.id(componentId)!.DestructionTime = new Date( guild.DojoComponents.id(componentId)!.DestructionTime = new Date(

View File

@ -1,15 +1,20 @@
import { GuildMember } from "@/src/models/guildModel"; import { GuildMember } from "@/src/models/guildModel";
import { Account } from "@/src/models/loginModel"; import { Account } from "@/src/models/loginModel";
import { getGuildForRequest } from "@/src/services/guildService"; import { getGuildForRequest, hasGuildPermission } from "@/src/services/guildService";
import { getInventory } from "@/src/services/inventoryService"; import { getInventory } from "@/src/services/inventoryService";
import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService"; import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
import { GuildPermission } from "@/src/types/guildTypes";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
export const removeFromGuildController: RequestHandler = async (req, res) => { export const removeFromGuildController: RequestHandler = async (req, res) => {
const account = await getAccountForRequest(req); const account = await getAccountForRequest(req);
const guild = await getGuildForRequest(req); const guild = await getGuildForRequest(req);
// TODO: Check permissions
const payload = JSON.parse(String(req.body)) as IRemoveFromGuildRequest; const payload = JSON.parse(String(req.body)) as IRemoveFromGuildRequest;
const isKick = !account._id.equals(payload.userId);
if (isKick && !(await hasGuildPermission(guild, account._id, GuildPermission.Regulator))) {
res.status(400).json("Invalid permission");
return;
}
const guildMember = (await GuildMember.findOne({ accountId: payload.userId, guildId: guild._id }))!; const guildMember = (await GuildMember.findOne({ accountId: payload.userId, guildId: guild._id }))!;
if (guildMember.status == 0) { if (guildMember.status == 0) {
@ -36,21 +41,19 @@ export const removeFromGuildController: RequestHandler = async (req, res) => {
await GuildMember.deleteOne({ _id: guildMember._id }); await GuildMember.deleteOne({ _id: guildMember._id });
guild.RosterActivity ??= []; guild.RosterActivity ??= [];
if (account._id.equals(payload.userId)) { if (isKick) {
// Leave
guild.RosterActivity.push({
dateTime: new Date(),
entryType: 7,
details: getSuffixedName(account)
});
} else {
// Kick
const kickee = (await Account.findOne({ _id: payload.userId }))!; const kickee = (await Account.findOne({ _id: payload.userId }))!;
guild.RosterActivity.push({ guild.RosterActivity.push({
dateTime: new Date(), dateTime: new Date(),
entryType: 12, entryType: 12,
details: getSuffixedName(kickee) + "," + getSuffixedName(account) details: getSuffixedName(kickee) + "," + getSuffixedName(account)
}); });
} else {
guild.RosterActivity.push({
dateTime: new Date(),
entryType: 7,
details: getSuffixedName(account)
});
} }
await guild.save(); await guild.save();

View File

@ -1,13 +1,18 @@
import { Guild } from "@/src/models/guildModel"; import { Guild } from "@/src/models/guildModel";
import { hasGuildPermission } from "@/src/services/guildService";
import { getInventory } from "@/src/services/inventoryService"; import { getInventory } from "@/src/services/inventoryService";
import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService"; import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
import { GuildPermission } from "@/src/types/guildTypes";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
export const setGuildMotdController: RequestHandler = async (req, res) => { export const setGuildMotdController: RequestHandler = async (req, res) => {
const account = await getAccountForRequest(req); const account = await getAccountForRequest(req);
const inventory = await getInventory(account._id.toString()); const inventory = await getInventory(account._id.toString(), "GuildId");
const guild = (await Guild.findOne({ _id: inventory.GuildId! }))!; const guild = (await Guild.findOne({ _id: inventory.GuildId! }))!;
// TODO: Check permissions if (!(await hasGuildPermission(guild, account._id, GuildPermission.Herald))) {
res.status(400).json("Invalid permission");
return;
}
const IsLongMOTD = "longMOTD" in req.query; const IsLongMOTD = "longMOTD" in req.query;
const MOTD = req.body ? String(req.body) : undefined; const MOTD = req.body ? String(req.body) : undefined;

View File

@ -1,14 +1,18 @@
import { RequestHandler } from "express"; import { RequestHandler } from "express";
import { IDojoComponentClient } from "@/src/types/guildTypes"; import { GuildPermission, IDojoComponentClient } from "@/src/types/guildTypes";
import { import {
getDojoClient, getDojoClient,
getGuildForRequest, getGuildForRequestEx,
hasAccessToDojo,
hasGuildPermission,
processDojoBuildMaterialsGathered, processDojoBuildMaterialsGathered,
setDojoRoomLogFunded setDojoRoomLogFunded
} from "@/src/services/guildService"; } from "@/src/services/guildService";
import { Types } from "mongoose"; import { Types } from "mongoose";
import { ExportDojoRecipes } from "warframe-public-export-plus"; import { ExportDojoRecipes } from "warframe-public-export-plus";
import { config } from "@/src/services/configService"; import { config } from "@/src/services/configService";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getInventory } from "@/src/services/inventoryService";
interface IStartDojoRecipeRequest { interface IStartDojoRecipeRequest {
PlacedComponent: IDojoComponentClient; PlacedComponent: IDojoComponentClient;
@ -16,8 +20,13 @@ interface IStartDojoRecipeRequest {
} }
export const startDojoRecipeController: RequestHandler = async (req, res) => { export const startDojoRecipeController: RequestHandler = async (req, res) => {
const guild = await getGuildForRequest(req); const accountId = await getAccountIdForRequest(req);
// At this point, we know that a member of the guild is making this request. Assuming they are allowed to start a build. const inventory = await getInventory(accountId, "GuildId LevelKeys");
const guild = await getGuildForRequestEx(req, inventory);
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Architect))) {
res.json({ DojoRequestStatus: -1 });
return;
}
const request = JSON.parse(String(req.body)) as IStartDojoRecipeRequest; const request = JSON.parse(String(req.body)) as IStartDojoRecipeRequest;
const room = Object.values(ExportDojoRecipes.rooms).find(x => x.resultType == request.PlacedComponent.pf); const room = Object.values(ExportDojoRecipes.rooms).find(x => x.resultType == request.PlacedComponent.pf);

View File

@ -4,6 +4,7 @@ import { addRecipes, getInventory } from "@/src/services/inventoryService";
import { Guild, GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel"; import { Guild, GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel"; import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
import { import {
GuildPermission,
IDojoClient, IDojoClient,
IDojoComponentClient, IDojoComponentClient,
IDojoComponentDatabase, IDojoComponentDatabase,
@ -11,6 +12,7 @@ import {
IDojoDecoClient, IDojoDecoClient,
IGuildClient, IGuildClient,
IGuildMemberClient, IGuildMemberClient,
IGuildMemberDatabase,
IGuildVault IGuildVault
} from "@/src/types/guildTypes"; } from "@/src/types/guildTypes";
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers"; import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
@ -322,3 +324,28 @@ export const createUniqueClanName = async (name: string): Promise<string> => {
} while (discriminator != initialDiscriminator); } while (discriminator != initialDiscriminator);
throw new Error(`clan name is so unoriginal it's already been done 1000 times: ${name}`); throw new Error(`clan name is so unoriginal it's already been done 1000 times: ${name}`);
}; };
export const hasAccessToDojo = (inventory: TInventoryDatabaseDocument): boolean => {
return inventory.LevelKeys.find(x => x.ItemType == "/Lotus/Types/Keys/DojoKey") !== undefined;
};
export const hasGuildPermission = async (
guild: TGuildDatabaseDocument,
accountId: string | Types.ObjectId,
perm: GuildPermission
): Promise<boolean> => {
const member = await GuildMember.findOne({ accountId: accountId, guildId: guild._id });
if (member) {
return hasGuildPermissionEx(guild, member, perm);
}
return false;
};
export const hasGuildPermissionEx = (
guild: TGuildDatabaseDocument,
member: IGuildMemberDatabase,
perm: GuildPermission
): boolean => {
const rank = guild.Ranks[member.rank];
return (rank.Permissions & perm) != 0;
};