ESM: Ported UUID, OTP, Numberwang and PHP operations

This commit is contained in:
n1474335 2018-05-21 12:35:11 +00:00
parent 739e06d7d3
commit eed28f67d5
6 changed files with 466 additions and 2 deletions

View File

@ -0,0 +1,69 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
import Operation from "../Operation";
import otp from "otp";
import ToBase32 from "./ToBase32";
/**
* Generate HOTP operation
*/
class GenerateHOTP extends Operation {
/**
* GenerateHOTP constructor
*/
constructor() {
super();
this.name = "Generate HOTP";
this.module = "Default";
this.description = "The HMAC-based One-Time Password algorithm (HOTP) is an algorithm that computes a one-time password from a shared secret key and an incrementing counter. It has been adopted as Internet Engineering Task Force standard RFC 4226, is the cornerstone of Initiative For Open Authentication (OATH), and is used in a number of two-factor authentication systems.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated.";
this.inputType = "byteArray";
this.outputType = "string";
this.args = [
{
"name": "Name",
"type": "string",
"value": ""
},
{
"name": "Key size",
"type": "number",
"value": 32
},
{
"name": "Code length",
"type": "number",
"value": 6
},
{
"name": "Counter",
"type": "number",
"value": 0
}
];
}
/**
* @param {byteArray} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const otpObj = otp({
name: args[0],
keySize: args[1],
codeLength: args[2],
secret: (new ToBase32).run(input, []),
});
const counter = args[3];
return `URI: ${otpObj.hotpURL}\n\nPassword: ${otpObj.hotp(counter)}`;
}
}
export default GenerateHOTP;

View File

@ -0,0 +1,75 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
import Operation from "../Operation";
import otp from "otp";
import ToBase32 from "./ToBase32";
/**
* Generate TOTP operation
*/
class GenerateTOTP extends Operation {
/**
* GenerateTOTP constructor
*/
constructor() {
super();
this.name = "Generate TOTP";
this.module = "Default";
this.description = "The Time-based One-Time Password algorithm (TOTP) is an algorithm that computes a one-time password from a shared secret key and the current time. It has been adopted as Internet Engineering Task Force standard RFC 6238, is the cornerstone of Initiative For Open Authentication (OATH), and is used in a number of two-factor authentication systems. A TOTP is an HOTP where the counter is the current time.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated. T0 and T1 are in seconds.";
this.inputType = "byteArray";
this.outputType = "string";
this.args = [
{
"name": "Name",
"type": "string",
"value": ""
},
{
"name": "Key size",
"type": "number",
"value": 32
},
{
"name": "Code length",
"type": "number",
"value": 6
},
{
"name": "Epoch offset (T0)",
"type": "number",
"value": 0
},
{
"name": "Interval (T1)",
"type": "number",
"value": 30
}
];
}
/**
* @param {byteArray} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const otpObj = otp({
name: args[0],
keySize: args[1],
codeLength: args[2],
secret: (new ToBase32).run(input, []),
epoch: args[3],
timeSlice: args[4]
});
return `URI: ${otpObj.totpURL}\n\nPassword: ${otpObj.totp()}`;
}
}
export default GenerateTOTP;

View File

@ -0,0 +1,49 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*/
import Operation from "../Operation";
import crypto from "crypto";
/**
* Generate UUID operation
*/
class GenerateUUID extends Operation {
/**
* GenerateUUID constructor
*/
constructor() {
super();
this.name = "Generate UUID";
this.module = "Crypto";
this.description = "Generates an RFC 4122 version 4 compliant Universally Unique Identifier (UUID), also known as a Globally Unique Identifier (GUID).<br><br>A version 4 UUID relies on random numbers, in this case generated using <code>window.crypto</code> if available and falling back to <code>Math.random</code> if not.";
this.inputType = "string";
this.outputType = "string";
this.args = [];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const buf = new Uint32Array(4).map(() => {
return crypto.randomBytes(4).readUInt32BE(0, true);
});
let i = 0;
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
const r = (buf[i >> 3] >> ((i % 8) * 4)) & 0xf,
v = c === "x" ? r : (r & 0x3 | 0x8);
i++;
return v.toString(16);
});
}
}
export default GenerateUUID;

View File

@ -0,0 +1,100 @@
/**
* @author Unknown Male 282
* @copyright Crown Copyright 2016
* @license Apache-2.0
*/
import Operation from "../Operation";
/**
* Numberwang operation. Remain indoors.
*/
class Numberwang extends Operation {
/**
* Numberwang constructor
*/
constructor() {
super();
this.name = "Numberwang";
this.module = "Default";
this.description = "Based on the popular gameshow by Mitchell and Webb.";
this.inputType = "string";
this.outputType = "string";
this.args = [];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
let output;
if (!input) {
output = "Let's play Wangernumb!";
} else {
const match = input.match(/(f0rty-s1x|shinty-six|filth-hundred and neeb|-?√?\d+(\.\d+)?i?([a-z]?)%?)/i);
if (match) {
if (match[3]) output = match[0] + "! That's AlphaNumericWang!";
else output = match[0] + "! That's Numberwang!";
} else {
// That's a bad miss!
output = "Sorry, that's not Numberwang. Let's rotate the board!";
}
}
const rand = Math.floor(Math.random() * didYouKnow.length);
return output + "\n\nDid you know: " + didYouKnow[rand];
}
}
/**
* Taken from http://numberwang.wikia.com/wiki/Numberwang_Wikia
*
* @constant
*/
const didYouKnow = [
"Numberwang, contrary to popular belief, is a fruit and not a vegetable.",
"Robert Webb once got WordWang while presenting an episode of Numberwang.",
"The 6705th digit of pi is Numberwang.",
"Numberwang was invented on a Sevenday.",
"Contrary to popular belief, Albert Einstein always got good grades in Numberwang at school. He once scored ^4$ on a test.",
"680 asteroids have been named after Numberwang.",
"Archimedes is most famous for proclaiming \"That's Numberwang!\" during an epiphany about water displacement he had while taking a bath.",
"Numberwang Day is celebrated in Japan on every day of the year apart from June 6.",
"Biologists recently discovered Numberwang within a strand of human DNA.",
"Numbernot is a special type of non-Numberwang number. It is divisible by 3 and the letter \"y\".",
"Julie once got 612.04 Numberwangs in a single episode of Emmerdale.",
"In India, it is traditional to shout out \"Numberwang!\" instead of checkmate during games of chess.",
"There is a rule on Countdown which states that if you get Numberwang in the numbers round, you automatically win. It has only ever been invoked twice.",
"\"Numberwang\" was the third-most common baby name for a brief period in 1722.",
"\"The Lion King\" was loosely based on Numberwang.",
"\"A Numberwang a day keeps the doctor away\" is how Donny Cosy, the oldest man in the world, explained how he was in such good health at the age of 136.",
"The \"number lock\" button on a keyboard is based on the popular round of the same name in \"Numberwang\".",
"Cambridge became the first university to offer a course in Numberwang in 1567.",
"Schrödinger's Numberwang is a number that has been confusing dentists for centuries.",
"\"Harry Potter and the Numberwang of Numberwang\" was rejected by publishers -41 times before it became a bestseller.",
"\"Numberwang\" is the longest-running British game show in history; it has aired 226 seasons, each containing 19 episodes, which makes a grand total of 132 episodes.",
"The triple Numberwang bonus was discovered by archaeologist Thomas Jefferson in Somerset.",
"Numberwang is illegal in parts of Czechoslovakia.",
"Numberwang was discovered in India in the 12th century.",
"Numberwang has the chemical formula Zn4SO2(HgEs)3.",
"The first pack of cards ever created featured two \"Numberwang\" cards instead of jokers.",
"Julius Caesar was killed by an overdose of Numberwang.",
"The most Numberwang musical note is G#.",
"In 1934, the forty-third Google Doodle promoted the upcoming television show \"Numberwang on Ice\".",
"A recent psychology study found that toddlers were 17% faster at identifying numbers which were Numberwang.",
"There are 700 ways to commit a foul in the television show \"Numberwang\". All 700 of these fouls were committed by Julie in one single episode in 1473.",
"Astronomers suspect God is Numberwang.",
"Numberwang is the official beverage of Canada.",
"In the pilot episode of \"The Price is Right\", if a contestant got the value of an item exactly right they were told \"That's Numberwang!\" and immediately won ₹5.7032.",
"The first person to get three Numberwangs in a row was Madonna.",
"\"Numberwang\" has the code U+46402 in Unicode.",
"The musical note \"Numberwang\" is between D# and E♮.",
"Numberwang was first played on the moon in 1834.",
];
export default Numberwang;

View File

@ -0,0 +1,171 @@
/**
* @author Jarmo van Lenthe [github.com/jarmovanlenthe]
* @copyright Jarmo van Lenthe
* @license Apache-2.0
*/
import Operation from "../Operation";
import OperationError from "../errors/OperationError";
/**
* PHP Deserialize operation
*/
class PHPDeserialize extends Operation {
/**
* PHPDeserialize constructor
*/
constructor() {
super();
this.name = "PHP Deserialize";
this.module = "Default";
this.description = "Deserializes PHP serialized data, outputting keyed arrays as JSON.<br><br>This function does not support <code>object</code> tags.<br><br>Example:<br><code>a:2:{s:1:&quot;a&quot;;i:10;i:0;a:1:{s:2:&quot;ab&quot;;b:1;}}</code><br>becomes<br><code>{&quot;a&quot;: 10,0: {&quot;ab&quot;: true}}</code><br><br><u>Output valid JSON:</u> JSON doesn't support integers as keys, whereas PHP serialization does. Enabling this will cast these integers to strings. This will also escape backslashes.";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Output valid JSON",
"type": "boolean",
"value": true
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
/**
* Recursive method for deserializing.
* @returns {*}
*/
function handleInput() {
/**
* Read `length` characters from the input, shifting them out the input.
* @param length
* @returns {string}
*/
function read(length) {
let result = "";
for (let idx = 0; idx < length; idx++) {
const char = inputPart.shift();
if (char === undefined) {
throw new OperationError("End of input reached before end of script");
}
result += char;
}
return result;
}
/**
* Read characters from the input until `until` is found.
* @param until
* @returns {string}
*/
function readUntil(until) {
let result = "";
for (;;) {
const char = read(1);
if (char === until) {
break;
} else {
result += char;
}
}
return result;
}
/**
* Read characters from the input that must be equal to `expect`
* @param expect
* @returns {string}
*/
function expect(expect) {
const result = read(expect.length);
if (result !== expect) {
throw new OperationError("Unexpected input found");
}
return result;
}
/**
* Helper function to handle deserialized arrays.
* @returns {Array}
*/
function handleArray() {
const items = parseInt(readUntil(":"), 10) * 2;
expect("{");
const result = [];
let isKey = true;
let lastItem = null;
for (let idx = 0; idx < items; idx++) {
const item = handleInput();
if (isKey) {
lastItem = item;
isKey = false;
} else {
const numberCheck = lastItem.match(/[0-9]+/);
if (args[0] && numberCheck && numberCheck[0].length === lastItem.length) {
result.push("\"" + lastItem + "\": " + item);
} else {
result.push(lastItem + ": " + item);
}
isKey = true;
}
}
expect("}");
return result;
}
const kind = read(1).toLowerCase();
switch (kind) {
case "n":
expect(";");
return "";
case "i":
case "d":
case "b": {
expect(":");
const data = readUntil(";");
if (kind === "b") {
return (parseInt(data, 10) !== 0);
}
return data;
}
case "a":
expect(":");
return "{" + handleArray() + "}";
case "s": {
expect(":");
const length = readUntil(":");
expect("\"");
const value = read(length);
expect("\";");
if (args[0]) {
return "\"" + value.replace(/"/g, "\\\"") + "\"";
} else {
return "\"" + value + "\"";
}
}
default:
throw new OperationError("Unknown type: " + kind);
}
}
const inputPart = input.split("");
return handleInput();
}
}
export default PHPDeserialize;

View File

@ -49,9 +49,9 @@ import "./tests/operations/Hexdump";
// import "./tests/operations/Image";
import "./tests/operations/MorseCode";
import "./tests/operations/MS";
// import "./tests/operations/PHP";
import "./tests/operations/PHP";
import "./tests/operations/NetBIOS";
// import "./tests/operations/OTP";
import "./tests/operations/OTP";
import "./tests/operations/PowerSet";
// import "./tests/operations/Regex";
import "./tests/operations/Rotate";