From a5c1adfffcf7b27c79d18d9e42d4b0fe195269a0 Mon Sep 17 00:00:00 2001 From: knotteye Date: Sat, 17 Oct 2020 05:12:41 -0500 Subject: [PATCH 01/16] Return live flag as well when getting user info --- src/api.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api.ts b/src/api.ts index 27b0d68..f1e40a2 100644 --- a/src/api.ts +++ b/src/api.ts @@ -86,7 +86,7 @@ async function getConfig(username: string, all?: boolean): Promise{ if(all) { let users = await db.query('SELECT stream_key,record_flag FROM users WHERE username='+db.raw.escape(username)); if(users[0]) Object.assign(t, users[0]); - let usermeta = await db.query('SELECT title,about FROM user_meta WHERE username='+db.raw.escape(username)); + let usermeta = await db.query('SELECT title,about,live FROM user_meta WHERE username='+db.raw.escape(username)); if(usermeta[0]) Object.assign(t, usermeta[0]); let ci = await db.query('SELECT irc,xmpp,twitch,discord FROM chat_integration WHERE username='+db.raw.escape(username)); if(ci[0]) Object.assign(t, ci[0]); @@ -94,7 +94,7 @@ async function getConfig(username: string, all?: boolean): Promise{ if(tw[0]) t['twitch_mirror'] = Object.assign({}, tw[0]); } else { - let um = await db.query('SELECT title,about FROM user_meta WHERE username='+db.raw.escape(username)); + let um = await db.query('SELECT title,about,live FROM user_meta WHERE username='+db.raw.escape(username)); if(um[0]) Object.assign(t, um[0]); } return t; From 56c4b94a80e026c2d68226511c0f3a44e969f0fe Mon Sep 17 00:00:00 2001 From: knotteye Date: Sat, 17 Oct 2020 05:26:31 -0500 Subject: [PATCH 02/16] Fix the start video function to avoid redudant calls --- site/index.html | 5 +++-- site/index.js | 40 ++++++++++++++++++++++++++++++++++++++++ templates/user.njk | 45 ++++++++++++++++++++++++++++++++++++++------- 3 files changed, 81 insertions(+), 9 deletions(-) diff --git a/site/index.html b/site/index.html index cd6342b..d3c0047 100644 --- a/site/index.html +++ b/site/index.html @@ -3,12 +3,13 @@ + + + - {% endblock %} {% block content %} @@ -28,7 +59,7 @@ function newPopup(url) { - +
From cc3876ff4a3434267bfdaee5eb801f64b58c4548 Mon Sep 17 00:00:00 2001 From: knotteye Date: Sat, 17 Oct 2020 15:37:25 -0500 Subject: [PATCH 03/16] Update URL when navigating to new pages and push state to history in client-side SPA --- site/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/site/index.js b/site/index.js index e1fadfc..ff2bc7f 100644 --- a/site/index.js +++ b/site/index.js @@ -1,5 +1,6 @@ async function render(path){ var context = await getContext(); + history.pushState({}, context.sitename, location.protocol+'//'+location.host+path); switch(path){ //nothing but context case (path.match(/^\/about\/?$/) || {}).input: @@ -104,6 +105,9 @@ async function render(path){ case "": render('/users/live'); break; + case "/index.html": + render('/users/live'); + break; //404 default: document.body.innerHTML = nunjucks.render('404.njk', context); From 30a62e6378914808ba1c640be2e5bd7758942433 Mon Sep 17 00:00:00 2001 From: knotteye Date: Sat, 17 Oct 2020 16:02:50 -0500 Subject: [PATCH 04/16] Handle back button when the user navigates to one of our own history events --- site/index.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/site/index.js b/site/index.js index ff2bc7f..c52c1c2 100644 --- a/site/index.js +++ b/site/index.js @@ -1,6 +1,7 @@ -async function render(path){ +async function render(path, s){ var context = await getContext(); - history.pushState({}, context.sitename, location.protocol+'//'+location.host+path); + if(!s) + history.pushState({}, context.sitename, location.protocol+'//'+location.host+path); switch(path){ //nothing but context case (path.match(/^\/about\/?$/) || {}).input: @@ -115,6 +116,10 @@ async function render(path){ } } +window.addEventListener('popstate', (event) => { + render(document.location.pathname, true); +}); + async function getContext(){ var info = JSON.parse(await makeRequest('GET', '/api/instance/info')); info.sitename = info.name; From dfd0bc4881bcd90c1ce71483d09cb2fb91e3f37a Mon Sep 17 00:00:00 2001 From: knotteye Date: Sat, 17 Oct 2020 16:13:07 -0500 Subject: [PATCH 05/16] Commit a local.css file to get rid of some error messages --- site/local.css | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 site/local.css diff --git a/site/local.css b/site/local.css new file mode 100644 index 0000000..7d7d359 --- /dev/null +++ b/site/local.css @@ -0,0 +1,2 @@ +/* This file is for themeing Satyr's frontend without worrying about changes +being overwritten. Feel free to make whatever local changes you want here. */ \ No newline at end of file From 06dc05eb8bc841db9a090ea9256b4366603fdc6b Mon Sep 17 00:00:00 2001 From: knotteye Date: Sat, 17 Oct 2020 16:55:55 -0500 Subject: [PATCH 06/16] Add a dependency for xmpp mirroring and add configurability --- install/config.example.yml | 6 +- package-lock.json | 502 +++++++++++++++++++++++++++++++++++++ package.json | 1 + src/config.ts | 4 +- 4 files changed, 508 insertions(+), 5 deletions(-) diff --git a/install/config.example.yml b/install/config.example.yml index 8925c03..fcb99d8 100644 --- a/install/config.example.yml +++ b/install/config.example.yml @@ -51,10 +51,10 @@ chat: xmpp: enabled: false - server: + server: # 'example.com' port: 5222 - nickname: 'SatyrChat' - username: 'SatyrChat' + jid: # 'satyrchat@example.com' + password: # 'verysecretexample' twitch: enabled: false diff --git a/package-lock.json b/package-lock.json index c5e1872..e70e2b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,30 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.67.tgz", "integrity": "sha512-R48tgL2izApf+9rYNH+3RBMbRpPeW3N8f0I9HMhggeq4UXwBDqumJ14SDs4ctTMhG11pIOduZ4z3QWGOiMc9Vg==" }, + "@xmpp/jid": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@xmpp/jid/-/jid-0.0.2.tgz", + "integrity": "sha1-DVKMqdWNr8gzZlVk/+YvMyoxZ/I=" + }, + "@xmpp/streamparser": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@xmpp/streamparser/-/streamparser-0.0.6.tgz", + "integrity": "sha1-EYAz6p23yGoctGED8mnr/3n28eo=", + "requires": { + "@xmpp/xml": "^0.1.3", + "inherits": "^2.0.3", + "ltx": "^2.5.0" + } + }, + "@xmpp/xml": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@xmpp/xml/-/xml-0.1.3.tgz", + "integrity": "sha1-HxQ5nlPkGWiFWGmPbGLnHjmoam4=", + "requires": { + "inherits": "^2.0.3", + "ltx": "^2.6.2" + } + }, "a-sync-waterfall": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz", @@ -46,6 +70,17 @@ "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -108,6 +143,14 @@ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, "asn1.js": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.2.0.tgz", @@ -118,16 +161,41 @@ "minimalistic-assert": "^1.0.0" } }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, "async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz", + "integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==" + }, "backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" }, + "backoff": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.3.0.tgz", + "integrity": "sha1-7nx+OAk/kuRyhZ22NedlJFT8Ieo=" + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -157,6 +225,21 @@ "node-pre-gyp": "0.15.0" } }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + }, + "dependencies": { + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + } + } + }, "better-assert": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", @@ -236,6 +319,11 @@ "fill-range": "^7.0.1" } }, + "browser-request": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/browser-request/-/browser-request-0.3.3.tgz", + "integrity": "sha1-ns5bWsqJopkyJC4Yv5M975h2zBc=" + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -251,6 +339,11 @@ "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -300,6 +393,14 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", @@ -390,6 +491,14 @@ "ts-toolbelt": "^6.9.0" } }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, "dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", @@ -431,6 +540,11 @@ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -506,6 +620,15 @@ } } }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -685,6 +808,26 @@ } } }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -728,6 +871,21 @@ "resolved": "https://registry.npmjs.org/flags/-/flags-0.1.3.tgz", "integrity": "sha1-lh0vyM3zZp1jBB4w5bJK2tNvV1g=" }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -772,6 +930,14 @@ "wide-align": "^1.1.0" } }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -794,6 +960,20 @@ "is-glob": "^4.0.1" } }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, "has-binary2": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", @@ -824,6 +1004,33 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, "http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", @@ -843,6 +1050,16 @@ } } }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, "iconv": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/iconv/-/iconv-2.2.3.tgz", @@ -955,11 +1172,21 @@ "resolved": "https://registry.npmjs.org/is-port-available/-/is-port-available-0.1.5.tgz", "integrity": "sha512-/r7UZAQtfgDFdhxzM71jG0mkC4oSRA513cImMILdRe/+UOIe0Se/D/Z7XCua4AFg5k4Zt3ALMGaC1W3FzlrR2w==" }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, "jose": { "version": "1.15.1", "resolved": "https://registry.npmjs.org/jose/-/jose-1.15.1.tgz", @@ -968,11 +1195,47 @@ "asn1.js": "^5.2.0" } }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, "lodash": { "version": "4.17.20", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" + }, "lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -988,6 +1251,14 @@ "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, + "ltx": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/ltx/-/ltx-2.10.0.tgz", + "integrity": "sha512-RB4zR6Mrp/0wTNS9WxMvpgfht/7u/8QAC9DpPD19opL/4OASPa28uoliFqeDkLUU8pQ4aeAfATBZmz1aSAHkMw==", + "requires": { + "inherits": "^2.0.4" + } + }, "make-error": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", @@ -1001,6 +1272,16 @@ "make-error": "^1.3.5" } }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -1171,6 +1452,79 @@ "tar": "^4.4.2" } }, + "node-xmpp-client": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/node-xmpp-client/-/node-xmpp-client-3.2.0.tgz", + "integrity": "sha1-r0Un3wzFq9JpDLohOcwezcgeoYk=", + "requires": { + "browser-request": "^0.3.3", + "debug": "^2.2.0", + "md5.js": "^1.3.3", + "minimist": "^1.2.0", + "node-xmpp-core": "^5.0.9", + "request": "^2.65.0", + "ws": "^1.1.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "ws": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", + "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", + "requires": { + "options": ">=0.0.5", + "ultron": "1.0.x" + } + } + } + }, + "node-xmpp-core": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/node-xmpp-core/-/node-xmpp-core-5.0.9.tgz", + "integrity": "sha1-XCjCjtsfs/i+uixnYHd2E/SPNCo=", + "requires": { + "@xmpp/jid": "^0.0.2", + "@xmpp/streamparser": "^0.0.6", + "@xmpp/xml": "^0.1.3", + "debug": "^2.2.0", + "inherits": "^2.0.1", + "lodash.assign": "^4.0.0", + "node-xmpp-tls-connect": "^1.0.1", + "reconnect-core": "https://github.com/dodo/reconnect-core/tarball/merged" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "node-xmpp-tls-connect": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/node-xmpp-tls-connect/-/node-xmpp-tls-connect-1.0.1.tgz", + "integrity": "sha1-kazkOsJrE4hhsr5HjfnfGdYdxcM=" + }, "nopt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", @@ -1236,6 +1590,11 @@ "commander": "^3.0.2" } }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -1262,6 +1621,11 @@ "wrappy": "1" } }, + "options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" + }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", @@ -1317,6 +1681,11 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", @@ -1342,6 +1711,21 @@ "ipaddr.js": "1.9.0" } }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qbox": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/qbox/-/qbox-0.1.7.tgz", + "integrity": "sha1-6A8NxdCfhp2IghaMP2asjdKEDwI=" + }, "qs": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", @@ -1418,6 +1802,13 @@ "picomatch": "^2.2.1" } }, + "reconnect-core": { + "version": "https://github.com/dodo/reconnect-core/tarball/merged", + "integrity": "sha512-wZK/v5ZaNaSUs2Wnwh2YSX/Jqv6bQHKNEwojdzV11tByKziR9ikOssf5tvUhx+8/oCBz6AakOFAjZuqPoiRHJQ==", + "requires": { + "backoff": "~2.3.0" + } + }, "recursive-readdir": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", @@ -1426,6 +1817,40 @@ "minimatch": "3.0.4" } }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + } + } + }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -1564,6 +1989,15 @@ } } }, + "simple-xmpp": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/simple-xmpp/-/simple-xmpp-1.3.1.tgz", + "integrity": "sha512-o0wGVlI8Q4o0qTz6Kylbo1QPOMVn+DA/vyHHZecqcQ+LK4ZWGe3wtRON9QjHAkSyxB36PoagmiUz4pHADau8Mw==", + "requires": { + "node-xmpp-client": "^3.0.0", + "qbox": "0.1.x" + } + }, "snekfetch": { "version": "3.6.4", "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", @@ -1742,6 +2176,29 @@ "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "dependencies": { + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + } + } + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -1829,6 +2286,15 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, "ts-node": { "version": "8.5.4", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.5.4.tgz", @@ -1846,6 +2312,14 @@ "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.9.9.tgz", "integrity": "sha512-5a8k6qfbrL54N4Dw+i7M6kldrbjgDWb5Vit8DnT+gwThhvqMg8KtxLE5Vmnft+geIgaSOfNJyAcnmmlflS+Vdg==" }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "tweetnacl": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", @@ -1865,11 +2339,24 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz", "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==" }, + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "requires": { + "punycode": "^2.1.0" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -1880,11 +2367,26 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, "wide-align": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", diff --git a/package.json b/package.json index bee4cbf..b2e207a 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "nunjucks": "^3.2.1", "parse-yaml": "^0.1.0", "recursive-readdir": "^2.2.2", + "simple-xmpp": "^1.3.1", "socket-anti-spam": "^2.0.0", "socket.io": "^2.3.0", "strftime": "^0.10.0", diff --git a/src/config.ts b/src/config.ts index d9edb2e..dd7e3a8 100644 --- a/src/config.ts +++ b/src/config.ts @@ -75,8 +75,8 @@ const config: Object = { enabled: false, server: null, port: 5222, - nickname: 'SatyrChat', - username: 'SatyrChat' + jid: null, + password: null }, localconfig['chat']['xmpp']), twitch: Object.assign({ From 9a6e5c8798ea15f79b8d26d7905e92009bd41cc7 Mon Sep 17 00:00:00 2001 From: knotteye Date: Sat, 17 Oct 2020 18:28:35 -0500 Subject: [PATCH 07/16] Add documentation for configuring XMPP bridge --- docs/CONFIGURATION.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 2cd6bb6..996cb61 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -44,8 +44,8 @@ crypto: # if you don't understand the implications, don't change this chat: -# the following settings are for chat mirroring bots -# users will still need to choose which channel to mirror +# the following settings are for chat bridging bots +# users will still need to choose which channel to bridge # for their chat at /profile/chat irc: enabled: true @@ -74,6 +74,21 @@ chat: # access token for the twitch chat bot # this is not the account password, you will need to generate a token here: # https://twitchapps.com/tmi/ + + xmpp: + enabled: true +# enable xmpp + server: '404.city' + port: 5222 + jid: 'satyr-dev@404.city' + password: 'abcde' +# connection settings for the bot + nickname: 'SatyrChat +# the nickname the bot will join MUCs with + +# note that for the best experience you should set the default number of history messages to 0 for the MUC +# The bot will attempt to request 0 history messages anyway, and will also attempt to ignore any history messages it receives +# but both of these things are unreliable ``` ### Web Frontend From 81afb7493b5cb404165734e054da8d1d80968e0f Mon Sep 17 00:00:00 2001 From: knotteye Date: Sat, 17 Oct 2020 18:30:38 -0500 Subject: [PATCH 08/16] Update config options for xmpp bridge --- install/config.example.yml | 7 ++++--- src/config.ts | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/install/config.example.yml b/install/config.example.yml index fcb99d8..74fc8f2 100644 --- a/install/config.example.yml +++ b/install/config.example.yml @@ -51,10 +51,11 @@ chat: xmpp: enabled: false - server: # 'example.com' + server: port: 5222 - jid: # 'satyrchat@example.com' - password: # 'verysecretexample' + jid: + password: + nickname: twitch: enabled: false diff --git a/src/config.ts b/src/config.ts index dd7e3a8..5cef9ce 100644 --- a/src/config.ts +++ b/src/config.ts @@ -76,7 +76,8 @@ const config: Object = { server: null, port: 5222, jid: null, - password: null + password: null, + nickname: 'SatyrChat' }, localconfig['chat']['xmpp']), twitch: Object.assign({ From cfa7c5ab133662761b329788937d2aed9854f2a5 Mon Sep 17 00:00:00 2001 From: knotteye Date: Sat, 17 Oct 2020 20:17:24 -0500 Subject: [PATCH 09/16] Implement XMPP mirror --- src/chat.ts | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/src/chat.ts b/src/chat.ts index 647b6db..9b2206e 100644 --- a/src/chat.ts +++ b/src/chat.ts @@ -4,9 +4,11 @@ import {io} from "./http"; import * as irc from "irc"; import * as discord from "discord.js"; import * as twitch from "dank-twitch-irc"; +import * as xmpp from "simple-xmpp"; +const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); var ircClient; -var xmppClient; +var xmppIgnore: Array = []; var twitchClient; var twitchArr: Array = []; var discordClient; @@ -51,7 +53,24 @@ async function init() { }); } if(config['chat']['xmpp']['enabled']){ - + xmpp.on('online', (data) => { + console.log("XMPP Client Ready"); + }); + xmpp.on('groupchat', function(conference, from, message, stamp) { + if(xmppIgnore.findIndex((e) => { return e === conference }) !== -1) return false; + if(from === config['chat']['xmpp']['nickname']) return false; + console.log(from+'\n'+conference+'\n'+message+'\n'+stamp); + var lu = getUsr(conference, "xmpp"); + for(var i=0;i, src: string) { @@ -126,7 +148,7 @@ async function sendAll(user: string, msg: Array, src: string) { if(src !== "irc") sendIRC(getCh(user, "irc"), '['+src.toUpperCase()+']'+msg[0]+': '+msg[1]); if(src !== "twitch") sendTwitch(getCh(user, "twitch"), '['+src.toUpperCase()+']'+msg[0]+': '+msg[1]); if(src !== "discord") sendDiscord(getCh(user, "discord"), '['+src.toUpperCase()+']'+msg[0]+': '+msg[1]); - //if(src !== "xmpp") sendXMPP(); + if(src !== "xmpp") sendXMPP(getCh(user, "xmpp"), '['+src.toUpperCase()+']'+msg[0]+': '+msg[1]); if(src !== "web") sendWeb(user, ['['+src.toUpperCase()+']'+msg[0], msg[1]]); } @@ -146,6 +168,7 @@ async function sendDiscord(channel: string, msg: string) { async function sendXMPP(channel: string, msg: string) { if(!config['chat']['xmpp']['enabled']) return; if(channel === null) return; + xmpp.send(channel, msg, true); } async function sendTwitch(channel: string, msg: string) { @@ -252,4 +275,24 @@ async function normalizeDiscordMsg(msg): Promise{ return nmsg; } +function xmppJoin(room: string): void{ + var stanza = new xmpp.Element('presence', {"to": room+'/'+config['chat']['xmpp']['nickname']}).c('x', { xmlns: 'http://jabber.org/protocol/muc' }).c('history', { maxstanzas: 0, seconds: 1}); + xmpp.conn.send(stanza); + xmppIgnore = xmppIgnore.concat([room]); + xmpp.join(room+'/'+config['chat']['xmpp']['nickname']); + sleep(4000).then(() => { + xmppIgnore = xmppIgnore.filter((item) => { + return item !== room; + }); + }); +} + +function updateXmppChan(): void{ + //simple-xmpp will ignore duplicate joins by itself so we can join repeatedly + for(var i=0;i Date: Sat, 17 Oct 2020 21:20:32 -0500 Subject: [PATCH 10/16] Fix logging in cluster.ts Fix a bug calling the cluster process in index.ts Set a default value for rtmp.cluster in config.ts Update documentation --- docs/CHAT.md | 10 +++++----- docs/CONFIGURATION.md | 21 +++++++++++++++------ docs/INSTALLATION.md | 2 +- docs/USAGE.md | 2 +- src/cluster.ts | 8 ++++---- src/config.ts | 1 + src/index.ts | 2 +- 7 files changed, 28 insertions(+), 18 deletions(-) diff --git a/docs/CHAT.md b/docs/CHAT.md index f32ecae..a3bebd7 100644 --- a/docs/CHAT.md +++ b/docs/CHAT.md @@ -3,7 +3,7 @@ This is not a guide to using the webchat, this a reference point for writing cli Satyr's webchat is based on [socket.io](https://socket.io/), you can find clients for [Java](https://github.com/socketio/socket.io-client-java), [C++](https://github.com/socketio/socket.io-client-cpp), [Swift](https://github.com/socketio/socket.io-client-swift), [Dart](https://github.com/rikulo/socket.io-client-dart), and probably more. -Socket.IO is loosely reminiscent of IRC in that you will receive events from the server and sent events to it. The following is a list of incoming and outgoing events you will need to handle or send. If you would like to see examples, templates/chat.html is implementation used in the webclient by satyr. +Socket.IO is loosely reminiscent of IRC in that you will receive events from the server and sent events to it. The following is a list of incoming and outgoing events you will need to handle or send. If you would like to see examples, templates/chat.html is the implementation used in the webclient by satyr. # Incoming Events These are events you will recieve from the server that need to be handled in some way. @@ -53,12 +53,12 @@ This is a request to set the client's nickname. The data attached to a NICK even password: "the optional password" } ``` -During the initial connect of the client, the server will check for the "Authorization" cookie. If the cookie is a valid, signed JWT, the client will be assigned the nickname of the user that cookie belongs to. If it doesn't exist or is invalid, the client will be assigned a nickname of the form Guest+some integer. +During the initial connect of the client, the server will check for the "Authorization" cookie. If the cookie is a valid, signed JWT the client will be assigned the nickname of the user that cookie belongs to. If it doesn't exist or is invalid, the client will be assigned a nickname of the form Guest+some integer. The server will send an alert notifying the client of either the nickname change, or some error. ## MSG -This is a chat message to send to room. It should be a JSON object in the following format: +This is a chat message to send to a room. It should be a JSON object in the following format: ``` { room: "the room to send the messag to", @@ -117,10 +117,10 @@ A request to unban an IP address. It can only be done by the owner of the room. # Final Notes -Sending more than 10 messages a second will cause the server to kick your client. If kicked this way 3 times, the client will be banned for 20 minutes. +Sending more than 10 messages per second will cause the server to kick your client. If kicked this way 3 times, the client will be banned for 20 minutes. Kicked or banned users will not be notified of this through an event. -The server *will* send your own MSG events back to you, you will need to parse them out if you want to append them immediately. +The server *will* send your own MSG events back to you, you will need to parse them out if you want to display them immediately. Clients who successfully authenticate as a registered user, through either a password or a signed JWT, can ignore nickname collision and have as many connections as they wish. \ No newline at end of file diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 996cb61..0c1853a 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -7,11 +7,23 @@ Some values you might want to change are satyr: registration: true # allow new users to register + port: 8000 +# the port to serve http on http: hsts: true # enable strict transport security +rtmp: + port: 1935 +# change the port to serve rtmp on + cluster: false +# enable clustering for the RTMP server +# clustering is an attempt to take better advantage of multi threaded systems in spite of node.js being single-threaded +# satyr will spawn one RTMP Worker per CPU core, and round-robin incoming connections between workers +# If you turn this on, satyr will no longer be able to reliably serve RTMP streams to clients +# Your users will have to use DASH instead + media: record: true # allow users to record VODs @@ -36,7 +48,7 @@ transcode: # https://trac.ffmpeg.org/wiki/HWAccelIntro is a good place to start # having more than 4-5 variants will start giving diminishing returns on stream quality for cpu load -# if you can't afford to generate at least 3 variants, it's reccomended to leave adaptive streaming off +# if you can't afford to generate at least 3 variants, it's recommended to leave adaptive streaming off crypto: saltRounds: 12 @@ -49,7 +61,6 @@ chat: # for their chat at /profile/chat irc: enabled: true -# enable irc mirroring server: chat.freenode.net port: 6697 tls: true @@ -61,7 +72,6 @@ chat: discord: enabled: true -# enabled discord integration token: abcdefghijklmnopqrstuvwxyz # the access token for the bot # note that the bot will mirror every channel matching the name the user has chosen @@ -77,10 +87,9 @@ chat: xmpp: enabled: true -# enable xmpp - server: '404.city' + server: 'example.com' port: 5222 - jid: 'satyr-dev@404.city' + jid: 'exampleBot@example.com' password: 'abcde' # connection settings for the bot nickname: 'SatyrChat diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md index 136d9a3..a4609b3 100644 --- a/docs/INSTALLATION.md +++ b/docs/INSTALLATION.md @@ -4,7 +4,7 @@ A more detailed walkthrough. ### System Dependencies Install ffmpeg(>= 4.2.1) and mysql through your distribution's package manager. See [this page](https://nodejs.org/en/download/package-manager/) for instructions on installing node v10. -If the version in your distro's package manager is different, you can install 'n' through npm to manage node versions. +If the version in your distro's package manager is different, you can install [n](https://www.npmjs.com/package/n) through npm to manage node versions. ### Installing Satyr Before starting, you should create a system user to run the satyr service. diff --git a/docs/USAGE.md b/docs/USAGE.md index 1469cf2..473e7b0 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -1,7 +1,7 @@ ## Satyr Usage ### Administration -Satyr needs access to port 1935 for RTMP streams, and will serve HTTP on port 8000. The ports can be changed with follow config lines. +Satyr needs access to port 1935 for RTMP streams, and will serve HTTP on port 8000. See CONFIGURATION.md for details on changing this. For HTTPS, run a reverse proxy in front of satyr. An example nginx block is shown below. ``` diff --git a/src/cluster.ts b/src/cluster.ts index 4a5181e..61f440c 100644 --- a/src/cluster.ts +++ b/src/cluster.ts @@ -133,14 +133,14 @@ if (cluster.isMaster) { db.query('update user_meta set live=true where username=\''+results[0].username+'\' limit 1'); db.query('SELECT twitch_key,enabled from twitch_mirror where username='+db.raw.escape(results[0].username)+' limit 1').then(async (tm) => { if(!tm[0]['enabled'] || !config['twitch_mirror']['enabled'] || !config['twitch_mirror']['ingest']) return; - console.log('[NodeMediaServer] Mirroring to twitch for stream:',id) + console.log(`[RTMP Cluster WORKER ${process.pid}] Mirroring to twitch for stream: ${id}`) execFile(config['media']['ffmpeg'], ['-loglevel', 'fatal', '-i', 'rtmp://127.0.0.1:'+wPort+'/'+config['media']['privateEndpoint']+'/'+key, '-vcodec', 'copy', '-acodec', 'copy', '-f', 'flv', config['twitch_mirror']['ingest']+tm[0]['twitch_key']], { detached: true, stdio : 'inherit', maxBuffer: Infinity }).unref(); }); - console.log('[NodeMediaServer] Stream key ok for stream:',id); + console.log(`[RTMP Cluster WORKER ${process.pid}] Stream key ok for stream: ${id}`); console.log(`[RTMP Cluster WORKER ${process.pid}] Stream key ok for stream: ${id}`); //notify master process that we're handling the stream for this user process.send({type: 'handle-publish', name:results[0].username}); @@ -171,14 +171,14 @@ if (cluster.isMaster) { let key: string = StreamPath.split("/")[2]; //correctly formatted urls again if (StreamPath.split("/").length !== 3){ - console.log("[NodeMediaServer] Malformed URL, closing connection for stream:",id); + console.log(`[RTMP Cluster WORKER ${process.pid}] Malformed URL, closing connection for stream: ${id}`); session.reject(); return false; } //localhost can play from whatever endpoint //other clients must use private endpoint if(app !== config['media']['publicEndpoint'] && !session.isLocal) { - console.log("[NodeMediaServer] Non-local Play from private endpoint, rejecting client:",id); + console.log(`[RTMP Cluster WORKER ${process.pid}] Non-local Play from private endpoint, rejecting client: ${id}`); session.reject(); return false; } diff --git a/src/config.ts b/src/config.ts index 5cef9ce..a68abaa 100644 --- a/src/config.ts +++ b/src/config.ts @@ -30,6 +30,7 @@ const config: Object = { insecureAuth: false, debug: false }, localconfig['database']), rtmp: Object.assign({ + cluster: false, port: 1935, chunk_size: 6000, gop_cache: true, diff --git a/src/index.ts b/src/index.ts index d2c3f15..49f9ae2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,7 +10,7 @@ async function run() { await initDB(); await clean(); await initHTTP(); - config['rtmp']['cluster'] ? execFile(process.cwd()+'/node_modules/.bin/ts-node' [process.cwd()+'src/cluster.ts']) : await initRTMP(); + config['rtmp']['cluster'] ? execFile(process.cwd()+'/node_modules/.bin/ts-node', [process.cwd()+'/src/cluster.ts']) : await initRTMP(); await initChat(); console.log(`Satyr v${config['satyr']['version']} ready`); } From 01744df3cd92d7eaa340646511c32ec026a524df Mon Sep 17 00:00:00 2001 From: knotteye Date: Sat, 17 Oct 2020 22:07:30 -0500 Subject: [PATCH 11/16] Fix a bug where XMPP bridge would repeatedly ignore channels --- src/chat.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/chat.ts b/src/chat.ts index 9b2206e..1a47ae6 100644 --- a/src/chat.ts +++ b/src/chat.ts @@ -9,6 +9,7 @@ const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); var ircClient; var xmppIgnore: Array = []; +var xmppJoined: Array = []; var twitchClient; var twitchArr: Array = []; var discordClient; @@ -276,10 +277,12 @@ async function normalizeDiscordMsg(msg): Promise{ } function xmppJoin(room: string): void{ - var stanza = new xmpp.Element('presence', {"to": room+'/'+config['chat']['xmpp']['nickname']}).c('x', { xmlns: 'http://jabber.org/protocol/muc' }).c('history', { maxstanzas: 0, seconds: 1}); + if(xmppJoined.findIndex((e) => { return e === room }) !== -1) return; + var stanza = new xmpp.Element('presence', {"to": room+'/'+config['chat']['xmpp']['nickname']}).c('x', { xmlns: 'http://jabber.org/protocol/muc' }).c('history', { maxstanzas: 0, seconds: 0}); xmpp.conn.send(stanza); xmppIgnore = xmppIgnore.concat([room]); xmpp.join(room+'/'+config['chat']['xmpp']['nickname']); + xmppJoined = xmppJoined.concat([room]); sleep(4000).then(() => { xmppIgnore = xmppIgnore.filter((item) => { return item !== room; @@ -288,7 +291,6 @@ function xmppJoin(room: string): void{ } function updateXmppChan(): void{ - //simple-xmpp will ignore duplicate joins by itself so we can join repeatedly for(var i=0;i Date: Sat, 17 Oct 2020 22:08:56 -0500 Subject: [PATCH 12/16] Expose whether cluster mode is enabled over /api/instance/config --- docs/REST.md | 1 + src/http.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/REST.md b/docs/REST.md index 9058efb..784b883 100644 --- a/docs/REST.md +++ b/docs/REST.md @@ -32,6 +32,7 @@ Configuration of the instance relating to media ``` { rtmp: { + cluster: false, port: 1935, ping_timeout: 60 }, diff --git a/src/http.ts b/src/http.ts index f83b61b..b15b04f 100644 --- a/src/http.ts +++ b/src/http.ts @@ -168,6 +168,7 @@ async function initAPI() { app.get('/api/instance/config', (req, res) => { res.json({ rtmp: { + cluster: config['rtmp']['cluster'], port: config['rtmp']['port'], ping_timeout: config['rtmp']['ping_timeout'] }, From 1fa6bf7e817e2704d57996e174824107a9e604be Mon Sep 17 00:00:00 2001 From: knotteye Date: Sat, 17 Oct 2020 22:23:05 -0500 Subject: [PATCH 13/16] Update documentation --- docs/USAGE.md | 46 ++++++++++++++++++--------------------------- install/satyr.nginx | 25 ++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 28 deletions(-) create mode 100644 install/satyr.nginx diff --git a/docs/USAGE.md b/docs/USAGE.md index 473e7b0..0e57a77 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -3,28 +3,17 @@ ### Administration Satyr needs access to port 1935 for RTMP streams, and will serve HTTP on port 8000. See CONFIGURATION.md for details on changing this. -For HTTPS, run a reverse proxy in front of satyr. An example nginx block is shown below. -``` -server { - port 80; - port [::]80; - server_name example.tld; - return https://$server_name$request_uri 301; -} -server { - port 443 ssl; - port [::]443 ssl; - server_name example.tld; - - ssl_trusted_certificate /etc/letsencrypt/live/example.tld/chain.pem; - ssl_certificate /etc/letsencrypt/live/example.tld/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/example.tld/privkey.pem; - - location / { - proxy_pass http://127.0.0.1:8000/; - } -} -``` +For HTTPS, run a reverse proxy in front of satyr. An example nginx config can be found at install/satyr.nginx +An example systemd service can also be at install/satyr.service + +#### CLI +Satyr's CLI tool can be run with `npm run cli` or `node_modules/.bin/ts-node src/cli.ts` + +It's not very complex. The following commands are available: +* `npm run cli -- --adduser sally --password "hunter12"` to create user sally with the password hunter12 +* `npm run cli -- --rmuser sally` to remove user sally +* `npm run cli -- --invite` to generate an invite code used for creating account even when registration is closed + ### Users @@ -35,13 +24,14 @@ Stream keys can be changed at example.tld/changesk, and passwords at /changepwd #### Chat Chat is based on Socket.IO, and can be accessed through the webclient at /chat. Chatting and changing a nickname do not require authentication, but the usernames of streamers are reserved. + The following commands are available: -`/nick sally (password)` Password is only required if sally is a registered user. -`/join sally` Join the chatroom for sally's stream and leave the previous room. -`/kick bob` Available only in your own room if you are a streamer. Forcefully disconnect the user. -`/ban bob (time)` Ban a user from your room. Bans are based on IP address. The optional time is in minutes. The default is 30. -`/banlist` List the IPs currently banned from your room. -`/unban (ip)` self explanatory +* `/nick sally (password)` Password is only required if sally is a registered user. +* `/join sally` Join the chatroom for sally's stream and leave the previous room. +* `/kick bob` Available only in your own room if you are a streamer. Forcefully disconnect the user. +* `/ban bob (time)` Ban a user from your room. Bans are based on IP address. The optional time is in minutes. The default is 30. +* `/banlist` List the IPs currently banned from your room. +* `/unban (ip)` self explanatory You can set up mirroring to and from webchat rooms and IRC channels, twitch streams, and discord server channels. More information is in CONFIGURATION.md diff --git a/install/satyr.nginx b/install/satyr.nginx new file mode 100644 index 0000000..fb3dc2f --- /dev/null +++ b/install/satyr.nginx @@ -0,0 +1,25 @@ +server { + port 80; + port [::]80; + server_name example.tld; + return https://$server_name$request_uri 301; +} +server { + port 443 ssl; + port [::]443 ssl; + server_name example.tld; + + ssl_trusted_certificate /etc/letsencrypt/live/example.tld/chain.pem; + ssl_certificate /etc/letsencrypt/live/example.tld/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/example.tld/privkey.pem; + + location / { + proxy_pass http://127.0.0.1:8000/; + } + + location ~* \.(mpd|m4s|mp4)$ { + # nginx can serve static files faster than node + # this should improve performance + root /opt/satyr/site/; + } +} \ No newline at end of file From 90cce68581a1fb95b2add7fe204f72f80e64ae4d Mon Sep 17 00:00:00 2001 From: knotteye Date: Sat, 17 Oct 2020 22:40:30 -0500 Subject: [PATCH 14/16] Fix bug --- site/index.js | 2 +- templates/base.njk | 23 +++++++++++++++++++++++ templates/user.njk | 4 ++-- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/site/index.js b/site/index.js index c52c1c2..2f78da6 100644 --- a/site/index.js +++ b/site/index.js @@ -186,7 +186,7 @@ async function startVideo(){ //player.initialize(document.querySelector("#videoPlayer"), url, true); //console.log('called startvideo'); while(true){ - if(document.querySelector('#videoPlayer') === null) + if(!document.querySelector('#videoPlayer')) break; if(window.location.pathname.substring(window.location.pathname.length - 1) !== '/'){ diff --git a/templates/base.njk b/templates/base.njk index f832bc3..aa150ed 100644 --- a/templates/base.njk +++ b/templates/base.njk @@ -12,6 +12,29 @@ xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xhr.send(""); } + function makeRequest(method, url, payload) { + return new Promise(function (resolve, reject) { + let xhr = new XMLHttpRequest(); + xhr.open(method, url); + xhr.onload = function () { + if (this.status >= 200 && this.status < 300) { + resolve(xhr.response); + } else { + reject({ + status: this.status, + statusText: xhr.statusText + }); + } + }; + xhr.onerror = function () { + reject({ + status: this.status, + statusText: xhr.statusText + }); + }; + !payload ? xhr.send() : xhr.send(payload); + }); + } {% block head %} {% endblock %} diff --git a/templates/user.njk b/templates/user.njk index 09aa4c1..2a637ff 100644 --- a/templates/user.njk +++ b/templates/user.njk @@ -4,13 +4,13 @@ -->