mirror of
https://github.com/PretendoNetwork/BOSS.git
synced 2026-03-21 17:34:19 -05:00
feat: Add support for importing encrypted files
This commit is contained in:
parent
ce4eec54bc
commit
dc471eefa9
|
|
@ -10,6 +10,7 @@ npm run cli -- import seed
|
|||
|
||||
1. Only files referenced by tasksheets are processed
|
||||
2. You can safely run seeding as many times as seeded, it ignores unchanged data.
|
||||
3. Files must be prefixed with their Data ID - followed by a `.`. For example: `39015.Festival.byaml` (Everything after the first dot is not enforced, name it appropiately)
|
||||
4. Tasksheets must follow this syntax: `1.<BOSS_APP_ID>.<TASKNAME>.taskheet.xml`
|
||||
5. Seeding only adds and updates data. Tasksheets or files that are removed are not deleted.
|
||||
3. Unencrypted task files must follow this syntax: `<DATA_ID>.<FILENAME>` - For example: `39015.Festival.byaml` (The name unused, but good practice to set it appropiately)
|
||||
4. Encrypted task files must follow this syntax: `<DATA_ID>.enc.<FILENAME>` - For example: `39015.enc.Festival.byaml` (The name unused, but good practice to set it appropiately)
|
||||
5. Tasksheets must follow this syntax: `1.<BOSS_APP_ID>.<TASKNAME>.taskheet.xml`
|
||||
6. Seeding only adds and updates data. Tasksheets or files that are removed are not deleted.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import path from 'path';
|
|||
import fs from 'fs/promises';
|
||||
import { Command } from 'commander';
|
||||
import { xml2js } from 'xml-js';
|
||||
import BOSS from 'boss-js';
|
||||
import { getCliContext } from './utils';
|
||||
import { seedFolder } from './root';
|
||||
import type { CliContext } from './utils';
|
||||
|
|
@ -21,7 +22,14 @@ export async function uploadFileIfChanged(ops: UploadFileOptions): Promise<void>
|
|||
console.warn(`${ops.dataId}: Could not find file on disk the specified data ID - skipping`);
|
||||
return;
|
||||
}
|
||||
const fileContents = await fs.readFile(path.join(seedFolder, 'files', newTaskFileName));
|
||||
let fileContents = await fs.readFile(path.join(seedFolder, 'files', newTaskFileName));
|
||||
if (newTaskFileName.startsWith(`${ops.dataId}.enc.`)) {
|
||||
// File is encrypted, let's decrypt before processing
|
||||
console.log(`${ops.dataId}: File is encrypted, decrypting...`);
|
||||
const keys = ops.ctx.getWiiuKeys();
|
||||
const decryptedContents = BOSS.decryptWiiU(fileContents, keys.aesKey, keys.hmacKey);
|
||||
fileContents = decryptedContents.content;
|
||||
}
|
||||
|
||||
const allExistingTaskFiles = await ops.ctx.grpc.listFiles({
|
||||
bossAppId: ops.bossAppId,
|
||||
|
|
|
|||
|
|
@ -2,8 +2,11 @@ import { BOSSDefinition } from '@pretendonetwork/grpc/boss/boss_service';
|
|||
import { createChannel, createClient, Metadata } from 'nice-grpc';
|
||||
import type { BOSSClient } from '@pretendonetwork/grpc/boss/boss_service';
|
||||
|
||||
export type WiiuKeys = { aesKey: string; hmacKey: string };
|
||||
|
||||
export type CliContext = {
|
||||
grpc: BOSSClient;
|
||||
getWiiuKeys: () => WiiuKeys;
|
||||
};
|
||||
|
||||
export function getCliContext(): CliContext {
|
||||
|
|
@ -27,7 +30,22 @@ export function getCliContext(): CliContext {
|
|||
});
|
||||
|
||||
return {
|
||||
grpc: client
|
||||
grpc: client,
|
||||
getWiiuKeys(): WiiuKeys {
|
||||
const aesKey = process.env.PN_BOSS_CLI_WIIU_AES_KEY ?? '';
|
||||
const hmacKey = process.env.PN_BOSS_CLI_WIIU_HMAC_KEY ?? '';
|
||||
|
||||
if (!aesKey) {
|
||||
throw new Error('Missing env variable PN_BOSS_CLI_WIIU_AES_KEY - needed for decryption');
|
||||
}
|
||||
if (!hmacKey) {
|
||||
throw new Error('Missing env variable PN_BOSS_CLI_WIIU_HMAC_KEY - needed for decryption');
|
||||
}
|
||||
return {
|
||||
aesKey,
|
||||
hmacKey
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
42
src/types/boss-js.d.ts
vendored
Normal file
42
src/types/boss-js.d.ts
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
declare module 'boss-js' {
|
||||
export type EncryptionInput = Buffer | string;
|
||||
export type EncryptionKey = Buffer | string;
|
||||
|
||||
export type DecryptionResultWiiu = {
|
||||
hash_type: number;
|
||||
iv: Buffer<ArrayBuffer>;
|
||||
hmac: Buffer<ArrayBuffer>;
|
||||
content: Buffer<ArrayBuffer>;
|
||||
};
|
||||
|
||||
export type DecryptionResult3ds = {
|
||||
hash_type: number;
|
||||
release_date: bigint;
|
||||
iv: Buffer<ArrayBuffer>;
|
||||
content_header_hash: Buffer<ArrayBuffer>;
|
||||
content_header_hash_signature: Buffer<ArrayBuffer>;
|
||||
payload_content_header_hash: Buffer<ArrayBuffer>;
|
||||
payload_content_header_hash_signature: Buffer<ArrayBuffer>;
|
||||
program_id: Buffer<ArrayBuffer>;
|
||||
content_datatype: number;
|
||||
ns_data_id: number;
|
||||
content: Buffer<ArrayBuffer>;
|
||||
};
|
||||
|
||||
export type EncryptionOptions3ds = {
|
||||
program_id?: string;
|
||||
title_id?: number;
|
||||
content_datatype: number;
|
||||
ns_data_id: number;
|
||||
};
|
||||
|
||||
export function encrypt(input: EncryptionInput, version: number, aesKey: string, options: EncryptionOptions3ds): Buffer<ArrayBuffer>;
|
||||
export function encrypt(input: EncryptionInput, version: number, aesKey: string, hmacKey: string): Buffer<ArrayBuffer>;
|
||||
export function decrypt(input: EncryptionInput, aesKey: EncryptionKey, hmacKey?: string): DecryptionResultWiiu | DecryptionResult3ds;
|
||||
|
||||
export function encryptWiiU(input: EncryptionInput, aesKey: string, hmacKey: string): Buffer<ArrayBuffer>;
|
||||
export function decryptWiiU(input: EncryptionInput, aesKey: string, hmacKey: string): DecryptionResultWiiu;
|
||||
|
||||
export function encrypt3DS(input: EncryptionInput, aesKey: EncryptionKey, options: EncryptionOptions3ds): Buffer<ArrayBuffer>;
|
||||
export function decrypt3DS(input: EncryptionInput, aesKey: EncryptionKey): DecryptionResult3ds;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user