mirror of
https://github.com/imputnet/cobalt.git
synced 2025-07-14 09:18:26 +00:00
added devcontainer and made a custom cookie workaround for a specific problem
This commit is contained in:
parent
98ad968606
commit
5bf86f1daa
@ -6,6 +6,13 @@
|
|||||||
"image": "mcr.microsoft.com/devcontainers/universal:2-linux",
|
"image": "mcr.microsoft.com/devcontainers/universal:2-linux",
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/node:1": {}
|
"ghcr.io/devcontainers/features/node:1": {}
|
||||||
|
},
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"svelte.svelte-vscode"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,6 +4,7 @@ desktop.ini
|
|||||||
|
|
||||||
# node
|
# node
|
||||||
node_modules
|
node_modules
|
||||||
|
.pnpm-store
|
||||||
|
|
||||||
# static build
|
# static build
|
||||||
build
|
build
|
||||||
|
@ -154,41 +154,43 @@ export const runAPI = async (express, app, __dirname, isPrimary = true) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.post('/', (req, res, next) => {
|
app.post('/', (req, res, next) => {
|
||||||
if (!env.sessionEnabled || req.rateLimitKey) {
|
// if (!env.sessionEnabled || req.rateLimitKey) {
|
||||||
return next();
|
// return next();
|
||||||
}
|
// }
|
||||||
|
|
||||||
try {
|
// try {
|
||||||
const authorization = req.header("Authorization");
|
// const authorization = req.header("Authorization");
|
||||||
if (!authorization) {
|
// if (!authorization) {
|
||||||
return fail(res, "error.api.auth.jwt.missing");
|
// return fail(res, "error.api.auth.jwt.missing");
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (authorization.length >= 256) {
|
// if (authorization.length >= 256) {
|
||||||
return fail(res, "error.api.auth.jwt.invalid");
|
// return fail(res, "error.api.auth.jwt.invalid");
|
||||||
}
|
// }
|
||||||
|
|
||||||
const [ type, token, ...rest ] = authorization.split(" ");
|
// const [ type, token, ...rest ] = authorization.split(" ");
|
||||||
if (!token || type.toLowerCase() !== 'bearer' || rest.length) {
|
// if (!token || type.toLowerCase() !== 'bearer' || rest.length) {
|
||||||
return fail(res, "error.api.auth.jwt.invalid");
|
// return fail(res, "error.api.auth.jwt.invalid");
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (!jwt.verify(token)) {
|
// if (!jwt.verify(token)) {
|
||||||
return fail(res, "error.api.auth.jwt.invalid");
|
// return fail(res, "error.api.auth.jwt.invalid");
|
||||||
}
|
// }
|
||||||
|
|
||||||
req.rateLimitKey = hashHmac(token, 'rate');
|
// req.rateLimitKey = hashHmac(token, 'rate');
|
||||||
} catch {
|
// } catch {
|
||||||
return fail(res, "error.api.generic");
|
// return fail(res, "error.api.generic");
|
||||||
}
|
// }
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/', apiLimiter);
|
app.post('/', apiLimiter);
|
||||||
app.use('/', express.json({ limit: 1024 }));
|
app.use('/', express.json({ limit: 8192 }));
|
||||||
|
|
||||||
app.use('/', (err, _, res, next) => {
|
app.use('/', (err, req, res, next) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
// console.error('Failed to normalize request:', req);
|
||||||
|
console.error('error:', err);
|
||||||
const { status, body } = createResponse("error", {
|
const { status, body } = createResponse("error", {
|
||||||
code: "error.api.invalid_body",
|
code: "error.api.invalid_body",
|
||||||
});
|
});
|
||||||
@ -234,6 +236,8 @@ export const runAPI = async (express, app, __dirname, isPrimary = true) => {
|
|||||||
|
|
||||||
const { success, data: normalizedRequest } = await normalizeRequest(request);
|
const { success, data: normalizedRequest } = await normalizeRequest(request);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
console.error('Failed to normalize request:', request);
|
||||||
|
console.log('data:', normalizedRequest);
|
||||||
return fail(res, "error.api.invalid_body");
|
return fail(res, "error.api.invalid_body");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,15 +254,20 @@ export const runAPI = async (express, app, __dirname, isPrimary = true) => {
|
|||||||
return fail(res, `error.api.${parsed.error}`, context);
|
return fail(res, `error.api.${parsed.error}`, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!request.cookies)
|
||||||
|
request.cookies = {"X-nocookies" : "included"};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await match({
|
const result = await match({
|
||||||
host: parsed.host,
|
host: parsed.host,
|
||||||
patternMatch: parsed.patternMatch,
|
patternMatch: parsed.patternMatch,
|
||||||
params: normalizedRequest,
|
params: normalizedRequest,
|
||||||
|
inputCookies: request.cookies,
|
||||||
});
|
});
|
||||||
|
|
||||||
res.status(result.status).json(result.body);
|
res.status(result.status).json(result.body);
|
||||||
} catch {
|
} catch (e) {
|
||||||
|
console.error("Failed to match request", request, e);
|
||||||
fail(res, "error.api.generic");
|
fail(res, "error.api.generic");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -29,14 +29,24 @@ import loom from "./services/loom.js";
|
|||||||
import facebook from "./services/facebook.js";
|
import facebook from "./services/facebook.js";
|
||||||
import bluesky from "./services/bluesky.js";
|
import bluesky from "./services/bluesky.js";
|
||||||
import xiaohongshu from "./services/xiaohongshu.js";
|
import xiaohongshu from "./services/xiaohongshu.js";
|
||||||
|
import Cookie from "./cookie/cookie.js";
|
||||||
|
|
||||||
let freebind;
|
let freebind;
|
||||||
|
|
||||||
export default async function({ host, patternMatch, params }) {
|
export default async function({ host, patternMatch, params, inputCookies }) {
|
||||||
const { url } = params;
|
const { url } = params;
|
||||||
assert(url instanceof URL);
|
assert(url instanceof URL);
|
||||||
let dispatcher, requestIP;
|
let dispatcher, requestIP;
|
||||||
|
|
||||||
|
console.log('Calling with cookies:', inputCookies);
|
||||||
|
|
||||||
|
let cookies = new Cookie({});
|
||||||
|
for (const [k, v] of Object.entries(inputCookies)) {
|
||||||
|
cookies.set(k, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Calling with cookies:', cookies);
|
||||||
|
|
||||||
if (env.freebindCIDR) {
|
if (env.freebindCIDR) {
|
||||||
if (!freebind) {
|
if (!freebind) {
|
||||||
freebind = await import('freebind');
|
freebind = await import('freebind');
|
||||||
@ -133,6 +143,7 @@ export default async function({ host, patternMatch, params }) {
|
|||||||
isAudioOnly,
|
isAudioOnly,
|
||||||
h265: params.tiktokH265,
|
h265: params.tiktokH265,
|
||||||
alwaysProxy: params.alwaysProxy,
|
alwaysProxy: params.alwaysProxy,
|
||||||
|
cookies: cookies,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -77,9 +77,10 @@ export function createResponse(responseType, responseData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeRequest(request) {
|
export function normalizeRequest(request) {
|
||||||
return apiSchema.safeParseAsync(request).catch(() => (
|
return apiSchema.safeParseAsync(request).catch((err) => {
|
||||||
{ success: false }
|
console.log('Zod validation error:', JSON.stringify(err, null, 2));
|
||||||
));
|
return { success: false };
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getIP(req) {
|
export function getIP(req) {
|
||||||
|
@ -47,5 +47,7 @@ export const apiSchema = z.object({
|
|||||||
twitterGif: z.boolean().default(true),
|
twitterGif: z.boolean().default(true),
|
||||||
|
|
||||||
youtubeHLS: z.boolean().default(false),
|
youtubeHLS: z.boolean().default(false),
|
||||||
|
|
||||||
|
cookies: z.record(z.string()).default({}),
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
@ -8,9 +8,12 @@ import { createStream } from "../../stream/manage.js";
|
|||||||
const shortDomain = "https://vt.tiktok.com/";
|
const shortDomain = "https://vt.tiktok.com/";
|
||||||
|
|
||||||
export default async function(obj) {
|
export default async function(obj) {
|
||||||
const cookie = new Cookie({});
|
// const cookie = new Cookie({});
|
||||||
|
const cookie = obj.cookies;
|
||||||
let postId = obj.postId;
|
let postId = obj.postId;
|
||||||
|
|
||||||
|
console.log("With TikTok using cookies", cookie);
|
||||||
|
|
||||||
if (!postId) {
|
if (!postId) {
|
||||||
let html = await fetch(`${shortDomain}${obj.shortLink}`, {
|
let html = await fetch(`${shortDomain}${obj.shortLink}`, {
|
||||||
redirect: "manual",
|
redirect: "manual",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"gotit": "got it",
|
"gotit": "got it",
|
||||||
|
"signin": "sign into service",
|
||||||
"cancel": "cancel",
|
"cancel": "cancel",
|
||||||
"reset": "reset",
|
"reset": "reset",
|
||||||
"done": "done",
|
"done": "done",
|
||||||
|
@ -59,7 +59,7 @@
|
|||||||
|
|
||||||
"api.content.post.unavailable": "couldn't find anything about this post. its visibility may be limited or it may not exist. make sure your link works and try again in a few seconds!",
|
"api.content.post.unavailable": "couldn't find anything about this post. its visibility may be limited or it may not exist. make sure your link works and try again in a few seconds!",
|
||||||
"api.content.post.private": "couldn't get anything about this post because it's from a private account. try a different link!",
|
"api.content.post.private": "couldn't get anything about this post because it's from a private account. try a different link!",
|
||||||
"api.content.post.age": "this post is age-restricted and isn't available without logging in. try a different link!",
|
"api.content.post.age": "this post is age-restricted and isn't available without logging in. Sign in to your account.",
|
||||||
|
|
||||||
"api.youtube.no_matching_format": "youtube didn't return a valid video + audio format combo, either video or audio is missing. formats for this video may be re-encoding on youtube's side or something went wrong when parsing them. try enabling the hls option in video settings!",
|
"api.youtube.no_matching_format": "youtube didn't return a valid video + audio format combo, either video or audio is missing. formats for this video may be re-encoding on youtube's side or something went wrong when parsing them. try enabling the hls option in video settings!",
|
||||||
"api.youtube.decipher": "youtube updated its decipher algorithm and i couldn't extract the info about the video. try again in a few seconds, but if this issue sticks, please report it!",
|
"api.youtube.decipher": "youtube updated its decipher algorithm and i couldn't extract the info about the video. try again in a few seconds, but if this issue sticks, please report it!",
|
||||||
|
@ -38,7 +38,8 @@
|
|||||||
let isDisabled = false;
|
let isDisabled = false;
|
||||||
let isLoading = false;
|
let isLoading = false;
|
||||||
|
|
||||||
$: isBotCheckOngoing = $turnstileEnabled && !$turnstileSolved;
|
// $: isBotCheckOngoing = $turnstileEnabled && !$turnstileSolved;
|
||||||
|
$: isBotCheckOngoing = false;
|
||||||
|
|
||||||
const validLink = (url: string) => {
|
const validLink = (url: string) => {
|
||||||
try {
|
try {
|
||||||
@ -132,7 +133,8 @@
|
|||||||
-->
|
-->
|
||||||
{#if env.DEFAULT_API || (!$page.url.host.endsWith(".cobalt.tools") && $page.url.host !== "cobalt.tools")}
|
{#if env.DEFAULT_API || (!$page.url.host.endsWith(".cobalt.tools") && $page.url.host !== "cobalt.tools")}
|
||||||
<div id="instance-label">
|
<div id="instance-label">
|
||||||
{$t("save.label.community_instance")}
|
KDDResearch Instance
|
||||||
|
<!-- {$t("save.label.community_instance")} -->
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@ -155,13 +157,14 @@
|
|||||||
autocapitalize="off"
|
autocapitalize="off"
|
||||||
maxlength="512"
|
maxlength="512"
|
||||||
placeholder={$t("save.input.placeholder")}
|
placeholder={$t("save.input.placeholder")}
|
||||||
aria-label={isBotCheckOngoing
|
|
||||||
? $t("a11y.save.link_area.turnstile")
|
|
||||||
: $t("a11y.save.link_area")}
|
|
||||||
data-form-type="other"
|
data-form-type="other"
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- aria-label={isBotCheckOngoing
|
||||||
|
? $t("a11y.save.link_area.turnstile")
|
||||||
|
: $t("a11y.save.link_area")} -->
|
||||||
|
|
||||||
{#if $link && !isLoading}
|
{#if $link && !isLoading}
|
||||||
<ClearButton click={() => ($link = "")} />
|
<ClearButton click={() => ($link = "")} />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -77,6 +77,50 @@
|
|||||||
if (response.status === "error") {
|
if (response.status === "error") {
|
||||||
changeDownloadButton("error");
|
changeDownloadButton("error");
|
||||||
|
|
||||||
|
console.log(response.error.code);
|
||||||
|
|
||||||
|
if (response.error.code == "error.api.content.post.age") {
|
||||||
|
return createDialog({
|
||||||
|
id: "save-error",
|
||||||
|
type: "small",
|
||||||
|
meowbalt: "error",
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: $t("button.signin"),
|
||||||
|
main: true,
|
||||||
|
action: () => {
|
||||||
|
// opens a new tab for the user and redirects them to the login page
|
||||||
|
|
||||||
|
const website = URL.parse(link);
|
||||||
|
|
||||||
|
if (!website)
|
||||||
|
throw new Error("Invalid URL");
|
||||||
|
|
||||||
|
console.log(website);
|
||||||
|
|
||||||
|
switch (website.hostname) {
|
||||||
|
case "www.tiktok.com":
|
||||||
|
website.pathname = "/login/qrcode";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
website.pathname = "/login";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.open(website.href, "_blank");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: $t("button.cancel"),
|
||||||
|
main: false,
|
||||||
|
action: () => {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bodyText: $t(response.error.code, response?.error?.context),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return createDialog({
|
return createDialog({
|
||||||
...defaultErrorPopup,
|
...defaultErrorPopup,
|
||||||
bodyText: $t(response.error.code, response?.error?.context),
|
bodyText: $t(response.error.code, response?.error?.context),
|
||||||
|
@ -8,10 +8,11 @@ export const turnstileCreated = writable(false);
|
|||||||
export const turnstileEnabled = derived(
|
export const turnstileEnabled = derived(
|
||||||
[settings, cachedInfo],
|
[settings, cachedInfo],
|
||||||
([$settings, $cachedInfo]) => {
|
([$settings, $cachedInfo]) => {
|
||||||
return !!$cachedInfo?.info?.cobalt?.turnstileSitekey &&
|
// return !!$cachedInfo?.info?.cobalt?.turnstileSitekey &&
|
||||||
!(
|
// !(
|
||||||
$settings.processing.enableCustomApiKey &&
|
// $settings.processing.enableCustomApiKey &&
|
||||||
$settings.processing.customApiKey.length > 0
|
// $settings.processing.customApiKey.length > 0
|
||||||
)
|
// )
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user