@mhmdhammoud/meritt-utils 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,43 @@
1
+ name: NPM Publish on Release
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ jobs:
7
+ build:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v3
11
+ - uses: actions/setup-node@v3
12
+ with:
13
+ node-version: 16
14
+ - run: npm ci
15
+
16
+ publish-npm:
17
+ needs: build
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v3
21
+ - uses: actions/setup-node@v3
22
+ with:
23
+ node-version: 16
24
+ registry-url: https://registry.npmjs.org/
25
+ - run: npm ci
26
+ - run: npm publish
27
+ env:
28
+ NODE_AUTH_TOKEN: ${{secrets.npm_token}}
29
+ notify:
30
+ needs: [publish-npm]
31
+ runs-on: ubuntu-latest
32
+ steps:
33
+ - name: Notify by Email
34
+ uses: dawidd6/action-send-mail@v2
35
+ with:
36
+ server_address: ${{ secrets.EMAIL_HOST }}
37
+ server_port: 465
38
+ username: ${{ secrets.EMAIL_USERNAME }}
39
+ password: ${{ secrets.EMAIL_PASSWORD }}
40
+ subject: ${{ github.event.head_commit.message }} ${{ github.job }} job of ${{ github.repository }} has ${{ job.status }}
41
+ body: ${{ github.job }} job in worflow ${{ github.workflow }} of ${{ github.repository }} has ${{ job.status }}
42
+ to: mohammad.hammoud.lb@hotmail.com,steef12009@gmail.com,sawwas.omar@gmail.com
43
+ from: Github Action
@@ -0,0 +1,29 @@
1
+ name: Changes
2
+ on:
3
+ push:
4
+ branches: [dev]
5
+ jobs:
6
+ type-check:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v3
10
+ - uses: actions/setup-node@v3
11
+ with:
12
+ node-version: 16
13
+ - run: npm ci
14
+ - run: npm run types
15
+ notify:
16
+ needs: [type-check]
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - name: Notify by Email
20
+ uses: dawidd6/action-send-mail@v2
21
+ with:
22
+ server_address: ${{ secrets.EMAIL_HOST }}
23
+ server_port: 465
24
+ username: ${{ secrets.EMAIL_USERNAME }}
25
+ password: ${{ secrets.EMAIL_PASSWORD }}
26
+ subject: ${{ github.event.head_commit.message }} ${{ github.job }} job of ${{ github.repository }} has ${{ job.status }}
27
+ body: ${{ github.job }} job in worflow ${{ github.workflow }} of ${{ github.repository }} has ${{ job.status }}
28
+ to: mohammad.hammoud.lb@hotmail.com,steef12009@gmail.com,sawwas.omar@gmail.com
29
+ from: Github Action
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env sh
2
+ . "$(dirname -- "$0")/_/husky.sh"
3
+
4
+ red='\033[0;31m'
5
+ green='\033[0;32m'
6
+ yellow='\033[0;33m'
7
+ blue='\033[0;34m'
8
+ magenta='\033[0;35m'
9
+ cyan='\033[0;36m'
10
+ clear='\033[0m'
11
+ echo "
12
+
13
+ __ __ ______ _____ _____ _______ _______ _____ ________ __
14
+ | \/ | ____| __ \|_ _|__ __|__ __| | __ \| ____\ \ / /
15
+ | \ / | |__ | |__) | | | | | | | | | | | |__ \ \ / /
16
+ | |\/| | __| | _ / | | | | | | | | | | __| \ \/ /
17
+ | | | | |____| | \ \ _| |_ | | | | | |__| | |____ \ /
18
+ |_| |_|______|_| \_\_____| |_| |_| |_____/|______| \/
19
+
20
+
21
+ "
22
+ echo -e "Let's hope you are not ${red}DUMB${clear}!"
23
+
24
+ echo -ne '\n'
25
+
26
+ echo -e "${yellow}Or Are You ??${clear}!"
27
+ echo -ne '\n'
28
+ echo -e "${yellow}Running pre-commit hook...${clear}"
29
+ echo -ne '\n'
30
+ echo -ne '\n'
31
+
32
+ echo -ne '##################### (25%)\r'
33
+ sleep 0.3
34
+ echo -ne '############################## (35%)\r'
35
+ sleep 0.3
36
+ echo -ne '###################################### (45%)\r'
37
+ sleep 0.3
38
+ echo -ne '############################################################ (77%)\r'
39
+ sleep 0.3
40
+ echo -ne '################################################################## (100%)\r'
41
+
42
+ echo -ne '\n'
43
+ echo -ne '\n'
44
+ echo -ne '\n'
45
+
46
+ echo -e "${yellow}Running types...${clear}"
47
+ echo -ne '\n'
48
+ npm run types
49
+ echo -ne '\n'
50
+
51
+ echo -e "${green}types passed...${clear} ✅"
52
+ echo -ne '\n'
53
+ echo -e "${yellow}Running linting...${clear}"
54
+
55
+ npm run lint
56
+ echo -e "${green}linting passed...${clear} ✅"
57
+
58
+ echo -ne '\n'
59
+
60
+ echo -e "${yellow}Seems like you are a${clear} ${green}CLEVER DEVELOPER${clear} 👌"
61
+ echo -ne '\n'
62
+ echo -e "${green}GOOD TO GO${clear} 🚀🚀🚀"
package/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  This is a collection of utility functions that are often used in Meritt projects.
4
4
 
5
+ ## Actions
6
+
7
+ [![Changes](https://github.com/Mhmdhammoud/meritt-utils/actions/workflows/push.yml/badge.svg)](https://github.com/Mhmdhammoud/meritt-utils/actions/workflows/push.yml) [![NPM Publish on Release](https://github.com/Mhmdhammoud/meritt-utils/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/Mhmdhammoud/meritt-utils/actions/workflows/npm-publish.yml)
8
+
5
9
  ## Installation
6
10
 
7
11
  For npm:
@@ -19,9 +23,13 @@ yarn add @mhmdhammoud/meritt-utils
19
23
  ## Usage
20
24
 
21
25
  ```typescript
22
- import {Crypto} from '@mhmdhammoud/meritt-utils'
26
+ // Import the classes you need
27
+ import {Crypto, Formatter} from '@mhmdhammoud/meritt-utils'
28
+
29
+ // Example of creating a product slug
30
+ const slug = Formatter.slugify('My Product Name') // my-product-name
31
+
32
+ // Example of encrypting and decrypting a string
23
33
 
24
- // Example of getting all Crypto methods
25
- const encryptedMessage = Crypto.encrypt('Hello World', 7)
26
- const decryptedMessage = Crypto.decrypt(encryptedMessage, 7)
34
+ const encryptedMessage = Crypto.encrypt('Hello World', 7) // [23,235,141,414]
27
35
  ```
@@ -0,0 +1,59 @@
1
+ # Changes
2
+
3
+ ## Version 1.0.4
4
+
5
+ ### Added
6
+
7
+ - Added generateKeys method that returns public and private keys
8
+
9
+ ```typescript
10
+ import {Crypto} from '@mhmdhammoud/meritt-utils'
11
+
12
+ // Example of generating a public and a private key
13
+ const response = Crypto.generateKeys()
14
+ console.log(response)
15
+
16
+ {
17
+ publicKey:7,
18
+ privateKey:247,
19
+ }
20
+
21
+
22
+ ```
23
+
24
+ ### Fixes and Improvements
25
+
26
+ - Checking for prime numbers discarding even and odd numbers and skips 6 iterations at a time until radical I
27
+
28
+ ## Version 1.0.3
29
+
30
+ ### Added
31
+
32
+ - Added Formatter class for manipulating strings
33
+
34
+ ```typescript
35
+ import {Formatter} from '@mhmdhammoud/meritt-utils'
36
+
37
+ // Example of creating a product slug
38
+ const slug = Formatter.slugify('My Product Name') // my-product-name
39
+ ```
40
+
41
+ ### Fixes and Improvements
42
+
43
+ - Fixed bug in Crypto class where encrypting a string with a key that is not a number would throw an error
44
+
45
+ - Improved Crypto class to allow encrypting and decrypting numbers and objects
46
+
47
+ - Documented Crypto class
48
+
49
+ ## Version 1.0.2
50
+
51
+ - Added Crypto class that contains encrypt and decrypt methods for strings, numbers, and objects using a public and private key
52
+
53
+ ```typescript
54
+ import {Crypto} from '@mhmdhammoud/meritt-utils'
55
+
56
+ // Example of encrypting and decrypting a string
57
+ const encryptedMessage = Crypto.encrypt('Hello World', 7) // [23,235,141,414]
58
+ const decryptedMessage = Crypto.decrypt(encryptedMessage, 247) // Hello World
59
+ ```
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export { Crypto } from './lib';
2
+ export { Formatter } from './lib';
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Crypto = void 0;
3
+ exports.Formatter = exports.Crypto = void 0;
4
4
  var lib_1 = require("./lib");
5
5
  Object.defineProperty(exports, "Crypto", { enumerable: true, get: function () { return lib_1.Crypto; } });
6
+ var lib_2 = require("./lib");
7
+ Object.defineProperty(exports, "Formatter", { enumerable: true, get: function () { return lib_2.Formatter; } });
@@ -1,19 +1,22 @@
1
- /**
2
- * The Crypto class
3
- * @class Crypto
4
- * @example
5
- * ```typescript
6
- * import crypto from './lib/crypto'
7
- * ```
8
- * */
9
1
  declare class Crypto {
10
2
  private _primeNumberP;
11
3
  private _primeNumberQ;
4
+ private _phiN;
12
5
  private _moduloDenominator;
6
+ /**
7
+ *
8
+ * @param number - The number to check if prime
9
+ * @returns The boolean answer of prime checking operation
10
+ * @example
11
+ * ```typescript
12
+ * this._isPrime(5)
13
+ * ```
14
+ * */
15
+ private _isPrime;
13
16
  /**
14
17
  * Set the P prime number for the RSA algorithm
15
- * @param {string} primeP - The prime number P
16
- * @memberof Crypto
18
+ * @param primeP - The prime number P of type string
19
+ * @returns void
17
20
  * @example
18
21
  * ```typescript
19
22
  * crypto.setPrimeP(17)
@@ -22,8 +25,8 @@ declare class Crypto {
22
25
  setPrimeP(primeP: number): void;
23
26
  /**
24
27
  * Set the Q prime number for the RSA algorithm
25
- * @param {string} primeQ - The prime number Q
26
- * @memberof Crypto
28
+ * @param primeQ - The prime number Q of type string
29
+ * @returns void
27
30
  * @example
28
31
  * ```typescript
29
32
  * crypto.setPrimeQ(19)
@@ -32,31 +35,61 @@ declare class Crypto {
32
35
  setPrimeQ(primeQ: number): void;
33
36
  /**
34
37
  *
35
- * @param {string} base - The base number
36
- * @param {string} exponent - The exponent number
37
- * @memberof Crypto
38
+ * @param base - The base number of type number
39
+ * @param exponent - The exponent number of type number
40
+ * @returns The modular exponentiation of the base and the exponent
38
41
  * @example
39
42
  * ```typescript
40
43
  * this.modularExponentiation(2, 3)
41
44
  * ```
42
45
  * */
43
46
  private _modularExponentiation;
47
+ /**
48
+ *
49
+ * @param temporaryVarriableOne - The number one
50
+ * @param temporaryVarriableTwo- The number two (phi n)
51
+ * @returns The boolean answer of relatively prime checking operation with phi n
52
+ * @example
53
+ * ```typescript
54
+ * this._areRelativelyPrime(5,9)
55
+ * ```
56
+ * */
57
+ private _areRelativelyPrime;
58
+ /**
59
+ *
60
+ * @returns The public and private key number which is a random number generated to match conditions set by RSA algorithm
61
+ * @example
62
+ * ```typescript
63
+ * crypto.generateKeys()
64
+ * ```
65
+ * */
66
+ generateKeys: () => Record<'publicKey' | 'privateKey', number>;
67
+ /**
68
+ *
69
+ * @param publicKey - The public key number
70
+ * @returns The private key number which is the modulus inverse with repect to modulo denominator
71
+ * @example
72
+ * ```typescript
73
+ * crypto.generatePrivateKey(5)
74
+ * ```
75
+ * */
76
+ private _generatePrivateKey;
44
77
  /**
45
78
  * Encrypt the message using the public key
46
- * @param {string} message - The message to encrypt
47
- * @param {string} publicKey - The public key
48
- * @memberof Crypto
79
+ * @param message - The message to encrypt of type string|number|Record
80
+ * @param publicKey - The public key to encrypt the message with of type number
81
+ * @returns The encrypted message of type number[]
49
82
  * @example
50
83
  * ```typescript
51
84
  * crypto.encrypt('Hello World', 7)
52
85
  * ```
53
86
  * */
54
- encrypt: (message: string, publicKey: number) => number[];
87
+ encrypt: (message: string | number | Record<any, any>, publicKey: number) => number[];
55
88
  /**
56
89
  * Decrypt the message using the private key
57
- * @param {string} encryptedMessage - The ciphertext to decrypt
58
- * @param {string} privateKey - The private key
59
- * @memberof Crypto
90
+ * @param encryptedMessage - The encryptedMessage to decrypt of type number[]
91
+ * @param privateKey - The private key to decrypt the message with of type number
92
+ * @returns The decrypted message of type string
60
93
  * @example
61
94
  * ```typescript
62
95
  * crypto.decrypt([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100], 23)
package/dist/lib/cypto.js CHANGED
@@ -1,30 +1,58 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- /**
4
- * The Crypto class
5
- * @class Crypto
6
- * @example
7
- * ```typescript
8
- * import crypto from './lib/crypto'
9
- * ```
10
- * */
3
+ /*
4
+ Author : Omar Sawwas
5
+ Date : 2023-06-17
6
+ Description : RSA algorithm
7
+ Version : 1.0
8
+ */
11
9
  class Crypto {
12
10
  constructor() {
13
11
  // Default variables
14
12
  this._primeNumberP = 17;
15
13
  this._primeNumberQ = 19;
14
+ this._phiN = (this._primeNumberP - 1) * (this._primeNumberQ - 1);
16
15
  this._moduloDenominator = this._primeNumberP * this._primeNumberQ;
17
16
  /**
18
17
  *
19
- * @param {string} base - The base number
20
- * @param {string} exponent - The exponent number
21
- * @memberof Crypto
18
+ * @param number - The number to check if prime
19
+ * @returns The boolean answer of prime checking operation
20
+ * @example
21
+ * ```typescript
22
+ * this._isPrime(5)
23
+ * ```
24
+ * */
25
+ this._isPrime = (number) => {
26
+ if (number <= 1) {
27
+ return false;
28
+ }
29
+ if (number <= 3) {
30
+ return true;
31
+ }
32
+ if (number % 2 === 0 || number % 3 === 0) {
33
+ return false;
34
+ }
35
+ for (let i = 5; i * i <= number; i += 6) {
36
+ if (number % i === 0 || number % (i + 2) === 0) {
37
+ return false;
38
+ }
39
+ }
40
+ return true;
41
+ };
42
+ /**
43
+ *
44
+ * @param base - The base number of type number
45
+ * @param exponent - The exponent number of type number
46
+ * @returns The modular exponentiation of the base and the exponent
22
47
  * @example
23
48
  * ```typescript
24
49
  * this.modularExponentiation(2, 3)
25
50
  * ```
26
51
  * */
27
52
  this._modularExponentiation = (base, exponent) => {
53
+ if (isNaN(base) || isNaN(exponent)) {
54
+ throw new Error('Provide a valid number');
55
+ }
28
56
  if (this._moduloDenominator === 1) {
29
57
  return 0;
30
58
  }
@@ -39,35 +67,144 @@ class Crypto {
39
67
  }
40
68
  return result;
41
69
  };
70
+ /**
71
+ *
72
+ * @param temporaryVarriableOne - The number one
73
+ * @param temporaryVarriableTwo- The number two (phi n)
74
+ * @returns The boolean answer of relatively prime checking operation with phi n
75
+ * @example
76
+ * ```typescript
77
+ * this._areRelativelyPrime(5,9)
78
+ * ```
79
+ * */
80
+ this._areRelativelyPrime = (temporaryVarriableOne, temporaryVarriableTwo) => {
81
+ while (temporaryVarriableTwo !== 0) {
82
+ const temp = temporaryVarriableTwo;
83
+ temporaryVarriableTwo = temporaryVarriableOne % temporaryVarriableTwo;
84
+ temporaryVarriableOne = temp;
85
+ }
86
+ return temporaryVarriableOne === 1;
87
+ };
88
+ /**
89
+ *
90
+ * @returns The public and private key number which is a random number generated to match conditions set by RSA algorithm
91
+ * @example
92
+ * ```typescript
93
+ * crypto.generateKeys()
94
+ * ```
95
+ * */
96
+ this.generateKeys = () => {
97
+ const temporaryArray = [];
98
+ for (let i = 2; i < this._phiN; i++) {
99
+ if (this._areRelativelyPrime(i, this._phiN)) {
100
+ temporaryArray.push(i);
101
+ }
102
+ }
103
+ if (temporaryArray.length === 0)
104
+ throw new Error('No public key options found!');
105
+ const randomIndex = Math.floor(Math.random() * temporaryArray.length);
106
+ // return temporaryArray[randomIndex]
107
+ const publicKey = temporaryArray[randomIndex];
108
+ const privateKey = this._generatePrivateKey(publicKey);
109
+ if (privateKey === publicKey) {
110
+ return this.generateKeys();
111
+ }
112
+ return {
113
+ privateKey: publicKey,
114
+ publicKey: privateKey,
115
+ };
116
+ };
117
+ /**
118
+ *
119
+ * @param publicKey - The public key number
120
+ * @returns The private key number which is the modulus inverse with repect to modulo denominator
121
+ * @example
122
+ * ```typescript
123
+ * crypto.generatePrivateKey(5)
124
+ * ```
125
+ * */
126
+ this._generatePrivateKey = (publicKey) => {
127
+ if (publicKey <= 1 || isNaN(publicKey)) {
128
+ throw new Error('Public key should be a number greater than 1');
129
+ }
130
+ if (!this._areRelativelyPrime(publicKey, this._phiN)) {
131
+ throw new Error('Public key should be relatively prime with respect to phi N');
132
+ }
133
+ let t1 = 0;
134
+ let t2 = 1;
135
+ let r1 = this._phiN;
136
+ let r2 = publicKey;
137
+ while (r2 !== 0) {
138
+ const quotient = Math.floor(r1 / r2);
139
+ const temp1 = t1;
140
+ const temp2 = r1;
141
+ t1 = t2;
142
+ r1 = r2;
143
+ t2 = temp1 - quotient * t2;
144
+ r2 = temp2 - quotient * r2;
145
+ }
146
+ if (r1 > 1) {
147
+ throw new Error('The number does not have a modular inverse.');
148
+ }
149
+ if (t1 < 0) {
150
+ t1 += this._phiN;
151
+ }
152
+ return t1;
153
+ };
42
154
  /**
43
155
  * Encrypt the message using the public key
44
- * @param {string} message - The message to encrypt
45
- * @param {string} publicKey - The public key
46
- * @memberof Crypto
156
+ * @param message - The message to encrypt of type string|number|Record
157
+ * @param publicKey - The public key to encrypt the message with of type number
158
+ * @returns The encrypted message of type number[]
47
159
  * @example
48
160
  * ```typescript
49
161
  * crypto.encrypt('Hello World', 7)
50
162
  * ```
51
163
  * */
52
164
  this.encrypt = (message, publicKey) => {
53
- const b = [];
165
+ if (isNaN(publicKey)) {
166
+ throw new Error('Public key should be a number');
167
+ }
168
+ if (publicKey <= 0) {
169
+ throw new Error('Private key should be a positive number different than 0');
170
+ }
171
+ if (typeof message === 'number') {
172
+ message = message.toString();
173
+ }
174
+ if (typeof message === 'object') {
175
+ message = JSON.stringify(message);
176
+ }
177
+ const encryptedMessage = [];
54
178
  for (let i = 0; i < message.length; i++) {
55
179
  const a = message.charCodeAt(i);
56
- b.push(this._modularExponentiation(a, publicKey));
180
+ encryptedMessage.push(this._modularExponentiation(a, publicKey));
57
181
  }
58
- return b;
182
+ return encryptedMessage;
59
183
  };
60
184
  /**
61
185
  * Decrypt the message using the private key
62
- * @param {string} encryptedMessage - The ciphertext to decrypt
63
- * @param {string} privateKey - The private key
64
- * @memberof Crypto
186
+ * @param encryptedMessage - The encryptedMessage to decrypt of type number[]
187
+ * @param privateKey - The private key to decrypt the message with of type number
188
+ * @returns The decrypted message of type string
65
189
  * @example
66
190
  * ```typescript
67
191
  * crypto.decrypt([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100], 23)
68
192
  * ```
69
193
  * */
70
194
  this.decrypt = (encryptedMessage, privateKey) => {
195
+ if (isNaN(privateKey)) {
196
+ throw new Error('Public key should be a number');
197
+ }
198
+ if (privateKey <= 0) {
199
+ throw new Error('Private key should be a positive number different than 0');
200
+ }
201
+ if (!Array.isArray(encryptedMessage)) {
202
+ throw new Error('Encrypted message should be an array');
203
+ }
204
+ const allValidNumbers = encryptedMessage.every((number) => !isNaN(number));
205
+ if (!allValidNumbers) {
206
+ throw new Error('Encrypted message should be an array of numbers');
207
+ }
71
208
  const decryptedAsciiMessage = [];
72
209
  for (let i = 0; i < encryptedMessage.length; i++) {
73
210
  const a = encryptedMessage[i];
@@ -82,44 +219,36 @@ class Crypto {
82
219
  }
83
220
  /**
84
221
  * Set the P prime number for the RSA algorithm
85
- * @param {string} primeP - The prime number P
86
- * @memberof Crypto
222
+ * @param primeP - The prime number P of type string
223
+ * @returns void
87
224
  * @example
88
225
  * ```typescript
89
226
  * crypto.setPrimeP(17)
90
227
  * ```
91
228
  * */
92
229
  setPrimeP(primeP) {
93
- let isPrime = true;
94
- for (let i = 2; i < primeP; i++) {
95
- if (primeP % i === 0) {
96
- isPrime = false;
97
- break;
98
- }
230
+ if (isNaN(primeP) || primeP === 0) {
231
+ throw new Error('Provide a valid number');
99
232
  }
100
- if (!isPrime) {
233
+ if (!this._isPrime(primeP)) {
101
234
  throw new Error('The number is not prime');
102
235
  }
103
236
  this._primeNumberP = primeP;
104
237
  }
105
238
  /**
106
239
  * Set the Q prime number for the RSA algorithm
107
- * @param {string} primeQ - The prime number Q
108
- * @memberof Crypto
240
+ * @param primeQ - The prime number Q of type string
241
+ * @returns void
109
242
  * @example
110
243
  * ```typescript
111
244
  * crypto.setPrimeQ(19)
112
245
  * ```
113
246
  * */
114
247
  setPrimeQ(primeQ) {
115
- let isPrime = true;
116
- for (let i = 2; i < primeQ; i++) {
117
- if (primeQ % i === 0) {
118
- isPrime = false;
119
- break;
120
- }
248
+ if (isNaN(primeQ) || primeQ === 0) {
249
+ throw new Error('Provide a valid number');
121
250
  }
122
- if (!isPrime) {
251
+ if (!this._isPrime(primeQ)) {
123
252
  throw new Error('The number is not prime');
124
253
  }
125
254
  this._primeNumberQ = primeQ;
@@ -0,0 +1,43 @@
1
+ declare class Formatter {
2
+ /**
3
+ * @remarks Normalizes input by removing underscores and hyphens and capitalizing the first letter of the sentence.
4
+ * @param stringToBeChanged - to be formatted without underscores and hyphens
5
+ * @param withWhiteSpacing - Determines if white spacing is needed in the final string or not (default: true)
6
+ * @returns string
7
+ * @example
8
+ * ```typescript
9
+ * formatter.toUpperFirst('hello world')
10
+ * // => 'Hello-World'
11
+ * ```
12
+ * */
13
+ toUpperFirst: (_: string | number, withSpacing?: boolean) => string;
14
+ /**
15
+ * @remarks normalizes input to supported path and file name format.
16
+ * Changes camelCase strings to kebab-case, replaces spaces with dash and keeps underscores. *
17
+ * @param str - String needed to be modified
18
+ * @returns formatted string
19
+ */
20
+ camelToKebab: (str: string) => string;
21
+ /**
22
+ * @remarks obfuscates email address
23
+ * @param email - email address to be obfuscated
24
+ * @returns obfuscated email address
25
+ * @example
26
+ * ```typescript
27
+ * formatter.obfuscate('johndoe@email.com') // => jo*****@gmail.com
28
+ * ```
29
+ * */
30
+ obfuscate: (email: string) => string;
31
+ /**
32
+ * @remarks Generates a slug from a given string
33
+ * @param title - string to be converted to slug
34
+ * @returns slug
35
+ * @example
36
+ * ```typescript
37
+ * formatter.slugify('Hello World') // => hello-world
38
+ * ```
39
+ * */
40
+ slugify: (title: string) => string;
41
+ }
42
+ declare const formatter: Formatter;
43
+ export default formatter;
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /*
4
+ Author : Mhmd Hammoud
5
+ Date : 2023-06-17
6
+ Description : String manipulation
7
+ Version : 1.0
8
+ */
9
+ class Formatter {
10
+ constructor() {
11
+ /**
12
+ * @remarks Normalizes input by removing underscores and hyphens and capitalizing the first letter of the sentence.
13
+ * @param stringToBeChanged - to be formatted without underscores and hyphens
14
+ * @param withWhiteSpacing - Determines if white spacing is needed in the final string or not (default: true)
15
+ * @returns string
16
+ * @example
17
+ * ```typescript
18
+ * formatter.toUpperFirst('hello world')
19
+ * // => 'Hello-World'
20
+ * ```
21
+ * */
22
+ this.toUpperFirst = (_, withSpacing = true) => {
23
+ if (typeof _ !== 'string')
24
+ throw new Error('Provide a valid string');
25
+ if (withSpacing) {
26
+ return _.split(' ')
27
+ .map((val) => val.charAt(0).toUpperCase() + val.slice(1))
28
+ .join(' ')
29
+ .replace(/ /g, '-')
30
+ .replace(/\//g, '-')
31
+ .replace(/\./g, '');
32
+ }
33
+ else {
34
+ return _.split(' ')
35
+ .map((val) => val.charAt(0).toUpperCase() + val.slice(1))
36
+ .join(' ')
37
+ .replace(/\//g, '-')
38
+ .replace(/\./g, '');
39
+ }
40
+ };
41
+ /**
42
+ * @remarks normalizes input to supported path and file name format.
43
+ * Changes camelCase strings to kebab-case, replaces spaces with dash and keeps underscores. *
44
+ * @param str - String needed to be modified
45
+ * @returns formatted string
46
+ */
47
+ this.camelToKebab = (str) => {
48
+ const STRING_DASHERIZE_REGEXP = /\s/g;
49
+ const STRING_DECAMELIZE_REGEXP = /([a-z\d])([A-Z])/g;
50
+ return str
51
+ .replace(STRING_DECAMELIZE_REGEXP, '$1-$2')
52
+ .toLowerCase()
53
+ .replace(STRING_DASHERIZE_REGEXP, '-');
54
+ };
55
+ /**
56
+ * @remarks obfuscates email address
57
+ * @param email - email address to be obfuscated
58
+ * @returns obfuscated email address
59
+ * @example
60
+ * ```typescript
61
+ * formatter.obfuscate('johndoe@email.com') // => jo*****@gmail.com
62
+ * ```
63
+ * */
64
+ this.obfuscate = (email) => {
65
+ if (typeof email !== 'string')
66
+ throw new Error('Provide a valid string');
67
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
68
+ if (!emailRegex.test(email))
69
+ throw new Error('Provide a valid email address');
70
+ const separatorIndex = email.indexOf('@');
71
+ if (separatorIndex < 3) {
72
+ // 'ab@gmail.com' -> '**@gmail.com'
73
+ return (email.slice(0, separatorIndex).replace(/./g, '*') +
74
+ email.slice(separatorIndex));
75
+ }
76
+ // 'test42@gmail.com' -> 'te****@gmail.com'
77
+ return (email.slice(0, 2) +
78
+ email.slice(2, separatorIndex).replace(/./g, '*') +
79
+ email.slice(separatorIndex));
80
+ };
81
+ /**
82
+ * @remarks Generates a slug from a given string
83
+ * @param title - string to be converted to slug
84
+ * @returns slug
85
+ * @example
86
+ * ```typescript
87
+ * formatter.slugify('Hello World') // => hello-world
88
+ * ```
89
+ * */
90
+ this.slugify = (title) => {
91
+ if (typeof title !== 'string')
92
+ throw new Error('Provide a valid string');
93
+ return title
94
+ .replace(/ /g, '-')
95
+ .replace(/%/g, '-')
96
+ .replace(/#/g, '-')
97
+ .replace(/\?/g, '-')
98
+ .replace(/,/g, '-')
99
+ .replace(/\//g, '-')
100
+ .replace(/\\/g, '-')
101
+ .replace(/\./g, '')
102
+ .replace(/'/g, '')
103
+ .replace(/"/g, '')
104
+ .replace(/\+/g, '-')
105
+ .replace(/\*/g, '-')
106
+ .replace(/\^/g, '-')
107
+ .replace(/@/g, '-')
108
+ .replace(/;/g, '-')
109
+ .replace(/:/g, '-')
110
+ .replace(/!/g, '-')
111
+ .replace(/&/g, '-')
112
+ .replace(/\$/g, '-')
113
+ .replace(/\(/g, '-')
114
+ .replace(/\)/g, '-')
115
+ .trim()
116
+ .toLowerCase();
117
+ };
118
+ }
119
+ }
120
+ const formatter = new Formatter();
121
+ exports.default = formatter;
@@ -1 +1,2 @@
1
1
  export { default as Crypto } from './cypto';
2
+ export { default as Formatter } from './formatter';
package/dist/lib/index.js CHANGED
@@ -3,6 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Crypto = void 0;
6
+ exports.Formatter = exports.Crypto = void 0;
7
7
  var cypto_1 = require("./cypto");
8
8
  Object.defineProperty(exports, "Crypto", { enumerable: true, get: function () { return __importDefault(cypto_1).default; } });
9
+ var formatter_1 = require("./formatter");
10
+ Object.defineProperty(exports, "Formatter", { enumerable: true, get: function () { return __importDefault(formatter_1).default; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhmdhammoud/meritt-utils",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "private": false,
@@ -19,7 +19,7 @@
19
19
  "types": "tsc --noemit",
20
20
  "prepare": "husky install",
21
21
  "lint": "eslint src --fix",
22
- "prepublish": "yarn build"
22
+ "prepublish": "npm run build"
23
23
  },
24
24
  "dependencies": {
25
25
  "dotenv": "^10.0.0"
package/src/index.ts CHANGED
@@ -1 +1,2 @@
1
1
  export {Crypto} from './lib'
2
+ export {Formatter} from './lib'
package/src/lib/cypto.ts CHANGED
@@ -1,35 +1,64 @@
1
- /**
2
- * The Crypto class
3
- * @class Crypto
4
- * @example
5
- * ```typescript
6
- * import crypto from './lib/crypto'
7
- * ```
8
- * */
1
+ /*
2
+ Author : Omar Sawwas
3
+ Date : 2023-06-17
4
+ Description : RSA algorithm
5
+ Version : 1.0
6
+ */
9
7
  class Crypto {
10
8
  // Default variables
11
9
  private _primeNumberP = 17
12
10
  private _primeNumberQ = 19
11
+ private _phiN = (this._primeNumberP - 1) * (this._primeNumberQ - 1)
13
12
  private _moduloDenominator = this._primeNumberP * this._primeNumberQ
14
13
 
14
+ /**
15
+ *
16
+ * @param number - The number to check if prime
17
+ * @returns The boolean answer of prime checking operation
18
+ * @example
19
+ * ```typescript
20
+ * this._isPrime(5)
21
+ * ```
22
+ * */
23
+
24
+ private _isPrime = (number: number): boolean => {
25
+ if (number <= 1) {
26
+ return false
27
+ }
28
+
29
+ if (number <= 3) {
30
+ return true
31
+ }
32
+
33
+ if (number % 2 === 0 || number % 3 === 0) {
34
+ return false
35
+ }
36
+
37
+ for (let i = 5; i * i <= number; i += 6) {
38
+ if (number % i === 0 || number % (i + 2) === 0) {
39
+ return false
40
+ }
41
+ }
42
+
43
+ return true
44
+ }
45
+
15
46
  /**
16
47
  * Set the P prime number for the RSA algorithm
17
- * @param {string} primeP - The prime number P
18
- * @memberof Crypto
48
+ * @param primeP - The prime number P of type string
49
+ * @returns void
19
50
  * @example
20
51
  * ```typescript
21
52
  * crypto.setPrimeP(17)
22
53
  * ```
23
54
  * */
55
+
24
56
  public setPrimeP(primeP: number) {
25
- let isPrime = true
26
- for (let i = 2; i < primeP; i++) {
27
- if (primeP % i === 0) {
28
- isPrime = false
29
- break
30
- }
57
+ if (isNaN(primeP) || primeP === 0) {
58
+ throw new Error('Provide a valid number')
31
59
  }
32
- if (!isPrime) {
60
+
61
+ if (!this._isPrime(primeP)) {
33
62
  throw new Error('The number is not prime')
34
63
  }
35
64
  this._primeNumberP = primeP
@@ -37,22 +66,19 @@ class Crypto {
37
66
 
38
67
  /**
39
68
  * Set the Q prime number for the RSA algorithm
40
- * @param {string} primeQ - The prime number Q
41
- * @memberof Crypto
69
+ * @param primeQ - The prime number Q of type string
70
+ * @returns void
42
71
  * @example
43
72
  * ```typescript
44
73
  * crypto.setPrimeQ(19)
45
74
  * ```
46
75
  * */
76
+
47
77
  public setPrimeQ(primeQ: number) {
48
- let isPrime = true
49
- for (let i = 2; i < primeQ; i++) {
50
- if (primeQ % i === 0) {
51
- isPrime = false
52
- break
53
- }
78
+ if (isNaN(primeQ) || primeQ === 0) {
79
+ throw new Error('Provide a valid number')
54
80
  }
55
- if (!isPrime) {
81
+ if (!this._isPrime(primeQ)) {
56
82
  throw new Error('The number is not prime')
57
83
  }
58
84
  this._primeNumberQ = primeQ
@@ -60,15 +86,19 @@ class Crypto {
60
86
 
61
87
  /**
62
88
  *
63
- * @param {string} base - The base number
64
- * @param {string} exponent - The exponent number
65
- * @memberof Crypto
89
+ * @param base - The base number of type number
90
+ * @param exponent - The exponent number of type number
91
+ * @returns The modular exponentiation of the base and the exponent
66
92
  * @example
67
93
  * ```typescript
68
94
  * this.modularExponentiation(2, 3)
69
95
  * ```
70
96
  * */
97
+
71
98
  private _modularExponentiation = (base: number, exponent: number) => {
99
+ if (isNaN(base) || isNaN(exponent)) {
100
+ throw new Error('Provide a valid number')
101
+ }
72
102
  if (this._moduloDenominator === 1) {
73
103
  return 0
74
104
  }
@@ -84,36 +114,172 @@ class Crypto {
84
114
  return result
85
115
  }
86
116
 
117
+ /**
118
+ *
119
+ * @param temporaryVarriableOne - The number one
120
+ * @param temporaryVarriableTwo- The number two (phi n)
121
+ * @returns The boolean answer of relatively prime checking operation with phi n
122
+ * @example
123
+ * ```typescript
124
+ * this._areRelativelyPrime(5,9)
125
+ * ```
126
+ * */
127
+
128
+ private _areRelativelyPrime = (
129
+ temporaryVarriableOne: number,
130
+ temporaryVarriableTwo: number
131
+ ) => {
132
+ while (temporaryVarriableTwo !== 0) {
133
+ const temp = temporaryVarriableTwo
134
+ temporaryVarriableTwo = temporaryVarriableOne % temporaryVarriableTwo
135
+ temporaryVarriableOne = temp
136
+ }
137
+ return temporaryVarriableOne === 1
138
+ }
139
+
140
+ /**
141
+ *
142
+ * @returns The public and private key number which is a random number generated to match conditions set by RSA algorithm
143
+ * @example
144
+ * ```typescript
145
+ * crypto.generateKeys()
146
+ * ```
147
+ * */
148
+
149
+ public generateKeys = (): Record<'publicKey' | 'privateKey', number> => {
150
+ const temporaryArray: number[] = []
151
+ for (let i = 2; i < this._phiN; i++) {
152
+ if (this._areRelativelyPrime(i, this._phiN)) {
153
+ temporaryArray.push(i)
154
+ }
155
+ }
156
+ if (temporaryArray.length === 0)
157
+ throw new Error('No public key options found!')
158
+ const randomIndex = Math.floor(Math.random() * temporaryArray.length)
159
+ // return temporaryArray[randomIndex]
160
+ const publicKey = temporaryArray[randomIndex]
161
+ const privateKey = this._generatePrivateKey(publicKey)
162
+ if (privateKey === publicKey) {
163
+ return this.generateKeys()
164
+ }
165
+ return {
166
+ privateKey: publicKey,
167
+ publicKey: privateKey,
168
+ }
169
+ }
170
+
171
+ /**
172
+ *
173
+ * @param publicKey - The public key number
174
+ * @returns The private key number which is the modulus inverse with repect to modulo denominator
175
+ * @example
176
+ * ```typescript
177
+ * crypto.generatePrivateKey(5)
178
+ * ```
179
+ * */
180
+
181
+ private _generatePrivateKey = (publicKey: number): number => {
182
+ if (publicKey <= 1 || isNaN(publicKey)) {
183
+ throw new Error('Public key should be a number greater than 1')
184
+ }
185
+
186
+ if (!this._areRelativelyPrime(publicKey, this._phiN)) {
187
+ throw new Error(
188
+ 'Public key should be relatively prime with respect to phi N'
189
+ )
190
+ }
191
+
192
+ let t1 = 0
193
+ let t2 = 1
194
+ let r1 = this._phiN
195
+ let r2 = publicKey
196
+
197
+ while (r2 !== 0) {
198
+ const quotient = Math.floor(r1 / r2)
199
+ const temp1 = t1
200
+ const temp2 = r1
201
+
202
+ t1 = t2
203
+ r1 = r2
204
+
205
+ t2 = temp1 - quotient * t2
206
+ r2 = temp2 - quotient * r2
207
+ }
208
+
209
+ if (r1 > 1) {
210
+ throw new Error('The number does not have a modular inverse.')
211
+ }
212
+
213
+ if (t1 < 0) {
214
+ t1 += this._phiN
215
+ }
216
+
217
+ return t1
218
+ }
219
+
87
220
  /**
88
221
  * Encrypt the message using the public key
89
- * @param {string} message - The message to encrypt
90
- * @param {string} publicKey - The public key
91
- * @memberof Crypto
222
+ * @param message - The message to encrypt of type string|number|Record
223
+ * @param publicKey - The public key to encrypt the message with of type number
224
+ * @returns The encrypted message of type number[]
92
225
  * @example
93
226
  * ```typescript
94
227
  * crypto.encrypt('Hello World', 7)
95
228
  * ```
96
229
  * */
97
- public encrypt = (message: string, publicKey: number): number[] => {
98
- const b: number[] = []
230
+
231
+ public encrypt = (
232
+ message: string | number | Record<any, any>,
233
+ publicKey: number
234
+ ): number[] => {
235
+ if (isNaN(publicKey)) {
236
+ throw new Error('Public key should be a number')
237
+ }
238
+ if (publicKey <= 0) {
239
+ throw new Error(
240
+ 'Private key should be a positive number different than 0'
241
+ )
242
+ }
243
+ if (typeof message === 'number') {
244
+ message = message.toString()
245
+ }
246
+ if (typeof message === 'object') {
247
+ message = JSON.stringify(message)
248
+ }
249
+ const encryptedMessage: number[] = []
99
250
  for (let i = 0; i < message.length; i++) {
100
251
  const a = message.charCodeAt(i)
101
- b.push(this._modularExponentiation(a, publicKey))
252
+ encryptedMessage.push(this._modularExponentiation(a, publicKey))
102
253
  }
103
- return b
254
+ return encryptedMessage
104
255
  }
105
256
 
106
257
  /**
107
258
  * Decrypt the message using the private key
108
- * @param {string} encryptedMessage - The ciphertext to decrypt
109
- * @param {string} privateKey - The private key
110
- * @memberof Crypto
259
+ * @param encryptedMessage - The encryptedMessage to decrypt of type number[]
260
+ * @param privateKey - The private key to decrypt the message with of type number
261
+ * @returns The decrypted message of type string
111
262
  * @example
112
263
  * ```typescript
113
264
  * crypto.decrypt([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100], 23)
114
265
  * ```
115
266
  * */
116
267
  public decrypt = (encryptedMessage: number[], privateKey: number): string => {
268
+ if (isNaN(privateKey)) {
269
+ throw new Error('Public key should be a number')
270
+ }
271
+ if (privateKey <= 0) {
272
+ throw new Error(
273
+ 'Private key should be a positive number different than 0'
274
+ )
275
+ }
276
+ if (!Array.isArray(encryptedMessage)) {
277
+ throw new Error('Encrypted message should be an array')
278
+ }
279
+ const allValidNumbers = encryptedMessage.every((number) => !isNaN(number))
280
+ if (!allValidNumbers) {
281
+ throw new Error('Encrypted message should be an array of numbers')
282
+ }
117
283
  const decryptedAsciiMessage: number[] = []
118
284
  for (let i = 0; i < encryptedMessage.length; i++) {
119
285
  const a = encryptedMessage[i]
@@ -0,0 +1,121 @@
1
+ /*
2
+ Author : Mhmd Hammoud
3
+ Date : 2023-06-17
4
+ Description : String manipulation
5
+ Version : 1.0
6
+ */
7
+ class Formatter {
8
+ /**
9
+ * @remarks Normalizes input by removing underscores and hyphens and capitalizing the first letter of the sentence.
10
+ * @param stringToBeChanged - to be formatted without underscores and hyphens
11
+ * @param withWhiteSpacing - Determines if white spacing is needed in the final string or not (default: true)
12
+ * @returns string
13
+ * @example
14
+ * ```typescript
15
+ * formatter.toUpperFirst('hello world')
16
+ * // => 'Hello-World'
17
+ * ```
18
+ * */
19
+ toUpperFirst = (_: string | number, withSpacing = true) => {
20
+ if (typeof _ !== 'string') throw new Error('Provide a valid string')
21
+ if (withSpacing) {
22
+ return _.split(' ')
23
+ .map((val: string) => val.charAt(0).toUpperCase() + val.slice(1))
24
+ .join(' ')
25
+ .replace(/ /g, '-')
26
+ .replace(/\//g, '-')
27
+ .replace(/\./g, '')
28
+ } else {
29
+ return _.split(' ')
30
+ .map((val: string) => val.charAt(0).toUpperCase() + val.slice(1))
31
+ .join(' ')
32
+ .replace(/\//g, '-')
33
+ .replace(/\./g, '')
34
+ }
35
+ }
36
+
37
+ /**
38
+ * @remarks normalizes input to supported path and file name format.
39
+ * Changes camelCase strings to kebab-case, replaces spaces with dash and keeps underscores. *
40
+ * @param str - String needed to be modified
41
+ * @returns formatted string
42
+ */
43
+ camelToKebab = (str: string) => {
44
+ const STRING_DASHERIZE_REGEXP = /\s/g
45
+ const STRING_DECAMELIZE_REGEXP = /([a-z\d])([A-Z])/g
46
+ return str
47
+ .replace(STRING_DECAMELIZE_REGEXP, '$1-$2')
48
+ .toLowerCase()
49
+ .replace(STRING_DASHERIZE_REGEXP, '-')
50
+ }
51
+
52
+ /**
53
+ * @remarks obfuscates email address
54
+ * @param email - email address to be obfuscated
55
+ * @returns obfuscated email address
56
+ * @example
57
+ * ```typescript
58
+ * formatter.obfuscate('johndoe@email.com') // => jo*****@gmail.com
59
+ * ```
60
+ * */
61
+ obfuscate = (email: string) => {
62
+ if (typeof email !== 'string') throw new Error('Provide a valid string')
63
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
64
+ if (!emailRegex.test(email))
65
+ throw new Error('Provide a valid email address')
66
+ const separatorIndex = email.indexOf('@')
67
+ if (separatorIndex < 3) {
68
+ // 'ab@gmail.com' -> '**@gmail.com'
69
+ return (
70
+ email.slice(0, separatorIndex).replace(/./g, '*') +
71
+ email.slice(separatorIndex)
72
+ )
73
+ }
74
+ // 'test42@gmail.com' -> 'te****@gmail.com'
75
+ return (
76
+ email.slice(0, 2) +
77
+ email.slice(2, separatorIndex).replace(/./g, '*') +
78
+ email.slice(separatorIndex)
79
+ )
80
+ }
81
+
82
+ /**
83
+ * @remarks Generates a slug from a given string
84
+ * @param title - string to be converted to slug
85
+ * @returns slug
86
+ * @example
87
+ * ```typescript
88
+ * formatter.slugify('Hello World') // => hello-world
89
+ * ```
90
+ * */
91
+ slugify = (title: string) => {
92
+ if (typeof title !== 'string') throw new Error('Provide a valid string')
93
+ return title
94
+ .replace(/ /g, '-')
95
+ .replace(/%/g, '-')
96
+ .replace(/#/g, '-')
97
+ .replace(/\?/g, '-')
98
+ .replace(/,/g, '-')
99
+ .replace(/\//g, '-')
100
+ .replace(/\\/g, '-')
101
+ .replace(/\./g, '')
102
+ .replace(/'/g, '')
103
+ .replace(/"/g, '')
104
+ .replace(/\+/g, '-')
105
+ .replace(/\*/g, '-')
106
+ .replace(/\^/g, '-')
107
+ .replace(/@/g, '-')
108
+ .replace(/;/g, '-')
109
+ .replace(/:/g, '-')
110
+ .replace(/!/g, '-')
111
+ .replace(/&/g, '-')
112
+ .replace(/\$/g, '-')
113
+ .replace(/\(/g, '-')
114
+ .replace(/\)/g, '-')
115
+ .trim()
116
+ .toLowerCase()
117
+ }
118
+ }
119
+
120
+ const formatter = new Formatter()
121
+ export default formatter
package/src/lib/index.ts CHANGED
@@ -1 +1,2 @@
1
1
  export {default as Crypto} from './cypto'
2
+ export {default as Formatter} from './formatter'