icynet-auth-server/src/modules/oauth2/adapter/code.adapter.ts

126 lines
3.5 KiB
TypeScript
Raw Normal View History

2022-03-09 18:37:04 +00:00
import { OAuth2CodeAdapter, OAuth2Code } from '@icynet/oauth2-provider';
import { OAuth2TokenType } from 'src/modules/objects/oauth2-token/oauth2-token.entity';
2024-03-12 15:49:06 +00:00
import { TokenService } from 'src/modules/utility/services/token.service';
import { OAuth2ClientService } from 'src/modules/objects/oauth2-client/oauth2-client.service';
import { UserService } from 'src/modules/objects/user/user.service';
import { OAuth2TokenService } from 'src/modules/objects/oauth2-token/oauth2-token.service';
import { FormUtilityService } from 'src/modules/utility/services/form-utility.service';
import { Injectable } from '@nestjs/common';
@Injectable()
2022-03-09 18:37:04 +00:00
export class CodeAdapter implements OAuth2CodeAdapter {
2024-03-12 15:49:06 +00:00
constructor(
private readonly token: TokenService,
private readonly tokenService: OAuth2TokenService,
private readonly clientService: OAuth2ClientService,
private readonly userService: UserService,
private readonly form: FormUtilityService,
) {}
2022-03-09 18:37:04 +00:00
ttl = 3600;
challengeMethods = ['plain', 'S256'];
2022-03-09 18:37:04 +00:00
async create(
userId: number,
clientId: string,
scope: string | string[],
ttl: number,
2022-09-16 15:11:36 +00:00
nonce?: string,
codeChallenge?: string,
codeChallengeMethod?: 'plain' | 'S256',
2022-03-09 18:37:04 +00:00
): Promise<string> {
2024-03-12 15:49:06 +00:00
const client = await this.clientService.getById(clientId);
const user = await this.userService.getById(userId);
const accessToken = this.token.generateString(64);
2022-03-09 18:37:04 +00:00
// Standardize scope value
const scopes = (
2024-03-12 15:49:06 +00:00
!Array.isArray(scope) ? this.form.splitScope(scope) : scope
2022-03-09 18:37:04 +00:00
).join(' ');
const expiresAt = new Date(Date.now() + ttl * 1000);
const pcke =
codeChallenge && codeChallengeMethod
? `${this.challengeMethods.indexOf(
codeChallengeMethod,
)}:${codeChallenge}`
: null;
2022-03-09 18:37:04 +00:00
2024-03-12 15:49:06 +00:00
this.tokenService.insertToken(
2022-03-09 18:37:04 +00:00
accessToken,
OAuth2TokenType.CODE,
client,
scopes,
expiresAt,
user,
2022-09-16 15:11:36 +00:00
nonce,
pcke,
2022-03-09 18:37:04 +00:00
);
return accessToken;
}
async fetchByCode(code: string | OAuth2Code): Promise<OAuth2Code> {
const findBy = typeof code === 'string' ? code : code.code;
2024-03-12 15:49:06 +00:00
const find = await this.tokenService.fetchByToken(
2022-03-09 18:37:04 +00:00
findBy,
OAuth2TokenType.CODE,
);
2022-03-26 07:22:14 +00:00
if (!find) {
return null;
}
let codeChallenge: string;
let codeChallengeMethod: 'plain' | 'S256';
if (find.pcke) {
codeChallengeMethod = this.challengeMethods[
Number(find.pcke.substring(0, 1))
] as 'plain' | 'S256';
codeChallenge = find.pcke.substring(2);
}
2022-03-09 18:37:04 +00:00
return {
...find,
code: find.token,
client_id: find.client.client_id,
user_id: find.user.id,
code_challenge: codeChallenge,
code_challenge_method: codeChallengeMethod,
2022-03-09 18:37:04 +00:00
};
}
async removeByCode(code: string | OAuth2Code): Promise<boolean> {
const findBy = typeof code === 'string' ? code : code.code;
2024-03-12 15:49:06 +00:00
const find = await this.tokenService.fetchByToken(
2022-03-09 18:37:04 +00:00
findBy,
OAuth2TokenType.CODE,
);
2024-03-12 15:49:06 +00:00
this.tokenService.remove(find);
2022-03-09 18:37:04 +00:00
return true;
}
getUserId(code: OAuth2Code): string {
return code.user_id as string;
}
getClientId(code: OAuth2Code): string {
return code.client_id as string;
}
getScope(code: OAuth2Code): string {
return code.scope;
}
checkTTL(code: OAuth2Code): boolean {
return code.expires_at.getTime() > Date.now();
}
getCodeChallenge(code: OAuth2Code) {
return {
method: code.code_challenge_method,
challenge: code.code_challenge,
};
}
2022-03-09 18:37:04 +00:00
}