refactor(jwt-parser): simplified code
This commit is contained in:
		
							parent
							
								
									acc7f0a586
								
							
						
					
					
						commit
						f52f7a845c
					
				| @ -58,6 +58,7 @@ | |||||||
|     "qrcode": "^1.5.1", |     "qrcode": "^1.5.1", | ||||||
|     "randombytes": "^2.1.0", |     "randombytes": "^2.1.0", | ||||||
|     "sql-formatter": "^8.2.0", |     "sql-formatter": "^8.2.0", | ||||||
|  |     "ts-pattern": "^4.1.3", | ||||||
|     "uuid": "^8.3.2", |     "uuid": "^8.3.2", | ||||||
|     "vue": "^3.2.45", |     "vue": "^3.2.45", | ||||||
|     "vue-router": "^4.1.6" |     "vue-router": "^4.1.6" | ||||||
|  | |||||||
							
								
								
									
										75
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										75
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							| @ -56,6 +56,7 @@ specifiers: | |||||||
|   sql-formatter: ^8.2.0 |   sql-formatter: ^8.2.0 | ||||||
|   standard-version: ^9.5.0 |   standard-version: ^9.5.0 | ||||||
|   start-server-and-test: ^1.14.0 |   start-server-and-test: ^1.14.0 | ||||||
|  |   ts-pattern: ^4.1.3 | ||||||
|   typescript: ~4.5.5 |   typescript: ~4.5.5 | ||||||
|   uuid: ^8.3.2 |   uuid: ^8.3.2 | ||||||
|   vite: ^2.9.15 |   vite: ^2.9.15 | ||||||
| @ -96,6 +97,7 @@ dependencies: | |||||||
|   qrcode: 1.5.1 |   qrcode: 1.5.1 | ||||||
|   randombytes: 2.1.0 |   randombytes: 2.1.0 | ||||||
|   sql-formatter: 8.2.0 |   sql-formatter: 8.2.0 | ||||||
|  |   ts-pattern: 4.1.3 | ||||||
|   uuid: 8.3.2 |   uuid: 8.3.2 | ||||||
|   vue: 3.2.45 |   vue: 3.2.45 | ||||||
|   vue-router: 4.1.6_vue@3.2.45 |   vue-router: 4.1.6_vue@3.2.45 | ||||||
| @ -122,7 +124,7 @@ devDependencies: | |||||||
|   eslint: 8.27.0 |   eslint: 8.27.0 | ||||||
|   eslint-config-prettier: 8.5.0_eslint@8.27.0 |   eslint-config-prettier: 8.5.0_eslint@8.27.0 | ||||||
|   eslint-import-resolver-typescript: 3.5.2_dcpv4nbdr5ks2h5677xdltrk6e |   eslint-import-resolver-typescript: 3.5.2_dcpv4nbdr5ks2h5677xdltrk6e | ||||||
|   eslint-plugin-import: 2.26.0_gbipkkcbnjmysmpjttq6vkmfqq |   eslint-plugin-import: 2.26.0_eslint@8.27.0 | ||||||
|   eslint-plugin-vue: 8.7.1_eslint@8.27.0 |   eslint-plugin-vue: 8.7.1_eslint@8.27.0 | ||||||
|   jsdom: 19.0.0 |   jsdom: 19.0.0 | ||||||
|   less: 4.1.3 |   less: 4.1.3 | ||||||
| @ -132,7 +134,7 @@ devDependencies: | |||||||
|   typescript: 4.5.5 |   typescript: 4.5.5 | ||||||
|   vite: 2.9.15_less@4.1.3 |   vite: 2.9.15_less@4.1.3 | ||||||
|   vite-plugin-md: 0.12.4_vite@2.9.15 |   vite-plugin-md: 0.12.4_vite@2.9.15 | ||||||
|   vite-plugin-pwa: 0.11.13_7mbbuzxp22mje5bxdolj2b6yg4 |   vite-plugin-pwa: 0.11.13_vite@2.9.15 | ||||||
|   vite-svg-loader: 3.6.0 |   vite-svg-loader: 3.6.0 | ||||||
|   vitest: 0.13.1_uwxj23d3xojfwkqpytqc7pyhry |   vitest: 0.13.1_uwxj23d3xojfwkqpytqc7pyhry | ||||||
|   vue-tsc: 0.31.4_typescript@4.5.5 |   vue-tsc: 0.31.4_typescript@4.5.5 | ||||||
| @ -2066,10 +2068,6 @@ packages: | |||||||
|     peerDependencies: |     peerDependencies: | ||||||
|       eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 |       eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 | ||||||
|       eslint-plugin-vue: ^8.0.1 |       eslint-plugin-vue: ^8.0.1 | ||||||
|       typescript: '*' |  | ||||||
|     peerDependenciesMeta: |  | ||||||
|       typescript: |  | ||||||
|         optional: true |  | ||||||
|     dependencies: |     dependencies: | ||||||
|       '@typescript-eslint/eslint-plugin': 5.42.1_vfr6z4qvdp6defk3ked6x75zyi |       '@typescript-eslint/eslint-plugin': 5.42.1_vfr6z4qvdp6defk3ked6x75zyi | ||||||
|       '@typescript-eslint/parser': 5.42.1_4rqwsplhh2ekz63wktwk7d7ht4 |       '@typescript-eslint/parser': 5.42.1_4rqwsplhh2ekz63wktwk7d7ht4 | ||||||
| @ -2079,6 +2077,7 @@ packages: | |||||||
|       vue-eslint-parser: 8.3.0_eslint@8.27.0 |       vue-eslint-parser: 8.3.0_eslint@8.27.0 | ||||||
|     transitivePeerDependencies: |     transitivePeerDependencies: | ||||||
|       - supports-color |       - supports-color | ||||||
|  |       - typescript | ||||||
|     dev: true |     dev: true | ||||||
| 
 | 
 | ||||||
|   /@vue/reactivity-transform/3.2.45: |   /@vue/reactivity-transform/3.2.45: | ||||||
| @ -2107,6 +2106,7 @@ packages: | |||||||
|       '@vue/runtime-core': 3.2.45 |       '@vue/runtime-core': 3.2.45 | ||||||
|       '@vue/shared': 3.2.45 |       '@vue/shared': 3.2.45 | ||||||
|       csstype: 2.6.21 |       csstype: 2.6.21 | ||||||
|  |     dev: false | ||||||
| 
 | 
 | ||||||
|   /@vue/server-renderer/3.2.45_vue@3.2.45: |   /@vue/server-renderer/3.2.45_vue@3.2.45: | ||||||
|     resolution: {integrity: sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g==} |     resolution: {integrity: sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g==} | ||||||
| @ -2116,6 +2116,7 @@ packages: | |||||||
|       '@vue/compiler-ssr': 3.2.45 |       '@vue/compiler-ssr': 3.2.45 | ||||||
|       '@vue/shared': 3.2.45 |       '@vue/shared': 3.2.45 | ||||||
|       vue: 3.2.45 |       vue: 3.2.45 | ||||||
|  |     dev: false | ||||||
| 
 | 
 | ||||||
|   /@vue/shared/3.2.45: |   /@vue/shared/3.2.45: | ||||||
|     resolution: {integrity: sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==} |     resolution: {integrity: sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==} | ||||||
| @ -2860,8 +2861,8 @@ packages: | |||||||
|     engines: {node: '>=10'} |     engines: {node: '>=10'} | ||||||
|     hasBin: true |     hasBin: true | ||||||
|     dependencies: |     dependencies: | ||||||
|       JSONStream: 1.3.5 |  | ||||||
|       is-text-path: 1.0.1 |       is-text-path: 1.0.1 | ||||||
|  |       JSONStream: 1.3.5 | ||||||
|       lodash: 4.17.21 |       lodash: 4.17.21 | ||||||
|       meow: 8.1.2 |       meow: 8.1.2 | ||||||
|       split2: 3.2.2 |       split2: 3.2.2 | ||||||
| @ -2990,6 +2991,7 @@ packages: | |||||||
| 
 | 
 | ||||||
|   /csstype/2.6.21: |   /csstype/2.6.21: | ||||||
|     resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==} |     resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==} | ||||||
|  |     dev: false | ||||||
| 
 | 
 | ||||||
|   /csstype/3.0.11: |   /csstype/3.0.11: | ||||||
|     resolution: {integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==} |     resolution: {integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==} | ||||||
| @ -3028,22 +3030,12 @@ packages: | |||||||
| 
 | 
 | ||||||
|   /debug/2.6.9: |   /debug/2.6.9: | ||||||
|     resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} |     resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} | ||||||
|     peerDependencies: |  | ||||||
|       supports-color: '*' |  | ||||||
|     peerDependenciesMeta: |  | ||||||
|       supports-color: |  | ||||||
|         optional: true |  | ||||||
|     dependencies: |     dependencies: | ||||||
|       ms: 2.0.0 |       ms: 2.0.0 | ||||||
|     dev: true |     dev: true | ||||||
| 
 | 
 | ||||||
|   /debug/3.2.7: |   /debug/3.2.7: | ||||||
|     resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} |     resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} | ||||||
|     peerDependencies: |  | ||||||
|       supports-color: '*' |  | ||||||
|     peerDependenciesMeta: |  | ||||||
|       supports-color: |  | ||||||
|         optional: true |  | ||||||
|     dependencies: |     dependencies: | ||||||
|       ms: 2.1.3 |       ms: 2.1.3 | ||||||
|     dev: true |     dev: true | ||||||
| @ -3582,8 +3574,6 @@ packages: | |||||||
|     dependencies: |     dependencies: | ||||||
|       debug: 3.2.7 |       debug: 3.2.7 | ||||||
|       resolve: 1.22.1 |       resolve: 1.22.1 | ||||||
|     transitivePeerDependencies: |  | ||||||
|       - supports-color |  | ||||||
|     dev: true |     dev: true | ||||||
| 
 | 
 | ||||||
|   /eslint-import-resolver-typescript/3.5.2_dcpv4nbdr5ks2h5677xdltrk6e: |   /eslint-import-resolver-typescript/3.5.2_dcpv4nbdr5ks2h5677xdltrk6e: | ||||||
| @ -3596,7 +3586,7 @@ packages: | |||||||
|       debug: 4.3.4 |       debug: 4.3.4 | ||||||
|       enhanced-resolve: 5.10.0 |       enhanced-resolve: 5.10.0 | ||||||
|       eslint: 8.27.0 |       eslint: 8.27.0 | ||||||
|       eslint-plugin-import: 2.26.0_gbipkkcbnjmysmpjttq6vkmfqq |       eslint-plugin-import: 2.26.0_eslint@8.27.0 | ||||||
|       get-tsconfig: 4.2.0 |       get-tsconfig: 4.2.0 | ||||||
|       globby: 13.1.2 |       globby: 13.1.2 | ||||||
|       is-core-module: 2.11.0 |       is-core-module: 2.11.0 | ||||||
| @ -3606,54 +3596,32 @@ packages: | |||||||
|       - supports-color |       - supports-color | ||||||
|     dev: true |     dev: true | ||||||
| 
 | 
 | ||||||
|   /eslint-module-utils/2.7.4_idrr6ghswzssuopqxluk4kfum4: |   /eslint-module-utils/2.7.4_eslint@8.27.0: | ||||||
|     resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} |     resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} | ||||||
|     engines: {node: '>=4'} |     engines: {node: '>=4'} | ||||||
|     peerDependencies: |     peerDependencies: | ||||||
|       '@typescript-eslint/parser': '*' |  | ||||||
|       eslint: '*' |       eslint: '*' | ||||||
|       eslint-import-resolver-node: '*' |  | ||||||
|       eslint-import-resolver-typescript: '*' |  | ||||||
|       eslint-import-resolver-webpack: '*' |  | ||||||
|     peerDependenciesMeta: |     peerDependenciesMeta: | ||||||
|       '@typescript-eslint/parser': |  | ||||||
|         optional: true |  | ||||||
|       eslint: |       eslint: | ||||||
|         optional: true |         optional: true | ||||||
|       eslint-import-resolver-node: |  | ||||||
|         optional: true |  | ||||||
|       eslint-import-resolver-typescript: |  | ||||||
|         optional: true |  | ||||||
|       eslint-import-resolver-webpack: |  | ||||||
|         optional: true |  | ||||||
|     dependencies: |     dependencies: | ||||||
|       '@typescript-eslint/parser': 5.42.1_4rqwsplhh2ekz63wktwk7d7ht4 |  | ||||||
|       debug: 3.2.7 |       debug: 3.2.7 | ||||||
|       eslint: 8.27.0 |       eslint: 8.27.0 | ||||||
|       eslint-import-resolver-node: 0.3.6 |  | ||||||
|       eslint-import-resolver-typescript: 3.5.2_dcpv4nbdr5ks2h5677xdltrk6e |  | ||||||
|     transitivePeerDependencies: |  | ||||||
|       - supports-color |  | ||||||
|     dev: true |     dev: true | ||||||
| 
 | 
 | ||||||
|   /eslint-plugin-import/2.26.0_gbipkkcbnjmysmpjttq6vkmfqq: |   /eslint-plugin-import/2.26.0_eslint@8.27.0: | ||||||
|     resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} |     resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} | ||||||
|     engines: {node: '>=4'} |     engines: {node: '>=4'} | ||||||
|     peerDependencies: |     peerDependencies: | ||||||
|       '@typescript-eslint/parser': '*' |  | ||||||
|       eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 |       eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 | ||||||
|     peerDependenciesMeta: |  | ||||||
|       '@typescript-eslint/parser': |  | ||||||
|         optional: true |  | ||||||
|     dependencies: |     dependencies: | ||||||
|       '@typescript-eslint/parser': 5.42.1_4rqwsplhh2ekz63wktwk7d7ht4 |  | ||||||
|       array-includes: 3.1.6 |       array-includes: 3.1.6 | ||||||
|       array.prototype.flat: 1.3.1 |       array.prototype.flat: 1.3.1 | ||||||
|       debug: 2.6.9 |       debug: 2.6.9 | ||||||
|       doctrine: 2.1.0 |       doctrine: 2.1.0 | ||||||
|       eslint: 8.27.0 |       eslint: 8.27.0 | ||||||
|       eslint-import-resolver-node: 0.3.6 |       eslint-import-resolver-node: 0.3.6 | ||||||
|       eslint-module-utils: 2.7.4_idrr6ghswzssuopqxluk4kfum4 |       eslint-module-utils: 2.7.4_eslint@8.27.0 | ||||||
|       has: 1.0.3 |       has: 1.0.3 | ||||||
|       is-core-module: 2.11.0 |       is-core-module: 2.11.0 | ||||||
|       is-glob: 4.0.3 |       is-glob: 4.0.3 | ||||||
| @ -3661,10 +3629,6 @@ packages: | |||||||
|       object.values: 1.1.6 |       object.values: 1.1.6 | ||||||
|       resolve: 1.22.1 |       resolve: 1.22.1 | ||||||
|       tsconfig-paths: 3.14.1 |       tsconfig-paths: 3.14.1 | ||||||
|     transitivePeerDependencies: |  | ||||||
|       - eslint-import-resolver-typescript |  | ||||||
|       - eslint-import-resolver-webpack |  | ||||||
|       - supports-color |  | ||||||
|     dev: true |     dev: true | ||||||
| 
 | 
 | ||||||
|   /eslint-plugin-prettier/4.2.1_v7o5sx5x3wbs57ifz6wc4f76we: |   /eslint-plugin-prettier/4.2.1_v7o5sx5x3wbs57ifz6wc4f76we: | ||||||
| @ -4870,8 +4834,6 @@ packages: | |||||||
|       mime: 1.6.0 |       mime: 1.6.0 | ||||||
|       needle: 3.1.0 |       needle: 3.1.0 | ||||||
|       source-map: 0.6.1 |       source-map: 0.6.1 | ||||||
|     transitivePeerDependencies: |  | ||||||
|       - supports-color |  | ||||||
|     dev: true |     dev: true | ||||||
| 
 | 
 | ||||||
|   /leven/3.1.0: |   /leven/3.1.0: | ||||||
| @ -5214,8 +5176,6 @@ packages: | |||||||
|       debug: 3.2.7 |       debug: 3.2.7 | ||||||
|       iconv-lite: 0.6.3 |       iconv-lite: 0.6.3 | ||||||
|       sax: 1.2.4 |       sax: 1.2.4 | ||||||
|     transitivePeerDependencies: |  | ||||||
|       - supports-color |  | ||||||
|     dev: true |     dev: true | ||||||
|     optional: true |     optional: true | ||||||
| 
 | 
 | ||||||
| @ -6495,6 +6455,10 @@ packages: | |||||||
|     engines: {node: '>=8'} |     engines: {node: '>=8'} | ||||||
|     dev: true |     dev: true | ||||||
| 
 | 
 | ||||||
|  |   /ts-pattern/4.1.3: | ||||||
|  |     resolution: {integrity: sha512-8beXMWTGEv1JfDjSxfNhe4uT5jKYdhmEUKzt4gZW9dmHlquq3b+IbEyA7vX9LjBfzHmvKnM4HiomAUCyaW2Pew==} | ||||||
|  |     dev: false | ||||||
|  | 
 | ||||||
|   /tsconfig-paths/3.14.1: |   /tsconfig-paths/3.14.1: | ||||||
|     resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} |     resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} | ||||||
|     dependencies: |     dependencies: | ||||||
| @ -6578,6 +6542,7 @@ packages: | |||||||
|     resolution: {integrity: sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==} |     resolution: {integrity: sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==} | ||||||
|     engines: {node: '>=4.2.0'} |     engines: {node: '>=4.2.0'} | ||||||
|     hasBin: true |     hasBin: true | ||||||
|  |     dev: true | ||||||
| 
 | 
 | ||||||
|   /uc.micro/1.0.6: |   /uc.micro/1.0.6: | ||||||
|     resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} |     resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} | ||||||
| @ -6734,11 +6699,10 @@ packages: | |||||||
|       vite: 2.9.15_less@4.1.3 |       vite: 2.9.15_less@4.1.3 | ||||||
|     dev: true |     dev: true | ||||||
| 
 | 
 | ||||||
|   /vite-plugin-pwa/0.11.13_7mbbuzxp22mje5bxdolj2b6yg4: |   /vite-plugin-pwa/0.11.13_vite@2.9.15: | ||||||
|     resolution: {integrity: sha512-Ssj14m3TRVLfkFEAWSMcFE2d1cSdEZyrVTzfY2lSL+umHYvcIFHVDAY143sygtBCb44OPczsAOmWwBTxwOvh7g==} |     resolution: {integrity: sha512-Ssj14m3TRVLfkFEAWSMcFE2d1cSdEZyrVTzfY2lSL+umHYvcIFHVDAY143sygtBCb44OPczsAOmWwBTxwOvh7g==} | ||||||
|     peerDependencies: |     peerDependencies: | ||||||
|       vite: ^2.0.0 |       vite: ^2.0.0 | ||||||
|       workbox-window: ^6.4.0 |  | ||||||
|     dependencies: |     dependencies: | ||||||
|       debug: 4.3.4 |       debug: 4.3.4 | ||||||
|       fast-glob: 3.2.12 |       fast-glob: 3.2.12 | ||||||
| @ -7004,6 +6968,7 @@ packages: | |||||||
|       '@vue/runtime-dom': 3.2.45 |       '@vue/runtime-dom': 3.2.45 | ||||||
|       '@vue/server-renderer': 3.2.45_vue@3.2.45 |       '@vue/server-renderer': 3.2.45_vue@3.2.45 | ||||||
|       '@vue/shared': 3.2.45 |       '@vue/shared': 3.2.45 | ||||||
|  |     dev: false | ||||||
| 
 | 
 | ||||||
|   /vueuc/0.4.49_vue@3.2.45: |   /vueuc/0.4.49_vue@3.2.45: | ||||||
|     resolution: {integrity: sha512-WarAC44a/Yx78CxkAgROYLq+LkAeCGA/6wHidVoFmHLbzyF3SiP2nzRNGD/8zJeJInXv18EnWK6A//eGgMMq8w==} |     resolution: {integrity: sha512-WarAC44a/Yx78CxkAgROYLq+LkAeCGA/6wHidVoFmHLbzyF3SiP2nzRNGD/8zJeJInXv18EnWK6A//eGgMMq8w==} | ||||||
|  | |||||||
| @ -1,29 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <n-space> |  | ||||||
|     <em>{{ claim }}</em> |  | ||||||
|     <span v-if="label.label !== claim"> |  | ||||||
|       <n-popover placement="right" trigger="hover"> |  | ||||||
|         <template #trigger> |  | ||||||
|           <n-icon :component="InfoCircle" trigger /> |  | ||||||
|         </template> |  | ||||||
|         {{ label.label }} |  | ||||||
|         <template v-if="label.ref !== ''" #footer> {{ label.ref }} </template> |  | ||||||
|       </n-popover> |  | ||||||
|     </span> |  | ||||||
|   </n-space> |  | ||||||
| </template> |  | ||||||
| 
 |  | ||||||
| <script setup lang="ts"> |  | ||||||
| import { computed } from 'vue'; |  | ||||||
| import { InfoCircle } from '@vicons/tabler'; |  | ||||||
| import { getClaimLabel } from './jwt-parser.service'; |  | ||||||
| 
 |  | ||||||
| const props = defineProps({ |  | ||||||
|   claim: { |  | ||||||
|     type: String, |  | ||||||
|     default: '', |  | ||||||
|   }, |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| const label = computed(() => getClaimLabel(props.claim ? props.claim : '')); |  | ||||||
| </script> |  | ||||||
| @ -4,8 +4,24 @@ import { defineTool } from '../tool'; | |||||||
| export const tool = defineTool({ | export const tool = defineTool({ | ||||||
|   name: 'JWT parser', |   name: 'JWT parser', | ||||||
|   path: '/jwt-parser', |   path: '/jwt-parser', | ||||||
|   description: 'Parse a JWT (JSON Web Token) to display its content.', |   description: 'Parse and decode your JSON Web Token (jwt) and display its content.', | ||||||
|   keywords: ['jwt', 'parser'], |   keywords: [ | ||||||
|  |     'jwt', | ||||||
|  |     'parser', | ||||||
|  |     'decode', | ||||||
|  |     'typ', | ||||||
|  |     'alg', | ||||||
|  |     'iss', | ||||||
|  |     'sub', | ||||||
|  |     'aud', | ||||||
|  |     'exp', | ||||||
|  |     'nbf', | ||||||
|  |     'iat', | ||||||
|  |     'jti', | ||||||
|  |     'json', | ||||||
|  |     'web', | ||||||
|  |     'token', | ||||||
|  |   ], | ||||||
|   component: () => import('./jwt-parser.vue'), |   component: () => import('./jwt-parser.vue'), | ||||||
|   icon: Key, |   icon: Key, | ||||||
| }); | }); | ||||||
|  | |||||||
							
								
								
									
										92
									
								
								src/tools/jwt-parser/jwt-parser.constants.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/tools/jwt-parser/jwt-parser.constants.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | |||||||
|  | // From https://datatracker.ietf.org/doc/html/rfc7518#section-3.1
 | ||||||
|  | export const ALGORITHM_DESCRIPTIONS: { [k: string]: string } = { | ||||||
|  |   HS256: 'HMAC using SHA-256', | ||||||
|  |   HS384: 'HMAC using SHA-384', | ||||||
|  |   HS512: 'HMAC using SHA-512', | ||||||
|  |   RS256: 'RSASSA-PKCS1-v1_5 using SHA-256', | ||||||
|  |   RS384: 'RSASSA-PKCS1-v1_5 using SHA-384', | ||||||
|  |   RS512: 'RSASSA-PKCS1-v1_5 using SHA-512', | ||||||
|  |   ES256: 'ECDSA using P-256 and SHA-256', | ||||||
|  |   ES384: 'ECDSA using P-384 and SHA-384', | ||||||
|  |   ES512: 'ECDSA using P-521 and SHA-512', | ||||||
|  |   PS256: 'RSASSA-PSS using SHA-256 and MGF1 with SHA-256', | ||||||
|  |   PS384: 'RSASSA-PSS using SHA-384 and MGF1 with SHA-384', | ||||||
|  |   PS512: 'RSASSA-PSS using SHA-512 and MGF1 with SHA-512', | ||||||
|  |   none: 'No digital signature or MAC performed', | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // List extracted from IANA: https://www.iana.org/assignments/jwt/jwt.xhtml
 | ||||||
|  | export const CLAIM_DESCRIPTIONS: Record<string, string> = { | ||||||
|  |   typ: 'Type', | ||||||
|  |   alg: 'Algorithm', | ||||||
|  |   iss: 'Issuer', | ||||||
|  |   sub: 'Subject', | ||||||
|  |   aud: 'Audience', | ||||||
|  |   exp: 'Expiration Time', | ||||||
|  |   nbf: 'Not Before', | ||||||
|  |   iat: 'Issued At', | ||||||
|  |   jti: 'JWT ID', | ||||||
|  |   name: 'Full name', | ||||||
|  |   given_name: 'Given name(s) or first name(s)', | ||||||
|  |   family_name: 'Surname(s) or last name(s)', | ||||||
|  |   middle_name: 'Middle name(s)', | ||||||
|  |   nickname: 'Casual name', | ||||||
|  |   preferred_username: 'Shorthand name by which the End-User wishes to be referred to', | ||||||
|  |   profile: 'Profile page URL', | ||||||
|  |   picture: 'Profile picture URL', | ||||||
|  |   website: 'Web page or blog URL', | ||||||
|  |   email: 'Preferred e-mail address', | ||||||
|  |   email_verified: 'True if the e-mail address has been verified; otherwise false', | ||||||
|  |   gender: 'Gender', | ||||||
|  |   birthdate: 'Birthday', | ||||||
|  |   zoneinfo: 'Time zone', | ||||||
|  |   locale: 'Locale', | ||||||
|  |   phone_number: 'Preferred telephone number', | ||||||
|  |   phone_number_verified: 'True if the phone number has been verified; otherwise false', | ||||||
|  |   address: 'Preferred postal address', | ||||||
|  |   updated_at: 'Time the information was last updated', | ||||||
|  |   azp: 'Authorized party - the party to which the ID Token was issued', | ||||||
|  |   nonce: 'Value used to associate a Client session with an ID Token', | ||||||
|  |   auth_time: 'Time when the authentication occurred', | ||||||
|  |   at_hash: 'Access Token hash value', | ||||||
|  |   c_hash: 'Code hash value', | ||||||
|  |   acr: 'Authentication Context Class Reference', | ||||||
|  |   amr: 'Authentication Methods References', | ||||||
|  |   sub_jwk: 'Public key used to check the signature of an ID Token', | ||||||
|  |   cnf: 'Confirmation', | ||||||
|  |   sip_from_tag: 'SIP From tag header field parameter value', | ||||||
|  |   sip_date: 'SIP Date header field value', | ||||||
|  |   sip_callid: 'SIP Call-Id header field value', | ||||||
|  |   sip_cseq_num: 'SIP CSeq numeric header field parameter value', | ||||||
|  |   sip_via_branch: 'SIP Via branch header field parameter value', | ||||||
|  |   orig: 'Originating Identity String', | ||||||
|  |   dest: 'Destination Identity String', | ||||||
|  |   mky: 'Media Key Fingerprint String', | ||||||
|  |   events: 'Security Events', | ||||||
|  |   toe: 'Time of Event', | ||||||
|  |   txn: 'Transaction Identifier', | ||||||
|  |   rph: 'Resource Priority Header Authorization', | ||||||
|  |   sid: 'Session ID', | ||||||
|  |   vot: 'Vector of Trust value', | ||||||
|  |   vtm: 'Vector of Trust trustmark URL', | ||||||
|  |   attest: 'Attestation level as defined in SHAKEN framework', | ||||||
|  |   origid: 'Originating Identifier as defined in SHAKEN framework', | ||||||
|  |   act: 'Actor', | ||||||
|  |   scope: 'Scope Values', | ||||||
|  |   client_id: 'Client Identifier', | ||||||
|  |   may_act: 'Authorized Actor - the party that is authorized to become the actor', | ||||||
|  |   jcard: 'jCard data', | ||||||
|  |   at_use_nbr: 'Number of API requests for which the access token can be used', | ||||||
|  |   div: 'Diverted Target of a Call', | ||||||
|  |   opt: 'Original PASSporT (in Full Form)', | ||||||
|  |   vc: 'Verifiable Credential as specified in the W3C Recommendation', | ||||||
|  |   vp: 'Verifiable Presentation as specified in the W3C Recommendation', | ||||||
|  |   sph: 'SIP Priority header field', | ||||||
|  |   ace_profile: 'ACE profile a token is supposed to be used with.', | ||||||
|  |   cnonce: 'Client nonce', | ||||||
|  |   exi: 'Expires in', | ||||||
|  |   roles: 'Roles', | ||||||
|  |   groups: 'Groups', | ||||||
|  |   entitlements: 'Entitlements', | ||||||
|  |   token_introspection: 'Token introspection response', | ||||||
|  | }; | ||||||
| @ -1,429 +1,46 @@ | |||||||
| import jwt_decode, { InvalidTokenError } from 'jwt-decode'; | import jwtDecode, { type JwtHeader, type JwtPayload } from 'jwt-decode'; | ||||||
|  | import _ from 'lodash'; | ||||||
|  | import { match } from 'ts-pattern'; | ||||||
|  | import { ALGORITHM_DESCRIPTIONS, CLAIM_DESCRIPTIONS } from './jwt-parser.constants'; | ||||||
| 
 | 
 | ||||||
| interface JWT { | export { decodeJwt }; | ||||||
|   header: Map<string, unknown>; | 
 | ||||||
|   payload: Map<string, unknown>; | function decodeJwt({ jwt }: { jwt: string }) { | ||||||
|  |   const rawHeader = jwtDecode<JwtHeader>(jwt, { header: true }); | ||||||
|  |   const rawPayload = jwtDecode<JwtPayload>(jwt); | ||||||
|  | 
 | ||||||
|  |   const header = _.map(rawHeader, (value, claim) => parseClaims({ claim, value })); | ||||||
|  |   const payload = _.map(rawPayload, (value, claim) => parseClaims({ claim, value })); | ||||||
|  | 
 | ||||||
|  |   return { | ||||||
|  |     header, | ||||||
|  |     payload, | ||||||
|  |   }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function safeJwtDecode(rawJwt: string): JWT { | function parseClaims({ claim, value }: { claim: string; value: unknown }) { | ||||||
|   try { |   const claimDescription = CLAIM_DESCRIPTIONS[claim]; | ||||||
|     const header = jwt_decode(rawJwt, { header: true }) as Map<string, unknown>; |   const formattedValue = _.toString(value); | ||||||
|     const payload = jwt_decode(rawJwt) as Map<string, unknown>; |   const friendlyValue = getFriendlyValue({ claim, value }); | ||||||
|     return { header, payload }; | 
 | ||||||
|   } catch (e) { |   return { | ||||||
|     if (e instanceof InvalidTokenError) { |     value: formattedValue, | ||||||
|       return { header: new Map<string, unknown>(), payload: new Map<string, unknown>() }; |     friendlyValue, | ||||||
|     } else { |     claim, | ||||||
|       throw e; |     claimDescription, | ||||||
|     } |   }; | ||||||
|   } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function getClaimLabel(claim: string): { label: string; ref: string } { | function getFriendlyValue({ claim, value }: { claim: string; value: unknown }) { | ||||||
|   const infos = STANDARD_CLAIMS.find((info) => info.name === claim); |   return match(claim) | ||||||
|   if (infos) { |     .with('exp', 'nbf', 'iat', () => dateFormatter(value)) | ||||||
|     return { label: infos.long_name, ref: infos.ref }; |     .with('alg', () => (_.isString(value) ? ALGORITHM_DESCRIPTIONS[value] : undefined)) | ||||||
|   } |     .otherwise(() => undefined); | ||||||
|   switch (claim) { |  | ||||||
|     case 'typ': |  | ||||||
|       return { label: 'Type', ref: '' }; |  | ||||||
|     case 'alg': |  | ||||||
|       return { label: 'Algorithm', ref: '' }; |  | ||||||
|   } |  | ||||||
|   return { label: claim, ref: '' }; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function parseClaimValue(claim: string, value: unknown): { value: unknown; extension?: unknown } { | const dateFormatter = (value: unknown) => { | ||||||
|   switch (claim) { |   if (_.isNil(value)) return undefined; | ||||||
|     case 'exp': |  | ||||||
|     case 'nbf': |  | ||||||
|     case 'iat': { |  | ||||||
|       // Convert to milliseconds, JWT specs says it should be in seconds, JS
 |  | ||||||
|       // works with milliseconds
 |  | ||||||
|       value = typeof value === 'string' ? parseInt(value) : value; |  | ||||||
|       const date = new Date((value as number) * 1000); |  | ||||||
|       return { value: `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`, extension: value }; |  | ||||||
|     } |  | ||||||
|     case 'alg': |  | ||||||
|       return { value: AlgorithmKeyDescriptionMapping[value as string], extension: value }; |  | ||||||
|     default: |  | ||||||
|       if (typeof value === 'boolean') { |  | ||||||
|         // Perhaps there's a better way to do this?
 |  | ||||||
|         return { value: value ? 'true' : 'false' }; |  | ||||||
|       } |  | ||||||
|       return { value: value }; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| // From https://datatracker.ietf.org/doc/html/rfc7518#section-3.1
 |   const date = new Date(Number(value) * 1000); | ||||||
| const AlgorithmKeyDescriptionMapping: { [k: string]: string } = { |   return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`; | ||||||
|   HS256: 'HMAC using SHA-256', |  | ||||||
|   HS384: 'HMAC using SHA-384', |  | ||||||
|   HS512: 'HMAC using SHA-512', |  | ||||||
|   RS256: 'RSASSA-PKCS1-v1_5 using SHA-256', |  | ||||||
|   RS384: 'RSASSA-PKCS1-v1_5 using SHA-384', |  | ||||||
|   RS512: 'RSASSA-PKCS1-v1_5 using SHA-512', |  | ||||||
|   ES256: 'ECDSA using P-256 and SHA-256', |  | ||||||
|   ES384: 'ECDSA using P-384 and SHA-384', |  | ||||||
|   ES512: 'ECDSA using P-521 and SHA-512', |  | ||||||
|   PS256: 'RSASSA-PSS using SHA-256 and MGF1 with SHA-256', |  | ||||||
|   PS384: 'RSASSA-PSS using SHA-384 and MGF1 with SHA-384', |  | ||||||
|   PS512: 'RSASSA-PSS using SHA-512 and MGF1 with SHA-512', |  | ||||||
|   none: 'No digital signature or MAC performed', |  | ||||||
| }; | }; | ||||||
| 
 |  | ||||||
| // List extracted from IANA: https://www.iana.org/assignments/jwt/jwt.xhtml
 |  | ||||||
| const STANDARD_CLAIMS = [ |  | ||||||
|   { |  | ||||||
|     name: 'iss', |  | ||||||
|     long_name: 'Issuer', |  | ||||||
|     ref: '[RFC7519 - Section 4.1.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'sub', |  | ||||||
|     long_name: 'Subject', |  | ||||||
|     ref: '[RFC7519 - Section 4.1.2]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'aud', |  | ||||||
|     long_name: 'Audience', |  | ||||||
|     ref: '[RFC7519 - Section 4.1.3]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'exp', |  | ||||||
|     long_name: 'Expiration Time', |  | ||||||
|     ref: '[RFC7519 - Section 4.1.4]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'nbf', |  | ||||||
|     long_name: 'Not Before', |  | ||||||
|     ref: '[RFC7519 - Section 4.1.5]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'iat', |  | ||||||
|     long_name: 'Issued At', |  | ||||||
|     ref: '[RFC7519 - Section 4.1.6]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'jti', |  | ||||||
|     long_name: 'JWT ID', |  | ||||||
|     ref: '[RFC7519 - Section 4.1.7]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'name', |  | ||||||
|     long_name: 'Full name', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'given_name', |  | ||||||
|     long_name: 'Given name(s) or first name(s)', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'family_name', |  | ||||||
|     long_name: 'Surname(s) or last name(s)', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'middle_name', |  | ||||||
|     long_name: 'Middle name(s)', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'nickname', |  | ||||||
|     long_name: 'Casual name', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'preferred_username', |  | ||||||
|     long_name: 'Shorthand name by which the End-User wishes to be referred to', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'profile', |  | ||||||
|     long_name: 'Profile page URL', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'picture', |  | ||||||
|     long_name: 'Profile picture URL', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'website', |  | ||||||
|     long_name: 'Web page or blog URL', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'email', |  | ||||||
|     long_name: 'Preferred e-mail address', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'email_verified', |  | ||||||
|     long_name: 'True if the e-mail address has been verified; otherwise false', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'gender', |  | ||||||
|     long_name: 'Gender', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'birthdate', |  | ||||||
|     long_name: 'Birthday', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'zoneinfo', |  | ||||||
|     long_name: 'Time zone', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'locale', |  | ||||||
|     long_name: 'Locale', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'phone_number', |  | ||||||
|     long_name: 'Preferred telephone number', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'phone_number_verified', |  | ||||||
|     long_name: 'True if the phone number has been verified; otherwise false', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'address', |  | ||||||
|     long_name: 'Preferred postal address', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'updated_at', |  | ||||||
|     long_name: 'Time the information was last updated', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 5.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'azp', |  | ||||||
|     long_name: 'Authorized party - the party to which the ID Token was issued', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 2]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'nonce', |  | ||||||
|     long_name: 'Value used to associate a Client session with an ID Token', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 2]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'auth_time', |  | ||||||
|     long_name: 'Time when the authentication occurred', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 2]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'at_hash', |  | ||||||
|     long_name: 'Access Token hash value', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 2]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'c_hash', |  | ||||||
|     long_name: 'Code hash value', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 3.3.2.11]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'acr', |  | ||||||
|     long_name: 'Authentication Context Class Reference', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 2]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'amr', |  | ||||||
|     long_name: 'Authentication Methods References', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 2]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'sub_jwk', |  | ||||||
|     long_name: 'Public key used to check the signature of an ID Token', |  | ||||||
|     ref: '[OpenID Connect Core 1.0 - Section 7.4]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'cnf', |  | ||||||
|     long_name: 'Confirmation', |  | ||||||
|     ref: '[RFC7800 - Section 3.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'sip_from_tag', |  | ||||||
|     long_name: 'SIP From tag header field parameter value', |  | ||||||
|     ref: '[RFC8055][RFC3261]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'sip_date', |  | ||||||
|     long_name: 'SIP Date header field value', |  | ||||||
|     ref: '[RFC8055][RFC3261]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'sip_callid', |  | ||||||
|     long_name: 'SIP Call-Id header field value', |  | ||||||
|     ref: '[RFC8055][RFC3261]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'sip_cseq_num', |  | ||||||
|     long_name: 'SIP CSeq numeric header field parameter value', |  | ||||||
|     ref: '[RFC8055][RFC3261]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'sip_via_branch', |  | ||||||
|     long_name: 'SIP Via branch header field parameter value', |  | ||||||
|     ref: '[RFC8055][RFC3261]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'orig', |  | ||||||
|     long_name: 'Originating Identity String', |  | ||||||
|     ref: '[RFC8225 - Section 5.2.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'dest', |  | ||||||
|     long_name: 'Destination Identity String', |  | ||||||
|     ref: '[RFC8225 - Section 5.2.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'mky', |  | ||||||
|     long_name: 'Media Key Fingerprint String', |  | ||||||
|     ref: '[RFC8225 - Section 5.2.2]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'events', |  | ||||||
|     long_name: 'Security Events', |  | ||||||
|     ref: '[RFC8417 - Section 2.2]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'toe', |  | ||||||
|     long_name: 'Time of Event', |  | ||||||
|     ref: '[RFC8417 - Section 2.2]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'txn', |  | ||||||
|     long_name: 'Transaction Identifier', |  | ||||||
|     ref: '[RFC8417 - Section 2.2]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'rph', |  | ||||||
|     long_name: 'Resource Priority Header Authorization', |  | ||||||
|     ref: '[RFC8443 - Section 3]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'sid', |  | ||||||
|     long_name: 'Session ID', |  | ||||||
|     ref: '[OpenID Connect Front-Channel Logout 1.0 - Section 3]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'vot', |  | ||||||
|     long_name: 'Vector of Trust value', |  | ||||||
|     ref: '[RFC8485]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'vtm', |  | ||||||
|     long_name: 'Vector of Trust trustmark URL', |  | ||||||
|     ref: '[RFC8485]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'attest', |  | ||||||
|     long_name: 'Attestation level as defined in SHAKEN framework', |  | ||||||
|     ref: '[RFC8588]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'origid', |  | ||||||
|     long_name: 'Originating Identifier as defined in SHAKEN framework', |  | ||||||
|     ref: '[RFC8588]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'act', |  | ||||||
|     long_name: 'Actor', |  | ||||||
|     ref: '[RFC8693 - Section 4.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'scope', |  | ||||||
|     long_name: 'Scope Values', |  | ||||||
|     ref: '[RFC8693 - Section 4.2]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'client_id', |  | ||||||
|     long_name: 'Client Identifier', |  | ||||||
|     ref: '[RFC8693 - Section 4.3]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'may_act', |  | ||||||
|     long_name: 'Authorized Actor - the party that is authorized to become the actor', |  | ||||||
|     ref: '[RFC8693 - Section 4.4]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'jcard', |  | ||||||
|     long_name: 'jCard data', |  | ||||||
|     ref: '[RFC8688][RFC7095]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'at_use_nbr', |  | ||||||
|     long_name: 'Number of API requests for which the access token can be used', |  | ||||||
|     ref: '[ETSI GS NFV-SEC 022 V2.7.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'div', |  | ||||||
|     long_name: 'Diverted Target of a Call', |  | ||||||
|     ref: '[RFC8946]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'opt', |  | ||||||
|     long_name: 'Original PASSporT (in Full Form)', |  | ||||||
|     ref: '[RFC8946]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'vc', |  | ||||||
|     long_name: 'Verifiable Credential as specified in the W3C Recommendation', |  | ||||||
|     ref: '[W3C Recommendation Verifiable Credentials Data Model 1.0 - Expressing verifiable information on the Web (19 November 2019) - Section 6.3.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'vp', |  | ||||||
|     long_name: 'Verifiable Presentation as specified in the W3C Recommendation', |  | ||||||
|     ref: '[W3C Recommendation Verifiable Credentials Data Model 1.0 - Expressing verifiable information on the Web (19 November 2019) - Section 6.3.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'sph', |  | ||||||
|     long_name: 'SIP Priority header field', |  | ||||||
|     ref: '[RFC9027]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'ace_profile', |  | ||||||
|     long_name: 'The ACE profile a token is supposed to be used with.', |  | ||||||
|     ref: '[RFC-ietf-ace-oauth-authz-46 - Section 5.10]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'cnonce', |  | ||||||
|     long_name: |  | ||||||
|       'client-nonce. A nonce previously provided to the AS by the RS via the client. Used to verify token freshness when the RS cannot synchronize its clock with the AS.', |  | ||||||
|     ref: '[RFC-ietf-ace-oauth-authz-46 - Section 5.10]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'exi', |  | ||||||
|     long_name: |  | ||||||
|       'Expires in. Lifetime of the token in seconds from the time the RS first sees it. Used to implement a weaker from of token expiration for devices that cannot synchronize their internal clocks.', |  | ||||||
|     ref: '[RFC-ietf-ace-oauth-authz-46 - Section 5.10.3]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'roles', |  | ||||||
|     long_name: 'Roles', |  | ||||||
|     ref: '[RFC7643 - Section 4.1.2][RFC9068 - Section 2.2.3.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'groups', |  | ||||||
|     long_name: 'Groups', |  | ||||||
|     ref: '[RFC7643 - Section 4.1.2][RFC9068 - Section 2.2.3.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'entitlements', |  | ||||||
|     long_name: 'Entitlements', |  | ||||||
|     ref: '[RFC7643 - Section 4.1.2][RFC9068 - Section 2.2.3.1]', |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     name: 'token_introspection', |  | ||||||
|     long_name: 'Token introspection response', |  | ||||||
|     ref: '[RFC-ietf-oauth-jwt-introspection-response-12 - Section 5]', |  | ||||||
|   }, |  | ||||||
| ]; |  | ||||||
|  | |||||||
| @ -4,48 +4,59 @@ | |||||||
|       <n-input v-model:value="rawJwt" type="textarea" placeholder="Put your token here..." rows="5" /> |       <n-input v-model:value="rawJwt" type="textarea" placeholder="Put your token here..." rows="5" /> | ||||||
|     </n-form-item> |     </n-form-item> | ||||||
| 
 | 
 | ||||||
|     <n-table> |     <n-table v-if="validation.isValid"> | ||||||
|       <tbody> |       <tbody> | ||||||
|         <td colspan="2" class="table-header"><strong>Header</strong></td> |         <template v-for="section of sections" :key="section.key"> | ||||||
|         <tr v-for="[key, value] in Object.entries(decodedJWT.header)" :key="key"> |           <th colspan="2" class="table-header">{{ section.title }}</th> | ||||||
|           <td class="claims"><claim-vue :claim="key" /></td> |           <tr v-for="{ claim, claimDescription, friendlyValue, value } in decodedJWT[section.key]" :key="claim + value"> | ||||||
|  |             <td class="claims"> | ||||||
|  |               <n-space> | ||||||
|  |                 <n-text strong>{{ claim }}</n-text> | ||||||
|  |                 <template v-if="claimDescription"> | ||||||
|  |                   <n-text depth="3">({{ claimDescription }})</n-text> | ||||||
|  |                 </template> | ||||||
|  |               </n-space> | ||||||
|  |             </td> | ||||||
|             <td> |             <td> | ||||||
|             <value-vue :claim="key" :value="value" /> |               <n-space> | ||||||
|           </td> |                 <n-text>{{ value }}</n-text> | ||||||
|         </tr> |                 <template v-if="friendlyValue"> | ||||||
|         <td colspan="2" class="table-header"><strong>Payload</strong></td> |                   <n-text depth="3">({{ friendlyValue }})</n-text> | ||||||
|         <tr v-for="[key, value] in Object.entries(decodedJWT.payload)" :key="key"> |                 </template> | ||||||
|           <td class="claims"><claim-vue :claim="key" /></td> |               </n-space> | ||||||
|           <td> |  | ||||||
|             <value-vue :claim="key" :value="value" /> |  | ||||||
|             </td> |             </td> | ||||||
|           </tr> |           </tr> | ||||||
|  |         </template> | ||||||
|       </tbody> |       </tbody> | ||||||
|     </n-table> |     </n-table> | ||||||
|   </n-card> |   </n-card> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import { computed, ref } from 'vue'; |  | ||||||
| import jwt_decode from 'jwt-decode'; |  | ||||||
| import { useValidation } from '@/composable/validation'; | import { useValidation } from '@/composable/validation'; | ||||||
| import { isNotThrowing } from '@/utils/boolean'; | import { isNotThrowing } from '@/utils/boolean'; | ||||||
| import { safeJwtDecode } from './jwt-parser.service'; | import { withDefaultOnError } from '@/utils/defaults'; | ||||||
| import claimVue from './claim.vue'; | import { computed, ref } from 'vue'; | ||||||
| import valueVue from './value.vue'; | import { decodeJwt } from './jwt-parser.service'; | ||||||
| 
 | 
 | ||||||
| const rawJwt = ref( | const rawJwt = ref( | ||||||
|   'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c', |   'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c', | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| const decodedJWT = computed(() => { | const decodedJWT = computed(() => | ||||||
|   return safeJwtDecode(rawJwt.value); |   withDefaultOnError(() => decodeJwt({ jwt: rawJwt.value }), { header: [], payload: [] }), | ||||||
| }); | ); | ||||||
|  | 
 | ||||||
|  | const sections = [ | ||||||
|  |   { key: 'header', title: 'Header' }, | ||||||
|  |   { key: 'payload', title: 'Payload' }, | ||||||
|  | ] as const; | ||||||
|  | 
 | ||||||
| const validation = useValidation({ | const validation = useValidation({ | ||||||
|   source: rawJwt, |   source: rawJwt, | ||||||
|   rules: [ |   rules: [ | ||||||
|     { |     { | ||||||
|       validator: (value) => value.length > 0 && isNotThrowing(() => jwt_decode(value, { header: true })), |       validator: (value) => value.length > 0 && isNotThrowing(() => decodeJwt({ jwt: rawJwt.value })), | ||||||
|       message: 'Invalid JWT', |       message: 'Invalid JWT', | ||||||
|     }, |     }, | ||||||
|   ], |   ], | ||||||
| @ -56,8 +67,4 @@ const validation = useValidation({ | |||||||
| .table-header { | .table-header { | ||||||
|   text-align: center; |   text-align: center; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| .claims { |  | ||||||
|   width: 20%; |  | ||||||
| } |  | ||||||
| </style> | </style> | ||||||
|  | |||||||
| @ -1,24 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <n-space> |  | ||||||
|     {{ value.value }} |  | ||||||
|     <em v-if="value.extension">({{ value.extension }})</em> |  | ||||||
|   </n-space> |  | ||||||
| </template> |  | ||||||
| 
 |  | ||||||
| <script setup lang="ts"> |  | ||||||
| import { computed } from 'vue'; |  | ||||||
| import { parseClaimValue } from './jwt-parser.service'; |  | ||||||
| 
 |  | ||||||
| const props = defineProps({ |  | ||||||
|   claim: { |  | ||||||
|     type: String, |  | ||||||
|     default: '', |  | ||||||
|   }, |  | ||||||
|   value: { |  | ||||||
|     type: String, |  | ||||||
|     default: '', |  | ||||||
|   }, |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| const value = computed(() => parseClaimValue(props.claim, props.value)); |  | ||||||
| </script> |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user