auth-verify 0.0.2 → 1.1.0
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 +10 -4
- package/readme.md +247 -70
- package/src/helpers/helper.js +284 -0
- package/src/jwt/cookie/index.js +29 -0
- package/src/jwt/index.js +392 -0
- package/src/otp/index.js +1052 -0
- package/src/session/index.js +81 -0
- package/test.js +178 -31
- package/auth-verify.js +0 -182
- package/authverify.db +0 -0
- package/otp.db +0 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
const crypto = require('crypto');
|
|
2
|
+
const nodemailer = require("nodemailer");
|
|
3
|
+
const axios = require('axios');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Convert time strings like "1h", "30m", "10s" to milliseconds
|
|
7
|
+
*/
|
|
8
|
+
function parseTime(str) {
|
|
9
|
+
if (typeof str === 'number') return str; // already ms
|
|
10
|
+
if (typeof str !== 'string') return 0;
|
|
11
|
+
|
|
12
|
+
const num = parseInt(str);
|
|
13
|
+
if (str.endsWith('h')) return num * 60 * 60 * 1000;
|
|
14
|
+
if (str.endsWith('m')) return num * 60 * 1000;
|
|
15
|
+
if (str.endsWith('s')) return num * 1000;
|
|
16
|
+
return num;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Generate a random numeric OTP of given length
|
|
21
|
+
*/
|
|
22
|
+
function generateSecureOTP(length = 6, hash = 'sha256') {
|
|
23
|
+
// Create random bytes
|
|
24
|
+
const randomBytes = crypto.randomBytes(32);
|
|
25
|
+
// Hash the bytes
|
|
26
|
+
const hashed = crypto.createHash(hash).update(randomBytes).digest('hex');
|
|
27
|
+
|
|
28
|
+
// Convert to numeric OTP
|
|
29
|
+
let otp = '';
|
|
30
|
+
for (let i = 0; i < hashed.length && otp.length < length; i++) {
|
|
31
|
+
const char = hashed[i];
|
|
32
|
+
if (!isNaN(char)) otp += char;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// If not enough digits, recursively generate more
|
|
36
|
+
if (otp.length < length) return generateSecureOTP(length, hash);
|
|
37
|
+
return otp.slice(0, length);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function otpSendingProcessByEmail({senderService, senderEmail, senderPass, senderHost, senderPort, senderSecure, receiverEmail, senderText, senderSubject, senderHtml}){
|
|
41
|
+
if(senderService == 'gmail'){
|
|
42
|
+
const transporter = nodemailer.createTransport({
|
|
43
|
+
service: senderService,
|
|
44
|
+
auth: {
|
|
45
|
+
user: senderEmail,
|
|
46
|
+
pass: senderPass, // not your normal password
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if(senderText && !senderHtml){
|
|
51
|
+
transporter.sendMail({
|
|
52
|
+
from: senderEmail,
|
|
53
|
+
to: receiverEmail,
|
|
54
|
+
subject: senderSubject,
|
|
55
|
+
text: senderText,
|
|
56
|
+
// html: senderHtml
|
|
57
|
+
}, (err, info) => {
|
|
58
|
+
if (err) return console.error("❌ Failed:", err);
|
|
59
|
+
// console.log("✅ Email sent:", info.response);
|
|
60
|
+
});
|
|
61
|
+
}else if (senderHtml && !senderText){
|
|
62
|
+
transporter.sendMail({
|
|
63
|
+
from: senderEmail,
|
|
64
|
+
to: receiverEmail,
|
|
65
|
+
subject: senderSubject,
|
|
66
|
+
// text: senderText,
|
|
67
|
+
html: senderHtml
|
|
68
|
+
}, (err, info) => {
|
|
69
|
+
if (err) return console.error("❌ Failed:", err);
|
|
70
|
+
// console.log("✅ Email sent:", info.response);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}else{
|
|
74
|
+
const transporter = nodemailer.createTransport({
|
|
75
|
+
host: senderHost,
|
|
76
|
+
port: senderPort,
|
|
77
|
+
secure: senderSecure, // true for 465, false for others
|
|
78
|
+
auth: {
|
|
79
|
+
user: senderEmail,
|
|
80
|
+
pass: senderPass,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
if(senderText && !senderHtml){
|
|
85
|
+
transporter.sendMail({
|
|
86
|
+
from: senderEmail,
|
|
87
|
+
to: receiverEmail,
|
|
88
|
+
subject: senderSubject,
|
|
89
|
+
text: senderText,
|
|
90
|
+
// html: senderHtml
|
|
91
|
+
}, (err, info) => {
|
|
92
|
+
if (err) return console.error("❌ Failed:", err);
|
|
93
|
+
// console.log("✅ Email sent:", info.response);
|
|
94
|
+
});
|
|
95
|
+
}else if (senderHtml && !senderText){
|
|
96
|
+
transporter.sendMail({
|
|
97
|
+
from: senderEmail,
|
|
98
|
+
to: receiverEmail,
|
|
99
|
+
subject: senderSubject,
|
|
100
|
+
// text: senderText,
|
|
101
|
+
html: senderHtml
|
|
102
|
+
}, (err, info) => {
|
|
103
|
+
if (err) return console.error("❌ Failed:", err);
|
|
104
|
+
// console.log("✅ Email sent:", info.response);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function resendGeneratedOTP({from, to, pass, service, host, secure, port, subject, text, html, code}, callbackData){
|
|
111
|
+
if(callbackData && typeof callbackData == 'function'){
|
|
112
|
+
// const code = generateSecureOTP(data.code.length, this.hashAlgorithm);
|
|
113
|
+
let transporter;
|
|
114
|
+
if (service === 'gmail') {
|
|
115
|
+
transporter = nodemailer.createTransport({
|
|
116
|
+
service: 'gmail',
|
|
117
|
+
auth: { user: from, pass }
|
|
118
|
+
});
|
|
119
|
+
} else if (service === 'smtp') {
|
|
120
|
+
transporter = nodemailer.createTransport({
|
|
121
|
+
host,
|
|
122
|
+
port,
|
|
123
|
+
secure: !!secure,
|
|
124
|
+
auth: { user: from, pass }
|
|
125
|
+
});
|
|
126
|
+
} else {
|
|
127
|
+
throw new Error(`Unsupported email service: ${service}`);
|
|
128
|
+
}
|
|
129
|
+
// prepare mail
|
|
130
|
+
const mail = {
|
|
131
|
+
from,
|
|
132
|
+
to,
|
|
133
|
+
subject: subject || 'Your OTP Code',
|
|
134
|
+
text: text || `Your OTP is ${code}`,
|
|
135
|
+
html: html || `<p>Your OTP is <b>${code}</b></p>`
|
|
136
|
+
};
|
|
137
|
+
transporter.sendMail(mail, (err, info)=>{
|
|
138
|
+
if(err) return callbackData(new Error(err));
|
|
139
|
+
callbackData(null, info);
|
|
140
|
+
});
|
|
141
|
+
}else{
|
|
142
|
+
try{
|
|
143
|
+
let transporter;
|
|
144
|
+
if (service === 'gmail') {
|
|
145
|
+
transporter = nodemailer.createTransport({
|
|
146
|
+
service: 'gmail',
|
|
147
|
+
auth: { user: from, pass }
|
|
148
|
+
});
|
|
149
|
+
} else if (service === 'smtp') {
|
|
150
|
+
transporter = nodemailer.createTransport({
|
|
151
|
+
host,
|
|
152
|
+
port,
|
|
153
|
+
secure: !!secure,
|
|
154
|
+
auth: { user: from, pass: pass }
|
|
155
|
+
});
|
|
156
|
+
} else {
|
|
157
|
+
throw new Error(`Unsupported email service: ${service}`);
|
|
158
|
+
}
|
|
159
|
+
// prepare mail
|
|
160
|
+
const mail = {
|
|
161
|
+
from,
|
|
162
|
+
to,
|
|
163
|
+
subject: subject || 'Your OTP Code',
|
|
164
|
+
text: text || `Your OTP is ${code}`,
|
|
165
|
+
html: html || `<p>Your OTP is <b>${code}</b></p>`
|
|
166
|
+
};
|
|
167
|
+
await transporter.sendMail(mail);
|
|
168
|
+
}catch(err){
|
|
169
|
+
throw new Error(err);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async function sendSMS({ provider, apiKey, apiSecret, from, to, text, mock = false }) {
|
|
175
|
+
try {
|
|
176
|
+
// 🧪 For testing only — no real SMS sent
|
|
177
|
+
if (mock) {
|
|
178
|
+
console.log(`📱 [Mock SMS via ${provider}]`);
|
|
179
|
+
console.log(`→ To: ${to}`);
|
|
180
|
+
console.log(`→ Message: ${text}`);
|
|
181
|
+
return { status: "SENT (mock)", to, text };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// 🔷 Infobip API
|
|
185
|
+
if (provider === 'infobip') {
|
|
186
|
+
await axios.post(
|
|
187
|
+
'https://api.infobip.com/sms/2/text/advanced',
|
|
188
|
+
{
|
|
189
|
+
messages: [{ from, destinations: [{ to }], text }],
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
headers: {
|
|
193
|
+
Authorization: `App ${apiKey}`,
|
|
194
|
+
'Content-Type': 'application/json',
|
|
195
|
+
},
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
return { status: "SENT", provider: "Infobip", to };
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// 🟪 Vonage API
|
|
202
|
+
if (provider === 'vonage') {
|
|
203
|
+
await axios.post(
|
|
204
|
+
'https://rest.nexmo.com/sms/json',
|
|
205
|
+
{
|
|
206
|
+
api_key: apiKey,
|
|
207
|
+
api_secret: apiSecret,
|
|
208
|
+
to,
|
|
209
|
+
from,
|
|
210
|
+
text,
|
|
211
|
+
},
|
|
212
|
+
{ headers: { 'Content-Type': 'application/json' } }
|
|
213
|
+
);
|
|
214
|
+
return { status: "SENT", provider: "Vonage", to };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// 🟩 Twilio API
|
|
218
|
+
if (provider === 'twilio') {
|
|
219
|
+
await axios.post(
|
|
220
|
+
`https://api.twilio.com/2010-04-01/Accounts/${apiKey}/Messages.json`,
|
|
221
|
+
new URLSearchParams({
|
|
222
|
+
To: to,
|
|
223
|
+
From: from,
|
|
224
|
+
Body: text,
|
|
225
|
+
}),
|
|
226
|
+
{
|
|
227
|
+
auth: {
|
|
228
|
+
username: apiKey,
|
|
229
|
+
password: apiSecret,
|
|
230
|
+
},
|
|
231
|
+
}
|
|
232
|
+
);
|
|
233
|
+
return { status: "SENT", provider: "Twilio", to };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
throw new Error(`Unsupported SMS provider: ${provider}`);
|
|
237
|
+
} catch (err) {
|
|
238
|
+
console.error("❌ SMS send failed:", err.message);
|
|
239
|
+
throw new Error(err.message);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// async function sendOTPwithTelegramBot(otpCode){
|
|
244
|
+
// bot.onText(/\/start/, (msg) => {
|
|
245
|
+
// bot.sendMessage(chatId, "Please share your phone number:", {
|
|
246
|
+
// reply_markup: {
|
|
247
|
+
// keyboard: [
|
|
248
|
+
// [
|
|
249
|
+
// {
|
|
250
|
+
// text: "📞 Share my phone number",
|
|
251
|
+
// request_contact: true, // 🔥 this requests the user's phone
|
|
252
|
+
// },
|
|
253
|
+
// ],
|
|
254
|
+
// ],
|
|
255
|
+
// resize_keyboard: true,
|
|
256
|
+
// one_time_keyboard: true,
|
|
257
|
+
// },
|
|
258
|
+
// });
|
|
259
|
+
// bot.sendMessage(msg.chat.id, `Your Verification code is <b>${otpCode}</b>`, {parse_mode: "HTML"});
|
|
260
|
+
// });
|
|
261
|
+
|
|
262
|
+
// bot.on("contact", (msg) => {
|
|
263
|
+
// const phoneNumber = msg.contact.phone_number;
|
|
264
|
+
// const firstName = msg.contact.first_name;
|
|
265
|
+
// const userId = msg.from.id;
|
|
266
|
+
|
|
267
|
+
// console.log("User shared phone:", phoneNumber);
|
|
268
|
+
|
|
269
|
+
// bot.sendMessage(
|
|
270
|
+
// msg.chat.id,
|
|
271
|
+
// `Thanks, ${firstName}! Your phone number is ${phoneNumber}.`
|
|
272
|
+
// );
|
|
273
|
+
|
|
274
|
+
// // Here you can verify or store it in your database
|
|
275
|
+
// });
|
|
276
|
+
// }
|
|
277
|
+
|
|
278
|
+
module.exports = {
|
|
279
|
+
parseTime,
|
|
280
|
+
generateSecureOTP,
|
|
281
|
+
otpSendingProcessByEmail,
|
|
282
|
+
resendGeneratedOTP,
|
|
283
|
+
sendSMS
|
|
284
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
class CookieManager {
|
|
2
|
+
static setCookie(res, name, value, options = {}) {
|
|
3
|
+
if (!res || typeof res.setHeader !== 'function') {
|
|
4
|
+
throw new Error("Response object must have setHeader() method");
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
let cookieStr = `${name}=${encodeURIComponent(value)}; Path=/;`;
|
|
8
|
+
|
|
9
|
+
if (options.httpOnly) cookieStr += " HttpOnly;";
|
|
10
|
+
if (options.secure) cookieStr += " Secure;";
|
|
11
|
+
if (options.maxAge) cookieStr += ` Max-Age=${Math.floor(options.maxAge / 1000)};`;
|
|
12
|
+
if (options.sameSite) cookieStr += ` SameSite=${options.sameSite};`;
|
|
13
|
+
if (options.domain) cookieStr += ` Domain=${options.domain};`;
|
|
14
|
+
|
|
15
|
+
const existing = res.getHeader('Set-Cookie') || [];
|
|
16
|
+
const newCookies = Array.isArray(existing) ? [...existing, cookieStr] : [cookieStr];
|
|
17
|
+
res.setHeader('Set-Cookie', newCookies);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static getCookie(req, name) {
|
|
21
|
+
const cookieHeader = req.headers?.cookie;
|
|
22
|
+
if (!cookieHeader) return null;
|
|
23
|
+
const cookies = cookieHeader.split(';').map(c => c.trim());
|
|
24
|
+
const found = cookies.find(c => c.startsWith(name + '='));
|
|
25
|
+
return found ? decodeURIComponent(found.split('=')[1]) : null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = CookieManager;
|