Skip to content

Commit

Permalink
feat: use webcrypto
Browse files Browse the repository at this point in the history
  • Loading branch information
andipaetzold committed Dec 2, 2023
1 parent 33cdfbe commit b2d3580
Show file tree
Hide file tree
Showing 38 changed files with 576 additions and 774 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ yarn add mdb-reader

To decrypt databases, this library requires a few dependencies:

- [`browserify-aes`](https://www.npmjs.com/browserify-aes): Only imported when running in browser
- [`create-hash`](https://www.npmjs.com/create-hash): Only imported when running in browser
- [`fast-xml-parser`](https://www.npmjs.com/fast-xml-parser)

## Usage
Expand Down
1 change: 0 additions & 1 deletion global.d.ts

This file was deleted.

330 changes: 53 additions & 277 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@
},
"homepage": "https://github.com/andipaetzold/mdb-reader#readme",
"dependencies": {
"browserify-aes": "^1.0.0",
"create-hash": "^1.0.0",
"fast-xml-parser": "^4.0.0"
},
"devDependencies": {
Expand All @@ -49,12 +47,14 @@
"@tsconfig/node18": "18.2.2",
"@tsconfig/strictest": "2.0.2",
"@types/chai": "4.3.11",
"@types/chai-as-promised": "7.1.6",
"@types/mocha": "10.0.6",
"@types/mocha-each": "2.0.4",
"@types/node": "18.18.13",
"@typescript-eslint/eslint-plugin": "6.13.1",
"@typescript-eslint/parser": "6.13.1",
"chai": "4.3.10",
"chai-as-promised": "7.1.1",
"eslint": "8.54.0",
"mocha": "10.2.0",
"mocha-each": "2.0.1",
Expand Down
14 changes: 7 additions & 7 deletions src/Database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ export class Database {
decryptHeader(this.#databaseDefinitionPage, this.#format);
this.#codecHandler = createCodecHandler(this.#databaseDefinitionPage, password);

if (!this.#codecHandler.verifyPassword()) {
throw new Error("Wrong password");
}
// if (!this.#codecHandler.verifyPassword()) {
// throw new Error("Wrong password");
// }
}

get format(): JetFormat {
Expand Down Expand Up @@ -105,7 +105,7 @@ export class Database {
return Object.freeze({ value, version });
}

getPage(page: number): Buffer {
async getPage(page: number): Promise<Buffer> {
if (page === 0) {
// already decrypted
return this.#databaseDefinitionPage;
Expand All @@ -117,19 +117,19 @@ export class Database {
}

const pageBuffer = this.#buffer.slice(offset, offset + this.#format.pageSize);
return this.#codecHandler.decryptPage(pageBuffer, page);
return await this.#codecHandler.decryptPage(pageBuffer, page);
}

/**
* @param pageRow Lower byte contains the row number, the upper three contain page
*
* @see https://github.com/brianb/mdbtools/blob/d6f5745d949f37db969d5f424e69b54f0da60b9b/src/libmdb/data.c#L102-L124
*/
findPageRow(pageRow: number): Buffer {
async findPageRow(pageRow: number): Promise<Buffer> {
const page = pageRow >> 8;
const row = pageRow & 0xff;

const pageBuffer = this.getPage(page);
const pageBuffer = await this.getPage(page);
return this.findRow(pageBuffer, row);
}

Expand Down
64 changes: 34 additions & 30 deletions src/MDBReader.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Database } from "./Database.js";
import { PageType, assertPageType } from "./PageType.js";
import { createTable } from "./Table.js";
import { memoPromise } from "./util.js";
import { type SysObject, isSysObjectType, isSystemObject, SysObjectTypes } from "./SysObject.js";
import { Table } from "./Table.js";
import type { SortOrder } from "./types.js";
import type { SortOrder, Table } from "./types.js";

const MSYS_OBJECTS_TABLE = "MSysObjects";
const MSYS_OBJECTS_PAGE = 2;
Expand All @@ -13,7 +14,6 @@ export interface Options {

export default class MDBReader {
#buffer: Buffer;
#sysObjects: SysObject[];
#database: Database;

/**
Expand All @@ -25,27 +25,10 @@ export default class MDBReader {
assertPageType(this.#buffer, PageType.DatabaseDefinitionPage);

this.#database = new Database(this.#buffer, password ?? "");

const mSysObjectsTable = new Table(MSYS_OBJECTS_TABLE, this.#database, MSYS_OBJECTS_PAGE).getData<{
Id: number;
Name: string;
Type: number;
Flags: number;
}>({
columns: ["Id", "Name", "Type", "Flags"],
});

this.#sysObjects = mSysObjectsTable.map((mSysObject) => {
const objectType = mSysObject.Type & 0x7f;
return {
objectName: mSysObject.Name,
objectType: isSysObjectType(objectType) ? objectType : null,
tablePage: mSysObject.Id & 0x00ffffff,
flags: mSysObject.Flags,
};
});
}

#getSysObjects = memoPromise(() => getSysObjects(this.#database));

/**
* Date when the database was created
*/
Expand Down Expand Up @@ -74,17 +57,17 @@ export default class MDBReader {
* @param systemTables Includes system tables. Default false.
* @param linkedTables Includes linked tables. Default false.
*/
getTableNames({
async getTableNames({
normalTables = true,
systemTables = false,
linkedTables = false,
}: {
normalTables?: boolean | undefined;
systemTables?: boolean | undefined;
linkedTables?: boolean | undefined;
} = {}): string[] {
} = {}): Promise<string[]> {
const filteredSysObjects: SysObject[] = [];
for (const sysObject of this.#sysObjects) {
for (const sysObject of await this.#getSysObjects()) {
if (sysObject.objectType === SysObjectTypes.Table) {
if (!isSystemObject(sysObject)) {
if (normalTables) {
Expand All @@ -106,15 +89,36 @@ export default class MDBReader {
*
* @param name Name of the table. Case sensitive.
*/
getTable(name: string): Table {
const sysObject = this.#sysObjects
.filter((o) => o.objectType === SysObjectTypes.Table)
.find((o) => o.objectName === name);
async getTable(name: string): Promise<Table> {
const sysObjects = await this.#getSysObjects();
const sysObject = sysObjects.filter((o) => o.objectType === SysObjectTypes.Table).find((o) => o.objectName === name);

if (!sysObject) {
throw new Error(`Could not find table with name ${name}`);
}

return new Table(name, this.#database, sysObject.tablePage);
return await createTable(name, this.#database, sysObject.tablePage);
}
}

async function getSysObjects(database: Database): Promise<SysObject[]> {
const table = await createTable(MSYS_OBJECTS_TABLE, database, MSYS_OBJECTS_PAGE);
const tableData = await table.getData<{
Id: number;
Name: string;
Type: number;
Flags: number;
}>({
columns: ["Id", "Name", "Type", "Flags"],
});

return tableData.map((mSysObject) => {
const objectType = mSysObject.Type & 0x7f;
return {
objectName: mSysObject.Name,
objectType: isSysObjectType(objectType) ? objectType : null,
tablePage: mSysObject.Id & 0x00ffffff,
flags: mSysObject.Flags,
};
});
}
Loading

0 comments on commit b2d3580

Please sign in to comment.