mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-31 23:55:23 +00:00
chore: openapi docs for undocumented routes and fix two broken doc blocks
This commit is contained in:
1 parent
5ecf8156e6
commit
de9b4a064c
9 files changed
+420
-5
No files matched your search
@@ -8,6 +8,16 @@ export function registerMaintenanceRoutes(
|
|||||||
ctx: PluginContext,
|
ctx: PluginContext,
|
||||||
service: MaintenanceService,
|
service: MaintenanceService,
|
||||||
) {
|
) {
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/automations/maintenance:
|
||||||
|
* get:
|
||||||
|
* summary: List maintenance windows on the caller's hosts
|
||||||
|
* tags: [Automations]
|
||||||
|
* responses:
|
||||||
|
* 200: { description: Maintenance state per host. }
|
||||||
|
* 401: { description: Not signed in. }
|
||||||
|
*/
|
||||||
router.get(
|
router.get(
|
||||||
"/maintenance",
|
"/maintenance",
|
||||||
ctx.rbac.require("view") as never,
|
ctx.rbac.require("view") as never,
|
||||||
@@ -65,11 +75,57 @@ export function registerMaintenanceRoutes(
|
|||||||
res.status(500).json({ error: "Failed to update maintenance" });
|
res.status(500).json({ error: "Failed to update maintenance" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/automations/maintenance/{hostId}:
|
||||||
|
* get:
|
||||||
|
* summary: Get a host's maintenance state and schedule
|
||||||
|
* tags: [Automations]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: hostId
|
||||||
|
* required: true
|
||||||
|
* schema: { type: integer }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: The active window, if any, and the planned ones. }
|
||||||
|
* 404: { description: Not one of the caller's hosts. }
|
||||||
|
*/
|
||||||
router.get(
|
router.get(
|
||||||
"/maintenance/:hostId",
|
"/maintenance/:hostId",
|
||||||
ctx.rbac.require("view") as never,
|
ctx.rbac.require("view") as never,
|
||||||
handle(false),
|
handle(false),
|
||||||
);
|
);
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/automations/maintenance/{hostId}:
|
||||||
|
* post:
|
||||||
|
* summary: Start, schedule, end or remove maintenance on a host
|
||||||
|
* description: While a host is in maintenance its downtime does not raise alerts. Past the estimated end plus the grace period, it can alert again.
|
||||||
|
* tags: [Automations]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: hostId
|
||||||
|
* required: true
|
||||||
|
* schema: { type: integer }
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required: [action]
|
||||||
|
* properties:
|
||||||
|
* action: { type: string, enum: [start, schedule, end, remove] }
|
||||||
|
* reason: { type: string }
|
||||||
|
* start: { type: string, format: date-time, description: When a scheduled window begins. }
|
||||||
|
* durationMinutes: { type: integer, description: Estimated length. }
|
||||||
|
* graceMinutes: { type: integer }
|
||||||
|
* recurrence: { type: string, description: Repeat a scheduled window, e.g. weekly or monthly. }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: The new maintenance state. }
|
||||||
|
* 400: { description: Invalid action or plan. }
|
||||||
|
* 404: { description: Not one of the caller's hosts. }
|
||||||
|
*/
|
||||||
router.post(
|
router.post(
|
||||||
"/maintenance/:hostId",
|
"/maintenance/:hostId",
|
||||||
ctx.rbac.require("edit") as never,
|
ctx.rbac.require("edit") as never,
|
||||||
|
|||||||
@@ -2050,6 +2050,30 @@ export async function activate(ctx: PluginContext) {
|
|||||||
closeDedicatedTransferSession,
|
closeDedicatedTransferSession,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/file-manager/transferMethodPreview:
|
||||||
|
* post:
|
||||||
|
* summary: Preview how a host to host transfer would run
|
||||||
|
* description: Says whether tar or per-file SFTP would be used, and why, without moving anything.
|
||||||
|
* tags: [File Manager]
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required: [sourceSessionId, destSessionId, sourcePaths, destPath]
|
||||||
|
* properties:
|
||||||
|
* sourceSessionId: { type: string }
|
||||||
|
* destSessionId: { type: string }
|
||||||
|
* sourcePaths: { type: array, items: { type: string } }
|
||||||
|
* destPath: { type: string }
|
||||||
|
* methodPreference: { type: string, enum: [auto, tar, item_sftp] }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: The chosen method and the reason. }
|
||||||
|
* 400: { description: Missing parameters. }
|
||||||
|
*/
|
||||||
app.post("/transferMethodPreview", async (req, res) => {
|
app.post("/transferMethodPreview", async (req, res) => {
|
||||||
const {
|
const {
|
||||||
sourceSessionId,
|
sourceSessionId,
|
||||||
@@ -2095,6 +2119,34 @@ export async function activate(ctx: PluginContext) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/file-manager/transferToHost:
|
||||||
|
* post:
|
||||||
|
* summary: Copy or move files from one host to another
|
||||||
|
* description: Starts a background transfer between two of the caller's file manager sessions.
|
||||||
|
* tags: [File Manager]
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required: [sourceSessionId, destSessionId, sourcePaths, destPath]
|
||||||
|
* properties:
|
||||||
|
* sourceSessionId: { type: string }
|
||||||
|
* destSessionId: { type: string }
|
||||||
|
* sourcePaths: { type: array, items: { type: string } }
|
||||||
|
* destPath: { type: string }
|
||||||
|
* methodPreference: { type: string, enum: [auto, tar, item_sftp] }
|
||||||
|
* move: { type: boolean, description: Delete the source after a successful copy. }
|
||||||
|
* parallelSegmentCount: { type: integer }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: The new transfer id. }
|
||||||
|
* 400: { description: Missing parameters or a session is not connected. }
|
||||||
|
* 403: { description: A session belongs to someone else. }
|
||||||
|
* 500: { description: The transfer could not start. }
|
||||||
|
*/
|
||||||
app.post("/transferToHost", async (req, res) => {
|
app.post("/transferToHost", async (req, res) => {
|
||||||
const {
|
const {
|
||||||
sourceSessionId,
|
sourceSessionId,
|
||||||
@@ -2168,6 +2220,16 @@ export async function activate(ctx: PluginContext) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/file-manager/activeTransfers:
|
||||||
|
* get:
|
||||||
|
* summary: List the caller's running host to host transfers
|
||||||
|
* tags: [File Manager]
|
||||||
|
* responses:
|
||||||
|
* 200: { description: The active transfers. }
|
||||||
|
* 401: { description: Not signed in. }
|
||||||
|
*/
|
||||||
app.get("/activeTransfers", async (req, res) => {
|
app.get("/activeTransfers", async (req, res) => {
|
||||||
const userId = ctx.currentActor();
|
const userId = ctx.currentActor();
|
||||||
if (!userId)
|
if (!userId)
|
||||||
@@ -2176,6 +2238,22 @@ export async function activate(ctx: PluginContext) {
|
|||||||
res.json({ transfers: listActiveTransfers(userId) });
|
res.json({ transfers: listActiveTransfers(userId) });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/file-manager/transferStatus/{transferId}:
|
||||||
|
* get:
|
||||||
|
* summary: Get a transfer's progress
|
||||||
|
* tags: [File Manager]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: transferId
|
||||||
|
* required: true
|
||||||
|
* schema: { type: string }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: The transfer's status and progress. }
|
||||||
|
* 401: { description: Not signed in. }
|
||||||
|
* 404: { description: No such transfer for this user. }
|
||||||
|
*/
|
||||||
app.get("/transferStatus/:transferId", async (req, res) => {
|
app.get("/transferStatus/:transferId", async (req, res) => {
|
||||||
const userId = ctx.currentActor();
|
const userId = ctx.currentActor();
|
||||||
const transferId = req.params.transferId;
|
const transferId = req.params.transferId;
|
||||||
@@ -2187,6 +2265,21 @@ export async function activate(ctx: PluginContext) {
|
|||||||
res.json(status);
|
res.json(status);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/file-manager/transferCancel/{transferId}:
|
||||||
|
* post:
|
||||||
|
* summary: Cancel a running transfer
|
||||||
|
* tags: [File Manager]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: transferId
|
||||||
|
* required: true
|
||||||
|
* schema: { type: string }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: The transfer was asked to stop. }
|
||||||
|
* 401: { description: Not signed in. }
|
||||||
|
*/
|
||||||
app.post("/transferCancel/:transferId", (req, res) => {
|
app.post("/transferCancel/:transferId", (req, res) => {
|
||||||
const userId = ctx.currentActor();
|
const userId = ctx.currentActor();
|
||||||
const transferId = req.params.transferId;
|
const transferId = req.params.transferId;
|
||||||
@@ -2200,6 +2293,22 @@ export async function activate(ctx: PluginContext) {
|
|||||||
res.json({ ok: true });
|
res.json({ ok: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/file-manager/transferCleanup/{transferId}:
|
||||||
|
* post:
|
||||||
|
* summary: Remove the partial files a cancelled transfer left
|
||||||
|
* tags: [File Manager]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: transferId
|
||||||
|
* required: true
|
||||||
|
* schema: { type: string }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: What was removed. }
|
||||||
|
* 401: { description: Not signed in. }
|
||||||
|
* 404: { description: No such transfer for this user. }
|
||||||
|
*/
|
||||||
app.post("/transferCleanup/:transferId", async (req, res) => {
|
app.post("/transferCleanup/:transferId", async (req, res) => {
|
||||||
const userId = ctx.currentActor();
|
const userId = ctx.currentActor();
|
||||||
const transferId = req.params.transferId;
|
const transferId = req.params.transferId;
|
||||||
@@ -2219,6 +2328,22 @@ export async function activate(ctx: PluginContext) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/file-manager/transferRetry/{transferId}:
|
||||||
|
* post:
|
||||||
|
* summary: Retry a failed or cancelled transfer
|
||||||
|
* tags: [File Manager]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: transferId
|
||||||
|
* required: true
|
||||||
|
* schema: { type: string }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: The transfer started again. }
|
||||||
|
* 401: { description: Not signed in. }
|
||||||
|
* 404: { description: No such transfer for this user. }
|
||||||
|
*/
|
||||||
app.post("/transferRetry/:transferId", (req, res) => {
|
app.post("/transferRetry/:transferId", (req, res) => {
|
||||||
const userId = ctx.currentActor();
|
const userId = ctx.currentActor();
|
||||||
const transferId = req.params.transferId;
|
const transferId = req.params.transferId;
|
||||||
|
|||||||
@@ -57,6 +57,22 @@ export function registerFileOperationRoutes(
|
|||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/file-manager/trash:
|
||||||
|
* get:
|
||||||
|
* summary: List items in the host's Termix trash
|
||||||
|
* tags: [File Manager]
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: sessionId
|
||||||
|
* required: true
|
||||||
|
* schema: { type: string }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: Trashed items, the retention in days and whether the caller may change it. }
|
||||||
|
* 400: { description: The session is not connected. }
|
||||||
|
* 403: { description: The session belongs to someone else. }
|
||||||
|
*/
|
||||||
app.get("/trash", async (req, res) => {
|
app.get("/trash", async (req, res) => {
|
||||||
const session = await ownedSession(req, res);
|
const session = await ownedSession(req, res);
|
||||||
if (!session) return;
|
if (!session) return;
|
||||||
@@ -73,6 +89,25 @@ export function registerFileOperationRoutes(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/file-manager/trash/{id}/restore:
|
||||||
|
* post:
|
||||||
|
* summary: Restore a trashed item to where it was
|
||||||
|
* tags: [File Manager]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* required: true
|
||||||
|
* schema: { type: string }
|
||||||
|
* - in: query
|
||||||
|
* name: sessionId
|
||||||
|
* required: true
|
||||||
|
* schema: { type: string }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: The restored path. }
|
||||||
|
* 409: { description: Something already exists at the original path. }
|
||||||
|
*/
|
||||||
app.post("/trash/:id/restore", async (req, res) => {
|
app.post("/trash/:id/restore", async (req, res) => {
|
||||||
const session = await ownedSession(req, res);
|
const session = await ownedSession(req, res);
|
||||||
if (!session) return;
|
if (!session) return;
|
||||||
@@ -91,6 +126,25 @@ export function registerFileOperationRoutes(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/file-manager/trash/{id}:
|
||||||
|
* delete:
|
||||||
|
* summary: Delete a trashed item for good
|
||||||
|
* tags: [File Manager]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* required: true
|
||||||
|
* schema: { type: string }
|
||||||
|
* - in: query
|
||||||
|
* name: sessionId
|
||||||
|
* required: true
|
||||||
|
* schema: { type: string }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: Deleted. }
|
||||||
|
* 500: { description: The delete failed on the host. }
|
||||||
|
*/
|
||||||
app.delete("/trash/:id", async (req, res) => {
|
app.delete("/trash/:id", async (req, res) => {
|
||||||
const session = await ownedSession(req, res);
|
const session = await ownedSession(req, res);
|
||||||
if (!session) return;
|
if (!session) return;
|
||||||
@@ -105,6 +159,21 @@ export function registerFileOperationRoutes(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/file-manager/trash:
|
||||||
|
* delete:
|
||||||
|
* summary: Empty the host's Termix trash
|
||||||
|
* tags: [File Manager]
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: sessionId
|
||||||
|
* required: true
|
||||||
|
* schema: { type: string }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: How many items were deleted. }
|
||||||
|
* 500: { description: The delete failed on the host. }
|
||||||
|
*/
|
||||||
app.delete("/trash", async (req, res) => {
|
app.delete("/trash", async (req, res) => {
|
||||||
const session = await ownedSession(req, res);
|
const session = await ownedSession(req, res);
|
||||||
if (!session) return;
|
if (!session) return;
|
||||||
@@ -115,6 +184,26 @@ export function registerFileOperationRoutes(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/file-manager/trash-retention:
|
||||||
|
* put:
|
||||||
|
* summary: Set how long trashed items are kept (admin only)
|
||||||
|
* tags: [File Manager]
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required: [retentionDays]
|
||||||
|
* properties:
|
||||||
|
* retentionDays: { type: integer, minimum: 1, maximum: 3650 }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: The new retention. }
|
||||||
|
* 400: { description: Out of range. }
|
||||||
|
* 403: { description: Admin access required. }
|
||||||
|
*/
|
||||||
app.put("/trash-retention", async (req, res) => {
|
app.put("/trash-retention", async (req, res) => {
|
||||||
if (!(await canManageRetention())) {
|
if (!(await canManageRetention())) {
|
||||||
return res.status(403).json({ error: "Admin access required" });
|
return res.status(403).json({ error: "Admin access required" });
|
||||||
|
|||||||
@@ -900,6 +900,29 @@ router.get("/discover/stream", async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/proxmox/discover:
|
||||||
|
* post:
|
||||||
|
* summary: Discover the guests on a Proxmox node
|
||||||
|
* description: Lists the node's VMs and containers so they can be added as hosts. /discover/stream reports the same with progress.
|
||||||
|
* tags: [Proxmox]
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required: [hostId]
|
||||||
|
* properties:
|
||||||
|
* hostId: { type: integer }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: The guests found. }
|
||||||
|
* 400: { description: Missing or invalid hostId. }
|
||||||
|
* 403: { description: Access denied to the host. }
|
||||||
|
* 404: { description: Host not found. }
|
||||||
|
* 422: { description: Host is not a Proxmox node or is unreachable. }
|
||||||
|
*/
|
||||||
router.post("/discover", async (req, res) => {
|
router.post("/discover", async (req, res) => {
|
||||||
const { hostId } = req.body as { hostId?: unknown };
|
const { hostId } = req.body as { hostId?: unknown };
|
||||||
const userId = pluginCtx().currentActor()!;
|
const userId = pluginCtx().currentActor()!;
|
||||||
|
|||||||
@@ -502,7 +502,7 @@ export function registerRoutes(router: Router, deps: RouteDeps): void {
|
|||||||
* name: probe
|
* name: probe
|
||||||
* schema:
|
* schema:
|
||||||
* type: string
|
* type: string
|
||||||
* description: "0" skips dialing guacd.
|
* description: Set to 0 to skip dialing guacd.
|
||||||
* - in: query
|
* - in: query
|
||||||
* name: hostId
|
* name: hostId
|
||||||
* schema:
|
* schema:
|
||||||
|
|||||||
@@ -200,6 +200,23 @@ export function registerRoomRoutes(
|
|||||||
} = actions;
|
} = actions;
|
||||||
const requireUse = ctx.rbac.require("use") as never;
|
const requireUse = ctx.rbac.require("use") as never;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/session-sharing/meeting-host/{syncId}:
|
||||||
|
* get:
|
||||||
|
* summary: Find this server's id for a synced host
|
||||||
|
* description: A desktop presents a host by its sync id; this returns the matching host the caller may connect to.
|
||||||
|
* tags: [Collab]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: syncId
|
||||||
|
* required: true
|
||||||
|
* schema: { type: string }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: The host id. }
|
||||||
|
* 401: { description: Not signed in. }
|
||||||
|
* 404: { description: No reachable host with that sync id. }
|
||||||
|
*/
|
||||||
router.get(
|
router.get(
|
||||||
"/meeting-host/:syncId",
|
"/meeting-host/:syncId",
|
||||||
requireUse,
|
requireUse,
|
||||||
|
|||||||
@@ -147,6 +147,29 @@ function endpointUrl(
|
|||||||
export function createWebEndpointRoutes(ctx: PluginContext): Router {
|
export function createWebEndpointRoutes(ctx: PluginContext): Router {
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/web-endpoint/open:
|
||||||
|
* post:
|
||||||
|
* summary: Open a tunnel to a host's web endpoint
|
||||||
|
* description: For endpoints reached through SSH. Returns the local port the tunnel listens on.
|
||||||
|
* tags: [Web Endpoint]
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required: [hostId, endpointId]
|
||||||
|
* properties:
|
||||||
|
* hostId: { type: integer }
|
||||||
|
* endpointId: { type: string }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: The local port. }
|
||||||
|
* 400: { description: Invalid request, or the endpoint does not use a tunnel. }
|
||||||
|
* 401: { description: Not signed in. }
|
||||||
|
* 404: { description: Host or endpoint not found. }
|
||||||
|
*/
|
||||||
router.post("/open", async (req, res) => {
|
router.post("/open", async (req, res) => {
|
||||||
const userId = ctx.currentActor();
|
const userId = ctx.currentActor();
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
@@ -200,6 +223,29 @@ export function createWebEndpointRoutes(ctx: PluginContext): Router {
|
|||||||
* capability check and audit line cover the whole decision, not just the
|
* capability check and audit line cover the whole decision, not just the
|
||||||
* final "open a window" step.
|
* final "open a window" step.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /plugin-api/web-endpoint/open-window:
|
||||||
|
* post:
|
||||||
|
* summary: Open a host's web endpoint in a desktop window
|
||||||
|
* tags: [Web Endpoint]
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required: [hostId, endpointId]
|
||||||
|
* properties:
|
||||||
|
* hostId: { type: integer }
|
||||||
|
* endpointId: { type: string }
|
||||||
|
* ignoreCert: { type: boolean, description: Accept a self-signed certificate for this window. }
|
||||||
|
* responses:
|
||||||
|
* 200: { description: The window opened. }
|
||||||
|
* 400: { description: Invalid request. }
|
||||||
|
* 401: { description: Not signed in. }
|
||||||
|
* 404: { description: Host not found or access denied. }
|
||||||
|
*/
|
||||||
router.post("/open-window", async (req, res) => {
|
router.post("/open-window", async (req, res) => {
|
||||||
const userId = ctx.currentActor();
|
const userId = ctx.currentActor();
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
|
|||||||
@@ -572,7 +572,6 @@ router.post(
|
|||||||
* authType:
|
* authType:
|
||||||
* type: string
|
* type: string
|
||||||
* description: Any registered SSH auth type that works for an unsaved host (password, key, credential, agent, none, or one a plugin marks for Quick Connect).
|
* description: Any registered SSH auth type that works for an unsaved host (password, key, credential, agent, none, or one a plugin marks for Quick Connect).
|
||||||
* description: Authentication method
|
|
||||||
* password:
|
* password:
|
||||||
* type: string
|
* type: string
|
||||||
* description: Password (required if authType is password)
|
* description: Password (required if authType is password)
|
||||||
@@ -1490,9 +1489,26 @@ router.get(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the minimum authentication material needed by the desktop app to
|
* @openapi
|
||||||
* connect to a shared host from the recipient's own network. The response is
|
* /host/db/host/{id}/local-connection-auth:
|
||||||
* deliberately transient: callers must not persist it or include it in logs.
|
* get:
|
||||||
|
* summary: Get the login a desktop needs to reach a shared host itself
|
||||||
|
* description: The minimum authentication material for connecting to a shared host from the recipient's own network. Transient; callers must not store or log it.
|
||||||
|
* tags:
|
||||||
|
* - SSH
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: The connection auth.
|
||||||
|
* 400:
|
||||||
|
* description: Invalid id.
|
||||||
|
* 404:
|
||||||
|
* description: Shared host not found.
|
||||||
*/
|
*/
|
||||||
router.get(
|
router.get(
|
||||||
"/db/host/:id/local-connection-auth",
|
"/db/host/:id/local-connection-auth",
|
||||||
|
|||||||
@@ -671,6 +671,49 @@ router.delete(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /rbac/host/{id}/access/{accessId}:
|
||||||
|
* patch:
|
||||||
|
* summary: Change a host access rule
|
||||||
|
* description: Updates the permission level or the expiry of one share. Requires the right to manage sharing on the host.
|
||||||
|
* tags:
|
||||||
|
* - RBAC
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* - in: path
|
||||||
|
* name: accessId
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* permissionLevel:
|
||||||
|
* type: string
|
||||||
|
* enum: [connect, view, edit, manage]
|
||||||
|
* durationHours:
|
||||||
|
* type: number
|
||||||
|
* nullable: true
|
||||||
|
* description: Hours from now until the share expires. Null removes the expiry.
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: The updated rule.
|
||||||
|
* 400:
|
||||||
|
* description: Invalid id or nothing to change.
|
||||||
|
* 403:
|
||||||
|
* description: Not allowed to manage sharing on this host.
|
||||||
|
* 404:
|
||||||
|
* description: No such rule.
|
||||||
|
*/
|
||||||
router.patch(
|
router.patch(
|
||||||
"/host/:id/access/:accessId",
|
"/host/:id/access/:accessId",
|
||||||
authenticateJWT,
|
authenticateJWT,
|
||||||
|
|||||||
Reference in new issue
Block a user