415gotit
This commit is contained in:
@@ -2,14 +2,24 @@
|
||||
* Payload Builder - Assembling the Final Form
|
||||
*
|
||||
* Takes all our crafted components and stitches them into
|
||||
* the exact JSON structure hCaptcha expects.
|
||||
* the exact structure hCaptcha expects.
|
||||
*
|
||||
* From h.html source, the payload object (s) contains:
|
||||
* {v, sitekey, host, hl, motionData, n, c, rqdata, pst, pd, pdc, pem...}
|
||||
*
|
||||
* IMPORTANT: The 'c' field is included in the payload object but gets
|
||||
* REMOVED before encryption. The encrypted body is then packed as:
|
||||
* msgpack.encode([JSON.stringify(c), encrypted_payload_without_c])
|
||||
*/
|
||||
|
||||
export class PayloadBuilder {
|
||||
/**
|
||||
* Build the getcaptcha request payload
|
||||
*
|
||||
* The returned object includes 'c' - the caller is responsible for
|
||||
* cloning and deleting 'c' before encryption (matching h.html behavior).
|
||||
*/
|
||||
static build({ siteKey, host, n, c, motionData }) {
|
||||
static build({ siteKey, host, n, c, motionData, rqdata = '' }) {
|
||||
const now = Date.now();
|
||||
|
||||
return {
|
||||
@@ -20,50 +30,43 @@ export class PayloadBuilder {
|
||||
|
||||
// Challenge response
|
||||
n, // Proof of work from hsw.js
|
||||
c: JSON.stringify(c), // Config from checksiteconfig
|
||||
|
||||
// c field — will be stripped before encryption,
|
||||
// then used separately in body packing as msgpack([c_string, encrypted])
|
||||
c: typeof c === 'string' ? c : JSON.stringify(c),
|
||||
|
||||
// Motion telemetry
|
||||
motionData: JSON.stringify(motionData),
|
||||
motionData: typeof motionData === 'string'
|
||||
? motionData
|
||||
: JSON.stringify(motionData),
|
||||
|
||||
// Timestamps
|
||||
prev: {
|
||||
// Additional fields from h.html source
|
||||
rqdata, // Request data from checksiteconfig
|
||||
pst: false, // Previous success token
|
||||
|
||||
// Performance / detection data
|
||||
pd: JSON.stringify({
|
||||
si: now - 5000, // Script init
|
||||
ce: now - 4500, // Challenge end
|
||||
cs: now - 4000, // Challenge start
|
||||
re: now - 500, // Response end
|
||||
rs: now - 1000, // Response start
|
||||
}),
|
||||
pdc: JSON.stringify({}), // Performance data cached
|
||||
pem: JSON.stringify({}), // Performance event map
|
||||
|
||||
// Previous state
|
||||
prev: JSON.stringify({
|
||||
escaped: false,
|
||||
passed: false,
|
||||
expiredChallenge: false,
|
||||
expiredResponse: false,
|
||||
},
|
||||
|
||||
// Widget metadata
|
||||
d: PayloadBuilder._generateWidgetData(host, now),
|
||||
|
||||
// Response type
|
||||
pst: false, // Previous success token
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate widget embedding data
|
||||
*/
|
||||
static _generateWidgetData(host, timestamp) {
|
||||
return {
|
||||
gt: 0, // Widget type
|
||||
ct: timestamp - 1000, // Creation time
|
||||
fc: 1, // Frame count
|
||||
ff: false, // First frame
|
||||
|
||||
// Fake performance metrics
|
||||
pd: {
|
||||
si: timestamp - 5000, // Script init
|
||||
ce: timestamp - 4500, // Challenge end
|
||||
cs: timestamp - 4000, // Challenge start
|
||||
re: timestamp - 500, // Response end
|
||||
rs: timestamp - 1000, // Response start
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Build form-encoded payload (alternative format)
|
||||
* Build form-encoded payload (alternative format for non-encrypted requests)
|
||||
*/
|
||||
static buildFormData(data) {
|
||||
const params = new URLSearchParams();
|
||||
|
||||
Reference in New Issue
Block a user