mybase 1.1.41 → 1.1.43
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.
- package/package.json +1 -1
- package/ts/index.d.ts +1 -0
- package/ts/index.js +1 -0
- package/ts/index.ts +1 -0
- package/ts/models/OTPGenerator.d.ts +12 -0
- package/ts/models/OTPGenerator.js +69 -0
- package/ts/models/OTPGenerator.test.ts +42 -0
- package/ts/models/OTPGenerator.ts +44 -0
package/package.json
CHANGED
package/ts/index.d.ts
CHANGED
package/ts/index.js
CHANGED
|
@@ -46,4 +46,5 @@ __exportStar(require("./funcs/knexConnection"), exports);
|
|
|
46
46
|
__exportStar(require("./models/Unixtime"), exports);
|
|
47
47
|
__exportStar(require("./models/Timespan"), exports);
|
|
48
48
|
__exportStar(require("./models/IPAddress"), exports);
|
|
49
|
+
__exportStar(require("./models/OTPGenerator"), exports);
|
|
49
50
|
//# sourceMappingURL=index.js.map
|
package/ts/index.ts
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Timespan } from './Timespan';
|
|
2
|
+
export declare class OTPGenerator {
|
|
3
|
+
private passkey;
|
|
4
|
+
private length;
|
|
5
|
+
constructor(passkey: string, length?: number);
|
|
6
|
+
generateOTP(): string;
|
|
7
|
+
validateOTP(otp: string): boolean;
|
|
8
|
+
age(otp: string): Timespan;
|
|
9
|
+
private generateOTPWithNonce;
|
|
10
|
+
private isValid;
|
|
11
|
+
private extractNonce;
|
|
12
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.OTPGenerator = void 0;
|
|
27
|
+
const crypto = __importStar(require("crypto"));
|
|
28
|
+
const Timespan_1 = require("./Timespan");
|
|
29
|
+
class OTPGenerator {
|
|
30
|
+
constructor(passkey, length = 4) {
|
|
31
|
+
this.passkey = passkey;
|
|
32
|
+
this.length = length;
|
|
33
|
+
}
|
|
34
|
+
// Generate OTP with the current timestamp as nonce
|
|
35
|
+
generateOTP() {
|
|
36
|
+
return this.generateOTPWithNonce(Date.now());
|
|
37
|
+
}
|
|
38
|
+
// Validate if the OTP matches by extracting the nonce and regenerating OTP
|
|
39
|
+
validateOTP(otp) {
|
|
40
|
+
if (!this.isValid(otp))
|
|
41
|
+
return false; // Validate plausibility of OTP
|
|
42
|
+
const nonce = this.extractNonce(otp);
|
|
43
|
+
return otp === this.generateOTPWithNonce(nonce);
|
|
44
|
+
}
|
|
45
|
+
// Get the age of the OTP compared to now
|
|
46
|
+
age(otp) {
|
|
47
|
+
if (!this.isValid(otp))
|
|
48
|
+
throw new Error('Invalid OTP');
|
|
49
|
+
const nonce = this.extractNonce(otp);
|
|
50
|
+
return new Timespan_1.Timespan(Date.now() - nonce);
|
|
51
|
+
}
|
|
52
|
+
// Helper to generate OTP based on a specific nonce
|
|
53
|
+
generateOTPWithNonce(nonce) {
|
|
54
|
+
const hash = crypto.createHmac('sha256', this.passkey).update(nonce.toString()).digest('hex');
|
|
55
|
+
const otp = [...hash.slice(0, this.length)].map(char => String.fromCharCode((parseInt(char, 16) % 26) + 97)).join('');
|
|
56
|
+
return `${otp}${nonce.toString(16).padStart(13, '0')}`;
|
|
57
|
+
}
|
|
58
|
+
// Private helper to validate plausibility of OTP
|
|
59
|
+
isValid(otp) {
|
|
60
|
+
return otp.length === this.length + 13;
|
|
61
|
+
}
|
|
62
|
+
// Private helper to extract the nonce from the OTP
|
|
63
|
+
extractNonce(otp) {
|
|
64
|
+
const nonceHex = otp.slice(-13);
|
|
65
|
+
return parseInt(nonceHex, 16);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.OTPGenerator = OTPGenerator;
|
|
69
|
+
//# sourceMappingURL=OTPGenerator.js.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { OTPGenerator } from './OTPGenerator';
|
|
2
|
+
import { wait } from './../funcs/wait';
|
|
3
|
+
import { Timespan } from './Timespan';
|
|
4
|
+
|
|
5
|
+
const passkey = 'hiowi3rmpewr34';
|
|
6
|
+
describe('OTPGenerator', () => {
|
|
7
|
+
it('should generate OTP', () => {
|
|
8
|
+
const otpGenerator = new OTPGenerator(passkey, 5);
|
|
9
|
+
const otp = otpGenerator.generateOTP();
|
|
10
|
+
// length should be 5 + 13
|
|
11
|
+
expect(otp.length).toBe(18);
|
|
12
|
+
console.log(otp);
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('should generate different OTPs in milliseconds', async () => {
|
|
16
|
+
const otpGenerator = new OTPGenerator(passkey, 5);
|
|
17
|
+
const otp1 = otpGenerator.generateOTP()
|
|
18
|
+
await wait(1/1000);
|
|
19
|
+
const otp2 = otpGenerator.generateOTP();
|
|
20
|
+
expect(otp1).not.toBe(otp2);
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('should generate different OTPs in milliseconds per password', async () => {
|
|
24
|
+
const otpGenerator1 = new OTPGenerator(passkey+'1', 5);
|
|
25
|
+
const otpGenerator2 = new OTPGenerator(passkey+'2', 5);
|
|
26
|
+
for(let i=0; i<10000; i++) {
|
|
27
|
+
const otp1 = otpGenerator1.generateOTP()
|
|
28
|
+
const otp2 = otpGenerator2.generateOTP();
|
|
29
|
+
expect(otp1).not.toBe(otp2);
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('age should be milliseconds since generation', async () => {
|
|
34
|
+
const otpGenerator = new OTPGenerator(passkey, 5);
|
|
35
|
+
const otp = otpGenerator.generateOTP();
|
|
36
|
+
await wait(1/1000);
|
|
37
|
+
const age = otpGenerator.age(otp);
|
|
38
|
+
expect(age).toBeInstanceOf(Timespan);
|
|
39
|
+
expect(age.miliseconds).toBeGreaterThan(0);
|
|
40
|
+
expect(age.miliseconds).toBeLessThan(100);
|
|
41
|
+
})
|
|
42
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as crypto from 'crypto';
|
|
2
|
+
import { Timespan } from './Timespan';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export class OTPGenerator {
|
|
6
|
+
constructor(private passkey: string, private length: number = 4) {}
|
|
7
|
+
|
|
8
|
+
// Generate OTP with the current timestamp as nonce
|
|
9
|
+
public generateOTP(): string {
|
|
10
|
+
return this.generateOTPWithNonce(Date.now());
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Validate if the OTP matches by extracting the nonce and regenerating OTP
|
|
14
|
+
public validateOTP(otp: string): boolean {
|
|
15
|
+
if (!this.isValid(otp)) return false; // Validate plausibility of OTP
|
|
16
|
+
const nonce = this.extractNonce(otp);
|
|
17
|
+
return otp === this.generateOTPWithNonce(nonce);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Get the age of the OTP compared to now
|
|
21
|
+
public age(otp: string): Timespan {
|
|
22
|
+
if (!this.isValid(otp)) throw new Error('Invalid OTP');
|
|
23
|
+
const nonce = this.extractNonce(otp);
|
|
24
|
+
return new Timespan(Date.now() - nonce)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Helper to generate OTP based on a specific nonce
|
|
28
|
+
private generateOTPWithNonce(nonce: number): string {
|
|
29
|
+
const hash = crypto.createHmac('sha256', this.passkey).update(nonce.toString()).digest('hex');
|
|
30
|
+
const otp = [...hash.slice(0, this.length)].map(char => String.fromCharCode((parseInt(char, 16) % 26) + 97)).join('');
|
|
31
|
+
return `${otp}${nonce.toString(16).padStart(13, '0')}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Private helper to validate plausibility of OTP
|
|
35
|
+
private isValid(otp: string): boolean {
|
|
36
|
+
return otp.length === this.length + 13;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Private helper to extract the nonce from the OTP
|
|
40
|
+
private extractNonce(otp: string): number {
|
|
41
|
+
const nonceHex = otp.slice(-13);
|
|
42
|
+
return parseInt(nonceHex, 16);
|
|
43
|
+
}
|
|
44
|
+
}
|