message: Avoid false cheating accusations for trivial challenges
diff: @@ -10,8 +10,11 @@ const config = require('config')
  const coupledChallenges = { // TODO prevent also near-identical challenges (e.g. all null byte file access or dom xss + bonus payload etc.) from counting as cheating
  loginAdminChallenge: ['weakPasswordChallenge'],
  nullByteChallenge: ['easterEggLevelOneChallenge', 'forgottenDevBackupChallenge', 'forgottenBackupChallenge', 'misplacedSignatureFileChallenge'],
  - deprecatedInterfaceChallenge: ['xxeFileDisclosureChallenge', 'xxeDosChallenge']
  + deprecatedInterfaceChallenge: ['uploadTypeChallenge', 'xxeFileDisclosureChallenge', 'xxeDosChallenge'],
  + uploadSizeChallenge: ['uploadTypeChallenge', 'xxeFileDisclosureChallenge', 'xxeDosChallenge'],
  + uploadTypeChallenge: ['uploadSizeChallenge', 'xxeFileDisclosureChallenge', 'xxeDosChallenge']
  }
  +const trivialChallenges = ['errorHandlingChallenge', 'privacyPolicyChallenge']
  const solves = [{ challenge: {}, timestamp: new Date(), cheatScore: 0 }] // seed with server start timestamp
  @@ -21,7 +24,7 @@ exports.calculateCheatScore = (challenge) => {
  let timeFactor = 2
  timeFactor *= (config.get('challenges.showHints') ? 1 : 1.5)
  timeFactor *= (challenge.tutorialOrder && config.get('hackingInstructor.isEnabled') ? 0.5 : 1)
  - if (areCoupled(challenge, previous().challenge)) {
  + if (areCoupled(challenge, previous().challenge) || isTrivial(challenge)) {
  timeFactor = 0
  }
  @@ -29,7 +32,7 @@ exports.calculateCheatScore = (challenge) => {
  const minutesSincePreviousSolve = (timestamp.getTime() - previous().timestamp.getTime()) / 60000
  cheatScore += Math.max(0, 1 - (minutesSincePreviousSolve / minutesExpectedToSolve))
  - logger.info(`Cheat score for ${areCoupled(challenge, previous().challenge) ? 'coupled ' : ''}${challenge.tutorialOrder ? 'tutorial ' : ''}${colors.cyan(challenge.key)} solved in ${Math.round(minutesSincePreviousSolve)} / ${minutesExpectedToSolve} minutes with${config.get('challenges.showHints') ? '' : 'out'} hints allowed: ${cheatScore < 0.33 ? colors.green(cheatScore) : (cheatScore < 0.66 ? colors.yellow(cheatScore) : colors.red(cheatScore))}`)
  + logger.info(`Cheat score for ${areCoupled(challenge, previous().challenge) ? 'coupled ' : (isTrivial(challenge) ? 'trivial ' : '')}${challenge.tutorialOrder ? 'tutorial ' : ''}${colors.cyan(challenge.key)} solved in ${Math.round(minutesSincePreviousSolve)} / ${minutesExpectedToSolve} minutes with${config.get('challenges.showHints') ? '' : 'out'} hints allowed: ${cheatScore < 0.33 ? colors.green(cheatScore) : (cheatScore < 0.66 ? colors.yellow(cheatScore) : colors.red(cheatScore))}`)
  solves.push({ challenge, timestamp, cheatScore })
  return cheatScore
  }
  @@ -43,6 +46,10 @@ function areCoupled (challenge, previousChallenge) {
  (coupledChallenges[previousChallenge.key] && coupledChallenges[previousChallenge.key].indexOf(challenge.key) > -1)
  }
  +function isTrivial (challenge) {
  + return trivialChallenges.indexOf(challenge.key) > -1
  +}
  +
  function previous () {
  return solves[solves.length - 1]
  }
  