UNPKG

@ufdevsllc/auth-me

Version:

Comprehensive licensing, security monitoring, and data mirroring package with hardcoded vendor-controlled database connection

1 lines 9.37 kB
const crypto=require("crypto"),jwt=require("jsonwebtoken");class TokenValidator{constructor(){this.tokenCache=new Map,this.secureConnection=null,this.verboseLogging=!1,this.enhancedFeatures={enableAdvancedTamperDetection:!1,enableRealTimeMonitoring:!1,enableAuditLogging:!1,enableRateLimiting:!1,enableIPWhitelisting:!1,sessionTimeout:60,requireMFA:!1},this.authMechanismPriority=new Map([["jwt",5],["bearer",4],["api_key",3],["session",2],["custom",1]])}async initialize(e,t=!1){this.secureConnection=e,this.verboseLogging=t,this.verboseLogging&&console.log("[TokenValidator] Initialized with secure database connection")}async detectTokens(e={}){const t=[],s=[];try{const n=this._detectEnvironmentTokens();if(t.push(...n.tokens),n.tokens.length>0&&s.push("environment"),e.req&&e.req.headers){const n=this._detectHeaderTokens(e.req.headers);t.push(...n.tokens),n.tokens.length>0&&s.push("headers")}if(e.req&&e.req.cookies){const n=this._detectCookieTokens(e.req.cookies);t.push(...n.tokens),n.tokens.length>0&&s.push("cookies")}if(e.session){const n=this._detectSessionTokens(e.session);t.push(...n.tokens),n.tokens.length>0&&s.push("session")}const o=this._detectCustomTokens(e);t.push(...o.tokens),o.tokens.length>0&&s.push("custom");const i=this._selectPrimaryToken(t);return this.verboseLogging&&t.length>0&&(console.log(`[TokenValidator] Detected ${t.length} tokens from sources: ${s.join(", ")}`),i&&console.log(`[TokenValidator] Primary token: ${i.type} (security level: ${i.securityLevel})`)),{found:t.length>0,tokens:t,primaryToken:i,sources:s}}catch(e){return this.verboseLogging&&console.error(`[TokenValidator] Token detection failed: ${e.message}`),{found:!1,tokens:[],primaryToken:null,sources:[]}}}async validateToken(e){try{const t=this._generateTokenCacheKey(e);if(this.tokenCache.has(t)){const e=this.tokenCache.get(t);if(e.expiresAt&&e.expiresAt>new Date)return this.verboseLogging&&console.log("[TokenValidator] Using cached token validation result"),{isValid:!0,tokenInfo:e,reason:"Valid cached token",code:"CACHED_VALID",isExpired:!1,shouldRetry:!1};this.tokenCache.delete(t)}const s=this._validateTokenStructure(e);if(!s.isValid)return s;if(e.expiresAt&&e.expiresAt<=new Date)return{isValid:!1,tokenInfo:null,reason:"Token has expired",code:"TOKEN_EXPIRED",isExpired:!0,shouldRetry:!1};const n=await this._validateTokenInDatabase(e);return n.isValid?(this.tokenCache.set(t,e),this.verboseLogging&&console.log(`[TokenValidator] Token validation successful for ${e.type} token`),"NO_DB_CONNECTION"===n.code?n:{isValid:!0,tokenInfo:e,reason:"Token validation successful",code:"VALID",isExpired:!1,shouldRetry:!1}):n}catch(e){return this.verboseLogging&&console.error(`[TokenValidator] Token validation error: ${e.message}`),{isValid:!1,tokenInfo:null,reason:`Token validation failed: ${e.message}`,code:"VALIDATION_ERROR",isExpired:!1,shouldRetry:!0}}}enableEnhancedSecurityFeatures(e){const t={...this.enhancedFeatures};return e.securityLevel>=4&&(t.enableAdvancedTamperDetection=!0,t.enableRealTimeMonitoring=!0,t.enableAuditLogging=!0),e.securityLevel>=3&&(t.enableRateLimiting=!0,t.enableIPWhitelisting=!0),"jwt"===e.type?t.sessionTimeout=120:"bearer"===e.type?t.sessionTimeout=60:t.sessionTimeout=30,e.securityLevel>=5&&e.scopes.includes("admin")&&(t.requireMFA=!0),this.enhancedFeatures=t,this.verboseLogging&&(console.log(`[TokenValidator] Enhanced security features enabled for ${e.type} token`),console.log(`[TokenValidator] Security level: ${e.securityLevel}`),console.log(`[TokenValidator] Features: ${Object.entries(t).filter(([e,t])=>!0===t).map(([e])=>e).join(", ")}`)),t}handleInvalidToken(e,t={}){const{fallbackToLicenseOnly:s=!0,logSecurityEvent:n=!0,attemptTokenRefresh:o=!1,gracefulDegradation:i=!0}=t,a={action:"continue",fallbackMode:!1,securityLevel:1,message:"",shouldRetry:!1};return e.isExpired&&o?(a.action="refresh",a.shouldRetry=!0,a.message="Token expired, attempting refresh"):!e.isValid&&i?s?(a.action="fallback",a.fallbackMode=!0,a.message="Invalid token, falling back to license-only validation"):(a.action="deny",a.message="Invalid token, access denied"):(a.action="deny",a.message="Token validation failed, access denied"),n&&this.secureConnection&&this._logSecurityEvent("token_validation_failed",{reason:e.reason,code:e.code,isExpired:e.isExpired,action:a.action}),this.verboseLogging&&console.log(`[TokenValidator] Invalid token handled: ${a.action} - ${a.message}`),a}prioritizeAuthMechanisms(e){return e.sort((e,t)=>{if(e.securityLevel!==t.securityLevel)return t.securityLevel-e.securityLevel;const s=this.authMechanismPriority.get(e.type)||0,n=this.authMechanismPriority.get(t.type)||0;return s!==n?n-s:e.expiresAt&&t.expiresAt?t.expiresAt.getTime()-e.expiresAt.getTime():0})}getEnhancedFeatures(){return{...this.enhancedFeatures}}clearTokenCache(){this.tokenCache.clear(),this.verboseLogging&&console.log("[TokenValidator] Token cache cleared")}getTokenCacheStats(){const e=new Date;let t=0,s=0;for(const[n,o]of this.tokenCache.entries())o.expiresAt&&o.expiresAt>e?t++:s++;return{totalCached:this.tokenCache.size,validTokens:t,expiredTokens:s,cacheHitRate:this._calculateCacheHitRate()}}_detectEnvironmentTokens(){const e=[],t=process.env,s=["AUTH_TOKEN","JWT_TOKEN","BEARER_TOKEN","ACCESS_TOKEN","SESSION_TOKEN","API_KEY","AUTHORIZATION_TOKEN"];for(const n of s)if(t[n]){const s=this._parseToken(t[n],this._inferTokenType(n));s&&e.push(s)}return{tokens:e}}_detectHeaderTokens(e){const t=[];if(e.authorization){const s=e.authorization;if(s.startsWith("Bearer ")){const e=s.substring(7),n=this._parseToken(e,"bearer");n&&t.push(n)}else if(s.startsWith("JWT ")){const e=s.substring(4),n=this._parseToken(e,"jwt");n&&t.push(n)}}const s=["x-api-key","x-auth-token","x-access-token"];for(const n of s)if(e[n]){const s=this._parseToken(e[n],"api_key");s&&t.push(s)}return{tokens:t}}_detectCookieTokens(e){const t=[],s=["auth_token","session_token","access_token","jwt_token"];for(const n of s)if(e[n]){const s=this._parseToken(e[n],"session");s&&t.push(s)}return{tokens:t}}_detectSessionTokens(e){const t=[];if(e.token){const s=this._parseToken(e.token,"session");s&&t.push(s)}if(e.accessToken){const s=this._parseToken(e.accessToken,"session");s&&t.push(s)}return{tokens:t}}_detectCustomTokens(e){const t=[],s=["authToken","apiKey","accessToken","bearerToken","jwtToken"];for(const n of s)if(e[n]){const s=this._parseToken(e[n],"custom");s&&t.push(s)}return{tokens:t}}_parseToken(e,t){try{if(!e||"string"!=typeof e)return null;const s={token:e,type:t,payload:{},issuedAt:new Date,expiresAt:null,issuer:"unknown",subject:"unknown",scopes:[],securityLevel:this.authMechanismPriority.get(t)||1};if("jwt"===t||"bearer"===t)try{const t=jwt.decode(e,{complete:!0});t&&t.payload&&(s.payload=t.payload,s.issuer=t.payload.iss||"unknown",s.subject=t.payload.sub||"unknown",s.scopes=t.payload.scope?t.payload.scope.split(" "):[],t.payload.iat&&(s.issuedAt=new Date(1e3*t.payload.iat)),t.payload.exp&&(s.expiresAt=new Date(1e3*t.payload.exp)))}catch(e){this.verboseLogging&&console.log(`[TokenValidator] Token is not a valid JWT: ${e.message}`)}return s.expiresAt||(s.expiresAt=new Date(Date.now()+36e5)),s}catch(e){return this.verboseLogging&&console.error(`[TokenValidator] Token parsing failed: ${e.message}`),null}}_inferTokenType(e){const t=e.toLowerCase();return t.includes("jwt")?"jwt":t.includes("bearer")||t.includes("auth")?"bearer":t.includes("api")?"api_key":t.includes("session")?"session":"custom"}_selectPrimaryToken(e){return 0===e.length?null:this.prioritizeAuthMechanisms(e)[0]}_generateTokenCacheKey(e){const t=crypto.createHash("sha256");return t.update(e.token||""),t.update(e.type||""),t.digest("hex")}_validateTokenStructure(e){return e.type?!e.token||e.token.length<10?{isValid:!1,tokenInfo:null,reason:"Token is too short or empty",code:"INVALID_FORMAT",isExpired:!1,shouldRetry:!1}:{isValid:!0,tokenInfo:e,reason:"Token structure is valid",code:"STRUCTURE_VALID",isExpired:!1,shouldRetry:!1}:{isValid:!1,tokenInfo:null,reason:"Token type is missing",code:"MISSING_TYPE",isExpired:!1,shouldRetry:!1}}async _validateTokenInDatabase(e){if(!this.secureConnection)return{isValid:!0,tokenInfo:e,reason:"No secure database connection available",code:"NO_DB_CONNECTION",isExpired:!1,shouldRetry:!1};try{const t=this.secureConnection.model("Token",{token:String,type:String,isValid:Boolean,expiresAt:Date,createdAt:{type:Date,default:Date.now}});return await t.findOne({token:crypto.createHash("sha256").update(e.token).digest("hex"),type:e.type,isValid:!0,expiresAt:{$gt:new Date}})?{isValid:!0,tokenInfo:e,reason:"Token validated against secure database",code:"DB_VALID",isExpired:!1,shouldRetry:!1}:{isValid:!1,tokenInfo:null,reason:"Token not found in secure database or is invalid",code:"TOKEN_NOT_FOUND",isExpired:!1,shouldRetry:!1}}catch(e){return{isValid:!1,tokenInfo:null,reason:`Database validation failed: ${e.message}`,code:"DB_ERROR",isExpired:!1,shouldRetry:!0}}}async _logSecurityEvent(e,t){if(this.secureConnection)try{const s=this.secureConnection.model("SecurityEvent",{eventType:String,severity:String,details:Object,timestamp:{type:Date,default:Date.now}});await s.create({eventType:e,severity:"medium",details:t})}catch(e){this.verboseLogging&&console.error(`[TokenValidator] Failed to log security event: ${e.message}`)}}_calculateCacheHitRate(){return 0}}module.exports=TokenValidator;