diff --git a/README.md b/README.md index 2367638..97a2691 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,11 @@ ### Other options -* Start without authorization: `docker run -p 8000:8000 -e DISABLE_AUTH=true -d ghcr.io/dyrector-io/darklens:latest` -* Select a stronger JWT secret: `docker run -p 8000:8000 -e JWT_SECRET=supersecret -d ghcr.io/dyrector-io/darklens:latest` -* Run on a public domain: `docker run -p 8000:8000 -e PUBLIC_URL=example.com AGENT_ADDRESS=example.com:5000 -d ghcr.io/dyrector-io/darklens:latest` +* Start without authorization: `docker run -p 8000:8000 -p 5000:5000 -e DISABLE_AUTH=true -d ghcr.io/dyrector-io/darklens:latest` +* Select a stronger JWT secret: `docker run -p 8000:8000 -p 5000:5000 -e JWT_SECRET=supersecret -d ghcr.io/dyrector-io/darklens:latest` +* Run on a public domain: `docker run -p 8000:8000 -p 5000:5000 -e PUBLIC_URL=example.com AGENT_ADDRESS=example.com:5000 -d ghcr.io/dyrector-io/darklens:latest` * Note: Agents require gRPC port 5000 to connect to the service -* Persist data: `docker run -p 8000:8000 -v darklens-data:/var/lib/darklens -d ghcr.io/dyrector-io/darklens:latest` +* Persist data: `docker run -p 8000:8000 -p 5000:5000 -v darklens-data:/var/lib/darklens -d ghcr.io/dyrector-io/darklens:latest` ## Development diff --git a/web/Dockerfile b/web/Dockerfile index eee2cce..87cdf12 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -31,7 +31,12 @@ FROM docker.io/library/node:20.5.0-alpine3.17 AS RUNNER ENV NODE_ENV production ENV TZ UTC + +# Defaults ENV DATABASE file:/var/lib/darklens/data.db +ENV JWT_SECRET super-secret +ENV AGENT_ADDRESS host.docker.internal:5000 +ENV PUBLIC_URL http://localhost:8000 RUN apk --update add tzdata openssl1.1-compat diff --git a/web/backend/src/app/auth/auth.http.controller.ts b/web/backend/src/app/auth/auth.http.controller.ts index aa785c3..3d1dcf9 100644 --- a/web/backend/src/app/auth/auth.http.controller.ts +++ b/web/backend/src/app/auth/auth.http.controller.ts @@ -34,8 +34,10 @@ export class AuthController { let token = null if (await this.userService.hasUsers()) { + console.log('A') token = await this.authService.signIn(signInDto.name, signInDto.password) } else { + console.log('B') token = await this.authService.register(signInDto.name, signInDto.password) } diff --git a/web/backend/src/app/node/node.http.controller.ts b/web/backend/src/app/node/node.http.controller.ts index 80fc71b..6c540f4 100644 --- a/web/backend/src/app/node/node.http.controller.ts +++ b/web/backend/src/app/node/node.http.controller.ts @@ -26,6 +26,7 @@ import { } from '@nestjs/swagger' import UuidParams from 'src/decorators/api-params.decorator' import { CreatedResponse, CreatedWithLocation } from '../../interceptors/created-with-location.decorator' +import { Public } from '../auth/auth.guard' import NodeTeamAccessGuard from './guards/node.team-access.http.guard' import { NodeId, PARAM_NODE_ID, ROUTE_NODES, ROUTE_NODE_ID } from './node.const' import { @@ -52,7 +53,7 @@ export default class NodeHttpController { @HttpCode(HttpStatus.OK) @ApiOperation({ description: - "Fetch data of deployment targets. Request must include `teamSlug` in URL. Response should include an array with the node's `type`, `status`, `description`, `icon`, `address`, `connectedAt` date, `version`, `id`, and `name`.", + "Fetch data of deployment targets. Response should include an array with the node's `type`, `status`, `description`, `icon`, `address`, `connectedAt` date, `version`, `id`, and `name`.", summary: 'Get data of nodes that belong to your team.', }) @ApiOkResponse({ @@ -69,7 +70,7 @@ export default class NodeHttpController { @HttpCode(HttpStatus.OK) @ApiOperation({ description: - "Fetch data of a specific node. Request must include `teamSlug` in URL, and `nodeId` in body. Response should include an array with the node's `type`, `status`, `description`, `icon`, `address`, `connectedAt` date, `version`, `updatable`, `id`, `name`, `hasToken`, and agent installation details.", + "Fetch data of a specific node. Request must include `nodeId` in body. Response should include an array with the node's `type`, `status`, `description`, `icon`, `address`, `connectedAt` date, `version`, `updatable`, `id`, `name`, `hasToken`, and agent installation details.", summary: 'Get data of nodes that belong to your team.', }) @ApiOkResponse({ type: NodeDetailsDto, description: 'Data of the node.' }) @@ -85,7 +86,7 @@ export default class NodeHttpController { @HttpCode(HttpStatus.CREATED) @ApiOperation({ description: - "Request must include the `teamSlug` in URL, and node's `name` in body. Response should include an array with the node's `type`, `status`, `description`, `icon`, `address`, `connectedAt` date, `version`, `id`, and `name`.", + "Request must include the node's `name` in body. Response should include an array with the node's `type`, `status`, `description`, `icon`, `address`, `connectedAt` date, `version`, `id`, and `name`.", summary: 'Create new node.', }) @CreatedWithLocation() @@ -106,8 +107,7 @@ export default class NodeHttpController { @Put(ROUTE_NODE_ID) @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ - description: - "Request must include the `teamSlug` in URL, and node's `name` in body, body can include `description` and `icon`.", + description: "Request must include the node's `name` in body, body can include `description` and `icon`.", summary: 'Update details of a node.', }) @ApiNoContentResponse({ description: 'Node details modified.' }) @@ -123,7 +123,7 @@ export default class NodeHttpController { @Delete(ROUTE_NODE_ID) @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ - description: "Request must include the `teamSlug` in URL, and node's `name` in body.", + description: "Request must include the node's `name` in body.", summary: 'Delete node.', }) @ApiNoContentResponse({ description: 'Node deleted.' }) @@ -137,7 +137,7 @@ export default class NodeHttpController { @Post(`${ROUTE_NODE_ID}/script`) @HttpCode(HttpStatus.CREATED) @ApiOperation({ - description: 'Request must include `teamSlug` in URL and `nodeId`, `type`, and `scriptType`.', + description: 'Request must include `nodeId`, `type`, and `scriptType` in URL.', summary: 'Create agent install script.', }) @ApiOkResponse({ type: NodeInstallDto, description: 'Install script generated.' }) @@ -154,7 +154,7 @@ export default class NodeHttpController { @Delete(`${ROUTE_NODE_ID}/script`) @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ - description: "Request must include the `teamSlug` in URL, and node's `name` in body.", + description: "Request must include the node's `name` in body.", summary: 'Delete node set up install script.', }) @ApiNoContentResponse({ description: 'Agent install script deleted.' }) @@ -164,12 +164,13 @@ export default class NodeHttpController { return await this.service.discardScript(nodeId) } + @Public() @Get(`${ROUTE_NODE_ID}/script`) @ApiOkResponse({ type: String }) @ApiProduces('text/plain') @ApiOperation({ description: - "Request must include the `teamSlug` in URL, and node's `name` in body. Response should include `type`, `status`, `description`, `icon`, `address`, `connectedAt` date, `version`, `updatable`, `id`, `name`, `hasToken`, and `install` details.", + "Request must include the node's `name` in body. Response should include `type`, `status`, `description`, `icon`, `address`, `connectedAt` date, `version`, `updatable`, `id`, `name`, `hasToken`, and `install` details.", summary: 'Fetch install script.', }) @ApiOkResponse({ type: NodeDetailsDto, description: 'Install script.' }) @@ -185,7 +186,7 @@ export default class NodeHttpController { @Delete(`${ROUTE_NODE_ID}/token`) @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ - description: "Request must include the `teamSlug` in URL, and node's `name` in body.", + description: "Request must include the node's `name` in body.", summary: "Revoke the node's access token.", }) @ApiNoContentResponse({ description: 'Token revoked.' }) @@ -199,7 +200,7 @@ export default class NodeHttpController { @Post(`${ROUTE_NODE_ID}/update`) @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ - description: "Request must include the `teamSlug` in URL, and node's `name` in body.", + description: "Request must include the node's `name` in body.", summary: 'Update the agent.', }) @ApiNoContentResponse({ description: 'Node details modified.' }) @@ -214,7 +215,7 @@ export default class NodeHttpController { @HttpCode(HttpStatus.OK) @ApiOperation({ description: - 'Request must include `teamSlug` in URL, and its body must include `skip`, `take`, and dates of `from` and `to`. Response should include an array of `items`: `createdAt` date, `event`, and `data`.', + 'Request must include `skip`, `take`, and dates of `from` and `to` in the body. Response should include an array of `items`: `createdAt` date, `event`, and `data`.', summary: 'Fetch audit log.', }) @ApiOkResponse({ type: NodeAuditLogListDto, description: 'Paginated list of the audit log.' }) diff --git a/web/backend/src/decorators/audit-logger.decorator.ts b/web/backend/src/decorators/audit-logger.decorator.ts index d1ccb66..4b2a457 100644 --- a/web/backend/src/decorators/audit-logger.decorator.ts +++ b/web/backend/src/decorators/audit-logger.decorator.ts @@ -1,6 +1,4 @@ -import { ExecutionContext, SetMetadata } from '@nestjs/common' -import { Reflector } from '@nestjs/core' -import { subscriptionOfContext } from 'src/websockets/decorators/ws.subscription.decorator' +import { SetMetadata } from '@nestjs/common' export const AUDIT_LOGGER_LEVEL = 'audit-logger-level' export type AuditLogLevelOptions = 'disabled' | 'no-data' | 'all' @@ -12,25 +10,3 @@ export type AuditLogLevelOptions = 'disabled' | 'no-data' | 'all' * @returns CustomDecorator */ export const AuditLogLevel = (level: AuditLogLevelOptions) => SetMetadata(AUDIT_LOGGER_LEVEL, level) - -export const AUDIT_LOGGER_TEAM_SLUG_PROVIDER = 'audit-logger-team-slug-provider' -export type AuditLogTeamSlugProvider = (context: ExecutionContext) => string - -export const teamSlugProviderOfContext = (context: ExecutionContext, reflector: Reflector) => - reflector.get(AUDIT_LOGGER_TEAM_SLUG_PROVIDER, context.getHandler()) - -/** - * AuditLogTeamSlug decorator to set a method of extracting - * the team slug from an ExecutionContext - * - * @param level - * @returns CustomDecorator - */ -export const AuditLogTeamSlug = (provider: AuditLogTeamSlugProvider) => - SetMetadata(AUDIT_LOGGER_TEAM_SLUG_PROVIDER, provider) - -export const teamSlugFromHttpRequestParams: AuditLogTeamSlugProvider = (context: ExecutionContext) => - context.switchToHttp().getRequest().params.teamSlug as string - -export const teamSlugFromWsContext: AuditLogTeamSlugProvider = (context: ExecutionContext) => - subscriptionOfContext(context).getParameter('teamSlug')