Skip to content

Commit

Permalink
Merge pull request #489 from boostcampwm2023/develop
Browse files Browse the repository at this point in the history
[release] v1.0.1 배포
  • Loading branch information
ccxz84 authored Dec 14, 2023
2 parents 6391faa + ed7dfda commit 0614ee0
Show file tree
Hide file tree
Showing 154 changed files with 3,791 additions and 1,094 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/app/backend/ @ldhbenecia @ccxz84
/app/frontend/ @ttaerrim @LEEJW1953 @js43o
/packages/morak-ui @ttaerrim @LEEJW1953 @js43o
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ lerna-debug.log*

# turbo
.turbo

# testing
**/coverage
113 changes: 80 additions & 33 deletions README.md

Large diffs are not rendered by default.

18 changes: 11 additions & 7 deletions app/backend/.sample.env → app/backend/.sample.dev.env
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
PORT=
DOMAIN=
SOCKET_PORT=
GOOGLE_CLIENT_ID=
GOOGLE_SECRET=
GOOGLE_CALLBACK_URL=
DATABASE_URL=
JWT_ACCESS_SECRET=
JWT_REFRESH_SECRET=
DOMAIN=
REDIS_PORT=
REDIS_HOST=
REDIS_MAX_AGE_REFRESH_TOKEN=
MAX_AGE_ACCESS_TOKEN=
MAX_AGE_REFRESH_TOKEN=
VAULT_ADDR=
VAULT_TOKEN=
VAULT_SECRET_URL=
DB_PORT=
DB_PASSWORD=
DB_USER=
DB_DATABASE_NAME=
DB_DATABASE_NAME=
DB_PORT=
DB_ROOT_PASSWORD=
MONGO_HOST=
MONGO_PORT=
MONGO_CHAT_DB=
CHAT_USER=
CHAT_PASSWORD=
DATABASE_URL=
2 changes: 1 addition & 1 deletion app/backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,4 @@ RUN chmod +x /docker-entrypoint.sh
RUN sed -i 's/\r//' /wait-for-it.sh
RUN sed -i 's/\r//' /docker-entrypoint.sh

CMD ["/wait-for-it.sh", "db:3306", "--", "/docker-entrypoint.sh"]
CMD ["/wait-for-it.sh", "--", "/docker-entrypoint.sh"]
9 changes: 0 additions & 9 deletions app/backend/libs/utils/swagger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,6 @@ export function setupSwagger(app: INestApplication): void {
.setVersion('1.0.0')
.addTag('moraks')
.addCookieAuth('token')
.addBearerAuth(
{
type: 'http',
scheme: 'bearer',
name: 'JWT',
in: 'header',
},
'access_token',
)
.build();

const document = SwaggerModule.createDocument(app, config);
Expand Down
6 changes: 4 additions & 2 deletions app/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,20 @@
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@morak/vault": "^1.0.0",
"@nestjs/cache-manager": "^2.1.1",
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/jwt": "^10.2.0",
"@nestjs/mapped-types": "*",
"@nestjs/mongoose": "^10.0.2",
"@nestjs/passport": "^10.0.2",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/platform-socket.io": "^10.2.10",
"@nestjs/swagger": "^7.1.14",
"@nestjs/websockets": "^10.2.10",
"@prisma/client": "^5.5.2",
"cache-manager": "^5.3.1",
"cache-manager-redis-store": "^2.0.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
Expand All @@ -42,8 +45,7 @@
"passport-google-oauth20": "^2.0.0",
"passport-jwt": "^4.0.1",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1",
"@morak/vault": "^1.0.0"
"rxjs": "^7.8.1"
},
"devDependencies": {
"@morak/apitype": "^1.0.0",
Expand Down
39 changes: 33 additions & 6 deletions app/backend/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import { GoogleOauthGuard } from './guards/google-oauth.guard';
import { LogoutDto } from './dto/user.dto';
import { getSecret } from '@morak/vault';

const isProduction = getSecret('NODE_ENV') === 'production';

@ApiTags('Oauth API')
@Controller('auth')
export class AuthController {
Expand Down Expand Up @@ -81,9 +83,16 @@ export class AuthController {

res.setHeader('Authorization', 'Bearer ' + [tokens.access_token, tokens.refresh_token]);

res.cookie('access_token', tokens.access_token, { httpOnly: false, maxAge: getSecret('MAX_AGE_ACCESS_TOKEN') });
res.cookie('access_token', tokens.access_token, {
httpOnly: true,
secure: isProduction ? true : false,
sameSite: 'lax',
maxAge: getSecret('MAX_AGE_ACCESS_TOKEN'),
});
res.cookie('refresh_token', tokens.refresh_token, {
httpOnly: true,
secure: isProduction ? true : false,
sameSite: 'lax',
maxAge: getSecret('MAX_AGE_REFRESH_TOKEN'),
});

Expand Down Expand Up @@ -119,14 +128,24 @@ export class AuthController {

res.setHeader('Authorization', 'Bearer ' + newAccessToken);
res.cookie('access_token', newAccessToken, {
httpOnly: false,
httpOnly: true,
secure: isProduction ? true : false,
sameSite: 'lax',
maxAge: getSecret('MAX_AGE_ACCESS_TOKEN'),
});

res.json({ newAccessToken });
} catch (err) {
res.clearCookie('access_token', { httpOnly: false });
res.clearCookie('refresh_token', { httpOnly: false });
res.clearCookie('access_token', {
httpOnly: true,
secure: isProduction ? true : false,
sameSite: 'lax',
});
res.clearCookie('refresh_token', {
httpOnly: true,
secure: isProduction ? true : false,
sameSite: 'lax',
});
throw new UnauthorizedException('Failed to refresh token');
}
}
Expand All @@ -149,8 +168,16 @@ export class AuthController {
const { providerId } = body;
await this.authService.logout(providerId);

res.clearCookie('access_token', { httpOnly: false });
res.clearCookie('refresh_token', { httpOnly: false });
res.clearCookie('access_token', {
httpOnly: true,
secure: isProduction ? true : false,
sameSite: 'lax',
});
res.clearCookie('refresh_token', {
httpOnly: true,
secure: isProduction ? true : false,
sameSite: 'lax',
});
} catch (error) {
console.error('Logout error:', error);
throw new UnauthorizedException('Failed to logout');
Expand Down
5 changes: 3 additions & 2 deletions app/backend/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { AuthRepository } from './auth.repository';
import { AtStrategy, GoogleStrategy, RtStrategy } from './strategies';
import { AtGuard } from './guards/at.guard';

@Module({
imports: [JwtModule.register({})],
controllers: [AuthController],
providers: [AuthService, AuthRepository, GoogleStrategy, AtStrategy, RtStrategy],
exports: [AuthService, AtStrategy],
providers: [AuthService, AuthRepository, GoogleStrategy, AtStrategy, RtStrategy, AtGuard],
exports: [AuthService, JwtModule, AtStrategy, AtGuard],
})
export class AuthModule {}
12 changes: 12 additions & 0 deletions app/backend/src/auth/auth.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ export class AuthRepository {
@Inject(CACHE_MANAGER) private cacheManager: Cache,
) {}

async getUserIdFromToken(providerId: string): Promise<bigint> {
const user = await this.prisma.member.findUnique({
where: {
providerId,
},
select: {
id: true,
},
});

return user.id;
}
async saveUser(userDto: CreateUserDto): Promise<Member> {
const { providerId, socialType, email, nickname, profilePicture } = userDto;

Expand Down
9 changes: 8 additions & 1 deletion app/backend/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export class AuthService {
private authRepository: AuthRepository,
) {}

private async getUserIdFromToken(providerId: string): Promise<bigint> {
return await this.authRepository.getUserIdFromToken(providerId);
}

async handleLogin(userDto: CreateUserDto): Promise<Tokens> {
const { providerId } = userDto;
const existingUser = await this.authRepository.findUserByIdentifier(providerId);
Expand Down Expand Up @@ -39,6 +43,7 @@ export class AuthService {

async signIn(userDto: CreateUserDto): Promise<Tokens | null> {
const { providerId, socialType, email, profilePicture, nickname } = userDto;
const userId = await this.getUserIdFromToken(providerId);

const existingUser = await this.authRepository.findUserByIdentifier(providerId);

Expand All @@ -49,6 +54,7 @@ export class AuthService {
}

const token = this.generateJwt({
userId,
providerId,
socialType,
email,
Expand All @@ -67,7 +73,7 @@ export class AuthService {
async refresh(refreshToken: string): Promise<string> {
try {
const decodedRefreshToken = this.jwtService.verify(refreshToken, { secret: getSecret('JWT_REFRESH_SECRET') });
const { providerId, socialType, email, profilePicture, nickname } = decodedRefreshToken;
const { userId, providerId, socialType, email, profilePicture, nickname } = decodedRefreshToken;

const storedRefreshToken = await this.authRepository.getRefreshToken(providerId);

Expand All @@ -76,6 +82,7 @@ export class AuthService {
}

const token = this.generateJwt({
userId,
providerId,
socialType,
email,
Expand Down
35 changes: 33 additions & 2 deletions app/backend/src/auth/guards/at.guard.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,36 @@
import { Injectable } from '@nestjs/common';
import { Injectable, ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { AuthGuard } from '@nestjs/passport';
import { getSecret } from '@morak/vault';

@Injectable()
export class AtGuard extends AuthGuard('jwt') {}
export class AtGuard extends AuthGuard('jwt') {
constructor(private jwtService: JwtService) {
super();
}

canActivate(context: ExecutionContext) {
const request = context.switchToHttp().getRequest();

if (!request.cookies) {
throw new UnauthorizedException('Unauthorized');
}

const accessToken = request.cookies.access_token;

try {
const decodedToken = this.jwtService.verify(accessToken, {
secret: getSecret('JWT_ACCESS_SECRET'),
});

const { userId, providerId, socialType, email, profilePicture, nickname } = decodedToken;
const userIdBigInt = BigInt(userId);

request.user = { id: userIdBigInt, providerId, socialType, email, profilePicture, nickname };

return true;
} catch (error) {
throw new UnauthorizedException('Invalid access token');
}
}
}
4 changes: 4 additions & 0 deletions app/backend/src/auth/interface/payload.interface.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { JwtPayload } from 'jsonwebtoken';

export interface Payload extends JwtPayload {
userId: bigint;
providerId: string;
socialType: string;
email: string;
profilePicture: string;
nickname: string;
}
3 changes: 1 addition & 2 deletions app/backend/src/groups/groups.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Post, UseGuards } from '@nestjs/common';
import { ApiBearerAuth, ApiBody, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
import { ApiBody, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
import { GroupsService } from './groups.service';
import { GetUser } from 'libs/decorators/get-user.decorator';
import { AtGuard } from 'src/auth/guards/at.guard';
Expand All @@ -12,7 +12,6 @@ import { CreateGroupsDto } from './dto/create-groups.dto';
@ApiTags('Group API')
@Controller('groups')
@UseGuards(AtGuard)
@ApiBearerAuth('access_token')
export class GroupsController {
constructor(private readonly groupsService: GroupsService) {}

Expand Down
Loading

0 comments on commit 0614ee0

Please sign in to comment.