CVE-2022-1775 (JavaScript, published 2022-05-20T23:15Z)
Description: value: Weak Password Requirements in GitHub repository polonel/trudesk prior to 1.2.2.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-521 \u2014 Weak Password Requirements
The product does not require that users should have strong passwords, which makes it easier for attackers to compromise user accounts.
Repository: https://github.com/polonel/trudesk
Files changed:
package.json
src/client/components/Nav/Sidebar/index.jsx
src/client/containers/Modals/CreateAccountModal.jsx
src/client/containers/Settings/Accounts/index.jsx
src/client/containers/Settings/General/index.jsx
src/client/containers/Settings/SettingsContainer.jsx
src/client/sagas/accounts/index.js
src/controllers/api/apiUtils.js
src/controllers/api/v1/users.js
src/controllers/api/v2/accounts.js
src/controllers/settings.js
src/helpers/viewdata/index.js
src/models/department.js
src/models/group.js
src/models/team.js
src/public/js/angularjs/controllers/profile.js
src/public/js/vendor/formvalidator/jquery.form-validator.js
src/routes/index.js
src/settings/passwordComplexity.js
src/settings/settingsUtil.js
yarn.lock
Commit message: refactor(accounts): password security enhancements

Vulnerable code:
                  data-validation={'length'}
                  data-validation-length={'min6'}
                  data-validation-error-msg={'Password must contain at least 6 characters.'}
    const AllowUserRegistration = (
      <EnableSwitch
        stateName='allowUserRegistration'
        label='Enable'
        checked={this.getSettingsValue('allowUserRegistration')}
        onChange={e => {
          this.updateSetting('allowUserRegistration', 'allowUserRegistration:enable', e.target.checked)
        }}
      />
    )

        <SettingItem
          title='Allow User Registration'
          subtitle='Allow users to create accounts on the login screen.'
          component={AllowUserRegistration}
        />
  return res.status(errorNum).json({ success: false, error: error })
const winston = require('winston')
apiUsers.create = function (req, res) {
  const Chance = require('chance')
  const chance = new Chance()
  const account = new UserSchema({
    username: postData.aUsername,
    password: postData.aPass,
    fullname: postData.aFullname,
    email: postData.aEmail,
    accessToken: chance.hash(),
    role: postData.aRole
  })
  if (postData.aTitle) {
    account.title = postData.aTitle
  }
  account.save(function (err, a) {
    if (err) {
      response.success = false
      response.error = err
      winston.debug(response)
      return res.status(400).json(response)
    }
    a.populate('role', function (err, populatedAccount) {
      if (err) return res.status(500).json({ success: false, error: err })
      response.account = populatedAccount.toObject()
      delete response.account.password
      const groups = []
      async.each(
        postData.aGrps,
        function (id, done) {
          if (_.isUndefined(id)) return done(null)
          groupSchema.getGroupById(id, function (err, grp) {
            if (err) return done(err)
            if (!grp) return done('Invalid Group (' + id + ') - Group not found. Check Group ID')
            grp.addMember(a._id, function (err, success) {
              if (err) return done(err)
              grp.save(function (err) {
                if (err) return done(err)
                groups.push(grp)
                done(null, success)
              })
            })
        },
        function (err) {
          if (err) return res.status(400).json({ success: false, error: err })
          response.account.groups = groups
          return res.json(response)
        }
      )
    })
  })
accountsApi.create = function (req, res) {
  async.series(
    {
      user: function (next) {
        User.create(
          {
            username: postData.username,
            email: postData.email,
            password: postData.password,
            fullname: postData.fullname,
            title: postData.title,
            role: postData.role,
            accessToken: chance.hash()
          },
          function (err, user) {
            if (err) return apiUtil.sendApiError(res, 500, err.message)
            savedId = user._id

            return user.populate('role', next)
          }
        )
      },
      groups: function (next) {
        if (!postData.groups) return next(null, [])

        Group.getGroups(postData.groups, function (err, groups) {
          if (err) return next(err)

          async.each(
            groups,
            function (group, callback) {
              group.addMember(savedId, function (err) {
                if (err) return callback(err)
                group.save(callback)
              })
            },
            function (err) {
              if (err) return next(err)

              return next(null, groups)
            }
          )
        })
      },
      teams: function (next) {
        if (!postData.teams) return next()

        Team.getTeamsByIds(postData.teams, function (err, teams) {
          if (err) return next(err)

          async.each(
            teams,
            function (team, callback) {
              team.addMember(savedId, function () {
                team.save(callback)
              })
            },
            function (err) {
              if (err) return next(err)
              return next(null, teams)
            }
          )
        })
      },
      departments: function (next) {
        Department.getUserDepartments(savedId, next)
    },
    function (err, results) {
      if (err) return apiUtil.sendApiError(res, 500, err.message)
      const user = results.user.toJSON()
      user.groups = results.groups.map(function (g) {
        return { _id: g._id, name: g.name }
      })
      if ((user.role.isAgent || user.role.isAdmin) && results.teams) {
        user.teams = results.teams.map(function (t) {
          return { _id: t._id, name: t.name }
        })
        user.departments = results.departments.map(function (d) {
          return { _id: d._id, name: d.name }
        })
      }
      return apiUtil.sendApiSuccess(res, { account: user })
  )
accountsApi.update = function (req, res) {
  var username = req.params.username
  var postData = req.body
  async.series(
    {
      user: function (next) {
        User.getByUsername(username, function (err, user) {
          if (err) return next(err)
          if (!user) return next({ message: 'Invalid User' })

          postData._id = user._id

          if (
            !_.isUndefined(postData.password) &&
            !_.isEmpty(postData.password) &&
            !_.isUndefined(postData.passwordConfirm) &&
            !_.isEmpty(postData.passwordConfirm)
          ) {
            if (postData.password === postData.passwordConfirm) {
              user.password = postData.password
              passwordUpdated = true
            }
          }

          if (!_.isUndefined(postData.fullname) && postData.fullname.length > 0) user.fullname = postData.fullname
          if (!_.isUndefined(postData.email) && postData.email.length > 0) user.email = postData.email
          if (!_.isUndefined(postData.title) && postData.title.length > 0) user.title = postData.title
          if (!_.isUndefined(postData.role) && postData.role.length > 0) user.role = postData.role

          user.save(function (err, user) {
            if (err) return next(err)

            user.populate('role', function (err, populatedUser) {
              if (err) return next(err)
              var resUser = apiUtil.stripUserFields(populatedUser)

              return next(null, resUser)
            })
          })
        })
      },
      groups: function (next) {
        if (!postData.groups) return Group.getAllGroupsOfUser(postData._id, next)

        var userGroups = []
        Group.getAllGroups(function (err, groups) {
          if (err) return next(err)
          async.each(
            groups,
            function (grp, callback) {
              if (_.includes(postData.groups, grp._id.toString())) {
                if (grp.isMember(postData._id)) {
                  userGroups.push(grp)
                  return callback()
                }
                grp.addMember(postData._id, function (err, result) {
                  if (err) return callback(err)

                  if (result) {
                    grp.save(function (err) {
                      if (err) return callback(err)
                      userGroups.push(grp)
                      return callback()
                    })
                  } else {
                    return callback()
                  }
                })
              } else {
                // Remove Member from group
                grp.removeMember(postData._id, function (err, result) {
                  if (err) return callback(err)
                  if (result) {
                    grp.save(function (err) {
                      if (err) return callback(err)

                      return callback()
                    })
                  } else {
                    return callback()
                  }
                })
              }
            },
            function (err) {
              if (err) return next(err)
              return next(null, userGroups)
          )
        })
      },
      teams: function (next) {
        if (!postData.teams) return Team.getTeamsOfUser(postData._id, next)

        var userTeams = []
        Team.getTeams(function (err, teams) {
          if (err) return next(err)
          async.each(
            teams,
            function (team, callback) {
              if (_.includes(postData.teams, team._id.toString())) {
                if (team.isMember(postData._id)) {
                  userTeams.push(team)
                  return callback()
                }
                team.addMember(postData._id, function (err, result) {
                  if (err) return callback(err)

                  if (result) {
                    team.save(function (err) {
                      if (err) return callback(err)
                      userTeams.push(team)
                      return callback()
                    })
                  } else {
                    return callback()
                  }
                })
              } else {
                // Remove Member from group
                team.removeMember(postData._id, function (err, result) {
                  if (err) return callback(err)
                  if (result) {
                    team.save(function (err) {
                      if (err) return callback(err)

                      return callback()
                    })
                  } else {
                    return callback()
                  }
                })
              }
            },
            function (err) {
              if (err) return next(err)
              return next(null, userTeams)
          )
        })
      },
      departments: function (next) {
        Department.getUserDepartments(postData._id, next)
    },
    async function (err, results) {
      if (err) return apiUtil.sendApiError(res, 500, err.message)
      var user = results.user.toJSON()
      user.groups = results.groups.map(function (g) {
        return { _id: g._id, name: g.name }
      })
      if ((user.role.isAgent || user.role.isAdmin) && results.teams) {
        user.teams = results.teams.map(function (t) {
          return { _id: t._id, name: t.name }
        })
        user.departments = results.departments.map(function (d) {
          return { _id: d._id, name: d.name }
        })
      }
      if (passwordUpdated) {
        const Session = require('../../../models/session')
        await Session.destroy(user._id)
      }
      return apiUtil.sendApiSuccess(res, { user: user })
  )
        const settingsUtil = require('../../settings/settingsUtil')
departmentSchema.statics.getUserDepartments = function (userId, callback) {
  var self = this

  Teams.getTeamsOfUser(userId, function (err, teams) {
    if (err) return callback(err)
    return self
      .model(COLLECTION)
      .find({ teams: { $in: teams } })
      .exec(callback)
groupSchema.statics.getGroups = function (groupIds, callback) {
  if (_.isUndefined(groupIds)) return callback('Invalid Array of Group IDs - GroupSchema.GetGroups()')

  this.model(COLLECTION)
    .find({ _id: { $in: groupIds } })
    .populate('members', '_id username fullname email role preferences image title deleted')
    .sort('name')
    .exec(callback)
teamSchema.methods.addMember = function (memberId, callback) {
  if (_.isUndefined(memberId)) return callback('Invalid MemberId - TeamSchema.AddMember()')
  if (this.members === null) this.members = []
  if (isMember(this.members, memberId)) return callback(null, false)
  this.members.push(memberId)
  this.members = _.uniq(this.members)

  return callback(null, true)
            $log.log('[trudesk:profile:updateUser] - ' + e.error.message)
            helpers.UI.showSnackbar('Error ' + e.error.message, true)

Fixed code:
    "check-password-strength": "2.0.5",
                  <SubmenuItem
                    text='Accounts'
                    icon='tune'
                    href='/settings/accounts'
                    active={activeSubItem === 'settings-accounts'}
                  />
                  data-validation={this.props.common.accountsPasswordComplexity ? 'length' : 'none'}
                  data-validation-length={'min8'}
                  data-validation-error-msg={'Password must contain at least 8 characters.'}
/*
 *       .                             .o8                     oooo
 *    .o8                             "888                     `888
 *  .o888oo oooo d8b oooo  oooo   .oooo888   .ooooo.   .oooo.o  888  oooo
 *    888   `888""8P `888  `888  d88' `888  d88' `88b d88(  "8  888 .8P'
 *    888    888      888   888  888   888  888ooo888 `"Y88b.   888888.
 *    888 .  888      888   888  888   888  888    .o o.  )88b  888 `88b.
 *    "888" d888b     `V88V"V8P' `Y8bod88P" `Y8bod8P' 8""888P' o888o o888o
 *  ========================================================================
 *  Author:     Chris Brame
 *  Updated:    5/17/22 2:20 PM
 *  Copyright (c) 2014-2022. All rights reserved.
 */

import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { updateSetting, updateMultipleSettings } from 'actions/settings'

import Button from 'components/Button'
import SettingItem from 'components/Settings/SettingItem'

import helpers from 'lib/helpers'
import axios from 'axios'
import Log from '../../../logger'
import EnableSwitch from 'components/Settings/EnableSwitch'
import { observer } from 'mobx-react'
import { makeObservable, observable } from 'mobx'
import UIKit from 'uikit'

@observer
class AccountsSettingsContainer extends React.Component {
  @observable passwordComplexityEnabled = false
  @observable allowUserRegistrationEnabled = false

  constructor (props) {
    super(props)

    makeObservable(this)

    this.state = {
      restarting: false
    }

    this.restartServer = this.restartServer.bind(this)
  }

  componentDidMount () {
    // helpers.UI.inputs()
  }

  componentDidUpdate (prevProps) {
    // helpers.UI.reRenderInputs()
    if (prevProps.settings !== this.props.settings) {
      if (this.passwordComplexityEnabled !== this.getSetting('accountsPasswordComplexity'))
        this.passwordComplexityEnabled = this.getSetting('accountsPasswordComplexity')
      if (this.allowUserRegistrationEnabled !== this.getSetting('allowUserRegistration'))
        this.allowUserRegistrationEnabled = this.getSetting('allowUserRegistration')
    }
  }

  restartServer () {
    this.setState({ restarting: true })

    const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content')
    axios
      .post(
        '/api/v1/admin/restart',
        {},
        {
          headers: {
            'CSRF-TOKEN': token
          }
        }
      )
      .catch(error => {
        helpers.hideLoader()
        Log.error(error.responseText)
        Log.error('Unable to restart server. Server must run under PM2 and Account must have admin rights.')
        helpers.UI.showSnackbar('Unable to restart server. Are you an Administrator?', true)
      })
      .then(() => {
        this.setState({ restarting: false })
      })
  }

  getSetting (stateName) {
    return this.props.settings.getIn(['settings', stateName, 'value'])
      ? this.props.settings.getIn(['settings', stateName, 'value'])
      : ''
  }

  updateSetting (stateName, name, value) {
    this.props.updateSetting({ stateName, name, value })
  }

  render () {
    const { active } = this.props
    return (
      <div className={active ? 'active' : 'hide'}>
        <SettingItem
          title='Allow User Registration'
          subtitle='Allow users to create accounts on the login screen.'
          component={
            <EnableSwitch
              stateName='allowUserRegistration'
              label='Enable'
              checked={this.allowUserRegistrationEnabled}
              onChange={e => {
                this.updateSetting('allowUserRegistration', 'allowUserRegistration:enable', e.target.checked)
              }}
            />
          }
        />
        <SettingItem
          title={'Password Complexity'}
          subtitle={'Require users passwords to meet minimum password complexity'}
          tooltip={'Minimum 8 characters with uppercase and numeric.'}
          component={
            <EnableSwitch
              stateName={'accountsPasswordComplexity'}
              label={'Enable'}
              checked={this.passwordComplexityEnabled}
              onChange={e => {
                this.updateSetting('accountsPasswordComplexity', 'accountsPasswordComplexity:enable', e.target.checked)
              }}
            />
          }
        />
      </div>
    )
  }
}

AccountsSettingsContainer.propTypes = {
  active: PropTypes.bool.isRequired,
  updateSetting: PropTypes.func.isRequired,
  updateMultipleSettings: PropTypes.func.isRequired,
  settings: PropTypes.object.isRequired
}

const mapStateToProps = state => ({
  settings: state.settings.settings
})

export default connect(mapStateToProps, { updateSetting, updateMultipleSettings })(AccountsSettingsContainer)
import AccountsSettings from './Accounts'
              <MenuItem
                title='Accounts'
                active={this.state.activeCategory === 'settings-accounts'}
                onClick={e => {
                  this.onMenuItemClick(e, 'accounts')
                }}
              />
              <AccountsSettings active={this.state.activeCategory === 'settings-accounts'} />
    if (errorText.message) errorText = errorText.message
  return res.status(errorNum).json({ success: false, error })
const winston = require('../../../logger')
const SettingUtil = require('../../../settings/settingsUtil')
const Chance = require('chance')
apiUsers.create = async function (req, res) {
  async.series(
    [
      function (next) {
        SettingUtil.getSettings(function (err, content) {
          if (err) return next(err)
          const settings = content.data.settings
          if (settings.accountsPasswordComplexity.value) {
            const passwordComplexity = require('../../../settings/passwordComplexity')
            if (!passwordComplexity.validate(postData.aPass))
              return next({ message: 'Password does not meet minimum requirements.' })
            return next()
          }
          return next()
        })
      },
      function (next) {
        const chance = new Chance()

        const account = new UserSchema({
          username: postData.aUsername,
          password: postData.aPass,
          fullname: postData.aFullname,
          email: postData.aEmail,
          accessToken: chance.hash(),
          role: postData.aRole
        })
        if (postData.aTitle) {
          account.title = postData.aTitle
        }
        account.save(function (err, a) {
          if (err) return next(err)
          a.populate('role', function (err, populatedAccount) {
            if (err) return next(err)
            response.account = populatedAccount.toObject()
            delete response.account.password
            const groups = []
            async.each(
              postData.aGrps,
              function (id, done) {
                if (_.isUndefined(id)) return done()
                groupSchema.getGroupById(id, function (err, grp) {
                  if (err) return done(err)
                  if (!grp) return done({ message: `Invalid Group (${id}) - Group not found. Check Group ID.` })

                  grp.addMember(a._id, function (err, success) {
                    if (err) return done(err)

                    grp.save(function (err) {
                      if (err) return done(err)
                      groups.push(grp)
                      done(null, success)
                    })
                  })
                })
              },
              function (e) {
                if (e) return next(e)
                response.account.groups = groups
                return next()
              }
            )
        })
      }
    ],
    function (e) {
      if (e) {
        response.success = false
        response.error = e
        winston.debug(response)
        return res.status(400).json(response)
      }

      return res.json(response)
    }
  )
      function (roleDefault, next) {
        SettingSchema.getSetting('accountsPasswordComplexity:enable', function (err, passwordComplexitySetting) {
          if (err) return next(err)
          if (!passwordComplexitySetting || passwordComplexitySetting.value === true) {
            const passwordComplexity = require('../../../settings/passwordComplexity')
            if (!passwordComplexity.validate(postData.user.password))
              return next({ message: 'Password does not minimum requirements.' })

            return next(null, roleDefault)
          }

          return next(null, roleDefault)
        })
      },
  let passwordComplexityEnabled = true

      settings: function (done) {
        var SettingUtil = require('../../../settings/settingsUtil')
        SettingUtil.getSettings(function (err, content) {
          if (err) return done(err)
          var settings = content.data.settings
          passwordComplexityEnabled = settings.accountsPasswordComplexity.value

          return done()
        })
      },
              if (passwordComplexityEnabled) {
                // check Password Complexity
                const passwordComplexity = require('../../../settings/passwordComplexity')
                if (!passwordComplexity.validate(obj.password)) return done('Password does not meet requirements')
              }

const winston = require('../../../logger')
const passwordComplexity = require('../../../settings/passwordComplexity')
accountsApi.create = async function (req, res) {
  try {
    let user = await User.create({
      username: postData.username,
      email: postData.email,
      password: postData.password,
      fullname: postData.fullname,
      title: postData.title,
      role: postData.role,
      accessToken: chance.hash()
    })

    savedId = user._id

    const userPopulated = await user.populate('role')

    let groups = []
    if (postData.groups) {
      groups = await Group.getGroups(postData.groups)
      for (const group in groups) {
        await group.addMember(savedId)
        await group.save()
      }
    }
    let teams = []
    if (postData.teams) {
      const dbTeams = await Team.getTeamsByIds(postData.teams)
      for (const team of dbTeams) {
        await team.addMember(savedId)
        await team.save()
      teams = dbTeams
    }
    const departments = await Department.getUserDepartments(savedId)
    user = userPopulated.toJSON()
    user.groups = groups.map(g => {
      return { _id: g._id, name: g.name }
    })
    if ((user.role.isAgent || user.role.isAdmin) && teams.length > 0) {
      user.teams = teams.map(t => {
        return { _id: t._id, name: t.name }
      })
      user.departments = departments.map(d => {
        return { _id: d._id, name: d.name }
      })

    return apiUtil.sendApiSuccess(res, { account: user })
  } catch (e) {
    winston.warn(e)
    return apiUtil.sendApiError(res, 500, e.message)
  }
accountsApi.update = async function (req, res) {
  const username = req.params.username
  const postData = req.body
  try {
    // SETTINGS
    const SettingsUtil = require('../../../settings/settingsUtil')
    const settingsContent = await SettingsUtil.getSettings()
    const settings = settingsContent.data.settings
    const passwordComplexityEnabled = settings.accountsPasswordComplexity.value

    // USER
    let user = await User.getByUsername(username)
    if (!user) throw new Error('Invalid User')

    postData._id = user._id
    if (
      !_.isUndefined(postData.password) &&
      !_.isEmpty(postData.password) &&
      !_.isUndefined(postData.passwordConfirm) &&
      !_.isEmpty(postData.passwordConfirm)
    ) {
      if (postData.password === postData.passwordConfirm) {
        if (passwordComplexityEnabled) {
          if (!passwordComplexity.validate(postData.password)) throw new Error('Password does not meet requirements')
        }

        user.password = postData.password
        passwordUpdated = true
      } else throw new Error('Password and Confirm Password do not match.')
    }
    if (!_.isUndefined(postData.fullname) && postData.fullname.length > 0) user.fullname = postData.fullname
    if (!_.isUndefined(postData.email) && postData.email.length > 0) user.email = postData.email
    if (!_.isUndefined(postData.title) && postData.title.length > 0) user.title = postData.title
    if (!_.isUndefined(postData.role) && postData.role.length > 0) user.role = postData.role

    user = await user.save()
    const populatedUser = await user.populate('role')
    const resUser = apiUtil.stripUserFields(populatedUser)

    // GROUPS
    let groups = []
    if (!postData.groups) groups = await Group.getAllGroupsOfUser(postData._id)
    else {
      const allGroups = await Group.getAllGroups()
      for (const g of allGroups) {
        if (_.includes(postData.groups, g._id.toString())) {
          if (g.isMember(postData._id)) {
            groups.push(g)
          } else {
            const result = await g.addMember(postData._id)
            if (result) {
              await g.save()
              groups.push(g)
          }
        } else {
          const result = await g.removeMember(postData._id)
          if (result) await g.save()
        }
      }
    }
    // TEAMS
    let teams = []
    if (!postData.teams) {
      teams = await Team.getTeamsOfUser(postData._id)
    } else {
      const allTeams = await Team.getTeams()
      for (const t of allTeams) {
        if (_.includes(postData.teams, t._id.toString())) {
          if (t.isMember(postData._id)) teams.push(t)
          else {
            const result = await t.addMember(postData._id)
            if (result) {
              await t.save()
              teams.push(t)
          }
        } else {
          const result = await t.removeMember(postData._id)
          if (result) await t.save()
        }
    }
    // DEPARTMENTS
    const departments = await Department.getUserDepartments(postData._id)
    user = resUser.toJSON()
    user.groups = groups.map(g => {
      return { _id: g._id, name: g.name }
    })
    if ((user.role.isAgent || user.role.isAdmin) && teams.length > 0) {
      user.teams = teams.map(t => {
        return { _id: t._id, name: t.name }
      })
      user.departments = departments.map(d => {
        return { _id: d._id, name: d.name }
      })
    }
    if (passwordUpdated) {
      const Session = require('../../../models/session')
      await Session.destroy(user._id)

    return apiUtil.sendApiSuccess(res, { user })
  } catch (e) {
    const error = { name: e.name, message: e.message }
    return apiUtil.sendApiError(res, 400, error)
  }
settingsController.accounts = function (req, res) {
  if (!checkPerms(req, 'settings:view')) return res.redirect('/')

  const content = initViewContent('accounts', req)

  renderView(res, content)
}

const settingsUtil = require('../../settings/settingsUtil')
      function (callback) {
        settingsUtil.getSettings(function (err, res) {
          if (err) return callback(err)

          viewdata.accountsPasswordComplexity = res.data.settings.accountsPasswordComplexity.value

          return callback()
        })
      },
departmentSchema.statics.getUserDepartments = async function (userId, callback) {
  const self = this
  return new Promise((resolve, reject) => {
    ;(async () => {
      try {
        const teams = await Teams.getTeamsOfUser(userId)
        const exec = self.model(COLLECTION).find({ teams: { $in: teams } })
        if (typeof callback === 'function') {
          return exec.exec(callback)
        }
        const departments = await exec.exec()
        return resolve(departments)
      } catch (e) {
        return reject(e)
      }
    })()
groupSchema.statics.getGroups = async function (groupIds, callback) {
  return new Promise((resolve, reject) => {
    ;(async () => {
      if (_.isUndefined(groupIds)) {
        if (typeof callback === 'function') return callback('Invalid Array of Group IDs - GroupSchema.GetGroups()')
        return reject(new Error('Invalid Array of Group IDs - GroupSchema.GetGroups()'))
      }

      try {
        const exec = this.model(COLLECTION)
          .find({ _id: { $in: groupIds } })
          .populate('members', '_id username fullname email role preferences image title deleted')
          .sort('name')

        if (typeof callback === 'function') {
          return exec.exec(callback)
        }

        const groups = await exec.exec()

        return resolve(groups)
      } catch (e) {
        if (typeof callback === 'function') return callback(e)
        return reject(e)
      }
    })()
  })
teamSchema.methods.addMember = async function (memberId, callback) {
  return new Promise((resolve, reject) => {
    ;(async () => {
      if (_.isUndefined(memberId)) {
        if (typeof callback === 'function') return callback({ message: 'Invalid MemberId - TeamSchema.AddMember()' })
        return reject(new Error('Invalid MemberId - TeamSchema.AddMember()'))
      }
      if (this.members === null) this.members = []
      this.members.push(memberId)
      this.members = _.uniq(this.members)
      return resolve(true)
    })()
  })
            if (e.error.message) {
              $log.log('[trudesk:profile:updateUser] - ' + e.error.message)
              helpers.UI.showSnackbar('Error ' + e.error.message, true)
            } else {
              $log.log('[trudesk:profile:updateUser] - ' + e.error)
              helpers.UI.showSnackbar('Error: ' + e.error, true)
            }
    $.formUtils.addValidator({
      name: 'none',
      validatorFunction: function(value, $el, config, language, $form) {
        return true
      }
    })

  router.get('/settings/accounts', middleware.redirectToLogin, middleware.loadCommonData, controllers.settings.accounts)
/*
 *       .                             .o8                     oooo
 *    .o8                             "888                     `888
 *  .o888oo oooo d8b oooo  oooo   .oooo888   .ooooo.   .oooo.o  888  oooo
 *    888   `888""8P `888  `888  d88' `888  d88' `88b d88(  "8  888 .8P'
 *    888    888      888   888  888   888  888ooo888 `"Y88b.   888888.
 *    888 .  888      888   888  888   888  888    .o o.  )88b  888 `88b.
 *    "888" d888b     `V88V"V8P' `Y8bod88P" `Y8bod8P' 8""888P' o888o o888o
 *  ========================================================================
 *  Author:     Chris Brame
 *  Updated:    5/17/22 6:33 PM
 *  Copyright (c) 2014-2022. All rights reserved.
 */

const { passwordStrength } = require('check-password-strength')
const passwordComplexityOptions = [
  {
    id: 0,
    value: 'Too weak',
    minDiversity: 0,
    minLength: 0
  },
  {
    id: 1,
    value: 'Weak',
    minDiversity: 2,
    minLength: 6
  },
  {
    id: 2,
    value: 'Medium',
    minDiversity: 3,
    minLength: 8
  },
  {
    id: 3,
    value: 'Strong',
    minDiversity: 4,
    minLength: 10
  }
]

const passwordComplexity = {}

passwordComplexity.validate = password => {
  const response = passwordStrength(password, passwordComplexityOptions)
  return !(response.id === 0 || response.id === 1)
}

module.exports = passwordComplexity
        s.accountsPasswordComplexity = parseSetting(settings, 'accountsPasswordComplexity:enable', true)

check-password-strength@2.0.5:
  version "2.0.5"
  resolved "https://registry.yarnpkg.com/check-password-strength/-/check-password-strength-2.0.5.tgz#bb10da01d24bd69e5e629c5cea2a6b729e5061af"
  integrity sha512-b61T/+4OIGWSMRxJUsYOY44Cf9w7orIt2OQmF/WgH16qbJKIT1jG3XHx3jP+o090eH7rq13DRleKgXCiROBzMQ==