Browse Source

Tidied up QR code operations

n1474335 6 years ago
parent
commit
9734b78aeb

+ 6 - 0
CHANGELOG.md

@@ -2,6 +2,9 @@
 All major and minor version changes will be documented in this file. Details of patch-level version changes can be found in [commit messages](https://github.com/gchq/CyberChef/commits/master).
 
 
+### [8.17.0] - 2018-12-25
+- 'Generate QR Code' and 'Parse QR Code' operations added [@j433866] | [#448]
+
 ### [8.16.0] - 2018-12-19
 - 'Play Media' operation added [@anthony-arnold] | [#446]
 
@@ -79,6 +82,7 @@ All major and minor version changes will be documented in this file. Details of
 
 
 
+[8.17.0]: https://github.com/gchq/CyberChef/releases/tag/v8.17.0
 [8.16.0]: https://github.com/gchq/CyberChef/releases/tag/v8.16.0
 [8.15.0]: https://github.com/gchq/CyberChef/releases/tag/v8.15.0
 [8.14.0]: https://github.com/gchq/CyberChef/releases/tag/v8.14.0
@@ -103,6 +107,7 @@ All major and minor version changes will be documented in this file. Details of
 
 [@n1474335]: https://github.com/n1474335
 [@d98762625]: https://github.com/d98762625
+[@j433866]: https://github.com/j433866
 [@GCHQ77703]: https://github.com/GCHQ77703
 [@artemisbot]: https://github.com/artemisbot
 [@picapi]: https://github.com/picapi
@@ -144,3 +149,4 @@ All major and minor version changes will be documented in this file. Details of
 [#441]: https://github.com/gchq/CyberChef/pull/441
 [#443]: https://github.com/gchq/CyberChef/pull/443
 [#446]: https://github.com/gchq/CyberChef/pull/446
+[#448]: https://github.com/gchq/CyberChef/pull/448

File diff suppressed because it is too large
+ 473 - 56
package-lock.json


+ 39 - 24
src/core/operations/GenerateQRCode.mjs

@@ -9,6 +9,7 @@ import OperationError from "../errors/OperationError";
 import qr from "qr-image";
 import { toBase64 } from "../lib/Base64";
 import Magic from "../lib/Magic";
+import Utils from "../Utils";
 
 /**
  * Generate QR Code operation
@@ -23,7 +24,7 @@ class GenerateQRCode extends Operation {
 
         this.name = "Generate QR Code";
         this.module = "Image";
-        this.description = "Generates a QR code from text.";
+        this.description = "Generates a Quick Response (QR) code from the input text.<br><br>A QR code is a type of matrix barcode (or two-dimensional barcode) first designed in 1994 for the automotive industry in Japan. A barcode is a machine-readable optical label that contains information about the item to which it is attached.";
         this.infoURL = "https://wikipedia.org/wiki/QR_code";
         this.inputType = "string";
         this.outputType = "byteArray";
@@ -32,17 +33,23 @@ class GenerateQRCode extends Operation {
             {
                 "name": "Image Format",
                 "type": "option",
-                "value": ["PNG", "SVG"]
+                "value": ["PNG", "SVG", "EPS", "PDF"]
             },
             {
-                "name": "Size of QR module",
+                "name": "Module size (px)",
                 "type": "number",
                 "value": 5
             },
             {
-                "name": "Margin",
+                "name": "Margin (num modules)",
                 "type": "number",
                 "value": 2
+            },
+            {
+                "name": "Error correction",
+                "type": "option",
+                "value": ["Low", "Medium", "Quartile", "High"],
+                "defaultIndex": 1
             }
         ];
     }
@@ -50,28 +57,39 @@ class GenerateQRCode extends Operation {
     /**
      * @param {string} input
      * @param {Object[]} args
-     * @returns {File}
+     * @returns {byteArray}
      */
     run(input, args) {
+        const [format, size, margin, errorCorrection] = args;
+
         // Create new QR image from the input data, and convert it to a buffer
-        const [format, size, margin] = args;
-        const qrImage = qr.imageSync(input, { type: format, size: size, margin: margin });
+        const qrImage = qr.imageSync(input, {
+            type: format,
+            size: size,
+            margin: margin,
+            "ec_level": errorCorrection.charAt(0).toUpperCase()
+        });
+
         if (qrImage == null) {
             throw new OperationError("Error generating QR code.");
         }
-        if (format === "SVG") {
-            return [...Buffer.from(qrImage)];
-        } else if (format === "PNG") {
-            // Return the QR image buffer as a byte array
-            return [...qrImage];
-        } else {
-            throw new OperationError("Error generating QR code.");
+
+        switch (format) {
+            case "SVG":
+            case "EPS":
+            case "PDF":
+                return [...Buffer.from(qrImage)];
+            case "PNG":
+                // Return the QR image buffer as a byte array
+                return [...qrImage];
+            default:
+                throw new OperationError("Unsupported QR code format.");
         }
     }
 
     /**
      * Displays the QR image using HTML for web apps
-     * 
+     *
      * @param {byteArray} data
      * @returns {html}
      */
@@ -79,24 +97,21 @@ class GenerateQRCode extends Operation {
         if (!data.length) return "";
 
         const [format] = args;
-        if (format === "SVG") {
-            let outputData = "";
-            for (let i = 0; i < data.length; i++){
-                outputData += String.fromCharCode(parseInt(data[i]));
-            }
-            return outputData;
-        } else {
+
+        if (format === "PNG") {
             let dataURI = "data:";
             const type = Magic.magicFileType(data);
             if (type && type.mime.indexOf("image") === 0){
                 dataURI += type.mime + ";";
             } else {
-                throw new OperationError("Invalid file type");
+                throw new OperationError("Invalid PNG file generated by QR image");
             }
             dataURI += "base64," + toBase64(data);
 
-            return "<img src='" + dataURI + "'>";
+            return `<img src="${dataURI}">`;
         }
+
+        return Utils.byteArrayToChars(data);
     }
 
 }

+ 20 - 18
src/core/operations/ParseQRCode.mjs

@@ -23,7 +23,7 @@ class ParseQRCode extends Operation {
 
         this.name = "Parse QR Code";
         this.module = "Image";
-        this.description = "Reads an image file and attempts to detect and read a QR code from the image.<br><br><u>Normalise Image</u><br>Attempt to normalise the image before parsing it, to try and improve detection of a QR code.";
+        this.description = "Reads an image file and attempts to detect and read a Quick Response (QR) code from the image.<br><br><u>Normalise Image</u><br>Attempts to normalise the image before parsing it to improve detection of a QR code.";
         this.infoURL = "https://wikipedia.org/wiki/QR_code";
         this.inputType = "byteArray";
         this.outputType = "string";
@@ -31,7 +31,7 @@ class ParseQRCode extends Operation {
             {
                 "name": "Normalise image",
                 "type": "boolean",
-                "value": true
+                "value": false
             }
         ];
     }
@@ -44,17 +44,19 @@ class ParseQRCode extends Operation {
     async run(input, args) {
         const type = Magic.magicFileType(input);
         const [normalise] = args;
+
         // Make sure that the input is an image
-        if (type && type.mime.indexOf("image") === 0){
-            let normalisedImage = null;
-            if (normalise){
+        if (type && type.mime.indexOf("image") === 0) {
+            let image = input;
+
+            if (normalise) {
                 // Process the image to be easier to read by jsqr
                 // Disables the alpha channel
                 // Sets the image default background to white
                 // Normalises the image colours
                 // Makes the image greyscale
-                // Converts image to a JPEG 
-                normalisedImage = await new Promise((resolve, reject) => {
+                // Converts image to a JPEG
+                image = await new Promise((resolve, reject) => {
                     jimp.read(Buffer.from(input))
                         .then(image => {
                             image
@@ -63,38 +65,38 @@ class ParseQRCode extends Operation {
                                 .normalize()
                                 .greyscale()
                                 .getBuffer(jimp.MIME_JPEG, (error, result) => {
-                                    resolve([...result]);
+                                    resolve(result);
                                 });
                         })
                         .catch(err => {
                             reject(new OperationError("Error reading the image file."));
                         });
                 });
-            } else {
-                normalisedImage = input;
             }
-            if (normalisedImage instanceof OperationError){
-                return normalisedImage;
+
+            if (image instanceof OperationError) {
+                throw image;
             }
+
             return new Promise((resolve, reject) => {
-                jimp.read(Buffer.from(normalisedImage))
+                jimp.read(Buffer.from(image))
                     .then(image => {
-                        if (image.bitmap != null){
+                        if (image.bitmap != null) {
                             const qrData = jsqr(image.bitmap.data, image.getWidth(), image.getHeight());
-                            if (qrData != null){
+                            if (qrData != null) {
                                 resolve(qrData.data);
                             } else {
                                 reject(new OperationError("Couldn't read a QR code from the image."));
                             }
                         } else {
-                            reject(new OperationError("Error reading the normalised image file."));
+                            reject(new OperationError("Error reading the image file."));
                         }
                     })
                     .catch(err => {
-                        reject(new OperationError("Error reading the normalised image file."));
+                        reject(new OperationError("Error reading the image file."));
                     });
             });
-        }  else {
+        } else {
             throw new OperationError("Invalid file type.");
         }
 

+ 6 - 6
test/tests/operations/ParseQRCode.mjs

@@ -1,6 +1,6 @@
-/** 
+/**
  * Parse QR Code tests
- * 
+ *
  * @author j433866 [j433866@gmail.com]
  * @copyright Crown Copyright 2018
  * @license Apache-2.0
@@ -15,7 +15,7 @@ TestRegister.addTests([
         recipeConfig: [
             {
                 "op": "From Hex",
-                "args": ["Space"]
+                "args": ["None"]
             },
             {
                 "op": "Parse QR Code",
@@ -34,7 +34,7 @@ TestRegister.addTests([
             },
             {
                 "op": "Parse QR Code",
-                "args": [true]
+                "args": [false]
             },
         ],
     },
@@ -45,7 +45,7 @@ TestRegister.addTests([
         recipeConfig: [
             {
                 "op": "From Hex",
-                "args": ["Space"]
+                "args": ["None"]
             },
             {
                 "op": "Parse QR Code",
@@ -60,7 +60,7 @@ TestRegister.addTests([
         recipeConfig: [
             {
                 "op": "From Hex",
-                "args": ["Space"]
+                "args": ["None"]
             },
             {
                 "op": "Parse QR Code",

Some files were not shown because too many files changed in this diff