mirror of
https://github.com/ZeppelinBot/Zeppelin.git
synced 2025-03-15 05:41:51 +00:00

* update pkgs
Signed-off-by: GitHub <noreply@github.com>
* new knub typings
Signed-off-by: GitHub <noreply@github.com>
* more pkg updates
Signed-off-by: GitHub <noreply@github.com>
* more fixes
Signed-off-by: GitHub <noreply@github.com>
* channel typings
Signed-off-by: GitHub <noreply@github.com>
* more message utils typings fixes
Signed-off-by: GitHub <noreply@github.com>
* migrate permissions
Signed-off-by: GitHub <noreply@github.com>
* fix: InternalPoster webhookables
Signed-off-by: GitHub <noreply@github.com>
* djs typings: Attachment & Util
Signed-off-by: GitHub <noreply@github.com>
* more typings
Signed-off-by: GitHub <noreply@github.com>
* fix: rename permissionNames
Signed-off-by: GitHub <noreply@github.com>
* more fixes
Signed-off-by: GitHub <noreply@github.com>
* half the number of errors
* knub commands => messageCommands
Signed-off-by: GitHub <noreply@github.com>
* configPreprocessor => configParser
Signed-off-by: GitHub <noreply@github.com>
* fix channel.messages
Signed-off-by: GitHub <noreply@github.com>
* revert automod any typing
Signed-off-by: GitHub <noreply@github.com>
* more configParser typings
Signed-off-by: GitHub <noreply@github.com>
* revert
Signed-off-by: GitHub <noreply@github.com>
* remove knub type params
Signed-off-by: GitHub <noreply@github.com>
* fix more MessageEmbed / MessageOptions
Signed-off-by: GitHub <noreply@github.com>
* dumb commit for @almeidx to see why this is stupid
Signed-off-by: GitHub <noreply@github.com>
* temp disable custom_events
Signed-off-by: GitHub <noreply@github.com>
* more minor typings fixes - 23 err left
Signed-off-by: GitHub <noreply@github.com>
* update djs dep
* +debug build method (revert this)
Signed-off-by: GitHub <noreply@github.com>
* Revert "+debug build method (revert this)"
This reverts commit a80af1e729
.
* Redo +debug build (Revert this)
Signed-off-by: GitHub <noreply@github.com>
* uniform before/after Load shorthands
Signed-off-by: GitHub <noreply@github.com>
* remove unused imports & add prettier plugin
Signed-off-by: GitHub <noreply@github.com>
* env fixes for web platform hosting
Signed-off-by: GitHub <noreply@github.com>
* feat: knub v32-next; related fixes
* fix: allow legacy keys in change_perms action
* fix: request Message Content intent
* fix: use Knub's config validation logic in API
* fix(dashboard): fix error when there are no message and/or slash commands in a plugin
* fix(automod): start_thread action thread options
* fix(CustomEvents): message command types
* chore: remove unneeded type annotation
* feat: add forum channel icon; use thread icon for news threads
* chore: make tslint happy
* chore: fix formatting
---------
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: almeidx <almeidx@pm.me>
Co-authored-by: Dragory <2606411+Dragory@users.noreply.github.com>
179 lines
6.6 KiB
TypeScript
179 lines
6.6 KiB
TypeScript
import { ApiPermissions } from "@shared/apiPermissions";
|
|
import express, { Request, Response } from "express";
|
|
import { YAMLException } from "js-yaml";
|
|
import moment from "moment-timezone";
|
|
import { validateGuildConfig } from "../configValidator";
|
|
import { AllowedGuilds } from "../data/AllowedGuilds";
|
|
import { ApiAuditLog } from "../data/ApiAuditLog";
|
|
import { AuditLogEventTypes } from "../data/apiAuditLogTypes";
|
|
import { ApiPermissionAssignments, ApiPermissionTypes } from "../data/ApiPermissionAssignments";
|
|
import { Configs } from "../data/Configs";
|
|
import { Queue } from "../Queue";
|
|
import { isSnowflake } from "../utils";
|
|
import { loadYamlSafely } from "../utils/loadYamlSafely";
|
|
import { ObjectAliasError } from "../utils/validateNoObjectAliases";
|
|
import { apiTokenAuthHandlers } from "./auth";
|
|
import { hasGuildPermission, requireGuildPermission } from "./permissions";
|
|
import { clientError, ok, serverError, unauthorized } from "./responses";
|
|
|
|
const apiPermissionAssignments = new ApiPermissionAssignments();
|
|
const auditLog = new ApiAuditLog();
|
|
|
|
export function initGuildsAPI(app: express.Express) {
|
|
const allowedGuilds = new AllowedGuilds();
|
|
const configs = new Configs();
|
|
|
|
const guildRouter = express.Router();
|
|
guildRouter.use(...apiTokenAuthHandlers());
|
|
|
|
guildRouter.get("/available", async (req: Request, res: Response) => {
|
|
const guilds = await allowedGuilds.getForApiUser(req.user!.userId);
|
|
res.json(guilds);
|
|
});
|
|
|
|
guildRouter.get(
|
|
"/my-permissions", // a
|
|
async (req: Request, res: Response) => {
|
|
const permissions = await apiPermissionAssignments.getByUserId(req.user!.userId);
|
|
res.json(permissions);
|
|
},
|
|
);
|
|
|
|
guildRouter.get("/:guildId", async (req: Request, res: Response) => {
|
|
if (!(await hasGuildPermission(req.user!.userId, req.params.guildId, ApiPermissions.ViewGuild))) {
|
|
return unauthorized(res);
|
|
}
|
|
|
|
const guild = await allowedGuilds.find(req.params.guildId);
|
|
res.json(guild);
|
|
});
|
|
|
|
guildRouter.post("/:guildId/check-permission", async (req: Request, res: Response) => {
|
|
const permission = req.body.permission;
|
|
const hasPermission = await hasGuildPermission(req.user!.userId, req.params.guildId, permission);
|
|
res.json({ result: hasPermission });
|
|
});
|
|
|
|
guildRouter.get(
|
|
"/:guildId/config",
|
|
requireGuildPermission(ApiPermissions.ReadConfig),
|
|
async (req: Request, res: Response) => {
|
|
const config = await configs.getActiveByKey(`guild-${req.params.guildId}`);
|
|
res.json({ config: config ? config.config : "" });
|
|
},
|
|
);
|
|
|
|
guildRouter.post("/:guildId/config", requireGuildPermission(ApiPermissions.EditConfig), async (req, res) => {
|
|
let config = req.body.config;
|
|
if (config == null) return clientError(res, "No config supplied");
|
|
|
|
config = config.trim() + "\n"; // Normalize start/end whitespace in the config
|
|
|
|
const currentConfig = await configs.getActiveByKey(`guild-${req.params.guildId}`);
|
|
if (currentConfig && config === currentConfig.config) {
|
|
return ok(res);
|
|
}
|
|
|
|
// Validate config
|
|
let parsedConfig;
|
|
try {
|
|
parsedConfig = loadYamlSafely(config);
|
|
} catch (e) {
|
|
if (e instanceof YAMLException) {
|
|
return res.status(400).json({ errors: [e.message] });
|
|
}
|
|
|
|
if (e instanceof ObjectAliasError) {
|
|
return res.status(400).json({ errors: [e.message] });
|
|
}
|
|
|
|
// tslint:disable-next-line:no-console
|
|
console.error("Error when loading YAML: " + e.message);
|
|
return serverError(res, "Server error");
|
|
}
|
|
|
|
if (parsedConfig == null) {
|
|
parsedConfig = {};
|
|
}
|
|
|
|
const error = await validateGuildConfig(parsedConfig);
|
|
if (error) {
|
|
return res.status(422).json({ errors: [error] });
|
|
}
|
|
|
|
await configs.saveNewRevision(`guild-${req.params.guildId}`, config, req.user!.userId);
|
|
|
|
ok(res);
|
|
});
|
|
|
|
guildRouter.get(
|
|
"/:guildId/permissions",
|
|
requireGuildPermission(ApiPermissions.ManageAccess),
|
|
async (req: Request, res: Response) => {
|
|
const permissions = await apiPermissionAssignments.getByGuildId(req.params.guildId);
|
|
res.json(permissions);
|
|
},
|
|
);
|
|
|
|
const permissionManagementQueue = new Queue();
|
|
guildRouter.post(
|
|
"/:guildId/set-target-permissions",
|
|
requireGuildPermission(ApiPermissions.ManageAccess),
|
|
async (req: Request, res: Response) => {
|
|
await permissionManagementQueue.add(async () => {
|
|
const { type, targetId, permissions, expiresAt } = req.body;
|
|
|
|
if (type !== ApiPermissionTypes.User) {
|
|
return clientError(res, "Invalid type");
|
|
}
|
|
if (!isSnowflake(targetId)) {
|
|
return clientError(res, "Invalid targetId");
|
|
}
|
|
const validPermissions = new Set(Object.values(ApiPermissions));
|
|
validPermissions.delete(ApiPermissions.Owner);
|
|
if (!Array.isArray(permissions) || permissions.some((p) => !validPermissions.has(p))) {
|
|
return clientError(res, "Invalid permissions");
|
|
}
|
|
if (expiresAt != null && !moment.utc(expiresAt).isValid()) {
|
|
return clientError(res, "Invalid expiresAt");
|
|
}
|
|
|
|
const existingAssignment = await apiPermissionAssignments.getByGuildAndUserId(req.params.guildId, targetId);
|
|
if (existingAssignment && existingAssignment.permissions.includes(ApiPermissions.Owner)) {
|
|
return clientError(res, "Can't change owner permissions");
|
|
}
|
|
|
|
if (permissions.length === 0) {
|
|
await apiPermissionAssignments.removeUser(req.params.guildId, targetId);
|
|
await auditLog.addEntry(req.params.guildId, req.user!.userId, AuditLogEventTypes.REMOVE_API_PERMISSION, {
|
|
type: ApiPermissionTypes.User,
|
|
target_id: targetId,
|
|
});
|
|
} else {
|
|
const existing = await apiPermissionAssignments.getByGuildAndUserId(req.params.guildId, targetId);
|
|
if (existing) {
|
|
await apiPermissionAssignments.updateUserPermissions(req.params.guildId, targetId, permissions);
|
|
await auditLog.addEntry(req.params.guildId, req.user!.userId, AuditLogEventTypes.EDIT_API_PERMISSION, {
|
|
type: ApiPermissionTypes.User,
|
|
target_id: targetId,
|
|
permissions,
|
|
expires_at: existing.expires_at,
|
|
});
|
|
} else {
|
|
await apiPermissionAssignments.addUser(req.params.guildId, targetId, permissions, expiresAt);
|
|
await auditLog.addEntry(req.params.guildId, req.user!.userId, AuditLogEventTypes.ADD_API_PERMISSION, {
|
|
type: ApiPermissionTypes.User,
|
|
target_id: targetId,
|
|
permissions,
|
|
expires_at: expiresAt,
|
|
});
|
|
}
|
|
}
|
|
|
|
ok(res);
|
|
});
|
|
},
|
|
);
|
|
|
|
app.use("/guilds", guildRouter);
|
|
}
|