🚧 Improve .solidpkg reader

This commit is contained in:
C-3PO 2018-06-21 23:05:07 +02:00
parent a382fe6e0f
commit 5b3a6c0dd7
Signed by: c3po
GPG key ID: 62993C4BB4D86F24
3 changed files with 63 additions and 7 deletions

View file

@ -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
View 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;
}

View file

@ -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 };
} }