auth-verify 0.0.2 → 1.0.3
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/index.js +79 -175
- package/package.json +12 -6
- package/readme.md +213 -70
- package/src/helpers/helper.js +284 -0
- package/src/jwt/index.js +208 -0
- package/src/otp/index.js +1052 -0
- package/src/session/index.js +81 -0
- package/test.js +161 -34
- package/auth-verify.js +0 -182
- package/authverify.db +0 -0
- package/otp.db +0 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const Redis = require("ioredis");
|
|
2
|
+
const { v4: uuidv4 } = require("uuid");
|
|
3
|
+
|
|
4
|
+
class SessionManager {
|
|
5
|
+
constructor(options = {}) {
|
|
6
|
+
this.storeType = options.storeTokens || 'memory'; // 'memory' or 'redis'
|
|
7
|
+
|
|
8
|
+
if (this.storeType === 'memory') {
|
|
9
|
+
this.sessions = new Map();
|
|
10
|
+
} else if (this.storeType === 'redis') {
|
|
11
|
+
this.redis = new Redis(options.redisUrl || "redis://localhost:6379");
|
|
12
|
+
} else {
|
|
13
|
+
throw new Error("{storeTokens} should be 'memory' or 'redis'");
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Create a session
|
|
18
|
+
async create(userId, options = {}) {
|
|
19
|
+
const sessionId = uuidv4();
|
|
20
|
+
const expiresIn = options.expiresIn || 3600; // default 1 hour
|
|
21
|
+
if (typeof expiresIn === "string") {
|
|
22
|
+
const timeValue = parseInt(expiresIn);
|
|
23
|
+
if (expiresIn.endsWith("s")) expiresIn = timeValue;
|
|
24
|
+
else if (expiresIn.endsWith("m")) expiresIn = timeValue * 60;
|
|
25
|
+
else if (expiresIn.endsWith("h")) expiresIn = timeValue * 60 * 60;
|
|
26
|
+
else if (expiresIn.endsWith("d")) expiresIn = timeValue * 60 * 60 * 24;
|
|
27
|
+
else throw new Error("Invalid expiresIn format (use s, m, h, d)");
|
|
28
|
+
}
|
|
29
|
+
const now = Date.now();
|
|
30
|
+
|
|
31
|
+
const sessionData = {
|
|
32
|
+
userId,
|
|
33
|
+
createdAt: now,
|
|
34
|
+
expiresAt: now + expiresIn * 1000
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
if (this.storeType === 'memory') {
|
|
38
|
+
this.sessions.set(sessionId, sessionData);
|
|
39
|
+
} else if (this.storeType === 'redis') {
|
|
40
|
+
await this.redis.set(
|
|
41
|
+
sessionId,
|
|
42
|
+
JSON.stringify(sessionData),
|
|
43
|
+
"EX",
|
|
44
|
+
expiresIn
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return sessionId;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Verify a session
|
|
52
|
+
async verify(sessionId) {
|
|
53
|
+
let data;
|
|
54
|
+
if (this.storeType === 'memory') {
|
|
55
|
+
data = this.sessions.get(sessionId);
|
|
56
|
+
} else if (this.storeType === 'redis') {
|
|
57
|
+
const raw = await this.redis.get(sessionId);
|
|
58
|
+
data = raw ? JSON.parse(raw) : null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!data) throw new Error("Session not found or expired");
|
|
62
|
+
|
|
63
|
+
if (Date.now() > data.expiresAt) {
|
|
64
|
+
await this.destroy(sessionId);
|
|
65
|
+
throw new Error("Session expired");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return data.userId;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Destroy a session
|
|
72
|
+
async destroy(sessionId) {
|
|
73
|
+
if (this.storeType === 'memory') {
|
|
74
|
+
this.sessions.delete(sessionId);
|
|
75
|
+
} else if (this.storeType === 'redis') {
|
|
76
|
+
await this.redis.del(sessionId);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = SessionManager;
|
package/test.js
CHANGED
|
@@ -1,34 +1,161 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
1
|
+
// const AuthVerify = require('./index'); // your library entry
|
|
2
|
+
// const auth = new AuthVerify({ jwtSecret: 's', storeTokens: 'memory', otpExpiry: 300 });
|
|
3
|
+
// const TelegramBot = require("node-telegram-bot-api");
|
|
4
|
+
|
|
5
|
+
// auth.otp.setSender({
|
|
6
|
+
// via: 'telegram'
|
|
7
|
+
// });
|
|
8
|
+
|
|
9
|
+
// // callback flow (nested, but correct)
|
|
10
|
+
// // auth.otp.generate(6, (err, code) => {
|
|
11
|
+
// // if (err) return console.error('generate err', err);
|
|
12
|
+
|
|
13
|
+
// // auth.otp.set('jahongir.sobirov.2007@mail.ru', (err) => {
|
|
14
|
+
// // if (err) return console.error('set err', err);
|
|
15
|
+
// // console.log('OTP stored in memory:', auth.otp.otpCode);
|
|
16
|
+
|
|
17
|
+
// // auth.otp.message({
|
|
18
|
+
// // to: 'jahongir.sobirov.2007@mail.ru',
|
|
19
|
+
// // subject: 'Your OTP',
|
|
20
|
+
// // text: `Your OTP is ${auth.otp.otpCode}`
|
|
21
|
+
// // }, (err, info) => {
|
|
22
|
+
// // if (err) return console.error('message err', err);
|
|
23
|
+
// // console.log('message sent ok', info && info.messageId);
|
|
24
|
+
|
|
25
|
+
// // // now verify
|
|
26
|
+
// // auth.otp.verify({ check: 'jahongir.sobirov.2007@mail.ru', code: "auth.otp.otpCode" }, (err, ok) => {
|
|
27
|
+
// // if (err){
|
|
28
|
+
// // // Resend OTP
|
|
29
|
+
// // auth.otp.resend("jahongir.sobirov.2007@mail.ru", (err, info) => {
|
|
30
|
+
// // if(err) return console.log("Resend failed:", err);
|
|
31
|
+
// // console.log("New OTP sent!");
|
|
32
|
+
// // });
|
|
33
|
+
// // };
|
|
34
|
+
|
|
35
|
+
// // console.log('Verified:', ok);
|
|
36
|
+
// // });
|
|
37
|
+
// // });
|
|
38
|
+
// // });
|
|
39
|
+
// // });
|
|
40
|
+
|
|
41
|
+
// // (async () => {
|
|
42
|
+
// // // try {
|
|
43
|
+
// // // 1️⃣ Generate OTP
|
|
44
|
+
// // auth.otp.generate(5).set('+998934313977'); // or auth.otp.code
|
|
45
|
+
// // // // 2️⃣ Store OTP
|
|
46
|
+
// // // await auth.otp.set('jahongir.sobirov.2007@mail.ru');
|
|
47
|
+
// // // console.log('OTP stored in memory:', auth.otp.code);
|
|
48
|
+
|
|
49
|
+
// // // // 3️⃣ Send OTP via email
|
|
50
|
+
// // // const info = await auth.otp.message({
|
|
51
|
+
// // // to: 'jahongir.sobirov.2007@mail.ru',
|
|
52
|
+
// // // subject: 'Your OTP',
|
|
53
|
+
// // // html: `Your OTP is ${auth.otp.code}`,
|
|
54
|
+
// // // });
|
|
55
|
+
// // // console.log('Message sent OK:', info && info.messageId);
|
|
56
|
+
|
|
57
|
+
// // // // 4️⃣ Verify OTP
|
|
58
|
+
// // // try {
|
|
59
|
+
// // // const verified = await auth.otp.verify({
|
|
60
|
+
// // // check: 'jahongir.sobirov.2007@mail.ru',
|
|
61
|
+
// // // code: '123456', // user's input
|
|
62
|
+
// // // });
|
|
63
|
+
// // // console.log('Verified:', verified);
|
|
64
|
+
// // // } catch (verifyErr) {
|
|
65
|
+
// // // console.log('Verification failed:', verifyErr.message);
|
|
66
|
+
|
|
67
|
+
// // // // 5️⃣ Resend OTP if verification fails
|
|
68
|
+
// // // try {
|
|
69
|
+
// // // const newCode = await auth.otp.resend('jahongir.sobirov.2007@mail.ru');
|
|
70
|
+
// // // console.log('New OTP sent:', newCode);
|
|
71
|
+
// // // } catch (resendErr) {
|
|
72
|
+
// // // console.log('Resend failed:', resendErr.message);
|
|
73
|
+
// // // }
|
|
74
|
+
// // // }
|
|
75
|
+
// // // } catch (err) {
|
|
76
|
+
// // // console.error('Error:', err);
|
|
77
|
+
// // // }
|
|
78
|
+
// // await auth.otp.message({
|
|
79
|
+
// // to: '+998934313977',
|
|
80
|
+
// // });
|
|
81
|
+
// // console.log(`OTP was sent`);
|
|
82
|
+
// // })();
|
|
83
|
+
|
|
84
|
+
// // Set custom logger
|
|
85
|
+
// auth.setLogger(console);
|
|
86
|
+
|
|
87
|
+
// // Access developer tools
|
|
88
|
+
// auth.dev.sender(async ({to, code})=>{
|
|
89
|
+
// const token = '6657700716:AAGW3s5Yxk5SrRH7yRqrgG-kVrG9a6PXBxk';
|
|
90
|
+
// const bot = new TelegramBot(token, {polling: false});
|
|
91
|
+
// bot.onText(/\/start/, async (msg)=>{
|
|
92
|
+
// const chatId = msg.chat.id;
|
|
93
|
+
// await bot.sendMessage(chatId, `🔐 Your verification code is: <b>${code}</b>`, {parse_mode: "HTML"})
|
|
94
|
+
// console.log(`✅ OTP ${code} sent to Telegram chat ${chatId}`);
|
|
95
|
+
// });
|
|
96
|
+
// });
|
|
97
|
+
|
|
98
|
+
// (async ()=>{
|
|
99
|
+
// try{
|
|
100
|
+
|
|
101
|
+
// }catch(err){}
|
|
102
|
+
// })();
|
|
103
|
+
|
|
104
|
+
const TelegramBot = require("node-telegram-bot-api");
|
|
105
|
+
const AuthVerify = require("./index"); // your library
|
|
106
|
+
|
|
107
|
+
// // Your bot token from BotFather
|
|
108
|
+
// const BOT_TOKEN = "6657700716:AAGW3s5Yxk5SrRH7yRqrgG-kVrG9a6PXBxk";
|
|
109
|
+
|
|
110
|
+
// // Step 1: Create a Telegram bot with polling enabled (to listen to /start)
|
|
111
|
+
// const bot = new TelegramBot(BOT_TOKEN, { polling: true });
|
|
112
|
+
|
|
113
|
+
// // Step 2: Create AuthVerify instance
|
|
114
|
+
// const auth = new AuthVerify({ jwtSecret: "super_secret_key" , storeTokens: 'memory'});
|
|
115
|
+
|
|
116
|
+
// // Step 3: Setup dev sender (so OTP messages are sent through Telegram)
|
|
117
|
+
// auth.dev.sender({
|
|
118
|
+
// send: async ({ to, code }) => {
|
|
119
|
+
// await bot.sendMessage(to, `🔑 Your OTP code is: ${code}`);
|
|
120
|
+
// },
|
|
121
|
+
// });
|
|
122
|
+
|
|
123
|
+
// // Step 4: When user sends /start, bot saves their chatId and sends an OTP
|
|
124
|
+
// bot.onText(/\/start/, async (msg) => {
|
|
125
|
+
// const chatId = msg.chat.id;
|
|
126
|
+
// const username = msg.from.username || msg.from.first_name;
|
|
127
|
+
|
|
128
|
+
// await bot.sendMessage(chatId, `👋 Hello ${username}! We'll send you an OTP now.`);
|
|
129
|
+
|
|
130
|
+
// // Generate and send OTP using auth.otp
|
|
131
|
+
// const otpCode = await auth.otp.generate(chatId); // you can customize
|
|
132
|
+
// await auth.otp.send(chatId); // uses our custom sender!
|
|
133
|
+
// });
|
|
134
|
+
|
|
135
|
+
// // Step 5: Listen for OTP input
|
|
136
|
+
// bot.on("message", async (msg) => {
|
|
137
|
+
// const chatId = msg.chat.id;
|
|
138
|
+
// const text = msg.text;
|
|
139
|
+
|
|
140
|
+
// // Ignore /start
|
|
141
|
+
// if (text.startsWith("/")) return;
|
|
142
|
+
|
|
143
|
+
// // Check if entered OTP is valid
|
|
144
|
+
// const isValid = await auth.otp.verify(chatId, text);
|
|
145
|
+
// if (isValid) {
|
|
146
|
+
// bot.sendMessage(chatId, "✅ OTP verified successfully!");
|
|
147
|
+
// } else {
|
|
148
|
+
// bot.sendMessage(chatId, "❌ Invalid or expired OTP. Try again!");
|
|
149
|
+
// }
|
|
150
|
+
// });
|
|
151
|
+
|
|
152
|
+
const auth = new AuthVerify({ jwtSecret: 's', storeTokens: 'memory', otpExpiry: '5m' });
|
|
153
|
+
|
|
154
|
+
// auth.register.sender("consoleOtp", async ({ to, code }) => {
|
|
155
|
+
// console.log(`🔑 Sending OTP ${code} to ${to}`);
|
|
156
|
+
// return true;
|
|
157
|
+
// });
|
|
158
|
+
|
|
159
|
+
// (async () => {
|
|
160
|
+
// await auth.use("consoleOtp").send({ to: "+998901234567", code: "654321" });
|
|
161
|
+
// })();
|
package/auth-verify.js
DELETED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
const sqlite3 = require("sqlite3").verbose();
|
|
2
|
-
const nodemailer = require('nodemailer')
|
|
3
|
-
const crypto = require('crypto');
|
|
4
|
-
const { request } = require("http");
|
|
5
|
-
|
|
6
|
-
class Verifier {
|
|
7
|
-
constructor(sender = {}){
|
|
8
|
-
this.otpLen = sender.otp?.leng || 6;
|
|
9
|
-
this.expMin = sender.otp?.expMin || 3;
|
|
10
|
-
this.limit = sender.otp?.limit || 5;
|
|
11
|
-
this.cooldown = sender.otp?.cooldown || 60;
|
|
12
|
-
// Setup SMTP
|
|
13
|
-
this.transport = nodemailer.createTransport({
|
|
14
|
-
service: `${sender.serv}`,
|
|
15
|
-
auth: {
|
|
16
|
-
user: `${sender.sender}`,
|
|
17
|
-
pass: sender.pass
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
this.sender = `${sender.smtp?.sender}`
|
|
22
|
-
|
|
23
|
-
//making a db for saving otp codes
|
|
24
|
-
this.db = new sqlite3.Database('./authverify.db');
|
|
25
|
-
this.db.serialize(()=>{
|
|
26
|
-
// creating a table
|
|
27
|
-
this.db.run(`
|
|
28
|
-
CREATE TABLE IF NOT EXISTS verifications (
|
|
29
|
-
email TEXT PRIMARY KEY,
|
|
30
|
-
code TEXT,
|
|
31
|
-
expiresAt TEXT,
|
|
32
|
-
requests INTEGER DEFAULT 0,
|
|
33
|
-
lastRequest TEXT
|
|
34
|
-
)
|
|
35
|
-
`);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Generate OTP securely
|
|
41
|
-
generateOTP() {
|
|
42
|
-
const buffer = crypto.randomBytes(this.otpLen);
|
|
43
|
-
const number = parseInt(buffer.toString('hex'), 16)
|
|
44
|
-
.toString()
|
|
45
|
-
.slice(0, this.otpLen);
|
|
46
|
-
return number.padStart(this.otpLen, '0');
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
html(html){
|
|
50
|
-
this.htmlContent = html;
|
|
51
|
-
return this;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
subject(subject){
|
|
55
|
-
this.mailSubject = subject;
|
|
56
|
-
return this;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
text(text){
|
|
60
|
-
this.mailText = text;
|
|
61
|
-
return this;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
sendTo(email, callback){
|
|
65
|
-
|
|
66
|
-
this.recieverEmail = email;
|
|
67
|
-
const code = this.generateOTP();
|
|
68
|
-
const expAt = new Date(Date.now() + this.expMin * 60 * 1000).toISOString();
|
|
69
|
-
|
|
70
|
-
this.db.get(`SELECT * FROM verifications WHERE email = ?`, [email], (err, row)=>{
|
|
71
|
-
if(err) return callback(err);
|
|
72
|
-
|
|
73
|
-
const now = new Date();
|
|
74
|
-
let requests = 1;
|
|
75
|
-
|
|
76
|
-
if(row){
|
|
77
|
-
const lastRequest = row.lastRequest ? new Date(row.lastRequest) : null;
|
|
78
|
-
|
|
79
|
-
if(lastRequest && now.toDateString() === lastRequest.toDateString()){
|
|
80
|
-
requests = row.requests + 1;
|
|
81
|
-
if(requests > this.limit){
|
|
82
|
-
return callback(new Error("Too many OTP requests today"));
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const diff = (now - lastRequest) / 1000;
|
|
86
|
-
if(diff < this.cooldown){
|
|
87
|
-
return callback(new Error(`Please wait ${Math.ceil(this.cooldown - diff)} seconds before requesting a new OTP.`));
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
this.db.run(`INSERT INTO verifications (email, code, expiresAt, requests, lastRequest) VALUES (?, ?, ?, ?, ?)
|
|
93
|
-
ON CONFLICT(email) DO UPDATE SET
|
|
94
|
-
code = excluded.code,
|
|
95
|
-
expiresAt = excluded.expiresAt,
|
|
96
|
-
requests = excluded.requests,
|
|
97
|
-
lastRequest = excluded.lastRequest`, [email, code, expAt, requests, now.toISOString()], (DBerr)=>{
|
|
98
|
-
if(DBerr) return callback(DBerr);
|
|
99
|
-
|
|
100
|
-
this.otpOptions = {
|
|
101
|
-
from: this.sender,
|
|
102
|
-
to: `${email}`,
|
|
103
|
-
subject: this.mailSubject ? this.mailSubject.replace("{otp}", code) : undefined,
|
|
104
|
-
text: this.mailText ? this.mailText.replace("{otp}", code) : undefined,
|
|
105
|
-
html: this.htmlContent ? this.htmlContent.replace("{otp}", code) : undefined
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
this.transport.sendMail(this.otpOptions, (emailErr, info)=>{
|
|
109
|
-
if(emailErr) return callback(emailErr);
|
|
110
|
-
|
|
111
|
-
// console.log('📨 Email sent:', info.response);
|
|
112
|
-
callback(null, true);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// console.log('💾 Code saved to DB');
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
return this;
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
code(userCode){
|
|
124
|
-
this.userCode = userCode
|
|
125
|
-
return this;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
verifyFor(email, callback){
|
|
129
|
-
const now = new Date().toISOString();
|
|
130
|
-
|
|
131
|
-
this.db.get(`SELECT * FROM verifications WHERE email = ? AND expiresAt > ?`, [email, now], (DBerr, row)=>{
|
|
132
|
-
if(DBerr) return callback(DBerr);
|
|
133
|
-
|
|
134
|
-
// console.log(`Code was got`);
|
|
135
|
-
|
|
136
|
-
if(!row){
|
|
137
|
-
// console.log(this.recieverEmail);
|
|
138
|
-
callback(null, false)
|
|
139
|
-
}else{
|
|
140
|
-
if(row.code === this.userCode){
|
|
141
|
-
// console.log('✅ User verified');
|
|
142
|
-
callback(null, true);
|
|
143
|
-
}else{
|
|
144
|
-
// console.log("❌ Code isn't correct")
|
|
145
|
-
callback(null, false);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
makeOTP(length){
|
|
152
|
-
const buffer = crypto.randomBytes(length);
|
|
153
|
-
const number = parseInt(buffer.toString('hex'), 16)
|
|
154
|
-
.toString()
|
|
155
|
-
.slice(0, length);
|
|
156
|
-
return number.padStart(length, '0');
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
getOTP(email, callback){
|
|
160
|
-
this.db.get(`SELECT * FROM verifications WHERE email = ?`, [email], (err, row)=>{
|
|
161
|
-
if(err) return callback(err);
|
|
162
|
-
if(!row) return callback(null, null);
|
|
163
|
-
|
|
164
|
-
callback(null, { code: row.code, expiresAt: row.expiresAt });
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
cleanExpired() {
|
|
169
|
-
const now = new Date().toISOString();
|
|
170
|
-
this.db.run(
|
|
171
|
-
`DELETE FROM verifications WHERE expiresAt <= ?`,
|
|
172
|
-
[now],
|
|
173
|
-
function(err) {
|
|
174
|
-
if (err) console.error("Error cleaning expired OTPs:", err.message);
|
|
175
|
-
// Optional: console.log(`${this.changes} expired OTPs removed`);
|
|
176
|
-
}
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
module.exports = Verifier;
|
package/authverify.db
DELETED
|
Binary file
|
package/otp.db
DELETED
|
Binary file
|