parent
							
								
									ee04bfed87
								
							
						
					
					
						commit
						3d63fde283
					
				
							
								
								
									
										3
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -127,6 +127,7 @@ declare module '@vue/runtime-core' { | ||||
|     MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default'] | ||||
|     MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] | ||||
|     NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] | ||||
|     NCheckbox: typeof import('naive-ui')['NCheckbox'] | ||||
|     NCode: typeof import('naive-ui')['NCode'] | ||||
|     NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] | ||||
|     NConfigProvider: typeof import('naive-ui')['NConfigProvider'] | ||||
| @ -145,6 +146,7 @@ declare module '@vue/runtime-core' { | ||||
|     NMenu: typeof import('naive-ui')['NMenu'] | ||||
|     NScrollbar: typeof import('naive-ui')['NScrollbar'] | ||||
|     NSpin: typeof import('naive-ui')['NSpin'] | ||||
|     NTable: typeof import('naive-ui')['NTable'] | ||||
|     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'] | ||||
| @ -159,6 +161,7 @@ declare module '@vue/runtime-core' { | ||||
|     RouterLink: typeof import('vue-router')['RouterLink'] | ||||
|     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'] | ||||
|     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'] | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import { describe, expect, it } from 'vitest'; | ||||
| import { computeChmodOctalRepresentation, computeChmodSymbolicRepresentation, computePermissionsFromChmodOctalRepresentation } from './chmod-calculator.service'; | ||||
| import { computeChmodOctalRepresentation, computeChmodSymbolicRepresentation, computePermissionsFromChmodOctalRepresentation, computePermissionsFromChmodSymbolicRepresentation } from './chmod-calculator.service'; | ||||
| 
 | ||||
| describe('chmod-calculator', () => { | ||||
|   describe('computeChmodOctalRepresentation', () => { | ||||
| @ -339,4 +339,119 @@ describe('chmod-calculator', () => { | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
|   describe('computePermissionsFromChmodSymbolicRepresentation', () => { | ||||
|     it('throws on invalid symbolic values', () => { | ||||
|       expect(() => computePermissionsFromChmodSymbolicRepresentation('rr---')).to.throw(); | ||||
|       expect(() => computePermissionsFromChmodSymbolicRepresentation('rwxrwx--w')).to.throw(); | ||||
|     }); | ||||
| 
 | ||||
|     it('get permissions from symbolic representation', () => { | ||||
|       expect( | ||||
|         computePermissionsFromChmodSymbolicRepresentation('dr-xr-xr-x'), | ||||
|       ).to.eql({ | ||||
|         owner: { read: true, write: false, execute: true }, | ||||
|         group: { read: true, write: false, execute: true }, | ||||
|         public: { read: true, write: false, execute: true }, | ||||
|         flags: { setuid: false, setgid: false, stickybit: false }, | ||||
|       }); | ||||
|       expect( | ||||
|         computePermissionsFromChmodSymbolicRepresentation('-rw-r--r--'), | ||||
|       ).to.eql({ | ||||
|         owner: { read: true, write: true, execute: false }, | ||||
|         group: { read: true, write: false, execute: false }, | ||||
|         public: { read: true, write: false, execute: false }, | ||||
|         flags: { setuid: false, setgid: false, stickybit: false }, | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computePermissionsFromChmodSymbolicRepresentation('rwxrwxrwx'), | ||||
|       ).to.eql({ | ||||
|         owner: { read: true, write: true, execute: true }, | ||||
|         group: { read: true, write: true, execute: true }, | ||||
|         public: { read: true, write: true, execute: true }, | ||||
|         flags: { setuid: false, setgid: false, stickybit: false }, | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computePermissionsFromChmodSymbolicRepresentation('---------'), | ||||
|       ).to.eql({ | ||||
|         owner: { read: false, write: false, execute: false }, | ||||
|         group: { read: false, write: false, execute: false }, | ||||
|         public: { read: false, write: false, execute: false }, | ||||
|         flags: { setuid: false, setgid: false, stickybit: false }, | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computePermissionsFromChmodSymbolicRepresentation('r---wxr-x'), | ||||
|       ).to.eql({ | ||||
|         owner: { read: true, write: false, execute: false }, | ||||
|         group: { read: false, write: true, execute: true }, | ||||
|         public: { read: true, write: false, execute: true }, | ||||
|         flags: { setuid: false, setgid: false, stickybit: false }, | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computePermissionsFromChmodSymbolicRepresentation('r---w---x'), | ||||
|       ).to.eql({ | ||||
|         owner: { read: true, write: false, execute: false }, | ||||
|         group: { read: false, write: true, execute: false }, | ||||
|         public: { read: false, write: false, execute: true }, | ||||
|         flags: { setuid: false, setgid: false, stickybit: false }, | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computePermissionsFromChmodSymbolicRepresentation('--x-w-r--'), | ||||
|       ).to.eql({ | ||||
|         owner: { read: false, write: false, execute: true }, | ||||
|         group: { read: false, write: true, execute: false }, | ||||
|         public: { read: true, write: false, execute: false }, | ||||
|         flags: { setuid: false, setgid: false, stickybit: false }, | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computePermissionsFromChmodSymbolicRepresentation('-w--w--w-'), | ||||
|       ).to.eql({ | ||||
|         owner: { read: false, write: true, execute: false }, | ||||
|         group: { read: false, write: true, execute: false }, | ||||
|         public: { read: false, write: true, execute: false }, | ||||
|         flags: { setuid: false, setgid: false, stickybit: false }, | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computePermissionsFromChmodSymbolicRepresentation('-ws-ws-wt'), | ||||
|       ).to.eql({ | ||||
|         owner: { read: false, write: true, execute: true }, | ||||
|         group: { read: false, write: true, execute: true }, | ||||
|         public: { read: false, write: true, execute: true }, | ||||
|         flags: { setuid: true, setgid: true, stickybit: true }, | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computePermissionsFromChmodSymbolicRepresentation('-ws-w--w-'), | ||||
|       ).to.eql({ | ||||
|         owner: { read: false, write: true, execute: true }, | ||||
|         group: { read: false, write: true, execute: false }, | ||||
|         public: { read: false, write: true, execute: false }, | ||||
|         flags: { setuid: true, setgid: false, stickybit: false }, | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computePermissionsFromChmodSymbolicRepresentation('-w--ws-w-'), | ||||
|       ).to.eql({ | ||||
|         owner: { read: false, write: true, execute: false }, | ||||
|         group: { read: false, write: true, execute: true }, | ||||
|         public: { read: false, write: true, execute: false }, | ||||
|         flags: { setuid: false, setgid: true, stickybit: false }, | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computePermissionsFromChmodSymbolicRepresentation('-w--w--wt'), | ||||
|       ).to.eql({ | ||||
|         owner: { read: false, write: true, execute: false }, | ||||
|         group: { read: false, write: true, execute: false }, | ||||
|         public: { read: false, write: true, execute: true }, | ||||
|         flags: { setuid: false, setgid: false, stickybit: true }, | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| import _ from 'lodash'; | ||||
| import type { GroupPermissions, Permissions, SpecialPermissions } from './chmod-calculator.types'; | ||||
| 
 | ||||
| export { computeChmodOctalRepresentation, computeChmodSymbolicRepresentation, computePermissionsFromChmodOctalRepresentation }; | ||||
| export { computeChmodOctalRepresentation, computeChmodSymbolicRepresentation, computePermissionsFromChmodOctalRepresentation, computePermissionsFromChmodSymbolicRepresentation }; | ||||
| 
 | ||||
| function computeChmodOctalRepresentation({ permissions }: { permissions: Permissions }): string { | ||||
|   const permissionValue = { read: 4, write: 2, execute: 1 }; | ||||
| @ -61,3 +61,28 @@ function computePermissionsFromChmodOctalRepresentation(octalPermissions: string | ||||
|     flags: computePermissionObject(specialPermissionValue, flagsPosition), | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| function computePermissionsFromChmodSymbolicRepresentation(symbolicPermissions: string): Permissions { | ||||
|   const formatRegex = /^[-dlbcsp]?([r-])([w-])([xs-])([r-])([w-])([xs-])([r-])([w-])([xt-])$/; | ||||
|   if (!symbolicPermissions || !symbolicPermissions.match(formatRegex)) { | ||||
|     throw new Error(`Invalid string permissions (must be in form 'rwxrwxrwx'): ${symbolicPermissions}`); | ||||
|   } | ||||
| 
 | ||||
|   const [_, rOwner, wOwner, xOwner, rGroup, wGroup, xGroup, rAll, wAll, xAll] = formatRegex.exec(symbolicPermissions) || []; | ||||
|   const getOctal = (flag: string, flagLetter: string, flagValue: number) => flag === flagLetter ? flagValue : 0; | ||||
|   const owner = getOctal(rOwner, 'r', 4) | ||||
|   + getOctal(wOwner, 'w', 2) | ||||
|   + getOctal(xOwner, 'x', 1) + getOctal(xOwner, 's', 1); | ||||
|   const groups = getOctal(rGroup, 'r', 4) | ||||
|   + getOctal(wGroup, 'w', 2) | ||||
|   + getOctal(xGroup, 'x', 1) + getOctal(xGroup, 's', 1); | ||||
|   const all = getOctal(rAll, 'r', 4) | ||||
|   + getOctal(wAll, 'w', 2) | ||||
|   + getOctal(xAll, 'x', 1) + getOctal(xAll, 't', 1); | ||||
|   const flags = getOctal(xOwner, 's', 4) | ||||
|     + getOctal(xGroup, 's', 2) | ||||
|     + getOctal(xAll, 't', 1); | ||||
|   const octalString = `${(flags > 0 ? flags : '')}${owner}${groups}${all}`; | ||||
| 
 | ||||
|   return computePermissionsFromChmodOctalRepresentation(octalString); | ||||
| } | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| import { useThemeVars } from 'naive-ui'; | ||||
| 
 | ||||
| import InputCopyable from '../../components/InputCopyable.vue'; | ||||
| import { computeChmodOctalRepresentation, computeChmodSymbolicRepresentation, computePermissionsFromChmodOctalRepresentation } from './chmod-calculator.service'; | ||||
| import { computeChmodOctalRepresentation, computeChmodSymbolicRepresentation, computePermissionsFromChmodOctalRepresentation, computePermissionsFromChmodSymbolicRepresentation } from './chmod-calculator.service'; | ||||
| 
 | ||||
| import type { Group, Scope } from './chmod-calculator.types'; | ||||
| import { useValidation } from '@/composable/validation'; | ||||
| @ -23,9 +23,9 @@ const permissions = ref({ | ||||
|   flags: { setuid: false, setgid: false, stickybit: false }, | ||||
| }); | ||||
| 
 | ||||
| const permissionsInput = ref('000'); | ||||
| const permissionsInputValidation = useValidation({ | ||||
|   source: permissionsInput, | ||||
| const octalPermissionsInput = ref('000'); | ||||
| const octalPermissionsInputValidation = useValidation({ | ||||
|   source: octalPermissionsInput, | ||||
|   rules: [ | ||||
|     { | ||||
|       message: 'Invalid octal permission string', | ||||
| @ -42,15 +42,43 @@ const permissionsInputValidation = useValidation({ | ||||
|   ], | ||||
| }); | ||||
| watch( | ||||
|   permissionsInput, | ||||
|   octalPermissionsInput, | ||||
|   (newPermissions) => { | ||||
|     if (!permissionsInputValidation.isValid) { | ||||
|     if (!octalPermissionsInputValidation.isValid) { | ||||
|       return; | ||||
|     } | ||||
|     permissions.value = computePermissionsFromChmodOctalRepresentation(newPermissions.trim()); | ||||
|   }, | ||||
| ); | ||||
| 
 | ||||
| const symbolicPermissionsInput = ref('---------'); | ||||
| const symbolicPermissionsInputValidation = useValidation({ | ||||
|   source: symbolicPermissionsInput, | ||||
|   rules: [ | ||||
|     { | ||||
|       message: 'Invalid symbolic permission string', | ||||
|       validator: (value) => { | ||||
|         try { | ||||
|           computePermissionsFromChmodSymbolicRepresentation(value.trim()); | ||||
|           return true; | ||||
|         } | ||||
|         catch { | ||||
|           return false; | ||||
|         } | ||||
|       }, | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
| watch( | ||||
|   symbolicPermissionsInput, | ||||
|   (newPermissions) => { | ||||
|     if (!symbolicPermissionsInputValidation.isValid) { | ||||
|       return; | ||||
|     } | ||||
|     permissions.value = computePermissionsFromChmodSymbolicRepresentation(newPermissions.trim()); | ||||
|   }, | ||||
| ); | ||||
| 
 | ||||
| const octal = computed(() => computeChmodOctalRepresentation({ permissions: permissions.value })); | ||||
| const symbolic = computed(() => computeChmodSymbolicRepresentation({ permissions: permissions.value })); | ||||
| </script> | ||||
| @ -58,13 +86,25 @@ const symbolic = computed(() => computeChmodSymbolicRepresentation({ permissions | ||||
| <template> | ||||
|   <div> | ||||
|     <c-input-text | ||||
|       v-model:value="permissionsInput" | ||||
|       v-model:value="octalPermissionsInput" | ||||
|       placeholder="Put your octal permissions here..." | ||||
|       label="Copy your octal permissions" | ||||
|       :validation="permissionsInputValidation" | ||||
|       :validation="octalPermissionsInputValidation" | ||||
|       mb-2 | ||||
|     /> | ||||
| 
 | ||||
|     <n-divider /> | ||||
| 
 | ||||
|     <c-input-text | ||||
|       v-model:value="symbolicPermissionsInput" | ||||
|       placeholder="Put your symbolic permissions here..." | ||||
|       label="Copy your symbolic permissions" | ||||
|       :validation="symbolicPermissionsInputValidation" | ||||
|       mb-2 | ||||
|     /> | ||||
| 
 | ||||
|     <n-divider /> | ||||
| 
 | ||||
|     <n-table :bordered="false" :bottom-bordered="false" single-column class="permission-table"> | ||||
|       <thead> | ||||
|         <tr> | ||||
|  | ||||
| @ -1,11 +1,10 @@ | ||||
| import { FileInvoice } from '@vicons/tabler'; | ||||
| import { defineTool } from '../tool'; | ||||
| import { translate } from '@/plugins/i18n.plugin'; | ||||
| 
 | ||||
| export const tool = defineTool({ | ||||
|   name: translate('tools.chmod-calculator.title'), | ||||
|   name: 'Chmod calculator', | ||||
|   path: '/chmod-calculator', | ||||
|   description: translate('tools.chmod-calculator.description'), | ||||
|   description: 'Compute your chmod permissions and commands with this online chmod calculator.', | ||||
|   keywords: [ | ||||
|     'chmod', | ||||
|     'calculator', | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user