Merge ec6c5b4066 into e1b4f9aafe
				
					
				
			This commit is contained in:
		
						commit
						82374a0797
					
				
							
								
								
									
										8
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -130,21 +130,14 @@ declare module '@vue/runtime-core' { | ||||
|     NCode: typeof import('naive-ui')['NCode'] | ||||
|     NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] | ||||
|     NConfigProvider: typeof import('naive-ui')['NConfigProvider'] | ||||
|     NDivider: typeof import('naive-ui')['NDivider'] | ||||
|     NEllipsis: typeof import('naive-ui')['NEllipsis'] | ||||
|     NFormItem: typeof import('naive-ui')['NFormItem'] | ||||
|     NGi: typeof import('naive-ui')['NGi'] | ||||
|     NGrid: typeof import('naive-ui')['NGrid'] | ||||
|     NH1: typeof import('naive-ui')['NH1'] | ||||
|     NH3: typeof import('naive-ui')['NH3'] | ||||
|     NIcon: typeof import('naive-ui')['NIcon'] | ||||
|     NInputNumber: typeof import('naive-ui')['NInputNumber'] | ||||
|     NLabel: typeof import('naive-ui')['NLabel'] | ||||
|     NLayout: typeof import('naive-ui')['NLayout'] | ||||
|     NLayoutSider: typeof import('naive-ui')['NLayoutSider'] | ||||
|     NMenu: typeof import('naive-ui')['NMenu'] | ||||
|     NScrollbar: typeof import('naive-ui')['NScrollbar'] | ||||
|     NSpin: typeof import('naive-ui')['NSpin'] | ||||
|     NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default'] | ||||
|     OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] | ||||
|     PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default'] | ||||
| @ -160,6 +153,7 @@ declare module '@vue/runtime-core' { | ||||
|     RouterView: typeof import('vue-router')['RouterView'] | ||||
|     RsaKeyPairGenerator: typeof import('./src/tools/rsa-key-pair-generator/rsa-key-pair-generator.vue')['default'] | ||||
|     SafelinkDecoder: typeof import('./src/tools/safelink-decoder/safelink-decoder.vue')['default'] | ||||
|     SensitiveDataMasker: typeof import('./src/tools/sensitive-data-masker/sensitive-data-masker.vue')['default'] | ||||
|     SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default'] | ||||
|     SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default'] | ||||
|     SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default'] | ||||
|  | ||||
| @ -55,6 +55,7 @@ | ||||
|     "cron-validator": "^1.3.1", | ||||
|     "cronstrue": "^2.26.0", | ||||
|     "crypto-js": "^4.1.1", | ||||
|     "data-guardian": "^1.1.3", | ||||
|     "date-fns": "^2.29.3", | ||||
|     "dompurify": "^3.0.6", | ||||
|     "emojilib": "^3.0.10", | ||||
| @ -64,6 +65,7 @@ | ||||
|     "highlight.js": "^11.7.0", | ||||
|     "iarna-toml-esm": "^3.0.5", | ||||
|     "ibantools": "^4.3.3", | ||||
|     "ip-regex": "^5.0.0", | ||||
|     "js-base64": "^3.7.6", | ||||
|     "json5": "^2.2.3", | ||||
|     "jwt-decode": "^3.1.2", | ||||
|  | ||||
							
								
								
									
										35
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										35
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							| @ -65,6 +65,9 @@ dependencies: | ||||
|   crypto-js: | ||||
|     specifier: ^4.1.1 | ||||
|     version: 4.1.1 | ||||
|   data-guardian: | ||||
|     specifier: ^1.1.3 | ||||
|     version: 1.1.3 | ||||
|   date-fns: | ||||
|     specifier: ^2.29.3 | ||||
|     version: 2.29.3 | ||||
| @ -92,6 +95,9 @@ dependencies: | ||||
|   ibantools: | ||||
|     specifier: ^4.3.3 | ||||
|     version: 4.3.3 | ||||
|   ip-regex: | ||||
|     specifier: ^5.0.0 | ||||
|     version: 5.0.0 | ||||
|   js-base64: | ||||
|     specifier: ^3.7.6 | ||||
|     version: 3.7.7 | ||||
| @ -3354,7 +3360,7 @@ packages: | ||||
|     dependencies: | ||||
|       '@unhead/dom': 0.5.1 | ||||
|       '@unhead/schema': 0.5.1 | ||||
|       '@vueuse/shared': 10.8.0(vue@3.3.4) | ||||
|       '@vueuse/shared': 10.11.0(vue@3.3.4) | ||||
|       unhead: 0.5.1 | ||||
|       vue: 3.3.4 | ||||
|     transitivePeerDependencies: | ||||
| @ -3987,19 +3993,19 @@ packages: | ||||
|       - vue | ||||
|     dev: false | ||||
| 
 | ||||
|   /@vueuse/shared@10.3.0(vue@3.3.4): | ||||
|     resolution: {integrity: sha512-kGqCTEuFPMK4+fNWy6dUOiYmxGcUbtznMwBZLC1PubidF4VZY05B+Oht7Jh7/6x4VOWGpvu3R37WHi81cKpiqg==} | ||||
|   /@vueuse/shared@10.11.0(vue@3.3.4): | ||||
|     resolution: {integrity: sha512-fyNoIXEq3PfX1L3NkNhtVQUSRtqYwJtJg+Bp9rIzculIZWHTkKSysujrOk2J+NrRulLTQH9+3gGSfYLWSEWU1A==} | ||||
|     dependencies: | ||||
|       vue-demi: 0.14.5(vue@3.3.4) | ||||
|       vue-demi: 0.14.8(vue@3.3.4) | ||||
|     transitivePeerDependencies: | ||||
|       - '@vue/composition-api' | ||||
|       - vue | ||||
|     dev: false | ||||
| 
 | ||||
|   /@vueuse/shared@10.8.0(vue@3.3.4): | ||||
|     resolution: {integrity: sha512-dUdy6zwHhULGxmr9YUg8e+EnB39gcM4Fe2oKBSrh3cOsV30JcMPtsyuspgFCUo5xxFNaeMf/W2yyKfST7Bg8oQ==} | ||||
|   /@vueuse/shared@10.3.0(vue@3.3.4): | ||||
|     resolution: {integrity: sha512-kGqCTEuFPMK4+fNWy6dUOiYmxGcUbtznMwBZLC1PubidF4VZY05B+Oht7Jh7/6x4VOWGpvu3R37WHi81cKpiqg==} | ||||
|     dependencies: | ||||
|       vue-demi: 0.14.7(vue@3.3.4) | ||||
|       vue-demi: 0.14.5(vue@3.3.4) | ||||
|     transitivePeerDependencies: | ||||
|       - '@vue/composition-api' | ||||
|       - vue | ||||
| @ -4719,6 +4725,11 @@ packages: | ||||
|     resolution: {integrity: sha512-4FbVrHDwfOASx7uQVxeiCTo7ggSdYZbqs8lH+WU6ViypPlDbe9y6IP5VVUDQBv9DcnyaiPT5XT0UWHgJ64zLeQ==} | ||||
|     dev: false | ||||
| 
 | ||||
|   /data-guardian@1.1.3: | ||||
|     resolution: {integrity: sha512-8M9KHTopFp3MXo7NelcmF+8L77S5jeDy3Uv4RWuYIQSaBZTawvY6W3ad/eLe8db2FcLPoC44DHJb4zWNcpoueQ==} | ||||
|     engines: {node: '>=12'} | ||||
|     dev: false | ||||
| 
 | ||||
|   /data-uri-to-buffer@4.0.1: | ||||
|     resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} | ||||
|     engines: {node: '>= 12'} | ||||
| @ -6188,6 +6199,11 @@ packages: | ||||
|       jsbn: 1.1.0 | ||||
|     dev: false | ||||
| 
 | ||||
|   /ip-regex@5.0.0: | ||||
|     resolution: {integrity: sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==} | ||||
|     engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} | ||||
|     dev: false | ||||
| 
 | ||||
|   /is-alphabetical@1.0.4: | ||||
|     resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} | ||||
|     dev: true | ||||
| @ -9158,8 +9174,8 @@ packages: | ||||
|       vue: 3.3.4 | ||||
|     dev: false | ||||
| 
 | ||||
|   /vue-demi@0.14.7(vue@3.3.4): | ||||
|     resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==} | ||||
|   /vue-demi@0.14.8(vue@3.3.4): | ||||
|     resolution: {integrity: sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==} | ||||
|     engines: {node: '>=12'} | ||||
|     hasBin: true | ||||
|     requiresBuild: true | ||||
| @ -9449,6 +9465,7 @@ packages: | ||||
| 
 | ||||
|   /workbox-google-analytics@7.0.0: | ||||
|     resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==} | ||||
|     deprecated: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained | ||||
|     dependencies: | ||||
|       workbox-background-sync: 7.0.0 | ||||
|       workbox-core: 7.0.0 | ||||
|  | ||||
| @ -6,6 +6,7 @@ import { tool as asciiTextDrawer } from './ascii-text-drawer'; | ||||
| 
 | ||||
| import { tool as textToUnicode } from './text-to-unicode'; | ||||
| import { tool as safelinkDecoder } from './safelink-decoder'; | ||||
| import { tool as sensitiveDataMasker } from './sensitive-data-masker'; | ||||
| import { tool as pdfSignatureChecker } from './pdf-signature-checker'; | ||||
| import { tool as numeronymGenerator } from './numeronym-generator'; | ||||
| import { tool as macAddressGenerator } from './mac-address-generator'; | ||||
| @ -172,6 +173,7 @@ export const toolsByCategory: ToolCategory[] = [ | ||||
|       textDiff, | ||||
|       numeronymGenerator, | ||||
|       asciiTextDrawer, | ||||
|       sensitiveDataMasker, | ||||
|     ], | ||||
|   }, | ||||
|   { | ||||
|  | ||||
							
								
								
									
										12
									
								
								src/tools/sensitive-data-masker/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/tools/sensitive-data-masker/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| import { ShieldLock } from '@vicons/tabler'; | ||||
| import { defineTool } from '../tool'; | ||||
| 
 | ||||
| export const tool = defineTool({ | ||||
|   name: 'Sensitive data masker', | ||||
|   path: '/sensitive-data-masker', | ||||
|   description: 'Clean sensitive data from textual content (ie logs)', | ||||
|   keywords: ['sensitive', 'data', 'masker', 'obfuscator', 'clean', 'log'], | ||||
|   component: () => import('./sensitive-data-masker.vue'), | ||||
|   icon: ShieldLock, | ||||
|   createdAt: new Date('2024-06-16'), | ||||
| }); | ||||
| @ -0,0 +1,75 @@ | ||||
| import { describe, expect, it } from 'vitest'; | ||||
| import { maskSensitiveData } from './sensitive-data-masker.service'; | ||||
| 
 | ||||
| describe('sensitive-data-masker', () => { | ||||
|   describe('maskSensitiveData', () => { | ||||
|     const data = `{
 | ||||
|   email: 'john.doe@example.com', | ||||
|   creditCard: '1234 5678 9000 9876', | ||||
|   id: '3f8a43fd-6489-4ec7-bd55-7a1ba172d77b', | ||||
|   name: 'John', | ||||
|   surname: 'Doe', | ||||
|   phone: '+358 40 1234567', | ||||
|   url: 'truc.google.com', | ||||
|   ip4: '83.24.45.56', | ||||
|   ip6: '2001:db8:0:85a3:0:0:ac1f:8001', | ||||
|   mac: '3D:F2:C9:A6:B3:4F', | ||||
|   token: 'eyJhbGciOiJIUzI1NiJ9.ew0KICAic3ViIjogIjEyMzQ1Njc4OTAiLA0KICAibmFtZSI6ICJBbGV4IEtvemxvdiIsDQogICJpYXQiOiAxNTE2MjM5MDIyDQp9.PNKysYFTCenU5bekHCmwIxCUXoYG41H_xc3uN3ZF_b8', | ||||
| }`;
 | ||||
| 
 | ||||
|     it('should maks sensitive data', () => { | ||||
|       expect(maskSensitiveData({ | ||||
|         value: data, | ||||
|       })).toBe(`{
 | ||||
|   email: 'jo****************om', | ||||
|   creditCard: '12***************76', | ||||
|   id: '3f********************************7b', | ||||
|   name: 'John', | ||||
|   surname: 'Doe', | ||||
|   phone: '+3***********67', | ||||
|   url: 'tr***********om', | ||||
|   ip4: '83*******56', | ||||
|   ip6: '20*************************01', | ||||
|   mac: '3D*************4F', | ||||
|   token: 'ey*****************************************************************************************************************************************************************b8', | ||||
| }`);
 | ||||
|     }); | ||||
|     it('should maks sensitive data (with custom regex)', () => { | ||||
|       expect(maskSensitiveData({ | ||||
|         value: data, | ||||
|         customRegex: 'John\nDoe', | ||||
|       })).toBe(`{
 | ||||
|   email: 'jo****************om', | ||||
|   creditCard: '12***************76', | ||||
|   id: '3f********************************7b', | ||||
|   name: '****', | ||||
|   surname: '***', | ||||
|   phone: '+3***********67', | ||||
|   url: 'tr***********om', | ||||
|   ip4: '83*******56', | ||||
|   ip6: '20*************************01', | ||||
|   mac: '3D*************4F', | ||||
|   token: 'ey*****************************************************************************************************************************************************************b8', | ||||
| }`);
 | ||||
|     }); | ||||
| 
 | ||||
|     it('should maks sensitive data (with excluded matchers)', () => { | ||||
|       expect(maskSensitiveData({ | ||||
|         value: data, | ||||
|         excludedMatchers: ['mac', 'ipv4'], | ||||
|       })).toBe(`{
 | ||||
|   email: 'jo****************om', | ||||
|   creditCard: '12***************76', | ||||
|   id: '3f********************************7b', | ||||
|   name: 'John', | ||||
|   surname: 'Doe', | ||||
|   phone: '+3***********67', | ||||
|   url: 'tr***********om', | ||||
|   ip4: '83.24.45.56', | ||||
|   ip6: '20*************************01', | ||||
|   mac: '3D:F2:C9:A6:B3:4F', | ||||
|   token: 'ey*****************************************************************************************************************************************************************b8', | ||||
| }`);
 | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| @ -0,0 +1,34 @@ | ||||
| import { type SensitiveContentKey, maskString } from 'data-guardian'; | ||||
| import ipRegex from 'ip-regex'; | ||||
| 
 | ||||
| const jwtRegex = /\b([a-zA-Z0-9_=]{5,})\.([a-zA-Z0-9_=]{5,})\.([a-zA-Z0-9_\-\+\/=]{5,})\b/g; | ||||
| const phoneRegex = /(?:(\+\d{1,4})[-.\s]?)(?:[(](\d{1,3})[)][-.\s]?)?(\d{1,4})[-.\s]?(\d{1,4})[-.\s]?(\d{1,9})\b/g; | ||||
| const macRegex = /\b([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})\b/g; | ||||
| const urlWithOrWithoutPrefixRegex = /\b(https?:\/\/)?(www\.)?[a-zA-Z0-9@:%._+~#=-]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&\/=]*)\b/g; | ||||
| 
 | ||||
| export type MatcherNames = 'uuid' | 'creditCard' | 'ssn' | 'url' | 'ipv4' | 'email' | 'passwordInUri' | 'mac' | 'ipv6' | 'urlWithOrWithoutPrefix' | 'jwt' | 'phone'; | ||||
| 
 | ||||
| export function maskSensitiveData({ | ||||
|   value, | ||||
|   customRegex = '', | ||||
|   excludedMatchers = [], | ||||
| }: { | ||||
|   value: string | ||||
|   customRegex?: string | ||||
|   excludedMatchers?: Array<MatcherNames> | ||||
| }) { | ||||
|   excludedMatchers = excludedMatchers || []; | ||||
|   const emptyRegex = /(?:)/g; | ||||
|   return maskString(value, null as never, { | ||||
|     customRegex: new RegExp((customRegex || '').split('\n').map(line => `(${line})`).join('|'), 'gi'), | ||||
|     macRegex: excludedMatchers.includes('mac') ? emptyRegex : macRegex, | ||||
|     ipv6Regex: excludedMatchers.includes('ipv6') ? emptyRegex : ipRegex.v6({ includeBoundaries: false }), | ||||
|     urlWithOrWithoutPrefixRegex: excludedMatchers.includes('urlWithOrWithoutPrefix') ? emptyRegex : urlWithOrWithoutPrefixRegex, | ||||
|     jwtRegex: excludedMatchers.includes('jwt') ? emptyRegex : jwtRegex, | ||||
|     phoneRegex: excludedMatchers.includes('phone') ? emptyRegex : phoneRegex, | ||||
|   }, { | ||||
|     excludeMatchers: [...excludedMatchers, ...[ | ||||
|       'passwordMention', 'password', 'passwordSubstring', | ||||
|     ]] as SensitiveContentKey[], | ||||
|   }); | ||||
| } | ||||
							
								
								
									
										64
									
								
								src/tools/sensitive-data-masker/sensitive-data-masker.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/tools/sensitive-data-masker/sensitive-data-masker.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | ||||
| <script setup lang="ts"> | ||||
| import { type MatcherNames, maskSensitiveData } from './sensitive-data-masker.service'; | ||||
| import { withDefaultOnError } from '@/utils/defaults'; | ||||
| 
 | ||||
| const defaultValue = `{ | ||||
|   email: 'john.doe@example.com', | ||||
|   creditCard: '1234 5678 9000 9876', | ||||
|   id: '3f8a43fd-6489-4ec7-bd55-7a1ba172d77b', | ||||
|   name: 'John', | ||||
|   surname: 'Doe', | ||||
|   phone: '+358 40 1234567', | ||||
|   url: 'truc.google.com', | ||||
|   ip4: '83.24.45.56', | ||||
|   ip6: '2001:db8:0:85a3:0:0:ac1f:8001', | ||||
|   mac: '3D:F2:C9:A6:B3:4F', | ||||
|   token: 'eyJhbGciOiJIUzI1NiJ9.ew0KICAic3ViIjogIjEyMzQ1Njc4OTAiLA0KICAibmFtZSI6ICJBbGV4IEtvemxvdiIsDQogICJpYXQiOiAxNTE2MjM5MDIyDQp9.PNKysYFTCenU5bekHCmwIxCUXoYG41H_xc3uN3ZF_b8', | ||||
| }`; | ||||
| 
 | ||||
| const customRegex = useStorage('sensitive-data:regex', ''); | ||||
| const excludedMatchers = useStorage('sensitive-data:exclude', [] as string[]); | ||||
| const allMatchers = [ | ||||
|   'uuid', 'creditCard', 'ssn', 'url', 'ipv4', 'email', | ||||
|   'passwordInUri', 'mac', 'ipv6', 'urlWithOrWithoutPrefix', | ||||
|   'jwt', 'phone']; | ||||
| 
 | ||||
| function transformer(value: string) { | ||||
|   return withDefaultOnError(() => maskSensitiveData({ | ||||
|     value, | ||||
|     customRegex: customRegex.value, | ||||
|     excludedMatchers: excludedMatchers.value as MatcherNames[], | ||||
|   }), ''); | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <div style="max-width: 600px;"> | ||||
|     <c-input-text | ||||
|       v-model:value="customRegex" | ||||
|       label="Your custom cleaning regex(es) (case insensitive):" | ||||
|       placeholder="Your custom cleaning regex(es)" | ||||
|       raw-text | ||||
|       multiline | ||||
|       rows="4" | ||||
|       mb-2 | ||||
|     /> | ||||
| 
 | ||||
|     <n-select | ||||
|       v-model:value="excludedMatchers" | ||||
|       placeholder="No Fallback" | ||||
|       multiple | ||||
|       :fallback-option="false" | ||||
|       :options="allMatchers.map(v => ({ label: v, value: v }))" | ||||
|       mb-2 | ||||
|     /> | ||||
| 
 | ||||
|     <format-transformer | ||||
|       input-label="Your log/textual data:" | ||||
|       :input-default="defaultValue" | ||||
|       input-placeholder="Paste your log/textual data here..." | ||||
|       output-label="Cleaned version:" | ||||
|       :transformer="transformer" | ||||
|     /> | ||||
|   </div> | ||||
| </template> | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user