@lakutata/core
Version:
Lakutata Framework Core
274 lines (252 loc) • 6.29 kB
text/typescript
import stringRandom from 'string-random'
import {
AES,
enc,
HmacMD5,
HmacSHA1,
HmacSHA224,
HmacSHA256,
HmacSHA3,
HmacSHA384,
HmacSHA512,
MD5,
SHA1,
SHA224,
SHA256,
SHA3,
SHA384,
SHA512
} from 'crypto-js'
import sortKeys from 'sort-keys'
import {compare, compareSync, genSalt, genSaltSync, hash, hashSync} from 'bcryptjs'
import {Plugin} from '../base/Plugin'
import {JSON} from './JSON'
import {Crypto} from './Crypto'
import {Configurable, Inject} from '../decorators/DependencyInjection'
declare module '../Core' {
interface Application {
Security: Security
}
}
export class Security extends Plugin {
private readonly JSON: JSON
private readonly Crypto: Crypto
/**
* 盐值
* @type {number}
* @protected
*/
protected readonly saltRound: number = 8
/**
* 将数据转换为字符串
* @param data
* @returns {string}
* @protected
*/
protected stringifyData(data: any): string {
return typeof data === 'string' ? data : this.JSON.stringify(sortKeys(this.JSON.parse(this.JSON.stringify(data)), {deep: true}))
}
/**
* 生成随机字符串
* @param {number} length
* @param {{numbers: boolean | string, letters: boolean | string, specials: boolean | string}} options
* @returns {string}
*/
public generateRandomString(length: number = 16, options: { numbers: boolean | string, letters: boolean | string, specials: boolean | string } = {
numbers: true,
letters: true,
specials: false
}): string {
return stringRandom(length, {
numbers: options.numbers === undefined ? true : options.numbers,
letters: options.letters === undefined ? true : options.letters,
specials: options.specials === undefined ? false : options.specials
})
}
/**
* 计算MD5哈希值
* @param data
* @param {string} key
* @returns {string}
* @constructor
*/
public MD5(data: any, key?: string): string {
const stringData: string = this.stringifyData(data)
if (key) {
return HmacMD5(stringData, key).toString()
} else {
return MD5(stringData).toString()
}
}
/**
* 计算SHA1哈希值
* @param data
* @param {string} key
* @returns {string}
* @constructor
*/
public SHA1(data: any, key?: string): string {
const stringData: string = this.stringifyData(data)
if (key) {
return HmacSHA1(stringData, key).toString()
} else {
return SHA1(stringData).toString()
}
}
/**
* 计算SHA3哈希值
* @param data
* @param {string} key
* @returns {string}
* @constructor
*/
public SHA3(data: any, key?: string): string {
const stringData: string = this.stringifyData(data)
if (key) {
return HmacSHA3(stringData, key).toString()
} else {
return SHA3(stringData).toString()
}
}
/**
* 计算SHA224哈希值
* @param data
* @param {string} key
* @returns {string}
* @constructor
*/
public SHA224(data: any, key?: string): string {
const stringData: string = this.stringifyData(data)
if (key) {
return HmacSHA224(stringData, key).toString()
} else {
return SHA224(stringData).toString()
}
}
/**
* 计算SHA256哈希值
* @param data
* @param {string} key
* @returns {string}
* @constructor
*/
public SHA256(data: any, key?: string): string {
const stringData: string = this.stringifyData(data)
if (key) {
return HmacSHA256(stringData, key).toString()
} else {
return SHA256(stringData).toString()
}
}
/**
* 计算SHA384哈希值
* @param data
* @param {string} key
* @returns {string}
* @constructor
*/
public SHA384(data: any, key?: string): string {
const stringData: string = this.stringifyData(data)
if (key) {
return HmacSHA384(stringData, key).toString()
} else {
return SHA384(stringData).toString()
}
}
/**
* 计算SHA512哈希值
* @param data
* @param {string} key
* @returns {string}
* @constructor
*/
public SHA512(data: any, key?: string): string {
const stringData: string = this.stringifyData(data)
if (key) {
return HmacSHA512(stringData, key).toString()
} else {
return SHA512(stringData).toString()
}
}
/**
* 使用密码加密数据
* @param data
* @param {string} password
* @returns {string}
*/
public encryptByPassword<T = any>(data: T, password: string): string {
const stringData: string = this.stringifyData(data)
return AES.encrypt(stringData, password).toString()
}
/**
* 使用密码解密数据
* @param {string} ciphertext
* @param {string} password
* @returns {T}
*/
public decryptByPassword<T = any>(ciphertext: string, password: string): T {
const decryptString: string = AES.decrypt(ciphertext, password).toString(enc.Utf8)
try {
return this.JSON.parse(decryptString)
} catch (e) {
return decryptString as any
}
}
/**
* 使用密钥加密数据
* @param {T} data
* @param {string} secretKey
* @returns {string}
*/
public encryptByKey<T = any>(data: T, secretKey: string): string {
return this.Crypto.encrypt(data, secretKey)
}
/**
* 使用密钥解密数据
* @param {string} ciphertext
* @param {string} secretKey
* @returns {T}
*/
public decryptByKey<T = any>(ciphertext: string, secretKey: string): T {
return this.Crypto.decrypt(ciphertext, secretKey)
}
/**
* 生成带盐值的密码哈希
* @param {string} password
* @returns {string}
*/
public generatePasswordHashSync(password: string): string {
const salt: string = genSaltSync(this.saltRound)
return hashSync(password, salt)
}
/**
* 异步生成带盐值的密码哈希
* @param {string} password
* @returns {Promise<string>}
*/
public async generatePasswordHash(password: string): Promise<string> {
const salt: string = await genSalt(this.saltRound)
return await hash(password, salt)
}
/**
* 验证密码与哈希是否匹配
* @param {string} password
* @param {string} hash
* @returns {boolean}
*/
public validatePasswordSync(password: string, hash: string): boolean {
return compareSync(password, hash)
}
/**
* 异步验证密码与哈希是否匹配
* @param {string} password
* @param {string} hash
* @returns {Promise<boolean>}
*/
public async validatePassword(password: string, hash: string): Promise<boolean> {
return await compare(password, hash)
}
}