From cefe5bbaa88947d6326afd6271b967010a9c1a0f Mon Sep 17 00:00:00 2001 From: n1474335 Date: Mon, 14 May 2018 17:03:23 +0000 Subject: [PATCH 1/5] ESM: Ported Convert operations --- src/core/operations/ConvertArea.mjs | 112 ++++++++++++++++++ src/core/operations/ConvertDataUnits.mjs | 111 ++++++++++++++++++ src/core/operations/ConvertDistance.mjs | 95 +++++++++++++++ src/core/operations/ConvertMass.mjs | 143 +++++++++++++++++++++++ src/core/operations/ConvertSpeed.mjs | 96 +++++++++++++++ 5 files changed, 557 insertions(+) create mode 100644 src/core/operations/ConvertArea.mjs create mode 100644 src/core/operations/ConvertDataUnits.mjs create mode 100644 src/core/operations/ConvertDistance.mjs create mode 100644 src/core/operations/ConvertMass.mjs create mode 100644 src/core/operations/ConvertSpeed.mjs diff --git a/src/core/operations/ConvertArea.mjs b/src/core/operations/ConvertArea.mjs new file mode 100644 index 00000000..dd88f52e --- /dev/null +++ b/src/core/operations/ConvertArea.mjs @@ -0,0 +1,112 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; + +/** + * Convert area operation + */ +class ConvertArea extends Operation { + + /** + * ConvertArea constructor + */ + constructor() { + super(); + + this.name = "Convert area"; + this.module = "Default"; + this.description = "Converts a unit of area to another format."; + this.inputType = "BigNumber"; + this.outputType = "BigNumber"; + this.args = [ + { + "name": "Input units", + "type": "option", + "value": AREA_UNITS + }, + { + "name": "Output units", + "type": "option", + "value": AREA_UNITS + } + ]; + } + + /** + * @param {BigNumber} input + * @param {Object[]} args + * @returns {BigNumber} + */ + run(input, args) { + const [inputUnits, outputUnits] = args; + + input = input.times(AREA_FACTOR[inputUnits]); + return input.div(AREA_FACTOR[outputUnits]); + } + +} + + +const AREA_UNITS = [ + "[Metric]", "Square metre (sq m)", "Square kilometre (sq km)", "Centiare (ca)", "Deciare (da)", "Are (a)", "Decare (daa)", "Hectare (ha)", "[/Metric]", + "[Imperial]", "Square inch (sq in)", "Square foot (sq ft)", "Square yard (sq yd)", "Square mile (sq mi)", "Perch (sq per)", "Rood (ro)", "International acre (ac)", "[/Imperial]", + "[US customary units]", "US survey acre (ac)", "US survey square mile (sq mi)", "US survey township", "[/US customary units]", + "[Nuclear physics]", "Yoctobarn (yb)", "Zeptobarn (zb)", "Attobarn (ab)", "Femtobarn (fb)", "Picobarn (pb)", "Nanobarn (nb)", "Microbarn (μb)", "Millibarn (mb)", "Barn (b)", "Kilobarn (kb)", "Megabarn (Mb)", "Outhouse", "Shed", "Planck area", "[/Nuclear physics]", + "[Comparisons]", "Washington D.C.", "Isle of Wight", "Wales", "Texas", "[/Comparisons]", +]; + +const AREA_FACTOR = { // Multiples of a square metre + // Metric + "Square metre (sq m)": 1, + "Square kilometre (sq km)": 1e6, + + "Centiare (ca)": 1, + "Deciare (da)": 10, + "Are (a)": 100, + "Decare (daa)": 1e3, + "Hectare (ha)": 1e4, + + // Imperial + "Square inch (sq in)": 0.00064516, + "Square foot (sq ft)": 0.09290304, + "Square yard (sq yd)": 0.83612736, + "Square mile (sq mi)": 2589988.110336, + "Perch (sq per)": 42.21, + "Rood (ro)": 1011, + "International acre (ac)": 4046.8564224, + + // US customary units + "US survey acre (ac)": 4046.87261, + "US survey square mile (sq mi)": 2589998.470305239, + "US survey township": 93239944.9309886, + + // Nuclear physics + "Yoctobarn (yb)": 1e-52, + "Zeptobarn (zb)": 1e-49, + "Attobarn (ab)": 1e-46, + "Femtobarn (fb)": 1e-43, + "Picobarn (pb)": 1e-40, + "Nanobarn (nb)": 1e-37, + "Microbarn (μb)": 1e-34, + "Millibarn (mb)": 1e-31, + "Barn (b)": 1e-28, + "Kilobarn (kb)": 1e-25, + "Megabarn (Mb)": 1e-22, + + "Planck area": 2.6e-70, + "Shed": 1e-52, + "Outhouse": 1e-34, + + // Comparisons + "Washington D.C.": 176119191.502848, + "Isle of Wight": 380000000, + "Wales": 20779000000, + "Texas": 696241000000, +}; + + +export default ConvertArea; diff --git a/src/core/operations/ConvertDataUnits.mjs b/src/core/operations/ConvertDataUnits.mjs new file mode 100644 index 00000000..dc22e351 --- /dev/null +++ b/src/core/operations/ConvertDataUnits.mjs @@ -0,0 +1,111 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; + +/** + * Convert data units operation + */ +class ConvertDataUnits extends Operation { + + /** + * ConvertDataUnits constructor + */ + constructor() { + super(); + + this.name = "Convert data units"; + this.module = "Default"; + this.description = "Converts a unit of data to another format."; + this.inputType = "BigNumber"; + this.outputType = "BigNumber"; + this.args = [ + { + "name": "Input units", + "type": "option", + "value": DATA_UNITS + }, + { + "name": "Output units", + "type": "option", + "value": DATA_UNITS + } + ]; + } + + /** + * @param {BigNumber} input + * @param {Object[]} args + * @returns {BigNumber} + */ + run(input, args) { + const [inputUnits, outputUnits] = args; + + input = input.times(DATA_FACTOR[inputUnits]); + return input.div(DATA_FACTOR[outputUnits]); + } + +} + +const DATA_UNITS = [ + "Bits (b)", "Nibbles", "Octets", "Bytes (B)", + "[Binary bits (2^n)]", "Kibibits (Kib)", "Mebibits (Mib)", "Gibibits (Gib)", "Tebibits (Tib)", "Pebibits (Pib)", "Exbibits (Eib)", "Zebibits (Zib)", "Yobibits (Yib)", "[/Binary bits (2^n)]", + "[Decimal bits (10^n)]", "Decabits", "Hectobits", "Kilobits (kb)", "Megabits (Mb)", "Gigabits (Gb)", "Terabits (Tb)", "Petabits (Pb)", "Exabits (Eb)", "Zettabits (Zb)", "Yottabits (Yb)", "[/Decimal bits (10^n)]", + "[Binary bytes (8 x 2^n)]", "Kibibytes (KiB)", "Mebibytes (MiB)", "Gibibytes (GiB)", "Tebibytes (TiB)", "Pebibytes (PiB)", "Exbibytes (EiB)", "Zebibytes (ZiB)", "Yobibytes (YiB)", "[/Binary bytes (8 x 2^n)]", + "[Decimal bytes (8 x 10^n)]", "Kilobytes (KB)", "Megabytes (MB)", "Gigabytes (GB)", "Terabytes (TB)", "Petabytes (PB)", "Exabytes (EB)", "Zettabytes (ZB)", "Yottabytes (YB)", "[/Decimal bytes (8 x 10^n)]" +]; + +const DATA_FACTOR = { // Multiples of a bit + "Bits (b)": 1, + "Nibbles": 4, + "Octets": 8, + "Bytes (B)": 8, + + // Binary bits (2^n) + "Kibibits (Kib)": 1024, + "Mebibits (Mib)": 1048576, + "Gibibits (Gib)": 1073741824, + "Tebibits (Tib)": 1099511627776, + "Pebibits (Pib)": 1125899906842624, + "Exbibits (Eib)": 1152921504606846976, + "Zebibits (Zib)": 1180591620717411303424, + "Yobibits (Yib)": 1208925819614629174706176, + + // Decimal bits (10^n) + "Decabits": 10, + "Hectobits": 100, + "Kilobits (Kb)": 1e3, + "Megabits (Mb)": 1e6, + "Gigabits (Gb)": 1e9, + "Terabits (Tb)": 1e12, + "Petabits (Pb)": 1e15, + "Exabits (Eb)": 1e18, + "Zettabits (Zb)": 1e21, + "Yottabits (Yb)": 1e24, + + // Binary bytes (8 x 2^n) + "Kibibytes (KiB)": 8192, + "Mebibytes (MiB)": 8388608, + "Gibibytes (GiB)": 8589934592, + "Tebibytes (TiB)": 8796093022208, + "Pebibytes (PiB)": 9007199254740992, + "Exbibytes (EiB)": 9223372036854775808, + "Zebibytes (ZiB)": 9444732965739290427392, + "Yobibytes (YiB)": 9671406556917033397649408, + + // Decimal bytes (8 x 10^n) + "Kilobytes (KB)": 8e3, + "Megabytes (MB)": 8e6, + "Gigabytes (GB)": 8e9, + "Terabytes (TB)": 8e12, + "Petabytes (PB)": 8e15, + "Exabytes (EB)": 8e18, + "Zettabytes (ZB)": 8e21, + "Yottabytes (YB)": 8e24, +}; + + +export default ConvertDataUnits; diff --git a/src/core/operations/ConvertDistance.mjs b/src/core/operations/ConvertDistance.mjs new file mode 100644 index 00000000..278a1c6d --- /dev/null +++ b/src/core/operations/ConvertDistance.mjs @@ -0,0 +1,95 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; + +/** + * Convert distance operation + */ +class ConvertDistance extends Operation { + + /** + * ConvertDistance constructor + */ + constructor() { + super(); + + this.name = "Convert distance"; + this.module = "Default"; + this.description = "Converts a unit of distance to another format."; + this.inputType = "BigNumber"; + this.outputType = "BigNumber"; + this.args = [ + { + "name": "Input units", + "type": "option", + "value": DISTANCE_UNITS + }, + { + "name": "Output units", + "type": "option", + "value": DISTANCE_UNITS + } + ]; + } + + /** + * @param {BigNumber} input + * @param {Object[]} args + * @returns {BigNumber} + */ + run(input, args) { + const [inputUnits, outputUnits] = args; + + input = input.times(DISTANCE_FACTOR[inputUnits]); + return input.div(DISTANCE_FACTOR[outputUnits]); + } + +} + +const DISTANCE_UNITS = [ + "[Metric]", "Nanometres (nm)", "Micrometres (µm)", "Millimetres (mm)", "Centimetres (cm)", "Metres (m)", "Kilometers (km)", "[/Metric]", + "[Imperial]", "Thou (th)", "Inches (in)", "Feet (ft)", "Yards (yd)", "Chains (ch)", "Furlongs (fur)", "Miles (mi)", "Leagues (lea)", "[/Imperial]", + "[Maritime]", "Fathoms (ftm)", "Cables", "Nautical miles", "[/Maritime]", + "[Comparisons]", "Cars (4m)", "Buses (8.4m)", "American football fields (91m)", "Football pitches (105m)", "[/Comparisons]", + "[Astronomical]", "Earth-to-Moons", "Earth's equators", "Astronomical units (au)", "Light-years (ly)", "Parsecs (pc)", "[/Astronomical]", +]; + +const DISTANCE_FACTOR = { // Multiples of a metre + "Nanometres (nm)": 1e-9, + "Micrometres (µm)": 1e-6, + "Millimetres (mm)": 1e-3, + "Centimetres (cm)": 1e-2, + "Metres (m)": 1, + "Kilometers (km)": 1e3, + + "Thou (th)": 0.0000254, + "Inches (in)": 0.0254, + "Feet (ft)": 0.3048, + "Yards (yd)": 0.9144, + "Chains (ch)": 20.1168, + "Furlongs (fur)": 201.168, + "Miles (mi)": 1609.344, + "Leagues (lea)": 4828.032, + + "Fathoms (ftm)": 1.853184, + "Cables": 185.3184, + "Nautical miles": 1853.184, + + "Cars (4m)": 4, + "Buses (8.4m)": 8.4, + "American football fields (91m)": 91, + "Football pitches (105m)": 105, + + "Earth-to-Moons": 380000000, + "Earth's equators": 40075016.686, + "Astronomical units (au)": 149597870700, + "Light-years (ly)": 9460730472580800, + "Parsecs (pc)": 3.0856776e16 +}; + + +export default ConvertDistance; diff --git a/src/core/operations/ConvertMass.mjs b/src/core/operations/ConvertMass.mjs new file mode 100644 index 00000000..18c0c84a --- /dev/null +++ b/src/core/operations/ConvertMass.mjs @@ -0,0 +1,143 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; + +/** + * Convert mass operation + */ +class ConvertMass extends Operation { + + /** + * ConvertMass constructor + */ + constructor() { + super(); + + this.name = "Convert mass"; + this.module = "Default"; + this.description = "Converts a unit of mass to another format."; + this.inputType = "BigNumber"; + this.outputType = "BigNumber"; + this.args = [ + { + "name": "Input units", + "type": "option", + "value": MASS_UNITS + }, + { + "name": "Output units", + "type": "option", + "value": MASS_UNITS + } + ]; + } + + /** + * @param {BigNumber} input + * @param {Object[]} args + * @returns {BigNumber} + */ + run(input, args) { + const [inputUnits, outputUnits] = args; + + input = input.times(MASS_FACTOR[inputUnits]); + return input.div(MASS_FACTOR[outputUnits]); + } + +} + + +const MASS_UNITS = [ + "[Metric]", "Yoctogram (yg)", "Zeptogram (zg)", "Attogram (ag)", "Femtogram (fg)", "Picogram (pg)", "Nanogram (ng)", "Microgram (μg)", "Milligram (mg)", "Centigram (cg)", "Decigram (dg)", "Gram (g)", "Decagram (dag)", "Hectogram (hg)", "Kilogram (kg)", "Megagram (Mg)", "Tonne (t)", "Gigagram (Gg)", "Teragram (Tg)", "Petagram (Pg)", "Exagram (Eg)", "Zettagram (Zg)", "Yottagram (Yg)", "[/Metric]", + "[Imperial Avoirdupois]", "Grain (gr)", "Dram (dr)", "Ounce (oz)", "Pound (lb)", "Nail", "Stone (st)", "Quarter (gr)", "Tod", "US hundredweight (cwt)", "Imperial hundredweight (cwt)", "US ton (t)", "Imperial ton (t)", "[/Imperial Avoirdupois]", + "[Imperial Troy]", "Grain (gr)", "Pennyweight (dwt)", "Troy dram (dr t)", "Troy ounce (oz t)", "Troy pound (lb t)", "Mark", "[/Imperial Troy]", + "[Archaic]", "Wey", "Wool wey", "Suffolk wey", "Wool sack", "Coal sack", "Load", "Last", "Flax or feather last", "Gunpowder last", "Picul", "Rice last", "[/Archaic]", + "[Comparisons]", "Big Ben (14 tonnes)", "Blue whale (180 tonnes)", "International Space Station (417 tonnes)", "Space Shuttle (2,041 tonnes)", "RMS Titanic (52,000 tonnes)", "Great Pyramid of Giza (6,000,000 tonnes)", "Earth's oceans (1.4 yottagrams)", "[/Comparisons]", + "[Astronomical]", "A teaspoon of neutron star (5,500 million tonnes)", "Lunar mass (ML)", "Earth mass (M⊕)", "Jupiter mass (MJ)", "Solar mass (M☉)", "Sagittarius A* (7.5 x 10^36 kgs-ish)", "Milky Way galaxy (1.2 x 10^42 kgs)", "The observable universe (1.45 x 10^53 kgs)", "[/Astronomical]", +]; + +const MASS_FACTOR = { // Multiples of a gram + // Metric + "Yoctogram (yg)": 1e-24, + "Zeptogram (zg)": 1e-21, + "Attogram (ag)": 1e-18, + "Femtogram (fg)": 1e-15, + "Picogram (pg)": 1e-12, + "Nanogram (ng)": 1e-9, + "Microgram (μg)": 1e-6, + "Milligram (mg)": 1e-3, + "Centigram (cg)": 1e-2, + "Decigram (dg)": 1e-1, + "Gram (g)": 1, + "Decagram (dag)": 10, + "Hectogram (hg)": 100, + "Kilogram (kg)": 1000, + "Megagram (Mg)": 1e6, + "Tonne (t)": 1e6, + "Gigagram (Gg)": 1e9, + "Teragram (Tg)": 1e12, + "Petagram (Pg)": 1e15, + "Exagram (Eg)": 1e18, + "Zettagram (Zg)": 1e21, + "Yottagram (Yg)": 1e24, + + // Imperial Avoirdupois + "Grain (gr)": 64.79891e-3, + "Dram (dr)": 1.7718451953125, + "Ounce (oz)": 28.349523125, + "Pound (lb)": 453.59237, + "Nail": 3175.14659, + "Stone (st)": 6.35029318e3, + "Quarter (gr)": 12700.58636, + "Tod": 12700.58636, + "US hundredweight (cwt)": 45.359237e3, + "Imperial hundredweight (cwt)": 50.80234544e3, + "US ton (t)": 907.18474e3, + "Imperial ton (t)": 1016.0469088e3, + + // Imperial Troy + "Pennyweight (dwt)": 1.55517384, + "Troy dram (dr t)": 3.8879346, + "Troy ounce (oz t)": 31.1034768, + "Troy pound (lb t)": 373.2417216, + "Mark": 248.8278144, + + // Archaic + "Wey": 76.5e3, + "Wool wey": 101.7e3, + "Suffolk wey": 161.5e3, + "Wool sack": 153000, + "Coal sack": 50.80234544e3, + "Load": 918000, + "Last": 1836000, + "Flax or feather last": 770e3, + "Gunpowder last": 1090e3, + "Picul": 60.478982e3, + "Rice last": 1200e3, + + // Comparisons + "Big Ben (14 tonnes)": 14e6, + "Blue whale (180 tonnes)": 180e6, + "International Space Station (417 tonnes)": 417e6, + "Space Shuttle (2,041 tonnes)": 2041e6, + "RMS Titanic (52,000 tonnes)": 52000e6, + "Great Pyramid of Giza (6,000,000 tonnes)": 6e12, + "Earth's oceans (1.4 yottagrams)": 1.4e24, + + // Astronomical + "A teaspoon of neutron star (5,500 million tonnes)": 5.5e15, + "Lunar mass (ML)": 7.342e25, + "Earth mass (M⊕)": 5.97219e27, + "Jupiter mass (MJ)": 1.8981411476999997e30, + "Solar mass (M☉)": 1.98855e33, + "Sagittarius A* (7.5 x 10^36 kgs-ish)": 7.5e39, + "Milky Way galaxy (1.2 x 10^42 kgs)": 1.2e45, + "The observable universe (1.45 x 10^53 kgs)": 1.45e56, +}; + + +export default ConvertMass; diff --git a/src/core/operations/ConvertSpeed.mjs b/src/core/operations/ConvertSpeed.mjs new file mode 100644 index 00000000..71c43a54 --- /dev/null +++ b/src/core/operations/ConvertSpeed.mjs @@ -0,0 +1,96 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; + +/** + * Convert speed operation + */ +class ConvertSpeed extends Operation { + + /** + * ConvertSpeed constructor + */ + constructor() { + super(); + + this.name = "Convert speed"; + this.module = "Default"; + this.description = "Converts a unit of speed to another format."; + this.inputType = "BigNumber"; + this.outputType = "BigNumber"; + this.args = [ + { + "name": "Input units", + "type": "option", + "value": SPEED_UNITS + }, + { + "name": "Output units", + "type": "option", + "value": SPEED_UNITS + } + ]; + } + + /** + * @param {BigNumber} input + * @param {Object[]} args + * @returns {BigNumber} + */ + run(input, args) { + const [inputUnits, outputUnits] = args; + + input = input.times(SPEED_FACTOR[inputUnits]); + return input.div(SPEED_FACTOR[outputUnits]); + } + +} + +const SPEED_UNITS = [ + "[Metric]", "Metres per second (m/s)", "Kilometres per hour (km/h)", "[/Metric]", + "[Imperial]", "Miles per hour (mph)", "Knots (kn)", "[/Imperial]", + "[Comparisons]", "Human hair growth rate", "Bamboo growth rate", "World's fastest snail", "Usain Bolt's top speed", "Jet airliner cruising speed", "Concorde", "SR-71 Blackbird", "Space Shuttle", "International Space Station", "[/Comparisons]", + "[Scientific]", "Sound in standard atmosphere", "Sound in water", "Lunar escape velocity", "Earth escape velocity", "Earth's solar orbit", "Solar system's Milky Way orbit", "Milky Way relative to the cosmic microwave background", "Solar escape velocity", "Neutron star escape velocity (0.3c)", "Light in a diamond (0.4136c)", "Signal in an optical fibre (0.667c)", "Light (c)", "[/Scientific]", +]; + +const SPEED_FACTOR = { // Multiples of m/s + // Metric + "Metres per second (m/s)": 1, + "Kilometres per hour (km/h)": 0.2778, + + // Imperial + "Miles per hour (mph)": 0.44704, + "Knots (kn)": 0.5144, + + // Comparisons + "Human hair growth rate": 4.8e-9, + "Bamboo growth rate": 1.4e-5, + "World's fastest snail": 0.00275, + "Usain Bolt's top speed": 12.42, + "Jet airliner cruising speed": 250, + "Concorde": 603, + "SR-71 Blackbird": 981, + "Space Shuttle": 1400, + "International Space Station": 7700, + + // Scientific + "Sound in standard atmosphere": 340.3, + "Sound in water": 1500, + "Lunar escape velocity": 2375, + "Earth escape velocity": 11200, + "Earth's solar orbit": 29800, + "Solar system's Milky Way orbit": 200000, + "Milky Way relative to the cosmic microwave background": 552000, + "Solar escape velocity": 617700, + "Neutron star escape velocity (0.3c)": 100000000, + "Light in a diamond (0.4136c)": 124000000, + "Signal in an optical fibre (0.667c)": 200000000, + "Light (c)": 299792458, +}; + + +export default ConvertSpeed; From 10005ce10496ac53772858ad65633bc108de88eb Mon Sep 17 00:00:00 2001 From: n1474335 Date: Mon, 14 May 2018 17:16:42 +0000 Subject: [PATCH 2/5] ESM: Ported OS operations --- .../operations/ParseUNIXFilePermissions.mjs | 323 ++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 src/core/operations/ParseUNIXFilePermissions.mjs diff --git a/src/core/operations/ParseUNIXFilePermissions.mjs b/src/core/operations/ParseUNIXFilePermissions.mjs new file mode 100644 index 00000000..829dda76 --- /dev/null +++ b/src/core/operations/ParseUNIXFilePermissions.mjs @@ -0,0 +1,323 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; + +/** + * 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.

Input should be in either octal (e.g. 755) or textual (e.g. drwxr-xr-x) format."; + this.inputType = "string"; + this.outputType = "string"; + this.args = []; + } + + /** + * @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 { + return "Invalid input format.\nPlease enter the permissions in either octal (e.g. 755) or textual (e.g. drwxr-xr-x) format."; + } + + 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; From bad45f19d6a01a063ec6f3120cedfca6ab1763c2 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Mon, 14 May 2018 17:48:57 +0000 Subject: [PATCH 3/5] ESM: Ported DateTime operations --- src/core/config/scripts/portOperation.mjs | 2 +- src/core/lib/DateTime.mjs | 313 ++++++++++++++++++ src/core/operations/FromUNIXTimestamp.mjs | 66 ++++ src/core/operations/ParseDateTime.mjs | 82 +++++ src/core/operations/Sleep.mjs | 47 +++ src/core/operations/ToUNIXTimestamp.mjs | 74 +++++ .../operations/TranslateDateTimeFormat.mjs | 78 +++++ 7 files changed, 661 insertions(+), 1 deletion(-) create mode 100644 src/core/lib/DateTime.mjs create mode 100644 src/core/operations/FromUNIXTimestamp.mjs create mode 100644 src/core/operations/ParseDateTime.mjs create mode 100644 src/core/operations/Sleep.mjs create mode 100644 src/core/operations/ToUNIXTimestamp.mjs create mode 100644 src/core/operations/TranslateDateTimeFormat.mjs diff --git a/src/core/config/scripts/portOperation.mjs b/src/core/config/scripts/portOperation.mjs index d746be1f..4491d493 100644 --- a/src/core/config/scripts/portOperation.mjs +++ b/src/core/config/scripts/portOperation.mjs @@ -167,7 +167,7 @@ export default ${moduleName}; } else { console.log("\x1b[32m\u2714\x1b[0m The run function was copied across. Double check that it was copied correctly. It may rely on other functions which have not been copied."); } - console.log(`\nOpen \x1b[32m${legacyFilename}\x1b[0m and copy any relevant code over. Make sure you check imports, args and highlights. Code required by multiple operations should be stored in /src/core/lib/`); + console.log(`\nOpen \x1b[32m${legacyFilename}\x1b[0m and copy any relevant code over. Make sure you check imports, args and highlights. Code required by multiple operations should be stored in /src/core/lib/.\n\nDont't forget to run \x1b[36mgrunt lint\x1b[0m!`); } diff --git a/src/core/lib/DateTime.mjs b/src/core/lib/DateTime.mjs new file mode 100644 index 00000000..89b0e3c6 --- /dev/null +++ b/src/core/lib/DateTime.mjs @@ -0,0 +1,313 @@ +/** + * DateTime resources. + * + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +/** + * DateTime units. + */ +export const UNITS = ["Seconds (s)", "Milliseconds (ms)", "Microseconds (μs)", "Nanoseconds (ns)"]; + +/** + * DateTime formats. + */ +export const DATETIME_FORMATS = [ + { + name: "Standard date and time", + value: "DD/MM/YYYY HH:mm:ss" + }, + { + name: "American-style date and time", + value: "MM/DD/YYYY HH:mm:ss" + }, + { + name: "International date and time", + value: "YYYY-MM-DD HH:mm:ss" + }, + { + name: "Verbose date and time", + value: "dddd Do MMMM YYYY HH:mm:ss Z z" + }, + { + name: "UNIX timestamp (seconds)", + value: "X" + }, + { + name: "UNIX timestamp offset (milliseconds)", + value: "x" + }, + { + name: "Automatic", + value: "" + }, +]; + +/** + * MomentJS DateTime formatting examples. + */ +export const FORMAT_EXAMPLES = `Format string tokens: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CategoryTokenOutput
MonthM1 2 ... 11 12
Mo1st 2nd ... 11th 12th
MM01 02 ... 11 12
MMMJan Feb ... Nov Dec
MMMMJanuary February ... November December
QuarterQ1 2 3 4
Day of MonthD1 2 ... 30 31
Do1st 2nd ... 30th 31st
DD01 02 ... 30 31
Day of YearDDD1 2 ... 364 365
DDDo1st 2nd ... 364th 365th
DDDD001 002 ... 364 365
Day of Weekd0 1 ... 5 6
do0th 1st ... 5th 6th
ddSu Mo ... Fr Sa
dddSun Mon ... Fri Sat
ddddSunday Monday ... Friday Saturday
Day of Week (Locale)e0 1 ... 5 6
Day of Week (ISO)E1 2 ... 6 7
Week of Yearw1 2 ... 52 53
wo1st 2nd ... 52nd 53rd
ww01 02 ... 52 53
Week of Year (ISO)W1 2 ... 52 53
Wo1st 2nd ... 52nd 53rd
WW01 02 ... 52 53
YearYY70 71 ... 29 30
YYYY1970 1971 ... 2029 2030
Week Yeargg70 71 ... 29 30
gggg1970 1971 ... 2029 2030
Week Year (ISO)GG70 71 ... 29 30
GGGG1970 1971 ... 2029 2030
AM/PMAAM PM
aam pm
HourH0 1 ... 22 23
HH00 01 ... 22 23
h1 2 ... 11 12
hh01 02 ... 11 12
Minutem0 1 ... 58 59
mm00 01 ... 58 59
Seconds0 1 ... 58 59
ss00 01 ... 58 59
Fractional SecondS0 1 ... 8 9
SS00 01 ... 98 99
SSS000 001 ... 998 999
SSSS ... SSSSSSSSS000[0..] 001[0..] ... 998[0..] 999[0..]
Timezonez or zzEST CST ... MST PST
Z-07:00 -06:00 ... +06:00 +07:00
ZZ-0700 -0600 ... +0600 +0700
Unix TimestampX1360013296
Unix Millisecond Timestampx1360013296123
`; + diff --git a/src/core/operations/FromUNIXTimestamp.mjs b/src/core/operations/FromUNIXTimestamp.mjs new file mode 100644 index 00000000..90c7f120 --- /dev/null +++ b/src/core/operations/FromUNIXTimestamp.mjs @@ -0,0 +1,66 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import moment from "moment-timezone"; +import {UNITS} from "../lib/DateTime"; + +/** + * From UNIX Timestamp operation + */ +class FromUNIXTimestamp extends Operation { + + /** + * FromUNIXTimestamp constructor + */ + constructor() { + super(); + + this.name = "From UNIX Timestamp"; + this.module = "Default"; + this.description = "Converts a UNIX timestamp to a datetime string.

e.g. 978346800 becomes Mon 1 January 2001 11:00:00 UTC

A UNIX timestamp is a 32-bit value representing the number of seconds since January 1, 1970 UTC (the UNIX epoch)."; + this.inputType = "number"; + this.outputType = "string"; + this.args = [ + { + "name": "Units", + "type": "option", + "value": UNITS + } + ]; + } + + /** + * @param {number} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const units = args[0]; + let d; + + input = parseFloat(input); + + if (units === "Seconds (s)") { + d = moment.unix(input); + return d.tz("UTC").format("ddd D MMMM YYYY HH:mm:ss") + " UTC"; + } else if (units === "Milliseconds (ms)") { + d = moment(input); + return d.tz("UTC").format("ddd D MMMM YYYY HH:mm:ss.SSS") + " UTC"; + } else if (units === "Microseconds (μs)") { + d = moment(input / 1000); + return d.tz("UTC").format("ddd D MMMM YYYY HH:mm:ss.SSS") + " UTC"; + } else if (units === "Nanoseconds (ns)") { + d = moment(input / 1000000); + return d.tz("UTC").format("ddd D MMMM YYYY HH:mm:ss.SSS") + " UTC"; + } else { + throw "Unrecognised unit"; + } + } + +} + +export default FromUNIXTimestamp; diff --git a/src/core/operations/ParseDateTime.mjs b/src/core/operations/ParseDateTime.mjs new file mode 100644 index 00000000..c48f848b --- /dev/null +++ b/src/core/operations/ParseDateTime.mjs @@ -0,0 +1,82 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import moment from "moment-timezone"; +import {DATETIME_FORMATS, FORMAT_EXAMPLES} from "../lib/DateTime"; + +/** + * Parse DateTime operation + */ +class ParseDateTime extends Operation { + + /** + * ParseDateTime constructor + */ + constructor() { + super(); + + this.name = "Parse DateTime"; + this.module = "Default"; + this.description = "Parses a DateTime string in your specified format and displays it in whichever timezone you choose with the following information:
  • Date
  • Time
  • Period (AM/PM)
  • Timezone
  • UTC offset
  • Daylight Saving Time
  • Leap year
  • Days in this month
  • Day of year
  • Week number
  • Quarter
Run with no input to see format string examples if required."; + this.inputType = "string"; + this.outputType = "html"; + this.args = [ + { + "name": "Built in formats", + "type": "populateOption", + "value": DATETIME_FORMATS, + "target": 1 + }, + { + "name": "Input format string", + "type": "binaryString", + "value": "DD/MM/YYYY HH:mm:ss" + }, + { + "name": "Input timezone", + "type": "option", + "value": ["UTC"].concat(moment.tz.names()) + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {html} + */ + run(input, args) { + const inputFormat = args[1], + inputTimezone = args[2]; + let date, + output = ""; + + try { + date = moment.tz(input, inputFormat, inputTimezone); + if (!date || date.format() === "Invalid date") throw Error; + } catch (err) { + return "Invalid format.\n\n" + FORMAT_EXAMPLES; + } + + output += "Date: " + date.format("dddd Do MMMM YYYY") + + "\nTime: " + date.format("HH:mm:ss") + + "\nPeriod: " + date.format("A") + + "\nTimezone: " + date.format("z") + + "\nUTC offset: " + date.format("ZZ") + + "\n\nDaylight Saving Time: " + date.isDST() + + "\nLeap year: " + date.isLeapYear() + + "\nDays in this month: " + date.daysInMonth() + + "\n\nDay of year: " + date.dayOfYear() + + "\nWeek number: " + date.weekYear() + + "\nQuarter: " + date.quarter(); + + return output; + } + +} + +export default ParseDateTime; diff --git a/src/core/operations/Sleep.mjs b/src/core/operations/Sleep.mjs new file mode 100644 index 00000000..4cd71bfe --- /dev/null +++ b/src/core/operations/Sleep.mjs @@ -0,0 +1,47 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2018 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; + +/** + * Sleep operation + */ +class Sleep extends Operation { + + /** + * Sleep constructor + */ + constructor() { + super(); + + this.name = "Sleep"; + this.module = "Default"; + this.description = "Sleep causes the recipe to wait for a specified number of milliseconds before continuing execution."; + this.inputType = "ArrayBuffer"; + this.outputType = "ArrayBuffer"; + this.args = [ + { + "name": "Time (ms)", + "type": "number", + "value": 1000 + } + ]; + } + + /** + * @param {ArrayBuffer} input + * @param {Object[]} args + * @returns {ArrayBuffer} + */ + async run(input, args) { + const ms = args[0]; + await new Promise(r => setTimeout(r, ms)); + return input; + } + +} + +export default Sleep; diff --git a/src/core/operations/ToUNIXTimestamp.mjs b/src/core/operations/ToUNIXTimestamp.mjs new file mode 100644 index 00000000..1907b5a6 --- /dev/null +++ b/src/core/operations/ToUNIXTimestamp.mjs @@ -0,0 +1,74 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import moment from "moment-timezone"; +import {UNITS} from "../lib/DateTime"; + +/** + * To UNIX Timestamp operation + */ +class ToUNIXTimestamp extends Operation { + + /** + * ToUNIXTimestamp constructor + */ + constructor() { + super(); + + this.name = "To UNIX Timestamp"; + this.module = "Default"; + this.description = "Parses a datetime string in UTC and returns the corresponding UNIX timestamp.

e.g. Mon 1 January 2001 11:00:00 becomes 978346800

A UNIX timestamp is a 32-bit value representing the number of seconds since January 1, 1970 UTC (the UNIX epoch)."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Units", + "type": "option", + "value": UNITS + }, + { + "name": "Treat as UTC", + "type": "boolean", + "value": true + }, + { + "name": "Show parsed datetime", + "type": "boolean", + "value": true + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const [units, treatAsUTC, showDateTime] = args, + d = treatAsUTC ? moment.utc(input) : moment(input); + + let result = ""; + + if (units === "Seconds (s)") { + result = d.unix(); + } else if (units === "Milliseconds (ms)") { + result = d.valueOf(); + } else if (units === "Microseconds (μs)") { + result = d.valueOf() * 1000; + } else if (units === "Nanoseconds (ns)") { + result = d.valueOf() * 1000000; + } else { + throw "Unrecognised unit"; + } + + return showDateTime ? `${result} (${d.tz("UTC").format("ddd D MMMM YYYY HH:mm:ss")} UTC)` : result.toString(); + } + +} + +export default ToUNIXTimestamp; diff --git a/src/core/operations/TranslateDateTimeFormat.mjs b/src/core/operations/TranslateDateTimeFormat.mjs new file mode 100644 index 00000000..b3895978 --- /dev/null +++ b/src/core/operations/TranslateDateTimeFormat.mjs @@ -0,0 +1,78 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import moment from "moment-timezone"; +import {DATETIME_FORMATS, FORMAT_EXAMPLES} from "../lib/DateTime"; + +/** + * Translate DateTime Format operation + */ +class TranslateDateTimeFormat extends Operation { + + /** + * TranslateDateTimeFormat constructor + */ + constructor() { + super(); + + this.name = "Translate DateTime Format"; + this.module = "Default"; + this.description = "Parses a datetime string in one format and re-writes it in another.

Run with no input to see the relevant format string examples."; + this.inputType = "string"; + this.outputType = "html"; + this.args = [ + { + "name": "Built in formats", + "type": "populateOption", + "value": DATETIME_FORMATS, + "target": 1 + }, + { + "name": "Input format string", + "type": "binaryString", + "value": "DD/MM/YYYY HH:mm:ss" + }, + { + "name": "Input timezone", + "type": "option", + "value": ["UTC"].concat(moment.tz.names()) + }, + { + "name": "Output format string", + "type": "binaryString", + "value": "dddd Do MMMM YYYY HH:mm:ss Z z" + }, + { + "name": "Output timezone", + "type": "option", + "value": ["UTC"].concat(moment.tz.names()) + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {html} + */ + run(input, args) { + const [inputFormat, inputTimezone, outputFormat, outputTimezone] = args; + let date; + + try { + date = moment.tz(input, inputFormat, inputTimezone); + if (!date || date.format() === "Invalid date") throw Error; + } catch (err) { + return "Invalid format.\n\n" + FORMAT_EXAMPLES; + } + + return date.tz(outputTimezone).format(outputFormat); + } + +} + +export default TranslateDateTimeFormat; From 61832a9e2a91f6f25d093497fded664006128a26 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Mon, 14 May 2018 18:07:17 +0000 Subject: [PATCH 4/5] ESM: whitespace tidying --- src/core/operations/AffineCipherDecode.mjs | 3 +-- src/core/operations/AffineCipherEncode.mjs | 1 + src/core/operations/BifidCipherDecode.mjs | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/operations/AffineCipherDecode.mjs b/src/core/operations/AffineCipherDecode.mjs index 3d418453..184fa67c 100644 --- a/src/core/operations/AffineCipherDecode.mjs +++ b/src/core/operations/AffineCipherDecode.mjs @@ -45,8 +45,7 @@ class AffineCipherDecode extends Operation { */ run(input, args) { const alphabet = "abcdefghijklmnopqrstuvwxyz", - a = args[0], - b = args[1], + [a, b] = args, aModInv = Utils.modInv(a, 26); // Calculates modular inverse of a let output = ""; diff --git a/src/core/operations/AffineCipherEncode.mjs b/src/core/operations/AffineCipherEncode.mjs index 939bf23a..e9aeec32 100644 --- a/src/core/operations/AffineCipherEncode.mjs +++ b/src/core/operations/AffineCipherEncode.mjs @@ -6,6 +6,7 @@ import Operation from "../Operation"; import { affineEncode } from "../lib/Ciphers"; + /** * Affine Cipher Encode operation */ diff --git a/src/core/operations/BifidCipherDecode.mjs b/src/core/operations/BifidCipherDecode.mjs index a78507e6..dbfc7628 100644 --- a/src/core/operations/BifidCipherDecode.mjs +++ b/src/core/operations/BifidCipherDecode.mjs @@ -7,6 +7,7 @@ import Operation from "../Operation"; import { genPolybiusSquare } from "../lib/Ciphers"; import OperationError from "../errors/OperationError"; + /** * Bifid Cipher Decode operation */ From a7d763287ed4b4a30bd9bd163ee7aa19f1c302ca Mon Sep 17 00:00:00 2001 From: n1474335 Date: Mon, 14 May 2018 18:23:16 +0000 Subject: [PATCH 5/5] ESM: Ported AES operations --- src/core/operations/AESDecrypt.mjs | 105 +++++++++++++++++++++++++++++ src/core/operations/AESEncrypt.mjs | 103 ++++++++++++++++++++++++++++ webpack.config.js | 4 ++ 3 files changed, 212 insertions(+) create mode 100644 src/core/operations/AESDecrypt.mjs create mode 100644 src/core/operations/AESEncrypt.mjs diff --git a/src/core/operations/AESDecrypt.mjs b/src/core/operations/AESDecrypt.mjs new file mode 100644 index 00000000..01415ddc --- /dev/null +++ b/src/core/operations/AESDecrypt.mjs @@ -0,0 +1,105 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import Utils from "../Utils"; +import forge from "node-forge/dist/forge.min.js"; + +/** + * AES Decrypt operation + */ +class AESDecrypt extends Operation { + + /** + * AESDecrypt constructor + */ + constructor() { + super(); + + this.name = "AES Decrypt"; + this.module = "Ciphers"; + this.description = "Advanced Encryption Standard (AES) is a U.S. Federal Information Processing Standard (FIPS). It was selected after a 5-year process where 15 competing designs were evaluated.

Key: The following algorithms will be used based on the size of the key:
  • 16 bytes = AES-128
  • 24 bytes = AES-192
  • 32 bytes = AES-256


IV: The Initialization Vector should be 16 bytes long. If not entered, it will default to 16 null bytes.

Padding: In CBC and ECB mode, PKCS#7 padding will be used.

GCM Tag: This field is ignored unless 'GCM' mode is used."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Key", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + }, + { + "name": "IV", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + }, + { + "name": "Mode", + "type": "option", + "value": ["CBC", "CFB", "OFB", "CTR", "GCM", "ECB"] + }, + { + "name": "Input", + "type": "option", + "value": ["Hex", "Raw"] + }, + { + "name": "Output", + "type": "option", + "value": ["Raw", "Hex"] + }, + { + "name": "GCM Tag", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const key = Utils.convertToByteArray(args[0].string, args[0].option), + iv = Utils.convertToByteArray(args[1].string, args[1].option), + mode = args[2], + inputType = args[3], + outputType = args[4], + gcmTag = Utils.convertToByteString(args[5].string, args[5].option); + + if ([16, 24, 32].indexOf(key.length) < 0) { + return `Invalid key length: ${key.length} bytes + +The following algorithms will be used based on the size of the key: + 16 bytes = AES-128 + 24 bytes = AES-192 + 32 bytes = AES-256`; + } + + input = Utils.convertToByteString(input, inputType); + + const decipher = forge.cipher.createDecipher("AES-" + mode, key); + decipher.start({ + iv: iv, + tag: gcmTag + }); + decipher.update(forge.util.createBuffer(input)); + const result = decipher.finish(); + + if (result) { + return outputType === "Hex" ? decipher.output.toHex() : decipher.output.getBytes(); + } else { + return "Unable to decrypt input with these parameters."; + } + } + +} + +export default AESDecrypt; diff --git a/src/core/operations/AESEncrypt.mjs b/src/core/operations/AESEncrypt.mjs new file mode 100644 index 00000000..62763c5f --- /dev/null +++ b/src/core/operations/AESEncrypt.mjs @@ -0,0 +1,103 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import Utils from "../Utils"; +import forge from "node-forge/dist/forge.min.js"; + +/** + * AES Encrypt operation + */ +class AESEncrypt extends Operation { + + /** + * AESEncrypt constructor + */ + constructor() { + super(); + + this.name = "AES Encrypt"; + this.module = "Ciphers"; + this.description = "Advanced Encryption Standard (AES) is a U.S. Federal Information Processing Standard (FIPS). It was selected after a 5-year process where 15 competing designs were evaluated.

Key: The following algorithms will be used based on the size of the key:
  • 16 bytes = AES-128
  • 24 bytes = AES-192
  • 32 bytes = AES-256
You can generate a password-based key using one of the KDF operations.

IV: The Initialization Vector should be 16 bytes long. If not entered, it will default to 16 null bytes.

Padding: In CBC and ECB mode, PKCS#7 padding will be used."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Key", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + }, + { + "name": "IV", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + }, + { + "name": "Mode", + "type": "option", + "value": ["CBC", "CFB", "OFB", "CTR", "GCM", "ECB"] + }, + { + "name": "Input", + "type": "option", + "value": ["Raw", "Hex"] + }, + { + "name": "Output", + "type": "option", + "value": ["Hex", "Raw"] + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const key = Utils.convertToByteArray(args[0].string, args[0].option), + iv = Utils.convertToByteArray(args[1].string, args[1].option), + mode = args[2], + inputType = args[3], + outputType = args[4]; + + if ([16, 24, 32].indexOf(key.length) < 0) { + return `Invalid key length: ${key.length} bytes + +The following algorithms will be used based on the size of the key: + 16 bytes = AES-128 + 24 bytes = AES-192 + 32 bytes = AES-256`; + } + + input = Utils.convertToByteString(input, inputType); + + const cipher = forge.cipher.createCipher("AES-" + mode, key); + cipher.start({iv: iv}); + cipher.update(forge.util.createBuffer(input)); + cipher.finish(); + + if (outputType === "Hex") { + if (mode === "GCM") { + return cipher.output.toHex() + "\n\n" + + "Tag: " + cipher.mode.tag.toHex(); + } + return cipher.output.toHex(); + } else { + if (mode === "GCM") { + return cipher.output.getBytes() + "\n\n" + + "Tag: " + cipher.mode.tag.getBytes(); + } + return cipher.output.getBytes(); + } + } + +} + +export default AESEncrypt; diff --git a/webpack.config.js b/webpack.config.js index 3f88cc78..822c8561 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -69,6 +69,10 @@ module.exports = { exclude: /node_modules\/(?!jsesc)/, loader: "babel-loader?compact=false" }, + { + test: /forge.min.js$/, + loader: "imports-loader?jQuery=>null" + }, { test: /\.css$/, use: ExtractTextPlugin.extract({