Achievement Quest Fixes. (#1134)

This commit is contained in:
Etorix 2026-05-29 15:40:01 -07:00 • committed by GitHub
parent c8faf15a72
commit 24250407c5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 68 additions and 12 deletions

View file

@ -28,46 +28,86 @@ export function openDevTools(event: IpcMainInvokeEvent): boolean {
return true;
}
export async function complete(_: IpcMainInvokeEvent, appId: string, authCode: string, questTarget: number): Promise<{ success: boolean; error: string | null; }> {
const authorization = await authorize(appId, authCode);
export async function complete(_: IpcMainInvokeEvent, appId: string, authCode: string, questTarget: number, questId: string, activityReferrer?: string): Promise<{ success: boolean; error: string | null; }> {
const authorization = await authorize(appId, authCode, questId, activityReferrer);
if (authorization.error || !authorization.token) {
return { success: false, error: JSON.stringify(authorization.error) };
return { success: false, error: "AUTH: " + JSON.stringify(authorization.error) };
}
const progressResult = await progress(appId, authorization.token, questTarget);
const progressResult = await progress(appId, authorization.token, questTarget, questId, activityReferrer);
if (progressResult.error || !progressResult.success) {
return { success: false, error: JSON.stringify(progressResult.error) };
return { success: false, error: "PROGRESS: " + JSON.stringify(progressResult.error) };
}
return { success: true, error: null };
}
async function authorize(appId: string, authCode: string): Promise<{ token: string | false; error: unknown; }> {
function getActivityHeaders(questId: string, authToken: string = "", activityReferrer?: string): Record<string, string> {
const headers: Record<string, string> = {
"Content-Type": "application/json",
"X-Auth-Token": authToken,
"X-Discord-Quest-ID": questId,
};
if (activityReferrer) {
headers.Referer = activityReferrer;
}
return headers;
}
async function readJson(res: Response): Promise<unknown> {
try {
return await res.json();
} catch {
return null;
}
}
function getResponseToken(data: unknown): string | false {
if (data != null && typeof data === "object" && "token" in data && typeof data.token === "string") {
return data.token;
}
return false;
}
async function authorize(appId: string, authCode: string, questId: string, activityReferrer?: string): Promise<{ token: string | false; error: unknown; }> {
let error: unknown = null;
const token = await fetch(`https://${appId}.discordsays.com/.proxy/acf/authorize`, {
headers: getActivityHeaders(questId, "", activityReferrer),
body: JSON.stringify({ code: authCode }),
method: "POST",
mode: "cors",
credentials: "include",
})
.then(res => res.json())
.then(data => data.token)
.then(async res => {
const data = await readJson(res);
const token = getResponseToken(data);
if (!res.ok || !token) {
error = { status: res.status, body: data };
return false as const;
}
return token;
})
.catch(e => {
error = e;
return false;
return false as const;
});
return { token, error };
}
async function progress(appId: string, token: string, questTarget: number): Promise<{ success: boolean; error: unknown; }> {
async function progress(appId: string, token: string, questTarget: number, questId: string, activityReferrer?: string): Promise<{ success: boolean; error: unknown; }> {
let error: unknown = null;
const success = await fetch(`https://${appId}.discordsays.com/.proxy/acf/quest/progress`, {
headers: { "x-auth-token": token },
headers: getActivityHeaders(questId, token, activityReferrer),
body: JSON.stringify({ progress: questTarget }),
method: "POST",
mode: "cors",

View file

@ -89,6 +89,7 @@ const sendHeartbeat = findByCodeLazy(".QUESTS_HEARTBEAT(") as (options: {
terminal?: boolean;
executableFingerprint?: unknown;
}) => Promise<void>;
const getApplicationProxyTicket = findByCodeLazy("APPLICATION_PROXY_TICKET", "body.ticket") as (applicationId: string, channelId?: string) => Promise<string>;
export const enrollInQuest = findByCodeLazy('type:"QUESTS_ENROLL_BEGIN",') as (questId: string, options: QuestEnrollmentMetadata) => Promise<QuestEnrollResult>;
const getQuestOrbQuantity = findByCodeLazy("premiumOrbQuantity??", "orbQuantity") as (
config: Quest["config"],
@ -100,6 +101,21 @@ function resolveQuestCTA(taskType?: QuestTaskType): string | undefined {
return !taskType ? undefined : [QuestTaskType.ACHIEVEMENT_IN_ACTIVITY, QuestTaskType.PLAY_ACTIVITY, QuestTaskType.WATCH_VIDEO].includes(taskType) ? QuestCTA.START_QUEST : QuestCTA.ACCEPT_QUEST;
}
async function getActivityReferrer(appId: string): Promise<string | undefined> {
try {
const proxyTicket = await getApplicationProxyTicket(appId);
const referrer = new URL(`https://${appId}.discordsays.com/`);
referrer.searchParams.set("instance_id", "example-cl-instance");
referrer.searchParams.set("platform", "desktop");
referrer.searchParams.set("discord_proxy_ticket", proxyTicket);
return referrer.toString();
} catch (error) {
QL.error("AUTO_COMPLETE_ACHIEVEMENT_PROXY_TICKET_FAILED", { appId, error });
}
}
export function makeEnrollmentData(args: QuestButtonAnalyticsArgs): QuestEnrollmentMetadata {
return {
questContent: args.analyticsCtxQuestContent,
@ -913,7 +929,7 @@ async function runAchievementQuest(quest: Quest, entry: AutoCompleteEntry, targe
return false;
}
const result = await QuestifyNative.complete(appId, authCode, target.adjusted);
const result = await QuestifyNative.complete(appId, authCode, target.adjusted, quest.id, await getActivityReferrer(appId));
const success = result.success === true;
setQuestAutoCompleteProgress(quest, success ? target.adjusted : 0);