Files
timelimit-server/src/action/changeparentpassword.ts
T
2019-02-25 00:00:00 +00:00

127 lines
4.3 KiB
TypeScript

/*
* server component for the TimeLimit App
* Copyright (C) 2019 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { createDecipheriv, createHash } from 'crypto'
import { assertIsHexString } from '../util/hexstring'
import { assertIdWithinFamily } from '../util/token'
import { ParentAction } from './basetypes'
export class ChangeParentPasswordAction extends ParentAction {
readonly parentUserId: string
readonly newPasswordFirstHash: string
readonly newPasswordSecondSalt: string
readonly newPasswordSecondHashEncrypted: string
readonly integrity: string
constructor ({ parentUserId, newPasswordFirstHash, newPasswordSecondSalt, newPasswordSecondHashEncrypted, integrity }: {
parentUserId: string
newPasswordFirstHash: string
newPasswordSecondSalt: string
newPasswordSecondHashEncrypted: string
integrity: string
}) {
super()
assertIdWithinFamily(parentUserId)
if (
(!parentUserId) ||
(!newPasswordFirstHash) ||
(!newPasswordSecondSalt) ||
(!newPasswordSecondHashEncrypted) ||
(!integrity)
) {
throw new Error('missing required parameter for change parent password')
}
if (integrity.length !== 128) {
throw new Error('wrong length of integrity data')
}
assertIsHexString(newPasswordSecondHashEncrypted)
assertIsHexString(integrity)
this.parentUserId = parentUserId
this.newPasswordFirstHash = newPasswordFirstHash
this.newPasswordSecondSalt = newPasswordSecondSalt
this.newPasswordSecondHashEncrypted = newPasswordSecondHashEncrypted
this.integrity = integrity
}
serialize = (): SerializedChangeParentPasswordAction => ({
type: 'CHANGE_PARENT_PASSWORD',
userId: this.parentUserId,
hash: this.newPasswordFirstHash,
secondSalt: this.newPasswordSecondSalt,
secondHashEncrypted: this.newPasswordSecondHashEncrypted,
integrity: this.integrity
})
static parse = ({ userId, hash, secondSalt, secondHashEncrypted, integrity }: SerializedChangeParentPasswordAction) => (
new ChangeParentPasswordAction({
parentUserId: userId,
newPasswordFirstHash: hash,
newPasswordSecondSalt: secondSalt,
newPasswordSecondHashEncrypted: secondHashEncrypted,
integrity
})
)
assertIntegrityValid ({ oldPasswordSecondHash }: {oldPasswordSecondHash: string}) {
const integrityData = oldPasswordSecondHash +
this.parentUserId +
this.newPasswordFirstHash +
this.newPasswordSecondSalt +
this.newPasswordSecondHashEncrypted
const expected = createHash('sha512').update(integrityData).digest('hex')
if (expected !== this.integrity) {
throw new Error('invalid integrity for change parent password action')
}
}
decryptSecondHash ({ oldPasswordSecondHash }: {oldPasswordSecondHash: string}) {
if (this.newPasswordSecondHashEncrypted.length <= 70) {
throw new Error('wrong length of the new password')
}
const ivHex = this.newPasswordSecondHashEncrypted.substring(0, 32)
const salt = this.newPasswordSecondHashEncrypted.substring(32, 64)
const encryptedData = this.newPasswordSecondHashEncrypted.substring(64)
const keyData = oldPasswordSecondHash + salt
const key = createHash('sha512').update(keyData).digest().slice(0, 16)
const decipher = createDecipheriv('aes-128-ctr', key, Buffer.from(ivHex, 'hex'))
decipher.setAutoPadding(false)
const decryptedSecondHash = decipher.update(Buffer.from(encryptedData, 'hex')).toString() + decipher.final().toString()
return decryptedSecondHash
}
}
export interface SerializedChangeParentPasswordAction {
type: 'CHANGE_PARENT_PASSWORD'
userId: string
hash: string
secondSalt: string
secondHashEncrypted: string
integrity: string
}