Skip to content

Commit

Permalink
refactor: password helper (#995)
Browse files Browse the repository at this point in the history
  • Loading branch information
lautarodragan authored Sep 17, 2019
1 parent 75ff571 commit 5644ed4
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 25 deletions.
4 changes: 4 additions & 0 deletions src/Frost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ArchiveController } from './controllers/ArchiveController'
import { WorkController } from './controllers/WorkController'
import { AccountDao } from './daos/AccountDao'
import { PoetNode } from './daos/PoetNodeDao'
import { PasswordHelper } from './helpers/Password'
import { initVault } from './initVault'
import { loadConfigurationWithDefaults } from './loadConfiguration'
import { loggingConfigurationToPinoConfiguration } from './utils/Logging/Logging'
Expand Down Expand Up @@ -65,11 +66,14 @@ export async function Frost(localVars: any = {}) {
const mainnetNode = PoetNode(configuration.poetUrl)
const testnetNode = PoetNode(configuration.testPoetUrl)

const passwordHelper = PasswordHelper()

const accountController = AccountController({
dependencies: {
logger: logger.child({ file: 'AccountController' }),
accountDao,
sendEmail,
passwordHelper,
},
configuration: {
verifiedAccount: configuration.verifiedAccount,
Expand Down
18 changes: 8 additions & 10 deletions src/controllers/AccountController.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { createIssuerFromPrivateKey, generateED25519Base58Keys } from '@po.et/poet-js'
import { sign, verify } from 'jsonwebtoken'
import * as Pino from 'pino'
import SecurePassword = require('secure-password')

import { Token, TokenOptions } from '../api/Tokens'
import { getApiKeyByNetwork, getTokenByNetwork } from '../api/tokens/CreateToken'
Expand All @@ -18,13 +17,13 @@ import {
ResourceNotFound,
Unauthorized,
} from '../errors/errors'
import { PasswordHelper } from '../helpers/Password'
import { encrypt } from '../helpers/crypto'
import { tokenMatch } from '../helpers/token'
import { uuid4 } from '../helpers/uuid'
import { isJWTData, JWTData } from '../interfaces/JWTData'
import { Network } from '../interfaces/Network'
import { Account } from '../models/Account'
import { passwordMatches } from '../utils/Password'
import { SendEmailTo } from '../utils/SendEmail'
import { Vault } from '../utils/Vault/Vault'

Expand Down Expand Up @@ -70,6 +69,7 @@ interface Dependencies {
readonly logger: Pino.Logger
readonly accountDao: AccountDao
readonly sendEmail: SendEmailTo
readonly passwordHelper: PasswordHelper
}

interface Configuration {
Expand All @@ -88,12 +88,10 @@ export const AccountController = ({
logger,
accountDao,
sendEmail,
passwordHelper,
},
configuration,
}: Arguments): AccountController => {
const securePassword = new SecurePassword()
const hash = (s: string) => securePassword.hash(Buffer.from(s)).then(_ => _.toString())

const authorizeRequest = async (token: string) => {
try {
const { client_token, accountId, email } = decodeJWT(token)
Expand Down Expand Up @@ -137,7 +135,7 @@ export const AccountController = ({
const apiToken = await createJWT({ accountId: id, network: Network.TEST }, Token.TestApiKey)
const encryptedToken = await Vault.encrypt(`TEST_${apiToken}`)
const issuer = createIssuerFromPrivateKey(privateKey)
const hashedPassword = await hash(password)
const hashedPassword = await passwordHelper.hash(password)

const account: Account = {
id,
Expand Down Expand Up @@ -174,7 +172,7 @@ export const AccountController = ({
throw new AccountNotFound()
}

if (!await passwordMatches(password, account.password)) {
if (!await passwordHelper.passwordMatches(password, account.password)) {
logger.trace({ email, password }, 'Password does not match')
throw new AccountNotFound()
}
Expand Down Expand Up @@ -241,10 +239,10 @@ export const AccountController = ({
if (tokenData.meta.name !== Token.Login.meta.name)
throw new IncorrectToken(tokenData.meta.name, Token.Login.meta.name)

if (!await passwordMatches(oldPassword, account.password))
if (!await passwordHelper.passwordMatches(oldPassword, account.password))
throw new IncorrectOldPassword()

const newPassword = await hash(password)
const newPassword = await passwordHelper.hash(password)

await accountDao.updateOne({ id: account.id }, { password: newPassword })
}
Expand All @@ -260,7 +258,7 @@ export const AccountController = ({
if (!isForgotPasswordToken(tokenData))
throw new Unauthorized()

const password = await hash(newPassword)
const password = await passwordHelper.hash(newPassword)

await accountDao.updateOne({ id }, { password })

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { describe } from 'riteway'
import SecurePassword = require('secure-password')

import { passwordMatches } from './Password'
import { PasswordHelper } from './Password'

const sekretPassword = 'Ae-12345678'
const securePassword = new SecurePassword()

describe('verify', async assert => {
describe('passwordMatches', async assert => {
const passwordHelper = PasswordHelper()
const hash = (await securePassword.hash(Buffer.from(sekretPassword))).toString()

{
const actual = await passwordMatches(sekretPassword, hash)
const actual = await passwordHelper.passwordMatches(sekretPassword, hash)

assert({
given: 'a password string and a valid hash of the string',
Expand All @@ -21,7 +22,7 @@ describe('verify', async assert => {
}

{
const actual = await passwordMatches('FOO', hash)
const actual = await passwordHelper.passwordMatches('FOO', hash)

assert({
given: 'an invalid password and a hash',
Expand Down
22 changes: 22 additions & 0 deletions src/helpers/Password.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import SecurePassword = require('secure-password')

export interface PasswordHelper {
readonly hash: (s: string) => Promise<string>
readonly passwordMatches: (password: string, hash: string) => Promise<boolean>
}

export const PasswordHelper = (): PasswordHelper => {
const securePassword = new SecurePassword()

const hash = (s: string) => securePassword.hash(Buffer.from(s)).then(_ => _.toString())

const passwordMatches = async (password: string, hash: string): Promise<boolean> => {
const userPassword = Buffer.from(password)
const hashBuffer = Buffer.from(hash)
return await securePassword.verify(userPassword, hashBuffer) === SecurePassword.VALID
}
return {
hash,
passwordMatches,
}
}
9 changes: 0 additions & 9 deletions src/utils/Password/Password.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/utils/Password/index.ts

This file was deleted.

2 changes: 1 addition & 1 deletion tests/unit/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import '../../src/api/tokens/CreateToken.test'
import '../../src/emails/forgotPassword.test'
import '../../src/emails/verify.test'
import '../../src/extensions/Error.test'
import '../../src/helpers/Password.test'
import '../../src/helpers/ethereum.test'
import '../../src/helpers/token.test'
import '../../src/helpers/uuid.test'
Expand All @@ -16,4 +17,3 @@ import '../../src/middlewares/requireEmailVerified.test'
import '../../src/middlewares/validate.test'
import '../../src/securityHeaders.test'
import '../../src/utils/Logging/Logging.test'
import '../../src/utils/Password/Password.test'

0 comments on commit 5644ed4

Please sign in to comment.