- Accept a single pasted/uploaded combined licence key (base64+gzip of licence+activation key), auto-detected in either paste mode, alongside the legacy two-field format - Warn and block applying a key generated for the wrong protocol before it ever reaches the backend - Decode both the legacy positional features string and a new named features object, so already-issued keys keep working unchanged - Show a live "Key Details" preview (validity, users, site IDs, enabled features) as a key is typed, pasted, or uploaded - Fix cypress test setup broken by the paste-format default change, and an unreliable FileReader-based base64 conversion in the test helpers
91 lines
2.9 KiB
TypeScript
91 lines
2.9 KiB
TypeScript
import * as base64Converter from 'base64-arraybuffer'
|
|
import {
|
|
COMBINED_KEY_PREFIX,
|
|
isCombinedLicenceKey,
|
|
splitCombinedLicenceKey
|
|
} from './combinedLicenceKey'
|
|
|
|
// Mirrors dckey's own encodeCombinedKey() (main.js) exactly, so these tests
|
|
// build fixtures the same way a real generated key would be produced,
|
|
// rather than relying on a hardcoded string that could go stale if either
|
|
// side's algorithm ever changes.
|
|
const gzipCompress = async (bytes: Uint8Array): Promise<ArrayBuffer> => {
|
|
const compressionStream = new CompressionStream('gzip')
|
|
const writer = compressionStream.writable.getWriter()
|
|
writer.write(new Uint8Array(bytes))
|
|
writer.close()
|
|
|
|
return new Response(compressionStream.readable).arrayBuffer()
|
|
}
|
|
|
|
const encodeCombinedLicenceKeyFixture = async (
|
|
licenceKey: string,
|
|
activationKey: string
|
|
): Promise<string> => {
|
|
const payloadBytes = new TextEncoder().encode(
|
|
`${licenceKey} ${activationKey}`
|
|
)
|
|
const compressedBytes = await gzipCompress(payloadBytes)
|
|
|
|
return COMBINED_KEY_PREFIX + base64Converter.encode(compressedBytes)
|
|
}
|
|
|
|
describe('isCombinedLicenceKey', () => {
|
|
it('is true for prefixed text', () => {
|
|
expect(isCombinedLicenceKey('DCKEY1:abc123')).toBeTrue()
|
|
})
|
|
|
|
it('is false for a plain legacy key', () => {
|
|
expect(isCombinedLicenceKey('some-legacy-licence-key')).toBeFalse()
|
|
})
|
|
|
|
it('is false for an empty string', () => {
|
|
expect(isCombinedLicenceKey('')).toBeFalse()
|
|
})
|
|
|
|
it('is true even with leading/trailing whitespace around the prefix', () => {
|
|
expect(isCombinedLicenceKey(' DCKEY1:abc123 ')).toBeTrue()
|
|
})
|
|
})
|
|
|
|
describe('splitCombinedLicenceKey', () => {
|
|
it('round-trips a fixture built the same way dckey encodes one', async () => {
|
|
const combined = await encodeCombinedLicenceKeyFixture(
|
|
'licence-key-value',
|
|
'activation-key-value'
|
|
)
|
|
|
|
expect(await splitCombinedLicenceKey(combined)).toEqual({
|
|
licenceKey: 'licence-key-value',
|
|
activationKey: 'activation-key-value'
|
|
})
|
|
})
|
|
|
|
it('returns null for text without the prefix', async () => {
|
|
expect(
|
|
await splitCombinedLicenceKey('a-plain-legacy-licence-key')
|
|
).toBeNull()
|
|
})
|
|
|
|
it('rejects for prefixed text that is not valid compressed data', async () => {
|
|
await expectAsync(
|
|
splitCombinedLicenceKey('DCKEY1:not-valid-base64-gzip-data')
|
|
).toBeRejected()
|
|
})
|
|
|
|
it('splits on the first space only, not every space', async () => {
|
|
// Not a real-world value today (licence/activation keys are base64,
|
|
// which never contains a space) - guards the split logic itself rather
|
|
// than that assumption.
|
|
const combined = await encodeCombinedLicenceKeyFixture(
|
|
'licence key with spaces',
|
|
'activation-key-value'
|
|
)
|
|
|
|
expect(await splitCombinedLicenceKey(combined)).toEqual({
|
|
licenceKey: 'licence',
|
|
activationKey: 'key with spaces activation-key-value'
|
|
})
|
|
})
|
|
})
|