111 lines
3.3 KiB
TypeScript
111 lines
3.3 KiB
TypeScript
import {
|
|
Controller,
|
|
Get,
|
|
Inject,
|
|
Param,
|
|
Post,
|
|
Query,
|
|
Req,
|
|
Res,
|
|
UseFilters,
|
|
UseGuards,
|
|
} from "@nestjs/common";
|
|
import { User } from "@prisma/client";
|
|
import { Request, Response } from "express";
|
|
import { nanoid } from "nanoid";
|
|
import { AuthService } from "../auth/auth.service";
|
|
import { GetUser } from "../auth/decorator/getUser.decorator";
|
|
import { JwtGuard } from "../auth/guard/jwt.guard";
|
|
import { ConfigService } from "../config/config.service";
|
|
import { OAuthCallbackDto } from "./dto/oauthCallback.dto";
|
|
import { ErrorPageExceptionFilter } from "./filter/errorPageException.filter";
|
|
import { OAuthGuard } from "./guard/oauth.guard";
|
|
import { ProviderGuard } from "./guard/provider.guard";
|
|
import { OAuthService } from "./oauth.service";
|
|
import { OAuthProvider } from "./provider/oauthProvider.interface";
|
|
import { OAuthExceptionFilter } from "./filter/oauthException.filter";
|
|
|
|
@Controller("oauth")
|
|
export class OAuthController {
|
|
constructor(
|
|
private authService: AuthService,
|
|
private oauthService: OAuthService,
|
|
private config: ConfigService,
|
|
@Inject("OAUTH_PROVIDERS")
|
|
private providers: Record<string, OAuthProvider<unknown>>,
|
|
) {}
|
|
|
|
@Get("available")
|
|
available() {
|
|
return this.oauthService.available();
|
|
}
|
|
|
|
@Get("status")
|
|
@UseGuards(JwtGuard)
|
|
async status(@GetUser() user: User) {
|
|
return this.oauthService.status(user);
|
|
}
|
|
|
|
@Get("auth/:provider")
|
|
@UseGuards(ProviderGuard)
|
|
@UseFilters(ErrorPageExceptionFilter)
|
|
async auth(
|
|
@Param("provider") provider: string,
|
|
@Res({ passthrough: true }) response: Response,
|
|
) {
|
|
const state = nanoid(16);
|
|
const url = await this.providers[provider].getAuthEndpoint(state);
|
|
response.cookie(`oauth_${provider}_state`, state, { sameSite: "lax" });
|
|
response.redirect(url);
|
|
}
|
|
|
|
@Get("callback/:provider")
|
|
@UseGuards(ProviderGuard, OAuthGuard)
|
|
@UseFilters(ErrorPageExceptionFilter, OAuthExceptionFilter)
|
|
async callback(
|
|
@Param("provider") provider: string,
|
|
@Query() query: OAuthCallbackDto,
|
|
@Req() request: Request,
|
|
@Res({ passthrough: true }) response: Response,
|
|
) {
|
|
const oauthToken = await this.providers[provider].getToken(query);
|
|
const user = await this.providers[provider].getUserInfo(oauthToken, query);
|
|
const id = await this.authService.getIdOfCurrentUser(request);
|
|
|
|
if (id) {
|
|
await this.oauthService.link(
|
|
id,
|
|
provider,
|
|
user.providerId,
|
|
user.providerUsername,
|
|
);
|
|
response.redirect(this.config.get("general.appUrl") + "/account");
|
|
} else {
|
|
const token: {
|
|
accessToken?: string;
|
|
refreshToken?: string;
|
|
loginToken?: string;
|
|
} = await this.oauthService.signIn(user, request.ip);
|
|
if (token.accessToken) {
|
|
this.authService.addTokensToResponse(
|
|
response,
|
|
token.refreshToken,
|
|
token.accessToken,
|
|
);
|
|
response.redirect(this.config.get("general.appUrl"));
|
|
} else {
|
|
response.redirect(
|
|
this.config.get("general.appUrl") + `/auth/totp/${token.loginToken}`,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Post("unlink/:provider")
|
|
@UseGuards(JwtGuard, ProviderGuard)
|
|
@UseFilters(ErrorPageExceptionFilter)
|
|
unlink(@GetUser() user: User, @Param("provider") provider: string) {
|
|
return this.oauthService.unlink(user, provider);
|
|
}
|
|
}
|