homebridge-config-ui-x
Version:
A web based management, configuration and control platform for Homebridge.
133 lines • 6.95 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
import process from 'node:process';
import { Controller, Get, Inject, NotFoundException, Param, Post, Query, Req, Res, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger';
import { API_PREFIX } from '../../../core/api.constants.js';
import { AdminGuard } from '../../../core/auth/guards/admin.guard.js';
import { PluginsSettingsUiTicketService } from './plugins-settings-ui-ticket.service.js';
import { PluginsSettingsUiService } from './plugins-settings-ui.service.js';
let PluginsSettingsUiController = class PluginsSettingsUiController {
pluginSettingsUiService;
ticketService;
constructor(pluginSettingsUiService, ticketService) {
this.pluginSettingsUiService = pluginSettingsUiService;
this.ticketService = ticketService;
}
async issueTicket(request, pluginName) {
await this.pluginSettingsUiService.getPluginUiMetadata(pluginName);
return {
ticket: this.ticketService.issue(pluginName, request.user.username, request.headers?.origin, request.headers?.host),
expiresIn: 60,
};
}
async serveCustomUiIndex(request, reply, pluginName, ticket, version) {
let uiOrigin;
let assetSession;
try {
const claims = this.ticketService.consume(ticket, pluginName);
uiOrigin = claims.uiOrigin;
assetSession = this.ticketService.issueAssetSession(pluginName, claims.username, claims.uiOrigin);
}
catch {
const existing = this.ticketService.validateAssetSession(this.ticketService.extractAssetSession(request.headers?.cookie), pluginName);
uiOrigin = existing.uiOrigin;
assetSession = existing.token;
}
this.setAssetSessionCookie(request, reply, assetSession);
reply.header('Cache-Control', 'no-store, private');
reply.header('Pragma', 'no-cache');
reply.header('Referrer-Policy', 'no-referrer');
return await this.pluginSettingsUiService.serveCustomUiAsset(reply, pluginName, 'index.html', uiOrigin, version);
}
revokeAssetSession(request, reply, pluginName) {
this.ticketService.revokeUserPlugin(request.user.username, pluginName);
this.setAssetSessionCookie(request, reply, '', 0);
return { status: 'OK' };
}
async serveCustomUiAsset(request, reply, pluginName, file, v) {
if (!file || /(?:^|\/)index\.html$/i.test(file) || /\.(?:html?|xhtml)$/i.test(file)) {
throw new NotFoundException();
}
const isDevelopmentSourceMap = process.env.UIX_DEVELOPMENT === '1' && file.toLowerCase().endsWith('.map');
if (!isDevelopmentSourceMap) {
const session = this.ticketService.validateAssetSession(this.ticketService.extractAssetSession(request.headers?.cookie), pluginName);
this.setAssetSessionCookie(request, reply, session.token);
}
return await this.pluginSettingsUiService.serveCustomUiAsset(reply, pluginName, file, '', v);
}
setAssetSessionCookie(request, reply, token, maxAge = PluginsSettingsUiTicketService.assetSessionTtl) {
const cookiePath = `${API_PREFIX}/plugins/settings-ui/${encodeURIComponent(request.params.pluginName)}/`;
const secure = request.protocol === 'https' ? '; Secure' : '';
reply.header('Set-Cookie', `hb-plugin-ui=${token}; HttpOnly; SameSite=Strict; Path=${cookiePath}; Max-Age=${maxAge}${secure}`);
}
};
__decorate([
Post('/:pluginName/ticket'),
UseGuards(AuthGuard('jwt'), AdminGuard),
ApiBearerAuth(),
ApiOperation({ summary: 'Issues a single-use ticket for a plugin custom UI.' }),
__param(0, Req()),
__param(1, Param('pluginName')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, String]),
__metadata("design:returntype", Promise)
], PluginsSettingsUiController.prototype, "issueTicket", null);
__decorate([
Get('/:pluginName/index.html'),
ApiOperation({ summary: 'Redeems a single-use ticket and returns a plugin custom UI.' }),
__param(0, Req()),
__param(1, Res()),
__param(2, Param('pluginName')),
__param(3, Query('ticket')),
__param(4, Query('v')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object, String, String, String]),
__metadata("design:returntype", Promise)
], PluginsSettingsUiController.prototype, "serveCustomUiIndex", null);
__decorate([
Post('/:pluginName/session/revoke'),
UseGuards(AuthGuard('jwt'), AdminGuard),
ApiBearerAuth(),
ApiOperation({ summary: 'Revokes the active custom-UI asset session.' }),
__param(0, Req()),
__param(1, Res({ passthrough: true })),
__param(2, Param('pluginName')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object, String]),
__metadata("design:returntype", void 0)
], PluginsSettingsUiController.prototype, "revokeAssetSession", null);
__decorate([
Get('/:pluginName/*'),
ApiOperation({ summary: 'Returns a static asset for a plugin custom UI.' }),
ApiParam({ name: 'pluginName', type: 'string' }),
__param(0, Req()),
__param(1, Res()),
__param(2, Param('pluginName')),
__param(3, Param('*')),
__param(4, Query('v')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object, Object, Object, String]),
__metadata("design:returntype", Promise)
], PluginsSettingsUiController.prototype, "serveCustomUiAsset", null);
PluginsSettingsUiController = __decorate([
ApiTags('Plugins'),
Controller('plugins/settings-ui'),
__param(0, Inject(PluginsSettingsUiService)),
__param(1, Inject(PluginsSettingsUiTicketService)),
__metadata("design:paramtypes", [PluginsSettingsUiService,
PluginsSettingsUiTicketService])
], PluginsSettingsUiController);
export { PluginsSettingsUiController };
//# sourceMappingURL=plugins-settings-ui.controller.js.map