Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat]: handle non-existing directories as empty if they have a meta file #2999

Merged
merged 6 commits into from
Jan 9, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 33 additions & 4 deletions packages/controller/test/lib/testFiles.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { TestContext } from '../_Types.js';
import { objectsUtils as utils } from '@iobroker/db-objects-redis';

export function register(it: Mocha.TestFunction, expect: Chai.ExpectStatic, context: TestContext): void {
const testName = `${context.name} ${context.adapterShortName} files: `;
@@ -10,7 +9,7 @@ export function register(it: Mocha.TestFunction, expect: Chai.ExpectStatic, cont
const fileName = 'testFile.bin';
const dataBinary = Buffer.from('1234');
// create an object of type file first
await context.adapter.setForeignObjectAsync(objId, {
await context.adapter.setForeignObject(objId, {
type: 'meta',
common: {
name: 'Files and more',
@@ -224,12 +223,42 @@ export function register(it: Mocha.TestFunction, expect: Chai.ExpectStatic, cont
});
});

it(`${testName}should respond with 'ERROR_NOT_FOUND' if calling readDir on a single file`, async () => {
it(`${testName}should read empty directory`, async () => {
const objects = context.objects;
const id = `${testId}.meta.files`;

await objects.setObject(id, {
type: 'meta',
common: { name: 'test', type: 'meta.user' },
native: {},
});

const res = await objects.readDirAsync(id, '');
expect(res).to.be.empty;
});

it(`${testName}should read empty directory with path`, async () => {
const objects = context.objects;
const id = `${testId}.meta.files`;

const res = await objects.readDirAsync(id, 'random/path');
expect(res).to.be.empty;
});

it(`${testName}should not read directory without meta object`, () => {
const objects = context.objects;
const id = `${testId}.meta.nonExisting`;

expect(objects.readDirAsync(id, '')).to.be.eventually.rejectedWith(`${id} is not an object of type "meta"`);
});

it(`${testName}should respond with empty array if calling readDir on a single file`, async () => {
const objects = context.objects;
const fileName = 'dir/notADir.txt';

await objects.writeFileAsync(testId, fileName, 'dataInFile');
expect(objects.readDirAsync(testId, fileName)).to.be.eventually.rejectedWith(utils.ERRORS.ERROR_NOT_FOUND);
const res = await objects.readDirAsync(testId, fileName);
expect(res).to.be.empty;
});

it(`${testName}should read file and prevent path traversing`, done => {
16 changes: 11 additions & 5 deletions packages/db-objects-redis/src/lib/objects/objectsInRedisClient.ts
Original file line number Diff line number Diff line change
@@ -847,15 +847,15 @@ export class ObjectsInRedisClient {
async validateMetaObject(id: string): Promise<void> {
if (this.existingMetaObjects[id] === undefined) {
// if not cached -> getObject
const obj = await this.getObjectAsync(id);
const obj = await this.getObject(id);
if (obj && obj.type === 'meta') {
this.existingMetaObjects[id] = true;
} else {
this.existingMetaObjects[id] = false;
return Promise.reject(new Error(`${id} is not an object of type "meta"`));
throw new Error(`${id} is not an object of type "meta"`);
}
} else if (this.existingMetaObjects[id] === false) {
return Promise.reject(new Error(`${id} is not an object of type "meta"`));
throw new Error(`${id} is not an object of type "meta"`);
}
}

@@ -990,7 +990,7 @@ export class ObjectsInRedisClient {
const obj = await this.getObject(id);
if (obj && !obj.acl) {
obj.acl = defaultAcl;
await this.setObjectAsync(id, obj, null);
await this.setObject(id, obj, null);
}
} catch (e) {
this.log.error(
@@ -1442,6 +1442,12 @@ export class ObjectsInRedisClient {
return tools.maybeCallbackWithError(callback, null, result);
}

try {
await this.validateMetaObject(id);
} catch (e) {
return tools.maybeCallbackWithRedisError(callback, e);
}

const dirID = this.getFileId(id, `${name}${name.length ? '/' : ''}*`);

let keys;
@@ -1462,7 +1468,7 @@ export class ObjectsInRedisClient {
const dirs: string[] = [];
const deepLevel = baseName.split('/').length;
if (!keys || !keys.length) {
return tools.maybeCallbackWithError(callback, ERRORS.ERROR_NOT_FOUND, []);
return tools.maybeCallbackWithError(callback, null, []);
}
keys = keys.sort().filter(key => {
if (key.endsWith('$%$meta')) {

Unchanged files with check annotations Beta

export interface AdapterOptions {

Check warning on line 1 in packages/adapter/src/lib/_Types.ts

GitHub Actions / Eslint

Missing JSDoc comment
subscribesChange?: (

Check warning on line 2 in packages/adapter/src/lib/_Types.ts

GitHub Actions / Eslint

Missing JSDoc comment
subs: Record<
string,
{
regex: RegExp;

Check warning on line 6 in packages/adapter/src/lib/_Types.ts

GitHub Actions / Eslint

Missing JSDoc comment
}
>,
) => void;
type Invoice = 'free' | (string & {});
export interface SuitableLicense {

Check warning on line 73 in packages/adapter/src/lib/_Types.ts

GitHub Actions / Eslint

Missing JSDoc comment
/** Name of the license type, not necessarily matching adapter */
product: string;
/** E-Mail of license owner */
decoded: {
/** E-Mail of license owner */
email: string;
comment: string;

Check warning on line 98 in packages/adapter/src/lib/_Types.ts

GitHub Actions / Eslint

Missing JSDoc comment
/** License type, eg private */
type: string;
/** Adapter name */
name: string;
/** Address of license owner */
address: {
Country: string;

Check warning on line 105 in packages/adapter/src/lib/_Types.ts

GitHub Actions / Eslint

Missing JSDoc comment
Name: string;

Check warning on line 106 in packages/adapter/src/lib/_Types.ts

GitHub Actions / Eslint

Missing JSDoc comment
AddressLine1: string;

Check warning on line 107 in packages/adapter/src/lib/_Types.ts

GitHub Actions / Eslint

Missing JSDoc comment
AddressLine2: string;

Check warning on line 108 in packages/adapter/src/lib/_Types.ts

GitHub Actions / Eslint

Missing JSDoc comment
ZIP: string;

Check warning on line 109 in packages/adapter/src/lib/_Types.ts

GitHub Actions / Eslint

Missing JSDoc comment
City: string;
};
ltype: string;