mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-04-24 08:46:15 -04:00
Added function to chmod-calculator to convert chmod symbolic string into octal value.
This commit is contained in:
parent
9bd4ad4dfd
commit
02c3c031f4
3 changed files with 309 additions and 38 deletions
|
@ -1,5 +1,7 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { computeChmodOctalRepresentation, computeChmodSymbolicRepresentation } from './chmod-calculator.service';
|
||||
import {
|
||||
checkSymbolicString, computeChmodOctalRepresentation, computeChmodSymbolicRepresentation, symbolicToOctal,
|
||||
} from './chmod-calculator.service';
|
||||
|
||||
describe('chmod-calculator', () => {
|
||||
describe('computeChmodOctalRepresentation', () => {
|
||||
|
@ -127,4 +129,167 @@ describe('chmod-calculator', () => {
|
|||
).to.eql('-w--w--w-');
|
||||
});
|
||||
});
|
||||
describe('symbolicToNumeric', () => {
|
||||
it('should return the correct octal value for symbolic strings', () => {
|
||||
expect(symbolicToOctal('rwxrwxrwx')).toBe(777);
|
||||
expect(symbolicToOctal('drwxrwxrwx')).toBe(777);
|
||||
expect(symbolicToOctal('-rwxrwxrwx')).toBe(777);
|
||||
expect(symbolicToOctal('lrwxrwxrwx')).toBe(777);
|
||||
|
||||
expect(symbolicToOctal('rwxr-xr-x')).toBe(755);
|
||||
expect(symbolicToOctal('drwxr-xr-x')).toBe(755);
|
||||
expect(symbolicToOctal('-rwxr-xr-x')).toBe(755);
|
||||
expect(symbolicToOctal('lrwxr-xr-x')).toBe(755);
|
||||
|
||||
expect(symbolicToOctal('rwxrwxr-x')).toBe(775);
|
||||
expect(symbolicToOctal('drwxrwxr-x')).toBe(775);
|
||||
expect(symbolicToOctal('-rwxrwxr-x')).toBe(775);
|
||||
expect(symbolicToOctal('lrwxrwxr-x')).toBe(775);
|
||||
|
||||
expect(symbolicToOctal('rw-r--r--')).toBe(644);
|
||||
expect(symbolicToOctal('drw-r--r--')).toBe(644);
|
||||
expect(symbolicToOctal('-rw-r--r--')).toBe(644);
|
||||
expect(symbolicToOctal('lrw-r--r--')).toBe(644);
|
||||
|
||||
expect(symbolicToOctal('rw-------')).toBe(600);
|
||||
expect(symbolicToOctal('drw-------')).toBe(600);
|
||||
expect(symbolicToOctal('-rw-------')).toBe(600);
|
||||
expect(symbolicToOctal('lrw-------')).toBe(600);
|
||||
|
||||
expect(symbolicToOctal('rwx------')).toBe(700);
|
||||
expect(symbolicToOctal('drwx------')).toBe(700);
|
||||
expect(symbolicToOctal('-rwx------')).toBe(700);
|
||||
expect(symbolicToOctal('lrwx------')).toBe(700);
|
||||
|
||||
expect(symbolicToOctal('rw-rw-rw-')).toBe(666);
|
||||
expect(symbolicToOctal('drw-rw-rw-')).toBe(666);
|
||||
expect(symbolicToOctal('-rw-rw-rw-')).toBe(666);
|
||||
expect(symbolicToOctal('lrw-rw-rw-')).toBe(666);
|
||||
|
||||
expect(symbolicToOctal('r--------')).toBe(400);
|
||||
expect(symbolicToOctal('dr--------')).toBe(400);
|
||||
expect(symbolicToOctal('-r--------')).toBe(400);
|
||||
expect(symbolicToOctal('lr--------')).toBe(400);
|
||||
|
||||
expect(symbolicToOctal('rw-rw-r--')).toBe(664);
|
||||
expect(symbolicToOctal('drw-rw-r--')).toBe(664);
|
||||
expect(symbolicToOctal('-rw-rw-r--')).toBe(664);
|
||||
expect(symbolicToOctal('lrw-rw-r--')).toBe(664);
|
||||
|
||||
expect(symbolicToOctal('rwxr--r--')).toBe(744);
|
||||
expect(symbolicToOctal('drwxr--r--')).toBe(744);
|
||||
expect(symbolicToOctal('-rwxr--r--')).toBe(744);
|
||||
expect(symbolicToOctal('lrwxr--r--')).toBe(744);
|
||||
|
||||
expect(symbolicToOctal('rwxrwx---')).toBe(770);
|
||||
expect(symbolicToOctal('drwxrwx---')).toBe(770);
|
||||
expect(symbolicToOctal('-rwxrwx---')).toBe(770);
|
||||
expect(symbolicToOctal('lrwxrwx---')).toBe(770);
|
||||
|
||||
expect(symbolicToOctal('r--r--r--')).toBe(444);
|
||||
expect(symbolicToOctal('dr--r--r--')).toBe(444);
|
||||
expect(symbolicToOctal('-r--r--r--')).toBe(444);
|
||||
expect(symbolicToOctal('lr--r--r--')).toBe(444);
|
||||
|
||||
expect(symbolicToOctal('r-xr-xr-x')).toBe(555);
|
||||
expect(symbolicToOctal('dr-xr-xr-x')).toBe(555);
|
||||
expect(symbolicToOctal('-r-xr-xr-x')).toBe(555);
|
||||
expect(symbolicToOctal('lr-xr-xr-x')).toBe(555);
|
||||
|
||||
expect(symbolicToOctal('---------')).toBe(0o00);
|
||||
expect(symbolicToOctal('d---------')).toBe(0o00);
|
||||
expect(symbolicToOctal('----------')).toBe(0o00);
|
||||
expect(symbolicToOctal('l---------')).toBe(0o00);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateSymbolicInput', () => {
|
||||
it('should return a non-empty error message for invalid duplicate entity permissions', () => {
|
||||
expect(checkSymbolicString('rrwrwxrwx')).not.toBe('');
|
||||
expect(checkSymbolicString('drrwrwxrwx')).not.toBe('');
|
||||
expect(checkSymbolicString('-rrwrwxrwx')).not.toBe('');
|
||||
expect(checkSymbolicString('lrrwrwxrwx')).not.toBe('');
|
||||
|
||||
expect(checkSymbolicString('rrwxrwxrw')).not.toBe('');
|
||||
expect(checkSymbolicString('drrwxrwxrw')).not.toBe('');
|
||||
expect(checkSymbolicString('-rrwxrwxrw')).not.toBe('');
|
||||
expect(checkSymbolicString('lrrwxrwxrw')).not.toBe('');
|
||||
|
||||
expect(checkSymbolicString('rwrwrrxwx')).not.toBe('');
|
||||
expect(checkSymbolicString('drwrwrrxwx')).not.toBe('');
|
||||
expect(checkSymbolicString('-rwrwrrxwx')).not.toBe('');
|
||||
expect(checkSymbolicString('lwrwrrxwx')).not.toBe('');
|
||||
|
||||
expect(checkSymbolicString('rwrwxrrwx')).not.toBe('');
|
||||
expect(checkSymbolicString('drwrwxrrwx')).not.toBe('');
|
||||
expect(checkSymbolicString('-rwrwxrrwx')).not.toBe('');
|
||||
expect(checkSymbolicString('lrwrwxrrwx')).not.toBe('');
|
||||
|
||||
expect(checkSymbolicString('rwxrrwrwx')).not.toBe('');
|
||||
expect(checkSymbolicString('drwxrrwrwx')).not.toBe('');
|
||||
expect(checkSymbolicString('-rwxrrwrwx')).not.toBe('');
|
||||
expect(checkSymbolicString('lwxrrwrwx')).not.toBe('');
|
||||
|
||||
expect(checkSymbolicString('rwxrwrwrx')).not.toBe('');
|
||||
expect(checkSymbolicString('drwxrwrwrx')).not.toBe('');
|
||||
expect(checkSymbolicString('-rwxrwrwrx')).not.toBe('');
|
||||
expect(checkSymbolicString('lwxrwrwrx')).not.toBe('');
|
||||
|
||||
expect(checkSymbolicString('rrwrwrwxw')).not.toBe('');
|
||||
expect(checkSymbolicString('drrwrwrwxw')).not.toBe('');
|
||||
expect(checkSymbolicString('-rrwrwrwxw')).not.toBe('');
|
||||
expect(checkSymbolicString('lrrwrwrwxw')).not.toBe('');
|
||||
|
||||
expect(checkSymbolicString('rrwxwrrwx')).not.toBe('');
|
||||
expect(checkSymbolicString('drrwxwrrwx')).not.toBe('');
|
||||
expect(checkSymbolicString('-rrwxwrrwx')).not.toBe('');
|
||||
expect(checkSymbolicString('lrrwxwrrwx')).not.toBe('');
|
||||
|
||||
expect(checkSymbolicString('rwrwrrwxr')).not.toBe('');
|
||||
expect(checkSymbolicString('drwrwrrwxr')).not.toBe('');
|
||||
expect(checkSymbolicString('-rwrwrrwxr')).not.toBe('');
|
||||
expect(checkSymbolicString('lwrwrrwxr')).not.toBe('');
|
||||
|
||||
expect(checkSymbolicString('rwrwxrwrw')).not.toBe('');
|
||||
expect(checkSymbolicString('drwrwxrwrw')).not.toBe('');
|
||||
expect(checkSymbolicString('-rwrwxrwrw')).not.toBe('');
|
||||
expect(checkSymbolicString('lwrwxrwrw')).not.toBe('');
|
||||
|
||||
expect(checkSymbolicString('rwxrrwxrw')).not.toBe('');
|
||||
expect(checkSymbolicString('drwxrrwxrw')).not.toBe('');
|
||||
expect(checkSymbolicString('-rwxrrwxrw')).not.toBe('');
|
||||
expect(checkSymbolicString('lrwxrrwxrw')).not.toBe('');
|
||||
|
||||
expect(checkSymbolicString('rww--rwrw-')).not.toBe('');
|
||||
expect(checkSymbolicString('drww--rwrw-')).not.toBe('');
|
||||
expect(checkSymbolicString('-rww--rwrw-')).not.toBe('');
|
||||
expect(checkSymbolicString('lrww--rwrw-')).not.toBe('');
|
||||
|
||||
expect(checkSymbolicString('r--wrrwxr')).not.toBe('');
|
||||
expect(checkSymbolicString('dr--wrrwxr')).not.toBe('');
|
||||
expect(checkSymbolicString('-r--wrrwxr')).not.toBe('');
|
||||
expect(checkSymbolicString('lr--wrrwxr')).not.toBe('');
|
||||
|
||||
expect(checkSymbolicString('rw--rrwxr-')).not.toBe('');
|
||||
expect(checkSymbolicString('drw--rrwxr-')).not.toBe('');
|
||||
expect(checkSymbolicString('-rw--rrwxr-')).not.toBe('');
|
||||
expect(checkSymbolicString('lrw--rrwxr-')).not.toBe('');
|
||||
});
|
||||
});
|
||||
describe('validateSymbolicInput', () => {
|
||||
describe('validateOrder', () => {
|
||||
it('should correctly validate the order of permissions', () => {
|
||||
expect(checkSymbolicString('rwxrwxrwx')).toBe('');
|
||||
expect(checkSymbolicString('rw-r--r--')).toBe('');
|
||||
expect(checkSymbolicString('r-xr-xr-x')).toBe('');
|
||||
expect(checkSymbolicString('-wxrw-r-x')).toBe('');
|
||||
expect(checkSymbolicString('rwxrw-r-x')).toBe('');
|
||||
expect(checkSymbolicString('rwxr-xrw-')).toBe('');
|
||||
expect(checkSymbolicString('rwxr-xrw-')).toBe('');
|
||||
expect(checkSymbolicString('rxwr-xrw-')).toBe('User permissions should be in the order of \'r\', \'w\', \'x\'.');
|
||||
expect(checkSymbolicString('rwxr-wrw-')).toBe('Group permissions should be in the order of \'r\', \'w\', \'x\'.');
|
||||
expect(checkSymbolicString('rwxr-xr-w')).toBe('Public permissions should be in the order of \'r\', \'w\', \'x\'.');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
import _ from 'lodash';
|
||||
import type { GroupPermissions, Permissions } from './chmod-calculator.types';
|
||||
|
||||
export { computeChmodOctalRepresentation, computeChmodSymbolicRepresentation };
|
||||
export {
|
||||
computeChmodOctalRepresentation,
|
||||
computeChmodSymbolicRepresentation,
|
||||
symbolicToOctal,
|
||||
checkSymbolicString,
|
||||
validateCharPositions,
|
||||
};
|
||||
|
||||
function computeChmodOctalRepresentation({ permissions }: { permissions: Permissions }): string {
|
||||
const permissionValue = { read: 4, write: 2, execute: 1 };
|
||||
|
@ -28,3 +34,79 @@ function computeChmodSymbolicRepresentation({ permissions }: { permissions: Perm
|
|||
getGroupPermissionValue(permissions.public),
|
||||
].join('');
|
||||
}
|
||||
|
||||
function validateCharPositions(permissionSet: string): boolean {
|
||||
const validChars = ['r', 'w', 'x'];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const permSetCharCurrent = permissionSet.charAt(i);
|
||||
const validCharCurent = validChars[i];
|
||||
if (permissionSet.charAt(i) !== '-' && permSetCharCurrent !== validCharCurent) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkDuplicateInGroup(group: string): boolean {
|
||||
const validPermissions = ['r', 'w', 'x'];
|
||||
const permissions = group.split('').filter(p => validPermissions.includes(p));
|
||||
const uniquePermissions = new Set(permissions);
|
||||
return permissions.length !== uniquePermissions.size;
|
||||
}
|
||||
|
||||
function symbolicToOctal(symbolic: string): number {
|
||||
const symbolicMap: Record<string, number> = {
|
||||
'r': 4,
|
||||
'w': 2,
|
||||
'x': 1,
|
||||
'-': 0,
|
||||
};
|
||||
|
||||
const userPart = symbolic.length === 10 ? symbolic.slice(1, 4) : symbolic.slice(0, 3);
|
||||
const groupPart = symbolic.length === 10 ? symbolic.slice(4, 7) : symbolic.slice(3, 6);
|
||||
const publicPart = symbolic.length === 10 ? symbolic.slice(7, 10) : symbolic.slice(6, 9);
|
||||
|
||||
const userNumeric = userPart.split('').reduce((sum, value) => sum + (symbolicMap[value] || 0), 0);
|
||||
const groupNumeric = groupPart.split('').reduce((sum, value) => sum + (symbolicMap[value] || 0), 0);
|
||||
const publicNumeric = publicPart.split('').reduce((sum, value) => sum + (symbolicMap[value] || 0), 0);
|
||||
|
||||
return userNumeric * 100 + groupNumeric * 10 + publicNumeric;
|
||||
}
|
||||
|
||||
function checkSymbolicString(symbolicInput: string): string {
|
||||
const generalPattern = /^([d-]|[lf-])?[rwx-]{9}$/;
|
||||
|
||||
if (symbolicInput.length === 0) {
|
||||
return '';
|
||||
}
|
||||
if (symbolicInput.length > 10) {
|
||||
return 'Invalid length.';
|
||||
}
|
||||
if (!generalPattern.test(symbolicInput)) {
|
||||
return 'Invalid permission pattern.';
|
||||
}
|
||||
|
||||
const userPermissions = symbolicInput.slice(-9, -6);
|
||||
const groupPermissions = symbolicInput.slice(-6, -3);
|
||||
const publicPermissions = symbolicInput.slice(-3);
|
||||
|
||||
if (checkDuplicateInGroup(userPermissions)) {
|
||||
return 'Duplicate rights are not allowed in the user section.';
|
||||
}
|
||||
if (checkDuplicateInGroup(groupPermissions)) {
|
||||
return 'Duplicate rights are not allowed in the group section.';
|
||||
}
|
||||
if (checkDuplicateInGroup(publicPermissions)) {
|
||||
return 'Duplicate rights are not allowed in the public section.';
|
||||
}
|
||||
if (!validateCharPositions(userPermissions)) {
|
||||
return 'User permissions should be in the order of \'r\', \'w\', \'x\'.';
|
||||
}
|
||||
if (!validateCharPositions(groupPermissions)) {
|
||||
return 'Group permissions should be in the order of \'r\', \'w\', \'x\'.';
|
||||
}
|
||||
if (!validateCharPositions(publicPermissions)) {
|
||||
return 'Public permissions should be in the order of \'r\', \'w\', \'x\'.';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
<script setup lang="ts">
|
||||
import { useThemeVars } from 'naive-ui';
|
||||
|
||||
import { computed, ref } from 'vue';
|
||||
import InputCopyable from '../../components/InputCopyable.vue';
|
||||
import { computeChmodOctalRepresentation, computeChmodSymbolicRepresentation } from './chmod-calculator.service';
|
||||
import {
|
||||
checkSymbolicString,
|
||||
computeChmodOctalRepresentation,
|
||||
computeChmodSymbolicRepresentation,
|
||||
symbolicToOctal,
|
||||
} from './chmod-calculator.service';
|
||||
|
||||
import type { Group, Scope } from './chmod-calculator.types';
|
||||
import CLabel from '@/ui/c-label/c-label.vue';
|
||||
|
||||
const themeVars = useThemeVars();
|
||||
|
||||
|
@ -21,48 +27,66 @@ const permissions = ref({
|
|||
public: { read: false, write: false, execute: false },
|
||||
});
|
||||
|
||||
const symbolicInput = ref('');
|
||||
|
||||
const octal = computed(() => computeChmodOctalRepresentation({ permissions: permissions.value }));
|
||||
const symbolic = computed(() => computeChmodSymbolicRepresentation({ permissions: permissions.value }));
|
||||
const computedOctal = computed(() => symbolicToOctal(symbolicInput.value));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<n-table :bordered="false" :bottom-bordered="false" single-column class="permission-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center" scope="col" />
|
||||
<th class="text-center" scope="col">
|
||||
Owner (u)
|
||||
</th>
|
||||
<th class="text-center" scope="col">
|
||||
Group (g)
|
||||
</th>
|
||||
<th class="text-center" scope="col">
|
||||
Public (o)
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="{ scope, title } of scopes" :key="scope">
|
||||
<td class="line-header">
|
||||
{{ title }}
|
||||
</td>
|
||||
<td v-for="group of groups" :key="group" class="text-center">
|
||||
<!-- <n-switch v-model:value="permissions[group][scope]" /> -->
|
||||
<n-checkbox v-model:checked="permissions[group][scope]" size="large" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</n-table>
|
||||
<c-card title="Calculate octal and symbolic permissions">
|
||||
<n-table :bordered="false" :bottom-bordered="false" single-column class="permission-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center" scope="col" />
|
||||
<th class="text-center" scope="col">
|
||||
Owner (u)
|
||||
</th>
|
||||
<th class="text-center" scope="col">
|
||||
Group (g)
|
||||
</th>
|
||||
<th class="text-center" scope="col">
|
||||
Public (o)
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="{ scope, title } of scopes" :key="scope">
|
||||
<td class="line-header">
|
||||
{{ title }}
|
||||
</td>
|
||||
<td v-for="group of groups" :key="group" class="text-center">
|
||||
<!-- <n-switch v-model:value="permissions[group][scope]" /> -->
|
||||
<n-checkbox v-model:checked="permissions[group][scope]" size="large" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</n-table>
|
||||
|
||||
<div class="octal-result">
|
||||
{{ octal }}
|
||||
</div>
|
||||
<div class="octal-result">
|
||||
{{ symbolic }}
|
||||
</div>
|
||||
<div class="octal-result">
|
||||
{{ octal }}
|
||||
</div>
|
||||
<div class="octal-result">
|
||||
{{ symbolic }}
|
||||
</div>
|
||||
|
||||
<InputCopyable :value="`chmod ${octal} path`" readonly />
|
||||
<InputCopyable :value="`chmod ${octal} path`" readonly />
|
||||
</c-card>
|
||||
<c-card title="Convert symbolic permission string to octal value">
|
||||
<p>For permission strings of length 10:<br>The first character represents the file type: "-" for a regular file, "d" for a directory, "l" for a symbolic link.</p>
|
||||
<CLabel /> <n-form-item label="Permission string" label-placement="left">
|
||||
<c-input-text v-model:value="symbolicInput" placeholder="-rw-r--r--" w-full />
|
||||
</n-form-item>
|
||||
<n-alert v-if="checkSymbolicString(symbolicInput)" style="margin-top: 25px" type="error">
|
||||
{{ checkSymbolicString(symbolicInput) }}
|
||||
</n-alert>
|
||||
<div class="octal-result">
|
||||
{{ computedOctal }}
|
||||
</div>
|
||||
<InputCopyable :value="`chmod ${computedOctal} path`" readonly />
|
||||
</c-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue