ParseUNIXFilePermissions.mjs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /**
  2. * @author n1474335 [n1474335@gmail.com]
  3. * @copyright Crown Copyright 2016
  4. * @license Apache-2.0
  5. */
  6. import Operation from "../Operation";
  7. import OperationError from "../errors/OperationError";
  8. /**
  9. * Parse UNIX file permissions operation
  10. */
  11. class ParseUNIXFilePermissions extends Operation {
  12. /**
  13. * ParseUNIXFilePermissions constructor
  14. */
  15. constructor() {
  16. super();
  17. this.name = "Parse UNIX file permissions";
  18. this.module = "Default";
  19. 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.";
  20. this.inputType = "string";
  21. this.outputType = "string";
  22. this.args = [];
  23. }
  24. /**
  25. * @param {string} input
  26. * @param {Object[]} args
  27. * @returns {string}
  28. */
  29. run(input, args) {
  30. const perms = {
  31. d: false, // directory
  32. sl: false, // symbolic link
  33. np: false, // named pipe
  34. s: false, // socket
  35. cd: false, // character device
  36. bd: false, // block device
  37. dr: false, // door
  38. sb: false, // sticky bit
  39. su: false, // setuid
  40. sg: false, // setgid
  41. ru: false, // read user
  42. wu: false, // write user
  43. eu: false, // execute user
  44. rg: false, // read group
  45. wg: false, // write group
  46. eg: false, // execute group
  47. ro: false, // read other
  48. wo: false, // write other
  49. eo: false // execute other
  50. };
  51. let d = 0,
  52. u = 0,
  53. g = 0,
  54. o = 0,
  55. output = "",
  56. octal = null,
  57. textual = null;
  58. if (input.search(/\s*[0-7]{1,4}\s*/i) === 0) {
  59. // Input is octal
  60. octal = input.match(/\s*([0-7]{1,4})\s*/i)[1];
  61. if (octal.length === 4) {
  62. d = parseInt(octal[0], 8);
  63. u = parseInt(octal[1], 8);
  64. g = parseInt(octal[2], 8);
  65. o = parseInt(octal[3], 8);
  66. } else {
  67. if (octal.length > 0) u = parseInt(octal[0], 8);
  68. if (octal.length > 1) g = parseInt(octal[1], 8);
  69. if (octal.length > 2) o = parseInt(octal[2], 8);
  70. }
  71. perms.su = d >> 2 & 0x1;
  72. perms.sg = d >> 1 & 0x1;
  73. perms.sb = d & 0x1;
  74. perms.ru = u >> 2 & 0x1;
  75. perms.wu = u >> 1 & 0x1;
  76. perms.eu = u & 0x1;
  77. perms.rg = g >> 2 & 0x1;
  78. perms.wg = g >> 1 & 0x1;
  79. perms.eg = g & 0x1;
  80. perms.ro = o >> 2 & 0x1;
  81. perms.wo = o >> 1 & 0x1;
  82. perms.eo = o & 0x1;
  83. } else if (input.search(/\s*[dlpcbDrwxsStT-]{1,10}\s*/) === 0) {
  84. // Input is textual
  85. textual = input.match(/\s*([dlpcbDrwxsStT-]{1,10})\s*/)[1];
  86. switch (textual[0]) {
  87. case "d":
  88. perms.d = true;
  89. break;
  90. case "l":
  91. perms.sl = true;
  92. break;
  93. case "p":
  94. perms.np = true;
  95. break;
  96. case "s":
  97. perms.s = true;
  98. break;
  99. case "c":
  100. perms.cd = true;
  101. break;
  102. case "b":
  103. perms.bd = true;
  104. break;
  105. case "D":
  106. perms.dr = true;
  107. break;
  108. }
  109. if (textual.length > 1) perms.ru = textual[1] === "r";
  110. if (textual.length > 2) perms.wu = textual[2] === "w";
  111. if (textual.length > 3) {
  112. switch (textual[3]) {
  113. case "x":
  114. perms.eu = true;
  115. break;
  116. case "s":
  117. perms.eu = true;
  118. perms.su = true;
  119. break;
  120. case "S":
  121. perms.su = true;
  122. break;
  123. }
  124. }
  125. if (textual.length > 4) perms.rg = textual[4] === "r";
  126. if (textual.length > 5) perms.wg = textual[5] === "w";
  127. if (textual.length > 6) {
  128. switch (textual[6]) {
  129. case "x":
  130. perms.eg = true;
  131. break;
  132. case "s":
  133. perms.eg = true;
  134. perms.sg = true;
  135. break;
  136. case "S":
  137. perms.sg = true;
  138. break;
  139. }
  140. }
  141. if (textual.length > 7) perms.ro = textual[7] === "r";
  142. if (textual.length > 8) perms.wo = textual[8] === "w";
  143. if (textual.length > 9) {
  144. switch (textual[9]) {
  145. case "x":
  146. perms.eo = true;
  147. break;
  148. case "t":
  149. perms.eo = true;
  150. perms.sb = true;
  151. break;
  152. case "T":
  153. perms.sb = true;
  154. break;
  155. }
  156. }
  157. } else {
  158. throw new OperationError("Invalid input format.\nPlease enter the permissions in either octal (e.g. 755) or textual (e.g. drwxr-xr-x) format.");
  159. }
  160. output += "Textual representation: " + permsToStr(perms);
  161. output += "\nOctal representation: " + permsToOctal(perms);
  162. // File type
  163. if (textual) {
  164. output += "\nFile type: " + ftFromPerms(perms);
  165. }
  166. // setuid, setgid
  167. if (perms.su) {
  168. output += "\nThe setuid flag is set";
  169. }
  170. if (perms.sg) {
  171. output += "\nThe setgid flag is set";
  172. }
  173. // sticky bit
  174. if (perms.sb) {
  175. output += "\nThe sticky bit is set";
  176. }
  177. // Permission matrix
  178. output += `
  179. +---------+-------+-------+-------+
  180. | | User | Group | Other |
  181. +---------+-------+-------+-------+
  182. | Read | ${perms.ru ? "X" : " "} | ${perms.rg ? "X" : " "} | ${perms.ro ? "X" : " "} |
  183. +---------+-------+-------+-------+
  184. | Write | ${perms.wu ? "X" : " "} | ${perms.wg ? "X" : " "} | ${perms.wo ? "X" : " "} |
  185. +---------+-------+-------+-------+
  186. | Execute | ${perms.eu ? "X" : " "} | ${perms.eg ? "X" : " "} | ${perms.eo ? "X" : " "} |
  187. +---------+-------+-------+-------+`;
  188. return output;
  189. }
  190. }
  191. /**
  192. * Given a permissions object dictionary, generates a textual permissions string.
  193. *
  194. * @param {Object} perms
  195. * @returns {string}
  196. */
  197. function permsToStr(perms) {
  198. let str = "",
  199. type = "-";
  200. if (perms.d) type = "d";
  201. if (perms.sl) type = "l";
  202. if (perms.np) type = "p";
  203. if (perms.s) type = "s";
  204. if (perms.cd) type = "c";
  205. if (perms.bd) type = "b";
  206. if (perms.dr) type = "D";
  207. str = type;
  208. str += perms.ru ? "r" : "-";
  209. str += perms.wu ? "w" : "-";
  210. if (perms.eu && perms.su) {
  211. str += "s";
  212. } else if (perms.su) {
  213. str += "S";
  214. } else if (perms.eu) {
  215. str += "x";
  216. } else {
  217. str += "-";
  218. }
  219. str += perms.rg ? "r" : "-";
  220. str += perms.wg ? "w" : "-";
  221. if (perms.eg && perms.sg) {
  222. str += "s";
  223. } else if (perms.sg) {
  224. str += "S";
  225. } else if (perms.eg) {
  226. str += "x";
  227. } else {
  228. str += "-";
  229. }
  230. str += perms.ro ? "r" : "-";
  231. str += perms.wo ? "w" : "-";
  232. if (perms.eo && perms.sb) {
  233. str += "t";
  234. } else if (perms.sb) {
  235. str += "T";
  236. } else if (perms.eo) {
  237. str += "x";
  238. } else {
  239. str += "-";
  240. }
  241. return str;
  242. }
  243. /**
  244. * Given a permissions object dictionary, generates an octal permissions string.
  245. *
  246. * @param {Object} perms
  247. * @returns {string}
  248. */
  249. function permsToOctal(perms) {
  250. let d = 0,
  251. u = 0,
  252. g = 0,
  253. o = 0;
  254. if (perms.su) d += 4;
  255. if (perms.sg) d += 2;
  256. if (perms.sb) d += 1;
  257. if (perms.ru) u += 4;
  258. if (perms.wu) u += 2;
  259. if (perms.eu) u += 1;
  260. if (perms.rg) g += 4;
  261. if (perms.wg) g += 2;
  262. if (perms.eg) g += 1;
  263. if (perms.ro) o += 4;
  264. if (perms.wo) o += 2;
  265. if (perms.eo) o += 1;
  266. return d.toString() + u.toString() + g.toString() + o.toString();
  267. }
  268. /**
  269. * Given a permissions object dictionary, returns the file type.
  270. *
  271. * @param {Object} perms
  272. * @returns {string}
  273. */
  274. function ftFromPerms(perms) {
  275. if (perms.d) return "Directory";
  276. if (perms.sl) return "Symbolic link";
  277. if (perms.np) return "Named pipe";
  278. if (perms.s) return "Socket";
  279. if (perms.cd) return "Character device";
  280. if (perms.bd) return "Block device";
  281. if (perms.dr) return "Door";
  282. return "Regular file";
  283. }
  284. export default ParseUNIXFilePermissions;