From 513e9d93b428799241615b9bad27c76560e7ad05 Mon Sep 17 00:00:00 2001 From: Braun Patrik Date: Sun, 9 Jul 2017 22:36:25 +0200 Subject: [PATCH] encrypting password --- README.md | 1 + backend/middlewares/user/AuthenticationMWs.ts | 3 ++- backend/model/PasswordHelper.ts | 12 ++++++++++++ backend/model/memory/UserManager.ts | 11 ++++++++++- backend/model/mysql/MySQLConnection.ts | 3 ++- backend/model/mysql/SharingManager.ts | 4 ++++ backend/model/mysql/UserManager.ts | 10 ++++++++++ frontend/app/gallery/share.service.ts | 5 +++-- .../app/gallery/share/share.gallery.component.ts | 5 +++-- package.json | 2 ++ 10 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 backend/model/PasswordHelper.ts diff --git a/README.md b/README.md index 9db04ec3..1171f77f 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ To configure it. Run `PiGallery2` first to create `config.json` file, then edit * keyboard support for navigation * showing low-res thumbnail while full image loads * Information panel for showing **Exif info** + * Automatic playing - `In progress` * Client side caching (directories and search results) * Rendering **photos** with GPS coordinates **on google map** * .gpx file support - `future plan` diff --git a/backend/middlewares/user/AuthenticationMWs.ts b/backend/middlewares/user/AuthenticationMWs.ts index 108e6558..f16f2b62 100644 --- a/backend/middlewares/user/AuthenticationMWs.ts +++ b/backend/middlewares/user/AuthenticationMWs.ts @@ -4,6 +4,7 @@ import {Error, ErrorCodes} from "../../../common/entities/Error"; import {UserDTO, UserRoles} from "../../../common/entities/UserDTO"; import {ObjectManagerRepository} from "../../model/ObjectManagerRepository"; import {Config} from "../../../common/config/private/Config"; +import {PasswordHelper} from "../../model/PasswordHelper"; export class AuthenticationMWs { @@ -135,7 +136,7 @@ export class AuthenticationMWs { sharingKey: req.query.sk || req.params.sharingKey, }); if (!sharing || sharing.expires < Date.now() || - (Config.Client.Sharing.passwordProtected === true && sharing.password !== password)) { + (Config.Client.Sharing.passwordProtected === true && sharing.password && !PasswordHelper.comparePassword(password, sharing.password))) { return next(new Error(ErrorCodes.CREDENTIAL_NOT_FOUND)); } diff --git a/backend/model/PasswordHelper.ts b/backend/model/PasswordHelper.ts new file mode 100644 index 00000000..2e346bb7 --- /dev/null +++ b/backend/model/PasswordHelper.ts @@ -0,0 +1,12 @@ +import * as bcrypt from "bcrypt"; + +export class PasswordHelper { + public static async cryptPassword(password) { + const salt = await bcrypt.genSalt(10); + return await bcrypt.hash(password, salt); + } + + public static async comparePassword(password, encryptedPassword) { + return bcrypt.compare(password, encryptedPassword); + } +} diff --git a/backend/model/memory/UserManager.ts b/backend/model/memory/UserManager.ts index 9a9f8c84..55a5a730 100644 --- a/backend/model/memory/UserManager.ts +++ b/backend/model/memory/UserManager.ts @@ -5,6 +5,7 @@ import {ProjectPath} from "../../ProjectPath"; import {Utils} from "../../../common/Utils"; import * as flatfile from "flat-file-db"; import * as path from "path"; +import {PasswordHelper} from "../PasswordHelper"; export class UserManager implements IUserManager { @@ -51,13 +52,21 @@ export class UserManager implements IUserManager { } public async find(filter: any) { - return this.db.get("users").filter((u: UserDTO) => Utils.equalsFilter(u, filter)); + let pass = filter.password; + delete filter.password; + return this.db.get("users").filter((u: UserDTO) => { + if (pass && !PasswordHelper.comparePassword(pass, u.password)) { + return false; + } + Utils.equalsFilter(u, filter) + }); } public async createUser(user: UserDTO) { user.id = parseInt(this.db.get("idCounter")) + 1; this.db.put("idCounter", user.id); let users = this.db.get("users"); + user.password = await PasswordHelper.cryptPassword(user.password); users.push(user); this.db.put("users", users); diff --git a/backend/model/mysql/MySQLConnection.ts b/backend/model/mysql/MySQLConnection.ts index 64231aef..8384bfa1 100644 --- a/backend/model/mysql/MySQLConnection.ts +++ b/backend/model/mysql/MySQLConnection.ts @@ -7,6 +7,7 @@ import {DirectoryEntity} from "./enitites/DirectoryEntity"; import {Config} from "../../../common/config/private/Config"; import {SharingEntity} from "./enitites/SharingEntity"; import {DataBaseConfig} from "../../../common/config/private/IPrivateConfig"; +import {PasswordHelper} from "../PasswordHelper"; export class MySQLConnection { @@ -88,7 +89,7 @@ export class MySQLConnection { if (admins.length == 0) { let a = new UserEntity(); a.name = "admin"; - a.password = "admin"; + a.password = await PasswordHelper.cryptPassword("admin"); a.role = UserRoles.Admin; await userRepository.persist(a); } diff --git a/backend/model/mysql/SharingManager.ts b/backend/model/mysql/SharingManager.ts index 06810d88..8bf8aea0 100644 --- a/backend/model/mysql/SharingManager.ts +++ b/backend/model/mysql/SharingManager.ts @@ -3,6 +3,7 @@ import {SharingDTO} from "../../../common/entities/SharingDTO"; import {MySQLConnection} from "./MySQLConnection"; import {SharingEntity} from "./enitites/SharingEntity"; import {Config} from "../../../common/config/private/Config"; +import {PasswordHelper} from "../PasswordHelper"; export class SharingManager implements ISharingManager { @@ -29,6 +30,9 @@ export class SharingManager implements ISharingManager { async createSharing(sharing: SharingDTO): Promise { await this.removeExpiredLink(); const connection = await MySQLConnection.getConnection(); + if (sharing.password) { + sharing.password = await PasswordHelper.cryptPassword(sharing.password); + } return await connection.getRepository(SharingEntity).persist(sharing); diff --git a/backend/model/mysql/UserManager.ts b/backend/model/mysql/UserManager.ts index d6e6b488..723a0287 100644 --- a/backend/model/mysql/UserManager.ts +++ b/backend/model/mysql/UserManager.ts @@ -2,6 +2,8 @@ import {UserDTO, UserRoles} from "../../../common/entities/UserDTO"; import {IUserManager} from "../interfaces/IUserManager"; import {UserEntity} from "./enitites/UserEntity"; import {MySQLConnection} from "./MySQLConnection"; +import {PasswordHelper} from "../PasswordHelper"; + export class UserManager implements IUserManager { @@ -11,10 +13,17 @@ export class UserManager implements IUserManager { public async findOne(filter: any) { const connection = await MySQLConnection.getConnection(); + let pass = filter.password; + delete filter.password; const user = (await connection.getRepository(UserEntity).findOne(filter)); + if (user.permissions && user.permissions != null) { user.permissions = JSON.parse(user.permissions); } + + if (pass && !PasswordHelper.comparePassword(pass, user.password)) { + throw "No entry found"; + } return user; }; @@ -34,6 +43,7 @@ export class UserManager implements IUserManager { if (user.permissions && user.permissions != null) { user.permissions = JSON.stringify(user.permissions); } + user.password = await PasswordHelper.cryptPassword(user.password); return await connection.getRepository(UserEntity).persist(user); } diff --git a/frontend/app/gallery/share.service.ts b/frontend/app/gallery/share.service.ts index b81f2907..daf1f92b 100644 --- a/frontend/app/gallery/share.service.ts +++ b/frontend/app/gallery/share.service.ts @@ -58,12 +58,13 @@ export class ShareService { }); } - public updateSharing(dir: string, sharingId: number, includeSubfolders: boolean, valid: number): Promise { + public updateSharing(dir: string, sharingId: number, includeSubfolders: boolean, password: string, valid: number): Promise { return this._networkService.putJson("/share/" + dir, { updateSharing: { id: sharingId, includeSubfolders: includeSubfolders, - valid: valid + valid: valid, + password: password } }); } diff --git a/frontend/app/gallery/share/share.gallery.component.ts b/frontend/app/gallery/share/share.gallery.component.ts index 3ffd322a..0c9c331d 100644 --- a/frontend/app/gallery/share/share.gallery.component.ts +++ b/frontend/app/gallery/share/share.gallery.component.ts @@ -25,7 +25,8 @@ export class GalleryShareComponent implements OnInit, OnDestroy { valid: { amount: 30, type: ValidityTypes.Days - } + }, + password: "" }; validityTypes = []; currentDir: string = ""; @@ -75,7 +76,7 @@ export class GalleryShareComponent implements OnInit, OnDestroy { async update() { this.url = "loading.."; - this.sharing = await this._sharingService.updateSharing(this.currentDir, this.sharing.id, this.input.includeSubfolders, this.calcValidity()); + this.sharing = await this._sharingService.updateSharing(this.currentDir, this.sharing.id, this.input.includeSubfolders, this.input.password, this.calcValidity()); console.log(this.sharing); this.url = Config.Client.publicUrl + "/share/" + this.sharing.sharingKey } diff --git a/package.json b/package.json index 8214498d..a9630c18 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "url": "https://github.com/bpatrik/PiGallery2/issues" }, "dependencies": { + "bcrypt": "^1.0.2", "body-parser": "^1.17.2", "ejs": "^2.5.6", "exif-parser": "^0.1.11", @@ -53,6 +54,7 @@ "@angular/platform-browser": "~4.2.6", "@angular/platform-browser-dynamic": "~4.2.6", "@angular/router": "~4.2.6", + "@types/bcrypt": "^1.0.0", "@types/express": "^4.0.36", "@types/express-session": "1.15.0", "@types/gm": "^1.17.31",