Merged PR 1: タスク 1359: API実装(認証/IDトークン検証)
## 概要 [タスク 1359: API実装(認証/IDトークン検証)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/OMDSDictation/_workitems/edit/1359) - IDトークンを受け取って内容を検証し、デコードしたペイロードを返すサービスを実装しました。 ## レビューポイント - サービスの処理の流れが認識とあっているか。 - ADB2CのAPI呼び出しを別サービスにしているが問題ないか - 公開鍵の変換処理を別サービスに切り出しているが構成に問題はないか。 - トークンの検証をエラーごとに処理しているがエラー内容は認識通りか ## UIの変更 - なし ## 動作確認状況 - テストが通ることを確認 # 備考 - IDトークンを検証して中身を返すまでの実装です。
This commit is contained in:
parent
bf7a985b0d
commit
41f0213fe9
@ -5,4 +5,6 @@ DB_NAME=omds
|
||||
DB_ROOT_PASS=omdsdbpass
|
||||
DB_USERNAME=omdsdbuser
|
||||
DB_PASSWORD=omdsdbpass
|
||||
NO_COLOR=TRUE
|
||||
NO_COLOR=TRUE
|
||||
TENANT_NAME=adb2codmsdev
|
||||
SIGNIN_FLOW_NAME=b2c_1_signin_dev
|
||||
334
dictation_server/package-lock.json
generated
334
dictation_server/package-lock.json
generated
@ -9,7 +9,6 @@
|
||||
"version": "0.0.1",
|
||||
"license": "UNLICENSED",
|
||||
"dependencies": {
|
||||
"@nestjs/axios": "^0.1.0",
|
||||
"@nestjs/common": "^8.0.0",
|
||||
"@nestjs/config": "^2.2.0",
|
||||
"@nestjs/core": "^8.0.0",
|
||||
@ -17,12 +16,16 @@
|
||||
"@nestjs/serve-static": "^2.2.2",
|
||||
"@nestjs/typeorm": "^9.0.1",
|
||||
"@openapitools/openapi-generator-cli": "^2.5.1",
|
||||
"@types/jsonwebtoken": "^9.0.1",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"axios": "^1.3.4",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.0",
|
||||
"connect-redis": "^6.1.3",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"express-session": "^1.17.3",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"jwk-to-pem": "^2.0.5",
|
||||
"mysql2": "^2.3.3",
|
||||
"redis": "^4.2.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
@ -40,10 +43,13 @@
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/express-session": "^1.17.5",
|
||||
"@types/jest": "27.5.0",
|
||||
"@types/jsonwebtoken": "^9.0.1",
|
||||
"@types/jwk-to-pem": "^2.0.1",
|
||||
"@types/node": "^16.0.0",
|
||||
"@types/supertest": "^2.0.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
||||
"@typescript-eslint/parser": "^5.0.0",
|
||||
"base64url": "^3.0.1",
|
||||
"eslint": "^8.0.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
@ -1460,19 +1466,6 @@
|
||||
"integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@nestjs/axios": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-0.1.1.tgz",
|
||||
"integrity": "sha512-rLEq6yfho2CZyOcxP+P4Q3FjkNuiiHDyzj3Cr9i4Kdn3Ng09ygtOB4++jjXPREc6650pOFfzNtw18QH7bfLnQA==",
|
||||
"dependencies": {
|
||||
"axios": "1.2.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^7.0.0 || ^8.0.0 || ^9.0.0",
|
||||
"reflect-metadata": "^0.1.12",
|
||||
"rxjs": "^6.0.0 || ^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/cli": {
|
||||
"version": "8.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-8.2.8.tgz",
|
||||
@ -2561,6 +2554,21 @@
|
||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/jsonwebtoken": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz",
|
||||
"integrity": "sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/jwk-to-pem": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/jwk-to-pem/-/jwk-to-pem-2.0.1.tgz",
|
||||
"integrity": "sha512-QXmRPhR/LPzvXBHTPfG2BBfMTkNLUD7NyRcPft8m5xFCeANa1BZyLgT0Gw+OxdWx6i1WCpT27EqyggP4UUHMrA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/mime": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
|
||||
@ -3243,15 +3251,26 @@
|
||||
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/asn1.js": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
|
||||
"integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
|
||||
"dependencies": {
|
||||
"bn.js": "^4.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"minimalistic-assert": "^1.0.0",
|
||||
"safer-buffer": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.1.tgz",
|
||||
"integrity": "sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==",
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz",
|
||||
"integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
@ -3373,6 +3392,15 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/base64url": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz",
|
||||
"integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
@ -3428,6 +3456,11 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/bn.js": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz",
|
||||
@ -3485,6 +3518,11 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/brorand": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
|
||||
"integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w=="
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.21.4",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
|
||||
@ -3534,6 +3572,11 @@
|
||||
"node-int64": "^0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-equal-constant-time": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
|
||||
},
|
||||
"node_modules/buffer-from": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||
@ -4367,6 +4410,14 @@
|
||||
"wcwidth": ">=1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ecdsa-sig-formatter": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
@ -4378,6 +4429,20 @@
|
||||
"integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/elliptic": {
|
||||
"version": "6.5.4",
|
||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
|
||||
"integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
|
||||
"dependencies": {
|
||||
"bn.js": "^4.11.9",
|
||||
"brorand": "^1.1.0",
|
||||
"hash.js": "^1.0.0",
|
||||
"hmac-drbg": "^1.0.1",
|
||||
"inherits": "^2.0.4",
|
||||
"minimalistic-assert": "^1.0.1",
|
||||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/emittery": {
|
||||
"version": "0.10.2",
|
||||
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz",
|
||||
@ -5563,6 +5628,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hash.js": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
|
||||
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"minimalistic-assert": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hexoid": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
|
||||
@ -5580,6 +5654,16 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/hmac-drbg": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||
"integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==",
|
||||
"dependencies": {
|
||||
"hash.js": "^1.0.3",
|
||||
"minimalistic-assert": "^1.0.0",
|
||||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hosted-git-info": {
|
||||
"version": "2.8.9",
|
||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
|
||||
@ -7038,6 +7122,50 @@
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonwebtoken": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
|
||||
"integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==",
|
||||
"dependencies": {
|
||||
"jws": "^3.2.2",
|
||||
"lodash": "^4.17.21",
|
||||
"ms": "^2.1.1",
|
||||
"semver": "^7.3.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"npm": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/jwa": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
|
||||
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
|
||||
"dependencies": {
|
||||
"buffer-equal-constant-time": "1.0.1",
|
||||
"ecdsa-sig-formatter": "1.0.11",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/jwk-to-pem": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz",
|
||||
"integrity": "sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==",
|
||||
"dependencies": {
|
||||
"asn1.js": "^5.3.0",
|
||||
"elliptic": "^6.5.4",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/jws": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
||||
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
||||
"dependencies": {
|
||||
"jwa": "^1.4.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/kleur": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
||||
@ -7419,6 +7547,16 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/minimalistic-assert": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
|
||||
},
|
||||
"node_modules/minimalistic-crypto-utils": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
|
||||
"integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg=="
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
@ -8624,7 +8762,6 @@
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
@ -8639,7 +8776,6 @@
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
@ -8650,8 +8786,7 @@
|
||||
"node_modules/semver/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "0.18.0",
|
||||
@ -11560,14 +11695,6 @@
|
||||
"integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
|
||||
"dev": true
|
||||
},
|
||||
"@nestjs/axios": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-0.1.1.tgz",
|
||||
"integrity": "sha512-rLEq6yfho2CZyOcxP+P4Q3FjkNuiiHDyzj3Cr9i4Kdn3Ng09ygtOB4++jjXPREc6650pOFfzNtw18QH7bfLnQA==",
|
||||
"requires": {
|
||||
"axios": "1.2.1"
|
||||
}
|
||||
},
|
||||
"@nestjs/cli": {
|
||||
"version": "8.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-8.2.8.tgz",
|
||||
@ -12389,6 +12516,21 @@
|
||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/jsonwebtoken": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz",
|
||||
"integrity": "sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/jwk-to-pem": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/jwk-to-pem/-/jwk-to-pem-2.0.1.tgz",
|
||||
"integrity": "sha512-QXmRPhR/LPzvXBHTPfG2BBfMTkNLUD7NyRcPft8m5xFCeANa1BZyLgT0Gw+OxdWx6i1WCpT27EqyggP4UUHMrA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/mime": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
|
||||
@ -12913,15 +13055,26 @@
|
||||
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
|
||||
"dev": true
|
||||
},
|
||||
"asn1.js": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
|
||||
"integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
|
||||
"requires": {
|
||||
"bn.js": "^4.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"minimalistic-assert": "^1.0.0",
|
||||
"safer-buffer": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.1.tgz",
|
||||
"integrity": "sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==",
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz",
|
||||
"integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
@ -13008,6 +13161,12 @@
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
|
||||
},
|
||||
"base64url": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz",
|
||||
"integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==",
|
||||
"dev": true
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
@ -13045,6 +13204,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"bn.js": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
|
||||
},
|
||||
"body-parser": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz",
|
||||
@ -13097,6 +13261,11 @@
|
||||
"fill-range": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"brorand": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
|
||||
"integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w=="
|
||||
},
|
||||
"browserslist": {
|
||||
"version": "4.21.4",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
|
||||
@ -13127,6 +13296,11 @@
|
||||
"node-int64": "^0.4.0"
|
||||
}
|
||||
},
|
||||
"buffer-equal-constant-time": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
|
||||
},
|
||||
"buffer-from": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||
@ -13734,6 +13908,14 @@
|
||||
"wcwidth": ">=1.0.1"
|
||||
}
|
||||
},
|
||||
"ecdsa-sig-formatter": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||
"requires": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
@ -13745,6 +13927,20 @@
|
||||
"integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
|
||||
"dev": true
|
||||
},
|
||||
"elliptic": {
|
||||
"version": "6.5.4",
|
||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
|
||||
"integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
|
||||
"requires": {
|
||||
"bn.js": "^4.11.9",
|
||||
"brorand": "^1.1.0",
|
||||
"hash.js": "^1.0.0",
|
||||
"hmac-drbg": "^1.0.1",
|
||||
"inherits": "^2.0.4",
|
||||
"minimalistic-assert": "^1.0.1",
|
||||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"emittery": {
|
||||
"version": "0.10.2",
|
||||
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz",
|
||||
@ -14638,6 +14834,15 @@
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
|
||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
|
||||
},
|
||||
"hash.js": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
|
||||
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"minimalistic-assert": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"hexoid": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
|
||||
@ -14649,6 +14854,16 @@
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
|
||||
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="
|
||||
},
|
||||
"hmac-drbg": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||
"integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==",
|
||||
"requires": {
|
||||
"hash.js": "^1.0.3",
|
||||
"minimalistic-assert": "^1.0.0",
|
||||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"hosted-git-info": {
|
||||
"version": "2.8.9",
|
||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
|
||||
@ -15770,6 +15985,46 @@
|
||||
"universalify": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"jsonwebtoken": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
|
||||
"integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==",
|
||||
"requires": {
|
||||
"jws": "^3.2.2",
|
||||
"lodash": "^4.17.21",
|
||||
"ms": "^2.1.1",
|
||||
"semver": "^7.3.8"
|
||||
}
|
||||
},
|
||||
"jwa": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
|
||||
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
|
||||
"requires": {
|
||||
"buffer-equal-constant-time": "1.0.1",
|
||||
"ecdsa-sig-formatter": "1.0.11",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"jwk-to-pem": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz",
|
||||
"integrity": "sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==",
|
||||
"requires": {
|
||||
"asn1.js": "^5.3.0",
|
||||
"elliptic": "^6.5.4",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"jws": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
||||
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
||||
"requires": {
|
||||
"jwa": "^1.4.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"kleur": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
||||
@ -16065,6 +16320,16 @@
|
||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
||||
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
|
||||
},
|
||||
"minimalistic-assert": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
|
||||
},
|
||||
"minimalistic-crypto-utils": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
|
||||
"integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg=="
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
@ -16968,7 +17233,6 @@
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
@ -16977,7 +17241,6 @@
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
@ -16985,8 +17248,7 @@
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -25,7 +25,6 @@
|
||||
"swgbundle:sentinel": "swagger-cli bundle -o openapi/build/bundle.yml -t yaml openapi/sentinel_ems/sentinel_ems.yml"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/axios": "^0.1.0",
|
||||
"@nestjs/common": "^8.0.0",
|
||||
"@nestjs/config": "^2.2.0",
|
||||
"@nestjs/core": "^8.0.0",
|
||||
@ -33,12 +32,16 @@
|
||||
"@nestjs/serve-static": "^2.2.2",
|
||||
"@nestjs/typeorm": "^9.0.1",
|
||||
"@openapitools/openapi-generator-cli": "^2.5.1",
|
||||
"@types/jsonwebtoken": "^9.0.1",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"axios": "^1.3.4",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.0",
|
||||
"connect-redis": "^6.1.3",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"express-session": "^1.17.3",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"jwk-to-pem": "^2.0.5",
|
||||
"mysql2": "^2.3.3",
|
||||
"redis": "^4.2.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
@ -56,10 +59,13 @@
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/express-session": "^1.17.5",
|
||||
"@types/jest": "27.5.0",
|
||||
"@types/jsonwebtoken": "^9.0.1",
|
||||
"@types/jwk-to-pem": "^2.0.1",
|
||||
"@types/node": "^16.0.0",
|
||||
"@types/supertest": "^2.0.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
||||
"@typescript-eslint/parser": "^5.0.0",
|
||||
"base64url": "^3.0.1",
|
||||
"eslint": "^8.0.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
|
||||
@ -6,6 +6,9 @@ import { join } from 'path';
|
||||
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';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -17,6 +20,8 @@ import { AuthController } from './features/auth/auth.controller';
|
||||
isGlobal: true,
|
||||
}),
|
||||
AuthModule,
|
||||
CryptoModule,
|
||||
AdB2cModule,
|
||||
// TypeOrmModule.forRootAsync({
|
||||
// imports: [ConfigModule],
|
||||
// useFactory: async (configService: ConfigService) => ({
|
||||
@ -33,7 +38,7 @@ import { AuthController } from './features/auth/auth.controller';
|
||||
// }),
|
||||
],
|
||||
controllers: [HealthController, AuthController],
|
||||
providers: [],
|
||||
providers: [AuthService],
|
||||
})
|
||||
export class AppModule {
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
|
||||
@ -1,4 +1,22 @@
|
||||
//TODO 仮のエラーコード作成
|
||||
/*
|
||||
エラーコード作成方針
|
||||
E+6桁(数字)で構成する。
|
||||
- 1~2桁目の値は種類(業務エラー、システムエラー...)
|
||||
- 3~4桁目の値は原因箇所(トークン、DB、...)
|
||||
- 5~6桁目の値は任意の重複しない値
|
||||
ex)
|
||||
E00XXXX : システムエラー(通信エラーやDB接続失敗など)
|
||||
E01XXXX : 業務エラー
|
||||
EXX00XX : 内部エラー(内部プログラムのエラー)
|
||||
EXX01XX : トークンエラー(トークン認証関連)
|
||||
EXX02XX : DBエラー(DB関連)
|
||||
*/
|
||||
export const ErrorCodes = [
|
||||
'E009999', // 汎用エラー
|
||||
'E000101', // トークン形式不正エラー
|
||||
'E000102', // トークン有効期限切れエラー
|
||||
'E000103', // トークン非アクティブエラー
|
||||
'E000104', // トークン署名エラー
|
||||
'E000105', // トークン発行元エラー
|
||||
'E000106', // トークンアルゴリズムエラー
|
||||
] as const;
|
||||
|
||||
@ -2,5 +2,11 @@ import { Errors } from './types/types';
|
||||
|
||||
// エラーコードとメッセージ対応表
|
||||
export const errors: Errors = {
|
||||
E009999: 'Internal Server Error',
|
||||
E009999: 'Internal Server Error.',
|
||||
E000101: 'Token invalid format Error.',
|
||||
E000102: 'Token expired Error.',
|
||||
E000103: 'Token not before Error',
|
||||
E000104: 'Token invalid signature Error.',
|
||||
E000105: 'Token invalid issuer Error.',
|
||||
E000106: 'Token invalid algorithm Error.',
|
||||
};
|
||||
|
||||
20
dictation_server/src/common/token/index.ts
Normal file
20
dictation_server/src/common/token/index.ts
Normal file
@ -0,0 +1,20 @@
|
||||
export type RefreshToken = {
|
||||
scope: string;
|
||||
};
|
||||
|
||||
export type AccessToken = {
|
||||
scope: string;
|
||||
};
|
||||
|
||||
export type B2cMetadata = {
|
||||
issuer: string;
|
||||
};
|
||||
|
||||
export type JwkSignKey = {
|
||||
kid: string;
|
||||
nbf: number;
|
||||
use: string;
|
||||
kty: string;
|
||||
e: string;
|
||||
n: string;
|
||||
};
|
||||
@ -1,5 +1,10 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AuthController } from './auth.controller';
|
||||
import { AuthService } from './auth.service';
|
||||
import {
|
||||
makeAdB2cServiceMock,
|
||||
makeDefaultAdB2cMockValue,
|
||||
} from './test/auth.service.mock';
|
||||
|
||||
describe('AuthController', () => {
|
||||
let controller: AuthController;
|
||||
@ -7,7 +12,10 @@ describe('AuthController', () => {
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [AuthController],
|
||||
}).compile();
|
||||
providers: [AuthService],
|
||||
})
|
||||
.useMocker(() => makeAdB2cServiceMock(makeDefaultAdB2cMockValue()))
|
||||
.compile();
|
||||
|
||||
controller = module.get<AuthController>(AuthController);
|
||||
});
|
||||
|
||||
@ -6,14 +6,18 @@ import {
|
||||
ApiTags,
|
||||
} from '@nestjs/swagger';
|
||||
import { ErrorResponse } from '../../common/error/types/types';
|
||||
import { AuthService } from './auth.service';
|
||||
import {
|
||||
AccessTokenResponse,
|
||||
TokenRequest,
|
||||
TokenResponse,
|
||||
} from './types/types';
|
||||
|
||||
@ApiTags('auth')
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
constructor(private readonly authService: AuthService) {}
|
||||
|
||||
@Post('token')
|
||||
@ApiResponse({
|
||||
status: HttpStatus.OK,
|
||||
@ -32,7 +36,8 @@ export class AuthController {
|
||||
})
|
||||
@ApiOperation({ operationId: 'token' })
|
||||
async token(@Body() body: TokenRequest): Promise<TokenResponse> {
|
||||
console.log(body);
|
||||
const payload = await this.authService.getVerifiedIdToken(body.idToken);
|
||||
console.log(payload);
|
||||
|
||||
return {
|
||||
accessToken: '',
|
||||
@ -61,6 +66,14 @@ export class AuthController {
|
||||
async accessToken(@Headers() headers): Promise<AccessTokenResponse> {
|
||||
console.log(headers['authorization']);
|
||||
|
||||
const authHeader = headers['authorization'];
|
||||
|
||||
let refreshToken = '';
|
||||
if (typeof authHeader === 'string') {
|
||||
refreshToken = authHeader.replace('Bearer ', '');
|
||||
}
|
||||
console.log(refreshToken);
|
||||
|
||||
return { accessToken: '' };
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AdB2cModule } from 'src/gateways/adb2c/adb2c.module';
|
||||
import { CryptoModule } from '../../gateways/crypto/crypto.module';
|
||||
import { AuthController } from './auth.controller';
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
@Module({
|
||||
imports: [CryptoModule, AdB2cModule],
|
||||
controllers: [AuthController],
|
||||
providers: [AuthService],
|
||||
})
|
||||
|
||||
@ -1,18 +1,134 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AuthService } from './auth.service';
|
||||
import { HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import {
|
||||
makeAdB2cServiceMock,
|
||||
makeAuthServiceMock,
|
||||
makeDefaultAdB2cMockValue,
|
||||
makeDefaultCryptoMockValue,
|
||||
} from './test/auth.service.mock';
|
||||
|
||||
describe('AuthService', () => {
|
||||
let service: AuthService;
|
||||
it('IDトークンの検証とペイロードの取得に成功する', async () => {
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwiaXNzIjoiaXNzdXNlciJ9.dURTqFfUc94qYNFS65xMqMT3tJi-uH8weJ5GU74F-UvhLKJmqVoNIbXCm-ASg2mZ5SxeX683q2MMrlzxNcNel-QIFTj0zWem4eLKuarsYRMTU8x27jMss0b_JkFtiy5KE2052_fLeW2aZBb4AjieIW34-c0Ol1rrih-W9Pk6ZEOwf14Ju0IAgdUw66-HuLOUprZjavvFp2rwuAC7gqEujg3wtjO7VR82NNoVv2dxByTdrzG_eOk8QKTJYBoM50ztT6WFs-qWetZIoQDxMJRA9ObfEVyJ4Bq2b4qelfuhAqbQWRNfCvqhoRPMJI6Y7-R94FuO1zg4d4Gm3J0qHj7r8Q';
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [AuthService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<AuthService>(AuthService);
|
||||
expect(await service.getVerifiedIdToken(token)).toEqual(idTokenPayload);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
it('IDトークンの形式が不正な場合、形式不正エラーとなる。', async () => {
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token = 'invalid.id.token';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E000101'), HttpStatus.UNAUTHORIZED),
|
||||
);
|
||||
});
|
||||
|
||||
it('IDトークンの有効期限が切れている場合、有効期限切れエラーとなる。', async () => {
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtpZCJ9.eyJleHAiOjEwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwiaXNzIjoiaXNzdWVyIn0.pk9-POXmo3ie7wfqizRr2NSX7YGEJed3krdMImzKp5qeRfsEJwM6zTSzjL_gbLQyMEDg3IoyWzVVUha4sdPcummtt8gJ6N25s_H9taFY-xJjx_-wmttGQvXD44apyUF_c_Xg0l7MzNQEqpnzsLdDcBITSN-Rk-bT_n9U4dxhYaWukOPfAPf7DzSxT9TCpTaCTPIAKp2JXVU41J9uv5WklhNjMSv9L5jWT-IstEC71-DO6jD6yFpAOLIG6Aq-C7rQolt_Cny9qKugu6hd7_Aj-YrW9773khUOyFotJ7Qs9g-qSEMy7M9ljvai2eu5Otfja3hlS5wF1VH_ENsXye6C0A';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E000102'), HttpStatus.UNAUTHORIZED),
|
||||
);
|
||||
});
|
||||
|
||||
it('IDトークンが開始日より前の場合、開始前エラーとなる。', async () => {
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6OTAwMDAwMDAwMCwiaXNzIjoiaXNzdWVyIn0.pSk3U8Wn_XTm6KxvdQpqQuGROjanLxLGsnRGg35jO4iPVysHKVWya7Leik3aTtK8lGCSoapodQoV4EXbP5CzBf5O83l9tKaF2pwEO_C9QePlLJIJMaCmqRFrr1ozcVFQNwYAr81KNmXBuEEG5duT36Fk2A9-PLDtwg816J4nMEnd1umgCSRTKOdxh265ybDxX1Pe8KDtzlCi8Wjj-lhFwxskpKD3xlFl2plhW9_P7eq-DJXtm1fvLk27zxwOq8uaaxu6sfXoeu1D4qi4aZ0MF-5eaOezc8KH-aYgU9o5yQCZH6tJJDrZvzi7GAFTd-c952V9jgPZpifEoDMRJXS5zA';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E000103'), HttpStatus.UNAUTHORIZED),
|
||||
);
|
||||
});
|
||||
|
||||
it('IDトークンの署名が不正な場合、署名不正エラーとなる。', async () => {
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwiaXNzIjoiaXNzdWVyIn0.sign';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E000104'), HttpStatus.UNAUTHORIZED),
|
||||
);
|
||||
});
|
||||
|
||||
it('IDトークンの発行元が想定と異なる場合、発行元不正エラーとなる。', async () => {
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwiaXNzIjoiaW52YWxpZCJ9.jmwBBc2r55YOr88W_4aRzFccmtmQfQRLob7YGM4bOPMGK-ExXJQG24CiMpODZEvVTtQKucEd2cBB6zzLYGCiKRHig8iM_EV57klMwKrczdL2ov8Hc3IyA407idDxDi0KyyveEctxEUdl3PgbY54CVc6URhUAzGdcQ2mKMRVe-Zxb7CrFYqwiHUCmCnSRFUYj_9kkI3epkdsXPsLyDApDEbLEeD1ztnoyYrbfmdce6flpf-h1r2VK4dMz8m4GMOLQHM9gWSzRUkUsN3hGOKTofUxCKC4CArfSP1vZ5k9FZrjqOZn1m6bxKalCox2n96GqLtuFV3-sOTnCqgHj0fQEJA';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E000105'), HttpStatus.UNAUTHORIZED),
|
||||
);
|
||||
});
|
||||
|
||||
it('Azure ADB2Cでネットワークエラーとなる場合、エラーとなる。(メタデータ)', async () => {
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
adb2cParam.getMetaData = new Error('failed get metadata');
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwiaXNzIjoiaXNzdXNlciJ9.dURTqFfUc94qYNFS65xMqMT3tJi-uH8weJ5GU74F-UvhLKJmqVoNIbXCm-ASg2mZ5SxeX683q2MMrlzxNcNel-QIFTj0zWem4eLKuarsYRMTU8x27jMss0b_JkFtiy5KE2052_fLeW2aZBb4AjieIW34-c0Ol1rrih-W9Pk6ZEOwf14Ju0IAgdUw66-HuLOUprZjavvFp2rwuAC7gqEujg3wtjO7VR82NNoVv2dxByTdrzG_eOk8QKTJYBoM50ztT6WFs-qWetZIoQDxMJRA9ObfEVyJ4Bq2b4qelfuhAqbQWRNfCvqhoRPMJI6Y7-R94FuO1zg4d4Gm3J0qHj7r8Q';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
),
|
||||
);
|
||||
});
|
||||
it('Azure ADB2Cでネットワークエラーとなる場合、エラーとなる。(キーセット)', async () => {
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
adb2cParam.getSignKeySets = new Error('failed get keyset');
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwiaXNzIjoiaXNzdXNlciJ9.dURTqFfUc94qYNFS65xMqMT3tJi-uH8weJ5GU74F-UvhLKJmqVoNIbXCm-ASg2mZ5SxeX683q2MMrlzxNcNel-QIFTj0zWem4eLKuarsYRMTU8x27jMss0b_JkFtiy5KE2052_fLeW2aZBb4AjieIW34-c0Ol1rrih-W9Pk6ZEOwf14Ju0IAgdUw66-HuLOUprZjavvFp2rwuAC7gqEujg3wtjO7VR82NNoVv2dxByTdrzG_eOk8QKTJYBoM50ztT6WFs-qWetZIoQDxMJRA9ObfEVyJ4Bq2b4qelfuhAqbQWRNfCvqhoRPMJI6Y7-R94FuO1zg4d4Gm3J0qHj7r8Q';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('Azure ADB2Cから取得した鍵が一致しない場合、エラーとなる。', async () => {
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
adb2cParam.getSignKeySets = [
|
||||
{ kid: 'invalid', kty: 'RSA', nbf: 0, use: 'sig', e: '', n: '' },
|
||||
];
|
||||
const cryptoParam = makeDefaultCryptoMockValue();
|
||||
const service = await makeAuthServiceMock(adb2cParam, cryptoParam);
|
||||
const token =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtpZCJ9.eyJleHAiOjkwMDAwMDAwMDAsIm5iZiI6MTAwMDAwMDAwMCwiaXNzIjoiaXNzdXNlciJ9.dURTqFfUc94qYNFS65xMqMT3tJi-uH8weJ5GU74F-UvhLKJmqVoNIbXCm-ASg2mZ5SxeX683q2MMrlzxNcNel-QIFTj0zWem4eLKuarsYRMTU8x27jMss0b_JkFtiy5KE2052_fLeW2aZBb4AjieIW34-c0Ol1rrih-W9Pk6ZEOwf14Ju0IAgdUw66-HuLOUprZjavvFp2rwuAC7gqEujg3wtjO7VR82NNoVv2dxByTdrzG_eOk8QKTJYBoM50ztT6WFs-qWetZIoQDxMJRA9ObfEVyJ4Bq2b4qelfuhAqbQWRNfCvqhoRPMJI6Y7-R94FuO1zg4d4Gm3J0qHj7r8Q';
|
||||
|
||||
await expect(service.getVerifiedIdToken(token)).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
const idTokenPayload = {
|
||||
exp: 9000000000,
|
||||
nbf: 1000000000,
|
||||
iss: 'issuser',
|
||||
};
|
||||
|
||||
@ -1,4 +1,123 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import { AdB2cService } from '../../gateways/adb2c/adb2c.service';
|
||||
import { CryptoService } from '../../gateways/crypto/crypto.service';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {}
|
||||
export class AuthService {
|
||||
constructor(
|
||||
private adB2cService: AdB2cService,
|
||||
private cryptoService: CryptoService,
|
||||
) {}
|
||||
private readonly logger = new Logger(AuthService.name);
|
||||
|
||||
async getVerifiedIdToken(token: string): Promise<any> {
|
||||
this.logger.log(`[IN] ${this.getVerifiedIdToken.name}`);
|
||||
|
||||
let kid = '';
|
||||
try {
|
||||
// JWTトークンのヘッダを見るため一度デコードする
|
||||
const decodedToken = jwt.decode(token, { complete: true });
|
||||
kid = decodedToken.header.kid;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
|
||||
let issuer = '';
|
||||
try {
|
||||
const metadata = await this.adB2cService.getMetaData();
|
||||
const keySets = await this.adB2cService.getSignKeySets();
|
||||
|
||||
issuer = metadata.issuer;
|
||||
|
||||
const jwkKey = keySets.find((x) => x.kid === kid);
|
||||
|
||||
if (!jwkKey) {
|
||||
throw new Error('Public Key Not Found.');
|
||||
}
|
||||
|
||||
const publicKey = await this.cryptoService.getPublicKeyFromJwk(jwkKey);
|
||||
|
||||
const verifiedToken = jwt.verify(token, publicKey, {
|
||||
algorithms: ['RS256'],
|
||||
issuer: [issuer],
|
||||
});
|
||||
|
||||
return verifiedToken;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const { name, message } = e;
|
||||
this.logger.error(`error=${name}: ${message}`);
|
||||
|
||||
switch (e.constructor) {
|
||||
case jwt.TokenExpiredError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000102'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
case jwt.NotBeforeError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000103'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
case jwt.JsonWebTokenError:
|
||||
// メッセージごとにエラーを判定しHTTPエラーを生成
|
||||
throw this.makeHttpErrorFromJsonWebTokenErrorMessage(
|
||||
message,
|
||||
issuer,
|
||||
);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
this.logger.error(`error=${e}`);
|
||||
}
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getVerifiedIdToken.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JWT検証時のError、JsonWebTokenErrorをメッセージごとに仕分けてHTTPエラーを生成
|
||||
*/
|
||||
makeHttpErrorFromJsonWebTokenErrorMessage = (
|
||||
message: string,
|
||||
issuer: string,
|
||||
): Error => {
|
||||
// 署名が不正
|
||||
if (message === 'invalid signature') {
|
||||
return new HttpException(
|
||||
makeErrorResponse('E000104'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
// 想定発行元と異なる
|
||||
if (message === `jwt issuer invalid. expected: ${issuer}`) {
|
||||
return new HttpException(
|
||||
makeErrorResponse('E000105'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
// アルゴリズムが想定と異なる
|
||||
if (message === 'invalid algorithm') {
|
||||
return new HttpException(
|
||||
makeErrorResponse('E000106'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
// トークンの形式が不正
|
||||
return new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
100
dictation_server/src/features/auth/test/auth.service.mock.ts
Normal file
100
dictation_server/src/features/auth/test/auth.service.mock.ts
Normal file
@ -0,0 +1,100 @@
|
||||
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';
|
||||
|
||||
export type AdB2cMockValue = {
|
||||
getMetaData: B2cMetadata | Error;
|
||||
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],
|
||||
})
|
||||
.useMocker((token) => {
|
||||
switch (token) {
|
||||
case AdB2cService:
|
||||
return makeAdB2cServiceMock(adB2cMockValue);
|
||||
case CryptoService:
|
||||
return makeCryptoServiceMock(cryptoMockValue);
|
||||
}
|
||||
})
|
||||
.compile();
|
||||
|
||||
return module.get<AuthService>(AuthService);
|
||||
};
|
||||
|
||||
export const makeDefaultAdB2cMockValue = (): AdB2cMockValue => {
|
||||
return {
|
||||
getMetaData: {
|
||||
issuer: 'issuser',
|
||||
},
|
||||
getSignKeySets: [
|
||||
{
|
||||
kid: 'kid',
|
||||
nbf: 1111111111,
|
||||
use: 'sig',
|
||||
kty: 'RSA',
|
||||
e: 'e',
|
||||
n: 'n',
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
export const makeAdB2cServiceMock = (value: AdB2cMockValue) => {
|
||||
const { getMetaData, getSignKeySets } = value;
|
||||
|
||||
return {
|
||||
getMetaData:
|
||||
getMetaData instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(getMetaData)
|
||||
: jest.fn<Promise<B2cMetadata>, []>().mockResolvedValue(getMetaData),
|
||||
getSignKeySets:
|
||||
getSignKeySets instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(getSignKeySets)
|
||||
: jest
|
||||
.fn<Promise<JwkSignKey[]>, []>()
|
||||
.mockResolvedValue(getSignKeySets),
|
||||
};
|
||||
};
|
||||
|
||||
export const makeDefaultCryptoMockValue = (): CryptoMockValue => {
|
||||
return {
|
||||
getPublicKeyFromJwk: [
|
||||
'-----BEGIN PUBLIC KEY-----',
|
||||
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsTVLNpW0/FzVCU7qo1DD',
|
||||
'jOkYWx6s/jE56YOOc3UzaaG/zb1FGyfRoUUgS4DnQxPNz9oM63RpQlhvG6UCwx23',
|
||||
'tL7p3PS0ZCsLeggcyLctbJAzLy/afF9ABoreorqp/AaEs+Vdwbykb+M+nB2Sxsc5',
|
||||
'7Tli2x8NiOZr5dafs3vMuIIKNsBaFAugFrd2ApxXR04jBRAorZRRFPtECE7D+hxD',
|
||||
'alw5DCd0mmdY0vrbRsgkbej0ZzzqzukJVXTMjy1YScqi3I9gLx2hLVmpK76Gtxn2',
|
||||
'1AIcn8P3rKZmDyPH+9KNfWC8+ubF+VuY6nItlCgiSyTKErAp6M9pyRHKbPpdUM3a',
|
||||
'IQIDAQAB',
|
||||
'-----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),
|
||||
};
|
||||
};
|
||||
10
dictation_server/src/gateways/adb2c/adb2c.module.ts
Normal file
10
dictation_server/src/gateways/adb2c/adb2c.module.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { AdB2cService } from './adb2c.service';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule],
|
||||
exports: [AdB2cService],
|
||||
providers: [AdB2cService],
|
||||
})
|
||||
export class AdB2cModule {}
|
||||
60
dictation_server/src/gateways/adb2c/adb2c.service.ts
Normal file
60
dictation_server/src/gateways/adb2c/adb2c.service.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import axios from 'axios';
|
||||
import { JwkSignKey, B2cMetadata } from '../../common/token';
|
||||
|
||||
@Injectable()
|
||||
export class AdB2cService {
|
||||
constructor(private readonly configService: ConfigService) {}
|
||||
private readonly logger = new Logger(AdB2cService.name);
|
||||
private readonly tenantName = this.configService.get<string>('TENANT_NAME');
|
||||
private readonly flowName =
|
||||
this.configService.get<string>('SIGNIN_FLOW_NAME');
|
||||
|
||||
/**
|
||||
* ADB2Cのメタデータを取得する
|
||||
* @returns meta data
|
||||
*/
|
||||
async getMetaData(): Promise<B2cMetadata> {
|
||||
this.logger.log(`[IN] ${this.getMetaData.name}`);
|
||||
try {
|
||||
// Azure AD B2Cのメタデータを取得する。 以下のURLから取得できる。
|
||||
// https://<テナント名>.b2clogin.com/<テナント名>.onmicrosoft.com/<ユーザーフロー名>/v2.0/.well-known/openid-configuration
|
||||
const metaData = await axios
|
||||
.get(
|
||||
`https://${this.tenantName}.b2clogin.com/${this.tenantName}.onmicrosoft.com/${this.flowName}/v2.0/.well-known/openid-configuration`,
|
||||
)
|
||||
.then((res) => res.data);
|
||||
|
||||
return metaData;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getMetaData.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* IDトークンの署名キーセットを取得する
|
||||
* @returns sign key sets
|
||||
*/
|
||||
async getSignKeySets(): Promise<JwkSignKey[]> {
|
||||
this.logger.log(`[IN] ${this.getSignKeySets.name}`);
|
||||
try {
|
||||
// 署名キーのキーセット配列を取得する。 以下のURLから取得できる。
|
||||
const keySets = await axios
|
||||
.get(
|
||||
`https://${this.tenantName}.b2clogin.com/${this.tenantName}.onmicrosoft.com/${this.flowName}/discovery/v2.0/keys`,
|
||||
)
|
||||
.then((res) => res.data.keys);
|
||||
|
||||
return keySets;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getSignKeySets.name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
10
dictation_server/src/gateways/crypto/crypto.module.ts
Normal file
10
dictation_server/src/gateways/crypto/crypto.module.ts
Normal file
@ -0,0 +1,10 @@
|
||||
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 {}
|
||||
92
dictation_server/src/gateways/crypto/crypto.service.ts
Normal file
92
dictation_server/src/gateways/crypto/crypto.service.ts
Normal file
@ -0,0 +1,92 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import jwkToPem from 'jwk-to-pem';
|
||||
import { JwkSignKey } from 'src/common/token';
|
||||
|
||||
@Injectable()
|
||||
export class CryptoService {
|
||||
constructor(private readonly configService: ConfigService) {}
|
||||
private readonly logger = new Logger(CryptoService.name);
|
||||
|
||||
async getPrivateKey(): Promise<string> {
|
||||
try {
|
||||
// XXX 動作確認用
|
||||
const privateKey = [
|
||||
'-----BEGIN RSA PRIVATE KEY-----',
|
||||
'MIIEpAIBAAKCAQEAsTVLNpW0/FzVCU7qo1DDjOkYWx6s/jE56YOOc3UzaaG/zb1F',
|
||||
'GyfRoUUgS4DnQxPNz9oM63RpQlhvG6UCwx23tL7p3PS0ZCsLeggcyLctbJAzLy/a',
|
||||
'fF9ABoreorqp/AaEs+Vdwbykb+M+nB2Sxsc57Tli2x8NiOZr5dafs3vMuIIKNsBa',
|
||||
'FAugFrd2ApxXR04jBRAorZRRFPtECE7D+hxDalw5DCd0mmdY0vrbRsgkbej0Zzzq',
|
||||
'zukJVXTMjy1YScqi3I9gLx2hLVmpK76Gtxn21AIcn8P3rKZmDyPH+9KNfWC8+ubF',
|
||||
'+VuY6nItlCgiSyTKErAp6M9pyRHKbPpdUM3aIQIDAQABAoIBAQCk7fkmwIdGKhCN',
|
||||
'LUns3opiZ8AnbpGLs702vR6kDvze35BoqDPdZl4RPwkjvMGBCLmRLly/+ATPnwcq',
|
||||
'L5Y2iz4jl1yKLaaHZBi2Zz6DARnh5QP+cwdiojQw4qb7xcfXrSltVZjBbBWPnWz0',
|
||||
'WAH3yAz94V9Emc47EFpz/CF/J0YOokxY8GlR4cwfK6NE0goAjzmatwV3IVFeR/eE',
|
||||
'x6JZAmd/0HMfOn3k/NumAMCJXKnZMQBAMQ3AduTO2lbZm+29yBqymtzTGFjrj0gm',
|
||||
'+E/ibD8vVzh0toPvUfPIqetdRT8vkUJ5UHhAkz9Vzvqhr6BhYhc2ft0x/z7HpaiX',
|
||||
'cDqnaRLBAoGBAODdPEktK1VOVXhOuikZBUHXU25iQdQRbM4kCtWiE8lBZ/f+6OPc',
|
||||
'BN+OedYMDhpFe/oFqGU4t610SPO1CdVRPnWHhMSabjh9G3gqOZjSW5tEAgT2wi+H',
|
||||
'IOVXnsos1qCMFdXWgVZw6F8wNcui9VabGic/EOqMRihEeSOjcradTSQFAoGBAMm+',
|
||||
'y2wZ8usanIDzADgTJnA4kBZzhIxK6qcPf3tPVXKuFUOFWwzGiDXeXTwM0sWN7kGb',
|
||||
'iymqhTWlYETQ3C6jPXTJiyOSco1rw45wO+xSHeQvUzXpk+9whbVAlhTcoVGiKz+9',
|
||||
'BS7+3+lKtBzXDNADxQfSGjiGb+ceilBGLV+WurRtAoGAPxn2a/aP/X1hAMTe+t95',
|
||||
'mTNqx0Qtguxs4yA8Jh04fjarjW1sP10jxPR/fjCd2IN9OflSey1CZhuGyVUZcFI/',
|
||||
'O84O1PkdSx7YkY0P4rHNYTHhezEf5yR9d75x4fxZMm59RifO3coLe4LU5dNSE76s',
|
||||
'xSyue5NnsK8ea4DXlSVpW10CgYAfHz3GWWJt/lbyVYpNHDcrzK39qKhj9BKq3ust',
|
||||
'nJlz7YL+PY5ENERC+yCq6NeC/lgo6tPXA6U1F2P4ebfdwfTzFTxPqoHdayhpysqT',
|
||||
'tD9EOkC96mCV6WfXBDWi1j5Ul43QcVphW5QzKwEKCerCFDLK+BBvc93Da6SuqYTK',
|
||||
'YDhBKQKBgQDKtNe8CjHRvkWoyKErMMpv5D0ce/yWq+oAaoqW1QKwngPyaiDeDwqM',
|
||||
'iOJzQxtvK4YqMYQdkgj5VLfWzeazd28RLODZua6phe776zuUv93LHTvYq/8RZfhk',
|
||||
'JIQJ7GETBnHmoTemwmJiSdVDsjJdtsyR4XRjIDNR5bGe7NNbZJpCUw==',
|
||||
'-----END RSA PRIVATE KEY-----',
|
||||
].join('\n');
|
||||
return privateKey;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getPublicKey.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
async getPublicKey(): Promise<string> {
|
||||
try {
|
||||
// XXX 動作確認用
|
||||
const publicKey = [
|
||||
'-----BEGIN PUBLIC KEY-----',
|
||||
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsTVLNpW0/FzVCU7qo1DD',
|
||||
'jOkYWx6s/jE56YOOc3UzaaG/zb1FGyfRoUUgS4DnQxPNz9oM63RpQlhvG6UCwx23',
|
||||
'tL7p3PS0ZCsLeggcyLctbJAzLy/afF9ABoreorqp/AaEs+Vdwbykb+M+nB2Sxsc5',
|
||||
'7Tli2x8NiOZr5dafs3vMuIIKNsBaFAugFrd2ApxXR04jBRAorZRRFPtECE7D+hxD',
|
||||
'alw5DCd0mmdY0vrbRsgkbej0ZzzqzukJVXTMjy1YScqi3I9gLx2hLVmpK76Gtxn2',
|
||||
'1AIcn8P3rKZmDyPH+9KNfWC8+ubF+VuY6nItlCgiSyTKErAp6M9pyRHKbPpdUM3a',
|
||||
'IQIDAQAB',
|
||||
'-----END PUBLIC KEY-----',
|
||||
].join('\n');
|
||||
return publicKey;
|
||||
} 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}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import * as cookieParser from 'cookie-parser';
|
||||
import cookieParser from 'cookie-parser';
|
||||
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
||||
import { AppModule } from './app.module';
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
@ -12,7 +12,12 @@ async function bootstrap() {
|
||||
app.use(new LoggerMiddleware(), cookieParser());
|
||||
|
||||
// バリデーター(+型の自動変換機能)を適用
|
||||
app.useGlobalPipes(new ValidationPipe({ transform: true }));
|
||||
app.useGlobalPipes(
|
||||
new ValidationPipe({
|
||||
transform: true,
|
||||
forbidUnknownValues: false,
|
||||
}),
|
||||
);
|
||||
|
||||
if (process.env.STAGE === 'local') {
|
||||
const options = new DocumentBuilder()
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
"noImplicitAny": false,
|
||||
"strictBindCallApply": false,
|
||||
"forceConsistentCasingInFileNames": false,
|
||||
"noFallthroughCasesInSwitch": false
|
||||
"noFallthroughCasesInSwitch": false,
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user