Skip to content

Commit

Permalink
Chore: Server: Added test tools to automatically populate the database (
Browse files Browse the repository at this point in the history
  • Loading branch information
laurent22 authored Oct 19, 2023
1 parent 7b42211 commit 4d1e0cc
Show file tree
Hide file tree
Showing 15 changed files with 2,476 additions and 33 deletions.
12 changes: 6 additions & 6 deletions packages/app-mobile/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ PODS:
- React-Core
- react-native-get-random-values (1.9.0):
- React-Core
- react-native-image-picker (5.6.1):
- react-native-image-picker (5.7.0):
- React-Core
- react-native-image-resizer (3.0.7):
- React-Core
Expand Down Expand Up @@ -418,11 +418,11 @@ PODS:
- React-Core
- RNVectorIcons (10.0.0):
- React-Core
- RNZipArchive (6.0.9):
- RNZipArchive (6.1.0):
- React-Core
- RNZipArchive/Core (= 6.0.9)
- RNZipArchive/Core (= 6.1.0)
- SSZipArchive (~> 2.2)
- RNZipArchive/Core (6.0.9):
- RNZipArchive/Core (6.1.0):
- React-Core
- SSZipArchive (~> 2.2)
- SSZipArchive (2.4.3)
Expand Down Expand Up @@ -669,7 +669,7 @@ SPEC CHECKSUMS:
react-native-fingerprint-scanner: ac6656f18c8e45a7459302b84da41a44ad96dbbe
react-native-geolocation: 0f7fe8a4c2de477e278b0365cce27d089a8c5903
react-native-get-random-values: dee677497c6a740b71e5612e8dbd83e7539ed5bb
react-native-image-picker: 5fcac5a5ffcb3737837f0617d43fd767249290de
react-native-image-picker: 3269f75c251cdcd61ab51b911dd30d6fff8c6169
react-native-image-resizer: 681f7607418b97c084ba2d0999b153b103040d8a
react-native-netinfo: fefd4e98d75cbdd6e85fc530f7111a8afdf2b0c5
react-native-rsa-native: 12132eb627797529fdb1f0d22fd0f8f9678df64a
Expand Down Expand Up @@ -705,7 +705,7 @@ SPEC CHECKSUMS:
RNSecureRandom: 07efbdf2cd99efe13497433668e54acd7df49fef
RNShare: 32e97adc8d8c97d4a26bcdd3c45516882184f8b6
RNVectorIcons: 8b5bb0fa61d54cd2020af4f24a51841ce365c7e9
RNZipArchive: 68a0c6db4b1c103f846f1559622050df254a3ade
RNZipArchive: ef9451b849c45a29509bf44e65b788829ab07801
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
Yoga: e7ea9e590e27460d28911403b894722354d73479

Expand Down
2 changes: 2 additions & 0 deletions packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"test-ci": "yarn test",
"test-debug": "node --inspect node_modules/.bin/jest -- --verbose=false",
"clean": "gulp clean",
"populateDatabase": "JOPLIN_TESTS_SERVER_DB=pg node dist/utils/testing/populateDatabase",
"stripeListen": "stripe listen --forward-to http://joplincloud.local:22300/stripe/webhook",
"watch": "tsc --watch --preserveWatchOutput --project tsconfig.json"
},
Expand Down Expand Up @@ -60,6 +61,7 @@
"devDependencies": {
"@joplin/tools": "~2.13",
"@rmp135/sql-ts": "1.18.0",
"@types/bcryptjs": "2.4.5",
"@types/formidable": "3.4.3",
"@types/fs-extra": "11.0.2",
"@types/jest": "29.5.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/migrations/20190913171451_create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export const up = async (db: DbConnection) => {
await db('users').insert({
id: adminId,
email: defaultAdminEmail,
password: hashPassword(defaultAdminPassword),
password: await hashPassword(defaultAdminPassword),
full_name: 'Admin',
is_admin: 1,
updated_time: now,
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/models/BaseModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ export default abstract class BaseModel<T> {
// The `name` argument is only for debugging, so that any stuck transaction
// can be more easily identified.
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
protected async withTransaction<T>(fn: Function, name: string): Promise<T> {
protected async withTransaction<T>(fn: Function, name = ''): Promise<T> {
const debugSteps = false;
const debugTimeout = true;
const timeoutMs = 10000;
Expand Down
16 changes: 9 additions & 7 deletions packages/server/src/models/TaskStateModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ export default class TaskStateModel extends BaseModel<TaskState> {
}

public async init(taskId: TaskId) {
const taskState: TaskState = await this.loadByTaskId(taskId);
if (taskState) return taskState;

return this.save({
task_id: taskId,
enabled: 1,
running: 0,
return this.withTransaction(async () => {
const taskState: TaskState = await this.loadByTaskId(taskId);
if (taskState) return taskState;

return this.save({
task_id: taskId,
enabled: 1,
running: 0,
});
});
}

Expand Down
3 changes: 3 additions & 0 deletions packages/server/src/models/UserItemModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,9 @@ export default class UserItemModel extends BaseModel<UserItem> {
for (const userItem of userItems) {
const item = items.find(i => i.id === userItem.item_id);

// The item may have been deleted between the async calls above
if (!item) continue;

if (options.recordChanges && this.models().item().shouldRecordChange(item.name)) {
await this.models().change().save({
item_type: ItemType.UserItem,
Expand Down
19 changes: 13 additions & 6 deletions packages/server/src/models/UserModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export default class UserModel extends BaseModel<User> {
public async login(email: string, password: string): Promise<User> {
const user = await this.loadByEmail(email);
if (!user) return null;
if (!checkPassword(password, user.password)) return null;
if (!(await checkPassword(password, user.password))) return null;
return user;
}

Expand Down Expand Up @@ -635,16 +635,23 @@ export default class UserModel extends BaseModel<User> {
public async save(object: User, options: SaveOptions = {}): Promise<User> {
const user = this.formatValues(object);

const isNew = await this.isNew(object, options);

if (user.password) {
if (isHashedPassword(user.password)) {
throw new ErrorBadRequest(`Unable to save user because password already seems to be hashed. User id: ${user.id}`);
if (!isNew) {
throw new ErrorBadRequest(`Unable to save user because password already seems to be hashed. User id: ${user.id}`);
} else {
// OK - We allow supplying an already hashed password for
// new users. This is mostly used for testing, because
// generating a bcrypt hash for each user is slow.
}
} else {
if (!options.skipValidation) this.validatePassword(user.password);
user.password = await hashPassword(user.password);
}
if (!options.skipValidation) this.validatePassword(user.password);
user.password = hashPassword(user.password);
}

const isNew = await this.isNew(object, options);

return this.withTransaction(async () => {
const savedUser = await super.save(user, options);

Expand Down
13 changes: 11 additions & 2 deletions packages/server/src/utils/array.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
/* eslint-disable import/prefer-default-export */

export function unique(array: any[]): any[] {
return array.filter((elem, index, self) => {
return index === self.indexOf(elem);
});
}

export const randomElement = <T>(array: T[]): T => {
if (!array || !array.length) return null;
return array[Math.floor(Math.random() * array.length)];
};

export const removeElement = (array: any[], element: any) => {
const index = array.indexOf(element);
if (index < 0) return;
array.splice(index, 1);
};
2 changes: 1 addition & 1 deletion packages/server/src/utils/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe('hashPassword', () => {
'$2a$10$LMKVPiNOWDZhtw9NizNIEuNGLsjOxQAcrwQJ0lnKuiaOtyFgZEnwO',
],
)('should return a string that starts with $2a$10 for the password: %', async (plainText) => {
expect(hashPassword(plainText).startsWith('$2a$10')).toBe(true);
expect((await hashPassword(plainText)).startsWith('$2a$10')).toBe(true);
});

});
12 changes: 6 additions & 6 deletions packages/server/src/utils/auth.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
const bcrypt = require('bcryptjs');
import * as bcrypt from 'bcryptjs';

export function hashPassword(password: string): string {
const salt = bcrypt.genSaltSync(10);
return bcrypt.hashSync(password, salt);
export async function hashPassword(password: string): Promise<string> {
const salt = await bcrypt.genSalt(10);
return bcrypt.hash(password, salt);
}

export function checkPassword(password: string, hash: string): boolean {
return bcrypt.compareSync(password, hash);
export async function checkPassword(password: string, hash: string): Promise<boolean> {
return bcrypt.compare(password, hash);
}

export const isHashedPassword = (password: string) => {
Expand Down
Loading

0 comments on commit 4d1e0cc

Please sign in to comment.