20 lines
1.1 KiB
JavaScript
20 lines
1.1 KiB
JavaScript
'use strict';
|
|
|
|
function createAuthenticator(options){
|
|
const {playerPattern,tokenPattern,readPlayer,hashToken,safeEqual}=options||{};
|
|
if(!(playerPattern instanceof RegExp)||!(tokenPattern instanceof RegExp))throw new TypeError('Authentication patterns are required');
|
|
if(typeof readPlayer!=='function'||typeof hashToken!=='function'||typeof safeEqual!=='function')throw new TypeError('Authentication ports are required');
|
|
const parse=req=>{
|
|
const raw=String(req?.headers?.authorization||''),match=/^Bearer\s+([^.]*)\.([^.]*)$/i.exec(raw);
|
|
if(!match||!playerPattern.test(match[1])||!tokenPattern.test(match[2]))throw Object.assign(new Error('Unauthorized'),{status:401});
|
|
return{playerId:match[1].toLowerCase(),token:match[2].toLowerCase()};
|
|
};
|
|
const player=async req=>{
|
|
const auth=parse(req),record=await readPlayer(auth.playerId);
|
|
if(!safeEqual(record.tokenHash,hashToken(auth.token)))throw Object.assign(new Error('Invalid cloud sync code'),{status:403});
|
|
return{...auth,record};
|
|
};
|
|
return Object.freeze({parse,player});
|
|
}
|
|
|
|
module.exports=Object.freeze({createAuthenticator});
|