feat(05-03): calendar backend — model, crypto, source CRUD module
- Add CalendarSource Prisma model with encrypted credentials (AES-256-GCM) - Create CalendarCryptoService with encrypt/decrypt using CALENDAR_ENCRYPTION_KEY - Create CalendarController with source CRUD endpoints (GET/POST/PATCH/DELETE) - Create CalendarService with ownership checks and SSRF URL validation - Add DTOs with https-only URL validation and class-validator decorators - Register CalendarModule in AppModule - Install tsdav, node-ical, ews-javascript-api, @microsoft/microsoft-graph-client - Stub provider files for Task 2 compilation
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
import { IsDateString, IsOptional } from 'class-validator';
|
||||
|
||||
/**
|
||||
* DTO for querying aggregated calendar events.
|
||||
*
|
||||
* Default window: now to now + 30 days (applied in CalendarService).
|
||||
*/
|
||||
export class CalendarEventsQueryDto {
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
from?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
to?: string;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import {
|
||||
IsBoolean,
|
||||
IsHexColor,
|
||||
IsIn,
|
||||
IsNotEmpty,
|
||||
IsOptional,
|
||||
IsString,
|
||||
IsUrl,
|
||||
} from 'class-validator';
|
||||
|
||||
/**
|
||||
* DTO for creating a new calendar source.
|
||||
*
|
||||
* Security:
|
||||
* - T-05-11: URL restricted to https only (SSRF mitigation)
|
||||
* - T-05-10: password is plaintext in transit (over TLS), encrypted at rest by CryptoService
|
||||
*/
|
||||
export class CreateCalendarSourceDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
name!: string;
|
||||
|
||||
@IsIn(['caldav', 'ics', 'exchange'])
|
||||
type!: string;
|
||||
|
||||
@IsUrl(
|
||||
{ protocols: ['https'], require_protocol: true },
|
||||
{ message: 'URL must use HTTPS protocol' },
|
||||
)
|
||||
url!: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
username?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
password?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsIn(['ews', 'graph'])
|
||||
exchangeMode?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsHexColor()
|
||||
color?: string;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import {
|
||||
IsBoolean,
|
||||
IsHexColor,
|
||||
IsIn,
|
||||
IsNotEmpty,
|
||||
IsOptional,
|
||||
IsString,
|
||||
IsUrl,
|
||||
} from 'class-validator';
|
||||
|
||||
/**
|
||||
* DTO for updating an existing calendar source.
|
||||
* All fields are optional — only provided fields are updated.
|
||||
*
|
||||
* Security:
|
||||
* - T-05-11: URL restricted to https only if provided
|
||||
* - CAL-02: isVisible toggle for widget source visibility
|
||||
*/
|
||||
export class UpdateCalendarSourceDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
name?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsIn(['caldav', 'ics', 'exchange'])
|
||||
type?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsUrl(
|
||||
{ protocols: ['https'], require_protocol: true },
|
||||
{ message: 'URL must use HTTPS protocol' },
|
||||
)
|
||||
url?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
username?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
password?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsIn(['ews', 'graph'])
|
||||
exchangeMode?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsHexColor()
|
||||
color?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
isVisible?: boolean;
|
||||
}
|
||||
Reference in New Issue
Block a user