mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-23 12:06:42 +02:00
🔒️ feat(auth): centralize JWT validation and add deployment docs
- Migrate Chat, Picture, Presi, Zitare backends to shared auth guards - Remove duplicate local JWT guards and decorators - Add CD staging workflow for tagged releases - Add comprehensive auth architecture documentation - Add Hetzner deployment and Docker setup guides - Add environment configuration audit docs - Update env generation scripts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
942c588e15
commit
5b0b3095ff
50 changed files with 11916 additions and 718 deletions
|
|
@ -2,8 +2,7 @@ import { Body, Controller, Get, Post, UseGuards } from '@nestjs/common';
|
|||
import { isOk } from '@manacore/shared-errors';
|
||||
import { ChatService } from './chat.service';
|
||||
import { ChatCompletionDto, ChatCompletionResponseDto } from './dto/chat-completion.dto';
|
||||
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
||||
import { CurrentUser, CurrentUserData } from '../common/decorators/current-user.decorator';
|
||||
import { JwtAuthGuard, CurrentUser, CurrentUserData } from '@manacore/shared-nestjs-auth';
|
||||
|
||||
@Controller('chat')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||
|
||||
export interface CurrentUserData {
|
||||
userId: string;
|
||||
email: string;
|
||||
role: string;
|
||||
sessionId?: string;
|
||||
}
|
||||
|
||||
export const CurrentUser = createParamDecorator(
|
||||
(data: unknown, ctx: ExecutionContext): CurrentUserData => {
|
||||
const request = ctx.switchToHttp().getRequest();
|
||||
return request.user;
|
||||
}
|
||||
);
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
// Development test user ID - used when DEV_BYPASS_AUTH=true
|
||||
const DEV_USER_ID = '17cb0be7-058a-4964-9e18-1fe7055fd014';
|
||||
|
||||
@Injectable()
|
||||
export class JwtAuthGuard implements CanActivate {
|
||||
constructor(private configService: ConfigService) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const request = context.switchToHttp().getRequest();
|
||||
|
||||
// Development mode: bypass auth if DEV_BYPASS_AUTH is set
|
||||
const isDev = this.configService.get<string>('NODE_ENV') === 'development';
|
||||
const bypassAuth = this.configService.get<string>('DEV_BYPASS_AUTH') === 'true';
|
||||
|
||||
if (isDev && bypassAuth) {
|
||||
// Use test user for development
|
||||
request.user = {
|
||||
userId: DEV_USER_ID,
|
||||
email: 'test@example.com',
|
||||
role: 'user',
|
||||
sessionId: 'dev-session',
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
const token = this.extractTokenFromHeader(request);
|
||||
|
||||
if (!token) {
|
||||
throw new UnauthorizedException('No token provided');
|
||||
}
|
||||
|
||||
try {
|
||||
// Get Mana Core Auth URL from config
|
||||
const authUrl =
|
||||
this.configService.get<string>('MANA_CORE_AUTH_URL') || 'http://localhost:3001';
|
||||
|
||||
// Validate token with Mana Core Auth
|
||||
const response = await fetch(`${authUrl}/api/v1/auth/validate`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ token }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new UnauthorizedException('Invalid token');
|
||||
}
|
||||
|
||||
const { valid, payload } = await response.json();
|
||||
|
||||
if (!valid || !payload) {
|
||||
throw new UnauthorizedException('Invalid token');
|
||||
}
|
||||
|
||||
// Attach user to request
|
||||
request.user = {
|
||||
userId: payload.sub,
|
||||
email: payload.email,
|
||||
role: payload.role,
|
||||
sessionId: payload.sessionId,
|
||||
};
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (error instanceof UnauthorizedException) {
|
||||
throw error;
|
||||
}
|
||||
console.error('Error validating token:', error);
|
||||
throw new UnauthorizedException('Token validation failed');
|
||||
}
|
||||
}
|
||||
|
||||
private extractTokenFromHeader(request: any): string | undefined {
|
||||
const [type, token] = request.headers.authorization?.split(' ') ?? [];
|
||||
return type === 'Bearer' ? token : undefined;
|
||||
}
|
||||
}
|
||||
|
|
@ -13,8 +13,7 @@ import { isOk } from '@manacore/shared-errors';
|
|||
import { ConversationService } from './conversation.service';
|
||||
import { type Conversation } from '../db/schema/conversations.schema';
|
||||
import { type Message } from '../db/schema/messages.schema';
|
||||
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
||||
import { CurrentUser, CurrentUserData } from '../common/decorators/current-user.decorator';
|
||||
import { JwtAuthGuard, CurrentUser, CurrentUserData } from '@manacore/shared-nestjs-auth';
|
||||
|
||||
@Controller('conversations')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ import { Body, Controller, Delete, Get, Param, Post, UseGuards } from '@nestjs/c
|
|||
import { isOk } from '@manacore/shared-errors';
|
||||
import { DocumentService } from './document.service';
|
||||
import { type Document } from '../db/schema/documents.schema';
|
||||
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
||||
import { CurrentUser, CurrentUserData } from '../common/decorators/current-user.decorator';
|
||||
import { JwtAuthGuard, CurrentUser, CurrentUserData } from '@manacore/shared-nestjs-auth';
|
||||
|
||||
@Controller('documents')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
|
|
|
|||
|
|
@ -6,16 +6,18 @@ async function bootstrap() {
|
|||
const app = await NestFactory.create(AppModule);
|
||||
|
||||
// Enable CORS for mobile and web apps
|
||||
const corsOrigins = process.env.CORS_ORIGINS?.split(',').map((origin) => origin.trim()) || [
|
||||
'http://localhost:3000',
|
||||
'http://localhost:5173',
|
||||
'http://localhost:5174',
|
||||
'http://localhost:5178',
|
||||
'http://localhost:8081',
|
||||
'exp://localhost:8081',
|
||||
'http://localhost:3001',
|
||||
];
|
||||
|
||||
app.enableCors({
|
||||
origin: [
|
||||
'http://localhost:3000',
|
||||
'http://localhost:5173',
|
||||
'http://localhost:5174', // Chat web app (dev server port)
|
||||
'http://localhost:5178', // Chat web app (alternative)
|
||||
'http://localhost:8081',
|
||||
'exp://localhost:8081',
|
||||
'http://localhost:3001', // Mana Core Auth
|
||||
],
|
||||
origin: corsOrigins,
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
});
|
||||
|
|
@ -33,7 +35,7 @@ async function bootstrap() {
|
|||
);
|
||||
|
||||
// Set global prefix for API routes
|
||||
app.setGlobalPrefix('api');
|
||||
app.setGlobalPrefix('api/v1');
|
||||
|
||||
const port = process.env.PORT || 3002;
|
||||
await app.listen(port);
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ import { Body, Controller, Delete, Get, Param, Patch, Post, UseGuards } from '@n
|
|||
import { isOk } from '@manacore/shared-errors';
|
||||
import { SpaceService } from './space.service';
|
||||
import { type Space, type SpaceMember } from '../db/schema/spaces.schema';
|
||||
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
||||
import { CurrentUser, CurrentUserData } from '../common/decorators/current-user.decorator';
|
||||
import { JwtAuthGuard, CurrentUser, CurrentUserData } from '@manacore/shared-nestjs-auth';
|
||||
|
||||
@Controller('spaces')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ import { Body, Controller, Delete, Get, Param, Patch, Post, UseGuards } from '@n
|
|||
import { isOk } from '@manacore/shared-errors';
|
||||
import { TemplateService } from './template.service';
|
||||
import { type Template } from '../db/schema/templates.schema';
|
||||
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
||||
import { CurrentUser, CurrentUserData } from '../common/decorators/current-user.decorator';
|
||||
import { JwtAuthGuard, CurrentUser, CurrentUserData } from '@manacore/shared-nestjs-auth';
|
||||
|
||||
@Controller('templates')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ async function bootstrap() {
|
|||
});
|
||||
|
||||
// Global prefix
|
||||
app.setGlobalPrefix('v1', {
|
||||
app.setGlobalPrefix('api/v1', {
|
||||
exclude: ['health', 'health/ready', 'health/live'],
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { Controller, Get, Post, Delete, Param, Query, Body, UseGuards } from '@nestjs/common';
|
||||
import { BatchService } from './batch.service';
|
||||
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
||||
import { CurrentUser, CurrentUserData } from '../common/decorators/current-user.decorator';
|
||||
import { JwtAuthGuard, CurrentUser, CurrentUserData } from '@manacore/shared-nestjs-auth';
|
||||
import { CreateBatchDto, GetBatchQueryDto } from './dto/batch.dto';
|
||||
|
||||
@Controller('batch')
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { Controller, Get, Post, Patch, Delete, Param, Body, UseGuards } from '@nestjs/common';
|
||||
import { BoardItemService } from './board-item.service';
|
||||
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
||||
import { CurrentUser, CurrentUserData } from '../common/decorators/current-user.decorator';
|
||||
import { JwtAuthGuard, CurrentUser, CurrentUserData } from '@manacore/shared-nestjs-auth';
|
||||
import {
|
||||
AddImageToBoardDto,
|
||||
AddTextToBoardDto,
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@ import {
|
|||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { BoardService } from './board.service';
|
||||
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
||||
import { CurrentUser, CurrentUserData } from '../common/decorators/current-user.decorator';
|
||||
import { JwtAuthGuard, CurrentUser, CurrentUserData } from '@manacore/shared-nestjs-auth';
|
||||
import {
|
||||
CreateBoardDto,
|
||||
UpdateBoardDto,
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||
|
||||
export interface CurrentUserData {
|
||||
userId: string;
|
||||
email: string;
|
||||
role: string;
|
||||
sessionId?: string;
|
||||
}
|
||||
|
||||
export const CurrentUser = createParamDecorator(
|
||||
(data: unknown, ctx: ExecutionContext): CurrentUserData => {
|
||||
const request = ctx.switchToHttp().getRequest();
|
||||
return request.user;
|
||||
}
|
||||
);
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
@Injectable()
|
||||
export class JwtAuthGuard implements CanActivate {
|
||||
constructor(private configService: ConfigService) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const request = context.switchToHttp().getRequest();
|
||||
const token = this.extractTokenFromHeader(request);
|
||||
|
||||
if (!token) {
|
||||
throw new UnauthorizedException('No token provided');
|
||||
}
|
||||
|
||||
try {
|
||||
// Get Mana Core Auth URL from config
|
||||
const authUrl =
|
||||
this.configService.get<string>('MANA_CORE_AUTH_URL') || 'http://localhost:3001';
|
||||
|
||||
// Validate token with Mana Core Auth
|
||||
const response = await fetch(`${authUrl}/api/v1/auth/validate`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ token }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new UnauthorizedException('Invalid token');
|
||||
}
|
||||
|
||||
const { valid, payload } = await response.json();
|
||||
|
||||
if (!valid || !payload) {
|
||||
throw new UnauthorizedException('Invalid token');
|
||||
}
|
||||
|
||||
// Attach user to request
|
||||
request.user = {
|
||||
userId: payload.sub,
|
||||
email: payload.email,
|
||||
role: payload.role,
|
||||
sessionId: payload.sessionId,
|
||||
};
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (error instanceof UnauthorizedException) {
|
||||
throw error;
|
||||
}
|
||||
console.error('Error validating token:', error);
|
||||
throw new UnauthorizedException('Token validation failed');
|
||||
}
|
||||
}
|
||||
|
||||
private extractTokenFromHeader(request: any): string | undefined {
|
||||
const [type, token] = request.headers.authorization?.split(' ') ?? [];
|
||||
return type === 'Bearer' ? token : undefined;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { Controller, Get, Query, UseGuards } from '@nestjs/common';
|
||||
import { ExploreService } from './explore.service';
|
||||
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
||||
import { JwtAuthGuard } from '@manacore/shared-nestjs-auth';
|
||||
import { GetPublicImagesDto, SearchPublicImagesDto } from './dto/explore.dto';
|
||||
|
||||
@Controller('explore')
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { Controller, Get, Post, Delete, Param, Body, UseGuards } from '@nestjs/common';
|
||||
import { GenerateService } from './generate.service';
|
||||
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
||||
import { CurrentUser, CurrentUserData } from '../common/decorators/current-user.decorator';
|
||||
import { JwtAuthGuard, CurrentUser, CurrentUserData } from '@manacore/shared-nestjs-auth';
|
||||
import { GenerateImageDto } from './dto/generate.dto';
|
||||
|
||||
@Controller('generate')
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@ import {
|
|||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { ImageService } from './image.service';
|
||||
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
||||
import { CurrentUser, CurrentUserData } from '../common/decorators/current-user.decorator';
|
||||
import { JwtAuthGuard, CurrentUser, CurrentUserData } from '@manacore/shared-nestjs-auth';
|
||||
import { GetImagesQueryDto, ToggleFavoriteDto, BatchImageIdsDto } from './dto/image.dto';
|
||||
|
||||
@Controller('images')
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ async function bootstrap() {
|
|||
const app = await NestFactory.create<NestExpressApplication>(AppModule);
|
||||
|
||||
// Enable CORS for mobile and web apps
|
||||
const allowedOrigins = [
|
||||
const allowedOrigins = process.env.CORS_ORIGINS?.split(',').map((origin) => origin.trim()) || [
|
||||
'http://localhost:3000',
|
||||
'http://localhost:5173',
|
||||
'http://localhost:5174',
|
||||
'http://localhost:5175',
|
||||
'http://localhost:8081',
|
||||
'exp://localhost:8081',
|
||||
'http://localhost:3001', // Mana Core Auth
|
||||
'http://localhost:3001',
|
||||
];
|
||||
|
||||
app.enableCors({
|
||||
|
|
@ -47,9 +47,9 @@ async function bootstrap() {
|
|||
});
|
||||
|
||||
// Set global prefix for API routes
|
||||
app.setGlobalPrefix('api');
|
||||
app.setGlobalPrefix('api/v1');
|
||||
|
||||
const port = process.env.PORT || 3003;
|
||||
const port = process.env.PORT || 3006;
|
||||
await app.listen(port);
|
||||
console.log(`Picture backend running on http://localhost:${port}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { Controller, Get, Patch, Body, UseGuards } from '@nestjs/common';
|
||||
import { ProfileService } from './profile.service';
|
||||
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
||||
import { CurrentUser, CurrentUserData } from '../common/decorators/current-user.decorator';
|
||||
import { JwtAuthGuard, CurrentUser, CurrentUserData } from '@manacore/shared-nestjs-auth';
|
||||
import { UpdateProfileDto, ProfileResponse, UserStatsResponse, RateLimitsResponse } from './dto/profile.dto';
|
||||
|
||||
@Controller('profiles')
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Controller, Get, Post, Patch, Delete, Param, Body, UseGuards } from '@nestjs/common';
|
||||
import { TagService } from './tag.service';
|
||||
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
||||
import { JwtAuthGuard } from '@manacore/shared-nestjs-auth';
|
||||
import { CreateTagDto, UpdateTagDto } from './dto/tag.dto';
|
||||
|
||||
@Controller('tags')
|
||||
|
|
|
|||
|
|
@ -11,8 +11,7 @@ import {
|
|||
} from '@nestjs/common';
|
||||
import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
|
||||
import { UploadService } from './upload.service';
|
||||
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
||||
import { CurrentUser, CurrentUserData } from '../common/decorators/current-user.decorator';
|
||||
import { JwtAuthGuard, CurrentUser, CurrentUserData } from '@manacore/shared-nestjs-auth';
|
||||
|
||||
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
|
||||
const ALLOWED_MIME_TYPES = ['image/jpeg', 'image/png', 'image/webp'];
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
"db:seed": "tsx src/db/seed.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@manacore/shared-nestjs-auth": "workspace:*",
|
||||
"@nestjs/common": "^10.4.15",
|
||||
"@nestjs/config": "^3.3.0",
|
||||
"@nestjs/core": "^10.4.15",
|
||||
|
|
|
|||
|
|
@ -1,84 +0,0 @@
|
|||
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
/**
|
||||
* JWT Auth Guard - Validates tokens via Mana Core Auth service
|
||||
*
|
||||
* Uses Better Auth with EdDSA algorithm (not RS256).
|
||||
* Validates tokens by calling the central auth service's /validate endpoint.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AuthGuard implements CanActivate {
|
||||
constructor(private configService: ConfigService) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const request = context.switchToHttp().getRequest();
|
||||
|
||||
// Development mode: bypass auth if DEV_BYPASS_AUTH is set
|
||||
const isDev = this.configService.get<string>('NODE_ENV') === 'development';
|
||||
const bypassAuth = this.configService.get<string>('DEV_BYPASS_AUTH') === 'true';
|
||||
|
||||
if (isDev && bypassAuth) {
|
||||
request.user = {
|
||||
sub: '00000000-0000-0000-0000-000000000000',
|
||||
email: 'dev@example.com',
|
||||
role: 'user',
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
const token = this.extractTokenFromHeader(request);
|
||||
|
||||
if (!token) {
|
||||
throw new UnauthorizedException('No token provided');
|
||||
}
|
||||
|
||||
try {
|
||||
// Get Mana Core Auth URL from config
|
||||
const authUrl =
|
||||
this.configService.get<string>('MANA_CORE_AUTH_URL') || 'http://localhost:3001';
|
||||
|
||||
// Validate token with Mana Core Auth
|
||||
const response = await fetch(`${authUrl}/api/v1/auth/validate`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ token }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new UnauthorizedException('Invalid token');
|
||||
}
|
||||
|
||||
const { valid, payload } = await response.json();
|
||||
|
||||
if (!valid || !payload) {
|
||||
throw new UnauthorizedException('Invalid token');
|
||||
}
|
||||
|
||||
// Attach user to request
|
||||
request.user = {
|
||||
sub: payload.sub,
|
||||
email: payload.email,
|
||||
role: payload.role,
|
||||
sessionId: payload.sessionId || payload.sid,
|
||||
};
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (error instanceof UnauthorizedException) {
|
||||
throw error;
|
||||
}
|
||||
console.error('[AuthGuard] Error validating token:', error);
|
||||
throw new UnauthorizedException('Token validation failed');
|
||||
}
|
||||
}
|
||||
|
||||
private extractTokenFromHeader(request: any): string | undefined {
|
||||
const authHeader = request.headers.authorization;
|
||||
if (!authHeader) {
|
||||
return undefined;
|
||||
}
|
||||
const [type, token] = authHeader.split(' ');
|
||||
return type === 'Bearer' ? token : undefined;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,43 +7,42 @@ import {
|
|||
Body,
|
||||
Param,
|
||||
UseGuards,
|
||||
Request,
|
||||
} from '@nestjs/common';
|
||||
import { DeckService } from './deck.service';
|
||||
import { CreateDeckDto, UpdateDeckDto } from './deck.dto';
|
||||
import { AuthGuard } from '../auth/auth.guard';
|
||||
import { JwtAuthGuard, CurrentUser, CurrentUserData } from '@manacore/shared-nestjs-auth';
|
||||
|
||||
@Controller('decks')
|
||||
@UseGuards(AuthGuard)
|
||||
@UseGuards(JwtAuthGuard)
|
||||
export class DeckController {
|
||||
constructor(private readonly deckService: DeckService) {}
|
||||
|
||||
@Get()
|
||||
async findAll(@Request() req: { user: { sub: string } }) {
|
||||
return this.deckService.findByUser(req.user.sub);
|
||||
async findAll(@CurrentUser() user: CurrentUserData) {
|
||||
return this.deckService.findByUser(user.userId);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
async findOne(@Param('id') id: string, @Request() req: { user: { sub: string } }) {
|
||||
return this.deckService.findOneWithSlides(id, req.user.sub);
|
||||
async findOne(@Param('id') id: string, @CurrentUser() user: CurrentUserData) {
|
||||
return this.deckService.findOneWithSlides(id, user.userId);
|
||||
}
|
||||
|
||||
@Post()
|
||||
async create(@Body() createDeckDto: CreateDeckDto, @Request() req: { user: { sub: string } }) {
|
||||
return this.deckService.create(req.user.sub, createDeckDto);
|
||||
async create(@Body() createDeckDto: CreateDeckDto, @CurrentUser() user: CurrentUserData) {
|
||||
return this.deckService.create(user.userId, createDeckDto);
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
async update(
|
||||
@Param('id') id: string,
|
||||
@Body() updateDeckDto: UpdateDeckDto,
|
||||
@Request() req: { user: { sub: string } }
|
||||
@CurrentUser() user: CurrentUserData
|
||||
) {
|
||||
return this.deckService.update(id, req.user.sub, updateDeckDto);
|
||||
return this.deckService.update(id, user.userId, updateDeckDto);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
async remove(@Param('id') id: string, @Request() req: { user: { sub: string } }) {
|
||||
return this.deckService.remove(id, req.user.sub);
|
||||
async remove(@Param('id') id: string, @CurrentUser() user: CurrentUserData) {
|
||||
return this.deckService.remove(id, user.userId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,16 +6,18 @@ async function bootstrap() {
|
|||
const app = await NestFactory.create(AppModule);
|
||||
|
||||
// Enable CORS for mobile and web apps
|
||||
const corsOrigins = process.env.CORS_ORIGINS?.split(',').map((origin) => origin.trim()) || [
|
||||
'http://localhost:3000',
|
||||
'http://localhost:5173',
|
||||
'http://localhost:5177',
|
||||
'http://localhost:5178',
|
||||
'http://localhost:8081',
|
||||
'exp://localhost:8081',
|
||||
'http://localhost:3001',
|
||||
];
|
||||
|
||||
app.enableCors({
|
||||
origin: [
|
||||
'http://localhost:3000',
|
||||
'http://localhost:5173',
|
||||
'http://localhost:5177',
|
||||
'http://localhost:5178', // Presi web app
|
||||
'http://localhost:8081',
|
||||
'exp://localhost:8081',
|
||||
'http://localhost:3001', // Mana Core Auth
|
||||
],
|
||||
origin: corsOrigins,
|
||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
});
|
||||
|
|
@ -30,7 +32,7 @@ async function bootstrap() {
|
|||
);
|
||||
|
||||
// Set global prefix for API routes
|
||||
app.setGlobalPrefix('api');
|
||||
app.setGlobalPrefix('api/v1');
|
||||
|
||||
const port = process.env.PORT || 3008;
|
||||
await app.listen(port);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Controller, Get, Post, Delete, Body, Param, UseGuards, Request } from '@nestjs/common';
|
||||
import { Controller, Get, Post, Delete, Body, Param, UseGuards } from '@nestjs/common';
|
||||
import { ShareService } from './share.service';
|
||||
import { CreateShareDto } from './share.dto';
|
||||
import { AuthGuard } from '../auth/auth.guard';
|
||||
import { JwtAuthGuard, CurrentUser, CurrentUserData } from '@manacore/shared-nestjs-auth';
|
||||
|
||||
@Controller('share')
|
||||
export class ShareController {
|
||||
|
|
@ -15,28 +15,28 @@ export class ShareController {
|
|||
|
||||
// Authenticated endpoints
|
||||
@Post('deck/:deckId')
|
||||
@UseGuards(AuthGuard)
|
||||
@UseGuards(JwtAuthGuard)
|
||||
async createShare(
|
||||
@Param('deckId') deckId: string,
|
||||
@Body() createShareDto: CreateShareDto,
|
||||
@Request() req: { user: { sub: string } }
|
||||
@CurrentUser() user: CurrentUserData
|
||||
) {
|
||||
const expiresAt = createShareDto.expiresAt ? new Date(createShareDto.expiresAt) : undefined;
|
||||
return this.shareService.createShare(deckId, req.user.sub, expiresAt);
|
||||
return this.shareService.createShare(deckId, user.userId, expiresAt);
|
||||
}
|
||||
|
||||
@Get('deck/:deckId/links')
|
||||
@UseGuards(AuthGuard)
|
||||
@UseGuards(JwtAuthGuard)
|
||||
async getSharesForDeck(
|
||||
@Param('deckId') deckId: string,
|
||||
@Request() req: { user: { sub: string } }
|
||||
@CurrentUser() user: CurrentUserData
|
||||
) {
|
||||
return this.shareService.getSharesForDeck(deckId, req.user.sub);
|
||||
return this.shareService.getSharesForDeck(deckId, user.userId);
|
||||
}
|
||||
|
||||
@Delete(':shareId')
|
||||
@UseGuards(AuthGuard)
|
||||
async deleteShare(@Param('shareId') shareId: string, @Request() req: { user: { sub: string } }) {
|
||||
return this.shareService.deleteShare(shareId, req.user.sub);
|
||||
@UseGuards(JwtAuthGuard)
|
||||
async deleteShare(@Param('shareId') shareId: string, @CurrentUser() user: CurrentUserData) {
|
||||
return this.shareService.deleteShare(shareId, user.userId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { Controller, Post, Put, Delete, Body, Param, UseGuards, Request } from '@nestjs/common';
|
||||
import { Controller, Post, Put, Delete, Body, Param, UseGuards } from '@nestjs/common';
|
||||
import { SlideService } from './slide.service';
|
||||
import { CreateSlideDto, UpdateSlideDto, ReorderSlidesDto } from './slide.dto';
|
||||
import { AuthGuard } from '../auth/auth.guard';
|
||||
import { JwtAuthGuard, CurrentUser, CurrentUserData } from '@manacore/shared-nestjs-auth';
|
||||
|
||||
@Controller()
|
||||
@UseGuards(AuthGuard)
|
||||
@UseGuards(JwtAuthGuard)
|
||||
export class SlideController {
|
||||
constructor(private readonly slideService: SlideService) {}
|
||||
|
||||
|
|
@ -12,27 +12,27 @@ export class SlideController {
|
|||
async create(
|
||||
@Param('deckId') deckId: string,
|
||||
@Body() createSlideDto: CreateSlideDto,
|
||||
@Request() req: { user: { sub: string } }
|
||||
@CurrentUser() user: CurrentUserData
|
||||
) {
|
||||
return this.slideService.create(deckId, req.user.sub, createSlideDto);
|
||||
return this.slideService.create(deckId, user.userId, createSlideDto);
|
||||
}
|
||||
|
||||
@Put('slides/:id')
|
||||
async update(
|
||||
@Param('id') id: string,
|
||||
@Body() updateSlideDto: UpdateSlideDto,
|
||||
@Request() req: { user: { sub: string } }
|
||||
@CurrentUser() user: CurrentUserData
|
||||
) {
|
||||
return this.slideService.update(id, req.user.sub, updateSlideDto);
|
||||
return this.slideService.update(id, user.userId, updateSlideDto);
|
||||
}
|
||||
|
||||
@Delete('slides/:id')
|
||||
async remove(@Param('id') id: string, @Request() req: { user: { sub: string } }) {
|
||||
return this.slideService.remove(id, req.user.sub);
|
||||
async remove(@Param('id') id: string, @CurrentUser() user: CurrentUserData) {
|
||||
return this.slideService.remove(id, user.userId);
|
||||
}
|
||||
|
||||
@Put('slides/reorder')
|
||||
async reorder(@Body() reorderDto: ReorderSlidesDto, @Request() req: { user: { sub: string } }) {
|
||||
return this.slideService.reorder(req.user.sub, reorderDto);
|
||||
async reorder(@Body() reorderDto: ReorderSlidesDto, @CurrentUser() user: CurrentUserData) {
|
||||
return this.slideService.reorder(user.userId, reorderDto);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,15 +6,17 @@ async function bootstrap() {
|
|||
const app = await NestFactory.create(AppModule);
|
||||
|
||||
// Enable CORS for mobile and web apps
|
||||
const corsOrigins = process.env.CORS_ORIGINS?.split(',').map((origin) => origin.trim()) || [
|
||||
'http://localhost:3000',
|
||||
'http://localhost:5173',
|
||||
'http://localhost:5177',
|
||||
'http://localhost:8081',
|
||||
'exp://localhost:8081',
|
||||
'http://localhost:3001',
|
||||
];
|
||||
|
||||
app.enableCors({
|
||||
origin: [
|
||||
'http://localhost:3000',
|
||||
'http://localhost:5173',
|
||||
'http://localhost:5177',
|
||||
'http://localhost:8081',
|
||||
'exp://localhost:8081',
|
||||
'http://localhost:3001', // Mana Core Auth
|
||||
],
|
||||
origin: corsOrigins,
|
||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
});
|
||||
|
|
@ -29,7 +31,7 @@ async function bootstrap() {
|
|||
);
|
||||
|
||||
// Set global prefix for API routes
|
||||
app.setGlobalPrefix('api');
|
||||
app.setGlobalPrefix('api/v1');
|
||||
|
||||
const port = process.env.PORT || 3007;
|
||||
await app.listen(port);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue