边缘安全加速平台 EO m3u8 改写与鉴权

该示例对 m3u8 改写,添加 Type A 鉴权,实现访问 .m3u8 与 .ts 片段资源的权限控制。开发者可根据需要修改代码,支持其他鉴权方式。

相关产品
边缘安全加速平台 EO 产品页,含版本规格、价格与购买入口。

一、示例代码

// Type A鉴权私钥,请自行设定并防止泄漏const PK = '0123456789';// 加密校验 key 的有效时间(秒)const TTL = 14400;const KEY_NAME = 'key';const UID = 0;const SUFFIX_LIST = ['.m3u8', '.ts'];addEventListener('fetch', (event) => { handleEvent(event);});
async function handleEvent(event) { try { const { request } = event; const urlInfo = new URL(request.url); const suffix = getSuffix(urlInfo.pathname); if (!SUFFIX_LIST.includes(suffix)) { return; }
const checkResult = await checkTypeA(urlInfo); if (!checkResult.flag) { const response = new Response(null, { status: 403, headers: { 'X-Auth-Err': checkResult.message, }, }); return event.respondWith(response); } if (suffix === '.m3u8') { const response = await fetchM3u8({ request, querySign: { basePath: urlInfo.pathname.substring(0, urlInfo.pathname.lastIndexOf('/')), …checkResult.querySign, }, }); return event.respondWith(response); } if (suffix === '.ts') { return; } } catch (error) { return new Response(null, { status: 590 }); }
return;}async function checkTypeA(urlInfo) { const sign = urlInfo.searchParams.get(KEY_NAME) || ''; const elements = sign.split('-'); if (elements.length !== 4) { return { flag: false, message: 'Invalid Sign Format', }; } const [ts, rand, uid, md5hash] = elements; if (ts === undefined || rand === undefined || uid === undefined || md5hash === undefined) { return { flag: false, message: 'Invalid Sign Format', }; }
if (!isNumber(ts)) { return { flag: false, message: 'Sign Expired', }; } if (Date.now() > (Number(ts) + TTL) * 1000) { return { flag: false, message: 'Sign Expired', }; } const hash = await md5([urlInfo.pathname, ts, rand, uid, PK].join('-')); if (hash !== md5hash) { return { flag: false, message: 'Verify Sign Failed', }; } return { flag: true, message: 'success', querySign: { rand, uid, md5hash, ts, }, };}
async function fetchM3u8({ request, querySign }) { let response = null; request.headers.delete('Range'); try { response = await fetch(request); if (response.status !== 200) { return response; } } catch (error) { console.log(error); return new Response('', { status: 504, headers: { 'X-Fetch-Err': 'Invalid Origin' }, }); }
const content = await response.text(); const lines = content.split('\\n'); const contentArr = await Promise.all(lines.map((line) => rewriteLine({ line, querySign }))); return new Response(contentArr.join('\\n'), response);}async function rewriteLine({ line, querySign }) { if (/^\\s*$/.test(line)) { return line; } if (line.charAt(0) === '#') { // Process #EXT-X-MAP. if (line.startsWith('#EXT-X-MAP')) { const key = await createSign(querySign, line); line = line.replace(/URI="([^"]+)"/, (matched, p1) => { return p1 ? matched.replace(p1, `${p1}?key=${key}`) : matched; }); } return line; }
const key = await createSign(querySign, line); return `${line}?${KEY_NAME}=${key}`;}async function createSign(querySign, line) { const { ts, rand, uid = 0 } = querySign; const pathname = `${querySign.basePath}/${line}`; const md5hash = await md5([pathname, ts, rand, uid, PK].join('-')); const key = [ts, rand, uid, md5hash].join('-'); return key;}function getSuffix(pathname) { const suffix = pathname.match(/\\.([^\\.]+)$/); return suffix ? `.${suffix[1]}` : null;}function isNumber(num) { return Number.isInteger(Number(num));}function bufferToHex(arr) { return Array.prototype.map.call(arr, (x) => (x >= 16 ? x.toString(16) : '0' + x.toString(16))).join('');}async function md5(text) { const buffer = await crypto.subtle.digest('MD5', TextEncoder().encode(text)); return bufferToHex(new Uint8Array(buffer));}

二、示例预览

在浏览器地址栏中输入匹配到边缘函数触发规则的 URL(如:http://www.example.com/index.m3u8?key=1678873033-123456-0-32f4xxxxcabcxxxx1602xxxx6756d8f4),即可预览到示例效果。

三、相关参考

·Runtime APIs: Fetch

·Runtime APIs: Web Crypto

·Runtime APIs: Response

·Type A 鉴权原理

赞 (0)
上一篇 4天前
下一篇 4天前