From 038c07c1b836a9b3c2662ed6ed8a505f00ddb639 Mon Sep 17 00:00:00 2001 From: wukko Date: Thu, 22 Jun 2023 20:24:01 +0600 Subject: [PATCH 01/62] attempt to fix the weird issue with authorization --- src/config.json | 2 +- src/localization/languages/en.json | 2 +- src/modules/stream/manage.js | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/config.json b/src/config.json index 91915bcf..d4505721 100644 --- a/src/config.json +++ b/src/config.json @@ -28,7 +28,7 @@ "litecoin": "ltc1qvp0xhrk2m7pa6p6z844qcslfyxv4p3vf95rhna" }, "links": { - "boosty": "https://boosty.to/wukko" + "boosty": "https://boosty.to/wukko/donate" } }, "links": { diff --git a/src/localization/languages/en.json b/src/localization/languages/en.json index 73677098..a6d15b73 100644 --- a/src/localization/languages/en.json +++ b/src/localization/languages/en.json @@ -29,7 +29,7 @@ "ErrorCouldntFetch": "i couldn't find anything about this link. check if it works and try again! some content may be region restricted, so keep that in mind.", "ErrorLengthLimit": "i can't process videos longer than {s} minutes, so pick something shorter instead!", "ErrorBadFetch": "something went wrong when i tried getting info about your link. are you sure it works? check if it does, and try again.", - "ErrorNoInternet": "there's no internet or {appName} api is down. check your connection and try again.", + "ErrorNoInternet": "there's no internet or {appName} api is temporarily unavailable. check your connection and try again.", "ErrorCantConnectToServiceAPI": "i couldn't connect to the service api. maybe it's down, or {appName} got blocked. try again, but if error persists, {ContactLink}.", "ErrorEmptyDownload": "i don't see anything i could download by your link. try a different one!", "ErrorLiveVideo": "this is a live video, i am yet to learn how to look into future. wait for the stream to finish and try again!", diff --git a/src/modules/stream/manage.js b/src/modules/stream/manage.js index ed2d2902..2a6011c8 100644 --- a/src/modules/stream/manage.js +++ b/src/modules/stream/manage.js @@ -44,9 +44,9 @@ export function createStream(obj) { export function verifyStream(ip, id, hmac, exp) { try { - if (id.length === 21) { - let streamInfo = streamCache.get(id); - if (!streamInfo) return { error: 'this stream token does not exist', status: 400 }; + if (id.toString().length === 21) { + let streamInfo = streamCache.get(id.toString()); + if (!streamInfo) return { error: "requested stream does not exist", status: 400 }; let ghmac = sha256(`${id},${ip},${streamInfo.service},${exp}`, streamSalt); if (String(hmac) === ghmac && String(exp) === String(streamInfo.exp) && ghmac === String(streamInfo.hmac) @@ -54,7 +54,7 @@ export function verifyStream(ip, id, hmac, exp) { return streamInfo; } } - return { error: "i couldn't verify whether you have access to this stream. try again or refresh the page!", status: 401 }; + return { error: "i couldn't verify whether you have access to this download. try again or refresh the page!", status: 401 }; } catch (e) { return { status: 500, body: { status: "error", text: "Internal Server Error" } }; } From 0e1c885266b15c8bf6581bb7856a0c74e9315912 Mon Sep 17 00:00:00 2001 From: wukko Date: Sun, 25 Jun 2023 13:47:34 +0600 Subject: [PATCH 02/62] more button contrast --- package.json | 2 +- src/front/cobalt.css | 20 ++++++++++---------- src/modules/changelog/changelog.json | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 8b8cdf78..6be55931 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cobalt", "description": "save what you love", - "version": "6.0", + "version": "6.1", "author": "wukko", "exports": "./src/cobalt.js", "type": "module", diff --git a/src/front/cobalt.css b/src/front/cobalt.css index 8229f915..ed2b4748 100644 --- a/src/front/cobalt.css +++ b/src/front/cobalt.css @@ -15,8 +15,8 @@ --accent: rgb(225, 225, 225); --accent-highlight: rgb(225, 225, 225, 4%); --accent-subtext: rgb(110, 110, 110); - --accent-hover: rgb(25, 25, 25); - --accent-button: rgb(20, 20, 20); + --accent-hover: rgb(30, 30, 30); + --accent-button: rgb(25, 25, 25); --subbackground: rgb(10, 10, 10); --background: rgb(0, 0, 0); } @@ -24,10 +24,10 @@ @media (prefers-color-scheme: light) { :root { --accent: rgb(25, 25, 25); - --accent-highlight: rgb(25, 25, 25, 6%); + --accent-highlight: rgb(25, 25, 25, 4%); --accent-subtext: rgb(110, 110, 110); - --accent-hover: rgb(225, 225, 225); - --accent-button: rgb(230, 230, 230); + --accent-hover: rgb(230, 230, 230); + --accent-button: rgb(225, 225, 225); --subbackground: rgb(240, 240, 240); --background: rgb(255, 255, 255); } @@ -36,17 +36,17 @@ --accent: rgb(225, 225, 225); --accent-highlight: rgb(225, 225, 225, 4%); --accent-subtext: rgb(110, 110, 110); - --accent-hover: rgb(25, 25, 25); - --accent-button: rgb(20, 20, 20); + --accent-hover: rgb(30, 30, 30); + --accent-button: rgb(25, 25, 25); --subbackground: rgb(10, 10, 10); --background: rgb(0, 0, 0); } [data-theme="light"] { --accent: rgb(25, 25, 25); - --accent-highlight: rgb(25, 25, 25, 6%); + --accent-highlight: rgb(25, 25, 25, 4%); --accent-subtext: rgb(110, 110, 110); - --accent-hover: rgb(225, 225, 225); - --accent-button: rgb(230, 230, 230); + --accent-hover: rgb(230, 230, 230); + --accent-button: rgb(225, 225, 225); --subbackground: rgb(240, 240, 240); --background: rgb(255, 255, 255); } diff --git a/src/modules/changelog/changelog.json b/src/modules/changelog/changelog.json index 6f1d7294..64017716 100644 --- a/src/modules/changelog/changelog.json +++ b/src/modules/changelog/changelog.json @@ -3,7 +3,7 @@ "version": "6.0", "title": "better reliability, new infrastructure, pinterest support, and way more!", "banner": "catswitchboxes.webp", - "content": "hey! long time no see, hopefully over 40 changes will make up for it :)\n\ncobalt now has an official community discord server. you can go there for news, support, or just to chat. go check it out!\n\ntl;dr\n*; new infra, new hosting structure, new main instance api url. developers, get it here.\n*; added support for pinterest, vine archive, tumblr audio, youtube vr videos.\n*; better web app performance and look.\n*; better stability thanks to load balancing.\n*; (hopefully) no more random video/audio download drops.\n\nservice improvements:\n*; added support for pinterest videos and stories (pr by @Snazzah).\n*; added support for tumblr audio. sorry, tumblr.\n*; added support for youtube vr videos. please note that they're in youtube's proprietary ratio.\n*; added support for vine archive.\n*; added support for ancient vk videos in 240p.\n*; fixed an issue related to muted video downloads from tumblr.\n*; moved to twitter v2 api.\n*; soundcloud share links are now processed without errors.\n\nui improvements:\n*; lazy image loading. should significantly speed up the page load.\n*; fixed checkbox width on mobile devices.\n*; addition of a temporary urgent notice.\n*; added hover border to all buttons.\n*; less annoying donation button highlight.\n*; more consistent color scheme.\n*; added link to a discord server into about popup.\n*; remember celebratory emoji changes? they've been fixed, and are now dynamically loaded!\n*; changelog history now lets you try to load it again if first attempt failed for whatever reason.\n*; padding (everywhere) has been slightly reduced to fit in more content and be consistent across ui.\n*; added more info to the \"how to save\" popup for ios devices.\n*; crypto wallet press-to-copy buttons now look like buttons.\n*; improved ui layout for smallest screens (iphone 5, 5s, se, etc).\n*; removed partial translations for sake of clarity and consistency.\n\ninternal improvements:\n*; separated web and api servers. they're now completely independent and therefore more stress-resistant.\n*; added a dedicated script for building the web app if you don't want to reload the frontend server.\n*; web app building improvements.\n*; async localization preloading.\n*; consistent server start time reporting.\n*; dynamic stream and ip hashing salt generation.\n\ninfrastructure improvements:\n*; load balancing: your api requests are now sent to the least busy server. yes, there are now several of them with more to come in the future.\n*; when possible, server in closest region is used instead of a far-away one. this should help with download speeds.\n*; currently there are servers in two locations: netherlands and kazakhstan. i will let you know when (and if) i manage to get an american one.\n\nupdates for developers and instance hosters:\n*; server info api endpoint: you can now check up on the api server of choice. it reports all the basic info you may need. check the api docs for more info.\n*; api names: each and every api instance should have a distinctive name. this will be useful in the future :)\n*; added docker compose sample config.\n*; updated and more granular setup script.\n*; better api scalability and faster server start up thanks to web and api separation.\n*; added ability to specify ffmpeg threads. simply add ffmpegThreads to your environment variables!\n\ni'm still in awe from how popular cobalt has become. there are now over 200k of unique users monthly, and that number only keeps growing. i even had to come up with something to accommodate for larger traffic, it's absolutely insane.\n\nlove you all, have a great day :D" + "content": "hey! long time no see, hopefully over 40 changes will make up for it :)\n\ncobalt now has an official community discord server. you can go there for news, support, or just to chat. go check it out!\n\ntl;dr\n*; new infra, new hosting structure, new main instance api url. developers, get it here.\n*; added support for pinterest, vine archive, tumblr audio, youtube vr videos.\n*; better web app performance and look.\n*; better stability thanks to load balancing.\n*; (hopefully) no more random video/audio download drops.\n\nservice improvements:\n*; added support for pinterest videos and stories (pr by @Snazzah).\n*; added support for tumblr audio. sorry, tumblr.\n*; added support for youtube vr videos. please note that they're in youtube's proprietary ratio.\n*; added support for vine archive.\n*; added support for ancient vk videos in 240p.\n*; fixed an issue related to muted video downloads from tumblr.\n*; moved to twitter v2 api.\n*; soundcloud share links are now processed without errors.\n\nui improvements:\n*; lazy image loading. should significantly speed up the page load.\n*; fixed checkbox width on mobile devices.\n*; addition of a temporary urgent notice.\n*; added hover border to all buttons.\n*; less annoying donation button highlight.\n*; more consistent color scheme.\n*; added link to a discord server into about popup.\n*; remember celebratory emoji changes? they've been fixed, and are now dynamically loaded!\n*; changelog history now lets you try to load it again if first attempt failed for whatever reason.\n*; padding (everywhere) has been slightly reduced to fit in more content and be consistent across ui.\n*; added more info to the \"how to save\" popup for ios devices.\n*; crypto wallet press-to-copy buttons now look like buttons.\n*; improved ui layout for smallest screens (iphone 5, 5s, se, etc).\n*; removed partial translations for sake of clarity and consistency.\n\ninternal improvements:\n*; separated web and api servers. they're now completely independent and therefore more stress-resistant.\n*; added a dedicated script for building the web app if you don't want to reload the frontend server.\n*; web app building improvements.\n*; async localization preloading.\n*; consistent server start time reporting.\n*; dynamic stream and ip hashing salt generation.\n\ninfrastructure improvements:\n*; load balancing: your api requests are now sent to the least busy server. yes, there are now several of them with more to come in the future.\n*; when possible, server in closest region is used instead of a far-away one. this should help with download speeds.\n*; currently there are multiple servers in europe. i will let you know when (and if) i manage to get an american one.\n\nupdates for developers and instance hosters:\n*; server info api endpoint: you can now check up on the api server of choice. it reports all the basic info you may need. check the api docs for more info.\n*; api names: each and every api instance should have a distinctive name. this will be useful in the future :)\n*; added docker compose sample config.\n*; updated and more granular setup script.\n*; better api scalability and faster server start up thanks to web and api separation.\n*; added ability to specify ffmpeg threads. simply add ffmpegThreads to your environment variables!\n\ni'm still in awe from how popular cobalt has become. there are now over 200k of unique users monthly, and that number only keeps growing. i even had to come up with something to accommodate for larger traffic, it's absolutely insane.\n\nlove you all, have a great day :D" }, "history": [{ "version": "5.4", From 65161107faafd376e3f2fe590a8971ef70a36ab8 Mon Sep 17 00:00:00 2001 From: wukko Date: Tue, 27 Jun 2023 19:56:15 +0600 Subject: [PATCH 03/62] 6.2: no more ip verification - removed ip verification and updated privacy policy to reflect this change. - streamable links now last for 20 seconds instead of 2 minutes. - cleaned up stream verification algorithm. now the same function isn't run 4 times in a row. - removed deprecated way of hosting a cobalt instance. --- README.md | 2 +- docker-compose.yml.example | 9 - package.json | 2 +- src/cobalt.js | 12 +- src/config.json | 4 +- src/core/api.js | 32 ++- src/core/both.js | 197 ------------------- src/localization/languages/en.json | 5 +- src/localization/languages/ru.json | 5 +- src/modules/pageRender/page.js | 1 + src/modules/processing/match.js | 2 +- src/modules/processing/matchActionDecider.js | 3 +- src/modules/setup.js | 2 +- src/modules/stream/manage.js | 23 +-- src/modules/stream/stream.js | 9 +- src/modules/sub/utils.js | 1 - 16 files changed, 42 insertions(+), 267 deletions(-) delete mode 100644 src/core/both.js diff --git a/README.md b/README.md index e930d078..981b9acd 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Setup script installs all needed `npm` dependencies, but you have to install `No 3. Run cobalt via `npm start` 4. Done. -You need to host API and web app separately ever since v.6.0. Setup script will help you with that! +You need to host API and web app separately since v.6.0. Setup script will help you with that! ### Ubuntu 22.04+ workaround `nscd` needs to be installed and running so that the `ffmpeg-static` binary can resolve DNS ([#101](https://github.com/wukko/cobalt/issues/101#issuecomment-1494822258)): diff --git a/docker-compose.yml.example b/docker-compose.yml.example index 8ba8c870..a2b79c0f 100644 --- a/docker-compose.yml.example +++ b/docker-compose.yml.example @@ -21,12 +21,3 @@ services: - webPort=9000 - webURL=https://co.wukko.me/ - apiURL=https://co.wuk.sh/ - cobalt-both: - build: . - restart: unless-stopped - container_name: cobalt-both - ports: - - 9000:9000/tcp - environment: - - port=9000 - - selfURL=https://co.wukko.me/ diff --git a/package.json b/package.json index 6be55931..c84753af 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cobalt", "description": "save what you love", - "version": "6.1", + "version": "6.2", "author": "wukko", "exports": "./src/cobalt.js", "type": "module", diff --git a/src/cobalt.js b/src/cobalt.js index d349a79e..ee92af77 100644 --- a/src/cobalt.js +++ b/src/cobalt.js @@ -11,7 +11,6 @@ import { fileURLToPath } from 'url'; import { runWeb } from "./core/web.js"; import { runAPI } from "./core/api.js"; -import { runBoth } from "./core/both.js"; const app = express(); @@ -19,19 +18,16 @@ const gitCommit = shortCommit(); const gitBranch = getCurrentBranch(); const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename).slice(0, -4); // go up another level (get rid of src/) +const __dirname = path.dirname(__filename).slice(0, -4); app.disable('x-powered-by'); -await loadLoc(); // preload localization +await loadLoc(); -// i don't like this at all if (process.env.apiURL && process.env.apiPort && !((process.env.webURL && process.env.webPort) || (process.env.selfURL && process.env.port))) { - await runAPI(express, app, gitCommit, gitBranch, __dirname); + runAPI(express, app, gitCommit, gitBranch, __dirname); } else if (process.env.webURL && process.env.webPort && !((process.env.apiURL && process.env.apiPort) || (process.env.selfURL && process.env.port))) { await runWeb(express, app, gitCommit, gitBranch, __dirname); -} else if (process.env.selfURL && process.env.port && !((process.env.apiURL && process.env.apiPort) || (process.env.webURL && process.env.webPort))) { - await runBoth(express, app, gitCommit, gitBranch, __dirname) } else { - console.log(Red(`cobalt hasn't been configured yet or configuration is invalid.\n`) + Bright(`please run the setup script to fix this: `) + Green(`npm run setup`)); + console.log(Red(`cobalt wasn't configured yet or configuration is invalid.\n`) + Bright(`please run the setup script to fix this: `) + Green(`npm run setup`)); } diff --git a/src/config.json b/src/config.json index d4505721..362ea34e 100644 --- a/src/config.json +++ b/src/config.json @@ -1,7 +1,7 @@ { - "streamLifespan": 120000, + "streamLifespan": 20000, "maxVideoDuration": 10800000, - "genericUserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36", + "genericUserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", "authorInfo": { "name": "wukko", "link": "https://wukko.me/", diff --git a/src/core/api.js b/src/core/api.js index 0363f5aa..c70dd41a 100644 --- a/src/core/api.js +++ b/src/core/api.js @@ -20,7 +20,7 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) { const apiLimiter = rateLimit({ windowMs: 60000, - max: 25, + max: 20, standardHeaders: false, legacyHeaders: false, keyGenerator: (req, res) => sha256(getIP(req), ipSalt), @@ -31,7 +31,7 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) { }); const apiLimiterStream = rateLimit({ windowMs: 60000, - max: 28, + max: 25, standardHeaders: false, legacyHeaders: false, keyGenerator: (req, res) => sha256(getIP(req), ipSalt), @@ -75,7 +75,6 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) { app.post('/api/json', async (req, res) => { try { - let ip = sha256(getIP(req), ipSalt); let lang = languageCode(req); let j = apiJSON(0, { t: "Bad request" }); try { @@ -83,7 +82,6 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) { if (request.url) { request.dubLang = request.dubLang ? lang : false; let chck = checkJSONPost(request); - if (chck) chck["ip"] = ip; j = chck ? await getJSON(chck["url"], lang, chck) : apiJSON(0, { t: loc(lang, 'ErrorCouldntFetch') }); } else { j = apiJSON(0, { t: loc(lang, 'ErrorNoLink') }); @@ -101,22 +99,22 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) { app.get('/api/:type', (req, res) => { try { - let ip = sha256(getIP(req), ipSalt); switch (req.params.type) { case 'stream': - let streamInfo = verifyStream(ip, req.query.t, req.query.h, req.query.e); - if (streamInfo.error) { - res.status(streamInfo.status).json(apiJSON(0, { t: streamInfo.error }).body); - return; - } - - if (req.query.p) { - res.status(200).json({ "status": "continue" }); - return; - } else if (req.query.t && req.query.h && req.query.e) { - stream(res, ip, req.query.t, req.query.h, req.query.e); + if (req.query.t && req.query.h && req.query.e && req.query.t.toString().length === 21 + && req.query.h.toString().length === 64 && req.query.e.toString().length === 13) { + let streamInfo = verifyStream(req.query.t, req.query.h, req.query.e); + if (streamInfo.error) { + res.status(streamInfo.status).json(apiJSON(0, { t: streamInfo.error }).body); + return; + } + if (req.query.p) { + res.status(200).json({ "status": "continue" }); + return; + } + stream(res, streamInfo); } else { - let j = apiJSON(0, { t: "no stream id" }) + let j = apiJSON(0, { t: "stream token, hmac, or expiry timestamp is missing." }) res.status(j.status).json(j.body); return; } diff --git a/src/core/both.js b/src/core/both.js deleted file mode 100644 index 1c0065bd..00000000 --- a/src/core/both.js +++ /dev/null @@ -1,197 +0,0 @@ -import cors from "cors"; -import rateLimit from "express-rate-limit"; -import { randomBytes } from "crypto"; - -const ipSalt = randomBytes(64).toString('hex'); - -import { appName, genericUserAgent, version } from "../modules/config.js"; -import { getJSON } from "../modules/api.js"; -import { apiJSON, checkJSONPost, getIP, languageCode } from "../modules/sub/utils.js"; -import { Bright, Cyan, Green, Red } from "../modules/sub/consoleText.js"; -import stream from "../modules/stream/stream.js"; -import loc from "../localization/manager.js"; -import { buildFront } from "../modules/build.js"; -import { changelogHistory } from "../modules/pageRender/onDemand.js"; -import { sha256 } from "../modules/sub/crypto.js"; -import findRendered from "../modules/pageRender/findRendered.js"; -import { celebrationsEmoji } from "../modules/pageRender/elements.js"; - -export async function runBoth(express, app, gitCommit, gitBranch, __dirname) { - const corsConfig = process.env.cors === '0' ? { origin: process.env.selfURL, optionsSuccessStatus: 200 } : {}; - - const apiLimiter = rateLimit({ - windowMs: 60000, - max: 25, - standardHeaders: false, - legacyHeaders: false, - keyGenerator: (req, res) => sha256(getIP(req), ipSalt), - handler: (req, res, next, opt) => { - res.status(429).json({ "status": "error", "text": loc(languageCode(req), 'ErrorRateLimit') }); - return; - } - }); - const apiLimiterStream = rateLimit({ - windowMs: 60000, - max: 28, - standardHeaders: false, - legacyHeaders: false, - keyGenerator: (req, res) => sha256(getIP(req), ipSalt), - handler: (req, res, next, opt) => { - res.status(429).json({ "status": "error", "text": loc(languageCode(req), 'ErrorRateLimit') }); - return; - } - }); - - const startTime = new Date(); - const startTimestamp = Math.floor(startTime.getTime()); - - // preload localization files and build static pages - await buildFront(gitCommit, gitBranch); - - app.use('/api/:type', cors(corsConfig)); - app.use('/api/json', apiLimiter); - app.use('/api/stream', apiLimiterStream); - app.use('/api/onDemand', apiLimiter); - - app.use('/', express.static('./build/min')); - app.use('/', express.static('./src/front')); - - app.use((req, res, next) => { - try { decodeURIComponent(req.path) } catch (e) { return res.redirect('/') } - next(); - }); - app.use((req, res, next) => { - if (req.header("user-agent") && req.header("user-agent").includes("Trident")) res.destroy(); - next(); - }); - app.use('/api/json', express.json({ - verify: (req, res, buf) => { - try { - JSON.parse(buf); - if (buf.length > 720) throw new Error(); - if (String(req.header('Content-Type')) !== "application/json") { - res.status(400).json({ 'status': 'error', 'text': 'invalid content type header' }); - return; - } - if (String(req.header('Accept')) !== "application/json") { - res.status(400).json({ 'status': 'error', 'text': 'invalid accept header' }); - return; - } - } catch(e) { - res.status(400).json({ 'status': 'error', 'text': 'invalid json body.' }); - return; - } - } - })); - - app.post('/api/json', async (req, res) => { - try { - let ip = sha256(getIP(req), ipSalt); - let lang = languageCode(req); - let j = apiJSON(0, { t: "Bad request" }); - try { - let request = req.body; - if (request.url) { - request.dubLang = request.dubLang ? lang : false; - let chck = checkJSONPost(request); - if (chck) chck["ip"] = ip; - j = chck ? await getJSON(chck["url"], lang, chck) : apiJSON(0, { t: loc(lang, 'ErrorCouldntFetch') }); - } else { - j = apiJSON(0, { t: loc(lang, 'ErrorNoLink') }); - } - } catch (e) { - j = apiJSON(0, { t: loc(lang, 'ErrorCantProcess') }); - } - res.status(j.status).json(j.body); - return; - } catch (e) { - res.destroy(); - return - } - }); - - app.get('/api/:type', (req, res) => { - try { - let ip = sha256(getIP(req), ipSalt); - switch (req.params.type) { - case 'stream': - if (req.query.p) { - res.status(200).json({ "status": "continue" }); - return; - } else if (req.query.t && req.query.h && req.query.e) { - stream(res, ip, req.query.t, req.query.h, req.query.e); - } else { - let j = apiJSON(0, { t: "no stream id" }) - res.status(j.status).json(j.body); - return; - } - break; - case 'onDemand': - if (req.query.blockId) { - let blockId = req.query.blockId.slice(0, 3); - let r, j; - switch(blockId) { - case "0": // changelog history - r = changelogHistory(); - j = r ? apiJSON(3, { t: r }) : apiJSON(0, { t: "couldn't render this block" }) - break; - case "1": // celebrations emoji - r = celebrationsEmoji(); - j = r ? apiJSON(3, { t: r }) : false - break; - default: - j = apiJSON(0, { t: "couldn't find a block with this id" }) - break; - } - if (j.body) { - res.status(j.status).json(j.body) - } else { - res.status(204).end() - } - } else { - let j = apiJSON(0, { t: "no block id" }); - res.status(j.status).json(j.body) - } - break; - case 'serverInfo': - res.status(200).json({ - version: version, - commit: gitCommit, - branch: gitBranch, - name: process.env.apiName ? process.env.apiName : "unknown", - url: process.env.apiURL, - cors: process.env.cors && process.env.cors === "0" ? 0 : 1, - startTime: `${startTimestamp}` - }); - break; - default: - let j = apiJSON(0, { t: "unknown response type" }) - res.status(j.status).json(j.body); - break; - } - } catch (e) { - res.status(500).json({ 'status': 'error', 'text': loc(languageCode(req), 'ErrorCantProcess') }); - return; - } - }); - app.get("/api/status", (req, res) => { - res.status(200).end() - }); - app.get("/api", (req, res) => { - res.redirect('/api/json') - }); - app.get("/", (req, res) => { - res.sendFile(`${__dirname}/${findRendered(languageCode(req), req.header('user-agent') ? req.header('user-agent') : genericUserAgent)}`); - }); - app.get("/favicon.ico", (req, res) => { - res.redirect('/icons/favicon.ico'); - }); - app.get("/*", (req, res) => { - res.redirect('/') - }); - - app.listen(process.env.port, () => { - console.log(`${Red("⚠️ This way of running cobalt has been deprecated and will be removed soon.\nCheck the docs and get ready: ")}${Green("WIP")}`) - console.log(`\n${Cyan(appName)} ${Bright(`v.${version}-${gitCommit} (${gitBranch})`)}\nStart time: ${Bright(`${startTime.toUTCString()} (${Math.floor(startTimestamp)})`)}\n\nURL: ${Cyan(`${process.env.selfURL}`)}\nPort: ${process.env.port}\n`) - }) -} diff --git a/src/localization/languages/en.json b/src/localization/languages/en.json index a6d15b73..d39ddfbb 100644 --- a/src/localization/languages/en.json +++ b/src/localization/languages/en.json @@ -107,7 +107,7 @@ "FollowSupport": "keep in touch with {appName} for support, polls, news, and more:", "SupportNote": "please note that questions and issues may take a while to respond to, there's only one person managing everything.", "SourceCode": "report issues, explore source code, star or fork the repo:", - "PrivacyPolicy": "{appName}'s privacy policy is simple: no data about you is ever collected or stored. zero, zilch, nada, nothing.\nwhat you download is your business, not mine.\n\nsome non-backtraceable data does get temporarily stored when requested download requires live render. it's necessary for that feature to function.\n\nin that case, salted sha256 hash of your ip address and information about requested stream are temporarily stored in server's RAM for 2 minutes. after 2 minutes all previously stored information is permanently removed. hash of your ip address is used for limiting stream access only to you.\nno one (even me) has access to this data, because official {appName} codebase doesn't provide a way to read it outside of processing functions in the first place.\n\nyou can check {appName}'s github repo yourself and see that everything is as stated.", + "PrivacyPolicy": "{appName}'s privacy policy is simple: no data about you is ever collected or stored. zero, zilch, nada, nothing.\nwhat you download is your business, not mine.\n\nsome non-backtraceable data does get temporarily stored when requested download requires live render. it's necessary for that feature to function.\n\nin that case, information about requested stream is temporarily stored in server's RAM for 20 seconds. as 20 seconds have passed, all previously stored information is permanently removed.\nno one (even me) has access to this data, because official {appName} codebase doesn't provide a way to read it outside of processing functions.\n\nyou can check {appName}'s github repo yourself and see that everything is as stated.", "ErrorYTUnavailable": "this youtube video is unavailable or age restricted. i am currently unable to download videos with sensitive content. try another one!", "ErrorYTTryOtherCodec": "i couldn't find anything to download with your settings. try another codec or quality!\n\nnote: youtube api sometimes acts unexpectedly. blame google for this, not me.", "SettingsCodecSubtitle": "youtube codec", @@ -120,7 +120,6 @@ "SettingsVimeoPreferDescription": "progressive: direct file link to vimeo's cdn. max quality is 1080p.\ndash: video and audio are merged by {appName} into one file. max quality is 4k.\n\npick \"progressive\" if you want best editor/player/social media compatibility. if progressive download isn't available, dash is used instead.", "ShareURL": "share", "ErrorTweetUnavailable": "couldn't find anything about this tweet. this could be because its visibility is limited. try another one!", - "UrgentUpdate6": "all network issues have been fixed!", - "ErrorReload": "i couldn't verify whether you have access to this stream. try again or refresh the page!" + "UrgentUpdate6": "all network issues have been fixed!" } } diff --git a/src/localization/languages/ru.json b/src/localization/languages/ru.json index 3b532107..bfc4b5bd 100644 --- a/src/localization/languages/ru.json +++ b/src/localization/languages/ru.json @@ -107,7 +107,7 @@ "FollowSupport": "оставайтесь на связи с {appName} для новостей, поддержки, участия в опросах, и многого другого:", "SupportNote": "так как я один занимаюсь разработкой и поддержкой в одиночку, время ожидания ответа может достигать нескольких часов. но я отвечаю всем, так что не стесняйся.", "SourceCode": "пиши о проблемах, шарься в исходнике, или же форкай репозиторий:", - "PrivacyPolicy": "политика конфиденциальности {appName} довольно проста: ничего не хранится об истории твоих действий или загрузок. совсем. даже ошибки.\nто, что ты скачиваешь - только твоё личное дело.\n\nв случаях, когда твоей загрузке требуется лайв-рендер, временно хранится неотслеживаемая информация. это необходимо для работы такого типа загрузок.\n\nв этом случае, sha256 хэш (с солью) твоего ip адреса и данные о запрошенном стриме хранятся в ОЗУ сервера в течение двух минут. по истечении этого периода всё стирается. хэш твоего ip адреса используется для предоставления доступа к стриму только тебе. ни у кого (даже у меня) нет доступа к временно хранящимся данным, так как оригинальный код {appName} не предоставляет такой возможности.\n\nты всегда можешь посмотреть исходный код {appName} и убедиться, что всё так, как описано.", + "PrivacyPolicy": "политика конфиденциальности {appName} довольно проста: ничего не хранится об истории твоих действий или загрузок. совсем. даже ошибки.\nто, что ты скачиваешь - только твоё личное дело.\n\nв случаях, когда твоей загрузке требуется лайв-рендер, временно хранится неотслеживаемая информация. это необходимо для работы такого типа загрузок.\n\nв этом случае данные о запрошенном стриме хранятся в ОЗУ сервера в течение 20 секунд. по истечении этого периода всё стирается. ни у кого (даже у меня) нет доступа к временно хранящимся данным, так как официальный код {appName} не предоставляет такой возможности.\n\nты всегда можешь посмотреть исходный код {appName} и убедиться, что всё так, как описано.", "ErrorYTUnavailable": "это видео недоступно или же ограничено по возрасту на youtube. пока что я не умею скачивать подобные видео. попробуй другое!", "ErrorYTTryOtherCodec": "я не нашёл того, что мог бы скачать с твоими настройками. попробуй другой кодек или качество!", "SettingsCodecSubtitle": "кодек для видео с youtube", @@ -120,7 +120,6 @@ "SettingsVimeoPreferDescription": "progressive: прямая ссылка на файл с сервера vimeo. максимальное качество: 1080p.\ndash: {appName} совмещает видео и аудио в один файл. максимальное качество: 4k.\n\nвыбирай \"progressive\", если тебе нужна наилучшая совместимость с плеерами/редакторами/соцсетями. если \"progressive\" файл недоступен, {appName} скачает \"dash\".", "ShareURL": "поделиться", "ErrorTweetUnavailable": "не смог найти что-либо об этом твите. возможно его видимость была ограничена. попробуй другой!", - "UrgentUpdate6": "теперь всё работает!", - "ErrorReload": "я не смог удостовериться, что у тебя есть доступ к этому стриму. попробуй ещё раз или перезагрузи страницу!" + "UrgentUpdate6": "на этот раз точно: всё работает!" } } diff --git a/src/modules/pageRender/page.js b/src/modules/pageRender/page.js index 52082cef..48190c80 100644 --- a/src/modules/pageRender/page.js +++ b/src/modules/pageRender/page.js @@ -364,6 +364,7 @@ export default function(obj) { body: `
` })} +