Merged PR 138: SendGridService内のprivateキーの取得方法を修正する

## 概要
[Task1736: SendGridService内のprivateキーの取得方法を修正する](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1736)

- CryptoServiceの削除
- トークン発行・認証に使用するKeyを環境変数から取得するように修正
- 既存テストの修正

## レビューポイント
- Keyの取得関数の配置場所は妥当か

## UIの変更
- Before/Afterのスクショなど
- スクショ置き場

## 動作確認状況
- ローカルでテストが通ることを確認
- keyを使う処理(ユーザー追加)を実行して、成功することを確認

## 補足
- 修正した箇所のロールチェックはレビュー対象外
  - 「タスク 1830: 認証・認可を宣言的に扱える仕組みを既存処理に適用する」で調整してもらう想定
This commit is contained in:
saito.k 2023-06-09 05:35:39 +00:00
parent 25072f558f
commit 0907bd28af
23 changed files with 192 additions and 402 deletions

View File

@ -7,7 +7,6 @@ import { LoggerMiddleware } from './common/loggerMiddleware';
import { AuthModule } from './features/auth/auth.module';
import { AuthController } from './features/auth/auth.controller';
import { AuthService } from './features/auth/auth.service';
import { CryptoModule } from './gateways/crypto/crypto.module';
import { AdB2cModule } from './gateways/adb2c/adb2c.module';
import { AccountsController } from './features/accounts/accounts.controller';
import { AccountsService } from './features/accounts/accounts.service';
@ -49,7 +48,6 @@ import { SortCriteriaRepositoryModule } from './repositories/sort_criteria/sort_
isGlobal: true,
}),
AuthModule,
CryptoModule,
AdB2cModule,
AccountsModule,
UsersModule,

View File

@ -1,8 +1,9 @@
import { Module } from '@nestjs/common';
import { AuthGuard } from './authguards';
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [],
imports: [ConfigModule],
controllers: [],
providers: [AuthGuard],
})

View File

@ -1,25 +1,23 @@
import {
Injectable,
CanActivate,
ExecutionContext,
HttpException,
HttpStatus,
Injectable,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Request } from 'express';
import { getPublicKey } from '../../../common/jwt/jwt';
import { makeErrorResponse } from '../../error/makeErrorResponse';
import { retrieveAuthorizationToken } from '../../http/helper';
import { isVerifyError, verify } from '../../jwt';
import { AccessToken } from '../../token';
import { retrieveAuthorizationToken } from '../../http/helper';
import { makeErrorResponse } from '../../error/makeErrorResponse';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private readonly configService: ConfigService) {}
canActivate(context: ExecutionContext): boolean | Promise<boolean> {
const pubkey = this.configService
.getOrThrow<string>('JWT_PUBLIC_KEY')
.replace('\\n', '\n');
const pubkey = getPublicKey(this.configService);
const req = context.switchToHttp().getRequest<Request>();
const token = retrieveAuthorizationToken(req);

View File

@ -1,3 +1,4 @@
import { ConfigService } from '@nestjs/config';
import * as jwt from 'jsonwebtoken';
// XXX: decodeがうまく使えないことがあるので応急対応 バージョン9以降だとなる
import { decode as jwtDecode } from 'jsonwebtoken';
@ -126,3 +127,19 @@ export const decode = <T extends object>(token: string): T | VerifyError => {
}
}
};
export const getPrivateKey = (configService: ConfigService): string => {
return (
// 開発環境用に改行コードを置換する
// 本番環境では\\nが含まれないため、置換が行われない想定
configService.get<string>('JWT_PRIVATE_KEY')?.replace('\\n', '\n') ?? ''
);
};
export const getPublicKey = (configService: ConfigService): string => {
return (
// 開発環境用に改行コードを置換する
// 本番環境では\\nが含まれないため、置換が行われない想定
configService.get<string>('JWT_PUBLIC_KEY')?.replace('\\n', '\n') ?? ''
);
};

View File

@ -64,6 +64,7 @@ export class AuthController {
idToken,
body.type,
);
const accessToken = await this.authService.generateAccessToken(
refreshToken,
);

View File

@ -1,12 +1,12 @@
import { Module } from '@nestjs/common';
import { UsersRepositoryModule } from '../../repositories/users/users.repository.module';
import { ConfigModule } from '@nestjs/config';
import { AdB2cModule } from '../../gateways/adb2c/adb2c.module';
import { CryptoModule } from '../../gateways/crypto/crypto.module';
import { UsersRepositoryModule } from '../../repositories/users/users.repository.module';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
@Module({
imports: [CryptoModule, AdB2cModule, UsersRepositoryModule],
imports: [ConfigModule, AdB2cModule, UsersRepositoryModule],
controllers: [AuthController],
providers: [AuthService],
})

View File

@ -3,14 +3,15 @@ import { makeErrorResponse } from '../../common/error/makeErrorResponse';
import {
makeAuthServiceMock,
makeDefaultAdB2cMockValue,
makeDefaultCryptoMockValue,
makeDefaultGetPublicKeyFromJwk,
} from './test/auth.service.mock';
describe('AuthService', () => {
it('IDトークンの検証とペイロードの取得に成功する', async () => {
const adb2cParam = makeDefaultAdB2cMockValue();
const cryptoParam = makeDefaultCryptoMockValue();
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
const service = await makeAuthServiceMock(adb2cParam);
//JWKの生成→PEM変換を自力で表現することが厳しいためMockで代替
service.getPublicKeyFromJwk = makeDefaultGetPublicKeyFromJwk;
const token =
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.RyieW-VHsHPQOjXbbhRc307AYJOc1sq2hrcu4SW1-K0pvLlkplepxvx02a3vCwQrnBYrIP5w6HExG-S_JgW5nYyWr6DeY11mA484n9KA8GeAcAXV37StH1gfWUJvfGb4C8BaMbMM9Ix4Z9NGwKA9vjNwevfmBZnz9lQUePgv6BJNmyvCt8ElJ01O-1WODbZuojJ4xXymA1OqluzfbphPOsqWTSNmTn0emkLjjnlMQf1iwM4C_kvvr8dUCFg0_UGDfQVJnzPEKB38UqnhLnC5WacrddDwQ0kBuGKZgZ_63Q_7fOvqAZivqLK7BPmbPxi6mx3R1S9Eq2ugzpY1LfJOjA';
@ -19,8 +20,7 @@ describe('AuthService', () => {
it('IDトークンの形式が不正な場合、形式不正エラーとなる。', async () => {
const adb2cParam = makeDefaultAdB2cMockValue();
const cryptoParam = makeDefaultCryptoMockValue();
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
const service = await makeAuthServiceMock(adb2cParam);
const token = 'invalid.id.token';
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
@ -30,8 +30,9 @@ describe('AuthService', () => {
it('IDトークンの有効期限が切れている場合、有効期限切れエラーとなる。', async () => {
const adb2cParam = makeDefaultAdB2cMockValue();
const cryptoParam = makeDefaultCryptoMockValue();
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
const service = await makeAuthServiceMock(adb2cParam);
//JWKの生成→PEM変換を自力で表現することが厳しいためMockで代替
service.getPublicKeyFromJwk = makeDefaultGetPublicKeyFromJwk;
const token =
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjEwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.r9x61Mf1S2qFgU_QDKB6tRFBmTQXyOEtpoacOlL_bQzFz1t3GsxMy6SJIvQQ-LtDgylQ1UCdMFiRuy4V8nyLuME0fR-9IkKsboGvwllHB_Isai3XFoja0jpDHMVby1m0B3Z9xOTb7YsaQGyEH-qs1TtnRm6Ny98h4Po80nK8HGefQZHBOlfQN_B1LiHwI3nLXV18NL-4olKXj2NloNRYtnWM0PaqDQcGvZFaSNvtrSYpo9ddD906QWDGVOQ7WvGSUgdNCoxX8Lb3r2-VSj6n84jpb-Y1Fz-GhLluNglAsBhasnJfUIvCIO3iG5pRyTYjHFAVHmzjr8xMOmhS3s41Jw';
@ -42,8 +43,9 @@ describe('AuthService', () => {
it('IDトークンが開始日より前の場合、開始前エラーとなる。', async () => {
const adb2cParam = makeDefaultAdB2cMockValue();
const cryptoParam = makeDefaultCryptoMockValue();
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
const service = await makeAuthServiceMock(adb2cParam);
//JWKの生成→PEM変換を自力で表現することが厳しいためMockで代替
service.getPublicKeyFromJwk = makeDefaultGetPublicKeyFromJwk;
const token =
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6OTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.fX2Gbd7fDPNE3Lw-xbum_5CVqQYqEmMhv_v5u8A-U81pmPD2P5rsJEJx66ns1taFLVaE3j9_OzotxrqjqqQqbACkagGcN5wvA3_ZIxyqmhrKYFJc53ZcO7d0pFWiQlluNBI_pnFNDlSMB2Ut8Th5aiPy2uamBM9wC99bcjo7HkHvTKBf6ljU6rPKoD51qGDWqNxjoH-hdSJ29wprvyxyk_yX6dp-cxXUj5DIgXYQuIZF71rdiPtGlAiyTBns8rS2QlEEXapZVlvYrK4mkpUXVDA7ifD8q6gAC2BStqHeys7CGp2MbV4ZwKCVbAUbMs6Tboh8rADZvQhuTEq7qlhZ-w';
@ -54,8 +56,7 @@ describe('AuthService', () => {
it('IDトークンの署名が不正な場合、署名不正エラーとなる。', async () => {
const adb2cParam = makeDefaultAdB2cMockValue();
const cryptoParam = makeDefaultCryptoMockValue();
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
const service = await makeAuthServiceMock(adb2cParam);
const token =
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdXNlciIsInN1YiI6InN1YiIsImF1ZCI6ImF1ZCIsIm5vbmNlIjoiZGVmYXVsdE5vbmNlIiwiaWF0IjoxMDAwMDAwMDAwLCJhdXRoX3RpbWUiOjEwMDAwMDAwMDAsImVtYWlscyI6WyJ4eHhAeHguY29tIl0sInRmcCI6InNpZ25pbl91c2VyZmxvdyJ9.sign';
@ -66,8 +67,9 @@ describe('AuthService', () => {
it('IDトークンの発行元が想定と異なる場合、発行元不正エラーとなる。', async () => {
const adb2cParam = makeDefaultAdB2cMockValue();
const cryptoParam = makeDefaultCryptoMockValue();
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
const service = await makeAuthServiceMock(adb2cParam);
//JWKの生成→PEM変換を自力で表現することが厳しいためMockで代替
service.getPublicKeyFromJwk = makeDefaultGetPublicKeyFromJwk;
const token =
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaW52bGlkX2lzc3VlciIsInN1YiI6InN1YiIsImF1ZCI6ImF1ZCIsIm5vbmNlIjoiZGVmYXVsdE5vbmNlIiwiaWF0IjoxMDAwMDAwMDAwLCJhdXRoX3RpbWUiOjEwMDAwMDAwMDAsImVtYWlscyI6WyJ4eHhAeHguY29tIl0sInRmcCI6InNpZ25pbl91c2VyZmxvdyJ9.0bp3e1mDG78PX3lo8zgOLXGenIqG_Vi6kw7CbwauAQM-cnUZ_aVCoJ_dAv_QmPElOQKcCkRrAvAZ91FwuHDlBGuuDqx8OwqN0VaD-4NPouoAswj-9HNvBm8gUn-pGaXkvWt_72UdCJavZJjDj_RHur8y8kFt5Qeab3mUP2x-uNcV2Q2x3M_IIfcRiIZkRZm_azKfiVIy7tzoUFLDss97y938aR8imMVxazoSQvj7RWIWylgeRr9yVt7qYl18cnEVL0IGtslFbqhfNsiEmRCMsttm5kXs7E9B0bhhUe_xbJW9VumQ6G7dgMrswevp_jRgbpWJoZsgErtqIRl9Tc9ikA';
@ -79,8 +81,7 @@ describe('AuthService', () => {
it('Azure ADB2Cでネットワークエラーとなる場合、エラーとなる。メタデータ', async () => {
const adb2cParam = makeDefaultAdB2cMockValue();
adb2cParam.getMetaData = new Error('failed get metadata');
const cryptoParam = makeDefaultCryptoMockValue();
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
const service = await makeAuthServiceMock(adb2cParam);
const token =
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.RyieW-VHsHPQOjXbbhRc307AYJOc1sq2hrcu4SW1-K0pvLlkplepxvx02a3vCwQrnBYrIP5w6HExG-S_JgW5nYyWr6DeY11mA484n9KA8GeAcAXV37StH1gfWUJvfGb4C8BaMbMM9Ix4Z9NGwKA9vjNwevfmBZnz9lQUePgv6BJNmyvCt8ElJ01O-1WODbZuojJ4xXymA1OqluzfbphPOsqWTSNmTn0emkLjjnlMQf1iwM4C_kvvr8dUCFg0_UGDfQVJnzPEKB38UqnhLnC5WacrddDwQ0kBuGKZgZ_63Q_7fOvqAZivqLK7BPmbPxi6mx3R1S9Eq2ugzpY1LfJOjA';
@ -94,8 +95,7 @@ describe('AuthService', () => {
it('Azure ADB2Cでネットワークエラーとなる場合、エラーとなる。キーセット', async () => {
const adb2cParam = makeDefaultAdB2cMockValue();
adb2cParam.getSignKeySets = new Error('failed get keyset');
const cryptoParam = makeDefaultCryptoMockValue();
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
const service = await makeAuthServiceMock(adb2cParam);
const token =
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.RyieW-VHsHPQOjXbbhRc307AYJOc1sq2hrcu4SW1-K0pvLlkplepxvx02a3vCwQrnBYrIP5w6HExG-S_JgW5nYyWr6DeY11mA484n9KA8GeAcAXV37StH1gfWUJvfGb4C8BaMbMM9Ix4Z9NGwKA9vjNwevfmBZnz9lQUePgv6BJNmyvCt8ElJ01O-1WODbZuojJ4xXymA1OqluzfbphPOsqWTSNmTn0emkLjjnlMQf1iwM4C_kvvr8dUCFg0_UGDfQVJnzPEKB38UqnhLnC5WacrddDwQ0kBuGKZgZ_63Q_7fOvqAZivqLK7BPmbPxi6mx3R1S9Eq2ugzpY1LfJOjA';
@ -112,8 +112,7 @@ describe('AuthService', () => {
adb2cParam.getSignKeySets = [
{ kid: 'invalid', kty: 'RSA', nbf: 0, use: 'sig', e: '', n: '' },
];
const cryptoParam = makeDefaultCryptoMockValue();
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
const service = await makeAuthServiceMock(adb2cParam);
const token =
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwidmVyIjoiMS4wIiwiaXNzIjoiaXNzdWVyIiwic3ViIjoic3ViIiwiYXVkIjoiYXVkIiwibm9uY2UiOiJkZWZhdWx0Tm9uY2UiLCJpYXQiOjEwMDAwMDAwMDAsImF1dGhfdGltZSI6MTAwMDAwMDAwMCwiZW1haWxzIjpbInh4eEB4eC5jb20iXSwidGZwIjoic2lnbmluX3VzZXJmbG93In0.RyieW-VHsHPQOjXbbhRc307AYJOc1sq2hrcu4SW1-K0pvLlkplepxvx02a3vCwQrnBYrIP5w6HExG-S_JgW5nYyWr6DeY11mA484n9KA8GeAcAXV37StH1gfWUJvfGb4C8BaMbMM9Ix4Z9NGwKA9vjNwevfmBZnz9lQUePgv6BJNmyvCt8ElJ01O-1WODbZuojJ4xXymA1OqluzfbphPOsqWTSNmTn0emkLjjnlMQf1iwM4C_kvvr8dUCFg0_UGDfQVJnzPEKB38UqnhLnC5WacrddDwQ0kBuGKZgZ_63Q_7fOvqAZivqLK7BPmbPxi6mx3R1S9Eq2ugzpY1LfJOjA';

View File

@ -1,24 +1,30 @@
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import jwt from 'jsonwebtoken';
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
import jwkToPem from 'jwk-to-pem';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
import { isVerifyError, sign, verify } from '../../common/jwt';
import { sign } from '../../common/jwt';
import {
getPrivateKey,
getPublicKey,
isVerifyError,
verify,
} from '../../common/jwt/jwt';
import {
AccessToken,
IDToken,
isIDToken,
JwkSignKey,
RefreshToken,
isIDToken,
} from '../../common/token';
import { AdB2cService } from '../../gateways/adb2c/adb2c.service';
import { CryptoService } from '../../gateways/crypto/crypto.service';
import { User } from '../../repositories/users/entity/user.entity';
import { ADMIN_ROLES, USER_ROLES } from '../../constants';
import { AdB2cService } from '../../gateways/adb2c/adb2c.service';
import { User } from '../../repositories/users/entity/user.entity';
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
@Injectable()
export class AuthService {
constructor(
private readonly cryptoService: CryptoService,
private readonly adB2cService: AdB2cService,
private readonly configService: ConfigService,
private readonly usersRepository: UsersRepositoryService,
@ -87,8 +93,7 @@ export class AuthService {
}
// 要求された環境用トークンの寿命を決定
const refreshTokenLifetime = type === 'web' ? lifetimeWeb : lifetimeDefault;
const privateKey = await this.cryptoService.getPrivateKey();
const privateKey = getPrivateKey(this.configService);
// ユーザーのロールを設定
// 万一不正なRoleが登録されていた場合、そのままDBの値を使用すると不正なロールのリフレッシュトークンが発行されるため、
@ -135,8 +140,8 @@ export class AuthService {
async generateAccessToken(refreshToken: string): Promise<string> {
const lifetime = this.configService.get('ACCESS_TOKEN_LIFETIME_WEB');
const privateKey = await this.cryptoService.getPrivateKey();
const pubkey = await this.cryptoService.getPublicKey();
const privateKey = getPrivateKey(this.configService);
const pubkey = getPublicKey(this.configService);
const token = verify<RefreshToken>(refreshToken, pubkey);
if (isVerifyError(token)) {
@ -189,7 +194,7 @@ export class AuthService {
throw new Error('Public Key Not Found.');
}
const publicKey = await this.cryptoService.getPublicKeyFromJwk(jwkKey);
const publicKey = this.getPublicKeyFromJwk(jwkKey);
const verifiedToken = jwt.verify(token, publicKey, {
algorithms: ['RS256'],
@ -237,6 +242,24 @@ export class AuthService {
}
}
getPublicKeyFromJwk(jwkKey: JwkSignKey): string {
try {
// JWK形式のJSONなのでJWTの公開鍵として使えるようにPEM形式に変換
const publicKey = jwkToPem({
kty: 'RSA',
n: jwkKey.n,
e: jwkKey.e,
});
return publicKey;
} catch (e) {
this.logger.error(`error=${e}`);
throw e;
} finally {
this.logger.log(`[OUT] ${this.getPublicKeyFromJwk.name}`);
}
}
/**
* JWT検証時のErrorJsonWebTokenErrorをメッセージごとに仕分けてHTTPエラーを生成
*/

View File

@ -1,6 +1,5 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AdB2cService } from '../../../gateways/adb2c/adb2c.service';
import { CryptoService } from '../../../gateways/crypto/crypto.service';
import { JwkSignKey, B2cMetadata } from '../../../common/token';
import { AuthService } from '../auth.service';
import { ConfigService } from '@nestjs/config';
@ -11,13 +10,8 @@ export type AdB2cMockValue = {
getSignKeySets: JwkSignKey[] | Error;
};
export type CryptoMockValue = {
getPublicKeyFromJwk: string | Error;
};
export const makeAuthServiceMock = async (
adB2cMockValue: AdB2cMockValue,
cryptoMockValue: CryptoMockValue,
): Promise<AuthService> => {
const module: TestingModule = await Test.createTestingModule({
providers: [AuthService],
@ -26,8 +20,6 @@ export const makeAuthServiceMock = async (
switch (token) {
case AdB2cService:
return makeAdB2cServiceMock(adB2cMockValue);
case CryptoService:
return makeCryptoServiceMock(cryptoMockValue);
case ConfigService:
return {};
case UsersRepositoryService:
@ -74,33 +66,17 @@ export const makeAdB2cServiceMock = (value: AdB2cMockValue) => {
};
};
export const makeDefaultCryptoMockValue = (): CryptoMockValue => {
return {
getPublicKeyFromJwk: [
'-----BEGIN PUBLIC KEY-----',
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5IZZNgDew9eGmuFTezwd',
'HYLSaJvUPPIKYoiOeVLD1paWNI517Vkaoh0ngprcKOdv6T1N07V4igK7mOim2zY3',
'yCTR6wcWR3PfFJrl9vh5SOo79koZoJb27YiM4jtxfx2dezzp0T2GoNR5rRolPUbW',
'FJXnDe0DVXYXpJLb4LAlF2XAyYX0SYKUVUsJnzm5k4xbXtnwPwVbpm0EdswBE6qS',
'fiL9zWk9dvHoKzSnfSDzDFoFcEoVchawzYXf/MM1YR4wo5XyzECc6Q5Ah4z522//',
'mBNNaDHv83Yuw3mGShT73iJ0JQdkTturshv2Ecma38r6ftrIwNYXw4VVatJM8+GO',
'OQIDAQAB',
'-----END PUBLIC KEY-----',
].join('\n'),
};
};
export const makeCryptoServiceMock = (value: CryptoMockValue) => {
const { getPublicKeyFromJwk } = value;
return {
getPublicKeyFromJwk:
getPublicKeyFromJwk instanceof Error
? jest
.fn<Promise<void>, [JwkSignKey]>()
.mockRejectedValue(getPublicKeyFromJwk)
: jest
.fn<Promise<string>, [JwkSignKey]>()
.mockResolvedValue(getPublicKeyFromJwk),
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export const makeDefaultGetPublicKeyFromJwk = (jwkKey: JwkSignKey): string => {
return [
'-----BEGIN PUBLIC KEY-----',
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5IZZNgDew9eGmuFTezwd',
'HYLSaJvUPPIKYoiOeVLD1paWNI517Vkaoh0ngprcKOdv6T1N07V4igK7mOim2zY3',
'yCTR6wcWR3PfFJrl9vh5SOo79koZoJb27YiM4jtxfx2dezzp0T2GoNR5rRolPUbW',
'FJXnDe0DVXYXpJLb4LAlF2XAyYX0SYKUVUsJnzm5k4xbXtnwPwVbpm0EdswBE6qS',
'fiL9zWk9dvHoKzSnfSDzDFoFcEoVchawzYXf/MM1YR4wo5XyzECc6Q5Ah4z522//',
'mBNNaDHv83Yuw3mGShT73iJ0JQdkTturshv2Ecma38r6ftrIwNYXw4VVatJM8+GO',
'OQIDAQAB',
'-----END PUBLIC KEY-----',
].join('\n');
};

View File

@ -22,6 +22,7 @@ describe('FilesService', () => {
await service.publishUploadSas({
userId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx',
role: 'Author',
tier: 5,
}),
).toEqual('https://blob-storage?sas-token');
});
@ -43,6 +44,7 @@ describe('FilesService', () => {
await service.publishUploadSas({
userId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx',
role: 'Author',
tier: 5,
}),
).toEqual('https://blob-storage?sas-token');
});
@ -63,6 +65,7 @@ describe('FilesService', () => {
service.publishUploadSas({
userId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx',
role: 'Author',
tier: 5,
}),
).rejects.toEqual(
new HttpException(makeErrorResponse('E009999'), HttpStatus.UNAUTHORIZED),
@ -86,6 +89,7 @@ describe('FilesService', () => {
service.publishUploadSas({
userId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx',
role: 'Author',
tier: 5,
}),
).rejects.toEqual(
new HttpException(makeErrorResponse('E009999'), HttpStatus.UNAUTHORIZED),

View File

@ -1,7 +1,6 @@
import { Test, TestingModule } from '@nestjs/testing';
import { LicensesController } from './licenses.controller';
import { LicensesService } from './licenses.service';
import { CryptoService } from '../../gateways/crypto/crypto.service';
import { ConfigModule } from '@nestjs/config';
describe('LicensesController', () => {
@ -17,7 +16,7 @@ describe('LicensesController', () => {
}),
],
controllers: [LicensesController],
providers: [LicensesService, CryptoService],
providers: [LicensesService],
})
.overrideProvider(LicensesService)
.useValue(mockLicensesService)

View File

@ -1,38 +1,33 @@
import {
Body,
Controller,
HttpException,
HttpStatus,
Post,
Req,
UseGuards,
HttpException,
} from '@nestjs/common';
import {
ApiBearerAuth,
ApiOperation,
ApiResponse,
ApiTags,
ApiOperation,
ApiBearerAuth,
} from '@nestjs/swagger';
import { ErrorResponse } from '../../common/error/types/types';
import { LicensesService } from './licenses.service';
import { CreateOrdersResponse, CreateOrdersRequest } from './types/types';
import { Request } from 'express';
import { CryptoService } from '../../gateways/crypto/crypto.service';
import { retrieveAuthorizationToken } from '../../common/http/helper';
import { confirmPermission } from '../../common/auth/auth';
import { decode } from 'jsonwebtoken';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
import { isVerifyError, verify } from '../../common/jwt';
import { AccessToken } from '../../common/token';
import { ErrorResponse } from '../../common/error/types/types';
import { AuthGuard } from '../../common/guards/auth/authguards';
import { RoleGuard } from '../../common/guards/role/roleguards';
import { retrieveAuthorizationToken } from '../../common/http/helper';
import { AccessToken } from '../../common/token';
import { LicensesService } from './licenses.service';
import { CreateOrdersRequest, CreateOrdersResponse } from './types/types';
@ApiTags('licenses')
@Controller('licenses')
export class LicensesController {
constructor(
private readonly licensesService: LicensesService,
private readonly cryptoService: CryptoService,
) {}
constructor(private readonly licensesService: LicensesService) {}
@ApiResponse({
status: HttpStatus.OK,
type: CreateOrdersResponse,
@ -55,8 +50,8 @@ export class LicensesController {
})
@ApiOperation({ operationId: 'createOrders' })
@ApiBearerAuth()
// @UseGuards(AuthGuard)
// @UseGuards(RoleGuard.requireds({ roles: ['admin', 'author'] }))
@UseGuards(AuthGuard)
@UseGuards(RoleGuard.requireds({ roles: ['admin', 'author'] }))
@Post('/orders')
async createOrders(
@Req() req: Request,
@ -65,8 +60,6 @@ export class LicensesController {
console.log(req.header('Authorization'));
console.log(body);
// アクセストークンにより権限を確認する
const pubKey = await this.cryptoService.getPublicKey();
const accessToken = retrieveAuthorizationToken(req);
//アクセストークンが存在しない場合のエラー
@ -76,26 +69,13 @@ export class LicensesController {
HttpStatus.UNAUTHORIZED,
);
}
const payload = verify<AccessToken>(accessToken, pubKey);
//アクセストークン形式エラー
if (isVerifyError(payload)) {
throw new HttpException(
makeErrorResponse('E000101'),
HttpStatus.UNAUTHORIZED,
);
}
//アクセストークンの権限不足エラー
if (!confirmPermission(payload.role)) {
throw new HttpException(
makeErrorResponse('E000108'),
HttpStatus.UNAUTHORIZED,
);
}
const decodedToken = decode(accessToken, {
json: true,
}) as AccessToken;
// ライセンス注文処理
await this.licensesService.licenseOrders(
payload,
decodedToken,
body.poNumber,
body.orderCount,
);

View File

@ -1,14 +1,12 @@
import { Module } from '@nestjs/common';
import { LicensesController } from './licenses.controller';
import { LicensesService } from './licenses.service';
import { CryptoModule } from '../../gateways/crypto/crypto.module';
import { UsersRepositoryModule } from '../../repositories/users/users.repository.module';
import { AccountsRepositoryModule } from '../../repositories/accounts/accounts.repository.module';
import { LicensesRepositoryModule } from '../../repositories/licenses/licenses.repository.module';
@Module({
imports: [
CryptoModule,
UsersRepositoryModule,
AccountsRepositoryModule,
LicensesRepositoryModule,

View File

@ -23,7 +23,7 @@ describe('LicensesService', () => {
accountsRepositoryMockValue,
);
const body = new CreateOrdersRequest();
const token: AccessToken = { userId: '0001', role: '' };
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
body.orderCount = 1000;
body.poNumber = '1';
expect(
@ -45,7 +45,7 @@ describe('LicensesService', () => {
accountsRepositoryMockValue,
);
const body = new CreateOrdersRequest();
const token: AccessToken = { userId: '', role: '' };
const token: AccessToken = { userId: '', role: '', tier: 5 };
body.orderCount = 1000;
body.poNumber = '1';
await expect(
@ -72,7 +72,7 @@ describe('LicensesService', () => {
accountsRepositoryMockValue,
);
const body = new CreateOrdersRequest();
const token: AccessToken = { userId: '0001', role: '' };
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
body.orderCount = 1000;
body.poNumber = '1';
await expect(
@ -97,7 +97,7 @@ describe('LicensesService', () => {
accountsRepositoryMockValue,
);
const body = new CreateOrdersRequest();
const token: AccessToken = { userId: '0001', role: '' };
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
body.orderCount = 1000;
body.poNumber = '1';
await expect(

View File

@ -5,7 +5,6 @@ import {
AdB2cService,
ConflictError,
} from '../../../gateways/adb2c/adb2c.service';
import { CryptoService } from '../../../gateways/crypto/crypto.service';
import { SendGridService } from '../../../gateways/sendgrid/sendgrid.service';
import { User } from '../../../repositories/users/entity/user.entity';
import { UsersRepositoryService } from '../../../repositories/users/users.repository.service';
@ -56,7 +55,6 @@ export type SendGridMockValue = {
};
export const makeUsersServiceMock = async (
cryptoMockValue: CryptoMockValue,
usersRepositoryMockValue: UsersRepositoryMockValue,
adB2cMockValue: AdB2cMockValue,
sendGridMockValue: SendGridMockValue,
@ -67,15 +65,12 @@ export const makeUsersServiceMock = async (
providers: [UsersService],
imports: [
ConfigModule.forRoot({
ignoreEnvFile: true,
ignoreEnvVars: true,
envFilePath: ['.env.local', '.env'],
}),
],
})
.useMocker((token) => {
switch (token) {
case CryptoService:
return makeCryptoServiceMock(cryptoMockValue);
case UsersRepositoryService:
return makeUsersRepositoryMock(usersRepositoryMockValue);
case AdB2cService:
@ -277,22 +272,6 @@ export const makeConfigMock = (value: ConfigMockValue) => {
};
};
export const makeDefaultCryptoMockValue = (): CryptoMockValue => {
return {
getPublicKey: [
'-----BEGIN PUBLIC KEY-----',
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5IZZNgDew9eGmuFTezwd',
'HYLSaJvUPPIKYoiOeVLD1paWNI517Vkaoh0ngprcKOdv6T1N07V4igK7mOim2zY3',
'yCTR6wcWR3PfFJrl9vh5SOo79koZoJb27YiM4jtxfx2dezzp0T2GoNR5rRolPUbW',
'FJXnDe0DVXYXpJLb4LAlF2XAyYX0SYKUVUsJnzm5k4xbXtnwPwVbpm0EdswBE6qS',
'fiL9zWk9dvHoKzSnfSDzDFoFcEoVchawzYXf/MM1YR4wo5XyzECc6Q5Ah4z522//',
'mBNNaDHv83Yuw3mGShT73iJ0JQdkTturshv2Ecma38r6ftrIwNYXw4VVatJM8+GO',
'OQIDAQAB',
'-----END PUBLIC KEY-----',
].join('\n'),
};
};
export const makeDefaultSendGridlValue = (): SendGridMockValue => {
return {
sendMail: undefined,

View File

@ -1,13 +1,11 @@
import { Test, TestingModule } from '@nestjs/testing';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { CryptoService } from '../../gateways/crypto/crypto.service';
import { ConfigModule } from '@nestjs/config';
describe('UsersController', () => {
let controller: UsersController;
const mockUserService = {};
const mockCryptoService = {};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
@ -18,12 +16,10 @@ describe('UsersController', () => {
}),
],
controllers: [UsersController],
providers: [UsersService, CryptoService],
providers: [UsersService],
})
.overrideProvider(UsersService)
.useValue(mockUserService)
.overrideProvider(CryptoService)
.useValue(mockCryptoService)
.compile();
controller = module.get<UsersController>(UsersController);

View File

@ -2,12 +2,12 @@ import {
Body,
Controller,
Get,
HttpException,
HttpStatus,
Post,
Req,
HttpException,
UseGuards,
Query,
Req,
UseGuards,
} from '@nestjs/common';
import {
ApiBearerAuth,
@ -16,39 +16,35 @@ import {
ApiTags,
} from '@nestjs/swagger';
import { Request } from 'express';
import { confirmPermission } from '../../common/auth/auth';
import { decode } from 'jsonwebtoken';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
import { ErrorResponse } from '../../common/error/types/types';
import { retrieveAuthorizationToken } from '../../common/http/helper';
import { isVerifyError, verify } from '../../common/jwt/jwt';
import { AccessToken } from '../../common/token';
import { CryptoService } from '../../gateways/crypto/crypto.service';
import {
ConfirmRequest,
ConfirmResponse,
GetRelationsResponse,
GetUsersResponse,
SignupRequest,
SignupResponse,
PostSortCriteriaRequest,
PostSortCriteriaResponse,
GetSortCriteriaRequest,
GetSortCriteriaResponse,
} from './types/types';
import { UsersService } from './users.service';
import jwt from 'jsonwebtoken';
import { AuthGuard } from '../../common/guards/auth/authguards';
import { RoleGuard } from '../../common/guards/role/roleguards';
import { retrieveAuthorizationToken } from '../../common/http/helper';
import { AccessToken } from '../../common/token';
import {
isSortDirection,
isTaskListSortableAttribute,
} from '../../common/types/sort';
import {
ConfirmRequest,
ConfirmResponse,
GetRelationsResponse,
GetSortCriteriaRequest,
GetSortCriteriaResponse,
GetUsersResponse,
PostSortCriteriaRequest,
PostSortCriteriaResponse,
SignupRequest,
SignupResponse,
} from './types/types';
import { UsersService } from './users.service';
@ApiTags('users')
@Controller('users')
export class UsersController {
constructor(
private readonly usersService: UsersService,
private readonly cryptoService: CryptoService,
) {}
constructor(private readonly usersService: UsersService) {}
@ApiResponse({
status: HttpStatus.OK,
@ -114,14 +110,12 @@ export class UsersController {
})
@ApiOperation({ operationId: 'getUsers' })
@ApiBearerAuth()
// @UseGuards(AuthGuard)
// @UseGuards(RoleGuard.requireds({ roles: ['admin', 'author'] }))
@UseGuards(AuthGuard)
@UseGuards(RoleGuard.requireds({ roles: ['admin', 'author'] }))
@Get()
async getUsers(@Req() req: Request): Promise<GetUsersResponse> {
console.log(req.header('Authorization'));
// アクセストークンにより権限を確認する
const pubKey = await this.cryptoService.getPublicKey();
const accessToken = retrieveAuthorizationToken(req);
// アクセストークンが存在しない場合のエラー
@ -131,25 +125,9 @@ export class UsersController {
HttpStatus.UNAUTHORIZED,
);
}
const payload = verify<AccessToken>(accessToken, pubKey);
const decodedToken = decode(accessToken, { json: true }) as AccessToken;
// アクセストークン形式エラー
if (isVerifyError(payload)) {
throw new HttpException(
makeErrorResponse('E000101'),
HttpStatus.UNAUTHORIZED,
);
}
// アクセストークンの権限不足エラー
if (!confirmPermission(payload.role)) {
throw new HttpException(
makeErrorResponse('E000108'),
HttpStatus.UNAUTHORIZED,
);
}
const users = await this.usersService.getUsers(accessToken);
const users = await this.usersService.getUsers(decodedToken);
return { users };
}
@ -175,6 +153,8 @@ export class UsersController {
})
@ApiOperation({ operationId: 'signup' })
@ApiBearerAuth()
@UseGuards(AuthGuard)
@UseGuards(RoleGuard.requireds({ roles: ['admin', 'author'] }))
@Post('/signup')
async signup(
@Req() req: Request,
@ -191,37 +171,20 @@ export class UsersController {
typistGroupId,
} = body;
// アクセストークンにより権限を確認する
const pubKey = await this.cryptoService.getPublicKey();
const accessToken = retrieveAuthorizationToken(req);
//アクセストークンが存在しない場合のエラー
// アクセストークンが存在しない場合のエラー
if (accessToken == undefined) {
throw new HttpException(
makeErrorResponse('E000107'),
HttpStatus.UNAUTHORIZED,
);
}
const payload = verify<AccessToken>(accessToken, pubKey);
//アクセストークン形式エラー
if (isVerifyError(payload)) {
throw new HttpException(
makeErrorResponse('E000101'),
HttpStatus.UNAUTHORIZED,
);
}
//アクセストークンの権限不足エラー
if (!confirmPermission(payload.role)) {
throw new HttpException(
makeErrorResponse('E000108'),
HttpStatus.UNAUTHORIZED,
);
}
const decodedToken = decode(accessToken, { json: true }) as AccessToken;
//ユーザ作成処理
await this.usersService.createUser(
payload,
decodedToken,
name,
role,
email,
@ -313,7 +276,7 @@ export class UsersController {
): Promise<PostSortCriteriaResponse> {
const { direction, paramName } = body;
const accessToken = retrieveAuthorizationToken(req);
const decodedToken = jwt.decode(accessToken, { json: true }) as AccessToken;
const decodedToken = decode(accessToken, { json: true }) as AccessToken;
//型チェック
if (
@ -361,7 +324,7 @@ export class UsersController {
): Promise<GetSortCriteriaResponse> {
const {} = query;
const accessToken = retrieveAuthorizationToken(req);
const decodedToken = jwt.decode(accessToken, { json: true }) as AccessToken;
const decodedToken = decode(accessToken, { json: true }) as AccessToken;
const { direction, paramName } = await this.usersService.getSortCriteria(
decodedToken,

View File

@ -1,16 +1,14 @@
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AdB2cModule } from '../../gateways/adb2c/adb2c.module';
import { CryptoModule } from '../../gateways/crypto/crypto.module';
import { SendGridModule } from '../../gateways/sendgrid/sendgrid.module';
import { SortCriteriaRepositoryModule } from '../../repositories/sort_criteria/sort_criteria.repository.module';
import { UsersRepositoryModule } from '../../repositories/users/users.repository.module';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { SortCriteriaRepositoryModule } from '../../repositories/sort_criteria/sort_criteria.repository.module';
@Module({
imports: [
CryptoModule,
UsersRepositoryModule,
SortCriteriaRepositoryModule,
AdB2cModule,

View File

@ -6,7 +6,6 @@ import { EmailAlreadyVerifiedError } from '../../repositories/users/users.reposi
import {
makeDefaultAdB2cMockValue,
makeDefaultConfigValue,
makeDefaultCryptoMockValue,
makeDefaultSendGridlValue,
makeDefaultSortCriteriaRepositoryMockValue,
makeDefaultUsersRepositoryMockValue,
@ -16,7 +15,6 @@ import { User } from './types/types';
describe('UsersService', () => {
it('ユーザの仮登録時に払い出されるトークンにより、未認証のユーザが認証済みになる', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendGridMockValue = makeDefaultSendGridlValue();
@ -24,7 +22,6 @@ describe('UsersService', () => {
const sortCriteriaRepositoryMockValue =
makeDefaultSortCriteriaRepositoryMockValue();
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendGridMockValue,
@ -37,7 +34,6 @@ describe('UsersService', () => {
});
it('ユーザーが発行されたパスワードでログインできるようにする', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
usersRepositoryMockValue.findUserById = {
id: 1,
@ -60,7 +56,6 @@ describe('UsersService', () => {
makeDefaultSortCriteriaRepositoryMockValue();
const sendGridMockValue = makeDefaultSendGridlValue();
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendGridMockValue,
@ -74,7 +69,6 @@ describe('UsersService', () => {
});
it('トークンの形式が不正な場合、形式不正エラーとなる。', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -82,7 +76,6 @@ describe('UsersService', () => {
const sortCriteriaRepositoryMockValue =
makeDefaultSortCriteriaRepositoryMockValue();
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -96,7 +89,6 @@ describe('UsersService', () => {
});
it('トークンの形式が不正な場合、形式不正エラーとなる。(メール認証API)', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
usersRepositoryMockValue.findUserById = {
id: 1,
@ -119,7 +111,6 @@ describe('UsersService', () => {
const sortCriteriaRepositoryMockValue =
makeDefaultSortCriteriaRepositoryMockValue();
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendGridMockValue,
@ -132,7 +123,6 @@ describe('UsersService', () => {
);
});
it('ユーザが既に認証済みだった場合、認証済みユーザエラーとなる。', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -144,7 +134,6 @@ describe('UsersService', () => {
new EmailAlreadyVerifiedError();
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -158,7 +147,6 @@ describe('UsersService', () => {
);
});
it('ユーザが既に認証済みだった場合、認証済みユーザエラーとなる。(メール認証API)', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
usersRepositoryMockValue.findUserById = {
id: 1,
@ -184,7 +172,6 @@ describe('UsersService', () => {
new EmailAlreadyVerifiedError();
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendGridMockValue,
@ -198,7 +185,6 @@ describe('UsersService', () => {
);
});
it('DBネットワークエラーとなる場合、エラーとなる。', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -208,7 +194,6 @@ describe('UsersService', () => {
usersRepositoryMockValue.updateUserVerified = new Error('DB error');
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -225,7 +210,6 @@ describe('UsersService', () => {
);
});
it('DBネットワークエラーとなる場合、エラーとなる。(メール認証API)', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
usersRepositoryMockValue.findUserById = {
id: 1,
@ -249,7 +233,6 @@ describe('UsersService', () => {
const sortCriteriaRepositoryMockValue =
makeDefaultSortCriteriaRepositoryMockValue();
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendGridMockValue,
@ -266,7 +249,6 @@ describe('UsersService', () => {
);
});
it('管理者権限のあるアクセストークンを使用して、新規ユーザが追加される(role:None)', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -274,7 +256,6 @@ describe('UsersService', () => {
const sortCriteriaRepositoryMockValue =
makeDefaultSortCriteriaRepositoryMockValue();
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -287,7 +268,7 @@ describe('UsersService', () => {
const autoRenew = true;
const licenseAlert = true;
const notification = true;
const token: AccessToken = { userId: '0001', role: '' };
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
expect(
await service.createUser(
token,
@ -304,7 +285,6 @@ describe('UsersService', () => {
describe('UsersService', () => {
it('管理者権限のあるアクセストークンを使用して、新規ユーザが追加される(role:Author)', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -312,7 +292,6 @@ describe('UsersService', () => {
const sortCriteriaRepositoryMockValue =
makeDefaultSortCriteriaRepositoryMockValue();
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -326,7 +305,7 @@ describe('UsersService', () => {
const licenseAlert = true;
const notification = true;
const authorId = 'testID';
const token: AccessToken = { userId: '0001', role: '' };
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
expect(
await service.createUser(
token,
@ -344,7 +323,6 @@ describe('UsersService', () => {
describe('UsersService', () => {
it('管理者権限のあるアクセストークンを使用して、新規ユーザが追加される(role:Transcriptioninst)', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -352,7 +330,6 @@ describe('UsersService', () => {
const sortCriteriaRepositoryMockValue =
makeDefaultSortCriteriaRepositoryMockValue();
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -366,7 +343,7 @@ describe('UsersService', () => {
const licenseAlert = true;
const notification = true;
const typistGroupId = 111;
const token: AccessToken = { userId: '0001', role: '' };
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
expect(
await service.createUser(
token,
@ -384,7 +361,6 @@ describe('UsersService', () => {
});
it('DBネットワークエラーとなる場合、エラーとなる。', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -393,7 +369,6 @@ it('DBネットワークエラーとなる場合、エラーとなる。', async
makeDefaultSortCriteriaRepositoryMockValue();
usersRepositoryMockValue.createNormalUser = new Error('DB error');
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -406,7 +381,7 @@ it('DBネットワークエラーとなる場合、エラーとなる。', async
const autoRenew = true;
const licenseAlert = true;
const notification = true;
const token: AccessToken = { userId: '0001', role: '' };
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
await expect(
service.createUser(
token,
@ -425,7 +400,6 @@ it('DBネットワークエラーとなる場合、エラーとなる。', async
);
});
it('Azure ADB2Cでネットワークエラーとなる場合、エラーとなる。', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
adb2cParam.createUser = new Error();
@ -434,7 +408,6 @@ it('Azure ADB2Cでネットワークエラーとなる場合、エラーとな
const sortCriteriaRepositoryMockValue =
makeDefaultSortCriteriaRepositoryMockValue();
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -447,7 +420,7 @@ it('Azure ADB2Cでネットワークエラーとなる場合、エラーとな
const autoRenew = true;
const licenseAlert = true;
const notification = true;
const token: AccessToken = { userId: '0001', role: '' };
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
await expect(
service.createUser(
token,
@ -466,7 +439,6 @@ it('Azure ADB2Cでネットワークエラーとなる場合、エラーとな
);
});
it('メールアドレスが重複している場合、エラーとなる。', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
adb2cParam.createUser = { reason: 'email', message: 'ObjectConflict' };
@ -475,7 +447,6 @@ it('メールアドレスが重複している場合、エラーとなる。', a
const sortCriteriaRepositoryMockValue =
makeDefaultSortCriteriaRepositoryMockValue();
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -488,7 +459,7 @@ it('メールアドレスが重複している場合、エラーとなる。', a
const autoRenew = true;
const licenseAlert = true;
const notification = true;
const token: AccessToken = { userId: '0001', role: '' };
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
await expect(
service.createUser(
token,
@ -504,7 +475,6 @@ it('メールアドレスが重複している場合、エラーとなる。', a
);
});
it('AuthorIDが重複している場合、エラーとなる。(AuthorID重複チェックでエラー)', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -515,7 +485,6 @@ it('AuthorIDが重複している場合、エラーとなる。(AuthorID重複
usersRepositoryMockValue.existsAuthorId = true;
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -529,7 +498,7 @@ it('AuthorIDが重複している場合、エラーとなる。(AuthorID重複
const licenseAlert = true;
const notification = true;
const authorId = 'testID';
const token: AccessToken = { userId: '0001', role: '' };
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
await expect(
service.createUser(
token,
@ -546,7 +515,6 @@ it('AuthorIDが重複している場合、エラーとなる。(AuthorID重複
);
});
it('AuthorIDが重複している場合、エラーとなる。(insert失敗)', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -557,7 +525,6 @@ it('AuthorIDが重複している場合、エラーとなる。(insert失敗)',
usersRepositoryMockValue.createNormalUser.name = 'ER_DUP_ENTRY';
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -571,7 +538,7 @@ it('AuthorIDが重複している場合、エラーとなる。(insert失敗)',
const licenseAlert = true;
const notification = true;
const authorId = 'testID';
const token: AccessToken = { userId: '0001', role: '' };
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
await expect(
service.createUser(
token,
@ -589,7 +556,6 @@ it('AuthorIDが重複している場合、エラーとなる。(insert失敗)',
});
it('ユーザの一覧を取得する', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -597,17 +563,16 @@ it('ユーザの一覧を取得する', async () => {
const sortCriteriaRepositoryMockValue =
makeDefaultSortCriteriaRepositoryMockValue();
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
configMockValue,
sortCriteriaRepositoryMockValue,
);
const token =
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw';
expect(await service.getUsers(token)).toEqual(expectedUsers);
expect(
await service.getUsers({ role: 'Admin', userId: 'XXXXXX', tier: 5 }),
).toEqual(expectedUsers);
});
const expectedUsers = [
@ -636,7 +601,6 @@ const expectedUsers = [
];
it('ユーザの一覧を取得に失敗する', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -648,7 +612,6 @@ it('ユーザの一覧を取得に失敗する', async () => {
);
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -656,16 +619,14 @@ it('ユーザの一覧を取得に失敗する', async () => {
sortCriteriaRepositoryMockValue,
);
const token =
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw';
await expect(service.getUsers(token)).rejects.toEqual(
await expect(
service.getUsers({ role: 'Admin', userId: 'XXXXXX', tier: 5 }),
).rejects.toEqual(
new HttpException(makeErrorResponse('E009999'), HttpStatus.NOT_FOUND),
);
});
it('ユーザの一覧を0件取得する', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -678,7 +639,6 @@ it('ユーザの一覧を0件取得する', async () => {
usersRepositoryMockValue.findSameAccountUsers = noDbUsers;
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -686,15 +646,13 @@ it('ユーザの一覧を0件取得する', async () => {
sortCriteriaRepositoryMockValue,
);
const token =
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw';
const emptyMergedUsers: User[] = [];
expect(await service.getUsers(token)).toEqual(emptyMergedUsers);
expect(
await service.getUsers({ role: 'Admin', userId: 'XXXXXX', tier: 5 }),
).toEqual(emptyMergedUsers);
});
it('ソート条件を変更できる', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -702,7 +660,6 @@ it('ソート条件を変更できる', async () => {
const sortCriteriaRepositoryMockValue =
makeDefaultSortCriteriaRepositoryMockValue();
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -714,12 +671,12 @@ it('ソート条件を変更できる', async () => {
await service.updateSortCriteria('AUTHOR_ID', 'ASC', {
role: 'none admin',
userId: 'xxxxxxxxxxxx',
tier: 5,
}),
).toEqual(undefined);
});
it('ユーザー情報が存在せず、ソート条件を変更できない', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -730,7 +687,6 @@ it('ユーザー情報が存在せず、ソート条件を変更できない', a
usersRepositoryMockValue.findUserByExternalId = new Error('user not found');
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -742,6 +698,7 @@ it('ユーザー情報が存在せず、ソート条件を変更できない', a
service.updateSortCriteria('AUTHOR_ID', 'ASC', {
role: 'none admin',
userId: 'xxxxxxxxxxxx',
tier: 5,
}),
).rejects.toEqual(
new HttpException(
@ -752,7 +709,6 @@ it('ユーザー情報が存在せず、ソート条件を変更できない', a
});
it('ソート条件が存在せず、ソート条件を変更できない', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -764,7 +720,6 @@ it('ソート条件が存在せず、ソート条件を変更できない', asyn
);
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -776,6 +731,7 @@ it('ソート条件が存在せず、ソート条件を変更できない', asyn
service.updateSortCriteria('AUTHOR_ID', 'ASC', {
role: 'none admin',
userId: 'xxxxxxxxxxxx',
tier: 5,
}),
).rejects.toEqual(
new HttpException(
@ -786,7 +742,6 @@ it('ソート条件が存在せず、ソート条件を変更できない', asyn
});
it('ソート条件を取得できる', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -794,7 +749,6 @@ it('ソート条件を取得できる', async () => {
const sortCriteriaRepositoryMockValue =
makeDefaultSortCriteriaRepositoryMockValue();
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -806,12 +760,12 @@ it('ソート条件を取得できる', async () => {
await service.getSortCriteria({
role: 'none admin',
userId: 'xxxxxxxxxxxx',
tier: 5,
}),
).toEqual({ direction: 'ASC', paramName: 'JOB_NUMBER' });
});
it('ソート条件が存在せず、ソート条件を取得できない', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -824,7 +778,6 @@ it('ソート条件が存在せず、ソート条件を取得できない', asyn
);
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -836,6 +789,7 @@ it('ソート条件が存在せず、ソート条件を取得できない', asyn
service.getSortCriteria({
role: 'none admin',
userId: 'xxxxxxxxxxxx',
tier: 5,
}),
).rejects.toEqual(
new HttpException(
@ -846,7 +800,6 @@ it('ソート条件が存在せず、ソート条件を取得できない', asyn
});
it('DBから取得した値が不正だった場合、エラーとなる', async () => {
const cryptoMockValue = makeDefaultCryptoMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
const adb2cParam = makeDefaultAdB2cMockValue();
const sendgridMockValue = makeDefaultSendGridlValue();
@ -861,7 +814,6 @@ it('DBから取得した値が不正だった場合、エラーとなる', async
};
const service = await makeUsersServiceMock(
cryptoMockValue,
usersRepositoryMockValue,
adb2cParam,
sendgridMockValue,
@ -873,6 +825,7 @@ it('DBから取得した値が不正だった場合、エラーとなる', async
service.getSortCriteria({
role: 'none admin',
userId: 'xxxxxxxxxxxx',
tier: 5,
}),
).rejects.toEqual(
new HttpException(

View File

@ -2,20 +2,20 @@ import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
import { isVerifyError, verify } from '../../common/jwt';
import { getPublicKey } from '../../common/jwt/jwt';
import { makePassword } from '../../common/password/password';
import { AccessToken } from '../../common/token';
import {
TaskListSortableAttribute,
SortDirection,
isTaskListSortableAttribute,
TaskListSortableAttribute,
isSortDirection,
isTaskListSortableAttribute,
} from '../../common/types/sort';
import {
AdB2cService,
ConflictError,
isConflictError,
} from '../../gateways/adb2c/adb2c.service';
import { CryptoService } from '../../gateways/crypto/crypto.service';
import { SendGridService } from '../../gateways/sendgrid/sendgrid.service';
import { SortCriteriaRepositoryService } from '../../repositories/sort_criteria/sort_criteria.repository.service';
import { User as EntityUser } from '../../repositories/users/entity/user.entity';
@ -28,7 +28,6 @@ import { User } from './types/types';
@Injectable()
export class UsersService {
constructor(
private readonly cryptoService: CryptoService,
private readonly usersRepository: UsersRepositoryService,
private readonly sortCriteriaRepository: SortCriteriaRepositoryService,
private readonly adB2cService: AdB2cService,
@ -43,8 +42,7 @@ export class UsersService {
*/
async confirmUser(token: string): Promise<void> {
this.logger.log(`[IN] ${this.confirmUser.name}`);
const pubKey = await this.cryptoService.getPublicKey();
const pubKey = getPublicKey(this.configService);
const decodedToken = verify<{
accountId: number;
@ -236,7 +234,8 @@ export class UsersService {
async confirmUserAndInitPassword(token: string): Promise<void> {
this.logger.log(`[IN] ${this.confirmUserAndInitPassword.name}`);
const pubKey = await this.cryptoService.getPublicKey();
const pubKey = getPublicKey(this.configService);
const decodedToken = verify<{
accountId: number;
userId: number;
@ -295,20 +294,13 @@ export class UsersService {
* @param accessToken
* @returns users
*/
async getUsers(accessToken: string): Promise<User[]> {
async getUsers(accessToken: AccessToken): Promise<User[]> {
this.logger.log(`[IN] ${this.getUsers.name}`);
try {
// DBよりアクセス者の所属するアカウントを取得する
const pubKey = await this.cryptoService.getPublicKey();
const payload = verify<AccessToken>(accessToken, pubKey);
if (isVerifyError(payload)) {
throw new Error(`${payload.reason} | ${payload.message}`);
}
// DBから同一アカウントのユーザ一覧を取得する
const dbUsers = await this.usersRepository.findSameAccountUsers(
payload.userId,
accessToken.userId,
);
// 値をマージして定義されたレスポンス通りに返す

View File

@ -1,10 +0,0 @@
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { CryptoService } from './crypto.service';
@Module({
imports: [ConfigModule],
exports: [CryptoService],
providers: [CryptoService],
})
export class CryptoModule {}

View File

@ -1,74 +0,0 @@
import { DefaultAzureCredential } from '@azure/identity';
import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import jwkToPem from 'jwk-to-pem';
import { JwkSignKey } from '../../common/token';
@Injectable()
export class CryptoService {
private readonly logger = new Logger(CryptoService.name);
private readonly credential: DefaultAzureCredential;
private readonly url: string;
constructor(private readonly configService: ConfigService) {}
/**
* Gets private key
* @returns private key(PEM)
*/
async getPrivateKey(): Promise<string> {
try {
const key = this.configService.get<string>('JWT_PRIVATE_KEY');
if (key) {
// 開発環境用に改行コードを置換する
// 本番環境では\\nが含まれないため、置換が行われない想定
return key.replace('\\n', '\n');
}
throw new Error(`JWT_PRIVATE_KEY not found.`);
} catch (e) {
this.logger.error(`error=${e}`);
throw e;
} finally {
this.logger.log(`[OUT] ${this.getPrivateKey.name}`);
}
}
/**
* Gets public key
* @returns public key(PEM)
*/
async getPublicKey(): Promise<string> {
try {
const key = this.configService.get<string>('JWT_PUBLIC_KEY');
if (key) {
// 開発環境用に改行コードを置換する
// 本番環境では\\nが含まれないため、置換が行われない想定
return key.replace('\\n', '\n');
}
throw new Error(`JWT_PUBLIC_KEY not found.`);
} catch (e) {
this.logger.error(`error=${e}`);
throw e;
} finally {
this.logger.log(`[OUT] ${this.getPublicKey.name}`);
}
}
async getPublicKeyFromJwk(jwkKey: JwkSignKey): Promise<string> {
try {
// JWK形式のJSONなのでJWTの公開鍵として使えるようにPEM形式に変換
const publicKey = jwkToPem({
kty: 'RSA',
n: jwkKey.n,
e: jwkKey.e,
});
return publicKey;
} catch (e) {
this.logger.error(`error=${e}`);
throw e;
} finally {
this.logger.log(`[OUT] ${this.getPublicKey.name}`);
}
}
}

View File

@ -2,6 +2,7 @@ import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { sign } from '../../common/jwt';
import sendgrid from '@sendgrid/mail';
import { getPrivateKey } from '../../common/jwt/jwt';
@Injectable()
export class SendGridService {
@ -25,9 +26,7 @@ export class SendGridService {
): Promise<{ subject: string; text: string; html: string }> {
const lifetime =
this.configService.get<number>('EMAIL_CONFIRM_LIFETIME') ?? 0;
const privateKey =
this.configService.get<string>('JWT_PRIVATE_KEY')?.replace('\\n', '\n') ??
'';
const privateKey = getPrivateKey(this.configService);
const token = sign<{ accountId: number; userId: number; email: string }>(
{
accountId,
@ -62,9 +61,9 @@ export class SendGridService {
): Promise<{ subject: string; text: string; html: string }> {
const lifetime =
this.configService.get<number>('EMAIL_CONFIRM_LIFETIME') ?? 0;
const privateKey =
this.configService.get<string>('JWT_PRIVATE_KEY')?.replace('\\n', '\n') ??
'';
const privateKey = getPrivateKey(this.configService);
const token = sign<{ accountId: number; userId: number; email: string }>(
{
accountId,