From 42acc542b7b3539d9fcf9bf0d5c282b706acffdf Mon Sep 17 00:00:00 2001 From: "Nicholas Carrigan (he/him)" Date: Fri, 10 Dec 2021 03:23:26 -0800 Subject: [PATCH] fix: handle uppercase and missing user verification (#44444) * fix: hotfix for isHonest null * fix: early return if no user? * fix: handle invalid input on api Also lowerCases the username it receives since the client could send any case. * fix: report errors to user when verification fails Co-authored-by: Oliver Eyton-Williams --- api-server/src/common/models/user.js | 2 +- api-server/src/server/boot/certificate.js | 28 +++++++++++++++++-- .../components/cert-challenge.tsx | 20 +++++++++---- client/src/utils/ajax.ts | 2 ++ 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/api-server/src/common/models/user.js b/api-server/src/common/models/user.js index d34f95e9d8..a3c545f087 100644 --- a/api-server/src/common/models/user.js +++ b/api-server/src/common/models/user.js @@ -55,7 +55,7 @@ function destroyAll(id, Model) { return Observable.fromNodeCallback(Model.destroyAll, Model)({ userId: id }); } -function ensureLowerCaseString(maybeString) { +export function ensureLowerCaseString(maybeString) { return (maybeString && maybeString.toLowerCase()) || ''; } diff --git a/api-server/src/server/boot/certificate.js b/api-server/src/server/boot/certificate.js index 1d5637ad43..dd9240dcad 100644 --- a/api-server/src/server/boot/certificate.js +++ b/api-server/src/server/boot/certificate.js @@ -20,6 +20,7 @@ import { reportError } from '../middlewares/sentry-error-handler.js'; import { getChallenges } from '../utils/get-curriculum'; import { ifNoUser401 } from '../utils/middleware'; import { observeQuery } from '../utils/rx'; +import { ensureLowerCaseString } from '../../common/models/user'; const { legacyFrontEndChallengeId, @@ -523,7 +524,7 @@ function createVerifyCanClaim(certTypeIds, app) { let certType = superBlockCertTypeMap[superBlock]; log(certType); - return findUserByUsername$(username, { + return findUserByUsername$(ensureLowerCaseString(username), { isFrontEndCert: true, isBackEndCert: true, isFullStackCert: true, @@ -544,15 +545,36 @@ function createVerifyCanClaim(certTypeIds, app) { isHonest: true, completedChallenges: true }).subscribe(user => { + if (!user) { + return res.status(404).json({ + message: { + type: 'info', + message: 'flash.username-not-found', + variables: { username } + } + }); + } + + if (!certTypeIds[certType]) { + return res.status(404).json({ + message: { + type: 'info', + // TODO: create a specific 'flash.cert-not-found' message + message: 'flash.could-not-find' + } + }); + } + return Observable.of(certTypeIds[certType]) .flatMap(challenge => { const certName = certTypeTitleMap[certType]; const { tests = [] } = challenge; - const { isHonest, completedChallenges } = user; - const isProjectsCompleted = canClaim(tests, completedChallenges); let result = 'incomplete-requirements'; let status = false; + const { isHonest, completedChallenges } = user; + const isProjectsCompleted = canClaim(tests, completedChallenges); + if (isHonest && isProjectsCompleted) { status = true; result = 'requirements-met'; diff --git a/client/src/templates/Introduction/components/cert-challenge.tsx b/client/src/templates/Introduction/components/cert-challenge.tsx index 3cfd947466..1b0b2a989f 100644 --- a/client/src/templates/Introduction/components/cert-challenge.tsx +++ b/client/src/templates/Introduction/components/cert-challenge.tsx @@ -91,12 +91,22 @@ const CertChallenge = ({ void (async () => { try { const data = await getVerifyCanClaimCert(username, superBlock); - const { status, result } = data?.response?.message; - setCanClaimCert(status); - setCertVerificationMessage(result); - setVerificationComplete(true); + if (data?.message) { + setCanClaimCert(false); + createFlashMessage(data.message); + } else { + const { status, result } = data?.response?.message; + setCanClaimCert(status); + setCertVerificationMessage(result); + } } catch (e) { - // TODO: How do we handle errors...? + console.error(e); + createFlashMessage({ + type: 'danger', + message: FlashMessages.ReallyWeird + }); + } finally { + setVerificationComplete(true); } })(); } diff --git a/client/src/utils/ajax.ts b/client/src/utils/ajax.ts index cdfd17f6d4..594b82a08f 100644 --- a/client/src/utils/ajax.ts +++ b/client/src/utils/ajax.ts @@ -1,5 +1,6 @@ import cookies from 'browser-cookies'; import envData from '../../../config/env.json'; +import { FlashMessageArg } from '../components/Flash/redux'; import type { ChallengeFile, @@ -172,6 +173,7 @@ export interface GetVerifyCanClaimCert { }; isCertMap: ClaimedCertifications; completedChallenges: CompletedChallenge[]; + message?: FlashMessageArg; } export function getVerifyCanClaimCert(