feat: Sprachnotizen-API (T7 L2 Task 7)
Upload (Audio nur per Magic Bytes, versiegelt, 2 MiB), Text-Weg, Liste, Abruf, Wiederholen, Verwerfen, alle verwerfen, Konfiguration und Zähler unter /voice-captures. Rechte voice-captures:use plus inspections:create (eigener Guard, API-Schlüssel ausgeschlossen), Zähler nur mit system:manage; jede Abfrage auf den Besitzer begrenzt. Grenzen je Benutzer unter Advisory-Lock (10 offen, 30 je Tag, 10 je 60 s), Wiederholen ebenfalls begrenzt und gedrosselt, Audio für QUEUED nur unter 24 h. Verwerfen löscht Inhalt und Claim sofort. Keine Inhalte in Log oder Audit. Wächter gegen Sprachinhalte in Suche, Export und Berichten erweitert. Refs #27 Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
19550d1394
commit
0b0bc3c6dc
21 files changed
+2843
-12
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { matchesFileSignature } from './file-signature';
|
||||
import { detectAudioType, matchesFileSignature } from './file-signature';
|
||||
|
||||
describe('matchesFileSignature', () => {
|
||||
it('accepts a buffer starting with the PNG signature', () => {
|
||||
@@ -47,3 +47,63 @@ describe('matchesFileSignature', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('detectAudioType', () => {
|
||||
it('knows EBML, OggS and ftyp and nothing else', () => {
|
||||
const webm = Buffer.from([0x1a, 0x45, 0xdf, 0xa3, 0x9f, 0x42]);
|
||||
const ogg = Buffer.concat([Buffer.from('OggS', 'ascii'), Buffer.alloc(8)]);
|
||||
const mp4 = Buffer.concat([
|
||||
Buffer.from([0x00, 0x00, 0x00, 0x20]),
|
||||
Buffer.from('ftypM4A ', 'ascii'),
|
||||
]);
|
||||
expect(detectAudioType(webm)).toBe('audio/webm');
|
||||
expect(detectAudioType(ogg)).toBe('audio/ogg');
|
||||
expect(detectAudioType(mp4)).toBe('audio/mp4');
|
||||
expect(
|
||||
detectAudioType(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a])),
|
||||
).toBeNull();
|
||||
expect(detectAudioType(Buffer.from('RIFF....WAVE', 'ascii'))).toBeNull();
|
||||
expect(detectAudioType(Buffer.from('%PDF-1.7', 'ascii'))).toBeNull();
|
||||
});
|
||||
|
||||
it.each(['heic', 'avif', 'mif1', 'qt ', '3gp4'])(
|
||||
'rejects an ftyp file with the brand %s',
|
||||
(brand) => {
|
||||
const file = Buffer.concat([
|
||||
Buffer.from([0, 0, 0, 0x20]),
|
||||
Buffer.from(`ftyp${brand}`, 'latin1'),
|
||||
]);
|
||||
expect(detectAudioType(file)).toBeNull();
|
||||
},
|
||||
);
|
||||
|
||||
it.each(['M4A ', 'isom', 'iso2', 'iso6', 'mp41', 'mp42', 'dash'])(
|
||||
'accepts the audio brand %s',
|
||||
(brand) => {
|
||||
const file = Buffer.concat([
|
||||
Buffer.from([0, 0, 0, 0x20]),
|
||||
Buffer.from(`ftyp${brand}`, 'latin1'),
|
||||
]);
|
||||
expect(detectAudioType(file)).toBe('audio/mp4');
|
||||
},
|
||||
);
|
||||
|
||||
it('rejects buffers that are too short for any signature', () => {
|
||||
expect(detectAudioType(Buffer.alloc(0))).toBeNull();
|
||||
expect(detectAudioType(Buffer.from([0x1a, 0x45, 0xdf]))).toBeNull();
|
||||
expect(
|
||||
detectAudioType(Buffer.from('OggS', 'ascii').subarray(0, 3)),
|
||||
).toBeNull();
|
||||
expect(
|
||||
detectAudioType(Buffer.from([0, 0, 0, 0x20, 0x66, 0x74])),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it('does not take a signature from the middle of the buffer', () => {
|
||||
const late = Buffer.concat([
|
||||
Buffer.alloc(16),
|
||||
Buffer.from('OggS', 'ascii'),
|
||||
]);
|
||||
expect(detectAudioType(late)).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user