Merge 4f5a09ed89 into 318fb6efb9
				
					
				
			This commit is contained in:
		
						commit
						93e3d32a2c
					
				
							
								
								
									
										3
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -129,6 +129,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'] | ||||
| @ -143,6 +144,8 @@ declare module '@vue/runtime-core' { | ||||
|     NLayoutSider: typeof import('naive-ui')['NLayoutSider'] | ||||
|     NMenu: typeof import('naive-ui')['NMenu'] | ||||
|     NScrollbar: typeof import('naive-ui')['NScrollbar'] | ||||
|     NSpin: typeof import('naive-ui')['NSpin'] | ||||
|     NTable: typeof import('naive-ui')['NTable'] | ||||
|     NSlider: typeof import('naive-ui')['NSlider'] | ||||
|     NSwitch: typeof import('naive-ui')['NSwitch'] | ||||
|     NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default'] | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import { describe, expect, it } from 'vitest'; | ||||
| import { computeChmodOctalRepresentation, computeChmodSymbolicRepresentation } from './chmod-calculator.service'; | ||||
| import { computeChmodOctalRepresentation, computeChmodSymbolicRepresentation, computePermissionsFromChmodOctalRepresentation, computePermissionsFromChmodSymbolicRepresentation, computeUmaskRepresentation } from './chmod-calculator.service'; | ||||
| 
 | ||||
| describe('chmod-calculator', () => { | ||||
|   describe('computeChmodOctalRepresentation', () => { | ||||
| @ -10,6 +10,7 @@ describe('chmod-calculator', () => { | ||||
|             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 }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('777'); | ||||
| @ -20,6 +21,7 @@ describe('chmod-calculator', () => { | ||||
|             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 }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('000'); | ||||
| @ -30,6 +32,7 @@ describe('chmod-calculator', () => { | ||||
|             owner: { read: false, write: true, execute: false }, | ||||
|             group: { read: false, write: true, execute: true }, | ||||
|             public: { read: true, write: false, execute: true }, | ||||
|             flags: { setuid: false, setgid: false, stickybit: false }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('235'); | ||||
| @ -40,6 +43,7 @@ describe('chmod-calculator', () => { | ||||
|             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 }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('421'); | ||||
| @ -50,6 +54,7 @@ describe('chmod-calculator', () => { | ||||
|             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 }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('124'); | ||||
| @ -60,11 +65,57 @@ describe('chmod-calculator', () => { | ||||
|             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 }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('222'); | ||||
|     }); | ||||
| 
 | ||||
|       expect( | ||||
|         computeChmodOctalRepresentation({ | ||||
|           permissions: { | ||||
|             owner: { read: false, write: true, execute: false }, | ||||
|             group: { read: false, write: true, execute: false }, | ||||
|             public: { read: false, write: true, execute: false }, | ||||
|             flags: { setuid: true, setgid: true, stickybit: true }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('7222'); | ||||
| 
 | ||||
|       expect( | ||||
|         computeChmodOctalRepresentation({ | ||||
|           permissions: { | ||||
|             owner: { read: false, write: true, execute: false }, | ||||
|             group: { read: false, write: true, execute: false }, | ||||
|             public: { read: false, write: true, execute: false }, | ||||
|             flags: { setuid: true, setgid: false, stickybit: false }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('4222'); | ||||
| 
 | ||||
|       expect( | ||||
|         computeChmodOctalRepresentation({ | ||||
|           permissions: { | ||||
|             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: true, stickybit: false }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('2222'); | ||||
| 
 | ||||
|       expect( | ||||
|         computeChmodOctalRepresentation({ | ||||
|           permissions: { | ||||
|             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: true }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('1222'); | ||||
|     }); | ||||
|   }); | ||||
|   describe('computeChmodSymbolicRepresentation', () => { | ||||
|     it('get the symbolic representation from permissions', () => { | ||||
|       expect( | ||||
|         computeChmodSymbolicRepresentation({ | ||||
| @ -72,6 +123,7 @@ describe('chmod-calculator', () => { | ||||
|             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 }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('rwxrwxrwx'); | ||||
| @ -82,6 +134,7 @@ describe('chmod-calculator', () => { | ||||
|             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 }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('---------'); | ||||
| @ -92,6 +145,7 @@ describe('chmod-calculator', () => { | ||||
|             owner: { read: false, write: true, execute: false }, | ||||
|             group: { read: false, write: true, execute: true }, | ||||
|             public: { read: true, write: false, execute: true }, | ||||
|             flags: { setuid: false, setgid: false, stickybit: false }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('-w--wxr-x'); | ||||
| @ -102,6 +156,7 @@ describe('chmod-calculator', () => { | ||||
|             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 }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('r---w---x'); | ||||
| @ -112,6 +167,7 @@ describe('chmod-calculator', () => { | ||||
|             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 }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('--x-w-r--'); | ||||
| @ -122,9 +178,382 @@ describe('chmod-calculator', () => { | ||||
|             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 }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('-w--w--w-'); | ||||
| 
 | ||||
|       expect( | ||||
|         computeChmodSymbolicRepresentation({ | ||||
|           permissions: { | ||||
|             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: true }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('--x-w-r-t'); | ||||
| 
 | ||||
|       expect( | ||||
|         computeChmodSymbolicRepresentation({ | ||||
|           permissions: { | ||||
|             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: true, stickybit: true }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('--x-wsr-t'); | ||||
| 
 | ||||
|       expect( | ||||
|         computeChmodSymbolicRepresentation({ | ||||
|           permissions: { | ||||
|             owner: { read: false, write: false, execute: true }, | ||||
|             group: { read: false, write: true, execute: false }, | ||||
|             public: { read: true, write: false, execute: false }, | ||||
|             flags: { setuid: true, setgid: true, stickybit: true }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('--s-wsr-t'); | ||||
| 
 | ||||
|       expect( | ||||
|         computeChmodSymbolicRepresentation({ | ||||
|           permissions: { | ||||
|             owner: { read: true, write: false, execute: true }, | ||||
|             group: { read: true, write: true, execute: false }, | ||||
|             public: { read: true, write: false, execute: false }, | ||||
|             flags: { setuid: false, setgid: false, stickybit: false }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('r-xrw-r--'); | ||||
| 
 | ||||
|       expect( | ||||
|         computeChmodSymbolicRepresentation({ | ||||
|           permissions: { | ||||
|             owner: { read: true, write: true, execute: true }, | ||||
|             group: { read: true, write: true, execute: true }, | ||||
|             public: { read: true, write: true, execute: true }, | ||||
|             flags: { setuid: true, setgid: true, stickybit: true }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.eql('rwsrwsrwt'); | ||||
|     }); | ||||
|   }); | ||||
|   describe('computePermissionsFromChmodOctalRepresentation', () => { | ||||
|     it('throws on invalid octal values', () => { | ||||
|       expect(() => computePermissionsFromChmodOctalRepresentation('12')).to.throw(); | ||||
|       expect(() => computePermissionsFromChmodOctalRepresentation('12345')).to.throw(); | ||||
|       expect(() => computePermissionsFromChmodOctalRepresentation('999')).to.throw(); | ||||
|       expect(() => computePermissionsFromChmodOctalRepresentation('9999')).to.throw(); | ||||
|     }); | ||||
| 
 | ||||
|     it('get permissions from octal representation', () => { | ||||
|       expect( | ||||
|         computePermissionsFromChmodOctalRepresentation('777'), | ||||
|       ).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( | ||||
|         computePermissionsFromChmodOctalRepresentation('000'), | ||||
|       ).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( | ||||
|         computePermissionsFromChmodOctalRepresentation('235'), | ||||
|       ).to.eql({ | ||||
|         owner: { read: false, write: true, execute: false }, | ||||
|         group: { read: false, write: true, execute: true }, | ||||
|         public: { read: true, write: false, execute: true }, | ||||
|         flags: { setuid: false, setgid: false, stickybit: false }, | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computePermissionsFromChmodOctalRepresentation('421'), | ||||
|       ).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( | ||||
|         computePermissionsFromChmodOctalRepresentation('124'), | ||||
|       ).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( | ||||
|         computePermissionsFromChmodOctalRepresentation('222'), | ||||
|       ).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( | ||||
|         computePermissionsFromChmodOctalRepresentation('7222'), | ||||
|       ).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: true, setgid: true, stickybit: true }, | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computePermissionsFromChmodOctalRepresentation('4222'), | ||||
|       ).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: true, setgid: false, stickybit: false }, | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computePermissionsFromChmodOctalRepresentation('2222'), | ||||
|       ).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: true, stickybit: false }, | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computePermissionsFromChmodOctalRepresentation('1222'), | ||||
|       ).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: true }, | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
|   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 }, | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('computeUmaskRepresentation', () => { | ||||
|     it('get the umask from permissions', () => { | ||||
|       expect( | ||||
|         computeUmaskRepresentation({ | ||||
|           permissions: { | ||||
|             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 }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.deep.eq({ | ||||
|         octal: '000', | ||||
|         symbolic: 'umask u=rwx,g=rwx,o=rwx', | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computeUmaskRepresentation({ | ||||
|           permissions: { | ||||
|             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 }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.deep.eq({ | ||||
|         octal: '777', | ||||
|         symbolic: 'umask u=,g=,o=', | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computeUmaskRepresentation({ | ||||
|           permissions: { | ||||
|             owner: { read: false, write: true, execute: false }, | ||||
|             group: { read: false, write: true, execute: true }, | ||||
|             public: { read: true, write: false, execute: true }, | ||||
|             flags: { setuid: false, setgid: false, stickybit: false }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.deep.eq({ | ||||
|         octal: '542', | ||||
|         symbolic: 'umask u=w,g=wx,o=rx', | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computeUmaskRepresentation({ | ||||
|           permissions: { | ||||
|             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 }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.deep.eq({ | ||||
|         octal: '356', | ||||
|         symbolic: 'umask u=r,g=w,o=x', | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computeUmaskRepresentation({ | ||||
|           permissions: { | ||||
|             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 }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.deep.eq({ | ||||
|         octal: '653', | ||||
|         symbolic: 'umask u=x,g=w,o=r', | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computeUmaskRepresentation({ | ||||
|           permissions: { | ||||
|             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 }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.deep.eq({ | ||||
|         octal: '555', | ||||
|         symbolic: 'umask u=w,g=w,o=w', | ||||
|       }); | ||||
| 
 | ||||
|       expect( | ||||
|         computeUmaskRepresentation({ | ||||
|           permissions: { | ||||
|             owner: { read: false, write: false, execute: true }, | ||||
|             group: { read: false, write: true, execute: false }, | ||||
|             public: { read: true, write: false, execute: false }, | ||||
|             flags: { setuid: true, setgid: true, stickybit: true }, | ||||
|           }, | ||||
|         }), | ||||
|       ).to.deep.eq({ | ||||
|         octal: '653', | ||||
|         symbolic: 'umask u=x,g=w,o=r', | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| @ -1,15 +1,21 @@ | ||||
| import _ from 'lodash'; | ||||
| import type { GroupPermissions, Permissions } from './chmod-calculator.types'; | ||||
| import type { GroupPermissions, Permissions, SpecialPermissions } from './chmod-calculator.types'; | ||||
| 
 | ||||
| export { computeChmodOctalRepresentation, computeChmodSymbolicRepresentation }; | ||||
| export { computeUmaskRepresentation, computeChmodOctalRepresentation, computeChmodSymbolicRepresentation, computePermissionsFromChmodOctalRepresentation, computePermissionsFromChmodSymbolicRepresentation }; | ||||
| 
 | ||||
| function computeChmodOctalRepresentation({ permissions }: { permissions: Permissions }): string { | ||||
|   const permissionValue = { read: 4, write: 2, execute: 1 }; | ||||
|   const specialPermissionValue = { setuid: 4, setgid: 2, stickybit: 1 }; | ||||
| 
 | ||||
|   const getGroupPermissionValue = (permission: GroupPermissions) => | ||||
|     _.reduce(permission, (acc, isPermSet, key) => acc + (isPermSet ? _.get(permissionValue, key, 0) : 0), 0); | ||||
|   const getSpecialPermissionValue = (permission: SpecialPermissions) => { | ||||
|     const octalValue = _.reduce(permission, (acc, isPermSet, key) => acc + (isPermSet ? _.get(specialPermissionValue, key, 0) : 0), 0); | ||||
|     return octalValue > 0 ? octalValue.toString() : ''; | ||||
|   }; | ||||
| 
 | ||||
|   return [ | ||||
|     getSpecialPermissionValue(permissions.flags || { setuid: false, setgid: false, stickybit: false }), | ||||
|     getGroupPermissionValue(permissions.owner), | ||||
|     getGroupPermissionValue(permissions.group), | ||||
|     getGroupPermissionValue(permissions.public), | ||||
| @ -18,13 +24,92 @@ function computeChmodOctalRepresentation({ permissions }: { permissions: Permiss | ||||
| 
 | ||||
| function computeChmodSymbolicRepresentation({ permissions }: { permissions: Permissions }): string { | ||||
|   const permissionValue = { read: 'r', write: 'w', execute: 'x' }; | ||||
|   const specialFlagPermission = 'execute'; | ||||
| 
 | ||||
|   const getGroupPermissionValue = (permission: GroupPermissions) => | ||||
|     _.reduce(permission, (acc, isPermSet, key) => acc + (isPermSet ? _.get(permissionValue, key, '') : '-'), ''); | ||||
|   const getGroupPermissionValue = (permission: GroupPermissions, specialFlag: null | 's' | 't') => | ||||
|     _.reduce(permission, (acc, isPermSet, key) => acc + ((key === specialFlagPermission ? specialFlag : undefined) | ||||
|     || (isPermSet ? _.get(permissionValue, key, '') : '-')), ''); | ||||
| 
 | ||||
|   return [ | ||||
|     getGroupPermissionValue(permissions.owner), | ||||
|     getGroupPermissionValue(permissions.group), | ||||
|     getGroupPermissionValue(permissions.public), | ||||
|     getGroupPermissionValue(permissions.owner, permissions.flags?.setuid ? 's' : null), | ||||
|     getGroupPermissionValue(permissions.group, permissions.flags?.setgid ? 's' : null), | ||||
|     getGroupPermissionValue(permissions.public, permissions.flags?.stickybit ? 't' : null), | ||||
|   ].join(''); | ||||
| } | ||||
| 
 | ||||
| function computePermissionsFromChmodOctalRepresentation(octalPermissions: string): Permissions { | ||||
|   const permissionValue = { read: 4, write: 2, execute: 1 }; | ||||
|   const specialPermissionValue = { setuid: 4, setgid: 2, stickybit: 1 }; | ||||
| 
 | ||||
|   if (!octalPermissions || !octalPermissions.match(/^[0-7]{3,4}$/)) { | ||||
|     throw new Error(`Invalid octal permissions (must be 3 or 4 octal digits): ${octalPermissions}`); | ||||
|   } | ||||
|   const fullOctalPermissions = octalPermissions.length === 3 ? `0${octalPermissions}` : octalPermissions; | ||||
| 
 | ||||
|   const hasSet = (position: number, flagValue: number) => (Number(fullOctalPermissions[position]) & flagValue) === flagValue; | ||||
|   function computePermissionObject<T>(permissionSet: object, position: number): T { | ||||
|     return _.reduce(permissionSet, (acc, flag, key) => ({ ...acc, [key]: hasSet(position, flag) }), {}) as T; | ||||
|   } | ||||
|   const flagsPosition = 0; | ||||
|   const ownerPosition = 1; | ||||
|   const groupPosition = 2; | ||||
|   const publicPosition = 3; | ||||
|   return { | ||||
|     owner: computePermissionObject(permissionValue, ownerPosition), | ||||
|     group: computePermissionObject(permissionValue, groupPosition), | ||||
|     public: computePermissionObject(permissionValue, publicPosition), | ||||
|     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); | ||||
| } | ||||
| 
 | ||||
| function computeUmaskRepresentation({ permissions }: { permissions: Permissions }): { | ||||
|   octal: string | ||||
|   symbolic: string | ||||
| } { | ||||
|   const permissionValue = { read: 'r', write: 'w', execute: 'x' }; | ||||
|   const getGroupPermissionValue = (permission: GroupPermissions) => | ||||
|     _.reduce(permission, (acc, isPermSet, key) => acc + ((isPermSet ? _.get(permissionValue, key, '') : '')), ''); | ||||
| 
 | ||||
|   const symbolic = `umask u=${getGroupPermissionValue(permissions.owner)},g=${getGroupPermissionValue(permissions.group)},o=${getGroupPermissionValue(permissions.public)}`; | ||||
|   const octal = (0o777 - Number.parseInt( | ||||
|     computeChmodOctalRepresentation({ | ||||
|       permissions: | ||||
|       { | ||||
|         owner: permissions.owner, | ||||
|         group: permissions.group, | ||||
|         public: permissions.public, | ||||
|         flags: { setuid: false, setgid: false, stickybit: false }, | ||||
|       }, | ||||
|     }), 8)) | ||||
|     .toString(8) | ||||
|     .padStart(3, '0'); | ||||
| 
 | ||||
|   return { | ||||
|     symbolic, octal, | ||||
|   }; | ||||
| } | ||||
|  | ||||
| @ -1,10 +1,17 @@ | ||||
| export type Scope = 'read' | 'write' | 'execute'; | ||||
| export type Group = 'owner' | 'group' | 'public'; | ||||
| export type SpecialFlags = 'setuid' | 'setgid' | 'stickybit'; | ||||
| 
 | ||||
| export type GroupPermissions = { | ||||
|   [k in Scope]: boolean; | ||||
| }; | ||||
| 
 | ||||
| export type SpecialPermissions = { | ||||
|   [k in SpecialFlags]: boolean; | ||||
| }; | ||||
| 
 | ||||
| export type Permissions = { | ||||
|   [k in Group]: GroupPermissions; | ||||
| } & { | ||||
|   flags: SpecialPermissions | ||||
| }; | ||||
|  | ||||
| @ -2,9 +2,10 @@ | ||||
| import { useThemeVars } from 'naive-ui'; | ||||
| 
 | ||||
| import InputCopyable from '../../components/InputCopyable.vue'; | ||||
| import { computeChmodOctalRepresentation, computeChmodSymbolicRepresentation } from './chmod-calculator.service'; | ||||
| import { computeChmodOctalRepresentation, computeChmodSymbolicRepresentation, computePermissionsFromChmodOctalRepresentation, computePermissionsFromChmodSymbolicRepresentation, computeUmaskRepresentation } from './chmod-calculator.service'; | ||||
| 
 | ||||
| import type { Group, Scope } from './chmod-calculator.types'; | ||||
| import { useValidation } from '@/composable/validation'; | ||||
| 
 | ||||
| const themeVars = useThemeVars(); | ||||
| 
 | ||||
| @ -19,14 +20,92 @@ const permissions = ref({ | ||||
|   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 }, | ||||
| }); | ||||
| 
 | ||||
| const octalPermissionsInput = ref('000'); | ||||
| const octalPermissionsInputValidation = useValidation({ | ||||
|   source: octalPermissionsInput, | ||||
|   rules: [ | ||||
|     { | ||||
|       message: 'Invalid octal permission string', | ||||
|       validator: (value) => { | ||||
|         try { | ||||
|           computePermissionsFromChmodOctalRepresentation(value.trim()); | ||||
|           return true; | ||||
|         } | ||||
|         catch { | ||||
|           return false; | ||||
|         } | ||||
|       }, | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
| watch( | ||||
|   octalPermissionsInput, | ||||
|   (newPermissions) => { | ||||
|     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 })); | ||||
| const umask = computed(() => computeUmaskRepresentation({ permissions: permissions.value })); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <div> | ||||
|     <c-input-text | ||||
|       v-model:value="octalPermissionsInput" | ||||
|       placeholder="Put your octal permissions here..." | ||||
|       label="Copy your octal permissions" | ||||
|       :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> | ||||
| @ -52,6 +131,20 @@ const symbolic = computed(() => computeChmodSymbolicRepresentation({ permissions | ||||
|             <n-checkbox v-model:checked="permissions[group][scope]" size="large" /> | ||||
|           </td> | ||||
|         </tr> | ||||
|         <tr> | ||||
|           <td class="line-header"> | ||||
|             Flags | ||||
|           </td> | ||||
|           <td class="text-center"> | ||||
|             <n-checkbox v-model:checked="permissions.flags.setuid" size="large" /> | ||||
|           </td> | ||||
|           <td class="text-center"> | ||||
|             <n-checkbox v-model:checked="permissions.flags.setgid" size="large" /> | ||||
|           </td> | ||||
|           <td class="text-center"> | ||||
|             <n-checkbox v-model:checked="permissions.flags.stickybit" size="large" /> | ||||
|           </td> | ||||
|         </tr> | ||||
|       </tbody> | ||||
|     </n-table> | ||||
| 
 | ||||
| @ -63,6 +156,11 @@ const symbolic = computed(() => computeChmodSymbolicRepresentation({ permissions | ||||
|     </div> | ||||
| 
 | ||||
|     <InputCopyable :value="`chmod ${octal} path`" readonly /> | ||||
| 
 | ||||
|     <c-card title="Umask"> | ||||
|       <InputCopyable :value="umask.octal" readonly /> | ||||
|       <InputCopyable :value="umask.symbolic" readonly /> | ||||
|     </c-card> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
|  | ||||
| @ -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', | ||||
| @ -17,6 +16,7 @@ export const tool = defineTool({ | ||||
|     'recursive', | ||||
|     'generator', | ||||
|     'octal', | ||||
|     'umask', | ||||
|   ], | ||||
|   component: () => import('./chmod-calculator.vue'), | ||||
|   icon: FileInvoice, | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user