shifro 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -629,7 +629,7 @@ to attach them to the start of each source file to most effectively
629
629
  state the exclusion of warranty; and each file should have at least
630
630
  the "copyright" line and a pointer to where the full notice is found.
631
631
 
632
- dempeg - a lightweight, dependency-free MP4 decrypter for Node.js
632
+ shifro - a lightweight, dependency-free MP4 decrypter for Node.js
633
633
  Copyright (C) 2024 Vitaly Gashkov <vitalygashkov@vk.com>
634
634
 
635
635
  This program is free software: you can redistribute it and/or modify
package/README.md CHANGED
@@ -77,10 +77,10 @@ const waitForInput = async () =>
77
77
  });
78
78
 
79
79
  const inputFile = await waitForInput();
80
- const inputStream = input.stream();
80
+ const inputStream = inputFile.stream();
81
81
 
82
82
  const outputFileHandle = window.showSaveFilePicker({ suggestedName: 'output.mp4', startIn: 'downloads' });
83
- const outputStream = await output.createWritable();
83
+ const outputStream = await outputFileHandle.createWritable();
84
84
 
85
85
  await decryptStream(inputStream, outputStream, {
86
86
  key,
package/dist/cli.cjs CHANGED
@@ -1,10 +1,12 @@
1
1
  #!/usr/bin/env node
2
- "use strict";var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=s(require(`node:util`)),l=s(require(`node:fs`)),u=s(require(`node:fs/promises`)),d=s(require(`node:stream`)),f=async({key:e,iv:t,data:n,algorithm:r=`AES-CTR`})=>{let i=r.toUpperCase(),a=await crypto.subtle.importKey(`raw`,e,{name:i},!1,[`decrypt`]),o=await crypto.subtle.decrypt({name:i,counter:t,length:64},a,n);return new Uint8Array(o)},p=e=>{let t=e.buffer,n=new DataView(t,e.byteOffset,e.byteLength);return n},m=(e,t=0,n)=>new Uint8Array(e.buffer,e.byteOffset+t,n);var h=class extends Error{constructor(e,t,n,r){super(r),this.severity=e,this.category=t,this.code=n,this.name=`DataViewReaderError`}},g=class{position=0;constructor(e,t=`BE`){this.dataView=p(e),this.littleEndian=t===`LE`}getDataView(){return this.dataView}hasMoreData(){return this.position<this.dataView.byteLength}getPosition(){return this.position}getLength(){return this.dataView.byteLength}readUint8(){this.checkBounds(1);let e=this.dataView.getUint8(this.position);return this.position+=1,e}readUint16(){this.checkBounds(2);let e=this.dataView.getUint16(this.position,this.littleEndian);return this.position+=2,e}readUint32(){this.checkBounds(4);let e=this.dataView.getUint32(this.position,this.littleEndian);return this.position+=4,e}readInt32(){this.checkBounds(4);let e=this.dataView.getInt32(this.position,this.littleEndian);return this.position+=4,e}readUint64(){let e,t;try{this.littleEndian?(e=this.dataView.getUint32(this.position,!0),t=this.dataView.getUint32(this.position+4,!0)):(t=this.dataView.getUint32(this.position,!1),e=this.dataView.getUint32(this.position+4,!1))}catch{throw this.outOfBounds()}if(t>2097151)throw new h(`CRITICAL`,`MEDIA`,`JS_INTEGER_OVERFLOW`,`64-bit integer overflow`);return this.position+=8,t*2**32+e}readBytes(e){this.checkBounds(e);let t=m(this.dataView,this.position,e);return this.position+=e,t}skip(e){this.checkBounds(e),this.position+=e}rewind(e){if(this.position<e)throw this.outOfBounds();this.position-=e}seek(e){if(e<0||e>this.dataView.byteLength)throw this.outOfBounds();this.position=e}readTerminatedString(){let e=this.position;for(;this.hasMoreData()&&this.dataView.getUint8(this.position)!==0;)this.position++;if(!this.hasMoreData())throw this.outOfBounds();let t=new Uint8Array(this.dataView.buffer,e,this.position-e);return this.position++,new TextDecoder().decode(t)}checkBounds(e){if(this.position+e>this.dataView.byteLength)throw this.outOfBounds()}outOfBounds(){return new h(`CRITICAL`,`MEDIA`,`BUFFER_READ_OUT_OF_BOUNDS`,`Read operation out of bounds`)}};let _=function(e){return e[e.BASIC_BOX=0]=`BASIC_BOX`,e[e.FULL_BOX=1]=`FULL_BOX`,e}({});var v=class e{headers=new Map;boxDefinitions=new Map;done=!1;box(t,n){let r=e.typeFromString(t);return this.headers.set(r,_.BASIC_BOX),this.boxDefinitions.set(r,n),this}fullBox(t,n){let r=e.typeFromString(t);return this.headers.set(r,_.FULL_BOX),this.boxDefinitions.set(r,n),this}stop(){this.done=!0}parse(e,t=!1,n=!1){let r=new g(e);for(this.done=!1;r.hasMoreData()&&!this.done;)this.parseNext(0,r,t,n)}parseNext(t,n,r,i){let a=n.getPosition();if(i&&a+8>n.getLength()){this.done=!0;return}let o=n.readUint32(),s=n.readUint32(),c=e.typeToString(s),l=!1;switch(o){case 0:o=n.getLength()-a;break;case 1:if(i&&n.getPosition()+8>n.getLength()){this.done=!0;return}o=Number(n.readUint64()),l=!0;break}let u=this.boxDefinitions.get(s);if(u){let e=null,d=null;if(this.headers.get(s)===_.FULL_BOX){if(i&&n.getPosition()+4>n.getLength()){this.done=!0;return}let t=n.readUint32();e=t>>>24,d=t&16777215}let f=a+o;if(r&&f>n.getLength()&&(f=n.getLength()),i&&f>n.getLength()){this.done=!0;return}let p=f-n.getPosition(),m=p>0?n.readBytes(p):new Uint8Array,h=new g(m),v={name:c,parser:this,partialOkay:!!r,version:e,flags:d,reader:h,size:o,start:a+t,has64BitSize:l};u(v)}else{let e=Math.min(a+o-n.getPosition(),n.getLength()-n.getPosition());n.skip(e)}}static children(t){let n=e.headerSize(t);for(;t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static sampleDescription(t){let n=e.headerSize(t),r=t.reader.readUint32();for(let e=0;e<r&&(t.parser.parseNext(t.start+n,t.reader,t.partialOkay),!t.parser.done);e++);}static visualSampleEntry(t){let n=e.headerSize(t);for(t.reader.skip(78);t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static audioSampleEntry(t){let n=e.headerSize(t);t.reader.skip(8);let r=t.reader.readUint16();for(t.reader.skip(6),r===2?t.reader.skip(48):t.reader.skip(12),r===1&&t.reader.skip(16);t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static allData(e){return t=>{let n=t.reader.getLength()-t.reader.getPosition();e(t.reader.readBytes(n))}}static typeFromString(e){if(e.length!==4)throw Error(`MP4 box names must be 4 characters long`);let t=0;for(let n of e)t=t<<8|n.charCodeAt(0);return t}static typeToString(e){return String.fromCharCode(e>>24&255,e>>16&255,e>>8&255,e&255)}static headerSize(e){let t=8,n=e.has64BitSize?8:0,r=e.flags===null?0:4;return t+n+r}};const ee=(e,t)=>{if(t&&t&1){let t=e.readUint8(),n=e.readUint8(),r=e.readBytes(16)}let n=e.readUint32(),r=[];for(let i=0;i<n;i++){let n=8,i=new Uint8Array(16);i.set(e.readBytes(n));let a={iv:i,subsamples:[]},o=t&&t&2;if(o){let t=e.readUint16();for(let n=0;n<t;n++){let t=e.readUint16(),n=e.readUint32();a.subsamples.push({bytesOfClearData:t,bytesOfEncryptedData:n})}}r.push(a)}return{samples:r}},y=(e,t,n)=>{let r=e.readUint32(),i=[],a=null;t&1&&(a=e.readInt32()),t&4&&e.skip(4);for(let a=0;a<r;a++){let r={};t&256&&(r.duration=e.readUint32()),t&512&&(r.size=e.readUint32()),t&1024&&e.skip(4),t&2048&&(r.compositionTimeOffset=n==0?e.readUint32():e.readInt32()),i.push(r)}return{samples:i,dataOffset:a}},te=(e,t)=>{let n,r,i,a,o=e.readUint32();return t&1&&(i=e.readUint64()),t&2&&(a=e.readUint32()),t&8&&(n=e.readUint32()),t&16&&(r=e.readUint32()),{trackId:o,defaultSampleDuration:n,defaultSampleSize:r,baseDataOffset:i,sampleDescriptionIndex:a}},b=(e,t,n)=>{if(t.length===0)return-1;let r=e.length-t.length+1;for(let i=n;i<r;i++){let n=!0;for(let r=0;r<t.length;r++)if(e[i+r]!==t[r]){n=!1;break}if(n)return i}return-1},x=(e,t,n)=>{let r=new TextEncoder,i=r.encode(t),a=r.encode(n);if(i.length!==a.length)throw Error(`Original and replacement must have the same byte length`);let o=0;do o=b(e,i,0),o!==-1&&e.set(a,o);while(o!==-1)},S=(e,t,n=0)=>{let r=new TextEncoder,i;return i=typeof t==`string`?r.encode(t):typeof t==`number`?new Uint8Array([t]):t,i.length===0?!0:e.length<i.length?!1:b(e,i,n)!==-1},C=(e,t)=>{if(e.length===0)return new Uint8Array;let n=t??e.reduce((e,t)=>e+t.length,0);n=Math.min(n,e.reduce((e,t)=>e+t.length,0));let r=new Uint8Array(n),i=0;for(let t of e){if(i>=n)break;let e=t.subarray(0,Math.min(t.length,n-i));r.set(e,i),i+=e.length}return r},ne=(e,t,n=0,r=0,i=e.length)=>{n=Math.max(0,Math.min(n,t.length)),r=Math.max(0,Math.min(r,e.length)),i=Math.min(i,e.length),i<r&&(i=r);let a=Math.min(i-r,t.length-n);return a<=0?0:(t.set(e.subarray(r,r+a),n),a)},re=(e,t,n=0,r)=>{let i=new TextEncoder,a=i.encode(t),o=Math.max(0,Math.min(n,e.length)),s=e.length-o,c=a.length;return typeof r==`number`&&(c=Math.min(c,r)),c=Math.min(c,s),c<=0?0:(e.set(a.subarray(0,c),o),c)},w=e=>Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),ie=e=>{let t=Array.from(e,e=>String.fromCodePoint(e)).join(``);return btoa(t)},ae=e=>e.match(/.{1,2}/g).map(e=>parseInt(e,16)),T=e=>{e.readUint8(),e.readUint8(),e.readUint8(),e.readUint8();let t=w(e.readBytes(16));return{defaultKID:t}},E=e=>{let t=`edef8ba979d64acea3c827dcd51d21ed`,n=e.version??0;if(n!==0&&n!==1)throw Error(`PSSH version can only be 0 or 1`);let r=e.reader.readBytes(16),i=w(r),a=[i.slice(0,8),i.slice(8,12),i.slice(12,16),i.slice(16,20),i.slice(20)].join(`-`),o=e.reader.getDataView(),s=new Uint8Array(o.buffer,o.byteOffset-12,e.size),c=ie(s),l=[];if(n>=1){let t=e.reader.readUint32();for(let n=0;n<t;n++)l.push(w(e.reader.readBytes(16)))}let u=e.reader.readUint32(),d=e.reader.readBytes(u),f=i===t;return{version:n,systemId:a,pssh:c,keyIds:l,systemData:d}},D=e=>{try{let t=!1,n=!1;return new v().box(`moov`,()=>{t=!0}).box(`moof`,()=>{n=!0}).parse(e,!0,!0),t&&!n}catch(e){return console.log(e),!1}},O=e=>{let t=null;return new v().box(`moov`,v.children).box(`trak`,v.children).box(`mdia`,v.children).box(`minf`,v.children).box(`stbl`,v.children).fullBox(`stsd`,v.sampleDescription).box(`encv`,v.visualSampleEntry).box(`enca`,v.audioSampleEntry).box(`sinf`,v.children).box(`frma`,e=>{let n=e.reader.readBytes(4);t=new TextDecoder().decode(n)}).parse(e,!0,!0),t},k=async e=>{let t=O(e);if(x(e,`sinf`,`skip`),x(e,`pssh`,`skip`),t)x(e,`encv`,t),x(e,`enca`,t);else{console.warn(`Could not detect original codec, using fallback values`);let t=S(e,`encv`)?`video`:`audio`;t===`video`?x(e,`encv`,`avc1`):x(e,`enca`,`mp4a`)}return e},A=e=>{let t={schemeType:``,defaultKID:``,psshList:[]};return new v().box(`moov`,v.children).box(`trak`,v.children).box(`mdia`,v.children).box(`minf`,v.children).box(`stbl`,v.children).fullBox(`stsd`,v.sampleDescription).fullBox(`pssh`,e=>t.psshList.push(E(e))).box(`encv`,v.visualSampleEntry).box(`enca`,v.audioSampleEntry).box(`sinf`,v.children).box(`schi`,v.children).fullBox(`schm`,e=>{t.schemeType=new TextDecoder().decode(e.reader.readBytes(4))}).fullBox(`tenc`,e=>{let{defaultKID:n}=T(e.reader);t.defaultKID=n}).parse(e,!1,!0),t},j=async(e,t)=>{let n=D(e);if(n)return k(e);let r,i,a,o;if(new v().box(`moof`,v.children).box(`traf`,v.children).fullBox(`tfhd`,e=>{a=te(e.reader,e.flags)}).fullBox(`trun`,e=>{i=y(e.reader,e.flags,e.version)}).fullBox(`senc`,e=>{r=ee(e.reader,e.flags)}).parse(e,!0,!0),o=i.dataOffset,r.samples.length!==i.samples.length)throw Error(`sample count mismatch: trun has ${i.samples.length}, senc has ${r.samples.length}`);let s=0,c=0;for(let n=0;n<r.samples.length;n++){let l=r.samples[n],u=i.samples[n],d=i.samples[n].size||a.defaultSampleSize||0;l.subsamples.length||l.subsamples.push({bytesOfClearData:0,bytesOfEncryptedData:d});let f=l.subsamples.some(e=>e.bytesOfEncryptedData>0);if(f){let n=0,r=[];for(let t of l.subsamples){if(n+=t.bytesOfClearData,t.bytesOfEncryptedData>0){let i=e.subarray(o+s+n,o+s+n+t.bytesOfEncryptedData);r.push(i)}n+=t.bytesOfEncryptedData}let i=C(r),a={iv:l.iv,data:i,timestamp:c},u=await t(a);if(u){n=0;let t=0,r=[];for(let i of l.subsamples){if(i.bytesOfClearData>0){let t=e.subarray(o+s+n,o+s+n+i.bytesOfClearData);r.push(t),n+=i.bytesOfClearData}if(i.bytesOfEncryptedData>0){let e=u.subarray(t,t+i.bytesOfEncryptedData);r.push(e),t+=i.bytesOfEncryptedData,n+=i.bytesOfEncryptedData}}let i=C(r);ne(i,e,o+s)}}s+=d,c+=u.duration||a.defaultSampleDuration||0}return new v().box(`moof`,v.children).box(`traf`,v.children).box(`senc`,t=>{let n=`skip`,r=t.start+n.length;re(e,n,r)}).parse(e,!0,!0),e},M=e=>{let t=null;new v().box(`moov`,e=>{t=e.start+e.size}).parse(e,!0,!0);let n=t?e.subarray(0,t):null;return{moovEnd:t,init:n}},N=e=>{let t=null,n=null;new v().box(`moof`,e=>{t===null&&(t=e.start)}).box(`mdat`,e=>{n===null&&(n=e.start+e.size)}).parse(e,!0,!0);let r=t!==null&&n!==null,i=r?e.subarray(t,n):null;return{segment:i,moofStart:t,mdatEnd:n}};var P=class{buffer=new Uint8Array;isProcessingInit=!0;scheme=null;processedBytes=0;constructor(e){this.options=e}async transform(e,t){try{this.buffer=C([this.buffer,e]);let n=!0;for(;n;){if(this.isProcessingInit){let{init:e,moovEnd:n}=M(this.buffer);if(!n||this.buffer.length<n)break;if(e&&D(e)){let r=A(e);this.scheme=r.schemeType;let i=await k(e);t.enqueue(i),this.updateProgress(i.byteLength),this.buffer=this.buffer.subarray(n),this.isProcessingInit=!1;continue}}let{moofStart:e,mdatEnd:r,segment:i}=N(this.buffer);if(e===null||r===null||!i||this.buffer.length<r)break;let a=e=>(e.encryptionScheme=this.scheme,this.options.transformSample(e)),o=await j(i,a);t.enqueue(o),this.updateProgress(o.byteLength),this.buffer=this.buffer.subarray(r),n=this.buffer.length>=8}}catch(e){t.error(e)}}async flush(e){this.buffer.length>0&&(e.enqueue(this.buffer),this.updateProgress(this.buffer.byteLength))}updateProgress(e){this.processedBytes+=e,this.options.onProgress&&this.options.onProgress(this.processedBytes)}};const F=async(e,t,{transformSample:n,onProgress:r,preventClose:i})=>{let a=new P({transformSample:n,onProgress:r}),o=new TransformStream({transform:(e,t)=>a.transform(e,t),flush:e=>a.flush(e)});await e.pipeThrough(o).pipeTo(t,{preventClose:i})},I=async(e,t)=>{let n=t.encryptionScheme,r=t.iv,i=t.data;return f(n===`cbcs`?{key:e,iv:r,data:i,algorithm:`AES-CBC`}:{key:e,iv:r,data:i,algorithm:`AES-CTR`})},L=async(e,t,{preventClose:n,onProgress:r,...i})=>{let a=`key`in i,o=new Uint8Array(ae(a?i.key:``)),s=async e=>I(o,e),c=a?s:i.transformSample;await F(e,t,{preventClose:n,onProgress:r,transformSample:c})},R=async(e,t,n)=>{let r=await(0,u.stat)(e),i=(0,l.createReadStream)(e,{highWaterMark:1024*1024*10}),a=d.Readable.toWeb(i),o=(0,l.createWriteStream)(t),s=d.Writable.toWeb(o);await L(a,s,{key:`key`in n?n.key:``,keyId:n.keyId,onProgress:e=>{process.stdout.write(`\rDecrypting... [${e}/${r.size}]`),e===r.size&&process.stdout.write(`
3
- `)}})};var z=`shifro`,B=`0.1.0`,V=`A lightweight, dependency-free MP4 decrypter`,H=[`dist`],U={dev:`vite`,build:`npm run build:lib && npm run build:cli`,"build:cli":`tsdown ./lib/node/cli.ts --format cjs --dts --minify --no-clean`,"build:lib":`tsdown shifro.ts --format cjs --format esm --dts --minify`,typecheck:`tsc --noEmit`,test:`vitest`,prepublishOnly:`npm run build`},W={shifro:`./dist/cli.cjs`},oe=`module`,G=`./dist/shifro.js`,K=`./dist/shifro.d.ts`,q={".":{require:{types:`./dist/shifro.d.cts`,default:`./dist/shifro.cjs`},import:{types:`./dist/shifro.d.ts`,default:`./dist/shifro.js`}}},se={type:`git`,url:`git+https://github.com/streamyx-labs/shifro.git`},ce=[`mp4`,`mpeg`,`cenc`,`cbcs`,`decrypt`,`decryption`,`decrypter`,`decryptor`,`dash`,`drm`,`mp4decrypt`,`mp4box`,`shaka`,`shaka-packager`],le={url:`https://github.com/streamyx-labs/shifro/issues`,email:`vitalygashkov@vk.com`},ue=`Vitaly Gashkov <vitalygashkov@vk.com>`,de=`AGPL-3.0`,J=`README.md`,fe=[{type:`individual`,url:`https://boosty.to/vitalygashkov`},{type:`patreon`,url:`https://www.patreon.com/vitalygashkov`}],pe={node:`20 || 21 || 22 || 23`},me={"@types/node":`^22.15.3`,tsdown:`^0.11.0-beta.3`,typescript:`^5.8.3`,vitest:`^3.1.2`},he={name:z,version:B,description:V,files:H,scripts:U,bin:W,type:oe,main:G,types:K,exports:q,repository:se,keywords:ce,bugs:le,author:ue,license:de,readmeFilename:J,funding:fe,engines:pe,devDependencies:me};const Y=(0,c.parseArgs)({allowPositionals:!0,strict:!1,options:{key:{short:`k`,type:`string`,multiple:!0},help:{short:`h`,type:`boolean`}}}),ge=Array.isArray(Y.values.key)?Y.values.key:[],[X,Z]=ge[0]?.split(`:`)??[],[Q,$]=Y.positionals;(async()=>{Q&&$&&X&&Z?(await R(Q,$,{key:Z,keyId:X}),console.log(`Done!`)):console.log(`
4
- dempeg version ${he.version}
2
+ "use strict";var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=s(require(`node:util`)),l=s(require(`node:fs`)),u=s(require(`node:fs/promises`)),d=s(require(`node:stream`)),f=async({key:e,iv:t,data:n,algorithm:r=`AES-CTR`})=>{let i=r.toUpperCase(),a=await crypto.subtle.importKey(`raw`,e,{name:i},!1,[`decrypt`]),o=await crypto.subtle.decrypt({name:i,counter:t,length:64},a,n);return new Uint8Array(o)},p=e=>{let t=e.buffer,n=new DataView(t,e.byteOffset,e.byteLength);return n},m=(e,t=0,n)=>new Uint8Array(e.buffer,e.byteOffset+t,n);var h=class extends Error{constructor(e,t,n,r){super(r),this.severity=e,this.category=t,this.code=n,this.name=`DataViewReaderError`}},g=class{position=0;constructor(e,t=`BE`){this.dataView=p(e),this.littleEndian=t===`LE`}getDataView(){return this.dataView}hasMoreData(){return this.position<this.dataView.byteLength}getPosition(){return this.position}getLength(){return this.dataView.byteLength}readUint8(){this.checkBounds(1);let e=this.dataView.getUint8(this.position);return this.position+=1,e}readUint16(){this.checkBounds(2);let e=this.dataView.getUint16(this.position,this.littleEndian);return this.position+=2,e}readUint32(){this.checkBounds(4);let e=this.dataView.getUint32(this.position,this.littleEndian);return this.position+=4,e}readInt32(){this.checkBounds(4);let e=this.dataView.getInt32(this.position,this.littleEndian);return this.position+=4,e}readUint64(){let e,t;try{this.littleEndian?(e=this.dataView.getUint32(this.position,!0),t=this.dataView.getUint32(this.position+4,!0)):(t=this.dataView.getUint32(this.position,!1),e=this.dataView.getUint32(this.position+4,!1))}catch{throw this.outOfBounds()}if(t>2097151)throw new h(`CRITICAL`,`MEDIA`,`JS_INTEGER_OVERFLOW`,`64-bit integer overflow`);return this.position+=8,t*2**32+e}readBytes(e){this.checkBounds(e);let t=m(this.dataView,this.position,e);return this.position+=e,t}skip(e){this.checkBounds(e),this.position+=e}rewind(e){if(this.position<e)throw this.outOfBounds();this.position-=e}seek(e){if(e<0||e>this.dataView.byteLength)throw this.outOfBounds();this.position=e}readTerminatedString(){let e=this.position;for(;this.hasMoreData()&&this.dataView.getUint8(this.position)!==0;)this.position++;if(!this.hasMoreData())throw this.outOfBounds();let t=new Uint8Array(this.dataView.buffer,e,this.position-e);return this.position++,new TextDecoder().decode(t)}checkBounds(e){if(this.position+e>this.dataView.byteLength)throw this.outOfBounds()}outOfBounds(){return new h(`CRITICAL`,`MEDIA`,`BUFFER_READ_OUT_OF_BOUNDS`,`Read operation out of bounds`)}};let _=function(e){return e[e.BASIC_BOX=0]=`BASIC_BOX`,e[e.FULL_BOX=1]=`FULL_BOX`,e}({});var v=class e{headers=new Map;boxDefinitions=new Map;done=!1;box(t,n){let r=e.typeFromString(t);return this.headers.set(r,_.BASIC_BOX),this.boxDefinitions.set(r,n),this}fullBox(t,n){let r=e.typeFromString(t);return this.headers.set(r,_.FULL_BOX),this.boxDefinitions.set(r,n),this}stop(){this.done=!0}parse(e,t=!1,n=!1){let r=new g(e);for(this.done=!1;r.hasMoreData()&&!this.done;)this.parseNext(0,r,t,n)}parseNext(t,n,r,i){let a=n.getPosition();if(i&&a+8>n.getLength()){this.done=!0;return}let o=n.readUint32(),s=n.readUint32(),c=e.typeToString(s),l=!1;switch(o){case 0:o=n.getLength()-a;break;case 1:if(i&&n.getPosition()+8>n.getLength()){this.done=!0;return}o=Number(n.readUint64()),l=!0;break}let u=this.boxDefinitions.get(s);if(u){let e=null,d=null;if(this.headers.get(s)===_.FULL_BOX){if(i&&n.getPosition()+4>n.getLength()){this.done=!0;return}let t=n.readUint32();e=t>>>24,d=t&16777215}let f=a+o;if(r&&f>n.getLength()&&(f=n.getLength()),i&&f>n.getLength()){this.done=!0;return}let p=f-n.getPosition(),m=p>0?n.readBytes(p):new Uint8Array,h=new g(m),v={name:c,parser:this,partialOkay:!!r,version:e,flags:d,reader:h,size:o,start:a+t,has64BitSize:l};u(v)}else{let e=Math.min(a+o-n.getPosition(),n.getLength()-n.getPosition());n.skip(e)}}static children(t){let n=e.headerSize(t);for(;t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static sampleDescription(t){let n=e.headerSize(t),r=t.reader.readUint32();for(let e=0;e<r&&(t.parser.parseNext(t.start+n,t.reader,t.partialOkay),!t.parser.done);e++);}static visualSampleEntry(t){let n=e.headerSize(t);for(t.reader.skip(78);t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static audioSampleEntry(t){let n=e.headerSize(t);t.reader.skip(8);let r=t.reader.readUint16();for(t.reader.skip(6),r===2?t.reader.skip(48):t.reader.skip(12),r===1&&t.reader.skip(16);t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static allData(e){return t=>{let n=t.reader.getLength()-t.reader.getPosition();e(t.reader.readBytes(n))}}static typeFromString(e){if(e.length!==4)throw Error(`MP4 box names must be 4 characters long`);let t=0;for(let n of e)t=t<<8|n.charCodeAt(0);return t}static typeToString(e){return String.fromCharCode(e>>24&255,e>>16&255,e>>8&255,e&255)}static headerSize(e){let t=8,n=e.has64BitSize?8:0,r=e.flags===null?0:4;return t+n+r}};const ee=(e,t)=>{if(t&&t&1){let t=e.readUint8(),n=e.readUint8(),r=e.readBytes(16)}let n=e.readUint32(),r=[];for(let i=0;i<n;i++){let n=8,i=new Uint8Array(16);i.set(e.readBytes(n));let a={iv:i,subsamples:[]},o=t&&t&2;if(o){let t=e.readUint16();for(let n=0;n<t;n++){let t=e.readUint16(),n=e.readUint32();a.subsamples.push({bytesOfClearData:t,bytesOfEncryptedData:n})}}r.push(a)}return{samples:r}},y=(e,t,n)=>{let r=e.readUint32(),i=[],a=null;t&1&&(a=e.readInt32()),t&4&&e.skip(4);for(let a=0;a<r;a++){let r={};t&256&&(r.duration=e.readUint32()),t&512&&(r.size=e.readUint32()),t&1024&&e.skip(4),t&2048&&(r.compositionTimeOffset=n==0?e.readUint32():e.readInt32()),i.push(r)}return{samples:i,dataOffset:a}},te=(e,t)=>{let n,r,i,a,o=e.readUint32();return t&1&&(i=e.readUint64()),t&2&&(a=e.readUint32()),t&8&&(n=e.readUint32()),t&16&&(r=e.readUint32()),{trackId:o,defaultSampleDuration:n,defaultSampleSize:r,baseDataOffset:i,sampleDescriptionIndex:a}},b=(e,t,n)=>{if(t.length===0)return-1;let r=e.length-t.length+1;for(let i=n;i<r;i++){let n=!0;for(let r=0;r<t.length;r++)if(e[i+r]!==t[r]){n=!1;break}if(n)return i}return-1},x=(e,t,n)=>{let r=new TextEncoder,i=r.encode(t),a=r.encode(n);if(i.length!==a.length)throw Error(`Original and replacement must have the same byte length`);let o=0;do o=b(e,i,0),o!==-1&&e.set(a,o);while(o!==-1)},S=(e,t,n=0)=>{let r=new TextEncoder,i;return i=typeof t==`string`?r.encode(t):typeof t==`number`?new Uint8Array([t]):t,i.length===0?!0:e.length<i.length?!1:b(e,i,n)!==-1},C=(e,t)=>{if(e.length===0)return new Uint8Array;let n=t??e.reduce((e,t)=>e+t.length,0);n=Math.min(n,e.reduce((e,t)=>e+t.length,0));let r=new Uint8Array(n),i=0;for(let t of e){if(i>=n)break;let e=t.subarray(0,Math.min(t.length,n-i));r.set(e,i),i+=e.length}return r},ne=(e,t,n=0,r=0,i=e.length)=>{n=Math.max(0,Math.min(n,t.length)),r=Math.max(0,Math.min(r,e.length)),i=Math.min(i,e.length),i<r&&(i=r);let a=Math.min(i-r,t.length-n);return a<=0?0:(t.set(e.subarray(r,r+a),n),a)},re=(e,t,n=0,r)=>{let i=new TextEncoder,a=i.encode(t),o=Math.max(0,Math.min(n,e.length)),s=e.length-o,c=a.length;return typeof r==`number`&&(c=Math.min(c,r)),c=Math.min(c,s),c<=0?0:(e.set(a.subarray(0,c),o),c)},w=e=>Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),ie=e=>{let t=Array.from(e,e=>String.fromCodePoint(e)).join(``);return btoa(t)},ae=e=>e.match(/.{1,2}/g)?.map(e=>parseInt(e,16))??[],T=e=>{e.readUint8(),e.readUint8(),e.readUint8(),e.readUint8();let t=w(e.readBytes(16));return{defaultKID:t}},E=e=>{let t=`edef8ba979d64acea3c827dcd51d21ed`,n=e.version??0;if(n!==0&&n!==1)throw Error(`PSSH version can only be 0 or 1`);let r=e.reader.readBytes(16),i=w(r),a=[i.slice(0,8),i.slice(8,12),i.slice(12,16),i.slice(16,20),i.slice(20)].join(`-`),o=e.reader.getDataView(),s=new Uint8Array(o.buffer,o.byteOffset-12,e.size),c=ie(s),l=[];if(n>=1){let t=e.reader.readUint32();for(let n=0;n<t;n++)l.push(w(e.reader.readBytes(16)))}let u=e.reader.readUint32(),d=e.reader.readBytes(u),f=i===t;return{version:n,systemId:a,pssh:c,keyIds:l,systemData:d}},D=e=>{try{let t=!1,n=!1;return new v().box(`moov`,()=>{t=!0}).box(`moof`,()=>{n=!0}).parse(e,!0,!0),t&&!n}catch(e){return console.log(e),!1}},O=e=>{let t=null;return new v().box(`moov`,v.children).box(`trak`,v.children).box(`mdia`,v.children).box(`minf`,v.children).box(`stbl`,v.children).fullBox(`stsd`,v.sampleDescription).box(`encv`,v.visualSampleEntry).box(`enca`,v.audioSampleEntry).box(`sinf`,v.children).box(`frma`,e=>{let n=e.reader.readBytes(4);t=new TextDecoder().decode(n)}).parse(e,!0,!0),t},k=async e=>{let t=O(e);if(x(e,`sinf`,`skip`),x(e,`pssh`,`skip`),t)x(e,`encv`,t),x(e,`enca`,t);else{console.warn(`Could not detect original codec, using fallback values`);let t=S(e,`encv`)?`video`:`audio`;t===`video`?x(e,`encv`,`avc1`):x(e,`enca`,`mp4a`)}return e},A=e=>{let t={schemeType:``,defaultKID:``,psshList:[]};return new v().box(`moov`,v.children).box(`trak`,v.children).box(`mdia`,v.children).box(`minf`,v.children).box(`stbl`,v.children).fullBox(`stsd`,v.sampleDescription).fullBox(`pssh`,e=>t.psshList.push(E(e))).box(`encv`,v.visualSampleEntry).box(`enca`,v.audioSampleEntry).box(`sinf`,v.children).box(`schi`,v.children).fullBox(`schm`,e=>{t.schemeType=new TextDecoder().decode(e.reader.readBytes(4))}).fullBox(`tenc`,e=>{let{defaultKID:n}=T(e.reader);t.defaultKID=n}).parse(e,!1,!0),t},j=async(e,t)=>{let n=D(e);if(n)return k(e);let r,i,a,o;if(new v().box(`moof`,v.children).box(`traf`,v.children).fullBox(`tfhd`,e=>{a=te(e.reader,e.flags)}).fullBox(`trun`,e=>{i=y(e.reader,e.flags,e.version)}).fullBox(`senc`,e=>{r=ee(e.reader,e.flags)}).parse(e,!0,!0),o=i.dataOffset,r.samples.length!==i.samples.length)throw Error(`sample count mismatch: trun has ${i.samples.length}, senc has ${r.samples.length}`);let s=0,c=0;for(let n=0;n<r.samples.length;n++){let l=r.samples[n],u=i.samples[n],d=i.samples[n].size||a.defaultSampleSize||0;l.subsamples.length||l.subsamples.push({bytesOfClearData:0,bytesOfEncryptedData:d});let f=l.subsamples.some(e=>e.bytesOfEncryptedData>0);if(f){let n=0,r=[];for(let t of l.subsamples){if(n+=t.bytesOfClearData,t.bytesOfEncryptedData>0){let i=e.subarray(o+s+n,o+s+n+t.bytesOfEncryptedData);r.push(i)}n+=t.bytesOfEncryptedData}let i=C(r),a={iv:l.iv,data:i,timestamp:c},u=await t(a);if(u){n=0;let t=0,r=[];for(let i of l.subsamples){if(i.bytesOfClearData>0){let t=e.subarray(o+s+n,o+s+n+i.bytesOfClearData);r.push(t),n+=i.bytesOfClearData}if(i.bytesOfEncryptedData>0){let e=u.subarray(t,t+i.bytesOfEncryptedData);r.push(e),t+=i.bytesOfEncryptedData,n+=i.bytesOfEncryptedData}}let i=C(r);ne(i,e,o+s)}}s+=d,c+=u.duration||a.defaultSampleDuration||0}return new v().box(`moof`,v.children).box(`traf`,v.children).box(`senc`,t=>{let n=`skip`,r=t.start+n.length;re(e,n,r)}).parse(e,!0,!0),e},M=e=>{let t=null;new v().box(`moov`,e=>{t=e.start+e.size}).parse(e,!0,!0);let n=t?e.subarray(0,t):null;return{moovEnd:t,init:n}},N=e=>{let t=null,n=null;new v().box(`moof`,e=>{t===null&&(t=e.start)}).box(`mdat`,e=>{n===null&&(n=e.start+e.size)}).parse(e,!0,!0);let r=t!==null&&n!==null,i=r?e.subarray(t,n):null;return{segment:i,moofStart:t,mdatEnd:n}};var P=class{buffer=new Uint8Array;isProcessingInit=!0;scheme=null;processedBytes=0;constructor(e){this.options=e}async transform(e,t){try{this.buffer=C([this.buffer,e]);let n=!0;for(;n;){if(this.isProcessingInit){let{init:e,moovEnd:n}=M(this.buffer);if(!n||this.buffer.length<n)break;if(e&&D(e)){let r=A(e);this.scheme=r.schemeType;let i=await k(e);t.enqueue(i),this.updateProgress(i.byteLength),this.buffer=this.buffer.subarray(n),this.isProcessingInit=!1;continue}}let{moofStart:e,mdatEnd:r,segment:i}=N(this.buffer);if(e===null||r===null||!i||this.buffer.length<r)break;let a=e=>(e.encryptionScheme=this.scheme,this.options.transformSample(e)),o=await j(i,a);t.enqueue(o),this.updateProgress(o.byteLength),this.buffer=this.buffer.subarray(r),n=this.buffer.length>=8}}catch(e){t.error(e)}}async flush(e){this.buffer.length>0&&(e.enqueue(this.buffer),this.updateProgress(this.buffer.byteLength))}updateProgress(e){this.processedBytes+=e,this.options.onProgress&&this.options.onProgress(this.processedBytes)}};const F=async(e,t,{transformSample:n,onProgress:r,preventClose:i})=>{let a=new P({transformSample:n,onProgress:r}),o=new TransformStream({transform:(e,t)=>a.transform(e,t),flush:e=>a.flush(e)});await e.pipeThrough(o).pipeTo(t,{preventClose:i})},I=async(e,t)=>{let n=t.encryptionScheme,r=t.iv,i=t.data;return f(n===`cbcs`?{key:e,iv:r,data:i,algorithm:`AES-CBC`}:{key:e,iv:r,data:i,algorithm:`AES-CTR`})},L=async(e,t,{preventClose:n,onProgress:r,...i})=>{let a=`key`in i,o=new Uint8Array(ae(a?i.key:``)),s=async e=>I(o,e),c=a?s:i.transformSample;await F(e,t,{preventClose:n,onProgress:r,transformSample:c})},R=async(e,t,n)=>{let r=await(0,u.stat)(e),i=(0,l.createReadStream)(e,{highWaterMark:1024*1024*10}),a=d.Readable.toWeb(i),o=(0,l.createWriteStream)(t),s=d.Writable.toWeb(o);console.time(`
3
+ Done!`),await L(a,s,{key:`key`in n?n.key:``,keyId:n.keyId,onProgress:e=>{process.stdout.write(`\rDecrypting... [${e}/${r.size}]`),e===r.size&&process.stdout.write(`
4
+ `)}}),console.timeEnd(`
5
+ Done!`)};var z=`shifro`,B=`0.1.2`,V=`A lightweight, dependency-free MP4 decrypter`,H=[`dist`],U={start:`node ./dist/cli.cjs`,web:`vite`,build:`npm run build:lib && npm run build:cli`,"build:cli":`tsdown ./lib/node/cli.ts --format cjs --dts --minify --no-clean`,"build:lib":`tsdown shifro.ts --format cjs --format esm --dts --minify`,typecheck:`tsc --noEmit`,test:`vitest`,prepublishOnly:`npm run build`},W={shifro:`./dist/cli.cjs`},oe=`module`,G=`./dist/shifro.js`,K=`./dist/shifro.d.ts`,q={".":{require:{types:`./dist/shifro.d.cts`,default:`./dist/shifro.cjs`},import:{types:`./dist/shifro.d.ts`,default:`./dist/shifro.js`}}},se={type:`git`,url:`git+https://github.com/streamyx-labs/shifro.git`},ce=[`mp4`,`mpeg`,`cenc`,`cbcs`,`decrypt`,`decryption`,`decrypter`,`decryptor`,`dash`,`drm`,`mp4decrypt`,`mp4box`,`shaka`,`shaka-packager`],le={url:`https://github.com/streamyx-labs/shifro/issues`,email:`vitalygashkov@vk.com`},ue=`Vitaly Gashkov <vitalygashkov@vk.com>`,de=`AGPL-3.0`,J=`README.md`,fe=[{type:`individual`,url:`https://boosty.to/vitalygashkov`},{type:`patreon`,url:`https://www.patreon.com/vitalygashkov`}],pe={node:`20 || 21 || 22 || 23`},me={"@types/node":`^22.15.3`,tsdown:`^0.11.0-beta.3`,typescript:`^5.8.3`,vitest:`^3.1.2`},he={name:z,version:B,description:V,files:H,scripts:U,bin:W,type:oe,main:G,types:K,exports:q,repository:se,keywords:ce,bugs:le,author:ue,license:de,readmeFilename:J,funding:fe,engines:pe,devDependencies:me};const Y=(0,c.parseArgs)({allowPositionals:!0,strict:!1,options:{key:{short:`k`,type:`string`,multiple:!0},help:{short:`h`,type:`boolean`}}}),ge=Array.isArray(Y.values.key)?Y.values.key:[],[X,Z]=ge[0]?.split(`:`)??[],[Q,$]=Y.positionals;(async()=>{Q&&$&&X&&Z?await R(Q,$,{key:Z,keyId:X}):console.log(`
6
+ shifro version ${he.version}
5
7
  (c) 2024 Vitaly Gashkov <vitalygashkov@vk.com>
6
8
 
7
- Usage: dempeg [options] <input> <output>
9
+ Usage: shifro [options] <input> <output>
8
10
 
9
11
  Options:
10
12
  --key <id>:<k>
package/dist/shifro.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";const e=async({key:e,iv:t,data:n,algorithm:r=`AES-CTR`})=>{let i=r.toUpperCase(),a=await crypto.subtle.importKey(`raw`,e,{name:i},!1,[`decrypt`]),o=await crypto.subtle.decrypt({name:i,counter:t,length:64},a,n);return new Uint8Array(o)},t=e=>{let t=e.buffer,n=new DataView(t,e.byteOffset,e.byteLength);return n},n=(e,t=0,n)=>new Uint8Array(e.buffer,e.byteOffset+t,n);var r=class extends Error{constructor(e,t,n,r){super(r),this.severity=e,this.category=t,this.code=n,this.name=`DataViewReaderError`}},i=class{position=0;constructor(e,n=`BE`){this.dataView=t(e),this.littleEndian=n===`LE`}getDataView(){return this.dataView}hasMoreData(){return this.position<this.dataView.byteLength}getPosition(){return this.position}getLength(){return this.dataView.byteLength}readUint8(){this.checkBounds(1);let e=this.dataView.getUint8(this.position);return this.position+=1,e}readUint16(){this.checkBounds(2);let e=this.dataView.getUint16(this.position,this.littleEndian);return this.position+=2,e}readUint32(){this.checkBounds(4);let e=this.dataView.getUint32(this.position,this.littleEndian);return this.position+=4,e}readInt32(){this.checkBounds(4);let e=this.dataView.getInt32(this.position,this.littleEndian);return this.position+=4,e}readUint64(){let e,t;try{this.littleEndian?(e=this.dataView.getUint32(this.position,!0),t=this.dataView.getUint32(this.position+4,!0)):(t=this.dataView.getUint32(this.position,!1),e=this.dataView.getUint32(this.position+4,!1))}catch{throw this.outOfBounds()}if(t>2097151)throw new r(`CRITICAL`,`MEDIA`,`JS_INTEGER_OVERFLOW`,`64-bit integer overflow`);return this.position+=8,t*2**32+e}readBytes(e){this.checkBounds(e);let t=n(this.dataView,this.position,e);return this.position+=e,t}skip(e){this.checkBounds(e),this.position+=e}rewind(e){if(this.position<e)throw this.outOfBounds();this.position-=e}seek(e){if(e<0||e>this.dataView.byteLength)throw this.outOfBounds();this.position=e}readTerminatedString(){let e=this.position;for(;this.hasMoreData()&&this.dataView.getUint8(this.position)!==0;)this.position++;if(!this.hasMoreData())throw this.outOfBounds();let t=new Uint8Array(this.dataView.buffer,e,this.position-e);return this.position++,new TextDecoder().decode(t)}checkBounds(e){if(this.position+e>this.dataView.byteLength)throw this.outOfBounds()}outOfBounds(){return new r(`CRITICAL`,`MEDIA`,`BUFFER_READ_OUT_OF_BOUNDS`,`Read operation out of bounds`)}};let a=function(e){return e[e.BASIC_BOX=0]=`BASIC_BOX`,e[e.FULL_BOX=1]=`FULL_BOX`,e}({});var o=class e{headers=new Map;boxDefinitions=new Map;done=!1;box(t,n){let r=e.typeFromString(t);return this.headers.set(r,a.BASIC_BOX),this.boxDefinitions.set(r,n),this}fullBox(t,n){let r=e.typeFromString(t);return this.headers.set(r,a.FULL_BOX),this.boxDefinitions.set(r,n),this}stop(){this.done=!0}parse(e,t=!1,n=!1){let r=new i(e);for(this.done=!1;r.hasMoreData()&&!this.done;)this.parseNext(0,r,t,n)}parseNext(t,n,r,o){let s=n.getPosition();if(o&&s+8>n.getLength()){this.done=!0;return}let c=n.readUint32(),l=n.readUint32(),u=e.typeToString(l),d=!1;switch(c){case 0:c=n.getLength()-s;break;case 1:if(o&&n.getPosition()+8>n.getLength()){this.done=!0;return}c=Number(n.readUint64()),d=!0;break}let f=this.boxDefinitions.get(l);if(f){let e=null,p=null;if(this.headers.get(l)===a.FULL_BOX){if(o&&n.getPosition()+4>n.getLength()){this.done=!0;return}let t=n.readUint32();e=t>>>24,p=t&16777215}let m=s+c;if(r&&m>n.getLength()&&(m=n.getLength()),o&&m>n.getLength()){this.done=!0;return}let h=m-n.getPosition(),g=h>0?n.readBytes(h):new Uint8Array,_=new i(g),v={name:u,parser:this,partialOkay:!!r,version:e,flags:p,reader:_,size:c,start:s+t,has64BitSize:d};f(v)}else{let e=Math.min(s+c-n.getPosition(),n.getLength()-n.getPosition());n.skip(e)}}static children(t){let n=e.headerSize(t);for(;t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static sampleDescription(t){let n=e.headerSize(t),r=t.reader.readUint32();for(let e=0;e<r&&(t.parser.parseNext(t.start+n,t.reader,t.partialOkay),!t.parser.done);e++);}static visualSampleEntry(t){let n=e.headerSize(t);for(t.reader.skip(78);t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static audioSampleEntry(t){let n=e.headerSize(t);t.reader.skip(8);let r=t.reader.readUint16();for(t.reader.skip(6),r===2?t.reader.skip(48):t.reader.skip(12),r===1&&t.reader.skip(16);t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static allData(e){return t=>{let n=t.reader.getLength()-t.reader.getPosition();e(t.reader.readBytes(n))}}static typeFromString(e){if(e.length!==4)throw Error(`MP4 box names must be 4 characters long`);let t=0;for(let n of e)t=t<<8|n.charCodeAt(0);return t}static typeToString(e){return String.fromCharCode(e>>24&255,e>>16&255,e>>8&255,e&255)}static headerSize(e){let t=8,n=e.has64BitSize?8:0,r=e.flags===null?0:4;return t+n+r}};const s=(e,t)=>{if(t&&t&1){let t=e.readUint8(),n=e.readUint8(),r=e.readBytes(16)}let n=e.readUint32(),r=[];for(let i=0;i<n;i++){let n=8,i=new Uint8Array(16);i.set(e.readBytes(n));let a={iv:i,subsamples:[]},o=t&&t&2;if(o){let t=e.readUint16();for(let n=0;n<t;n++){let t=e.readUint16(),n=e.readUint32();a.subsamples.push({bytesOfClearData:t,bytesOfEncryptedData:n})}}r.push(a)}return{samples:r}},c=(e,t,n)=>{let r=e.readUint32(),i=[],a=null;t&1&&(a=e.readInt32()),t&4&&e.skip(4);for(let a=0;a<r;a++){let r={};t&256&&(r.duration=e.readUint32()),t&512&&(r.size=e.readUint32()),t&1024&&e.skip(4),t&2048&&(r.compositionTimeOffset=n==0?e.readUint32():e.readInt32()),i.push(r)}return{samples:i,dataOffset:a}},l=(e,t)=>{let n,r,i,a,o=e.readUint32();return t&1&&(i=e.readUint64()),t&2&&(a=e.readUint32()),t&8&&(n=e.readUint32()),t&16&&(r=e.readUint32()),{trackId:o,defaultSampleDuration:n,defaultSampleSize:r,baseDataOffset:i,sampleDescriptionIndex:a}},u=(e,t,n)=>{if(t.length===0)return-1;let r=e.length-t.length+1;for(let i=n;i<r;i++){let n=!0;for(let r=0;r<t.length;r++)if(e[i+r]!==t[r]){n=!1;break}if(n)return i}return-1},d=(e,t,n)=>{let r=new TextEncoder,i=r.encode(t),a=r.encode(n);if(i.length!==a.length)throw Error(`Original and replacement must have the same byte length`);let o=0;do o=u(e,i,0),o!==-1&&e.set(a,o);while(o!==-1)},f=(e,t,n=0)=>{let r=new TextEncoder,i;return i=typeof t==`string`?r.encode(t):typeof t==`number`?new Uint8Array([t]):t,i.length===0?!0:e.length<i.length?!1:u(e,i,n)!==-1},p=(e,t)=>{if(e.length===0)return new Uint8Array;let n=t??e.reduce((e,t)=>e+t.length,0);n=Math.min(n,e.reduce((e,t)=>e+t.length,0));let r=new Uint8Array(n),i=0;for(let t of e){if(i>=n)break;let e=t.subarray(0,Math.min(t.length,n-i));r.set(e,i),i+=e.length}return r},m=(e,t,n=0,r=0,i=e.length)=>{n=Math.max(0,Math.min(n,t.length)),r=Math.max(0,Math.min(r,e.length)),i=Math.min(i,e.length),i<r&&(i=r);let a=Math.min(i-r,t.length-n);return a<=0?0:(t.set(e.subarray(r,r+a),n),a)},h=(e,t,n=0,r)=>{let i=new TextEncoder,a=i.encode(t),o=Math.max(0,Math.min(n,e.length)),s=e.length-o,c=a.length;return typeof r==`number`&&(c=Math.min(c,r)),c=Math.min(c,s),c<=0?0:(e.set(a.subarray(0,c),o),c)},g=e=>Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),_=e=>{let t=Array.from(e,e=>String.fromCodePoint(e)).join(``);return btoa(t)},v=e=>e.match(/.{1,2}/g).map(e=>parseInt(e,16)),y=e=>{e.readUint8(),e.readUint8(),e.readUint8(),e.readUint8();let t=g(e.readBytes(16));return{defaultKID:t}},b=e=>{let t=`edef8ba979d64acea3c827dcd51d21ed`,n=e.version??0;if(n!==0&&n!==1)throw Error(`PSSH version can only be 0 or 1`);let r=e.reader.readBytes(16),i=g(r),a=[i.slice(0,8),i.slice(8,12),i.slice(12,16),i.slice(16,20),i.slice(20)].join(`-`),o=e.reader.getDataView(),s=new Uint8Array(o.buffer,o.byteOffset-12,e.size),c=_(s),l=[];if(n>=1){let t=e.reader.readUint32();for(let n=0;n<t;n++)l.push(g(e.reader.readBytes(16)))}let u=e.reader.readUint32(),d=e.reader.readBytes(u),f=i===t;return{version:n,systemId:a,pssh:c,keyIds:l,systemData:d}},x=e=>{try{let t=!1,n=!1;return new o().box(`moov`,()=>{t=!0}).box(`moof`,()=>{n=!0}).parse(e,!0,!0),t&&!n}catch(e){return console.log(e),!1}},S=e=>{let t=null;return new o().box(`moov`,o.children).box(`trak`,o.children).box(`mdia`,o.children).box(`minf`,o.children).box(`stbl`,o.children).fullBox(`stsd`,o.sampleDescription).box(`encv`,o.visualSampleEntry).box(`enca`,o.audioSampleEntry).box(`sinf`,o.children).box(`frma`,e=>{let n=e.reader.readBytes(4);t=new TextDecoder().decode(n)}).parse(e,!0,!0),t},C=async e=>{let t=S(e);if(d(e,`sinf`,`skip`),d(e,`pssh`,`skip`),t)d(e,`encv`,t),d(e,`enca`,t);else{console.warn(`Could not detect original codec, using fallback values`);let t=f(e,`encv`)?`video`:`audio`;t===`video`?d(e,`encv`,`avc1`):d(e,`enca`,`mp4a`)}return e},w=e=>{let t={schemeType:``,defaultKID:``,psshList:[]};return new o().box(`moov`,o.children).box(`trak`,o.children).box(`mdia`,o.children).box(`minf`,o.children).box(`stbl`,o.children).fullBox(`stsd`,o.sampleDescription).fullBox(`pssh`,e=>t.psshList.push(b(e))).box(`encv`,o.visualSampleEntry).box(`enca`,o.audioSampleEntry).box(`sinf`,o.children).box(`schi`,o.children).fullBox(`schm`,e=>{t.schemeType=new TextDecoder().decode(e.reader.readBytes(4))}).fullBox(`tenc`,e=>{let{defaultKID:n}=y(e.reader);t.defaultKID=n}).parse(e,!1,!0),t},T=async(e,t)=>{let n=x(e);if(n)return C(e);let r,i,a,u;if(new o().box(`moof`,o.children).box(`traf`,o.children).fullBox(`tfhd`,e=>{a=l(e.reader,e.flags)}).fullBox(`trun`,e=>{i=c(e.reader,e.flags,e.version)}).fullBox(`senc`,e=>{r=s(e.reader,e.flags)}).parse(e,!0,!0),u=i.dataOffset,r.samples.length!==i.samples.length)throw Error(`sample count mismatch: trun has ${i.samples.length}, senc has ${r.samples.length}`);let d=0,f=0;for(let n=0;n<r.samples.length;n++){let o=r.samples[n],s=i.samples[n],c=i.samples[n].size||a.defaultSampleSize||0;o.subsamples.length||o.subsamples.push({bytesOfClearData:0,bytesOfEncryptedData:c});let l=o.subsamples.some(e=>e.bytesOfEncryptedData>0);if(l){let n=0,r=[];for(let t of o.subsamples){if(n+=t.bytesOfClearData,t.bytesOfEncryptedData>0){let i=e.subarray(u+d+n,u+d+n+t.bytesOfEncryptedData);r.push(i)}n+=t.bytesOfEncryptedData}let i=p(r),a={iv:o.iv,data:i,timestamp:f},s=await t(a);if(s){n=0;let t=0,r=[];for(let i of o.subsamples){if(i.bytesOfClearData>0){let t=e.subarray(u+d+n,u+d+n+i.bytesOfClearData);r.push(t),n+=i.bytesOfClearData}if(i.bytesOfEncryptedData>0){let e=s.subarray(t,t+i.bytesOfEncryptedData);r.push(e),t+=i.bytesOfEncryptedData,n+=i.bytesOfEncryptedData}}let i=p(r);m(i,e,u+d)}}d+=c,f+=s.duration||a.defaultSampleDuration||0}return new o().box(`moof`,o.children).box(`traf`,o.children).box(`senc`,t=>{let n=`skip`,r=t.start+n.length;h(e,n,r)}).parse(e,!0,!0),e},E=e=>{let t=null;new o().box(`moov`,e=>{t=e.start+e.size}).parse(e,!0,!0);let n=t?e.subarray(0,t):null;return{moovEnd:t,init:n}},D=e=>{let t=null,n=null;new o().box(`moof`,e=>{t===null&&(t=e.start)}).box(`mdat`,e=>{n===null&&(n=e.start+e.size)}).parse(e,!0,!0);let r=t!==null&&n!==null,i=r?e.subarray(t,n):null;return{segment:i,moofStart:t,mdatEnd:n}};var O=class{buffer=new Uint8Array;isProcessingInit=!0;scheme=null;processedBytes=0;constructor(e){this.options=e}async transform(e,t){try{this.buffer=p([this.buffer,e]);let n=!0;for(;n;){if(this.isProcessingInit){let{init:e,moovEnd:n}=E(this.buffer);if(!n||this.buffer.length<n)break;if(e&&x(e)){let r=w(e);this.scheme=r.schemeType;let i=await C(e);t.enqueue(i),this.updateProgress(i.byteLength),this.buffer=this.buffer.subarray(n),this.isProcessingInit=!1;continue}}let{moofStart:e,mdatEnd:r,segment:i}=D(this.buffer);if(e===null||r===null||!i||this.buffer.length<r)break;let a=e=>(e.encryptionScheme=this.scheme,this.options.transformSample(e)),o=await T(i,a);t.enqueue(o),this.updateProgress(o.byteLength),this.buffer=this.buffer.subarray(r),n=this.buffer.length>=8}}catch(e){t.error(e)}}async flush(e){this.buffer.length>0&&(e.enqueue(this.buffer),this.updateProgress(this.buffer.byteLength))}updateProgress(e){this.processedBytes+=e,this.options.onProgress&&this.options.onProgress(this.processedBytes)}};const k=async(e,t,{transformSample:n,onProgress:r,preventClose:i})=>{let a=new O({transformSample:n,onProgress:r}),o=new TransformStream({transform:(e,t)=>a.transform(e,t),flush:e=>a.flush(e)});await e.pipeThrough(o).pipeTo(t,{preventClose:i})},A=async(t,n)=>{let r=n.encryptionScheme,i=n.iv,a=n.data;return e(r===`cbcs`?{key:t,iv:i,data:a,algorithm:`AES-CBC`}:{key:t,iv:i,data:a,algorithm:`AES-CTR`})},j=async(e,t)=>{let n=`key`in t,r=new Uint8Array(v(n?t.key:``)),i=async e=>A(r,{encryptionScheme:`encryptionScheme`in t?t.encryptionScheme:void 0,...e}),a=n?i:t.transformSample;return T(e,a)},M=async(e,t,{preventClose:n,onProgress:r,...i})=>{let a=`key`in i,o=new Uint8Array(v(a?i.key:``)),s=async e=>A(o,e),c=a?s:i.transformSample;await k(e,t,{preventClose:n,onProgress:r,transformSample:c})};exports.decryptSegment=j,exports.decryptStream=M,exports.decryptWithKey=A;
1
+ "use strict";const e=async({key:e,iv:t,data:n,algorithm:r=`AES-CTR`})=>{let i=r.toUpperCase(),a=await crypto.subtle.importKey(`raw`,e,{name:i},!1,[`decrypt`]),o=await crypto.subtle.decrypt({name:i,counter:t,length:64},a,n);return new Uint8Array(o)},t=e=>{let t=e.buffer,n=new DataView(t,e.byteOffset,e.byteLength);return n},n=(e,t=0,n)=>new Uint8Array(e.buffer,e.byteOffset+t,n);var r=class extends Error{constructor(e,t,n,r){super(r),this.severity=e,this.category=t,this.code=n,this.name=`DataViewReaderError`}},i=class{position=0;constructor(e,n=`BE`){this.dataView=t(e),this.littleEndian=n===`LE`}getDataView(){return this.dataView}hasMoreData(){return this.position<this.dataView.byteLength}getPosition(){return this.position}getLength(){return this.dataView.byteLength}readUint8(){this.checkBounds(1);let e=this.dataView.getUint8(this.position);return this.position+=1,e}readUint16(){this.checkBounds(2);let e=this.dataView.getUint16(this.position,this.littleEndian);return this.position+=2,e}readUint32(){this.checkBounds(4);let e=this.dataView.getUint32(this.position,this.littleEndian);return this.position+=4,e}readInt32(){this.checkBounds(4);let e=this.dataView.getInt32(this.position,this.littleEndian);return this.position+=4,e}readUint64(){let e,t;try{this.littleEndian?(e=this.dataView.getUint32(this.position,!0),t=this.dataView.getUint32(this.position+4,!0)):(t=this.dataView.getUint32(this.position,!1),e=this.dataView.getUint32(this.position+4,!1))}catch{throw this.outOfBounds()}if(t>2097151)throw new r(`CRITICAL`,`MEDIA`,`JS_INTEGER_OVERFLOW`,`64-bit integer overflow`);return this.position+=8,t*2**32+e}readBytes(e){this.checkBounds(e);let t=n(this.dataView,this.position,e);return this.position+=e,t}skip(e){this.checkBounds(e),this.position+=e}rewind(e){if(this.position<e)throw this.outOfBounds();this.position-=e}seek(e){if(e<0||e>this.dataView.byteLength)throw this.outOfBounds();this.position=e}readTerminatedString(){let e=this.position;for(;this.hasMoreData()&&this.dataView.getUint8(this.position)!==0;)this.position++;if(!this.hasMoreData())throw this.outOfBounds();let t=new Uint8Array(this.dataView.buffer,e,this.position-e);return this.position++,new TextDecoder().decode(t)}checkBounds(e){if(this.position+e>this.dataView.byteLength)throw this.outOfBounds()}outOfBounds(){return new r(`CRITICAL`,`MEDIA`,`BUFFER_READ_OUT_OF_BOUNDS`,`Read operation out of bounds`)}};let a=function(e){return e[e.BASIC_BOX=0]=`BASIC_BOX`,e[e.FULL_BOX=1]=`FULL_BOX`,e}({});var o=class e{headers=new Map;boxDefinitions=new Map;done=!1;box(t,n){let r=e.typeFromString(t);return this.headers.set(r,a.BASIC_BOX),this.boxDefinitions.set(r,n),this}fullBox(t,n){let r=e.typeFromString(t);return this.headers.set(r,a.FULL_BOX),this.boxDefinitions.set(r,n),this}stop(){this.done=!0}parse(e,t=!1,n=!1){let r=new i(e);for(this.done=!1;r.hasMoreData()&&!this.done;)this.parseNext(0,r,t,n)}parseNext(t,n,r,o){let s=n.getPosition();if(o&&s+8>n.getLength()){this.done=!0;return}let c=n.readUint32(),l=n.readUint32(),u=e.typeToString(l),d=!1;switch(c){case 0:c=n.getLength()-s;break;case 1:if(o&&n.getPosition()+8>n.getLength()){this.done=!0;return}c=Number(n.readUint64()),d=!0;break}let f=this.boxDefinitions.get(l);if(f){let e=null,p=null;if(this.headers.get(l)===a.FULL_BOX){if(o&&n.getPosition()+4>n.getLength()){this.done=!0;return}let t=n.readUint32();e=t>>>24,p=t&16777215}let m=s+c;if(r&&m>n.getLength()&&(m=n.getLength()),o&&m>n.getLength()){this.done=!0;return}let h=m-n.getPosition(),g=h>0?n.readBytes(h):new Uint8Array,_=new i(g),v={name:u,parser:this,partialOkay:!!r,version:e,flags:p,reader:_,size:c,start:s+t,has64BitSize:d};f(v)}else{let e=Math.min(s+c-n.getPosition(),n.getLength()-n.getPosition());n.skip(e)}}static children(t){let n=e.headerSize(t);for(;t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static sampleDescription(t){let n=e.headerSize(t),r=t.reader.readUint32();for(let e=0;e<r&&(t.parser.parseNext(t.start+n,t.reader,t.partialOkay),!t.parser.done);e++);}static visualSampleEntry(t){let n=e.headerSize(t);for(t.reader.skip(78);t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static audioSampleEntry(t){let n=e.headerSize(t);t.reader.skip(8);let r=t.reader.readUint16();for(t.reader.skip(6),r===2?t.reader.skip(48):t.reader.skip(12),r===1&&t.reader.skip(16);t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static allData(e){return t=>{let n=t.reader.getLength()-t.reader.getPosition();e(t.reader.readBytes(n))}}static typeFromString(e){if(e.length!==4)throw Error(`MP4 box names must be 4 characters long`);let t=0;for(let n of e)t=t<<8|n.charCodeAt(0);return t}static typeToString(e){return String.fromCharCode(e>>24&255,e>>16&255,e>>8&255,e&255)}static headerSize(e){let t=8,n=e.has64BitSize?8:0,r=e.flags===null?0:4;return t+n+r}};const s=(e,t)=>{if(t&&t&1){let t=e.readUint8(),n=e.readUint8(),r=e.readBytes(16)}let n=e.readUint32(),r=[];for(let i=0;i<n;i++){let n=8,i=new Uint8Array(16);i.set(e.readBytes(n));let a={iv:i,subsamples:[]},o=t&&t&2;if(o){let t=e.readUint16();for(let n=0;n<t;n++){let t=e.readUint16(),n=e.readUint32();a.subsamples.push({bytesOfClearData:t,bytesOfEncryptedData:n})}}r.push(a)}return{samples:r}},c=(e,t,n)=>{let r=e.readUint32(),i=[],a=null;t&1&&(a=e.readInt32()),t&4&&e.skip(4);for(let a=0;a<r;a++){let r={};t&256&&(r.duration=e.readUint32()),t&512&&(r.size=e.readUint32()),t&1024&&e.skip(4),t&2048&&(r.compositionTimeOffset=n==0?e.readUint32():e.readInt32()),i.push(r)}return{samples:i,dataOffset:a}},l=(e,t)=>{let n,r,i,a,o=e.readUint32();return t&1&&(i=e.readUint64()),t&2&&(a=e.readUint32()),t&8&&(n=e.readUint32()),t&16&&(r=e.readUint32()),{trackId:o,defaultSampleDuration:n,defaultSampleSize:r,baseDataOffset:i,sampleDescriptionIndex:a}},u=(e,t,n)=>{if(t.length===0)return-1;let r=e.length-t.length+1;for(let i=n;i<r;i++){let n=!0;for(let r=0;r<t.length;r++)if(e[i+r]!==t[r]){n=!1;break}if(n)return i}return-1},d=(e,t,n)=>{let r=new TextEncoder,i=r.encode(t),a=r.encode(n);if(i.length!==a.length)throw Error(`Original and replacement must have the same byte length`);let o=0;do o=u(e,i,0),o!==-1&&e.set(a,o);while(o!==-1)},f=(e,t,n=0)=>{let r=new TextEncoder,i;return i=typeof t==`string`?r.encode(t):typeof t==`number`?new Uint8Array([t]):t,i.length===0?!0:e.length<i.length?!1:u(e,i,n)!==-1},p=(e,t)=>{if(e.length===0)return new Uint8Array;let n=t??e.reduce((e,t)=>e+t.length,0);n=Math.min(n,e.reduce((e,t)=>e+t.length,0));let r=new Uint8Array(n),i=0;for(let t of e){if(i>=n)break;let e=t.subarray(0,Math.min(t.length,n-i));r.set(e,i),i+=e.length}return r},m=(e,t,n=0,r=0,i=e.length)=>{n=Math.max(0,Math.min(n,t.length)),r=Math.max(0,Math.min(r,e.length)),i=Math.min(i,e.length),i<r&&(i=r);let a=Math.min(i-r,t.length-n);return a<=0?0:(t.set(e.subarray(r,r+a),n),a)},h=(e,t,n=0,r)=>{let i=new TextEncoder,a=i.encode(t),o=Math.max(0,Math.min(n,e.length)),s=e.length-o,c=a.length;return typeof r==`number`&&(c=Math.min(c,r)),c=Math.min(c,s),c<=0?0:(e.set(a.subarray(0,c),o),c)},g=e=>Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),_=e=>{let t=Array.from(e,e=>String.fromCodePoint(e)).join(``);return btoa(t)},v=e=>e.match(/.{1,2}/g)?.map(e=>parseInt(e,16))??[],y=e=>{e.readUint8(),e.readUint8(),e.readUint8(),e.readUint8();let t=g(e.readBytes(16));return{defaultKID:t}},b=e=>{let t=`edef8ba979d64acea3c827dcd51d21ed`,n=e.version??0;if(n!==0&&n!==1)throw Error(`PSSH version can only be 0 or 1`);let r=e.reader.readBytes(16),i=g(r),a=[i.slice(0,8),i.slice(8,12),i.slice(12,16),i.slice(16,20),i.slice(20)].join(`-`),o=e.reader.getDataView(),s=new Uint8Array(o.buffer,o.byteOffset-12,e.size),c=_(s),l=[];if(n>=1){let t=e.reader.readUint32();for(let n=0;n<t;n++)l.push(g(e.reader.readBytes(16)))}let u=e.reader.readUint32(),d=e.reader.readBytes(u),f=i===t;return{version:n,systemId:a,pssh:c,keyIds:l,systemData:d}},x=e=>{try{let t=!1,n=!1;return new o().box(`moov`,()=>{t=!0}).box(`moof`,()=>{n=!0}).parse(e,!0,!0),t&&!n}catch(e){return console.log(e),!1}},S=e=>{let t=null;return new o().box(`moov`,o.children).box(`trak`,o.children).box(`mdia`,o.children).box(`minf`,o.children).box(`stbl`,o.children).fullBox(`stsd`,o.sampleDescription).box(`encv`,o.visualSampleEntry).box(`enca`,o.audioSampleEntry).box(`sinf`,o.children).box(`frma`,e=>{let n=e.reader.readBytes(4);t=new TextDecoder().decode(n)}).parse(e,!0,!0),t},C=async e=>{let t=S(e);if(d(e,`sinf`,`skip`),d(e,`pssh`,`skip`),t)d(e,`encv`,t),d(e,`enca`,t);else{console.warn(`Could not detect original codec, using fallback values`);let t=f(e,`encv`)?`video`:`audio`;t===`video`?d(e,`encv`,`avc1`):d(e,`enca`,`mp4a`)}return e},w=e=>{let t={schemeType:``,defaultKID:``,psshList:[]};return new o().box(`moov`,o.children).box(`trak`,o.children).box(`mdia`,o.children).box(`minf`,o.children).box(`stbl`,o.children).fullBox(`stsd`,o.sampleDescription).fullBox(`pssh`,e=>t.psshList.push(b(e))).box(`encv`,o.visualSampleEntry).box(`enca`,o.audioSampleEntry).box(`sinf`,o.children).box(`schi`,o.children).fullBox(`schm`,e=>{t.schemeType=new TextDecoder().decode(e.reader.readBytes(4))}).fullBox(`tenc`,e=>{let{defaultKID:n}=y(e.reader);t.defaultKID=n}).parse(e,!1,!0),t},T=async(e,t)=>{let n=x(e);if(n)return C(e);let r,i,a,u;if(new o().box(`moof`,o.children).box(`traf`,o.children).fullBox(`tfhd`,e=>{a=l(e.reader,e.flags)}).fullBox(`trun`,e=>{i=c(e.reader,e.flags,e.version)}).fullBox(`senc`,e=>{r=s(e.reader,e.flags)}).parse(e,!0,!0),u=i.dataOffset,r.samples.length!==i.samples.length)throw Error(`sample count mismatch: trun has ${i.samples.length}, senc has ${r.samples.length}`);let d=0,f=0;for(let n=0;n<r.samples.length;n++){let o=r.samples[n],s=i.samples[n],c=i.samples[n].size||a.defaultSampleSize||0;o.subsamples.length||o.subsamples.push({bytesOfClearData:0,bytesOfEncryptedData:c});let l=o.subsamples.some(e=>e.bytesOfEncryptedData>0);if(l){let n=0,r=[];for(let t of o.subsamples){if(n+=t.bytesOfClearData,t.bytesOfEncryptedData>0){let i=e.subarray(u+d+n,u+d+n+t.bytesOfEncryptedData);r.push(i)}n+=t.bytesOfEncryptedData}let i=p(r),a={iv:o.iv,data:i,timestamp:f},s=await t(a);if(s){n=0;let t=0,r=[];for(let i of o.subsamples){if(i.bytesOfClearData>0){let t=e.subarray(u+d+n,u+d+n+i.bytesOfClearData);r.push(t),n+=i.bytesOfClearData}if(i.bytesOfEncryptedData>0){let e=s.subarray(t,t+i.bytesOfEncryptedData);r.push(e),t+=i.bytesOfEncryptedData,n+=i.bytesOfEncryptedData}}let i=p(r);m(i,e,u+d)}}d+=c,f+=s.duration||a.defaultSampleDuration||0}return new o().box(`moof`,o.children).box(`traf`,o.children).box(`senc`,t=>{let n=`skip`,r=t.start+n.length;h(e,n,r)}).parse(e,!0,!0),e},E=e=>{let t=null;new o().box(`moov`,e=>{t=e.start+e.size}).parse(e,!0,!0);let n=t?e.subarray(0,t):null;return{moovEnd:t,init:n}},D=e=>{let t=null,n=null;new o().box(`moof`,e=>{t===null&&(t=e.start)}).box(`mdat`,e=>{n===null&&(n=e.start+e.size)}).parse(e,!0,!0);let r=t!==null&&n!==null,i=r?e.subarray(t,n):null;return{segment:i,moofStart:t,mdatEnd:n}};var O=class{buffer=new Uint8Array;isProcessingInit=!0;scheme=null;processedBytes=0;constructor(e){this.options=e}async transform(e,t){try{this.buffer=p([this.buffer,e]);let n=!0;for(;n;){if(this.isProcessingInit){let{init:e,moovEnd:n}=E(this.buffer);if(!n||this.buffer.length<n)break;if(e&&x(e)){let r=w(e);this.scheme=r.schemeType;let i=await C(e);t.enqueue(i),this.updateProgress(i.byteLength),this.buffer=this.buffer.subarray(n),this.isProcessingInit=!1;continue}}let{moofStart:e,mdatEnd:r,segment:i}=D(this.buffer);if(e===null||r===null||!i||this.buffer.length<r)break;let a=e=>(e.encryptionScheme=this.scheme,this.options.transformSample(e)),o=await T(i,a);t.enqueue(o),this.updateProgress(o.byteLength),this.buffer=this.buffer.subarray(r),n=this.buffer.length>=8}}catch(e){t.error(e)}}async flush(e){this.buffer.length>0&&(e.enqueue(this.buffer),this.updateProgress(this.buffer.byteLength))}updateProgress(e){this.processedBytes+=e,this.options.onProgress&&this.options.onProgress(this.processedBytes)}};const k=async(e,t,{transformSample:n,onProgress:r,preventClose:i})=>{let a=new O({transformSample:n,onProgress:r}),o=new TransformStream({transform:(e,t)=>a.transform(e,t),flush:e=>a.flush(e)});await e.pipeThrough(o).pipeTo(t,{preventClose:i})},A=async(t,n)=>{let r=n.encryptionScheme,i=n.iv,a=n.data;return e(r===`cbcs`?{key:t,iv:i,data:a,algorithm:`AES-CBC`}:{key:t,iv:i,data:a,algorithm:`AES-CTR`})},j=async(e,t)=>{let n=`key`in t,r=new Uint8Array(v(n?t.key:``)),i=async e=>A(r,{encryptionScheme:`encryptionScheme`in t?t.encryptionScheme:void 0,...e}),a=n?i:t.transformSample;return T(e,a)},M=async(e,t,{preventClose:n,onProgress:r,...i})=>{let a=`key`in i,o=new Uint8Array(v(a?i.key:``)),s=async e=>A(o,e),c=a?s:i.transformSample;await k(e,t,{preventClose:n,onProgress:r,transformSample:c})};exports.decryptSegment=j,exports.decryptStream=M,exports.decryptWithKey=A;
package/dist/shifro.js CHANGED
@@ -1 +1 @@
1
- const e=async({key:e,iv:t,data:n,algorithm:r=`AES-CTR`})=>{let i=r.toUpperCase(),a=await crypto.subtle.importKey(`raw`,e,{name:i},!1,[`decrypt`]),o=await crypto.subtle.decrypt({name:i,counter:t,length:64},a,n);return new Uint8Array(o)},t=e=>{let t=e.buffer,n=new DataView(t,e.byteOffset,e.byteLength);return n},n=(e,t=0,n)=>new Uint8Array(e.buffer,e.byteOffset+t,n);var r=class extends Error{constructor(e,t,n,r){super(r),this.severity=e,this.category=t,this.code=n,this.name=`DataViewReaderError`}},i=class{position=0;constructor(e,n=`BE`){this.dataView=t(e),this.littleEndian=n===`LE`}getDataView(){return this.dataView}hasMoreData(){return this.position<this.dataView.byteLength}getPosition(){return this.position}getLength(){return this.dataView.byteLength}readUint8(){this.checkBounds(1);let e=this.dataView.getUint8(this.position);return this.position+=1,e}readUint16(){this.checkBounds(2);let e=this.dataView.getUint16(this.position,this.littleEndian);return this.position+=2,e}readUint32(){this.checkBounds(4);let e=this.dataView.getUint32(this.position,this.littleEndian);return this.position+=4,e}readInt32(){this.checkBounds(4);let e=this.dataView.getInt32(this.position,this.littleEndian);return this.position+=4,e}readUint64(){let e,t;try{this.littleEndian?(e=this.dataView.getUint32(this.position,!0),t=this.dataView.getUint32(this.position+4,!0)):(t=this.dataView.getUint32(this.position,!1),e=this.dataView.getUint32(this.position+4,!1))}catch{throw this.outOfBounds()}if(t>2097151)throw new r(`CRITICAL`,`MEDIA`,`JS_INTEGER_OVERFLOW`,`64-bit integer overflow`);return this.position+=8,t*2**32+e}readBytes(e){this.checkBounds(e);let t=n(this.dataView,this.position,e);return this.position+=e,t}skip(e){this.checkBounds(e),this.position+=e}rewind(e){if(this.position<e)throw this.outOfBounds();this.position-=e}seek(e){if(e<0||e>this.dataView.byteLength)throw this.outOfBounds();this.position=e}readTerminatedString(){let e=this.position;for(;this.hasMoreData()&&this.dataView.getUint8(this.position)!==0;)this.position++;if(!this.hasMoreData())throw this.outOfBounds();let t=new Uint8Array(this.dataView.buffer,e,this.position-e);return this.position++,new TextDecoder().decode(t)}checkBounds(e){if(this.position+e>this.dataView.byteLength)throw this.outOfBounds()}outOfBounds(){return new r(`CRITICAL`,`MEDIA`,`BUFFER_READ_OUT_OF_BOUNDS`,`Read operation out of bounds`)}};let a=function(e){return e[e.BASIC_BOX=0]=`BASIC_BOX`,e[e.FULL_BOX=1]=`FULL_BOX`,e}({});var o=class e{headers=new Map;boxDefinitions=new Map;done=!1;box(t,n){let r=e.typeFromString(t);return this.headers.set(r,a.BASIC_BOX),this.boxDefinitions.set(r,n),this}fullBox(t,n){let r=e.typeFromString(t);return this.headers.set(r,a.FULL_BOX),this.boxDefinitions.set(r,n),this}stop(){this.done=!0}parse(e,t=!1,n=!1){let r=new i(e);for(this.done=!1;r.hasMoreData()&&!this.done;)this.parseNext(0,r,t,n)}parseNext(t,n,r,o){let s=n.getPosition();if(o&&s+8>n.getLength()){this.done=!0;return}let c=n.readUint32(),l=n.readUint32(),u=e.typeToString(l),d=!1;switch(c){case 0:c=n.getLength()-s;break;case 1:if(o&&n.getPosition()+8>n.getLength()){this.done=!0;return}c=Number(n.readUint64()),d=!0;break}let f=this.boxDefinitions.get(l);if(f){let e=null,p=null;if(this.headers.get(l)===a.FULL_BOX){if(o&&n.getPosition()+4>n.getLength()){this.done=!0;return}let t=n.readUint32();e=t>>>24,p=t&16777215}let m=s+c;if(r&&m>n.getLength()&&(m=n.getLength()),o&&m>n.getLength()){this.done=!0;return}let h=m-n.getPosition(),g=h>0?n.readBytes(h):new Uint8Array,_=new i(g),v={name:u,parser:this,partialOkay:!!r,version:e,flags:p,reader:_,size:c,start:s+t,has64BitSize:d};f(v)}else{let e=Math.min(s+c-n.getPosition(),n.getLength()-n.getPosition());n.skip(e)}}static children(t){let n=e.headerSize(t);for(;t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static sampleDescription(t){let n=e.headerSize(t),r=t.reader.readUint32();for(let e=0;e<r&&(t.parser.parseNext(t.start+n,t.reader,t.partialOkay),!t.parser.done);e++);}static visualSampleEntry(t){let n=e.headerSize(t);for(t.reader.skip(78);t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static audioSampleEntry(t){let n=e.headerSize(t);t.reader.skip(8);let r=t.reader.readUint16();for(t.reader.skip(6),r===2?t.reader.skip(48):t.reader.skip(12),r===1&&t.reader.skip(16);t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static allData(e){return t=>{let n=t.reader.getLength()-t.reader.getPosition();e(t.reader.readBytes(n))}}static typeFromString(e){if(e.length!==4)throw Error(`MP4 box names must be 4 characters long`);let t=0;for(let n of e)t=t<<8|n.charCodeAt(0);return t}static typeToString(e){return String.fromCharCode(e>>24&255,e>>16&255,e>>8&255,e&255)}static headerSize(e){let t=8,n=e.has64BitSize?8:0,r=e.flags===null?0:4;return t+n+r}};const s=(e,t)=>{if(t&&t&1){let t=e.readUint8(),n=e.readUint8(),r=e.readBytes(16)}let n=e.readUint32(),r=[];for(let i=0;i<n;i++){let n=8,i=new Uint8Array(16);i.set(e.readBytes(n));let a={iv:i,subsamples:[]},o=t&&t&2;if(o){let t=e.readUint16();for(let n=0;n<t;n++){let t=e.readUint16(),n=e.readUint32();a.subsamples.push({bytesOfClearData:t,bytesOfEncryptedData:n})}}r.push(a)}return{samples:r}},c=(e,t,n)=>{let r=e.readUint32(),i=[],a=null;t&1&&(a=e.readInt32()),t&4&&e.skip(4);for(let a=0;a<r;a++){let r={};t&256&&(r.duration=e.readUint32()),t&512&&(r.size=e.readUint32()),t&1024&&e.skip(4),t&2048&&(r.compositionTimeOffset=n==0?e.readUint32():e.readInt32()),i.push(r)}return{samples:i,dataOffset:a}},l=(e,t)=>{let n,r,i,a,o=e.readUint32();return t&1&&(i=e.readUint64()),t&2&&(a=e.readUint32()),t&8&&(n=e.readUint32()),t&16&&(r=e.readUint32()),{trackId:o,defaultSampleDuration:n,defaultSampleSize:r,baseDataOffset:i,sampleDescriptionIndex:a}},u=(e,t,n)=>{if(t.length===0)return-1;let r=e.length-t.length+1;for(let i=n;i<r;i++){let n=!0;for(let r=0;r<t.length;r++)if(e[i+r]!==t[r]){n=!1;break}if(n)return i}return-1},d=(e,t,n)=>{let r=new TextEncoder,i=r.encode(t),a=r.encode(n);if(i.length!==a.length)throw Error(`Original and replacement must have the same byte length`);let o=0;do o=u(e,i,0),o!==-1&&e.set(a,o);while(o!==-1)},f=(e,t,n=0)=>{let r=new TextEncoder,i;return i=typeof t==`string`?r.encode(t):typeof t==`number`?new Uint8Array([t]):t,i.length===0?!0:e.length<i.length?!1:u(e,i,n)!==-1},p=(e,t)=>{if(e.length===0)return new Uint8Array;let n=t??e.reduce((e,t)=>e+t.length,0);n=Math.min(n,e.reduce((e,t)=>e+t.length,0));let r=new Uint8Array(n),i=0;for(let t of e){if(i>=n)break;let e=t.subarray(0,Math.min(t.length,n-i));r.set(e,i),i+=e.length}return r},m=(e,t,n=0,r=0,i=e.length)=>{n=Math.max(0,Math.min(n,t.length)),r=Math.max(0,Math.min(r,e.length)),i=Math.min(i,e.length),i<r&&(i=r);let a=Math.min(i-r,t.length-n);return a<=0?0:(t.set(e.subarray(r,r+a),n),a)},h=(e,t,n=0,r)=>{let i=new TextEncoder,a=i.encode(t),o=Math.max(0,Math.min(n,e.length)),s=e.length-o,c=a.length;return typeof r==`number`&&(c=Math.min(c,r)),c=Math.min(c,s),c<=0?0:(e.set(a.subarray(0,c),o),c)},g=e=>Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),_=e=>{let t=Array.from(e,e=>String.fromCodePoint(e)).join(``);return btoa(t)},v=e=>e.match(/.{1,2}/g).map(e=>parseInt(e,16)),y=e=>{e.readUint8(),e.readUint8(),e.readUint8(),e.readUint8();let t=g(e.readBytes(16));return{defaultKID:t}},b=e=>{let t=`edef8ba979d64acea3c827dcd51d21ed`,n=e.version??0;if(n!==0&&n!==1)throw Error(`PSSH version can only be 0 or 1`);let r=e.reader.readBytes(16),i=g(r),a=[i.slice(0,8),i.slice(8,12),i.slice(12,16),i.slice(16,20),i.slice(20)].join(`-`),o=e.reader.getDataView(),s=new Uint8Array(o.buffer,o.byteOffset-12,e.size),c=_(s),l=[];if(n>=1){let t=e.reader.readUint32();for(let n=0;n<t;n++)l.push(g(e.reader.readBytes(16)))}let u=e.reader.readUint32(),d=e.reader.readBytes(u),f=i===t;return{version:n,systemId:a,pssh:c,keyIds:l,systemData:d}},x=e=>{try{let t=!1,n=!1;return new o().box(`moov`,()=>{t=!0}).box(`moof`,()=>{n=!0}).parse(e,!0,!0),t&&!n}catch(e){return console.log(e),!1}},S=e=>{let t=null;return new o().box(`moov`,o.children).box(`trak`,o.children).box(`mdia`,o.children).box(`minf`,o.children).box(`stbl`,o.children).fullBox(`stsd`,o.sampleDescription).box(`encv`,o.visualSampleEntry).box(`enca`,o.audioSampleEntry).box(`sinf`,o.children).box(`frma`,e=>{let n=e.reader.readBytes(4);t=new TextDecoder().decode(n)}).parse(e,!0,!0),t},C=async e=>{let t=S(e);if(d(e,`sinf`,`skip`),d(e,`pssh`,`skip`),t)d(e,`encv`,t),d(e,`enca`,t);else{console.warn(`Could not detect original codec, using fallback values`);let t=f(e,`encv`)?`video`:`audio`;t===`video`?d(e,`encv`,`avc1`):d(e,`enca`,`mp4a`)}return e},w=e=>{let t={schemeType:``,defaultKID:``,psshList:[]};return new o().box(`moov`,o.children).box(`trak`,o.children).box(`mdia`,o.children).box(`minf`,o.children).box(`stbl`,o.children).fullBox(`stsd`,o.sampleDescription).fullBox(`pssh`,e=>t.psshList.push(b(e))).box(`encv`,o.visualSampleEntry).box(`enca`,o.audioSampleEntry).box(`sinf`,o.children).box(`schi`,o.children).fullBox(`schm`,e=>{t.schemeType=new TextDecoder().decode(e.reader.readBytes(4))}).fullBox(`tenc`,e=>{let{defaultKID:n}=y(e.reader);t.defaultKID=n}).parse(e,!1,!0),t},T=async(e,t)=>{let n=x(e);if(n)return C(e);let r,i,a,u;if(new o().box(`moof`,o.children).box(`traf`,o.children).fullBox(`tfhd`,e=>{a=l(e.reader,e.flags)}).fullBox(`trun`,e=>{i=c(e.reader,e.flags,e.version)}).fullBox(`senc`,e=>{r=s(e.reader,e.flags)}).parse(e,!0,!0),u=i.dataOffset,r.samples.length!==i.samples.length)throw Error(`sample count mismatch: trun has ${i.samples.length}, senc has ${r.samples.length}`);let d=0,f=0;for(let n=0;n<r.samples.length;n++){let o=r.samples[n],s=i.samples[n],c=i.samples[n].size||a.defaultSampleSize||0;o.subsamples.length||o.subsamples.push({bytesOfClearData:0,bytesOfEncryptedData:c});let l=o.subsamples.some(e=>e.bytesOfEncryptedData>0);if(l){let n=0,r=[];for(let t of o.subsamples){if(n+=t.bytesOfClearData,t.bytesOfEncryptedData>0){let i=e.subarray(u+d+n,u+d+n+t.bytesOfEncryptedData);r.push(i)}n+=t.bytesOfEncryptedData}let i=p(r),a={iv:o.iv,data:i,timestamp:f},s=await t(a);if(s){n=0;let t=0,r=[];for(let i of o.subsamples){if(i.bytesOfClearData>0){let t=e.subarray(u+d+n,u+d+n+i.bytesOfClearData);r.push(t),n+=i.bytesOfClearData}if(i.bytesOfEncryptedData>0){let e=s.subarray(t,t+i.bytesOfEncryptedData);r.push(e),t+=i.bytesOfEncryptedData,n+=i.bytesOfEncryptedData}}let i=p(r);m(i,e,u+d)}}d+=c,f+=s.duration||a.defaultSampleDuration||0}return new o().box(`moof`,o.children).box(`traf`,o.children).box(`senc`,t=>{let n=`skip`,r=t.start+n.length;h(e,n,r)}).parse(e,!0,!0),e},E=e=>{let t=null;new o().box(`moov`,e=>{t=e.start+e.size}).parse(e,!0,!0);let n=t?e.subarray(0,t):null;return{moovEnd:t,init:n}},D=e=>{let t=null,n=null;new o().box(`moof`,e=>{t===null&&(t=e.start)}).box(`mdat`,e=>{n===null&&(n=e.start+e.size)}).parse(e,!0,!0);let r=t!==null&&n!==null,i=r?e.subarray(t,n):null;return{segment:i,moofStart:t,mdatEnd:n}};var O=class{buffer=new Uint8Array;isProcessingInit=!0;scheme=null;processedBytes=0;constructor(e){this.options=e}async transform(e,t){try{this.buffer=p([this.buffer,e]);let n=!0;for(;n;){if(this.isProcessingInit){let{init:e,moovEnd:n}=E(this.buffer);if(!n||this.buffer.length<n)break;if(e&&x(e)){let r=w(e);this.scheme=r.schemeType;let i=await C(e);t.enqueue(i),this.updateProgress(i.byteLength),this.buffer=this.buffer.subarray(n),this.isProcessingInit=!1;continue}}let{moofStart:e,mdatEnd:r,segment:i}=D(this.buffer);if(e===null||r===null||!i||this.buffer.length<r)break;let a=e=>(e.encryptionScheme=this.scheme,this.options.transformSample(e)),o=await T(i,a);t.enqueue(o),this.updateProgress(o.byteLength),this.buffer=this.buffer.subarray(r),n=this.buffer.length>=8}}catch(e){t.error(e)}}async flush(e){this.buffer.length>0&&(e.enqueue(this.buffer),this.updateProgress(this.buffer.byteLength))}updateProgress(e){this.processedBytes+=e,this.options.onProgress&&this.options.onProgress(this.processedBytes)}};const k=async(e,t,{transformSample:n,onProgress:r,preventClose:i})=>{let a=new O({transformSample:n,onProgress:r}),o=new TransformStream({transform:(e,t)=>a.transform(e,t),flush:e=>a.flush(e)});await e.pipeThrough(o).pipeTo(t,{preventClose:i})},A=async(t,n)=>{let r=n.encryptionScheme,i=n.iv,a=n.data;return e(r===`cbcs`?{key:t,iv:i,data:a,algorithm:`AES-CBC`}:{key:t,iv:i,data:a,algorithm:`AES-CTR`})},j=async(e,t)=>{let n=`key`in t,r=new Uint8Array(v(n?t.key:``)),i=async e=>A(r,{encryptionScheme:`encryptionScheme`in t?t.encryptionScheme:void 0,...e}),a=n?i:t.transformSample;return T(e,a)},M=async(e,t,{preventClose:n,onProgress:r,...i})=>{let a=`key`in i,o=new Uint8Array(v(a?i.key:``)),s=async e=>A(o,e),c=a?s:i.transformSample;await k(e,t,{preventClose:n,onProgress:r,transformSample:c})};export{j as decryptSegment,M as decryptStream,A as decryptWithKey};
1
+ const e=async({key:e,iv:t,data:n,algorithm:r=`AES-CTR`})=>{let i=r.toUpperCase(),a=await crypto.subtle.importKey(`raw`,e,{name:i},!1,[`decrypt`]),o=await crypto.subtle.decrypt({name:i,counter:t,length:64},a,n);return new Uint8Array(o)},t=e=>{let t=e.buffer,n=new DataView(t,e.byteOffset,e.byteLength);return n},n=(e,t=0,n)=>new Uint8Array(e.buffer,e.byteOffset+t,n);var r=class extends Error{constructor(e,t,n,r){super(r),this.severity=e,this.category=t,this.code=n,this.name=`DataViewReaderError`}},i=class{position=0;constructor(e,n=`BE`){this.dataView=t(e),this.littleEndian=n===`LE`}getDataView(){return this.dataView}hasMoreData(){return this.position<this.dataView.byteLength}getPosition(){return this.position}getLength(){return this.dataView.byteLength}readUint8(){this.checkBounds(1);let e=this.dataView.getUint8(this.position);return this.position+=1,e}readUint16(){this.checkBounds(2);let e=this.dataView.getUint16(this.position,this.littleEndian);return this.position+=2,e}readUint32(){this.checkBounds(4);let e=this.dataView.getUint32(this.position,this.littleEndian);return this.position+=4,e}readInt32(){this.checkBounds(4);let e=this.dataView.getInt32(this.position,this.littleEndian);return this.position+=4,e}readUint64(){let e,t;try{this.littleEndian?(e=this.dataView.getUint32(this.position,!0),t=this.dataView.getUint32(this.position+4,!0)):(t=this.dataView.getUint32(this.position,!1),e=this.dataView.getUint32(this.position+4,!1))}catch{throw this.outOfBounds()}if(t>2097151)throw new r(`CRITICAL`,`MEDIA`,`JS_INTEGER_OVERFLOW`,`64-bit integer overflow`);return this.position+=8,t*2**32+e}readBytes(e){this.checkBounds(e);let t=n(this.dataView,this.position,e);return this.position+=e,t}skip(e){this.checkBounds(e),this.position+=e}rewind(e){if(this.position<e)throw this.outOfBounds();this.position-=e}seek(e){if(e<0||e>this.dataView.byteLength)throw this.outOfBounds();this.position=e}readTerminatedString(){let e=this.position;for(;this.hasMoreData()&&this.dataView.getUint8(this.position)!==0;)this.position++;if(!this.hasMoreData())throw this.outOfBounds();let t=new Uint8Array(this.dataView.buffer,e,this.position-e);return this.position++,new TextDecoder().decode(t)}checkBounds(e){if(this.position+e>this.dataView.byteLength)throw this.outOfBounds()}outOfBounds(){return new r(`CRITICAL`,`MEDIA`,`BUFFER_READ_OUT_OF_BOUNDS`,`Read operation out of bounds`)}};let a=function(e){return e[e.BASIC_BOX=0]=`BASIC_BOX`,e[e.FULL_BOX=1]=`FULL_BOX`,e}({});var o=class e{headers=new Map;boxDefinitions=new Map;done=!1;box(t,n){let r=e.typeFromString(t);return this.headers.set(r,a.BASIC_BOX),this.boxDefinitions.set(r,n),this}fullBox(t,n){let r=e.typeFromString(t);return this.headers.set(r,a.FULL_BOX),this.boxDefinitions.set(r,n),this}stop(){this.done=!0}parse(e,t=!1,n=!1){let r=new i(e);for(this.done=!1;r.hasMoreData()&&!this.done;)this.parseNext(0,r,t,n)}parseNext(t,n,r,o){let s=n.getPosition();if(o&&s+8>n.getLength()){this.done=!0;return}let c=n.readUint32(),l=n.readUint32(),u=e.typeToString(l),d=!1;switch(c){case 0:c=n.getLength()-s;break;case 1:if(o&&n.getPosition()+8>n.getLength()){this.done=!0;return}c=Number(n.readUint64()),d=!0;break}let f=this.boxDefinitions.get(l);if(f){let e=null,p=null;if(this.headers.get(l)===a.FULL_BOX){if(o&&n.getPosition()+4>n.getLength()){this.done=!0;return}let t=n.readUint32();e=t>>>24,p=t&16777215}let m=s+c;if(r&&m>n.getLength()&&(m=n.getLength()),o&&m>n.getLength()){this.done=!0;return}let h=m-n.getPosition(),g=h>0?n.readBytes(h):new Uint8Array,_=new i(g),v={name:u,parser:this,partialOkay:!!r,version:e,flags:p,reader:_,size:c,start:s+t,has64BitSize:d};f(v)}else{let e=Math.min(s+c-n.getPosition(),n.getLength()-n.getPosition());n.skip(e)}}static children(t){let n=e.headerSize(t);for(;t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static sampleDescription(t){let n=e.headerSize(t),r=t.reader.readUint32();for(let e=0;e<r&&(t.parser.parseNext(t.start+n,t.reader,t.partialOkay),!t.parser.done);e++);}static visualSampleEntry(t){let n=e.headerSize(t);for(t.reader.skip(78);t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static audioSampleEntry(t){let n=e.headerSize(t);t.reader.skip(8);let r=t.reader.readUint16();for(t.reader.skip(6),r===2?t.reader.skip(48):t.reader.skip(12),r===1&&t.reader.skip(16);t.reader.hasMoreData()&&!t.parser.done;)t.parser.parseNext(t.start+n,t.reader,t.partialOkay)}static allData(e){return t=>{let n=t.reader.getLength()-t.reader.getPosition();e(t.reader.readBytes(n))}}static typeFromString(e){if(e.length!==4)throw Error(`MP4 box names must be 4 characters long`);let t=0;for(let n of e)t=t<<8|n.charCodeAt(0);return t}static typeToString(e){return String.fromCharCode(e>>24&255,e>>16&255,e>>8&255,e&255)}static headerSize(e){let t=8,n=e.has64BitSize?8:0,r=e.flags===null?0:4;return t+n+r}};const s=(e,t)=>{if(t&&t&1){let t=e.readUint8(),n=e.readUint8(),r=e.readBytes(16)}let n=e.readUint32(),r=[];for(let i=0;i<n;i++){let n=8,i=new Uint8Array(16);i.set(e.readBytes(n));let a={iv:i,subsamples:[]},o=t&&t&2;if(o){let t=e.readUint16();for(let n=0;n<t;n++){let t=e.readUint16(),n=e.readUint32();a.subsamples.push({bytesOfClearData:t,bytesOfEncryptedData:n})}}r.push(a)}return{samples:r}},c=(e,t,n)=>{let r=e.readUint32(),i=[],a=null;t&1&&(a=e.readInt32()),t&4&&e.skip(4);for(let a=0;a<r;a++){let r={};t&256&&(r.duration=e.readUint32()),t&512&&(r.size=e.readUint32()),t&1024&&e.skip(4),t&2048&&(r.compositionTimeOffset=n==0?e.readUint32():e.readInt32()),i.push(r)}return{samples:i,dataOffset:a}},l=(e,t)=>{let n,r,i,a,o=e.readUint32();return t&1&&(i=e.readUint64()),t&2&&(a=e.readUint32()),t&8&&(n=e.readUint32()),t&16&&(r=e.readUint32()),{trackId:o,defaultSampleDuration:n,defaultSampleSize:r,baseDataOffset:i,sampleDescriptionIndex:a}},u=(e,t,n)=>{if(t.length===0)return-1;let r=e.length-t.length+1;for(let i=n;i<r;i++){let n=!0;for(let r=0;r<t.length;r++)if(e[i+r]!==t[r]){n=!1;break}if(n)return i}return-1},d=(e,t,n)=>{let r=new TextEncoder,i=r.encode(t),a=r.encode(n);if(i.length!==a.length)throw Error(`Original and replacement must have the same byte length`);let o=0;do o=u(e,i,0),o!==-1&&e.set(a,o);while(o!==-1)},f=(e,t,n=0)=>{let r=new TextEncoder,i;return i=typeof t==`string`?r.encode(t):typeof t==`number`?new Uint8Array([t]):t,i.length===0?!0:e.length<i.length?!1:u(e,i,n)!==-1},p=(e,t)=>{if(e.length===0)return new Uint8Array;let n=t??e.reduce((e,t)=>e+t.length,0);n=Math.min(n,e.reduce((e,t)=>e+t.length,0));let r=new Uint8Array(n),i=0;for(let t of e){if(i>=n)break;let e=t.subarray(0,Math.min(t.length,n-i));r.set(e,i),i+=e.length}return r},m=(e,t,n=0,r=0,i=e.length)=>{n=Math.max(0,Math.min(n,t.length)),r=Math.max(0,Math.min(r,e.length)),i=Math.min(i,e.length),i<r&&(i=r);let a=Math.min(i-r,t.length-n);return a<=0?0:(t.set(e.subarray(r,r+a),n),a)},h=(e,t,n=0,r)=>{let i=new TextEncoder,a=i.encode(t),o=Math.max(0,Math.min(n,e.length)),s=e.length-o,c=a.length;return typeof r==`number`&&(c=Math.min(c,r)),c=Math.min(c,s),c<=0?0:(e.set(a.subarray(0,c),o),c)},g=e=>Array.from(e).map(e=>e.toString(16).padStart(2,`0`)).join(``),_=e=>{let t=Array.from(e,e=>String.fromCodePoint(e)).join(``);return btoa(t)},v=e=>e.match(/.{1,2}/g)?.map(e=>parseInt(e,16))??[],y=e=>{e.readUint8(),e.readUint8(),e.readUint8(),e.readUint8();let t=g(e.readBytes(16));return{defaultKID:t}},b=e=>{let t=`edef8ba979d64acea3c827dcd51d21ed`,n=e.version??0;if(n!==0&&n!==1)throw Error(`PSSH version can only be 0 or 1`);let r=e.reader.readBytes(16),i=g(r),a=[i.slice(0,8),i.slice(8,12),i.slice(12,16),i.slice(16,20),i.slice(20)].join(`-`),o=e.reader.getDataView(),s=new Uint8Array(o.buffer,o.byteOffset-12,e.size),c=_(s),l=[];if(n>=1){let t=e.reader.readUint32();for(let n=0;n<t;n++)l.push(g(e.reader.readBytes(16)))}let u=e.reader.readUint32(),d=e.reader.readBytes(u),f=i===t;return{version:n,systemId:a,pssh:c,keyIds:l,systemData:d}},x=e=>{try{let t=!1,n=!1;return new o().box(`moov`,()=>{t=!0}).box(`moof`,()=>{n=!0}).parse(e,!0,!0),t&&!n}catch(e){return console.log(e),!1}},S=e=>{let t=null;return new o().box(`moov`,o.children).box(`trak`,o.children).box(`mdia`,o.children).box(`minf`,o.children).box(`stbl`,o.children).fullBox(`stsd`,o.sampleDescription).box(`encv`,o.visualSampleEntry).box(`enca`,o.audioSampleEntry).box(`sinf`,o.children).box(`frma`,e=>{let n=e.reader.readBytes(4);t=new TextDecoder().decode(n)}).parse(e,!0,!0),t},C=async e=>{let t=S(e);if(d(e,`sinf`,`skip`),d(e,`pssh`,`skip`),t)d(e,`encv`,t),d(e,`enca`,t);else{console.warn(`Could not detect original codec, using fallback values`);let t=f(e,`encv`)?`video`:`audio`;t===`video`?d(e,`encv`,`avc1`):d(e,`enca`,`mp4a`)}return e},w=e=>{let t={schemeType:``,defaultKID:``,psshList:[]};return new o().box(`moov`,o.children).box(`trak`,o.children).box(`mdia`,o.children).box(`minf`,o.children).box(`stbl`,o.children).fullBox(`stsd`,o.sampleDescription).fullBox(`pssh`,e=>t.psshList.push(b(e))).box(`encv`,o.visualSampleEntry).box(`enca`,o.audioSampleEntry).box(`sinf`,o.children).box(`schi`,o.children).fullBox(`schm`,e=>{t.schemeType=new TextDecoder().decode(e.reader.readBytes(4))}).fullBox(`tenc`,e=>{let{defaultKID:n}=y(e.reader);t.defaultKID=n}).parse(e,!1,!0),t},T=async(e,t)=>{let n=x(e);if(n)return C(e);let r,i,a,u;if(new o().box(`moof`,o.children).box(`traf`,o.children).fullBox(`tfhd`,e=>{a=l(e.reader,e.flags)}).fullBox(`trun`,e=>{i=c(e.reader,e.flags,e.version)}).fullBox(`senc`,e=>{r=s(e.reader,e.flags)}).parse(e,!0,!0),u=i.dataOffset,r.samples.length!==i.samples.length)throw Error(`sample count mismatch: trun has ${i.samples.length}, senc has ${r.samples.length}`);let d=0,f=0;for(let n=0;n<r.samples.length;n++){let o=r.samples[n],s=i.samples[n],c=i.samples[n].size||a.defaultSampleSize||0;o.subsamples.length||o.subsamples.push({bytesOfClearData:0,bytesOfEncryptedData:c});let l=o.subsamples.some(e=>e.bytesOfEncryptedData>0);if(l){let n=0,r=[];for(let t of o.subsamples){if(n+=t.bytesOfClearData,t.bytesOfEncryptedData>0){let i=e.subarray(u+d+n,u+d+n+t.bytesOfEncryptedData);r.push(i)}n+=t.bytesOfEncryptedData}let i=p(r),a={iv:o.iv,data:i,timestamp:f},s=await t(a);if(s){n=0;let t=0,r=[];for(let i of o.subsamples){if(i.bytesOfClearData>0){let t=e.subarray(u+d+n,u+d+n+i.bytesOfClearData);r.push(t),n+=i.bytesOfClearData}if(i.bytesOfEncryptedData>0){let e=s.subarray(t,t+i.bytesOfEncryptedData);r.push(e),t+=i.bytesOfEncryptedData,n+=i.bytesOfEncryptedData}}let i=p(r);m(i,e,u+d)}}d+=c,f+=s.duration||a.defaultSampleDuration||0}return new o().box(`moof`,o.children).box(`traf`,o.children).box(`senc`,t=>{let n=`skip`,r=t.start+n.length;h(e,n,r)}).parse(e,!0,!0),e},E=e=>{let t=null;new o().box(`moov`,e=>{t=e.start+e.size}).parse(e,!0,!0);let n=t?e.subarray(0,t):null;return{moovEnd:t,init:n}},D=e=>{let t=null,n=null;new o().box(`moof`,e=>{t===null&&(t=e.start)}).box(`mdat`,e=>{n===null&&(n=e.start+e.size)}).parse(e,!0,!0);let r=t!==null&&n!==null,i=r?e.subarray(t,n):null;return{segment:i,moofStart:t,mdatEnd:n}};var O=class{buffer=new Uint8Array;isProcessingInit=!0;scheme=null;processedBytes=0;constructor(e){this.options=e}async transform(e,t){try{this.buffer=p([this.buffer,e]);let n=!0;for(;n;){if(this.isProcessingInit){let{init:e,moovEnd:n}=E(this.buffer);if(!n||this.buffer.length<n)break;if(e&&x(e)){let r=w(e);this.scheme=r.schemeType;let i=await C(e);t.enqueue(i),this.updateProgress(i.byteLength),this.buffer=this.buffer.subarray(n),this.isProcessingInit=!1;continue}}let{moofStart:e,mdatEnd:r,segment:i}=D(this.buffer);if(e===null||r===null||!i||this.buffer.length<r)break;let a=e=>(e.encryptionScheme=this.scheme,this.options.transformSample(e)),o=await T(i,a);t.enqueue(o),this.updateProgress(o.byteLength),this.buffer=this.buffer.subarray(r),n=this.buffer.length>=8}}catch(e){t.error(e)}}async flush(e){this.buffer.length>0&&(e.enqueue(this.buffer),this.updateProgress(this.buffer.byteLength))}updateProgress(e){this.processedBytes+=e,this.options.onProgress&&this.options.onProgress(this.processedBytes)}};const k=async(e,t,{transformSample:n,onProgress:r,preventClose:i})=>{let a=new O({transformSample:n,onProgress:r}),o=new TransformStream({transform:(e,t)=>a.transform(e,t),flush:e=>a.flush(e)});await e.pipeThrough(o).pipeTo(t,{preventClose:i})},A=async(t,n)=>{let r=n.encryptionScheme,i=n.iv,a=n.data;return e(r===`cbcs`?{key:t,iv:i,data:a,algorithm:`AES-CBC`}:{key:t,iv:i,data:a,algorithm:`AES-CTR`})},j=async(e,t)=>{let n=`key`in t,r=new Uint8Array(v(n?t.key:``)),i=async e=>A(r,{encryptionScheme:`encryptionScheme`in t?t.encryptionScheme:void 0,...e}),a=n?i:t.transformSample;return T(e,a)},M=async(e,t,{preventClose:n,onProgress:r,...i})=>{let a=`key`in i,o=new Uint8Array(v(a?i.key:``)),s=async e=>A(o,e),c=a?s:i.transformSample;await k(e,t,{preventClose:n,onProgress:r,transformSample:c})};export{j as decryptSegment,M as decryptStream,A as decryptWithKey};
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "shifro",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "A lightweight, dependency-free MP4 decrypter",
5
5
  "files": [
6
6
  "dist"
7
7
  ],
8
8
  "scripts": {
9
- "dev": "vite",
9
+ "start": "node ./dist/cli.cjs",
10
+ "web": "vite",
10
11
  "build": "npm run build:lib && npm run build:cli",
11
12
  "build:cli": "tsdown ./lib/node/cli.ts --format cjs --dts --minify --no-clean",
12
13
  "build:lib": "tsdown shifro.ts --format cjs --format esm --dts --minify",