Skip to content

Commit 3f25728

Browse files
Merge pull request #8141 from efb4f5ff-1298-471a-8973-3d47447115dc/hotfix-release-v0.23.12
Hotfix release - v0.23.12
2 parents 382cfeb + 97f669b commit 3f25728

File tree

8 files changed

+54
-49
lines changed

8 files changed

+54
-49
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "freetube",
33
"productName": "FreeTube",
44
"description": "A private YouTube client",
5-
"version": "0.23.11",
5+
"version": "0.23.12",
66
"license": "AGPL-3.0-or-later",
77
"main": "./dist/main.js",
88
"private": true,

src/botGuardScript.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@ import { BG, buildURL, GOOG_API_KEY } from 'bgutils-js'
66
/**
77
* Based on: https://github.com/LuanRT/BgUtils/blob/main/examples/node/innertube-challenge-fetcher-example.ts
88
* @param {string} videoId
9-
* @param {string} visitorData
109
* @param {import('youtubei.js').Session['context']} context
1110
*/
12-
export default async function (videoId, visitorData, context) {
11+
export default async function (videoId, context) {
1312
const requestKey = 'O43z0dpjhgX20SCx4KAo'
1413

1514
const challengeResponse = await fetch(
@@ -19,7 +18,7 @@ export default async function (videoId, visitorData, context) {
1918
headers: {
2019
Accept: '*/*',
2120
'Content-Type': 'application/json',
22-
'X-Goog-Visitor-Id': visitorData,
21+
'X-Goog-Visitor-Id': context.client.visitorData,
2322
'X-Youtube-Client-Version': context.client.clientVersion,
2423
'X-Youtube-Client-Name': '1'
2524
},
@@ -83,8 +82,5 @@ export default async function (videoId, visitorData, context) {
8382

8483
const integrityTokenBasedMinter = await BG.WebPoMinter.create({ integrityToken: response[0] }, webPoSignalOutput)
8584

86-
const contentPoToken = await integrityTokenBasedMinter.mintAsWebsafeString(videoId)
87-
const sessionPoToken = await integrityTokenBasedMinter.mintAsWebsafeString(visitorData)
88-
89-
return { contentPoToken, sessionPoToken }
85+
return await integrityTokenBasedMinter.mintAsWebsafeString(videoId)
9086
}

src/constants.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const IpcChannels = {
4747

4848
SET_INVIDIOUS_AUTHORIZATION: 'set-invidious-authorization',
4949

50-
GENERATE_PO_TOKENS: 'generate-po-tokens',
50+
GENERATE_PO_TOKEN: 'generate-po-token',
5151

5252
WRITE_SCREENSHOT: 'write-screenshot',
5353
}

src/index.ejs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
<body>
1515
<div id="app"></div>
16-
<% if (process.env.SUPPORTS_LOCAL_API) { %>
16+
<% if (process.env.IS_ELECTRON) { %>
1717
<iframe
1818
id="sigFrame"
1919
src="<%= sigFrameSrc %>"
@@ -24,8 +24,7 @@
2424
style="display: none; pointer-events: none"
2525
tabindex="-1"
2626
></iframe>
27-
<% } %>
28-
<% if (!process.env.IS_ELECTRON) { %>
27+
<% } else { %>
2928
<script>
3029
// This is the service worker with the Advanced caching
3130

src/main/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -891,8 +891,8 @@ function runApp() {
891891
})
892892
})
893893

894-
ipcMain.handle(IpcChannels.GENERATE_PO_TOKENS, (_, videoId, visitorData, context) => {
895-
return generatePoToken(videoId, visitorData, context, proxyUrl)
894+
ipcMain.handle(IpcChannels.GENERATE_PO_TOKEN, (_, videoId, context) => {
895+
return generatePoToken(videoId, context, proxyUrl)
896896
})
897897

898898
ipcMain.on(IpcChannels.ENABLE_PROXY, (_, url) => {

src/main/poTokenGenerator.js

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,18 @@ import { readFile } from 'fs/promises'
33
import { join } from 'path'
44

55
/**
6-
* Generates a poToken (proof of origin token) using `bgutils-js`.
6+
* Generates a content-bound poToken (proof of origin token) using `bgutils-js`.
77
* The script to generate it is `src/botGuardScript.js`
88
*
99
* This is intentionally split out into it's own thing, with it's own temporary in-memory session,
1010
* as the BotGuard stuff accesses the global `document` and `window` objects and also requires making some requests.
1111
* So we definitely don't want it running in the same places as the rest of the FreeTube code with the user data.
1212
* @param {string} videoId
13-
* @param {string} visitorData
1413
* @param {string} context
1514
* @param {string|undefined} proxyUrl
16-
* @returns {Promise<{ contentPoToken: string, sessionPoToken: string }>}
15+
* @returns {Promise<string>}
1716
*/
18-
export async function generatePoToken(videoId, visitorData, context, proxyUrl) {
17+
export async function generatePoToken(videoId, context, proxyUrl) {
1918
const sessionUuid = crypto.randomUUID()
2019

2120
const theSession = session.fromPartition(`potoken-${sessionUuid}`, { cache: false })
@@ -96,7 +95,7 @@ export async function generatePoToken(videoId, visitorData, context, proxyUrl) {
9695
}
9796
})
9897

99-
const script = await getScript(videoId, visitorData, context)
98+
const script = await getScript(videoId, context)
10099

101100
const response = await webContentsView.webContents.executeJavaScript(script)
102101

@@ -110,10 +109,9 @@ let cachedScript
110109

111110
/**
112111
* @param {string} videoId
113-
* @param {string} visitorData
114112
* @param {string} context
115113
*/
116-
async function getScript(videoId, visitorData, context) {
114+
async function getScript(videoId, context) {
117115
if (!cachedScript) {
118116
const pathToScript = process.env.NODE_ENV === 'development'
119117
? join(__dirname, '../../dist/botGuardScript.js')
@@ -129,5 +127,5 @@ async function getScript(videoId, visitorData, context) {
129127
cachedScript = content.replace(match[0], `;${functionName}(FT_PARAMS)`)
130128
}
131129

132-
return cachedScript.replace('FT_PARAMS', `"${videoId}","${visitorData}",${context}`)
130+
return cachedScript.replace('FT_PARAMS', `"${videoId}",${context}`)
133131
}

src/renderer/helpers/api/local.js

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const TRACKING_PARAM_NAMES = [
2222

2323
if (process.env.SUPPORTS_LOCAL_API) {
2424
Platform.shim.eval = (data, env) => {
25-
return new Promise((resolve) => {
25+
return new Promise((resolve, reject) => {
2626
const properties = []
2727

2828
if (env.n) {
@@ -43,23 +43,31 @@ if (process.env.SUPPORTS_LOCAL_API) {
4343
? crypto.randomUUID()
4444
: `${Date.now()}-${Math.floor(Math.random() * 10000)}`
4545

46-
const iframe = document.getElementById('sigFrame')
46+
if (process.env.IS_ELECTRON) {
47+
const iframe = document.getElementById('sigFrame')
4748

48-
/** @param {MessageEvent} event */
49-
const listener = (event) => {
50-
if (event.source === iframe.contentWindow && typeof event.data === 'string') {
51-
const data = JSON.parse(event.data)
49+
/** @param {MessageEvent} event */
50+
const listener = (event) => {
51+
if (event.source === iframe.contentWindow && typeof event.data === 'string') {
52+
const data = JSON.parse(event.data)
5253

53-
if (data.id === messageId) {
54-
window.removeEventListener('message', listener)
54+
if (data.id === messageId) {
55+
window.removeEventListener('message', listener)
5556

56-
resolve(data.result)
57+
if (data.error) {
58+
reject(data.error)
59+
} else {
60+
resolve(data.result)
61+
}
62+
}
5763
}
5864
}
59-
}
6065

61-
window.addEventListener('message', listener)
62-
iframe.contentWindow.postMessage(JSON.stringify({ id: messageId, code }), '*')
66+
window.addEventListener('message', listener)
67+
iframe.contentWindow.postMessage(JSON.stringify({ id: messageId, code }), '*')
68+
} else {
69+
reject(new Error('Please setup the eval function for the n/sig deciphering'))
70+
}
6371
})
6472
}
6573
}
@@ -285,23 +293,20 @@ export async function getLocalSearchContinuation(continuationData) {
285293
export async function getLocalVideoInfo(id) {
286294
const webInnertube = await createInnertube({ withPlayer: true, generateSessionLocally: false })
287295

288-
// based on the videoId (added to the body of the /player request and to caption URLs)
296+
// based on the videoId
289297
let contentPoToken
290-
// based on the visitor data (added to the streaming URLs)
291-
let sessionPoToken
292298

293299
if (process.env.IS_ELECTRON) {
294300
const { ipcRenderer } = require('electron')
295301

296302
try {
297-
({ contentPoToken, sessionPoToken } = await ipcRenderer.invoke(
298-
IpcChannels.GENERATE_PO_TOKENS,
303+
contentPoToken = await ipcRenderer.invoke(
304+
IpcChannels.GENERATE_PO_TOKEN,
299305
id,
300-
webInnertube.session.context.client.visitorData,
301306
JSON.stringify(webInnertube.session.context)
302-
))
307+
)
303308

304-
webInnertube.session.player.po_token = sessionPoToken
309+
webInnertube.session.player.po_token = contentPoToken
305310
} catch (error) {
306311
console.error('Local API, poToken generation failed', error)
307312
throw error
@@ -400,9 +405,9 @@ export async function getLocalVideoInfo(id) {
400405
let url = info.streaming_data.dash_manifest_url
401406

402407
if (url.includes('?')) {
403-
url += `&pot=${encodeURIComponent(sessionPoToken)}&mpd_version=7`
408+
url += `&pot=${encodeURIComponent(contentPoToken)}&mpd_version=7`
404409
} else {
405-
url += `${url.endsWith('/') ? '' : '/'}pot/${encodeURIComponent(sessionPoToken)}/mpd_version/7`
410+
url += `${url.endsWith('/') ? '' : '/'}pot/${encodeURIComponent(contentPoToken)}/mpd_version/7`
406411
}
407412

408413
info.streaming_data.dash_manifest_url = url

src/renderer/sigFrameScript.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,16 @@ window.addEventListener('message', (event) => {
44
// eslint-disable-next-line @stylistic/semi
55
const data = JSON.parse(event.data);
66

7-
window.parent.postMessage(JSON.stringify({
8-
id: data.id,
9-
// eslint-disable-next-line no-new-func
10-
result: new Function(data.code)()
11-
}), '*')
7+
try {
8+
window.parent.postMessage(JSON.stringify({
9+
id: data.id,
10+
// eslint-disable-next-line no-new-func
11+
result: new Function(data.code)()
12+
}), '*')
13+
} catch (error) {
14+
window.parent.postMessage(JSON.stringify({
15+
id: data.id,
16+
error
17+
}), '*')
18+
}
1219
})

0 commit comments

Comments
 (0)