From 25cf8a37a2118d4b8703ab309da76b9d9ef74afb Mon Sep 17 00:00:00 2001 From: knotteye Date: Tue, 3 Dec 2019 19:51:14 -0600 Subject: [PATCH 1/9] Big Commit! Seriously, this one is pretty massive. Satyr now has proper sessions in the browser (like a real website), and a lot of changes were made. API Endpoints were changed from requiring a username and password to requiring a valid JsonWebToken, obtained from /api/login Satyr will generate a PEM format key for JWT signing and verification on startup if it can't find one at config/jwt.pem This file was added to .gitignore Two new depencies: cookie-parser and jose, for reading and signing JWTs. Refactored http.ts into mutiple functions, with a couple helper functions related to cookies and JWT decoding and verification. Socket.IO chat will also automatically log in users with a valid JWT. Refactor api.ts to reflect new requirements from endpoints. Minor bugfix in server.ts so we don't throw an uncaught exception when rejecting a stream with an invalid key. Transcode options readded to default.toml. They do nothing and they are not sane defaults. Both of those things are in the todo list. --- .gitignore | 1 + config/default.toml | 7 +- package-lock.json | 49 +++++- package.json | 2 + src/api.ts | 39 +++-- src/http.ts | 330 +++++++++++++++++++++++++++++-------- src/server.ts | 2 +- templates/base.njk | 2 +- templates/changepwd.njk | 7 +- templates/changesk.njk | 11 -- templates/login.njk | 10 ++ templates/profile.njk | 13 +- templates/registration.njk | 20 ++- 13 files changed, 375 insertions(+), 118 deletions(-) delete mode 100644 templates/changesk.njk create mode 100644 templates/login.njk diff --git a/.gitignore b/.gitignore index 0cdbe36..fad7bdd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ node_modules site/live config/local.toml +config/jwt.pem config/generated.toml install/db_setup.sql build/** diff --git a/config/default.toml b/config/default.toml index ea03684..3ff79ca 100644 --- a/config/default.toml +++ b/config/default.toml @@ -50,4 +50,9 @@ port = 8000 record = false publicEndpoint = 'live' privateEndpoint = 'stream' -ffmpeg = '' \ No newline at end of file +ffmpeg = '' + +[transcode] +adapative = false +variants = 3 +format = 'dash' \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 582080b..9c53b90 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "satyr", - "version": "0.4.3", + "version": "0.4.4", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -121,6 +121,16 @@ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" }, + "asn1.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.2.0.tgz", + "integrity": "sha512-Q7hnYGGNYbcmGrCPulXfkEw7oW7qjWeM4ZTALmgpuIcZLxyqqKYWxCZg2UBm8bklrnB4m2mGyJPWfoktdORD8A==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", @@ -257,6 +267,11 @@ "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", @@ -507,6 +522,22 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" }, + "cookie-parser": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.4.tgz", + "integrity": "sha512-lo13tqF3JEtFO7FyA49CqbhaFkskRJ0u/UAiINgrIXeRCY41c88/zxtrECl8AKH3B0hj9q10+h3Kt8I7KlW4tw==", + "requires": { + "cookie": "0.3.1", + "cookie-signature": "1.0.6" + }, + "dependencies": { + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + } + } + }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -1837,6 +1868,14 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "optional": true }, + "jose": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/jose/-/jose-1.15.1.tgz", + "integrity": "sha512-Gp+53zIEb68qTuyagcalDMVn1s0WrxiGBQJbEjShOdv3CYmbPIJEAN0Qtn4rCa7XgODoEa7HHuz8GoYgIpIzog==", + "requires": { + "asn1.js": "^5.2.0" + } + }, "json5": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", @@ -1940,6 +1979,11 @@ "mime-db": "1.40.0" } }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -2984,8 +3028,7 @@ "typescript": { "version": "3.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz", - "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==", - "dev": true + "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==" }, "union-value": { "version": "1.0.1", diff --git a/package.json b/package.json index 221094e..7b023d9 100644 --- a/package.json +++ b/package.json @@ -17,9 +17,11 @@ "bcrypt": "^3.0.6", "body-parser": "^1.19.0", "config": "^3.2.2", + "cookie-parser": "^1.4.4", "dirty": "^1.1.0", "express": "^4.17.1", "flags": "^0.1.3", + "jose": "^1.15.1", "mysql": "^2.17.1", "node-media-server": ">=2.1.3 <3.0.0", "nunjucks": "^3.2.0", diff --git a/src/api.ts b/src/api.ts index 5c01cd6..7ff9944 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,4 +1,5 @@ import * as db from "./database" +import { unregisterUser } from "./irc"; var config: any; function init(conf: object){ @@ -20,18 +21,26 @@ async function register(name: string, password: string, confirm: string) { return {"error":""}; } -async function update(name: string, password: string, title: string, bio: string, record: boolean){ - if(!name || !password) return {"error":"Insufficient parameters"}; - let auth: boolean = await db.validatePassword(name, password); - if(!auth) return {"error":"Username or Password Incorrect"}; - await db.query('UPDATE user_meta set title='+db.raw.escape(title)+', about='+db.raw.escape(bio)+' where username='+db.raw.escape(name)); - if(!record) await db.query('UPDATE users set record_flag=false where username='+db.raw.escape(name)); - else await db.query('UPDATE users set record_flag=true where username='+db.raw.escape(name)); +async function update(fields: object){ + if(!fields['title'] && !fields['bio'] && (fields['rec'] !== 'true' && fields['rec'] !== 'false')) return {"error":"no valid fields specified"}; + let qs: string = ""; + let f: boolean = false; + if(fields['title']) {qs += ' user_meta.title='+db.raw.escape(fields['title']);f = true;} + if(fields['bio']) { + if(f) qs+=','; + qs += ' user_meta.about='+db.raw.escape(fields['bio']); + f=true; + } + if(typeof(fields['rec']) === 'boolean' || typeof(fields['rec']) === 'number') { + if(f) qs+=','; + qs += ' users.record_flag='+db.raw.escape(fields['rec']); + } + await db.query('UPDATE users,user_meta SET'+qs+' WHERE users.username='+db.raw.escape(fields['name'])+' AND user_meta.username='+db.raw.escape(fields['name'])); return {"success":""}; } async function changepwd(name: string, password: string, newpwd: string){ - if(!name || !password) return {"error":"Insufficient parameters"}; + if(!name || !password || !newpwd) return {"error":"Insufficient parameters"}; let auth: boolean = await db.validatePassword(name, password); if(!auth) return {"error":"Username or Password Incorrect"}; let newhash: string = await db.hash(newpwd); @@ -39,13 +48,17 @@ async function changepwd(name: string, password: string, newpwd: string){ return {"success":""}; } -async function changesk(name: string, password: string){ - if(!name || !password) return {"error":"Insufficient parameters"}; - let auth: boolean = await db.validatePassword(name, password); - if(!auth) return {"error":"Username or Password Incorrect"}; +async function changesk(name: string){ let key: string = await db.genKey(); await db.query('UPDATE users set stream_key='+db.raw.escape(key)+'where username='+db.raw.escape(name)+' limit 1'); return {"success":key}; } -export { init, register, update, changepwd, changesk }; \ No newline at end of file +async function login(name: string, password: string){ + if(!name || !password) return {"error":"Insufficient parameters"}; + let auth: boolean = await db.validatePassword(name, password); + if(!auth) return {"error":"Username or Password Incorrect"}; + return false; +} + +export { init, register, update, changepwd, changesk, login }; \ No newline at end of file diff --git a/src/http.ts b/src/http.ts index 2d2b5ff..94302c2 100644 --- a/src/http.ts +++ b/src/http.ts @@ -4,22 +4,35 @@ import * as bodyparser from "body-parser"; import * as fs from "fs"; import * as socketio from "socket.io"; import * as http from "http"; +import * as cookies from "cookie-parser"; import * as dirty from "dirty"; import * as api from "./api"; import * as db from "./database"; import * as irc from "./irc"; +import { readFileSync, writeFileSync } from "fs"; +import { JWT, JWK } from "jose"; +import { strict } from "assert"; +import { parse } from "path"; const app = express(); const server = http.createServer(app); const io = socketio(server); const store = dirty(); +var jwkey; +try{ + jwkey = JWK.asKey(readFileSync('./config/jwt.pem')); +} catch (e) { + console.log("No key found for JWT signing, generating one now."); + jwkey = JWK.generateSync('RSA', 2048, { use: 'sig' }); + writeFileSync('./config/jwt.pem', jwkey.toPEM(true)); +} var njkconf; async function init(satyr: any, port: number, ircconf: any){ njk.configure('templates', { - autoescape: true, - express : app, - watch: false + autoescape : true, + express : app, + watch : true }); njkconf ={ sitename: satyr.name, @@ -28,88 +41,287 @@ async function init(satyr: any, port: number, ircconf: any){ rootredirect: satyr.rootredirect, version: satyr.version }; + app.use(cookies()); app.use(bodyparser.json()); app.use(bodyparser.urlencoded({ extended: true })); //site handlers + await initSite(satyr.registration); + //api handlers + await initAPI(); + //static files if nothing else matches first + app.use(express.static(satyr.directory)); + //404 Handler + app.use(function (req, res, next) { + if(tryDecode(req.cookies.Authorization)) { + res.status(404).render('404.njk', Object.assign({auth: {is: true, name: JWT.decode(req.cookies.Authorization)['username']}}, njkconf)); + } + else res.status(404).render('404.njk', njkconf); + //res.status(404).render('404.njk', njkconf); + }); + await initChat(ircconf); + server.listen(port); +} + +async function newNick(socket, skip?: boolean) { + if(socket.handshake.headers['cookie'] && !skip){ + let c = await parseCookie(socket.handshake.headers['cookie']); + let t = await validToken(c['Authorization']); + if(t) return t['username']; + } + //i just realized how shitty of an idea this is + let n: string = 'Guest'+Math.floor(Math.random() * Math.floor(1000)); + if(store.get(n)) return newNick(socket, true); + else { + store.set(n, socket.id); + return n; + } +} + +async function chgNick(socket, nick) { + let rooms = Object.keys(socket.rooms); + for(let i=1;i { + db.query('select username,title from user_meta where live=1 limit 10;').then((result) => { + res.send(result); + }); + }); + app.get('/api/users/live/:num', (req, res) => { + if(req.params.num > 50) req.params.num = 50; + db.query('select username,title from user_meta where live=1 limit '+req.params.num+';').then((result) => { + res.send(result); + }); + }); + app.post('/api/register', (req, res) => { + api.register(req.body.username, req.body.password, req.body.confirm).then( (result) => { + if(result[0]) return genToken(req.body.username).then((t) => { + res.cookie('Authorization', t); + res.send(result); + return; + }); + res.send(result); + }); + }); + app.post('/api/user/update', (req, res) => { + validToken(req.cookies.Authorization).then((t) => { + if(t) { + return api.update({name: t['username'], + title: "title" in req.body ? req.body.title : false, + bio: "bio" in req.body ? req.body.bio : false, + rec: "record" in req.body ? req.body.record : "NA" + }).then((r) => { + res.send(r); + return; + }); + } + else { + res.send('{"error":"invalid token"}'); + return; + } + }); + /*api.update(req.body.username, req.body.password, req.body.title, req.body.bio, req.body.record).then((result) => { + res.send(result); + });*/ + }); + app.post('/api/user/password', (req, res) => { + validToken(req.cookies.Authorization).then((t) => { + if(t) { + return api.changepwd(t['username'], req.body.password, req.body.newpassword).then((r) => { + res.send(r); + return; + }); + } + else { + res.send('{"error":"invalid token"}'); + return; + } + }); + }); + app.post('/api/user/streamkey', (req, res) => { + validToken(req.cookies.Authorization).then((t) => { + if(t) { + api.changesk(t['username']).then((r) => { + res.send(r); + }); + } + else { + res.send('{"error":"invalid token"}'); + } + }); + }); + app.post('/api/login', (req, res) => { + if(req.cookies.Authorization) validToken(req.cookies.Authorization).then((t) => { + if(t) { + if(t['exp'] - 86400 < Math.floor(Date.now() / 1000)){ + return genToken(t['username']).then((t) => { + res.cookie('Authorization', t); + res.send('{"success":""}'); + return; + }); + } + else { + res.send('{"success":"already verified"}'); + return; + } + } + else { + res.send('{"error":"invalid token"}'); + return; + } + }); + else { + api.login(req.body.username, req.body.password).then((result) => { + if(!result){ + genToken(req.body.username).then((t) => { + res.cookie('Authorization', t); + res.send('{"success":""}'); + }) + } + else { + res.send(result); + } + }); + } + }) +} + +async function initSite(openReg) { app.get('/', (req, res) => { res.redirect(njkconf.rootredirect); }); app.get('/about', (req, res) => { - res.render('about.njk', njkconf); + if(tryDecode(req.cookies.Authorization)) { + res.render('about.njk', Object.assign({auth: {is: true, name: JWT.decode(req.cookies.Authorization)['username']}}, njkconf)); + } + else res.render('about.njk',njkconf); }); app.get('/users', (req, res) => { db.query('select username from users').then((result) => { - res.render('list.njk', Object.assign({list: result}, njkconf)); + if(tryDecode(req.cookies.Authorization)) { + res.render('list.njk', Object.assign({list: result}, {auth: {is: true, name: JWT.decode(req.cookies.Authorization)['username']}}, njkconf)); + } + else res.render('list.njk', Object.assign({list: result}, njkconf)); + //res.render('list.njk', Object.assign({list: result}, njkconf)); }); }); app.get('/users/live', (req, res) => { db.query('select username,title from user_meta where live=1;').then((result) => { - res.render('live.njk', Object.assign({list: result}, njkconf)); + if(tryDecode(req.cookies.Authorization)) { + res.render('live.njk', Object.assign({list: result}, {auth: {is: true, name: JWT.decode(req.cookies.Authorization)['username']}}, njkconf)); + } + else res.render('live.njk', Object.assign({list: result}, njkconf)); + //res.render('live.njk', Object.assign({list: result}, njkconf)); }); }); - app.get('/users/*', (req, res) => { - db.query('select username,title,about from user_meta where username='+db.raw.escape(req.url.split('/')[2].toLowerCase())).then((result) => { + app.get('/users/:user', (req, res) => { + db.query('select username,title,about from user_meta where username='+db.raw.escape(req.params.user)).then((result) => { if(result[0]){ - res.render('user.njk', Object.assign(result[0], njkconf)); + if(tryDecode(req.cookies.Authorization)) { + res.render('user.njk', Object.assign(result[0], {auth: {is: true, name: JWT.decode(req.cookies.Authorization)['username']}}, njkconf)); + } + else res.render('user.njk', Object.assign(result[0], njkconf)); + //res.render('user.njk', Object.assign(result[0], njkconf)); } - else res.render('404.njk', njkconf); + else if(tryDecode(req.cookies.Authorization)) { + res.status(404).render('404.njk', Object.assign({auth: {is: true, name: JWT.decode(req.cookies.Authorization)['username']}}, njkconf)); + } + else res.status(404).render('404.njk', njkconf); }); }); - app.get('/vods/*', (req, res) => { - db.query('select username from user_meta where username='+db.raw.escape(req.url.split('/')[2].toLowerCase())).then((result) => { + app.get('/vods/:user', (req, res) => { + db.query('select username from user_meta where username='+db.raw.escape(req.params.user)).then((result) => { if(result[0]){ - fs.readdir('./site/live/'+njkconf.user, {withFileTypes: true} , (err, files) => { - res.render('vods.njk', Object.assign({user: result[0].username, list: files.filter(fn => fn.name.endsWith('.mp4'))}, njkconf)); + fs.readdir('./site/live/'+result[0].username, {withFileTypes: true} , (err, files) => { + if(tryDecode(req.cookies.Authorization)) { + res.render('vods.njk', Object.assign({user: result[0].username, list: files.filter(fn => fn.name.endsWith('.mp4'))}, {auth: {is: true, name: JWT.decode(req.cookies.Authorization)['username']}}, njkconf)); + } + else res.render('vods.njk', Object.assign({user: result[0].username, list: files.filter(fn => fn.name.endsWith('.mp4'))}, njkconf)); + //res.render('vods.njk', Object.assign({user: result[0].username, list: files.filter(fn => fn.name.endsWith('.mp4'))}, njkconf)); }); } - else res.render('404.njk', njkconf); + else if(tryDecode(req.cookies.Authorization)) { + res.status(404).render('404.njk', Object.assign({auth: {is: true, name: JWT.decode(req.cookies.Authorization)['username']}}, njkconf)); + } + else res.status(404).render('404.njk', njkconf); }); }); + app.get('/login', (req, res) => { + if(tryDecode(req.cookies.Authorization)) { + res.redirect(njkconf.rootredirect); + } + else res.render('login.njk',njkconf); + }); app.get('/register', (req, res) => { - res.render('registration.njk', njkconf); + if(tryDecode(req.cookies.Authorization) || !openReg) { + res.redirect(njkconf.rootredirect); + } + else res.render('registration.njk',njkconf); }); app.get('/profile', (req, res) => { - res.render('profile.njk', njkconf); + if(tryDecode(req.cookies.Authorization)) { + res.render('profile.njk', Object.assign({auth: {is: true, name: JWT.decode(req.cookies.Authorization)['username']}}, njkconf)); + } + else res.redirect(njkconf.rootredirect); }); app.get('/changepwd', (req, res) => { - res.render('changepwd.njk', njkconf); - }); - app.get('/changesk', (req, res) => { - res.render('changesk.njk', njkconf); + if(tryDecode(req.cookies.Authorization)) { + res.render('changepwd.njk', Object.assign({auth: {is: true, name: JWT.decode(req.cookies.Authorization)['username']}}, njkconf)); + } + else res.redirect(njkconf.rootredirect); }); app.get('/chat', (req, res) => { res.render('chat.html', njkconf); }); app.get('/help', (req, res) => { - res.render('help.njk', njkconf); - }); - //api handlers - app.post('/api/register', (req, res) => { - api.register(req.body.username, req.body.password, req.body.confirm).then( (result) => { - res.send(result); - }); - }); - app.post('/api/user', (req, res) => { - api.update(req.body.username, req.body.password, req.body.title, req.body.bio, req.body.record).then((result) => { - res.send(result); - }); - }); - app.post('/api/user/password', (req, res) => { - api.changepwd(req.body.username, req.body.password, req.body.newpassword).then((result) => { - res.send(result); - }); - }); - app.post('/api/user/streamkey', (req, res) => { - api.changesk(req.body.username, req.body.password).then((result) => { - res.send(result); - }) - }); - //static files if nothing else matches first - app.use(express.static('site')); - //404 Handler - app.use(function (req, res, next) { - res.status(404).render('404.njk', njkconf); + if(tryDecode(req.cookies.Authorization)) { + res.render('help.njk', Object.assign({auth: {is: true, name: JWT.decode(req.cookies.Authorization)['username']}}, njkconf)); + } + else res.render('help.njk',njkconf); }); +} + +async function initChat(ircconf: any) { //irc peering if(ircconf.enable){ await irc.connect({ @@ -190,26 +402,6 @@ async function init(satyr: any, port: number, ircconf: any){ else socket.emit('ALERT', 'Not authorized to do that.'); }); }); - server.listen(port); -} - -async function newNick(socket) { - //i just realized how shitty of an idea this is - let n: string = 'Guest'+Math.floor(Math.random() * Math.floor(1000)); - if(store.get(n)) return newNick(socket); - else { - store.set(n, socket.id); - return n; - } -} -async function chgNick(socket, nick) { - let rooms = Object.keys(socket.rooms); - for(let i=1;i { - keystore.rm(results[0].username); + if(results[0]) keystore.rm(results[0].username); }); } diff --git a/templates/base.njk b/templates/base.njk index a7aa9e7..7f2a642 100644 --- a/templates/base.njk +++ b/templates/base.njk @@ -8,7 +8,7 @@
{% block content %} diff --git a/templates/changepwd.njk b/templates/changepwd.njk index aa29838..c3eaf03 100644 --- a/templates/changepwd.njk +++ b/templates/changepwd.njk @@ -1,11 +1,10 @@ {% extends "base.njk" %} {% block content %} -

Change your password on {{ sitename }}

Not registered yet? Sign up here.
Update your profile or stream key.
+

Change your password on {{ sitename }}

- Username:

- Password:

- New Password:

+ Old Password:

+ New Password:


diff --git a/templates/changesk.njk b/templates/changesk.njk deleted file mode 100644 index 30802a6..0000000 --- a/templates/changesk.njk +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "base.njk" %} -{% block content %} -

Get a new stream key on {{ sitename }}

Not registered yet? Sign up here.
Update your profile or password.
-

-
- Username:

- Password:

- -
- -{% endblock %} diff --git a/templates/login.njk b/templates/login.njk new file mode 100644 index 0000000..f5cb4f8 --- /dev/null +++ b/templates/login.njk @@ -0,0 +1,10 @@ +{% extends "base.njk" %} +{% block content %} +

Log in to {{ sitename }}

Not registered yet? Sign up here.

+
+ Username:

+ Password:

+ +
+ +{% endblock %} \ No newline at end of file diff --git a/templates/profile.njk b/templates/profile.njk index 465f061..a370a6c 100644 --- a/templates/profile.njk +++ b/templates/profile.njk @@ -1,14 +1,15 @@ {% extends "base.njk" %} {% block content %} -

Update your profile on {{ sitename }}

Not registered yet? Sign up here.
Change your password or stream key.
+

Update your profile on {{ sitename }}

Or, change your password.

-
- Username:

- Password:

+ Stream Title:

Bio:

- Record VODs:
- + Record VODs: Yes No

+ +

+
+
{% endblock %} \ No newline at end of file diff --git a/templates/registration.njk b/templates/registration.njk index 2bdfe0c..5b0ba91 100644 --- a/templates/registration.njk +++ b/templates/registration.njk @@ -1,17 +1,19 @@ {% extends "base.njk" %} {% block content %} -
-
+

Register on {{ sitename }}

Already registered? Log in here.

+
Username:

Password:

- Confirm:

+ Confirm:


-
+
+ + + {% include "tos.html" %}
-
-
- {% include "tos.html" %} -
-
+ {% endblock %} \ No newline at end of file From 74c90114c71cd9d7d9b838e71dcbaeac4291abf2 Mon Sep 17 00:00:00 2001 From: knotteye Date: Tue, 3 Dec 2019 19:58:40 -0600 Subject: [PATCH 2/9] Bump Version I still don't understand pre-release versioning. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7b023d9..750ad3f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "satyr", - "version": "0.4.4", + "version": "0.5.0", "description": "A livestreaming server.", "license": "AGPL-3.0", "author": "knotteye", From 5a52308503d62e74c3ee778014d99b3cfbd254a8 Mon Sep 17 00:00:00 2001 From: knotteye Date: Wed, 4 Dec 2019 17:36:48 -0600 Subject: [PATCH 3/9] Stop using dash.js, videojs supports it natively. Modal messages also work again Turn off watch in nunjucks config (oops) Change some redirects based on logged in status. --- site/dashjs/AUTHORS.md | 49 -------------------------------- site/dashjs/LICENSE.md | 14 --------- site/dashjs/dash.all.min.js | 3 -- site/videojs/videojs-dash.min.js | 2 -- src/http.ts | 8 +++--- templates/user.njk | 2 -- 6 files changed, 4 insertions(+), 74 deletions(-) delete mode 100644 site/dashjs/AUTHORS.md delete mode 100644 site/dashjs/LICENSE.md delete mode 100644 site/dashjs/dash.all.min.js delete mode 100644 site/videojs/videojs-dash.min.js diff --git a/site/dashjs/AUTHORS.md b/site/dashjs/AUTHORS.md deleted file mode 100644 index 9488135..0000000 --- a/site/dashjs/AUTHORS.md +++ /dev/null @@ -1,49 +0,0 @@ -# Dash.js Authors List -#####Please add entries to the bottom of the list in the following format -* @GitHub UserName (Required) [Name and/or Organization] (Optional) - -#Authors -* @nweber [Digital Primates] -* @jefftapper [Jeff Tapper, Digital Primates] -* @KozhinM [Mikail Kozhin, Microsoft Open Technologies] -* @kirkshoop [Kirk Shoop, Microsoft Open Technologies] -* @wilaw [Will Law, Akamai Technologies] -* @AkamaiDASH [Dan Sparacio, Akamai Technologies] -* @dsilhavy [Daniel Silhavy, Fraunhofer Fokus] -* @greg80303 [Greg Rutz, CableLabs] -* @heff [Steve Hefferman, Brightcove] -* @Tomjohnson916 [Tom Johnson, Brightcove] -* @jeroenwiljering [Jeroen Wijering, JWPlayer] -* @bbcrddave [David Evans, BBC R&D] -* @bbert [Bertrand Berthelot, Orange] -* @vigneshvg [Vignesh Venkatasubramanian, Google] -* @nicosang [Nicolas Angot, Orange] -* @PriyadarshiniV -* @senthil-codr [Senthil] -* @dweremeichik [Dylan Weremeichik] -* @aleal-envivio -* @mconlin -* @umavinoth -* @lbonn -* @mdale [Michael Dale, Kaltura] -* @sgrebnov [Sergey Grebnov, Microsoft Open Technologies] -* @wesleytodd [Wes Todd, Vubeology] -* @colde [Loke Dupont, Xstream] -* @rgardler [Ross Gardler, Microsoft Open Technologies] -* @squapp -* @xiaomings -* @rcollins112 [Rich Collins, Wowza] -* @timothy003 [Timothy Liang] -* @JaapHaitsma -* @72lions [Thodoris Tsiridis, 72lions] -* @TobbeMobiTV [Torbjörn Einarsson, MobiTV] -* @TobbeEdgeware [Torbjörn Einarsson, Edgeware] -* @mstorsjo [Martin Storsjö] -* @Hyddan [Daniel Hedenius] -* @qjia7 -* @waqarz -* @WMSPanel [WMSPanel Team] -* @matt-hammond-bbc [Matt Hammond, BBC R&D] -* @siropeich [Siro Blanco, Epic Labs] -* @epiclabsDASH [Jesus Oliva, Epic Labs] -* @adripanico [Adrian Caballero, Epic Labs] diff --git a/site/dashjs/LICENSE.md b/site/dashjs/LICENSE.md deleted file mode 100644 index f7517a4..0000000 --- a/site/dashjs/LICENSE.md +++ /dev/null @@ -1,14 +0,0 @@ -# dash.js BSD License Agreement - -The copyright in this software is being made available under the BSD License, included below. This software may be subject to other third party and contributor rights, including patent rights, and no such rights are granted under this license. - -**Copyright (c) 2015, Dash Industry Forum. -**All rights reserved.** - -* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -* Neither the name of the Dash Industry Forum nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -**THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.** - \ No newline at end of file diff --git a/site/dashjs/dash.all.min.js b/site/dashjs/dash.all.min.js deleted file mode 100644 index 6b18d5e..0000000 --- a/site/dashjs/dash.all.min.js +++ /dev/null @@ -1,3 +0,0 @@ -/*! v3.0.0-b0f46e83, 2019-06-29T00:07:30Z */ -!function a(o,s,u){function l(t,e){if(!s[t]){if(!o[t]){var n="function"==typeof require&&require;if(!e&&n)return n(t,!0);if(f)return f(t,!0);var r=new Error("Cannot find module '"+t+"'");throw r.code="MODULE_NOT_FOUND",r}var i=s[t]={exports:{}};o[t][0].call(i.exports,function(e){return l(o[t][1][e]||e)},i,i.exports,a,o,s,u)}return s[t].exports}for(var f="function"==typeof require&&require,e=0;e>6):(r<65536?t.push(224|r>>12):(t.push(240|r>>18),t.push(128|63&r>>12)),t.push(128|63&r>>6)),t.push(128|63&r))}return t},decode:function(e){for(var t=[],n=0;n>18)),n.push(o.charAt(63&i>>12)),n.push(o.charAt(63&i>>6)),n.push(o.charAt(63&i))}if(2==e.length-t){i=(e[t]<<16)+(e[t+1]<<8);n.push(o.charAt(63&i>>18)),n.push(o.charAt(63&i>>12)),n.push(o.charAt(63&i>>6)),n.push("=")}else if(1==e.length-t){i=e[t]<<16;n.push(o.charAt(63&i>>18)),n.push(o.charAt(63&i>>12)),n.push("==")}return n.join("")}function d(e){for(var t=0,n=[],r=0|e.length/4;0>16),n.push(255&i>>8),n.push(255&i),t+=4}return n&&("="==e.charAt(t-2)?(n.pop(),n.pop()):"="==e.charAt(t-1)&&n.pop()),n}o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",u=function(){for(var e=[],t=0;t=n&&console.log(this.time+" ["+e+"] "+t)}};o.prototype={reset:function(){this.foreground="white",this.underline=!1,this.italics=!1,this.background="black",this.flash=!1},setStyles:function(e){for(var t=["foreground","underline","italics","background","flash"],n=0;n ("+u([r,i])+")"),!(n=(n=(n=(n=this.parseCmd(r,i))||this.parseMidrow(r,i))||this.parsePAC(r,i))||this.parseBackgroundAttributes(r,i)))if(a=this.parseChars(r,i))if(this.currChNr&&0<=this.currChNr)this.channels[this.currChNr-1].insertChars(a);else h.log("WARNING","No channel found yet. TEXT-MODE?");n?this.dataCounters.cmd+=2:a?this.dataCounters.char+=2:(this.dataCounters.other+=2,h.log("WARNING","Couldn't parse cleaned data "+u([r,i])+" orig: "+u([t[o],t[o+1]])))}else this.dataCounters.padding+=2},parseCmd:function(e,t){var n=null;if(!((20===e||21===e||28===e||29===e)&&32<=t&&t<=47)&&!((23===e||31===e)&&33<=t&&t<=35))return!1;n=20===e||21===e||23===e?1:2;var r=this.channels[n-1];return 20===e||21===e||28===e||29===e?32===t?r.cc_RCL():33===t?r.cc_BS():34===t?r.cc_AOF():35===t?r.cc_AON():36===t?r.cc_DER():37===t?r.cc_RU(2):38===t?r.cc_RU(3):39===t?r.cc_RU(4):40===t?r.cc_FON():41===t?r.cc_RDC():42===t?r.cc_TR():43===t?r.cc_RTD():44===t?r.cc_EDM():45===t?r.cc_CR():46===t?r.cc_ENM():47===t&&r.cc_EOC():r.cc_TO(t-32),this.lastCmdA=e,this.lastCmdB=t,this.currChNr=n,!0},parseMidrow:function(e,t){var n=null;if((17===e||25===e)&&32<=t&&t<=47){if((n=17===e?1:2)!==this.currChNr)return h.log("ERROR","Mismatch channel in midrow parsing"),!1;var r=this.channels[n-1];return r.insertChars([32]),r.cc_MIDROW(t),h.log("DEBUG","MIDROW ("+u([e,t])+")"),this.lastCmdA=e,this.lastCmdB=t,!0}return!1},parsePAC:function(e,t){var n,r=null;if(!((17<=e&&e<=23||25<=e&&e<=31)&&64<=t&&t<=127)&&!((16===e||24===e)&&64<=t&&t<=95))return!1;n=e<=23?1:2,r=64<=t&&t<=95?1==n?a[e]:f[e]:1==n?l[e]:d[e];var i=this.interpretPAC(r,t);return this.channels[n-1].setPAC(i),this.lastCmdA=e,this.lastCmdB=t,this.currChNr=n,!0},interpretPAC:function(e,t){var n=t,r={color:null,italics:!1,indent:null,underline:!1,row:e};return n=95/g,">").replace(/"/g,""").replace(/'/g,"'"):e}function R(e,t,n,r){for(var i=0;i":">"}function f(e,t){return""}function d(e,t){return!!("property"==A.arrayAccessForm&&function(e,t){return-1!==e.indexOf(t,e.length-t.length)}(t.toString(),"_asArray")||0==t.toString().indexOf(A.attributePrefix)||0==t.toString().indexOf("__")||e[t]instanceof Function)}function c(e){var t=0;if(e instanceof Object)for(var n in e)d(e,n)||t++;return t}function h(e){var t=[];if(e instanceof Object)for(var n in e)-1==n.toString().indexOf("__")&&0==n.toString().indexOf(A.attributePrefix)&&t.push(n);return t}function p(e){var t="";return e instanceof Object?t+=function(e){var t="";return null!=e.__cdata&&(t+=""),null!=e.__text&&(A.escapeMode?t+=u(e.__text):t+=e.__text),t}(e):null!=e&&(A.escapeMode?t+=u(e):t+=e),t}function g(e,t){return""===e?t:e+"."+t}function _(e,t,n,r){var i="";if(0==e.length)i+=l(e,t,n,!0);else for(var a=0;a")+2)),(t=new ActiveXObject("Microsoft.XMLDOM")).async="false",t.loadXML(e);return t},this.asArray=function(e){return void 0===e||null==e?[]:e instanceof Array?e:[e]},this.toXmlDateTime=function(e){return e instanceof Date?e.toISOString():"number"==typeof e?new Date(e).toISOString():null},this.asDateTime=function(e){return"string"==typeof e?M(e):e},this.xml2json=function(e){return C(e)},this.xml_str2json=function(e){var t=this.parseXmlString(e);return null!=t?this.xml2json(t):null},this.json2xml_str=function(e){return m(e,"")},this.json2xml=function(e){var t=this.json2xml_str(e);return this.parseXmlString(t)},this.getVersion=function(){return"1.2.0"}},t.exports=n.default},{}],4:[function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(n,"__esModule",{value:!0});var i=e(5),a=r(e(125)),o=r(e(159)),s=r(e(103)),u=r(e(47));dashjs.Protection=o.default,dashjs.MetricsReporting=a.default,dashjs.MediaPlayerFactory=s.default,dashjs.Debug=u.default,n.default=dashjs,n.MediaPlayer=i.MediaPlayer,n.Protection=o.default,n.MetricsReporting=a.default,n.MediaPlayerFactory=s.default,n.Debug=u.default},{103:103,125:125,159:159,47:47,5:5}],5:[function(u,e,l){(function(e){"use strict";function t(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(l,"__esModule",{value:!0});var n=t(u(101)),r=t(u(49)),i=t(u(47)),a=u(52),o="undefined"!=typeof window&&window||e,s=o.dashjs;(s=s||(o.dashjs={})).MediaPlayer=n.default,s.FactoryMaker=r.default,s.Debug=i.default,s.Version=(0,a.getVersionString)(),l.default=s,l.MediaPlayer=n.default,l.FactoryMaker=r.default,l.Debug=i.default}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{101:101,47:47,49:49,52:52}],6:[function(e,t,n){"use strict";n.byteLength=function(e){var t=d(e),n=t[0],r=t[1];return 3*(n+r)/4-r},n.toByteArray=function(e){for(var t,n=d(e),r=n[0],i=n[1],a=new f(function(e,t,n){return 3*(t+n)/4-n}(0,r,i)),o=0,s=0>16&255,a[o++]=t>>8&255,a[o++]=255&t;2===i&&(t=l[e.charCodeAt(u)]<<2|l[e.charCodeAt(u+1)]>>4,a[o++]=255&t);1===i&&(t=l[e.charCodeAt(u)]<<10|l[e.charCodeAt(u+1)]<<4|l[e.charCodeAt(u+2)]>>2,a[o++]=t>>8&255,a[o++]=255&t);return a},n.fromByteArray=function(e){for(var t,n=e.length,r=n%3,i=[],a=0,o=n-r;a>2]+s[t<<4&63]+"==")):2==r&&(t=(e[n-2]<<8)+e[n-1],i.push(s[t>>10]+s[t>>4&63]+s[t<<2&63]+"="));return i.join("")};for(var s=[],l=[],f="undefined"!=typeof Uint8Array?Uint8Array:Array,r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",i=0,a=r.length;i>18&63]+s[i>>12&63]+s[i>>6&63]+s[63&i]);return a.join("")}l["-".charCodeAt(0)]=62,l["_".charCodeAt(0)]=63},{}],7:[function(e,t,n){},{}],8:[function(e,t,n){"use strict";var r=e(6),a=e(12);n.Buffer=d,n.SlowBuffer=function(e){+e!=e&&(e=0);return d.alloc(+e)},n.INSPECT_MAX_BYTES=50;var i=2147483647;function o(e){if(i>>1;case"base64":return L(e).length;default:if(i)return r?-1:P(e).length;t=(""+t).toLowerCase(),i=!0}}function p(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function g(e,t,n,r,i){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):2147483647=e.length){if(i)return-1;n=e.length-1}else if(n<0){if(!i)return-1;n=0}if("string"==typeof t&&(t=d.from(t,r)),d.isBuffer(t))return 0===t.length?-1:_(e,t,n,r,i);if("number"==typeof t)return t&=255,"function"==typeof Uint8Array.prototype.indexOf?i?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):_(e,[t],n,r,i);throw new TypeError("val must be string, number or Buffer")}function _(e,t,n,r,i){var a,o=1,s=e.length,u=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;s/=o=2,u/=2,n/=2}function l(e,t){return 1===o?e[t]:e.readUInt16BE(t*o)}if(i){var f=-1;for(a=n;a>>10&1023|55296),f=56320|1023&f),r.push(f),i+=d}return function(e){var t=e.length;if(t<=T)return String.fromCharCode.apply(String,e);var n="",r=0;for(;rthis.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if((n>>>=0)<=(t>>>=0))return"";for(e=e||"utf8";;)switch(e){case"hex":return I(this,t,n);case"utf8":case"utf-8":return y(this,t,n);case"ascii":return S(this,t,n);case"latin1":case"binary":return A(this,t,n);case"base64":return v(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return b(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}.apply(this,arguments)},d.prototype.equals=function(e){if(!d.isBuffer(e))throw new TypeError("Argument must be a Buffer");return this===e||0===d.compare(this,e)},d.prototype.inspect=function(){var e="",t=n.INSPECT_MAX_BYTES;return e=this.toString("hex",0,t).replace(/(.{2})/g,"$1 ").trim(),this.length>t&&(e+=" ... "),""},d.prototype.compare=function(e,t,n,r,i){if(F(e,Uint8Array)&&(e=d.from(e,e.offset,e.byteLength)),!d.isBuffer(e))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof e);if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===i&&(i=this.length),t<0||n>e.length||r<0||i>this.length)throw new RangeError("out of range index");if(i<=r&&n<=t)return 0;if(i<=r)return-1;if(n<=t)return 1;if(this===e)return 0;for(var a=(i>>>=0)-(r>>>=0),o=(n>>>=0)-(t>>>=0),s=Math.min(a,o),u=this.slice(r,i),l=e.slice(t,n),f=0;f>>=0,isFinite(n)?(n>>>=0,void 0===r&&(r="utf8")):(r=n,n=void 0)}var i=this.length-t;if((void 0===n||ithis.length)throw new RangeError("Attempt to write outside buffer bounds");r=r||"utf8";for(var a,o,s,u,l,f,d,c,h,p=!1;;)switch(r){case"hex":return m(this,e,t,n);case"utf8":case"utf-8":return c=t,h=n,x(P(e,(d=this).length-c),d,c,h);case"ascii":return E(this,e,t,n);case"latin1":case"binary":return E(this,e,t,n);case"base64":return u=this,l=t,f=n,x(L(e),u,l,f);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return o=t,s=n,x(function(e,t){for(var n,r,i,a=[],o=0;o>8,i=n%256,a.push(i),a.push(r);return a}(e,(a=this).length-o),a,o,s);default:if(p)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),p=!0}},d.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var T=4096;function S(e,t,n){var r="";n=Math.min(e.length,n);for(var i=t;ie.length)throw new RangeError("Index out of range")}function M(e,t,n,r){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function C(e,t,n,r,i){return t=+t,n>>>=0,i||M(e,0,n,4),a.write(e,t,n,r,23,4),n+4}function w(e,t,n,r,i){return t=+t,n>>>=0,i||M(e,0,n,8),a.write(e,t,n,r,52,8),n+8}d.prototype.slice=function(e,t){var n=this.length;(e=~~e)<0?(e+=n)<0&&(e=0):n>>=0,t>>>=0,n||R(e,t,this.length);for(var r=this[e],i=1,a=0;++a>>=0,t>>>=0,n||R(e,t,this.length);for(var r=this[e+--t],i=1;0>>=0,t||R(e,1,this.length),this[e]},d.prototype.readUInt16LE=function(e,t){return e>>>=0,t||R(e,2,this.length),this[e]|this[e+1]<<8},d.prototype.readUInt16BE=function(e,t){return e>>>=0,t||R(e,2,this.length),this[e]<<8|this[e+1]},d.prototype.readUInt32LE=function(e,t){return e>>>=0,t||R(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},d.prototype.readUInt32BE=function(e,t){return e>>>=0,t||R(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},d.prototype.readIntLE=function(e,t,n){e>>>=0,t>>>=0,n||R(e,t,this.length);for(var r=this[e],i=1,a=0;++a>>=0,t>>>=0,n||R(e,t,this.length);for(var r=t,i=1,a=this[e+--r];0>>=0,t||R(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},d.prototype.readInt16LE=function(e,t){e>>>=0,t||R(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},d.prototype.readInt16BE=function(e,t){e>>>=0,t||R(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},d.prototype.readInt32LE=function(e,t){return e>>>=0,t||R(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},d.prototype.readInt32BE=function(e,t){return e>>>=0,t||R(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},d.prototype.readFloatLE=function(e,t){return e>>>=0,t||R(e,4,this.length),a.read(this,e,!0,23,4)},d.prototype.readFloatBE=function(e,t){return e>>>=0,t||R(e,4,this.length),a.read(this,e,!1,23,4)},d.prototype.readDoubleLE=function(e,t){return e>>>=0,t||R(e,8,this.length),a.read(this,e,!0,52,8)},d.prototype.readDoubleBE=function(e,t){return e>>>=0,t||R(e,8,this.length),a.read(this,e,!1,52,8)},d.prototype.writeUIntLE=function(e,t,n,r){e=+e,t>>>=0,n>>>=0,r||D(this,e,t,n,Math.pow(2,8*n)-1,0);var i=1,a=0;for(this[t]=255&e;++a>>=0,n>>>=0,r||D(this,e,t,n,Math.pow(2,8*n)-1,0);var i=n-1,a=1;for(this[t+i]=255&e;0<=--i&&(a*=256);)this[t+i]=e/a&255;return t+n},d.prototype.writeUInt8=function(e,t,n){return e=+e,t>>>=0,n||D(this,e,t,1,255,0),this[t]=255&e,t+1},d.prototype.writeUInt16LE=function(e,t,n){return e=+e,t>>>=0,n||D(this,e,t,2,65535,0),this[t]=255&e,this[t+1]=e>>>8,t+2},d.prototype.writeUInt16BE=function(e,t,n){return e=+e,t>>>=0,n||D(this,e,t,2,65535,0),this[t]=e>>>8,this[t+1]=255&e,t+2},d.prototype.writeUInt32LE=function(e,t,n){return e=+e,t>>>=0,n||D(this,e,t,4,4294967295,0),this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e,t+4},d.prototype.writeUInt32BE=function(e,t,n){return e=+e,t>>>=0,n||D(this,e,t,4,4294967295,0),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e,t+4},d.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t>>>=0,!r){var i=Math.pow(2,8*n-1);D(this,e,t,n,i-1,-i)}var a=0,o=1,s=0;for(this[t]=255&e;++a>0)-s&255;return t+n},d.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t>>>=0,!r){var i=Math.pow(2,8*n-1);D(this,e,t,n,i-1,-i)}var a=n-1,o=1,s=0;for(this[t+a]=255&e;0<=--a&&(o*=256);)e<0&&0===s&&0!==this[t+a+1]&&(s=1),this[t+a]=(e/o>>0)-s&255;return t+n},d.prototype.writeInt8=function(e,t,n){return e=+e,t>>>=0,n||D(this,e,t,1,127,-128),e<0&&(e=255+e+1),this[t]=255&e,t+1},d.prototype.writeInt16LE=function(e,t,n){return e=+e,t>>>=0,n||D(this,e,t,2,32767,-32768),this[t]=255&e,this[t+1]=e>>>8,t+2},d.prototype.writeInt16BE=function(e,t,n){return e=+e,t>>>=0,n||D(this,e,t,2,32767,-32768),this[t]=e>>>8,this[t+1]=255&e,t+2},d.prototype.writeInt32LE=function(e,t,n){return e=+e,t>>>=0,n||D(this,e,t,4,2147483647,-2147483648),this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24,t+4},d.prototype.writeInt32BE=function(e,t,n){return e=+e,t>>>=0,n||D(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e,t+4},d.prototype.writeFloatLE=function(e,t,n){return C(this,e,t,!0,n)},d.prototype.writeFloatBE=function(e,t,n){return C(this,e,t,!1,n)},d.prototype.writeDoubleLE=function(e,t,n){return w(this,e,t,!0,n)},d.prototype.writeDoubleBE=function(e,t,n){return w(this,e,t,!1,n)},d.prototype.copy=function(e,t,n,r){if(!d.isBuffer(e))throw new TypeError("argument should be a Buffer");if(n=n||0,r||0===r||(r=this.length),t>=e.length&&(t=e.length),t=t||0,0=this.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t>>=0,n=void 0===n?this.length:n>>>0,"number"==typeof(e=e||0))for(a=t;a>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;a.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;a.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return a}function L(e){return r.toByteArray(function(e){if((e=(e=e.split("=")[0]).trim().replace(O,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function x(e,t,n,r){for(var i=0;i=t.length||i>=e.length);++i)t[i+n]=e[i];return i}function F(e,t){return e instanceof t||null!=e&&null!=e.constructor&&null!=e.constructor.name&&e.constructor.name===t.name}function U(e){return e!=e}},{12:12,6:6}],9:[function(e,t,n){var i={parseBuffer:function(e){return new a(e).parse()},addBoxProcessor:function(e,t){"string"==typeof e&&"function"==typeof t&&(o.prototype._boxProcessors[e]=t)},createFile:function(){return new a},createBox:function(e,t,n){var r=o.create(e);return t&&t.append(r,n),r},createFullBox:function(e,t,n){var r=i.createBox(e,t,n);return r.version=0,r.flags=0,r},Utils:{}};i.Utils.dataViewToString=function(e,t){var n=t||"utf-8";if("undefined"!=typeof TextDecoder)return new TextDecoder(n).decode(e);var r=[],i=0;if("utf-8"===n)for(;i>6):(r<65536?t.push(224|r>>12):(t.push(240|r>>18),t.push(128|63&r>>12)),t.push(128|63&r>>6)),t.push(128|63&r))}return t},i.Utils.appendBox=function(e,t,n){if(t._offset=e._cursor.offset,t._root=e._root?e._root:e,t._raw=e._raw,t._parent=e,-1!==n)if(null!=n){var r,i=-1;if("number"==typeof n)i=n;else{if("string"==typeof n)r=n;else{if("object"!=typeof n||!n.type)return void e.boxes.push(t);r=n.type}for(var a=0;a>3,t},o.prototype._readUint=function(e){var t,n,r=null,i=this._cursor.offset-this._raw.byteOffset;switch(e){case 8:r=this._raw.getUint8(i);break;case 16:r=this._raw.getUint16(i);break;case 24:r=((t=this._raw.getUint16(i))<<8)+(n=this._raw.getUint8(2+i));break;case 32:r=this._raw.getUint32(i);break;case 64:t=this._raw.getUint32(i),n=this._raw.getUint32(4+i),r=t*Math.pow(2,32)+n}return this._cursor.offset+=e>>3,r},o.prototype._readString=function(e){for(var t="",n=0;nthis._raw.buffer.byteLength)this._root._incomplete=!0;else{switch(this._procField("size","uint",32),this._procField("type","string",4),1===this.size&&this._procField("largesize","uint",64),"uuid"===this.type&&this._procFieldArray("usertype",16,"uint",8),this.size){case 0:this._raw=new DataView(this._raw.buffer,this._offset,this._raw.byteLength-this._cursor.offset+8);break;case 1:this._offset+this.size>this._raw.buffer.byteLength?(this._incomplete=!0,this._root._incomplete=!0):this._raw=new DataView(this._raw.buffer,this._offset,this.largesize);break;default:this._offset+this.size>this._raw.buffer.byteLength?(this._incomplete=!0,this._root._incomplete=!0):this._raw=new DataView(this._raw.buffer,this._offset,this.size)}this._incomplete||(this._boxProcessors[this.type]&&this._boxProcessors[this.type].call(this),-1!==this._boxContainers.indexOf(this.type)?this._parseContainerBox():this._data=this._readData())}},o.prototype._parseFullBox=function(){this.version=this._readUint(8),this.flags=this._readUint(24)},o.prototype._parseContainerBox=function(){for(this.boxes=[];this._cursor.offset-this._raw.byteOffset>3}else this.size+=e>>3},o.prototype._writeUint=function(e,t){if(this._rawo){var n,r,i=this._cursor.offset-this._rawo.byteOffset;switch(e){case 8:this._rawo.setUint8(i,t);break;case 16:this._rawo.setUint16(i,t);break;case 24:n=(16776960&t)>>8,r=255&t,this._rawo.setUint16(i,n),this._rawo.setUint8(2+i,r);break;case 32:this._rawo.setUint32(i,t);break;case 64:r=t-(n=Math.floor(t/Math.pow(2,32)))*Math.pow(2,32),this._rawo.setUint32(i,n),this._rawo.setUint32(4+i,r)}this._cursor.offset+=e>>3}else this.size+=e>>3},o.prototype._writeString=function(e,t){for(var n=0;n>10&31),96+(this.language>>5&31),96+(31&this.language))),this._procField("pre_defined","uint",16)},o.prototype._boxProcessors.mehd=function(){this._procFullBox(),this._procField("fragment_duration","uint",1==this.version?64:32)},o.prototype._boxProcessors.mfhd=function(){this._procFullBox(),this._procField("sequence_number","uint",32)},o.prototype._boxProcessors.mfro=function(){this._procFullBox(),this._procField("mfra_size","uint",32)},o.prototype._boxProcessors.mp4a=o.prototype._boxProcessors.enca=function(){this._procFieldArray("reserved1",6,"uint",8),this._procField("data_reference_index","uint",16),this._procFieldArray("reserved2",2,"uint",32),this._procField("channelcount","uint",16),this._procField("samplesize","uint",16),this._procField("pre_defined","uint",16),this._procField("reserved3","uint",16),this._procField("samplerate","template",32),this._procField("esds","data",-1)},o.prototype._boxProcessors.mvhd=function(){this._procFullBox(),this._procField("creation_time","uint",1==this.version?64:32),this._procField("modification_time","uint",1==this.version?64:32),this._procField("timescale","uint",32),this._procField("duration","uint",1==this.version?64:32),this._procField("rate","template",32),this._procField("volume","template",16),this._procField("reserved1","uint",16),this._procFieldArray("reserved2",2,"uint",32),this._procFieldArray("matrix",9,"template",32),this._procFieldArray("pre_defined",6,"uint",32),this._procField("next_track_ID","uint",32)},o.prototype._boxProcessors.payl=function(){this._procField("cue_text","utf8")},o.prototype._boxProcessors.pssh=function(){this._procFullBox(),this._procFieldArray("SystemID",16,"uint",8),this._procField("DataSize","uint",32),this._procFieldArray("Data",this.DataSize,"uint",8)},o.prototype._boxProcessors.schm=function(){this._procFullBox(),this._procField("scheme_type","uint",32),this._procField("scheme_version","uint",32),1&this.flags&&this._procField("scheme_uri","string",-1)},o.prototype._boxProcessors.sdtp=function(){this._procFullBox();var e=-1;this._parsing&&(e=this._raw.byteLength-(this._cursor.offset-this._raw.byteOffset)),this._procFieldArray("sample_dependency_table",e,"uint",8)},o.prototype._boxProcessors.sidx=function(){this._procFullBox(),this._procField("reference_ID","uint",32),this._procField("timescale","uint",32),this._procField("earliest_presentation_time","uint",1==this.version?64:32),this._procField("first_offset","uint",1==this.version?64:32),this._procField("reserved","uint",16),this._procField("reference_count","uint",16),this._procEntries("references",this.reference_count,function(e){this._parsing||(e.reference=(1&e.reference_type)<<31,e.reference|=2147483647&e.referenced_size,e.sap=(1&e.starts_with_SAP)<<31,e.sap|=(3&e.SAP_type)<<28,e.sap|=268435455&e.SAP_delta_time),this._procEntryField(e,"reference","uint",32),this._procEntryField(e,"subsegment_duration","uint",32),this._procEntryField(e,"sap","uint",32),this._parsing&&(e.reference_type=e.reference>>31&1,e.referenced_size=2147483647&e.reference,e.starts_with_SAP=e.sap>>31&1,e.SAP_type=e.sap>>28&7,e.SAP_delta_time=268435455&e.sap)})},o.prototype._boxProcessors.smhd=function(){this._procFullBox(),this._procField("balance","uint",16),this._procField("reserved","uint",16)},o.prototype._boxProcessors.ssix=function(){this._procFullBox(),this._procField("subsegment_count","uint",32),this._procEntries("subsegments",this.subsegment_count,function(e){this._procEntryField(e,"ranges_count","uint",32),this._procSubEntries(e,"ranges",e.ranges_count,function(e){this._procEntryField(e,"level","uint",8),this._procEntryField(e,"range_size","uint",24)})})},o.prototype._boxProcessors.stsd=function(){this._procFullBox(),this._procField("entry_count","uint",32),this._procSubBoxes("entries",this.entry_count)},o.prototype._boxProcessors.subs=function(){this._procFullBox(),this._procField("entry_count","uint",32),this._procEntries("entries",this.entry_count,function(e){this._procEntryField(e,"sample_delta","uint",32),this._procEntryField(e,"subsample_count","uint",16),this._procSubEntries(e,"subsamples",e.subsample_count,function(e){this._procEntryField(e,"subsample_size","uint",1===this.version?32:16),this._procEntryField(e,"subsample_priority","uint",8),this._procEntryField(e,"discardable","uint",8),this._procEntryField(e,"codec_specific_parameters","uint",32)})})},o.prototype._boxProcessors.tenc=function(){this._procFullBox(),this._procField("default_IsEncrypted","uint",24),this._procField("default_IV_size","uint",8),this._procFieldArray("default_KID",16,"uint",8)},o.prototype._boxProcessors.tfdt=function(){this._procFullBox(),this._procField("baseMediaDecodeTime","uint",1==this.version?64:32)},o.prototype._boxProcessors.tfhd=function(){this._procFullBox(),this._procField("track_ID","uint",32),1&this.flags&&this._procField("base_data_offset","uint",64),2&this.flags&&this._procField("sample_description_offset","uint",32),8&this.flags&&this._procField("default_sample_duration","uint",32),16&this.flags&&this._procField("default_sample_size","uint",32),32&this.flags&&this._procField("default_sample_flags","uint",32)},o.prototype._boxProcessors.tfra=function(){this._procFullBox(),this._procField("track_ID","uint",32),this._parsing||(this.reserved=0,this.reserved|=(48&this.length_size_of_traf_num)<<4,this.reserved|=(12&this.length_size_of_trun_num)<<2,this.reserved|=3&this.length_size_of_sample_num),this._procField("reserved","uint",32),this._parsing&&(this.length_size_of_traf_num=(48&this.reserved)>>4,this.length_size_of_trun_num=(12&this.reserved)>>2,this.length_size_of_sample_num=3&this.reserved),this._procField("number_of_entry","uint",32),this._procEntries("entries",this.number_of_entry,function(e){this._procEntryField(e,"time","uint",1===this.version?64:32),this._procEntryField(e,"moof_offset","uint",1===this.version?64:32),this._procEntryField(e,"traf_number","uint",8*(this.length_size_of_traf_num+1)),this._procEntryField(e,"trun_number","uint",8*(this.length_size_of_trun_num+1)),this._procEntryField(e,"sample_number","uint",8*(this.length_size_of_sample_num+1))})},o.prototype._boxProcessors.tkhd=function(){this._procFullBox(),this._procField("creation_time","uint",1==this.version?64:32),this._procField("modification_time","uint",1==this.version?64:32),this._procField("track_ID","uint",32),this._procField("reserved1","uint",32),this._procField("duration","uint",1==this.version?64:32),this._procFieldArray("reserved2",2,"uint",32),this._procField("layer","uint",16),this._procField("alternate_group","uint",16),this._procField("volume","template",16),this._procField("reserved3","uint",16),this._procFieldArray("matrix",9,"template",32),this._procField("width","template",32),this._procField("height","template",32)},o.prototype._boxProcessors.trex=function(){this._procFullBox(),this._procField("track_ID","uint",32),this._procField("default_sample_description_index","uint",32),this._procField("default_sample_duration","uint",32),this._procField("default_sample_size","uint",32),this._procField("default_sample_flags","uint",32)},o.prototype._boxProcessors.trun=function(){this._procFullBox(),this._procField("sample_count","uint",32),1&this.flags&&this._procField("data_offset","int",32),4&this.flags&&this._procField("first_sample_flags","uint",32),this._procEntries("samples",this.sample_count,function(e){256&this.flags&&this._procEntryField(e,"sample_duration","uint",32),512&this.flags&&this._procEntryField(e,"sample_size","uint",32),1024&this.flags&&this._procEntryField(e,"sample_flags","uint",32),2048&this.flags&&this._procEntryField(e,"sample_composition_time_offset",1===this.version?"int":"uint",32)})},o.prototype._boxProcessors["url "]=o.prototype._boxProcessors["urn "]=function(){this._procFullBox(),"urn "===this.type&&this._procField("name","string",-1),this._procField("location","string",-1)},o.prototype._boxProcessors.vlab=function(){this._procField("source_label","utf8")},o.prototype._boxProcessors.vmhd=function(){this._procFullBox(),this._procField("graphicsmode","uint",16),this._procFieldArray("opcolor",3,"uint",16)},o.prototype._boxProcessors.vttC=function(){this._procField("config","utf8")},o.prototype._boxProcessors.vtte=function(){}},{}],10:[function(e,t,n){var u=Object.create||function(e){function t(){}return t.prototype=e,new t},o=Object.keys||function(e){var t=[];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&t.push(n);return n},a=Function.prototype.bind||function(e){var t=this;return function(){return t.apply(e,arguments)}};function r(){this._events&&Object.prototype.hasOwnProperty.call(this,"_events")||(this._events=u(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0}((t.exports=r).EventEmitter=r).prototype._events=void 0,r.prototype._maxListeners=void 0;var i,s=10;try{var l={};Object.defineProperty&&Object.defineProperty(l,"x",{value:0}),i=0===l.x}catch(e){i=!1}function f(e){return void 0===e._maxListeners?r.defaultMaxListeners:e._maxListeners}function d(e,t,n,r){var i,a,o;if("function"!=typeof n)throw new TypeError('"listener" argument must be a function');if((a=e._events)?(a.newListener&&(e.emit("newListener",t,n.listener?n.listener:n),a=e._events),o=a[t]):(a=e._events=u(null),e._eventsCount=0),o){if("function"==typeof o?o=a[t]=r?[n,o]:[o,n]:r?o.unshift(n):o.push(n),!o.warned&&(i=f(e))&&0i){o.warned=!0;var s=new Error("Possible EventEmitter memory leak detected. "+o.length+' "'+String(t)+'" listeners added. Use emitter.setMaxListeners() to increase limit.');s.name="MaxListenersExceededWarning",s.emitter=e,s.type=t,s.count=o.length,"object"==typeof console&&console.warn&&console.warn("%s: %s",s.name,s.message)}}else o=a[t]=n,++e._eventsCount;return e}function c(){if(!this.fired)switch(this.target.removeListener(this.type,this.wrapFn),this.fired=!0,arguments.length){case 0:return this.listener.call(this.target);case 1:return this.listener.call(this.target,arguments[0]);case 2:return this.listener.call(this.target,arguments[0],arguments[1]);case 3:return this.listener.call(this.target,arguments[0],arguments[1],arguments[2]);default:for(var e=new Array(arguments.length),t=0;t>1,f=-7,d=n?i-1:0,c=n?-1:1,h=e[t+d];for(d+=c,a=h&(1<<-f)-1,h>>=-f,f+=s;0>=-f,f+=r;0>1,c=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,h=r?0:a-1,p=r?1:-1,g=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(s=isNaN(t)?1:0,o=f):(o=Math.floor(Math.log(t)/Math.LN2),t*(u=Math.pow(2,-o))<1&&(o--,u*=2),2<=(t+=1<=o+d?c/u:c*Math.pow(2,1-d))*u&&(o++,u/=2),f<=o+d?(s=0,o=f):1<=o+d?(s=(t*u-1)*Math.pow(2,i),o+=d):(s=t*Math.pow(2,d-1)*Math.pow(2,i),o=0));8<=i;e[n+h]=255&s,h+=p,s/=256,i-=8);for(o=o< elements at ("+this.line+","+this.column+")"),(v=new T).initFromNode(e,h),g.unshift(v);else if("head"===e.local)g[0]instanceof T||F(h,"Parent of element is not at ("+this.line+","+this.column+")"),null!==v.head&&F("Second element at ("+this.line+","+this.column+")"),v.head=new S,g.unshift(v.head);else if("styling"===e.local)g[0]instanceof S||F(h,"Parent of element is not at ("+this.line+","+this.column+")"),null!==v.head.styling&&F("Second element at ("+this.line+","+this.column+")"),v.head.styling=new A,g.unshift(v.head.styling);else if("style"===e.local){var r;g[0]instanceof A?((r=new I).initFromNode(e,h),r.id?v.head.styling.styles[r.id]=r:x(h,"