mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-05-11 09:59:59 +08:00
🎨 Style(custom): lint code
This commit is contained in:
@@ -1,96 +1,97 @@
|
||||
// AESHelper.spec.ts
|
||||
import crypto from 'node:crypto'
|
||||
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { AESHelper } from '../src/main/utils/aesHelper'
|
||||
|
||||
vi.mock('@core/picgo', () => ({
|
||||
default: { getConfig: vi.fn(() => undefined) }
|
||||
}))
|
||||
vi.mock('~/utils/configPaths', () => ({
|
||||
configPaths: { settings: { aesPassword: 'settings.aesPassword' } }
|
||||
}))
|
||||
|
||||
const HEX_RE = /^[0-9a-f]+$/i
|
||||
|
||||
describe('AESHelper', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('round-trips (encrypt -> decrypt) with explicit password', () => {
|
||||
const helper = new AESHelper('testPass123')
|
||||
const plaintext = JSON.stringify({ hello: 'world', n: 42 })
|
||||
const enc = helper.encrypt(plaintext)
|
||||
const dec = helper.decrypt(enc)
|
||||
expect(dec).toBe(plaintext)
|
||||
})
|
||||
|
||||
it('produces iv:cipher hex format with 16-byte IV', () => {
|
||||
const helper = new AESHelper('formatPass')
|
||||
const enc = helper.encrypt('format-check')
|
||||
const parts = enc.split(':')
|
||||
expect(parts.length).toBe(2)
|
||||
const [ivHex, cipherHex] = parts
|
||||
expect(ivHex.length).toBe(32)
|
||||
expect(HEX_RE.test(ivHex)).toBe(true)
|
||||
expect(cipherHex.length).toBeGreaterThan(0)
|
||||
expect(HEX_RE.test(cipherHex)).toBe(true)
|
||||
})
|
||||
|
||||
it('is non-deterministic (random IV) for the same plaintext', () => {
|
||||
const helper = new AESHelper('randomIvPass')
|
||||
const pt = 'same-plaintext'
|
||||
const a = helper.encrypt(pt)
|
||||
const b = helper.encrypt(pt)
|
||||
expect(a).not.toBe(b)
|
||||
expect(helper.decrypt(a)).toBe(pt)
|
||||
expect(helper.decrypt(b)).toBe(pt)
|
||||
})
|
||||
|
||||
it('returns "{}" on malformed inputs (compatibility behavior)', () => {
|
||||
const helper = new AESHelper('badInputPass')
|
||||
expect(helper.decrypt('')).toBe('{}') // empty
|
||||
expect(helper.decrypt('nocolonhere')).toBe('{}') // no separator
|
||||
expect(helper.decrypt('00:abcd')).toBe('{}') // IV too short
|
||||
})
|
||||
|
||||
it('returns "{}" if ciphertext is tampered', () => {
|
||||
const helper = new AESHelper('tamperPass')
|
||||
const enc = helper.encrypt('secure-data')
|
||||
const [ivHex, cipherHex] = enc.split(':')
|
||||
const last = cipherHex.at(-1)!
|
||||
const flipped = last.toLowerCase() === 'a' ? 'b' : 'a'
|
||||
const tampered = `${ivHex}:${cipherHex.slice(0, -1)}${flipped}`
|
||||
expect(helper.decrypt(tampered)).toBe('{}')
|
||||
})
|
||||
|
||||
it('two instances with the same password can decrypt each other', () => {
|
||||
const h1 = new AESHelper('sharedPass')
|
||||
const h2 = new AESHelper('sharedPass')
|
||||
const enc1 = h1.encrypt('hello')
|
||||
const enc2 = h2.encrypt('world')
|
||||
expect(h2.decrypt(enc1)).toBe('hello')
|
||||
expect(h1.decrypt(enc2)).toBe('world')
|
||||
})
|
||||
|
||||
it('works with default constructor (uses picgo fallback password)', async () => {
|
||||
const h1 = new AESHelper()
|
||||
const h2 = new AESHelper()
|
||||
const enc = h1.encrypt('fallback-ok')
|
||||
expect(h2.decrypt(enc)).toBe('fallback-ok')
|
||||
})
|
||||
|
||||
it('caches derived keys for the same password (pbkdf2Sync called once)', () => {
|
||||
const spy = vi.spyOn(crypto, 'pbkdf2Sync')
|
||||
const uniquePwd = 'cache-me-please-' + Math.random().toString(36).slice(2)
|
||||
|
||||
const a = new AESHelper(uniquePwd)
|
||||
const b = new AESHelper(uniquePwd)
|
||||
a.encrypt('x'); b.encrypt('y')
|
||||
|
||||
const callsForPwd = spy.mock.calls.filter(args => args[0] === uniquePwd)
|
||||
expect(callsForPwd.length).toBe(1)
|
||||
})
|
||||
})
|
||||
// AESHelper.spec.ts
|
||||
import crypto from 'node:crypto'
|
||||
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { AESHelper } from '../src/main/utils/aesHelper'
|
||||
|
||||
vi.mock('@core/picgo', () => ({
|
||||
default: { getConfig: vi.fn(() => undefined) }
|
||||
}))
|
||||
vi.mock('~/utils/configPaths', () => ({
|
||||
configPaths: { settings: { aesPassword: 'settings.aesPassword' } }
|
||||
}))
|
||||
|
||||
const HEX_RE = /^[0-9a-f]+$/i
|
||||
|
||||
describe('AESHelper', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('round-trips (encrypt -> decrypt) with explicit password', () => {
|
||||
const helper = new AESHelper('testPass123')
|
||||
const plaintext = JSON.stringify({ hello: 'world', n: 42 })
|
||||
const enc = helper.encrypt(plaintext)
|
||||
const dec = helper.decrypt(enc)
|
||||
expect(dec).toBe(plaintext)
|
||||
})
|
||||
|
||||
it('produces iv:cipher hex format with 16-byte IV', () => {
|
||||
const helper = new AESHelper('formatPass')
|
||||
const enc = helper.encrypt('format-check')
|
||||
const parts = enc.split(':')
|
||||
expect(parts.length).toBe(2)
|
||||
const [ivHex, cipherHex] = parts
|
||||
expect(ivHex.length).toBe(32)
|
||||
expect(HEX_RE.test(ivHex)).toBe(true)
|
||||
expect(cipherHex.length).toBeGreaterThan(0)
|
||||
expect(HEX_RE.test(cipherHex)).toBe(true)
|
||||
})
|
||||
|
||||
it('is non-deterministic (random IV) for the same plaintext', () => {
|
||||
const helper = new AESHelper('randomIvPass')
|
||||
const pt = 'same-plaintext'
|
||||
const a = helper.encrypt(pt)
|
||||
const b = helper.encrypt(pt)
|
||||
expect(a).not.toBe(b)
|
||||
expect(helper.decrypt(a)).toBe(pt)
|
||||
expect(helper.decrypt(b)).toBe(pt)
|
||||
})
|
||||
|
||||
it('returns "{}" on malformed inputs (compatibility behavior)', () => {
|
||||
const helper = new AESHelper('badInputPass')
|
||||
expect(helper.decrypt('')).toBe('{}') // empty
|
||||
expect(helper.decrypt('nocolonhere')).toBe('{}') // no separator
|
||||
expect(helper.decrypt('00:abcd')).toBe('{}') // IV too short
|
||||
})
|
||||
|
||||
it('returns "{}" if ciphertext is tampered', () => {
|
||||
const helper = new AESHelper('tamperPass')
|
||||
const enc = helper.encrypt('secure-data')
|
||||
const [ivHex, cipherHex] = enc.split(':')
|
||||
const last = cipherHex.at(-1)!
|
||||
const flipped = last.toLowerCase() === 'a' ? 'b' : 'a'
|
||||
const tampered = `${ivHex}:${cipherHex.slice(0, -1)}${flipped}`
|
||||
expect(helper.decrypt(tampered)).toBe('{}')
|
||||
})
|
||||
|
||||
it('two instances with the same password can decrypt each other', () => {
|
||||
const h1 = new AESHelper('sharedPass')
|
||||
const h2 = new AESHelper('sharedPass')
|
||||
const enc1 = h1.encrypt('hello')
|
||||
const enc2 = h2.encrypt('world')
|
||||
expect(h2.decrypt(enc1)).toBe('hello')
|
||||
expect(h1.decrypt(enc2)).toBe('world')
|
||||
})
|
||||
|
||||
it('works with default constructor (uses picgo fallback password)', async () => {
|
||||
const h1 = new AESHelper()
|
||||
const h2 = new AESHelper()
|
||||
const enc = h1.encrypt('fallback-ok')
|
||||
expect(h2.decrypt(enc)).toBe('fallback-ok')
|
||||
})
|
||||
|
||||
it('caches derived keys for the same password (pbkdf2Sync called once)', () => {
|
||||
const spy = vi.spyOn(crypto, 'pbkdf2Sync')
|
||||
const uniquePwd = 'cache-me-please-' + Math.random().toString(36).slice(2)
|
||||
|
||||
const a = new AESHelper(uniquePwd)
|
||||
const b = new AESHelper(uniquePwd)
|
||||
a.encrypt('x')
|
||||
b.encrypt('y')
|
||||
|
||||
const callsForPwd = spy.mock.calls.filter(args => args[0] === uniquePwd)
|
||||
expect(callsForPwd.length).toBe(1)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user