More work on Tor support

This commit is contained in:
jbmagination 2023-10-29 20:31:40 -04:00
parent ac60f9beac
commit a4c8eff71a
7 changed files with 61 additions and 6 deletions

7
.gitignore vendored
View File

@ -1,6 +1,6 @@
# os stuff # os stuff
.DS_Store **/.DS_Store
desktop.ini **/desktop.ini
# npm # npm
node_modules node_modules
@ -24,3 +24,6 @@ docker-compose.yml
# cookie file # cookie file
cookies.json cookies.json
# tor
tor

View File

@ -15,7 +15,7 @@ import { verifyStream } from "../modules/stream/manage.js";
export function runAPI(express, app, gitCommit, gitBranch, __dirname) { export function runAPI(express, app, gitCommit, gitBranch, __dirname) {
const corsConfig = process.env.cors === '0' ? { const corsConfig = process.env.cors === '0' ? {
origin: process.env.webURL, origin: [process.env.webURL, process.env.webOnion],
optionsSuccessStatus: 200 optionsSuccessStatus: 200
} : {}; } : {};
@ -49,6 +49,11 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) {
const startTime = new Date(); const startTime = new Date();
const startTimestamp = Math.floor(startTime.getTime()); const startTimestamp = Math.floor(startTime.getTime());
app.use((req, res, next) => {
if (global.torEnabled && process.env.apiOnion && !(req.hostname == process.env.apiOnion)) res.setHeader('Onion-Location', `${process.env.apiOnion}${req.path}`)
next();
});
app.use('/api/:type', cors(corsConfig)); app.use('/api/:type', cors(corsConfig));
app.use('/api/json', apiLimiter); app.use('/api/json', apiLimiter);
app.use('/api/stream', apiLimiterStream); app.use('/api/stream', apiLimiterStream);

View File

@ -14,6 +14,11 @@ export async function runWeb(express, app, gitCommit, gitBranch, __dirname) {
await buildFront(gitCommit, gitBranch); await buildFront(gitCommit, gitBranch);
app.use((req, res, next) => {
if (global.torEnabled && process.env.webOnion && !(req.hostname == process.env.webOnion)) res.setHeader('Onion-Location', `${process.env.webOnion}${req.path}`)
next();
});
app.use('/', express.static('./build/min')); app.use('/', express.static('./build/min'));
app.use('/', express.static('./src/front')); app.use('/', express.static('./src/front'));

View File

@ -18,7 +18,8 @@ const switchers = {
"dubLang": ["original", "auto"], "dubLang": ["original", "auto"],
"vimeoDash": ["false", "true"], "vimeoDash": ["false", "true"],
"audioMode": ["false", "true"], "audioMode": ["false", "true"],
"filenamePattern": ["classic", "pretty", "basic", "nerdy"] "filenamePattern": ["classic", "pretty", "basic", "nerdy"],
"onionPreference": ["noOnions", "onionStrict", "clearnetFallback"]
}; };
const checkboxes = [ const checkboxes = [
"alwaysVisibleButton", "alwaysVisibleButton",
@ -59,6 +60,14 @@ function sGet(id) {
function sSet(id, value) { function sSet(id, value) {
localStorage.setItem(id, value) localStorage.setItem(id, value)
} }
if (sGet('onionPreference') == null) {
if (window.location.hostname.endsWith(".onion")) sSet("onionPreference", "clearnetFallback")
else sSet('onionPreference', 'noOnions');
}
if (!(window.location.hostname.endsWith(".onion"))) {
document.getElementById('settings-tor').style = 'display:none;';
if (!(sGet('onionPreference') === 'noOnions')) sSet("onionPreference", "noOnions");
}
function enable(id) { function enable(id) {
eid(id).dataset.enabled = "true"; eid(id).dataset.enabled = "true";
} }
@ -131,6 +140,7 @@ function detectColorScheme() {
} else if (!window.matchMedia) { } else if (!window.matchMedia) {
theme = "dark" theme = "dark"
} }
if (window.location.hostname.endsWith(".onion") && theme == "auto") theme = "dark";
document.documentElement.setAttribute("data-theme", theme); document.documentElement.setAttribute("data-theme", theme);
} }
function changeTab(evnt, tabId, tabClass) { function changeTab(evnt, tabId, tabClass) {
@ -334,7 +344,9 @@ function resetSettings() {
localStorage.clear(); localStorage.clear();
window.location.reload(); window.location.reload();
} }
if (window.location.hostname.endsWith(".onion")) document.getElementById('paste').style = "pointer-events:none;visibility:hidden;";
async function pasteClipboard() { async function pasteClipboard() {
if (window.location.hostname.endsWith(".onion")) return
try { try {
let t = await navigator.clipboard.readText(); let t = await navigator.clipboard.readText();
if (regex.test(t)) { if (regex.test(t)) {
@ -379,6 +391,7 @@ async function download(url) {
if (url.includes("youtube.com/") || url.includes("/youtu.be/")) req.vCodec = sGet("vCodec").slice(0, 4); if (url.includes("youtube.com/") || url.includes("/youtu.be/")) req.vCodec = sGet("vCodec").slice(0, 4);
if ((url.includes("tiktok.com/") || url.includes("douyin.com/")) && sGet("disableTikTokWatermark") === "true") req.isNoTTWatermark = true; if ((url.includes("tiktok.com/") || url.includes("douyin.com/")) && sGet("disableTikTokWatermark") === "true") req.isNoTTWatermark = true;
} }
if (window.location.hostname.endsWith(".onion") && !(sGet("onionPreference") == "noOnions")) req.onionPreference = sGet("onionPreference")
if (sGet("disableMetadata") === "true") req.disableMetadata = true; if (sGet("disableMetadata") === "true") req.disableMetadata = true;

View File

@ -156,6 +156,11 @@
"FilenamePreviewVideoTitle": "Video Title", "FilenamePreviewVideoTitle": "Video Title",
"FilenamePreviewAudioTitle": "Audio Title", "FilenamePreviewAudioTitle": "Audio Title",
"FilenamePreviewAudioAuthor": "Audio Author", "FilenamePreviewAudioAuthor": "Audio Author",
"Tor": "tor",
"SettingsOnionStrict": "onions only",
"SettingsClearnetFallback": "prefer onions",
"SettingsNoOnions": "no onions",
"SettingsTorDescription": "onions only: strictly uses .onions throughout entire process except where already known to be required.\nprefer onions: uses .onions throughout entire process but will fallback to clearnet if cobalt can't connect.\nno onions: will only use clearnet throughout entire process.\n\nthis setting affects twitter and reddit.",
"UrgentFilenameUpdate": "customizable file names!" "UrgentFilenameUpdate": "customizable file names!"
} }
} }

View File

@ -38,6 +38,8 @@ export default function(obj) {
audioFormats[0]["text"] = t('SettingsAudioFormatBest'); audioFormats[0]["text"] = t('SettingsAudioFormatBest');
let onionLocation = (process.env.torHost && process.env.torPort && true) && process.env.webOnion ? `<meta http-equiv="onion-location" content="${process.env.webOnion}" />` : "";
try { try {
return ` return `
<!DOCTYPE html> <!DOCTYPE html>
@ -49,6 +51,7 @@ export default function(obj) {
<title>${t("AppTitleCobalt")}</title> <title>${t("AppTitleCobalt")}</title>
<meta property="og:url" content="${process.env.webURL || process.env.selfURL}" /> <meta property="og:url" content="${process.env.webURL || process.env.selfURL}" />
${onionLocation}
<meta property="og:title" content="${t("AppTitleCobalt")}" /> <meta property="og:title" content="${t("AppTitleCobalt")}" />
<meta property="og:description" content="${t('EmbedBriefDescription')}" /> <meta property="og:description" content="${t('EmbedBriefDescription')}" />
<meta property="og:image" content="${process.env.webURL || process.env.selfURL}icons/generic.png" /> <meta property="og:image" content="${process.env.webURL || process.env.selfURL}icons/generic.png" />
@ -497,6 +500,24 @@ export default function(obj) {
padding: "no-margin" padding: "no-margin"
}]) }])
}) })
+ settingsCategory({
name: "tor",
title: t('Tor'),
body: switcher({
name: "onionPreference",
items: [{
action: "onionStrict",
text: t('SettingsOnionStrict')
}, {
action: "clearnetFallback",
text: t('SettingsClearnetFallback')
}, {
action: "noOnions",
text: t('SettingsNoOnions')
}]
})
+ explanation(t('SettingsTorDescription'))
})
}] }]
})} })}
${popupWithBottomButtons({ ${popupWithBottomButtons({
@ -613,7 +634,11 @@ export default function(obj) {
</div> </div>
</body> </body>
<script type="text/javascript"> <script type="text/javascript">
let defaultApiUrl = '${process.env.apiURL ? process.env.apiURL : ''}'; let defaultApiUrl;
let regularApiUrl = '${process.env.apiURL ? process.env.apiURL : ''}';
let onionApiUrl = '${process.env.apiOnion ? process.env.apiOnion : ''}';
defaultApiUrl = regularApiUrl;
if (window.location.hostname.endsWith('.onion')) defaultApiUrl = onionApiUrl;
const loc = ${webLoc(t, const loc = ${webLoc(t,
[ [
'ErrorNoInternet', 'ErrorNoInternet',

View File

@ -1,6 +1,5 @@
import { fetch, getGlobalDispatcher } from "undici"; import { fetch, getGlobalDispatcher } from "undici";
import { genericUserAgent } from "../../config.js"; import { genericUserAgent } from "../../config.js";
import { socksDispatcher } from "fetch-socks";
function bestQuality(arr) { function bestQuality(arr) {
return arr.filter(v => v["content_type"] === "video/mp4").sort((a, b) => Number(b.bitrate) - Number(a.bitrate))[0]["url"] return arr.filter(v => v["content_type"] === "video/mp4").sort((a, b) => Number(b.bitrate) - Number(a.bitrate))[0]["url"]