🚧 Improve .solidpkg reader
This commit is contained in:
parent
a382fe6e0f
commit
5b3a6c0dd7
3 changed files with 63 additions and 7 deletions
|
@ -1,6 +1,6 @@
|
||||||
import getUrlContents from './getUrlContents';
|
import getUrlContents from '../getUrlContents';
|
||||||
import { Product } from './interfaces/ISettings';
|
import { Product } from '../interfaces/ISettings';
|
||||||
import verifyProductName from './verifyProductName';
|
import verifyProductName from '../verifyProductName';
|
||||||
|
|
||||||
export default function getSolidpkg(product: Product, from: number, to: number): Promise<Buffer> {
|
export default function getSolidpkg(product: Product, from: number, to: number): Promise<Buffer> {
|
||||||
//Verify function arguments
|
//Verify function arguments
|
23
src/ssn/modifyPassword.ts
Normal file
23
src/ssn/modifyPassword.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/** Takes a password as it is included in the extra field, and returns a password that can be used to decode the file. */
|
||||||
|
export default function modifyPassword(passwordIn: Uint8Array) {
|
||||||
|
const passwordLength = passwordIn.byteLength;
|
||||||
|
const passwordOut = new Uint8Array(passwordLength);
|
||||||
|
|
||||||
|
for (let i = 0; i < passwordLength; i += 1) {
|
||||||
|
if (passwordIn[i] === 0) { break; }
|
||||||
|
let curChar = passwordIn[i] + (1 << (i % 32));
|
||||||
|
if (curChar > 0x7E) {
|
||||||
|
if (curChar === 0xFF || curChar === 0x7F) {
|
||||||
|
curChar = 0x3F;
|
||||||
|
} else {
|
||||||
|
curChar = curChar & 0x7F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (curChar < 0x21) {
|
||||||
|
curChar = (curChar | (1 << ((curChar % 3) + 5))) + 1;
|
||||||
|
}
|
||||||
|
passwordOut[i] = curChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
return passwordOut;
|
||||||
|
}
|
|
@ -1,9 +1,15 @@
|
||||||
|
import { TextDecoder } from 'util';
|
||||||
|
import modifyPassword from './modifyPassword';
|
||||||
|
|
||||||
const MAGIC_END_OF_CENTRAL_DIR = 0x06054b50;
|
const MAGIC_END_OF_CENTRAL_DIR = 0x06054b50;
|
||||||
const MAGIC_CENTRAL_DIR = 0x02014b50;
|
const MAGIC_CENTRAL_DIR = 0x02014b50;
|
||||||
const COMPRESSION_DEFLATE = 8;
|
const COMPRESSION_DEFLATE = 8;
|
||||||
|
|
||||||
|
const Decoder = new TextDecoder('utf-8');
|
||||||
|
|
||||||
export default function readSolidpkg(buffer: Buffer) {
|
export default function readSolidpkg(buffer: Buffer) {
|
||||||
const dv = new DataView(buffer.buffer);
|
const arrayBuffer = buffer.buffer;
|
||||||
|
const dv = new DataView(arrayBuffer);
|
||||||
|
|
||||||
//--------------- READ END OF CENTRAL DIR ---------------
|
//--------------- READ END OF CENTRAL DIR ---------------
|
||||||
|
|
||||||
|
@ -75,10 +81,37 @@ export default function readSolidpkg(buffer: Buffer) {
|
||||||
const fileCommentLength = dv.getUint16(pos, true); pos += 2;
|
const fileCommentLength = dv.getUint16(pos, true); pos += 2;
|
||||||
pos += 8; //skip disk num start and file attributes
|
pos += 8; //skip disk num start and file attributes
|
||||||
const relOffset = dv.getUint32(pos, true); pos += 4;
|
const relOffset = dv.getUint32(pos, true); pos += 4;
|
||||||
pos += fileNameLength; //skip file name
|
const fileName = Decoder.decode(new DataView(arrayBuffer, pos, fileNameLength)); pos += fileNameLength; //skip file name
|
||||||
//TODO: read password from extra field
|
|
||||||
|
|
||||||
|
//read password from extra field
|
||||||
|
let encodedPassword: Uint8Array | undefined;
|
||||||
|
while (pos + 4 <= extraFieldLength) {
|
||||||
|
const fieldId = dv.getUint16(pos, true); pos += 2;
|
||||||
|
const fieldLength = dv.getUint16(pos, true); pos += 2;
|
||||||
|
switch (fieldId) {
|
||||||
|
case 0x8810: { //password
|
||||||
|
if (fieldLength > 120) {
|
||||||
|
throw new Error(`Password is too long, it should be 120 characters at most but is ${fieldLength} characters long.`);
|
||||||
|
}
|
||||||
|
const passwordLength = fieldLength;
|
||||||
|
encodedPassword = new Uint8Array(arrayBuffer, pos, fieldLength);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x80AE: //unknown, some kind of hash or checksum, ignore it
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//unknown field, ignore it
|
||||||
|
}
|
||||||
|
pos += fieldLength;
|
||||||
|
}
|
||||||
|
if (typeof encodedPassword === 'undefined') {
|
||||||
|
throw new Error('Could not find password in extra field.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const decodedPassword = modifyPassword(encodedPassword);
|
||||||
|
|
||||||
|
//TODO: read encrypted + compressed file
|
||||||
//...
|
//...
|
||||||
|
|
||||||
return { lastMod1, lastMod2, fileCrc, comprSize, uncomprSize, fileNameLength, extraFieldLength, fileCommentLength, relOffset };
|
return { lastMod1, lastMod2, fileCrc, comprSize, uncomprSize, fileNameLength, extraFieldLength, fileCommentLength, relOffset, fileName, encodedPassword, decodedPassword };
|
||||||
}
|
}
|
Loading…
Reference in a new issue