Repository: icebob/fastest-validator
Pull request #214 (2021-02-02 23:00:24)

Base64 string validation
At first, I just want to support basic base64 string validations (no padding or mime options)
I used a regex from here: https://github.com/miguelmota/is-base64/blob/master/is-base64.js


Patch:
diff --git a/README.md b/README.md
index 1cbe17d..a43cca4 100644
--- a/README.md
+++ b/README.md
@@ -44,6 +44,9 @@ $ npm run bench
 
 # Table of contents
 
+- [fastest-validator ![NPM version](https://www.npmjs.com/package/fastest-validator) [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=The%20fastest%20JS%20validator%20library%20for%20NodeJS&url=https://github.com/icebob/fastest-validator&via=Icebobcsi&hashtags=nodejs,javascript)](#fastest-validator--)
+  - [Key features](#key-features)
+- [How fast?](#how-fast)
 - [Table of contents](#table-of-contents)
   - [Installation](#installation)
     - [NPM](#npm)
@@ -52,9 +55,9 @@ $ npm run bench
     - [Browser usage](#browser-usage)
     - [Deno usage](#deno-usage)
     - [Supported frameworks](#supported-frameworks)
-- [Optional, Required & Nullable fields](#optional--required---nullable-fields)
-  * [Optional](#optional)
-  * [Nullable](#nullable)
+- [Optional, Required & Nullable fields](#optional-required--nullable-fields)
+  - [Optional](#optional)
+  - [Nullable](#nullable)
 - [Strict validation](#strict-validation)
   - [Remove additional fields](#remove-additional-fields)
 - [Multiple validators](#multiple-validators)
@@ -62,37 +65,55 @@ $ npm run bench
 - [Sanitizations](#sanitizations)
   - [Default values](#default-values)
 - [Shorthand definitions](#shorthand-definitions)
+    - [Array of X](#array-of-x)
+    - [Nested objects](#nested-objects)
 - [Alias definition](#alias-definition)
 - [Default options](#default-options)
 - [Built-in validators](#built-in-validators)
   - [`any`](#any)
   - [`array`](#array)
+    - [Properties](#properties)
   - [`boolean`](#boolean)
+    - [Properties](#properties-1)
   - [`class`](#class)
+    - [Properties](#properties-2)
   - [`currency`](#currency)
+    - [Properties](#properties-3)
   - [`date`](#date)
+    - [Properties](#properties-4)
   - [`email`](#email)
+    - [Properties](#properties-5)
   - [`enum`](#enum)
+    - [Properties](#properties-6)
   - [`equal`](#equal)
+    - [Properties](#properties-7)
   - [`forbidden`](#forbidden)
+    - [Properties](#properties-8)
   - [`function`](#function)
   - [`luhn`](#luhn)
   - [`mac`](#mac)
   - [`multi`](#multi)
   - [`number`](#number)
+    - [Properties](#properties-9)
   - [`object`](#object)
+    - [Properties](#properties-10)
   - [`string`](#string)
+    - [Properties](#properties-11)
   - [`tuple`](#tuple)
+    - [Properties](#properties-12)
   - [`url`](#url)
-  - [`objectID`](#objectID)
+    - [Properties](#properties-13)
   - [`uuid`](#uuid)
+    - [Properties](#properties-14)
+  - [`objectID`](#objectid)
+    - [Properties](#properties-15)
 - [Custom validator](#custom-validator)
   - [Custom validation for built-in rules](#custom-validation-for-built-in-rules)
 - [Custom error messages (l10n)](#custom-error-messages-l10n)
 - [Personalised Messages](#personalised-messages)
+- [Plugins](#plugins)
 - [Message types](#message-types)
   - [Message fields](#message-fields)
-- [Plugins](#plugins)
 - [Development](#development)
 - [Test](#test)
   - [Coverage report](#coverage-report)
@@ -930,6 +951,7 @@ Property | Default  | Description
 `alphadash`   | `null`   | The value must be an alphabetic string that contains dashes.
 `hex`   | `null`   | The value must be a hex string.
 `singleLine`   | `null`   | The value must be a single line string.
+`base64`   | `null`   | The value must be a base64 string.
 `trim`   | `null`   | If `true`, the value will be trimmed. _It's a sanitizer, it will change the value in the original object._
 `trimLeft`   | `null`   | If `true`, the value will be left trimmed. _It's a sanitizer, it will change the value in the original object._
 `trimRight`   | `null`   | If `true`, the value will be right trimmed. _It's a sanitizer, it will change the value in the original object._
@@ -1310,6 +1332,7 @@ Name                | Default text
 `stringAlphadash`	| The '{field}' field must be an alphadash string.
 `stringHex`	| The '{field}' field must be a hex string.
 `stringSingleLine`	| The '{field}' field must be a single line string.
+`stringBase64`	| The '{field}' field must be a base64 string.
 `number`	| The '{field}' field must be a number.
 `numberMin`	| The '{field}' field must be greater than or equal to {expected}.
 `numberMax`	| The '{field}' field must be less than or equal to {expected}.
diff --git a/index.d.ts b/index.d.ts
index cd19398..b93f63c 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -418,6 +418,11 @@ declare module "fastest-validator" {
 		 * @default false
 		 */
 		singleLine?: boolean;
+		/**
+		 * The value must be a base64 string
+		 * @default false
+		 */
+		base64?: boolean;
 		/**
 		 * if true and the type is not a String, converts with String()
 		 * @default false
diff --git a/lib/messages.js b/lib/messages.js
index becd3b0..7128085 100644
--- a/lib/messages.js
+++ b/lib/messages.js
@@ -17,6 +17,7 @@ module.exports = {
 	stringAlphadash: "The '{field}' field must be an alphadash string.",
 	stringHex: "The '{field}' field must be a hex string.",
 	stringSingleLine: "The '{field}' field must be a single line string.",
+	stringBase64: "The '{field}' field must be a base64 string.",
 
 	number: "The '{field}' field must be a number.",
 	numberMin: "The '{field}' field must be greater than or equal to {expected}.",
diff --git a/lib/rules/string.js b/lib/rules/string.js
index 127ac1d..b52e7bd 100644
--- a/lib/rules/string.js
+++ b/lib/rules/string.js
@@ -5,6 +5,7 @@ const ALPHA_PATTERN = /^[a-zA-Z]+$/;
 const ALPHANUM_PATTERN = /^[a-zA-Z0-9]+$/;
 const ALPHADASH_PATTERN = /^[a-zA-Z0-9_-]+$/;
 const HEX_PATTERN = /^[0-9a-fA-F]+$/;
+const BASE64_PATTERN = /^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
 
 /**	Signature: function(value, field, parent, errors, context)
  */
@@ -215,6 +216,15 @@ module.exports = function checkString({ schema, messages }, path, context) {
 		`);
 	}
 
+
+	if(schema.base64 === true) {
+		src.push(`
+			if(!${BASE64_PATTERN.toString()}.test(value)) {
+				${this.makeError({ type: "stringBase64",  actual: "origValue", messages })}
+			}
+		`);
+	}
+
 	src.push(`
 		return value;
 	`);


Test patch:
diff --git a/test/rules/string.spec.js b/test/rules/string.spec.js
index defaf14..eefa015 100644
--- a/test/rules/string.spec.js
+++ b/test/rules/string.spec.js
@@ -203,6 +203,17 @@ describe("Test rule: string", () => {
 		expect(check(new Date())).toEqual(true);
 	});
 
+	it("should validate base64", () => {
+		const check = v.compile({ $$root: true, type: "string", base64: true });
+		expect(check("")).toEqual(true);
+		expect(check("uuLMhh==")).toEqual(true);
+		expect(check("1342234")).toEqual([{"actual": "1342234", "field": undefined, "message": "The '' field must be a base64 string.", "type": "stringBase64"}]);
+		expect(check("dfasdfr342")).toEqual(expect.any(Array));
+		expect(check("afQ$%rfew")).toEqual(expect.any(Array));
+		expect(check("uuLMhh")).toEqual(expect.any(Array));
+		expect(check("uucLMhh==")).toEqual(expect.any(Array));
+	});
+
 	describe("Test sanitization", () => {
 
 		it("should convert & check values", () => {