- Implemented Zustand store for S/MIME functionality, including state management for key records and public certificates. - Added methods for importing PKCS#12 files and public certificates, binding identities to keys, and managing unlocked keys. - Introduced session storage for remembering unlocked keys across sessions. - Enhanced error handling and loading states during data operations.
194 lines
6.7 KiB
TypeScript
194 lines
6.7 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { detectSmime } from '../smime-detect';
|
|
|
|
describe('detectSmime', () => {
|
|
describe('no S/MIME content', () => {
|
|
it('returns null type when no arguments provided', () => {
|
|
const result = detectSmime();
|
|
expect(result.type).toBeNull();
|
|
expect(result.supported).toBe(false);
|
|
});
|
|
|
|
it('returns null type for plain text content', () => {
|
|
const result = detectSmime('text/plain');
|
|
expect(result.type).toBeNull();
|
|
expect(result.supported).toBe(false);
|
|
});
|
|
|
|
it('returns null type for multipart/mixed without S/MIME', () => {
|
|
const result = detectSmime('multipart/mixed; boundary="abc"');
|
|
expect(result.type).toBeNull();
|
|
expect(result.supported).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('Content-Type header detection', () => {
|
|
it('detects enveloped-data from Content-Type', () => {
|
|
const ct = 'application/pkcs7-mime; smime-type=enveloped-data; name="smime.p7m"';
|
|
const body = { partId: '1', blobId: 'blob1', type: ct };
|
|
const result = detectSmime(ct, body);
|
|
expect(result.type).toBe('enveloped-data');
|
|
expect(result.supported).toBe(true);
|
|
expect(result.blobId).toBe('blob1');
|
|
expect(result.partId).toBe('1');
|
|
});
|
|
|
|
it('detects signed-data from Content-Type', () => {
|
|
const ct = 'application/pkcs7-mime; smime-type=signed-data; name="smime.p7m"';
|
|
const body = { partId: '2', blobId: 'blob2', type: ct };
|
|
const result = detectSmime(ct, body);
|
|
expect(result.type).toBe('signed-data');
|
|
expect(result.supported).toBe(true);
|
|
expect(result.blobId).toBe('blob2');
|
|
});
|
|
|
|
it('detects x-pkcs7-mime variant', () => {
|
|
const ct = 'application/x-pkcs7-mime; smime-type=enveloped-data';
|
|
const body = { partId: '1', blobId: 'blob1', type: ct };
|
|
const result = detectSmime(ct, body);
|
|
expect(result.type).toBe('enveloped-data');
|
|
expect(result.supported).toBe(true);
|
|
});
|
|
|
|
it('detects detached signature via multipart/signed', () => {
|
|
const ct = 'multipart/signed; protocol="application/pkcs7-signature"; micalg=sha-256';
|
|
const result = detectSmime(ct);
|
|
expect(result.type).toBe('detached-sig');
|
|
expect(result.supported).toBe(false);
|
|
});
|
|
|
|
it('handles generic pkcs7-mime without smime-type', () => {
|
|
const ct = 'application/pkcs7-mime; name="smime.p7m"';
|
|
const body = { partId: '1', blobId: 'blob1', type: ct };
|
|
const result = detectSmime(ct, body);
|
|
// Should default to enveloped-data for generic pkcs7-mime
|
|
expect(result.type).toBe('enveloped-data');
|
|
expect(result.blobId).toBe('blob1');
|
|
});
|
|
|
|
it('is case-insensitive for Content-Type', () => {
|
|
const ct = 'Application/PKCS7-MIME; smime-type=Enveloped-Data';
|
|
const body = { partId: '1', blobId: 'b1', type: ct };
|
|
const result = detectSmime(ct, body);
|
|
expect(result.type).toBe('enveloped-data');
|
|
expect(result.supported).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('bodyStructure detection', () => {
|
|
it('finds pkcs7-mime part in bodyStructure tree', () => {
|
|
const body = {
|
|
type: 'multipart/mixed',
|
|
subParts: [
|
|
{ partId: '1', type: 'text/plain', blobId: 'text-blob' },
|
|
{
|
|
partId: '2',
|
|
type: 'application/pkcs7-mime; smime-type=enveloped-data',
|
|
blobId: 'cms-blob',
|
|
},
|
|
],
|
|
};
|
|
const result = detectSmime(undefined, body);
|
|
expect(result.type).toBe('enveloped-data');
|
|
expect(result.supported).toBe(true);
|
|
expect(result.blobId).toBe('cms-blob');
|
|
expect(result.partId).toBe('2');
|
|
});
|
|
|
|
it('detects detached sig in multipart/signed bodyStructure', () => {
|
|
const body = {
|
|
type: 'multipart/signed',
|
|
subParts: [
|
|
{ partId: '1', type: 'text/plain', blobId: 'text-blob' },
|
|
{ partId: '2', type: 'application/pkcs7-signature', blobId: 'sig-blob' },
|
|
],
|
|
};
|
|
const result = detectSmime(undefined, body);
|
|
expect(result.type).toBe('detached-sig');
|
|
expect(result.supported).toBe(false);
|
|
});
|
|
|
|
it('walks nested bodyStructure', () => {
|
|
const body = {
|
|
type: 'multipart/mixed',
|
|
subParts: [
|
|
{
|
|
type: 'multipart/alternative',
|
|
subParts: [
|
|
{ partId: '1.1', type: 'text/plain', blobId: 'txt' },
|
|
{ partId: '1.2', type: 'text/html', blobId: 'html' },
|
|
],
|
|
},
|
|
{
|
|
partId: '2',
|
|
type: 'application/pkcs7-mime; smime-type=signed-data',
|
|
blobId: 'sig-blob',
|
|
},
|
|
],
|
|
};
|
|
const result = detectSmime(undefined, body);
|
|
expect(result.type).toBe('signed-data');
|
|
expect(result.supported).toBe(true);
|
|
expect(result.blobId).toBe('sig-blob');
|
|
});
|
|
});
|
|
|
|
describe('attachment detection', () => {
|
|
it('detects .p7m attachment', () => {
|
|
const attachments = [
|
|
{ partId: '3', blobId: 'att-blob', name: 'message.p7m', type: 'application/octet-stream' },
|
|
];
|
|
const result = detectSmime(undefined, null, attachments);
|
|
expect(result.type).toBe('enveloped-data');
|
|
expect(result.supported).toBe(true);
|
|
expect(result.blobId).toBe('att-blob');
|
|
});
|
|
|
|
it('detects .p7s attachment as detached-sig', () => {
|
|
const attachments = [
|
|
{ partId: '3', blobId: 'sig-blob', name: 'smime.p7s', type: 'application/octet-stream' },
|
|
];
|
|
const result = detectSmime(undefined, null, attachments);
|
|
expect(result.type).toBe('detached-sig');
|
|
expect(result.supported).toBe(false);
|
|
});
|
|
|
|
it('detects pkcs7-mime attachment type', () => {
|
|
const attachments = [
|
|
{
|
|
partId: '2',
|
|
blobId: 'enc-blob',
|
|
name: 'encrypted.bin',
|
|
type: 'application/pkcs7-mime; smime-type=enveloped-data',
|
|
},
|
|
];
|
|
const result = detectSmime(undefined, null, attachments);
|
|
expect(result.type).toBe('enveloped-data');
|
|
expect(result.supported).toBe(true);
|
|
});
|
|
|
|
it('skips non-S/MIME attachments', () => {
|
|
const attachments = [
|
|
{ partId: '2', blobId: 'pdf-blob', name: 'document.pdf', type: 'application/pdf' },
|
|
];
|
|
const result = detectSmime(undefined, null, attachments);
|
|
expect(result.type).toBeNull();
|
|
expect(result.supported).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('priority order', () => {
|
|
it('Content-Type takes precedence over bodyStructure', () => {
|
|
const ct = 'application/pkcs7-mime; smime-type=enveloped-data';
|
|
const body = {
|
|
partId: '1',
|
|
blobId: 'from-ct',
|
|
type: ct,
|
|
};
|
|
const result = detectSmime(ct, body);
|
|
expect(result.type).toBe('enveloped-data');
|
|
expect(result.blobId).toBe('from-ct');
|
|
});
|
|
});
|
|
});
|