From 7dc3a198e4a156bc6a2363df81c03d37b2b04ba3 Mon Sep 17 00:00:00 2001 From: rubikscraft Date: Sun, 25 Dec 2022 23:11:13 +0100 Subject: [PATCH] Improve preference managment --- .../preference-common.service.ts | 8 +-- .../preference-defaults.service.ts | 47 ++++++++++----- .../sys-preference-db.service.ts | 19 ++++--- .../usr-preference-db.service.ts | 25 +++++--- .../models/constants/syspreferences.const.ts | 24 -------- .../models/constants/usrpreferences.const.ts | 12 ---- .../src/routes/api/usage/usage.controller.ts | 8 ++- frontend/src/app/i18n/sys-pref.i18n.ts | 3 + shared/src/dto/sys-preferences.enum.ts | 57 +++++++++++++++++++ shared/src/dto/usr-preferences.enum.ts | 18 ++++++ shared/src/validators/ms.validator.ts | 5 ++ 11 files changed, 158 insertions(+), 68 deletions(-) delete mode 100644 backend/src/models/constants/syspreferences.const.ts delete mode 100644 backend/src/models/constants/usrpreferences.const.ts create mode 100644 shared/src/validators/ms.validator.ts diff --git a/backend/src/collections/preference-db/preference-common.service.ts b/backend/src/collections/preference-db/preference-common.service.ts index 484ee96..8c5b052 100644 --- a/backend/src/collections/preference-db/preference-common.service.ts +++ b/backend/src/collections/preference-db/preference-common.service.ts @@ -17,8 +17,8 @@ type EnumValue = E[keyof E]; type PrefValueTypeType = { [key in EnumValue]: PrefValueTypeStrings; }; -type EncodedPref = { - key: string; +type EncodedPref = { + key: EnumValue; value: string; }; @@ -32,7 +32,7 @@ export class PreferenceCommonService { // E is either the SysPreference or the UsrPreference enum // the pref value types is the object containing the type of each key in E public DecodePref( - preference: EncodedPref, + preference: EncodedPref, prefType: E, prefValueTypes: PrefValueTypeType, ): Failable { @@ -69,7 +69,7 @@ export class PreferenceCommonService { value: PrefValueType, prefType: E, prefValueTypes: PrefValueTypeType, - ): AsyncFailable { + ): AsyncFailable> { const validatedKey = this.validatePrefKey(key, prefType); if (HasFailed(validatedKey)) return validatedKey; diff --git a/backend/src/collections/preference-db/preference-defaults.service.ts b/backend/src/collections/preference-db/preference-defaults.service.ts index 0c84363..d2c872c 100644 --- a/backend/src/collections/preference-db/preference-defaults.service.ts +++ b/backend/src/collections/preference-db/preference-defaults.service.ts @@ -15,14 +15,14 @@ export class PreferenceDefaultsService { constructor(private readonly jwtConfigService: EarlyJwtConfigService) {} - public readonly usrDefaults: { - [key in UsrPreference]: () => PrefValueType; + private readonly usrDefaults: { + [key in UsrPreference]: (() => PrefValueType) | PrefValueType; } = { - [UsrPreference.KeepOriginal]: () => false, + [UsrPreference.KeepOriginal]: false, }; - public readonly sysDefaults: { - [key in SysPreference]: () => PrefValueType; + private readonly sysDefaults: { + [key in SysPreference]: (() => PrefValueType) | PrefValueType; } = { [SysPreference.JwtSecret]: () => { const envSecret = this.jwtConfigService.getJwtSecret(); @@ -37,16 +37,37 @@ export class PreferenceDefaultsService { }, [SysPreference.JwtExpiresIn]: () => this.jwtConfigService.getJwtExpiresIn() ?? '7d', - [SysPreference.BCryptStrength]: () => 12, + [SysPreference.BCryptStrength]: 10, - [SysPreference.RemoveDerivativesAfter]: () => '7d', - [SysPreference.SaveDerivatives]: () => true, - [SysPreference.AllowEditing]: () => true, + [SysPreference.RemoveDerivativesAfter]: '7d', + [SysPreference.SaveDerivatives]: true, + [SysPreference.AllowEditing]: true, - [SysPreference.ConversionTimeLimit]: () => '10s', - [SysPreference.ConversionMemoryLimit]: () => 512, + [SysPreference.ConversionTimeLimit]: '15s', + [SysPreference.ConversionMemoryLimit]: 512, - [SysPreference.TrackingUrl]: () => '', - [SysPreference.TrackingId]: () => '', + [SysPreference.EnableTracking]: false, + [SysPreference.TrackingUrl]: '', + [SysPreference.TrackingId]: '', + + [SysPreference.EnableTelemetry]: true, }; + + public getSysDefault(pref: SysPreference): PrefValueType { + const value = this.sysDefaults[pref]; + if (typeof value === 'function') { + return value(); + } else { + return value; + } + } + + public getUsrDefault(pref: UsrPreference): PrefValueType { + const value = this.usrDefaults[pref]; + if (typeof value === 'function') { + return value(); + } else { + return value; + } + } } diff --git a/backend/src/collections/preference-db/sys-preference-db.service.ts b/backend/src/collections/preference-db/sys-preference-db.service.ts index b3305a3..e3e853c 100644 --- a/backend/src/collections/preference-db/sys-preference-db.service.ts +++ b/backend/src/collections/preference-db/sys-preference-db.service.ts @@ -5,17 +5,18 @@ import { PrefValueType, PrefValueTypeStrings, } from 'picsur-shared/dist/dto/preferences.dto'; -import { SysPreference } from 'picsur-shared/dist/dto/sys-preferences.enum'; +import { + SysPreference, + SysPreferenceList, + SysPreferenceValidators, + SysPreferenceValueTypes, +} from 'picsur-shared/dist/dto/sys-preferences.enum'; import { AsyncFailable, Fail, FT, HasFailed } from 'picsur-shared/dist/types'; import { Repository } from 'typeorm'; import { ESysPreferenceBackend, ESysPreferenceSchema, } from '../../database/entities/sys-preference.entity'; -import { - SysPreferenceList, - SysPreferenceValueTypes, -} from '../../models/constants/syspreferences.const'; import { MutexFallBack } from '../../util/mutex-fallback'; import { PreferenceCommonService } from './preference-common.service'; import { PreferenceDefaultsService } from './preference-defaults.service'; @@ -85,7 +86,7 @@ export class SysPreferenceDbService { // Return return this.prefCommon.DecodePref( - result.data, + result.data as any, SysPreference, SysPreferenceValueTypes, ); @@ -136,7 +137,7 @@ export class SysPreferenceDbService { private async saveDefault( key: SysPreference, // Force enum here because we dont validate ): AsyncFailable { - return this.setPreference(key, this.defaultsService.sysDefaults[key]()); + return this.setPreference(key, this.defaultsService.getSysDefault(key)); } private async encodeSysPref( @@ -151,6 +152,10 @@ export class SysPreferenceDbService { ); if (HasFailed(validated)) return validated; + const valueValidated = SysPreferenceValidators[key as SysPreference].safeParse( + value, + ); + let verifySysPreference = new ESysPreferenceBackend(); verifySysPreference.key = validated.key; verifySysPreference.value = validated.value; diff --git a/backend/src/collections/preference-db/usr-preference-db.service.ts b/backend/src/collections/preference-db/usr-preference-db.service.ts index b6145d3..0fbb12c 100644 --- a/backend/src/collections/preference-db/usr-preference-db.service.ts +++ b/backend/src/collections/preference-db/usr-preference-db.service.ts @@ -5,17 +5,18 @@ import { PrefValueType, PrefValueTypeStrings, } from 'picsur-shared/dist/dto/preferences.dto'; -import { UsrPreference } from 'picsur-shared/dist/dto/usr-preferences.enum'; +import { + UsrPreference, + UsrPreferenceList, + UsrPreferenceValidators, + UsrPreferenceValueTypes, +} from 'picsur-shared/dist/dto/usr-preferences.enum'; import { AsyncFailable, Fail, FT, HasFailed } from 'picsur-shared/dist/types'; import { Repository } from 'typeorm'; import { EUsrPreferenceBackend, EUsrPreferenceSchema, } from '../../database/entities/usr-preference.entity'; -import { - UsrPreferenceList, - UsrPreferenceValueTypes, -} from '../../models/constants/usrpreferences.const'; import { MutexFallBack } from '../../util/mutex-fallback'; import { PreferenceCommonService } from './preference-common.service'; import { PreferenceDefaultsService } from './preference-defaults.service'; @@ -91,7 +92,7 @@ export class UsrPreferenceDbService { // Return const unpacked = this.prefCommon.DecodePref( - result.data, + result.data as any, UsrPreference, UsrPreferenceValueTypes, ); @@ -175,7 +176,7 @@ export class UsrPreferenceDbService { return this.setPreference( userid, key, - this.defaultsService.usrDefaults[key](), + this.defaultsService.getUsrDefault(key), ); } @@ -192,6 +193,16 @@ export class UsrPreferenceDbService { ); if (HasFailed(validated)) return validated; + if (!UsrPreferenceValidators[validated.key](validated.value)) + throw Fail( + FT.UsrValidation, + undefined, + 'Preference validator failed for ' + + validated.key + + ' with value ' + + validated.value, + ); + let verifySysPreference = new EUsrPreferenceBackend(); verifySysPreference.key = validated.key; verifySysPreference.value = validated.value; diff --git a/backend/src/models/constants/syspreferences.const.ts b/backend/src/models/constants/syspreferences.const.ts deleted file mode 100644 index 7e5856a..0000000 --- a/backend/src/models/constants/syspreferences.const.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { PrefValueTypeStrings } from 'picsur-shared/dist/dto/preferences.dto'; -import { SysPreference } from 'picsur-shared/dist/dto/sys-preferences.enum'; - -export type SysPreferences = SysPreference[]; -export const SysPreferenceList: string[] = Object.values(SysPreference); - -// Syspref Value types -export const SysPreferenceValueTypes: { - [key in SysPreference]: PrefValueTypeStrings; -} = { - [SysPreference.JwtSecret]: 'string', - [SysPreference.JwtExpiresIn]: 'string', - [SysPreference.BCryptStrength]: 'number', - - [SysPreference.RemoveDerivativesAfter]: 'string', - [SysPreference.SaveDerivatives]: 'boolean', - [SysPreference.AllowEditing]: 'boolean', - - [SysPreference.ConversionTimeLimit]: 'string', - [SysPreference.ConversionMemoryLimit]: 'number', - - [SysPreference.TrackingUrl]: 'string', - [SysPreference.TrackingId]: 'string', -}; diff --git a/backend/src/models/constants/usrpreferences.const.ts b/backend/src/models/constants/usrpreferences.const.ts deleted file mode 100644 index bd11ba7..0000000 --- a/backend/src/models/constants/usrpreferences.const.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { PrefValueTypeStrings } from 'picsur-shared/dist/dto/preferences.dto'; -import { UsrPreference } from 'picsur-shared/dist/dto/usr-preferences.enum'; - -export type UsrPreferences = UsrPreference[]; -export const UsrPreferenceList: string[] = Object.values(UsrPreference); - -// Syspref Value types -export const UsrPreferenceValueTypes: { - [key in UsrPreference]: PrefValueTypeStrings; -} = { - [UsrPreference.KeepOriginal]: 'boolean', -}; diff --git a/backend/src/routes/api/usage/usage.controller.ts b/backend/src/routes/api/usage/usage.controller.ts index 5c9b779..d819e2f 100644 --- a/backend/src/routes/api/usage/usage.controller.ts +++ b/backend/src/routes/api/usage/usage.controller.ts @@ -39,6 +39,12 @@ export class UsageController { throw Fail(FT.NotFound, undefined, 'Tracking URL not set'); } - await res.from(`${trackingUrl}/api`); + await res.from(`${trackingUrl}/api`, { + rewriteRequestHeaders(req, headers) { + // remove cookies + delete headers.cookie; + return headers; + }, + }); } } diff --git a/frontend/src/app/i18n/sys-pref.i18n.ts b/frontend/src/app/i18n/sys-pref.i18n.ts index dd344a2..ff3870a 100644 --- a/frontend/src/app/i18n/sys-pref.i18n.ts +++ b/frontend/src/app/i18n/sys-pref.i18n.ts @@ -14,6 +14,9 @@ export const SysPreferenceFriendlyNames: { [SysPreference.ConversionTimeLimit]: 'Transcode/Edit Time Limit', [SysPreference.ConversionMemoryLimit]: 'Transcode/Edit Memory Limit MB', + [SysPreference.EnableTracking]: 'Enable Ackee Web Tracking', [SysPreference.TrackingUrl]: 'Ackee tracking URL', [SysPreference.TrackingId]: 'Ackee trackign website ID', + + [SysPreference.EnableTelemetry]: 'Enable System Telemetry', }; diff --git a/shared/src/dto/sys-preferences.enum.ts b/shared/src/dto/sys-preferences.enum.ts index 2b61ac4..4d88115 100644 --- a/shared/src/dto/sys-preferences.enum.ts +++ b/shared/src/dto/sys-preferences.enum.ts @@ -1,3 +1,11 @@ +import { PrefValueTypeStrings } from './preferences.dto'; +import ms from 'ms'; +import { IsValidMS } from '../validators/ms.validator'; +import { URLRegex, UUIDRegex } from '../util/common-regex'; +import { z } from 'zod'; +import { IsPosInt } from '../validators/positive-int.validator'; +import { IsEntityID } from '../validators/entity-id.validator'; + // This enum is only here to make accessing the values easier, and type checking in the backend export enum SysPreference { JwtSecret = 'jwt_secret', @@ -11,6 +19,55 @@ export enum SysPreference { ConversionTimeLimit = 'conversion_time_limit', ConversionMemoryLimit = 'conversion_memory_limit', + EnableTracking = 'enable_tracking', TrackingUrl = 'tracking_url', TrackingId = 'tracking_id', + + EnableTelemetry = 'enable_telemetry', } + +export type SysPreferences = SysPreference[]; +export const SysPreferenceList: string[] = Object.values(SysPreference); + +// Syspref Value types +export const SysPreferenceValueTypes: { + [key in SysPreference]: PrefValueTypeStrings; +} = { + [SysPreference.JwtSecret]: 'string', + [SysPreference.JwtExpiresIn]: 'string', + [SysPreference.BCryptStrength]: 'number', + + [SysPreference.RemoveDerivativesAfter]: 'string', + [SysPreference.SaveDerivatives]: 'boolean', + [SysPreference.AllowEditing]: 'boolean', + + [SysPreference.ConversionTimeLimit]: 'string', + [SysPreference.ConversionMemoryLimit]: 'number', + + [SysPreference.EnableTracking]: 'boolean', + [SysPreference.TrackingUrl]: 'string', + [SysPreference.TrackingId]: 'string', + + [SysPreference.EnableTelemetry]: 'boolean', +}; + +export const SysPreferenceValidators: { + [key in SysPreference]: z.ZodTypeAny; +} = { + [SysPreference.JwtSecret]: z.boolean(), + [SysPreference.JwtExpiresIn]: IsValidMS(), + + [SysPreference.BCryptStrength]: IsPosInt(), + [SysPreference.RemoveDerivativesAfter]: IsValidMS(), + [SysPreference.SaveDerivatives]: z.boolean(), + + [SysPreference.AllowEditing]: z.boolean(), + [SysPreference.ConversionTimeLimit]: IsValidMS(), + [SysPreference.ConversionMemoryLimit]: IsPosInt(), + + [SysPreference.EnableTracking]: z.boolean(), + [SysPreference.TrackingUrl]: z.string().regex(URLRegex), + [SysPreference.TrackingId]: IsEntityID(), + + [SysPreference.EnableTelemetry]: z.boolean(), +}; diff --git a/shared/src/dto/usr-preferences.enum.ts b/shared/src/dto/usr-preferences.enum.ts index 4eae68e..8eb626c 100644 --- a/shared/src/dto/usr-preferences.enum.ts +++ b/shared/src/dto/usr-preferences.enum.ts @@ -1,4 +1,22 @@ +import { PrefValueTypeStrings } from './preferences.dto'; + // This enum is only here to make accessing the values easier, and type checking in the backend export enum UsrPreference { KeepOriginal = 'keep_original', } + +export type UsrPreferences = UsrPreference[]; +export const UsrPreferenceList: string[] = Object.values(UsrPreference); + +// Syspref Value types +export const UsrPreferenceValueTypes: { + [key in UsrPreference]: PrefValueTypeStrings; +} = { + [UsrPreference.KeepOriginal]: 'boolean', +}; + +export const UsrPreferenceValidators: { + [key in UsrPreference]: (value: any) => boolean; +} = { + [UsrPreference.KeepOriginal]: (value: any) => typeof value === 'boolean', +}; diff --git a/shared/src/validators/ms.validator.ts b/shared/src/validators/ms.validator.ts new file mode 100644 index 0000000..06c046d --- /dev/null +++ b/shared/src/validators/ms.validator.ts @@ -0,0 +1,5 @@ +import ms from 'ms'; +import { z } from 'zod'; + +export const IsValidMS = () => + z.preprocess((v) => ms(v as any), z.number().int().min(0));