1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-30 10:36:35 +02:00

Server: Check share ID when uploading a note

This commit is contained in:
Laurent Cozic 2021-06-07 16:17:52 +02:00
parent 5528ab7cc8
commit 3c41b45e8e
3 changed files with 19 additions and 5 deletions

View File

@ -1,15 +1,13 @@
import time from '../../time';
import shim from '../../shim';
import Setting from '../../models/Setting';
const { synchronizerStart, allSyncTargetItemsEncrypted, kvStore, supportDir, setupDatabaseAndSynchronizer, synchronizer, fileApi, switchClient, encryptionService, loadEncryptionMasterKey, decryptionWorker, checkThrowAsync } = require('../../testing/test-utils.js');
import { createFolderTree, syncTargetName, synchronizerStart, allSyncTargetItemsEncrypted, kvStore, supportDir, setupDatabaseAndSynchronizer, synchronizer, fileApi, switchClient, encryptionService, loadEncryptionMasterKey, decryptionWorker, checkThrowAsync } from '../../testing/test-utils';
import Folder from '../../models/Folder';
import Note from '../../models/Note';
import Resource from '../../models/Resource';
import ResourceFetcher from '../../services/ResourceFetcher';
import MasterKey from '../../models/MasterKey';
import BaseItem from '../../models/BaseItem';
import { createFolderTree } from '../../testing/test-utils';
let insideBeforeEach = false;
@ -415,6 +413,13 @@ describe('Synchronizer.e2ee', function() {
}));
it('should not encrypt items that are shared by folder', (async () => {
// We skip this test for Joplin Server because it's going to check if
// the share_id refers to an existing share.
if (syncTargetName() === 'joplinServer') {
expect(true).toBe(true);
return;
}
Setting.setValue('encryption.enabled', true);
await loadEncryptionMasterKey();

View File

@ -278,6 +278,11 @@ export default abstract class BaseModel<T> {
return this.db(this.tableName).select(options.fields || this.defaultFields).whereIn('id', ids);
}
public async exists(id: string): Promise<boolean> {
const o = await this.load(id, { fields: ['id'] });
return !!o;
}
public async load(id: string, options: LoadOptions = {}): Promise<T> {
if (!id) throw new Error('id cannot be empty');

View File

@ -3,7 +3,7 @@ import { ItemType, databaseSchema, Uuid, Item, ShareType, Share, ChangeType, Use
import { defaultPagination, paginateDbQuery, PaginatedResults, Pagination } from './utils/pagination';
import { isJoplinItemName, isJoplinResourceBlobPath, linkedResourceIds, serializeJoplinItem, unserializeJoplinItem } from '../utils/joplinUtils';
import { ModelType } from '@joplin/lib/BaseModel';
import { ApiError, ErrorForbidden, ErrorNotFound, ErrorUnprocessableEntity } from '../utils/errors';
import { ApiError, ErrorForbidden, ErrorUnprocessableEntity } from '../utils/errors';
import { Knex } from 'knex';
import { ChangePreviousItem } from './ChangeModel';
@ -345,6 +345,10 @@ export default class ItemModel extends BaseModel<Item> {
if ('name' in item && !item.name) throw new ErrorUnprocessableEntity('name cannot be empty');
}
if (item.jop_share_id) {
if (!(await this.models().share().exists(item.jop_share_id))) throw new ErrorUnprocessableEntity(`share not found: ${item.jop_share_id}`);
}
return super.validate(item, options);
}
@ -499,7 +503,7 @@ export default class ItemModel extends BaseModel<Item> {
public async deleteForUser(userId: Uuid, item: Item): Promise<void> {
if (this.isRootSharedFolder(item)) {
const share = await this.models().share().byItemId(item.id);
if (!share) throw new ErrorNotFound(`Cannot find share associated with item ${item.id}`);
if (!share) throw new Error(`Cannot find share associated with item ${item.id}`);
const userShare = await this.models().shareUser().byShareAndUserId(share.id, userId);
if (!userShare) return;
await this.models().shareUser().delete(userShare.id);