2018-05-14 19:16:42 +02:00
/ * *
* @ author n1474335 [ n1474335 @ gmail . com ]
* @ copyright Crown Copyright 2016
* @ license Apache - 2.0
* /
2019-07-09 13:23:59 +02:00
import Operation from "../Operation.mjs" ;
import OperationError from "../errors/OperationError.mjs" ;
2018-05-14 19:16:42 +02:00
/ * *
* Parse UNIX file permissions operation
* /
class ParseUNIXFilePermissions extends Operation {
/ * *
* ParseUNIXFilePermissions constructor
* /
constructor ( ) {
super ( ) ;
this . name = "Parse UNIX file permissions" ;
this . module = "Default" ;
this . description = "Given a UNIX/Linux file permission string in octal or textual format, this operation explains which permissions are granted to which user groups.<br><br>Input should be in either octal (e.g. <code>755</code>) or textual (e.g. <code>drwxr-xr-x</code>) format." ;
2018-08-21 20:07:13 +02:00
this . infoURL = "https://wikipedia.org/wiki/File_system_permissions#Traditional_Unix_permissions" ;
2018-05-14 19:16:42 +02:00
this . inputType = "string" ;
this . outputType = "string" ;
this . args = [ ] ;
2020-02-25 12:27:03 +01:00
this . checks = {
input : {
regex : [
{
match : "^\\s*d[rxw-]{9}\\s*$" ,
flags : "" ,
args : [ ]
}
]
}
} ;
2018-05-14 19:16:42 +02:00
}
/ * *
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run ( input , args ) {
const perms = {
d : false , // directory
sl : false , // symbolic link
np : false , // named pipe
s : false , // socket
cd : false , // character device
bd : false , // block device
dr : false , // door
sb : false , // sticky bit
su : false , // setuid
sg : false , // setgid
ru : false , // read user
wu : false , // write user
eu : false , // execute user
rg : false , // read group
wg : false , // write group
eg : false , // execute group
ro : false , // read other
wo : false , // write other
eo : false // execute other
} ;
let d = 0 ,
u = 0 ,
g = 0 ,
o = 0 ,
output = "" ,
octal = null ,
textual = null ;
if ( input . search ( /\s*[0-7]{1,4}\s*/i ) === 0 ) {
// Input is octal
octal = input . match ( /\s*([0-7]{1,4})\s*/i ) [ 1 ] ;
if ( octal . length === 4 ) {
d = parseInt ( octal [ 0 ] , 8 ) ;
u = parseInt ( octal [ 1 ] , 8 ) ;
g = parseInt ( octal [ 2 ] , 8 ) ;
o = parseInt ( octal [ 3 ] , 8 ) ;
} else {
if ( octal . length > 0 ) u = parseInt ( octal [ 0 ] , 8 ) ;
if ( octal . length > 1 ) g = parseInt ( octal [ 1 ] , 8 ) ;
if ( octal . length > 2 ) o = parseInt ( octal [ 2 ] , 8 ) ;
}
perms . su = d >> 2 & 0x1 ;
perms . sg = d >> 1 & 0x1 ;
perms . sb = d & 0x1 ;
perms . ru = u >> 2 & 0x1 ;
perms . wu = u >> 1 & 0x1 ;
perms . eu = u & 0x1 ;
perms . rg = g >> 2 & 0x1 ;
perms . wg = g >> 1 & 0x1 ;
perms . eg = g & 0x1 ;
perms . ro = o >> 2 & 0x1 ;
perms . wo = o >> 1 & 0x1 ;
perms . eo = o & 0x1 ;
} else if ( input . search ( /\s*[dlpcbDrwxsStT-]{1,10}\s*/ ) === 0 ) {
// Input is textual
textual = input . match ( /\s*([dlpcbDrwxsStT-]{1,10})\s*/ ) [ 1 ] ;
switch ( textual [ 0 ] ) {
case "d" :
perms . d = true ;
break ;
case "l" :
perms . sl = true ;
break ;
case "p" :
perms . np = true ;
break ;
case "s" :
perms . s = true ;
break ;
case "c" :
perms . cd = true ;
break ;
case "b" :
perms . bd = true ;
break ;
case "D" :
perms . dr = true ;
break ;
}
if ( textual . length > 1 ) perms . ru = textual [ 1 ] === "r" ;
if ( textual . length > 2 ) perms . wu = textual [ 2 ] === "w" ;
if ( textual . length > 3 ) {
switch ( textual [ 3 ] ) {
case "x" :
perms . eu = true ;
break ;
case "s" :
perms . eu = true ;
perms . su = true ;
break ;
case "S" :
perms . su = true ;
break ;
}
}
if ( textual . length > 4 ) perms . rg = textual [ 4 ] === "r" ;
if ( textual . length > 5 ) perms . wg = textual [ 5 ] === "w" ;
if ( textual . length > 6 ) {
switch ( textual [ 6 ] ) {
case "x" :
perms . eg = true ;
break ;
case "s" :
perms . eg = true ;
perms . sg = true ;
break ;
case "S" :
perms . sg = true ;
break ;
}
}
if ( textual . length > 7 ) perms . ro = textual [ 7 ] === "r" ;
if ( textual . length > 8 ) perms . wo = textual [ 8 ] === "w" ;
if ( textual . length > 9 ) {
switch ( textual [ 9 ] ) {
case "x" :
perms . eo = true ;
break ;
case "t" :
perms . eo = true ;
perms . sb = true ;
break ;
case "T" :
perms . sb = true ;
break ;
}
}
} else {
2018-05-15 19:01:04 +02:00
throw new OperationError ( "Invalid input format.\nPlease enter the permissions in either octal (e.g. 755) or textual (e.g. drwxr-xr-x) format." ) ;
2018-05-14 19:16:42 +02:00
}
output += "Textual representation: " + permsToStr ( perms ) ;
output += "\nOctal representation: " + permsToOctal ( perms ) ;
// File type
if ( textual ) {
output += "\nFile type: " + ftFromPerms ( perms ) ;
}
// setuid, setgid
if ( perms . su ) {
output += "\nThe setuid flag is set" ;
}
if ( perms . sg ) {
output += "\nThe setgid flag is set" ;
}
// sticky bit
if ( perms . sb ) {
output += "\nThe sticky bit is set" ;
}
// Permission matrix
output += `
+ -- -- -- -- - + -- -- -- - + -- -- -- - + -- -- -- - +
| | User | Group | Other |
+ -- -- -- -- - + -- -- -- - + -- -- -- - + -- -- -- - +
| Read | $ { perms . ru ? "X" : " " } | $ { perms . rg ? "X" : " " } | $ { perms . ro ? "X" : " " } |
+ -- -- -- -- - + -- -- -- - + -- -- -- - + -- -- -- - +
| Write | $ { perms . wu ? "X" : " " } | $ { perms . wg ? "X" : " " } | $ { perms . wo ? "X" : " " } |
+ -- -- -- -- - + -- -- -- - + -- -- -- - + -- -- -- - +
| Execute | $ { perms . eu ? "X" : " " } | $ { perms . eg ? "X" : " " } | $ { perms . eo ? "X" : " " } |
+ -- -- -- -- - + -- -- -- - + -- -- -- - + -- -- -- - + ` ;
return output ;
}
}
/ * *
* Given a permissions object dictionary , generates a textual permissions string .
*
* @ param { Object } perms
* @ returns { string }
* /
function permsToStr ( perms ) {
let str = "" ,
type = "-" ;
if ( perms . d ) type = "d" ;
if ( perms . sl ) type = "l" ;
if ( perms . np ) type = "p" ;
if ( perms . s ) type = "s" ;
if ( perms . cd ) type = "c" ;
if ( perms . bd ) type = "b" ;
if ( perms . dr ) type = "D" ;
str = type ;
str += perms . ru ? "r" : "-" ;
str += perms . wu ? "w" : "-" ;
if ( perms . eu && perms . su ) {
str += "s" ;
} else if ( perms . su ) {
str += "S" ;
} else if ( perms . eu ) {
str += "x" ;
} else {
str += "-" ;
}
str += perms . rg ? "r" : "-" ;
str += perms . wg ? "w" : "-" ;
if ( perms . eg && perms . sg ) {
str += "s" ;
} else if ( perms . sg ) {
str += "S" ;
} else if ( perms . eg ) {
str += "x" ;
} else {
str += "-" ;
}
str += perms . ro ? "r" : "-" ;
str += perms . wo ? "w" : "-" ;
if ( perms . eo && perms . sb ) {
str += "t" ;
} else if ( perms . sb ) {
str += "T" ;
} else if ( perms . eo ) {
str += "x" ;
} else {
str += "-" ;
}
return str ;
}
/ * *
* Given a permissions object dictionary , generates an octal permissions string .
*
* @ param { Object } perms
* @ returns { string }
* /
function permsToOctal ( perms ) {
let d = 0 ,
u = 0 ,
g = 0 ,
o = 0 ;
if ( perms . su ) d += 4 ;
if ( perms . sg ) d += 2 ;
if ( perms . sb ) d += 1 ;
if ( perms . ru ) u += 4 ;
if ( perms . wu ) u += 2 ;
if ( perms . eu ) u += 1 ;
if ( perms . rg ) g += 4 ;
if ( perms . wg ) g += 2 ;
if ( perms . eg ) g += 1 ;
if ( perms . ro ) o += 4 ;
if ( perms . wo ) o += 2 ;
if ( perms . eo ) o += 1 ;
return d . toString ( ) + u . toString ( ) + g . toString ( ) + o . toString ( ) ;
}
/ * *
* Given a permissions object dictionary , returns the file type .
*
* @ param { Object } perms
* @ returns { string }
* /
function ftFromPerms ( perms ) {
if ( perms . d ) return "Directory" ;
if ( perms . sl ) return "Symbolic link" ;
if ( perms . np ) return "Named pipe" ;
if ( perms . s ) return "Socket" ;
if ( perms . cd ) return "Character device" ;
if ( perms . bd ) return "Block device" ;
if ( perms . dr ) return "Door" ;
return "Regular file" ;
}
export default ParseUNIXFilePermissions ;