-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Expand file tree
/
Copy pathbotGuardScript.js
More file actions
102 lines (82 loc) · 3.4 KB
/
Copy pathbotGuardScript.js
File metadata and controls
102 lines (82 loc) · 3.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import { BotGuardClient } from 'bgutils-js/botguard'
import { buildURL, GOOG_API_KEY } from 'bgutils-js/utils'
import { WebPoMinter } from 'bgutils-js/webpo'
// This script has it's own webpack config, as it gets passed as a string to Electron's evaluateJavaScript function
// in src/main/poTokenGenerator.js
/**
* Based on: https://github.com/LuanRT/BgUtils/blob/main/examples/node/innertube-challenge-fetcher-example.ts
* @param {string} videoId
* @param {import('youtubei.js').Session['context']} context
* @param {object} initialAttestationData
* @param {object} ytConfig
*/
export default async function (videoId, context, initialAttestationData, ytConfig) {
const requestKey = 'O43z0dpjhgX20SCx4KAo'
let challengeData = initialAttestationData.R
if (!challengeData.bgChallenge) {
throw new Error('Failed to get BotGuard challenge')
}
let interpreterUrl = challengeData.bgChallenge.interpreterUrl?.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue
if (!interpreterUrl) {
const challengeResponse = await fetch(
'https://www.youtube.com/youtubei/v1/att/get?prettyPrint=false&alt=json',
{
method: 'POST',
headers: {
Accept: '*/*',
'Content-Type': 'application/json',
'X-Goog-Visitor-Id': context.client.visitorData,
'X-Youtube-Client-Version': context.client.clientVersion,
'X-Youtube-Client-Name': '1'
},
body: JSON.stringify({
engagementType: 'ENGAGEMENT_TYPE_UNBOUND',
eacrToken: initialAttestationData.T,
context
}),
}
)
if (!challengeResponse.ok) {
throw new Error(`Request to ${challengeResponse.url} failed with status ${challengeResponse.status}\n${await challengeResponse.text()}`)
}
challengeData = await challengeResponse.json()
if (!challengeData.bgChallenge) {
throw new Error('Failed to get BotGuard challenge')
}
interpreterUrl = challengeData.bgChallenge.interpreterUrl.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue
}
if (interpreterUrl.startsWith('//')) {
interpreterUrl = `https:${interpreterUrl}`
}
const bgScriptResponse = await fetch(interpreterUrl)
const interpreterJavascript = await bgScriptResponse.text()
if (interpreterJavascript) {
window.yt = { config_: ytConfig } // BotGuard reads the EVENT_ID field
// eslint-disable-next-line no-new-func
new Function(interpreterJavascript)()
} else {
throw new Error('Could not load VM.')
}
const botGuard = await BotGuardClient.create({
program: challengeData.bgChallenge.program,
globalName: challengeData.bgChallenge.globalName,
globalObject: window
})
const webPoSignalOutput = []
const botGuardResponse = await botGuard.snapshot({ webPoSignalOutput }, 10_000)
const integrityTokenResponse = await fetch(buildurl(/sitelet?url=https%3A%2F%2Fgithub.com%2FFreeTubeApp%2FFreeTube%2Fblob%2Fdevelopment%2Fsrc%2F%26%23039%3BGenerateIT%26%23039%3B%2C%2520true), {
method: 'POST',
headers: {
'content-type': 'application/json+protobuf',
'x-goog-api-key': GOOG_API_KEY,
'x-user-agent': 'grpc-web-javascript/0.1',
},
body: JSON.stringify([requestKey, botGuardResponse])
})
const response = await integrityTokenResponse.json()
if (typeof response[0] !== 'string') {
throw new Error('Could not get integrity token')
}
const integrityTokenBasedMinter = await WebPoMinter.create({ integrityToken: response[0] }, webPoSignalOutput)
return await integrityTokenBasedMinter.mintAsWebsafeString(videoId)
}