From 19d3f10d351334bb5e3fcb2c88445a15a9386e8c Mon Sep 17 00:00:00 2001 From: "Patrik J. Braun" Date: Fri, 3 Jan 2020 20:28:03 +0100 Subject: [PATCH] improving code quality. restricting secret to be accessible through rest api --- gulpfile.ts | 14 ++---- src/backend/middlewares/RenderingMWs.ts | 4 +- src/backend/model/jobs/jobs/IndexingJob.ts | 2 - .../model/jobs/jobs/ThumbnailGenerationJob.ts | 2 - src/common/config/private/ConfigClass.ts | 13 ++--- src/frontend/app/app.component.ts | 1 - .../info-panel.lightbox.gallery.component.ts | 47 ++++++++---------- .../backend/integration/routers/UserRouter.ts | 2 +- .../routers/admin/SettingsRouter.ts | 48 +++++++++++++++++++ 9 files changed, 82 insertions(+), 51 deletions(-) create mode 100644 test/backend/integration/routers/admin/SettingsRouter.ts diff --git a/gulpfile.ts b/gulpfile.ts index 60d3429c..49d27fd5 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -43,13 +43,7 @@ gulp.task('build-backend', function () { }); -const handleError = (cb: (err: any) => void) => { - return (err: any, stdout: string, stderr: string) => { - console.log(stdout); - console.log(stderr); - cb(err); - }; -}; + const createDynamicTranslationFile = async (language: string) => { // load const folder = './src/frontend/' + translationFolder; @@ -290,7 +284,7 @@ const translate = async (list: any[], cb: (err?: any) => void) => { '--source-lang="en" ' + '--source-file="./locale.source.xlf" ' + '--destination-filename="messages" ' + - '--destination-folder="./src/frontend/"' + translationFolder + ' --destination-languages=' + localsStr); + '--destination-folder="./src/frontend/"' + translationFolder + ' --destination-languages=' + localsStr); console.log(stdout); console.error(stderr); cb(); @@ -318,10 +312,10 @@ const merge = async (list: any[], cb: (err?: any) => void) => { }; gulp.task('update-translation-only', function (cb) { - translate(getLanguages(), cb); + translate(getLanguages(), cb).catch(console.error); }); gulp.task('merge-translation-only', function (cb) { - merge(getLanguages(), cb); + merge(getLanguages(), cb).catch(console.error); }); gulp.task('update-translation', gulp.series('extract-locale', 'update-translation-only')); diff --git a/src/backend/middlewares/RenderingMWs.ts b/src/backend/middlewares/RenderingMWs.ts index 69409a66..9df0f73c 100644 --- a/src/backend/middlewares/RenderingMWs.ts +++ b/src/backend/middlewares/RenderingMWs.ts @@ -54,7 +54,9 @@ export class RenderingMWs { public static renderConfig(req: Request, res: Response, next: NextFunction) { - const message = new Message(null, Config.original()); + const originalConf = Config.original(); + originalConf.Server.sessionSecret = null; + const message = new Message(null, originalConf); res.json(message); } diff --git a/src/backend/model/jobs/jobs/IndexingJob.ts b/src/backend/model/jobs/jobs/IndexingJob.ts index 60850b95..7bdc54cd 100644 --- a/src/backend/model/jobs/jobs/IndexingJob.ts +++ b/src/backend/model/jobs/jobs/IndexingJob.ts @@ -6,8 +6,6 @@ import {ConfigTemplateEntry, DefaultsJobs} from '../../../../common/entities/job import {ServerConfig} from '../../../../common/config/private/IPrivateConfig'; import {JobProgressStates} from '../../../../common/entities/job/JobProgressDTO'; -declare var global: NodeJS.Global; -const LOG_TAG = '[IndexingJob]'; export class IndexingJob extends Job { public readonly Name = DefaultsJobs[DefaultsJobs.Indexing]; diff --git a/src/backend/model/jobs/jobs/ThumbnailGenerationJob.ts b/src/backend/model/jobs/jobs/ThumbnailGenerationJob.ts index 9c71d461..bff508bc 100644 --- a/src/backend/model/jobs/jobs/ThumbnailGenerationJob.ts +++ b/src/backend/model/jobs/jobs/ThumbnailGenerationJob.ts @@ -7,8 +7,6 @@ import {MediaDTO} from '../../../../common/entities/MediaDTO'; import {FileDTO} from '../../../../common/entities/FileDTO'; import {backendTexts} from '../../../../common/BackendTexts'; -const LOG_TAG = '[ThumbnailGenerationJob]'; - export class ThumbnailGenerationJob extends FileJob<{ sizes: number[], indexedOnly: boolean }> { diff --git a/src/common/config/private/ConfigClass.ts b/src/common/config/private/ConfigClass.ts index f9dae634..d63dc8cb 100644 --- a/src/common/config/private/ConfigClass.ts +++ b/src/common/config/private/ConfigClass.ts @@ -1,5 +1,6 @@ import {IPrivateConfig, ServerConfig} from './IPrivateConfig'; import * as path from 'path'; +import * as crypto from 'crypto'; import {ConfigLoader} from 'typeconfig'; import {Utils} from '../../Utils'; import {UserRoles} from '../../entities/UserDTO'; @@ -61,14 +62,10 @@ export class ConfigClass extends PrivateConfigDefaultsClass implements IPrivateC } if (Array.isArray(this.Server.sessionSecret) === false) { - const s4 = (): string => { - return Math.floor((1 + Math.random()) * 0x10000) - .toString(16) - .substring(1); - }; - this.Server.sessionSecret = ['key1' + s4() + s4() + s4() + s4(), - 'key2' + s4() + s4() + s4() + s4(), - 'key3' + s4() + s4() + s4() + s4()]; + // if not secret is set, generate one randomly + this.Server.sessionSecret = [crypto.randomBytes(256).toString('hex'), + crypto.randomBytes(256).toString('hex'), + crypto.randomBytes(256).toString('hex')]; } } diff --git a/src/frontend/app/app.component.ts b/src/frontend/app/app.component.ts index b92439e3..78316482 100644 --- a/src/frontend/app/app.component.ts +++ b/src/frontend/app/app.component.ts @@ -1,6 +1,5 @@ import {Component, OnDestroy, OnInit} from '@angular/core'; import {AuthenticationService} from './model/network/authentication.service'; -import {UserDTO} from '../../common/entities/UserDTO'; import {Router} from '@angular/router'; import {Config} from '../../common/config/public/Config'; import {Title} from '@angular/platform-browser'; diff --git a/src/frontend/app/ui/gallery/lightbox/infopanel/info-panel.lightbox.gallery.component.ts b/src/frontend/app/ui/gallery/lightbox/infopanel/info-panel.lightbox.gallery.component.ts index ea4a1ce4..533c0050 100644 --- a/src/frontend/app/ui/gallery/lightbox/infopanel/info-panel.lightbox.gallery.component.ts +++ b/src/frontend/app/ui/gallery/lightbox/infopanel/info-panel.lightbox.gallery.component.ts @@ -16,21 +16,13 @@ export class InfoPanelLightboxComponent { @Input() media: MediaDTO; @Output() closed = new EventEmitter(); - public mapEnabled = true; + public readonly mapEnabled: boolean; constructor(public queryService: QueryService, public mapService: MapService) { this.mapEnabled = Config.Client.Map.enabled; } - isPhoto() { - return this.media && MediaDTO.isPhoto(this.media); - } - - calcMpx() { - return (this.media.metadata.size.width * this.media.metadata.size.height / 1000000).toFixed(2); - } - get FullPath(): string { return Utils.concatUrls(this.media.directory.path, this.media.directory.name, this.media.name); } @@ -39,21 +31,39 @@ export class InfoPanelLightboxComponent { return Utils.concatUrls(this.media.directory.path, this.media.directory.name); } + get VideoData(): VideoMetadata { + if (typeof (this.media).metadata.bitRate === 'undefined') { + return null; + } + return (this.media).metadata; + } + get PositionData(): PositionMetaData { + return (this.media).metadata.positionData; + } + get CameraData(): CameraMetadata { + return (this.media).metadata.cameraData; + } + + isPhoto() { + return this.media && MediaDTO.isPhoto(this.media); + } + + calcMpx() { + return (this.media.metadata.size.width * this.media.metadata.size.height / 1000000).toFixed(2); + } isThisYear() { return (new Date()).getFullYear() === (new Date(this.media.metadata.creationDate)).getFullYear(); } - getTime() { const date = new Date(this.media.metadata.creationDate); return date.toTimeString().split(' ')[0]; } - toFraction(f: number) { if (f > 1) { return f; @@ -61,13 +71,6 @@ export class InfoPanelLightboxComponent { return '1/' + (1 / f); } - get VideoData(): VideoMetadata { - if (typeof (this.media).metadata.bitRate === 'undefined') { - return null; - } - return (this.media).metadata; - } - hasPositionData(): boolean { return !!(this.media).metadata.positionData && !!((this.media).metadata.positionData.city || @@ -80,10 +83,6 @@ export class InfoPanelLightboxComponent { (this.media).metadata.positionData.GPSData.latitude && (this.media).metadata.positionData.GPSData.longitude; } - get PositionData(): PositionMetaData { - return (this.media).metadata.positionData; - } - getPositionText(): string { if (!(this.media).metadata.positionData) { return ''; @@ -99,10 +98,6 @@ export class InfoPanelLightboxComponent { return str; } - get CameraData(): CameraMetadata { - return (this.media).metadata.cameraData; - } - close() { this.closed.emit(); } diff --git a/test/backend/integration/routers/UserRouter.ts b/test/backend/integration/routers/UserRouter.ts index 6447b3ff..66d1537b 100644 --- a/test/backend/integration/routers/UserRouter.ts +++ b/test/backend/integration/routers/UserRouter.ts @@ -31,7 +31,7 @@ describe('UserRouter', () => { await rimrafPR(tempDir); }); - describe('/GET login', () => { + describe('/POST login', () => { it('it should GET all the books', async () => { const srv = new Server(); await srv.onStarted.wait(); diff --git a/test/backend/integration/routers/admin/SettingsRouter.ts b/test/backend/integration/routers/admin/SettingsRouter.ts new file mode 100644 index 00000000..c83af728 --- /dev/null +++ b/test/backend/integration/routers/admin/SettingsRouter.ts @@ -0,0 +1,48 @@ +import * as path from 'path'; +import * as util from 'util'; +import * as rimraf from 'rimraf'; +import {Config} from '../../../../../src/common/config/private/Config'; +import {ServerConfig} from '../../../../../src/common/config/private/IPrivateConfig'; +import {SQLConnection} from '../../../../../src/backend/model/database/sql/SQLConnection'; +import {Server} from '../../../../../src/backend/server'; + +process.env.NODE_ENV = 'test'; +const chai: any = require('chai'); +const chaiHttp = require('chai-http'); +const should = chai.should(); +chai.use(chaiHttp); + +const rimrafPR = util.promisify(rimraf); +describe('SettingsRouter', () => { + + const tempDir = path.join(__dirname, '../../tmp'); + beforeEach(async () => { + await rimrafPR(tempDir); + Config.Server.Threading.enabled = false; + Config.Server.Database.type = ServerConfig.DatabaseType.sqlite; + Config.Server.Database.dbFolder = tempDir; + }); + + + afterEach(async () => { + await SQLConnection.close(); + await rimrafPR(tempDir); + }); + + describe('/GET settings', () => { + it('it should GET all the books', async () => { + const originalSettings = Config.original(); + originalSettings.Server.sessionSecret = null; + const srv = new Server(); + await srv.onStarted.wait(); + const result = await chai.request(srv.App) + .get('/api/settings'); + + result.res.should.have.status(200); + result.body.should.be.a('object'); + should.equal(result.body.error, null); + result.body.result.should.deep.equal(originalSettings); + + }); + }); +});