UNPKG

node-less-otp

Version:

A super lightweight library for generating and verifying one-time passwords (OTPs) without the database interaction and additional dependencies.

2 lines (1 loc) 1.82 kB
import t from"crypto";class e{hashSet=(()=>new Set)();constructor(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.secretSalt=e.secretSalt||function(){const e=Math.floor(17*Math.random())+16;return t.randomBytes(e).toString("hex")}(),this.algorithm=e.algorithm||"aes-256-cbc",this.ivLength=e.ivLength||16,this.enableSet=e.enableSet??true}gen(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const r=function(t){const e=function(t){return/^(N{\d+}|L{\d+}|U{\d+}|A{\d+}|M{\d+})+$/.test(t)}(t);if(!e)throw new Error("Invalid template format");const r=()=>Math.floor(10*Math.random()).toString(),n=()=>String.fromCharCode(Math.floor(26*Math.random())+97),h=()=>String.fromCharCode(Math.floor(26*Math.random())+65);return t.replace(/N{(\d+)}/g,((t,e)=>Array.from({length:e},r).join(""))).replace(/L{(\d+)}/g,((t,e)=>Array.from({length:e},n).join(""))).replace(/U{(\d+)}/g,((t,e)=>Array.from({length:e},h).join("")))}(e.template||"N{6}"),n=e.ttl?Date.now()+1e3*e.ttl:1/0,h=JSON.stringify({otp:r,expiresAt:n}),o=this.encryptOtp(t,h);return this.enableSet&&this.hashSet.add(o),{otp:r,hash:o}}verify(t,e,r){try{const{otp:n,expiresAt:h}=this.decryptOtp(e,t),o=this.enableSet&&!this.hashSet.has(e),a=h<Date.now();if(o||a)return!1;const i=n===r;return i&&this.hashSet.delete(e),i}catch(t){return console.error(t),!1}}encryptOtp(e,r){const n=this.deriveKey(e),h=t.randomBytes(this.ivLength),o=t.createCipheriv(this.algorithm,n,h),a=o.update(r,"utf8","hex")+o.final("hex");return h.toString("hex")+":"+a}decryptOtp(e,r){const n=this.deriveKey(r),[h,o]=e.split(":"),a=Buffer.from(h,"hex"),i=t.createDecipheriv(this.algorithm,n,a),s=i.update(o,"hex","utf8")+i.final("utf8");return JSON.parse(s)}deriveKey(e){return t.createHash("sha256").update(this.secretSalt+e).digest()}}export{e as LessOtp};