mirror of
https://github.com/swissmakers/swiss-datashare.git
synced 2026-04-17 12:43:13 +02:00
feat: delete all sessions if password was changed
This commit is contained in:
@@ -21,6 +21,7 @@ import { AuthRegisterDTO } from "./dto/authRegister.dto";
|
|||||||
import { AuthSignInDTO } from "./dto/authSignIn.dto";
|
import { AuthSignInDTO } from "./dto/authSignIn.dto";
|
||||||
import { AuthSignInTotpDTO } from "./dto/authSignInTotp.dto";
|
import { AuthSignInTotpDTO } from "./dto/authSignInTotp.dto";
|
||||||
import { EnableTotpDTO } from "./dto/enableTotp.dto";
|
import { EnableTotpDTO } from "./dto/enableTotp.dto";
|
||||||
|
import { TokenDTO } from "./dto/token.dto";
|
||||||
import { UpdatePasswordDTO } from "./dto/updatePassword.dto";
|
import { UpdatePasswordDTO } from "./dto/updatePassword.dto";
|
||||||
import { VerifyTotpDTO } from "./dto/verifyTotp.dto";
|
import { VerifyTotpDTO } from "./dto/verifyTotp.dto";
|
||||||
import { JwtGuard } from "./guard/jwt.guard";
|
import { JwtGuard } from "./guard/jwt.guard";
|
||||||
@@ -45,8 +46,8 @@ export class AuthController {
|
|||||||
|
|
||||||
response = this.addTokensToResponse(
|
response = this.addTokensToResponse(
|
||||||
response,
|
response,
|
||||||
result.accessToken,
|
result.refreshToken,
|
||||||
result.refreshToken
|
result.accessToken
|
||||||
);
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -64,8 +65,8 @@ export class AuthController {
|
|||||||
if (result.accessToken && result.refreshToken) {
|
if (result.accessToken && result.refreshToken) {
|
||||||
response = this.addTokensToResponse(
|
response = this.addTokensToResponse(
|
||||||
response,
|
response,
|
||||||
result.accessToken,
|
result.refreshToken,
|
||||||
result.refreshToken
|
result.accessToken
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,17 +84,28 @@ export class AuthController {
|
|||||||
|
|
||||||
response = this.addTokensToResponse(
|
response = this.addTokensToResponse(
|
||||||
response,
|
response,
|
||||||
result.accessToken,
|
result.refreshToken,
|
||||||
result.refreshToken
|
result.accessToken
|
||||||
);
|
);
|
||||||
|
|
||||||
return result;
|
return new TokenDTO().from(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Patch("password")
|
@Patch("password")
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async updatePassword(@GetUser() user: User, @Body() dto: UpdatePasswordDTO) {
|
async updatePassword(
|
||||||
await this.authService.updatePassword(user, dto.oldPassword, dto.password);
|
@GetUser() user: User,
|
||||||
|
@Res({ passthrough: true }) response: Response,
|
||||||
|
@Body() dto: UpdatePasswordDTO
|
||||||
|
) {
|
||||||
|
const result = await this.authService.updatePassword(
|
||||||
|
user,
|
||||||
|
dto.oldPassword,
|
||||||
|
dto.password
|
||||||
|
);
|
||||||
|
|
||||||
|
response = this.addTokensToResponse(response, result.refreshToken);
|
||||||
|
return new TokenDTO().from(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post("token")
|
@Post("token")
|
||||||
@@ -108,7 +120,7 @@ export class AuthController {
|
|||||||
request.cookies.refresh_token
|
request.cookies.refresh_token
|
||||||
);
|
);
|
||||||
response.cookie("access_token", accessToken);
|
response.cookie("access_token", accessToken);
|
||||||
return { accessToken };
|
return new TokenDTO().from({ accessToken });
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post("signOut")
|
@Post("signOut")
|
||||||
@@ -146,10 +158,11 @@ export class AuthController {
|
|||||||
|
|
||||||
private addTokensToResponse(
|
private addTokensToResponse(
|
||||||
response: Response,
|
response: Response,
|
||||||
accessToken: string,
|
refreshToken?: string,
|
||||||
refreshToken: string
|
accessToken?: string
|
||||||
) {
|
) {
|
||||||
response.cookie("access_token", accessToken);
|
if (accessToken) response.cookie("access_token", accessToken);
|
||||||
|
if (refreshToken)
|
||||||
response.cookie("refresh_token", refreshToken, {
|
response.cookie("refresh_token", refreshToken, {
|
||||||
path: "/api/auth/token",
|
path: "/api/auth/token",
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
|
|||||||
@@ -87,10 +87,16 @@ export class AuthService {
|
|||||||
|
|
||||||
const hash = await argon.hash(newPassword);
|
const hash = await argon.hash(newPassword);
|
||||||
|
|
||||||
return await this.prisma.user.update({
|
await this.prisma.refreshToken.deleteMany({
|
||||||
|
where: { userId: user.id },
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.prisma.user.update({
|
||||||
where: { id: user.id },
|
where: { id: user.id },
|
||||||
data: { password: hash },
|
data: { password: hash },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return this.createRefreshToken(user.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createAccessToken(user: User, refreshTokenId: string) {
|
async createAccessToken(user: User, refreshTokenId: string) {
|
||||||
@@ -112,7 +118,12 @@ export class AuthService {
|
|||||||
refreshTokenId: string;
|
refreshTokenId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
await this.prisma.refreshToken.delete({ where: { id: refreshTokenId } });
|
await this.prisma.refreshToken
|
||||||
|
.delete({ where: { id: refreshTokenId } })
|
||||||
|
.catch((e) => {
|
||||||
|
// Ignore error if refresh token doesn't exist
|
||||||
|
if (e.code != "P2025") throw e;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async refreshAccessToken(refreshToken: string) {
|
async refreshAccessToken(refreshToken: string) {
|
||||||
|
|||||||
15
backend/src/auth/dto/token.dto.ts
Normal file
15
backend/src/auth/dto/token.dto.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { Expose, plainToClass } from "class-transformer";
|
||||||
|
|
||||||
|
export class TokenDTO {
|
||||||
|
@Expose()
|
||||||
|
accessToken: string;
|
||||||
|
|
||||||
|
@Expose()
|
||||||
|
refreshToken: string;
|
||||||
|
|
||||||
|
from(partial: Partial<TokenDTO>) {
|
||||||
|
return plainToClass(TokenDTO, partial, {
|
||||||
|
excludeExtraneousValues: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user