2026-03-12 15:49:37 +04:00

137 lines
3.6 KiB
JavaScript

/**
* Create a mock JWT token with custom payload
* @param {object} payload - JWT payload data
* @param {object} options - Token options
* @returns {string} Mock JWT token
*/
export function createMockJwt(payload = {}, options = {}) {
const { expiresIn = 3600 } = options // Default 1 hour
const now = Math.floor(Date.now() / 1000)
const defaultPayload = {
sub: '12345',
email: 'test@example.com',
iat: now,
exp: now + expiresIn,
user: {
id: '12345',
email: 'test@example.com',
name: 'Test User'
},
...payload
}
const header = { alg: 'HS256', typ: 'JWT' }
// Create base64url encoded parts
const encodedHeader = base64UrlEncode(JSON.stringify(header))
const encodedPayload = base64UrlEncode(JSON.stringify(defaultPayload))
// Mock signature (not cryptographically valid, but structurally correct)
const mockSignature = base64UrlEncode('mock-signature-for-testing')
return `${encodedHeader}.${encodedPayload}.${mockSignature}`
}
/**
* Create an expired JWT token
* @param {object} payload - Additional payload data
* @returns {string} Expired JWT token
*/
export function createExpiredJwt(payload = {}) {
const pastTime = Math.floor(Date.now() / 1000) - 3600 // 1 hour ago
return createMockJwt({
...payload,
iat: pastTime - 3600,
exp: pastTime
}, { expiresIn: -3600 })
}
/**
* Create an invalid JWT token (malformed)
* @param {string} type - Type of invalid token
* @returns {string} Invalid JWT token
*/
export function createInvalidJwt(type = 'malformed') {
switch (type) {
case 'malformed':
return 'not-a-valid-jwt'
case 'missing-parts':
return 'header.payload'
case 'invalid-base64':
return 'invalid!!!.base64!!!.content!!!'
case 'invalid-json':
return `${base64UrlEncode('not-json')}.${base64UrlEncode('not-json')}.signature`
case 'empty':
return ''
default:
return 'invalid'
}
}
/**
* Create a JWT token with specific user data
* @param {object} user - User data to include
* @param {object} options - Token options
* @returns {string} JWT token with user data
*/
export function createUserJwt(user, options = {}) {
return createMockJwt({
sub: user.id || '12345',
email: user.email || 'user@example.com',
user: {
id: user.id || '12345',
email: user.email || 'user@example.com',
name: user.name || 'Test User',
...user
}
}, options)
}
/**
* Decode a JWT token payload (for test verification)
* @param {string} token - JWT token
* @returns {object|null} Decoded payload or null
*/
export function decodeTestJwt(token) {
try {
if (!token || typeof token !== 'string') return null
const parts = token.split('.')
if (parts.length !== 3) return null
const payload = parts[1]
const decoded = JSON.parse(base64UrlDecode(payload))
return decoded
} catch {
return null
}
}
/**
* Check if a JWT token is expired
* @param {string} token - JWT token
* @returns {boolean} True if expired
*/
export function isTestJwtExpired(token) {
const payload = decodeTestJwt(token)
if (!payload || typeof payload.exp !== 'number') return true
return Math.floor(Date.now() / 1000) >= payload.exp
}
// Helper functions for base64url encoding/decoding
function base64UrlEncode(str) {
const base64 = btoa(unescape(encodeURIComponent(str)))
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
}
function base64UrlDecode(str) {
let base64 = str.replace(/-/g, '+').replace(/_/g, '/')
const pad = base64.length % 4
if (pad) {
base64 += '='.repeat(4 - pad)
}
return decodeURIComponent(escape(atob(base64)))
}