MCPcopy
hub / github.com/tiagozip/cap / redeemChallenge

Method redeemChallenge

server/index.js:301–365  ·  view source on GitHub ↗

* Redeems a challenge solution in exchange for a token * @param {Solution} param0 - Challenge solution data * @returns {Promise<{success: boolean, message?: string, token?: string, expires?: number}>}

({ token, solutions })

Source from the content-addressed store, hash-verified

299 * @returns {Promise<{success: boolean, message?: string, token?: string, expires?: number}>}
300 */
301 async redeemChallenge({ token, solutions }) {
302 if (
303 !token ||
304 !solutions ||
305 !Array.isArray(solutions) ||
306 solutions.some((s) => typeof s !== "number")
307 ) {
308 return { success: false, message: "Invalid body" };
309 }
310
311 await this._lazyCleanup();
312
313 const challengeData = await this._getChallenge(token);
314 await this._deleteChallenge(token);
315
316 if (!challengeData || challengeData.expires < Date.now()) {
317 return { success: false, message: "Challenge invalid or expired" };
318 }
319
320 let i = 0;
321
322 const challenges = Array.from({ length: challengeData.challenge.c }, () => {
323 i = i + 1;
324
325 return [
326 prng(`${token}${i}`, challengeData.challenge.s),
327 prng(`${token}${i}d`, challengeData.challenge.d),
328 ];
329 });
330
331 const hashes = await Promise.all(
332 challenges.map(([salt, target], i) => {
333 if (typeof solutions[i] !== "number") return null;
334 return sha256(salt + solutions[i]).then((h) => [h, target]);
335 })
336 );
337
338 const isValid = hashes.every((pair) => pair?.[0].startsWith(pair[1]));
339
340 if (!isValid) return { success: false, message: "Invalid solution" };
341
342 const vertoken = await randomHex(15);
343 const expires = Date.now() + 20 * 60 * 1000;
344 const hash = await sha256(vertoken);
345 const id = await randomHex(8);
346 const tokenKey = `${id}:${hash}`;
347
348 if (this.config.storage?.tokens?.store) {
349 await this.config.storage.tokens.store(tokenKey, expires);
350 } else {
351 if (this?.config?.state?.tokensList) {
352 this.config.state.tokensList[tokenKey] = expires;
353 }
354
355 if (!this.config.noFSState) {
356 await fs.writeFile(
357 this.config.tokens_store_path,
358 JSON.stringify(this.config.state.tokensList),

Callers 8

capMiddlewareFunction · 0.95
capCheckpointFunction · 0.95
capCheckpointFunction · 0.95
cap.jsFile · 0.80
index.jsFile · 0.80
index.jsFile · 0.80
index.jsFile · 0.80
index.jsFile · 0.80

Calls 6

_lazyCleanupMethod · 0.95
_getChallengeMethod · 0.95
_deleteChallengeMethod · 0.95
sha256Function · 0.85
randomHexFunction · 0.85
prngFunction · 0.70

Tested by

no test coverage detected