diff options
author | Chocobozzz <me@florianbigard.com> | 2022-11-15 14:41:55 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2022-11-15 14:41:55 +0100 |
commit | 4638cd713dcdd007cd7f49b9a95fa62ac7823e7c (patch) | |
tree | 3e341c6ebbd1ce9e2bbacd72e7e3793e0bd467c2 /server/models | |
parent | 6bcb559fc9a491fc3ce83e7c077ee9dc742b1d63 (diff) | |
download | PeerTube-4638cd713dcdd007cd7f49b9a95fa62ac7823e7c.tar.gz PeerTube-4638cd713dcdd007cd7f49b9a95fa62ac7823e7c.tar.zst PeerTube-4638cd713dcdd007cd7f49b9a95fa62ac7823e7c.zip |
Don't inject untrusted input
Even if it's already checked in middlewares
It's better to have safe modals too
Diffstat (limited to 'server/models')
-rw-r--r-- | server/models/abuse/abuse-query-builder.ts | 5 | ||||
-rw-r--r-- | server/models/actor/actor.ts | 4 | ||||
-rw-r--r-- | server/models/user/user-notification.ts | 3 | ||||
-rw-r--r-- | server/models/user/user.ts | 15 | ||||
-rw-r--r-- | server/models/utils.ts | 5 | ||||
-rw-r--r-- | server/models/video/sql/video/videos-id-list-query-builder.ts | 5 | ||||
-rw-r--r-- | server/models/video/video-channel.ts | 4 | ||||
-rw-r--r-- | server/models/video/video-playlist-element.ts | 21 | ||||
-rw-r--r-- | server/models/video/video-share.ts | 5 |
9 files changed, 39 insertions, 28 deletions
diff --git a/server/models/abuse/abuse-query-builder.ts b/server/models/abuse/abuse-query-builder.ts index cfc924ba4..74f4542e5 100644 --- a/server/models/abuse/abuse-query-builder.ts +++ b/server/models/abuse/abuse-query-builder.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | 1 | ||
2 | import { exists } from '@server/helpers/custom-validators/misc' | 2 | import { exists } from '@server/helpers/custom-validators/misc' |
3 | import { forceNumber } from '@shared/core-utils' | ||
3 | import { AbuseFilter, AbuseState, AbuseVideoIs } from '@shared/models' | 4 | import { AbuseFilter, AbuseState, AbuseVideoIs } from '@shared/models' |
4 | import { buildBlockedAccountSQL, buildDirectionAndField } from '../utils' | 5 | import { buildBlockedAccountSQL, buildDirectionAndField } from '../utils' |
5 | 6 | ||
@@ -135,12 +136,12 @@ function buildAbuseListQuery (options: BuildAbusesQueryOptions, type: 'count' | | |||
135 | } | 136 | } |
136 | 137 | ||
137 | if (exists(options.count)) { | 138 | if (exists(options.count)) { |
138 | const count = parseInt(options.count + '', 10) | 139 | const count = forceNumber(options.count) |
139 | suffix += `LIMIT ${count} ` | 140 | suffix += `LIMIT ${count} ` |
140 | } | 141 | } |
141 | 142 | ||
142 | if (exists(options.start)) { | 143 | if (exists(options.start)) { |
143 | const start = parseInt(options.start + '', 10) | 144 | const start = forceNumber(options.start) |
144 | suffix += `OFFSET ${start} ` | 145 | suffix += `OFFSET ${start} ` |
145 | } | 146 | } |
146 | } | 147 | } |
diff --git a/server/models/actor/actor.ts b/server/models/actor/actor.ts index 88db241dc..d7afa727d 100644 --- a/server/models/actor/actor.ts +++ b/server/models/actor/actor.ts | |||
@@ -18,7 +18,7 @@ import { | |||
18 | import { activityPubContextify } from '@server/lib/activitypub/context' | 18 | import { activityPubContextify } from '@server/lib/activitypub/context' |
19 | import { getBiggestActorImage } from '@server/lib/actor-image' | 19 | import { getBiggestActorImage } from '@server/lib/actor-image' |
20 | import { ModelCache } from '@server/models/model-cache' | 20 | import { ModelCache } from '@server/models/model-cache' |
21 | import { getLowercaseExtension } from '@shared/core-utils' | 21 | import { forceNumber, getLowercaseExtension } from '@shared/core-utils' |
22 | import { ActivityIconObject, ActivityPubActorType, ActorImageType } from '@shared/models' | 22 | import { ActivityIconObject, ActivityPubActorType, ActorImageType } from '@shared/models' |
23 | import { AttributesOnly } from '@shared/typescript-utils' | 23 | import { AttributesOnly } from '@shared/typescript-utils' |
24 | import { | 24 | import { |
@@ -446,7 +446,7 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> { | |||
446 | } | 446 | } |
447 | 447 | ||
448 | static rebuildFollowsCount (ofId: number, type: 'followers' | 'following', transaction?: Transaction) { | 448 | static rebuildFollowsCount (ofId: number, type: 'followers' | 'following', transaction?: Transaction) { |
449 | const sanitizedOfId = parseInt(ofId + '', 10) | 449 | const sanitizedOfId = forceNumber(ofId) |
450 | const where = { id: sanitizedOfId } | 450 | const where = { id: sanitizedOfId } |
451 | 451 | ||
452 | let columnToUpdate: string | 452 | let columnToUpdate: string |
diff --git a/server/models/user/user-notification.ts b/server/models/user/user-notification.ts index 6209cb4bf..d37fa5dc7 100644 --- a/server/models/user/user-notification.ts +++ b/server/models/user/user-notification.ts | |||
@@ -2,6 +2,7 @@ import { ModelIndexesOptions, Op, WhereOptions } from 'sequelize' | |||
2 | import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' | 2 | import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' |
3 | import { getBiggestActorImage } from '@server/lib/actor-image' | 3 | import { getBiggestActorImage } from '@server/lib/actor-image' |
4 | import { UserNotificationIncludes, UserNotificationModelForApi } from '@server/types/models/user' | 4 | import { UserNotificationIncludes, UserNotificationModelForApi } from '@server/types/models/user' |
5 | import { forceNumber } from '@shared/core-utils' | ||
5 | import { uuidToShort } from '@shared/extra-utils' | 6 | import { uuidToShort } from '@shared/extra-utils' |
6 | import { UserNotification, UserNotificationType } from '@shared/models' | 7 | import { UserNotification, UserNotificationType } from '@shared/models' |
7 | import { AttributesOnly } from '@shared/typescript-utils' | 8 | import { AttributesOnly } from '@shared/typescript-utils' |
@@ -284,7 +285,7 @@ export class UserNotificationModel extends Model<Partial<AttributesOnly<UserNoti | |||
284 | } | 285 | } |
285 | 286 | ||
286 | static removeNotificationsOf (options: { id: number, type: 'account' | 'server', forUserId?: number }) { | 287 | static removeNotificationsOf (options: { id: number, type: 'account' | 'server', forUserId?: number }) { |
287 | const id = parseInt(options.id + '', 10) | 288 | const id = forceNumber(options.id) |
288 | 289 | ||
289 | function buildAccountWhereQuery (base: string) { | 290 | function buildAccountWhereQuery (base: string) { |
290 | const whereSuffix = options.forUserId | 291 | const whereSuffix = options.forUserId |
diff --git a/server/models/user/user.ts b/server/models/user/user.ts index f70feed73..672728a2a 100644 --- a/server/models/user/user.ts +++ b/server/models/user/user.ts | |||
@@ -70,6 +70,7 @@ import { VideoImportModel } from '../video/video-import' | |||
70 | import { VideoLiveModel } from '../video/video-live' | 70 | import { VideoLiveModel } from '../video/video-live' |
71 | import { VideoPlaylistModel } from '../video/video-playlist' | 71 | import { VideoPlaylistModel } from '../video/video-playlist' |
72 | import { UserNotificationSettingModel } from './user-notification-setting' | 72 | import { UserNotificationSettingModel } from './user-notification-setting' |
73 | import { forceNumber } from '@shared/core-utils' | ||
73 | 74 | ||
74 | enum ScopeNames { | 75 | enum ScopeNames { |
75 | FOR_ME_API = 'FOR_ME_API', | 76 | FOR_ME_API = 'FOR_ME_API', |
@@ -900,27 +901,27 @@ export class UserModel extends Model<Partial<AttributesOnly<UserModel>>> { | |||
900 | videoQuotaDaily: this.videoQuotaDaily, | 901 | videoQuotaDaily: this.videoQuotaDaily, |
901 | 902 | ||
902 | videoQuotaUsed: videoQuotaUsed !== undefined | 903 | videoQuotaUsed: videoQuotaUsed !== undefined |
903 | ? parseInt(videoQuotaUsed + '', 10) + LiveQuotaStore.Instance.getLiveQuotaOf(this.id) | 904 | ? forceNumber(videoQuotaUsed) + LiveQuotaStore.Instance.getLiveQuotaOf(this.id) |
904 | : undefined, | 905 | : undefined, |
905 | 906 | ||
906 | videoQuotaUsedDaily: videoQuotaUsedDaily !== undefined | 907 | videoQuotaUsedDaily: videoQuotaUsedDaily !== undefined |
907 | ? parseInt(videoQuotaUsedDaily + '', 10) + LiveQuotaStore.Instance.getLiveQuotaOf(this.id) | 908 | ? forceNumber(videoQuotaUsedDaily) + LiveQuotaStore.Instance.getLiveQuotaOf(this.id) |
908 | : undefined, | 909 | : undefined, |
909 | 910 | ||
910 | videosCount: videosCount !== undefined | 911 | videosCount: videosCount !== undefined |
911 | ? parseInt(videosCount + '', 10) | 912 | ? forceNumber(videosCount) |
912 | : undefined, | 913 | : undefined, |
913 | abusesCount: abusesCount | 914 | abusesCount: abusesCount |
914 | ? parseInt(abusesCount, 10) | 915 | ? forceNumber(abusesCount) |
915 | : undefined, | 916 | : undefined, |
916 | abusesAcceptedCount: abusesAcceptedCount | 917 | abusesAcceptedCount: abusesAcceptedCount |
917 | ? parseInt(abusesAcceptedCount, 10) | 918 | ? forceNumber(abusesAcceptedCount) |
918 | : undefined, | 919 | : undefined, |
919 | abusesCreatedCount: abusesCreatedCount !== undefined | 920 | abusesCreatedCount: abusesCreatedCount !== undefined |
920 | ? parseInt(abusesCreatedCount + '', 10) | 921 | ? forceNumber(abusesCreatedCount) |
921 | : undefined, | 922 | : undefined, |
922 | videoCommentsCount: videoCommentsCount !== undefined | 923 | videoCommentsCount: videoCommentsCount !== undefined |
923 | ? parseInt(videoCommentsCount + '', 10) | 924 | ? forceNumber(videoCommentsCount) |
924 | : undefined, | 925 | : undefined, |
925 | 926 | ||
926 | noInstanceConfigWarningModal: this.noInstanceConfigWarningModal, | 927 | noInstanceConfigWarningModal: this.noInstanceConfigWarningModal, |
diff --git a/server/models/utils.ts b/server/models/utils.ts index 1e168d419..3476799ce 100644 --- a/server/models/utils.ts +++ b/server/models/utils.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import { literal, Op, OrderItem, Sequelize } from 'sequelize' | 1 | import { literal, Op, OrderItem, Sequelize } from 'sequelize' |
2 | import validator from 'validator' | 2 | import validator from 'validator' |
3 | import { forceNumber } from '@shared/core-utils' | ||
3 | 4 | ||
4 | type SortType = { sortModel: string, sortValue: string } | 5 | type SortType = { sortModel: string, sortValue: string } |
5 | 6 | ||
@@ -202,7 +203,7 @@ function buildBlockedAccountSQLOptimized (columnNameJoin: string, blockerIds: nu | |||
202 | } | 203 | } |
203 | 204 | ||
204 | function buildServerIdsFollowedBy (actorId: any) { | 205 | function buildServerIdsFollowedBy (actorId: any) { |
205 | const actorIdNumber = parseInt(actorId + '', 10) | 206 | const actorIdNumber = forceNumber(actorId) |
206 | 207 | ||
207 | return '(' + | 208 | return '(' + |
208 | 'SELECT "actor"."serverId" FROM "actorFollow" ' + | 209 | 'SELECT "actor"."serverId" FROM "actorFollow" ' + |
@@ -218,7 +219,7 @@ function buildWhereIdOrUUID (id: number | string) { | |||
218 | function parseAggregateResult (result: any) { | 219 | function parseAggregateResult (result: any) { |
219 | if (!result) return 0 | 220 | if (!result) return 0 |
220 | 221 | ||
221 | const total = parseInt(result + '', 10) | 222 | const total = forceNumber(result) |
222 | if (isNaN(total)) return 0 | 223 | if (isNaN(total)) return 0 |
223 | 224 | ||
224 | return total | 225 | return total |
diff --git a/server/models/video/sql/video/videos-id-list-query-builder.ts b/server/models/video/sql/video/videos-id-list-query-builder.ts index 14f903851..7c864bf27 100644 --- a/server/models/video/sql/video/videos-id-list-query-builder.ts +++ b/server/models/video/sql/video/videos-id-list-query-builder.ts | |||
@@ -6,6 +6,7 @@ import { buildDirectionAndField, createSafeIn, parseRowCountResult } from '@serv | |||
6 | import { MUserAccountId, MUserId } from '@server/types/models' | 6 | import { MUserAccountId, MUserId } from '@server/types/models' |
7 | import { VideoInclude, VideoPrivacy, VideoState } from '@shared/models' | 7 | import { VideoInclude, VideoPrivacy, VideoState } from '@shared/models' |
8 | import { AbstractRunQuery } from '../../../shared/abstract-run-query' | 8 | import { AbstractRunQuery } from '../../../shared/abstract-run-query' |
9 | import { forceNumber } from '@shared/core-utils' | ||
9 | 10 | ||
10 | /** | 11 | /** |
11 | * | 12 | * |
@@ -689,12 +690,12 @@ export class VideosIdListQueryBuilder extends AbstractRunQuery { | |||
689 | } | 690 | } |
690 | 691 | ||
691 | private setLimit (countArg: number) { | 692 | private setLimit (countArg: number) { |
692 | const count = parseInt(countArg + '', 10) | 693 | const count = forceNumber(countArg) |
693 | this.limit = `LIMIT ${count}` | 694 | this.limit = `LIMIT ${count}` |
694 | } | 695 | } |
695 | 696 | ||
696 | private setOffset (startArg: number) { | 697 | private setOffset (startArg: number) { |
697 | const start = parseInt(startArg + '', 10) | 698 | const start = forceNumber(startArg) |
698 | this.offset = `OFFSET ${start}` | 699 | this.offset = `OFFSET ${start}` |
699 | } | 700 | } |
700 | } | 701 | } |
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index 91dafbcf1..9e461b6ca 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts | |||
@@ -19,7 +19,7 @@ import { | |||
19 | } from 'sequelize-typescript' | 19 | } from 'sequelize-typescript' |
20 | import { CONFIG } from '@server/initializers/config' | 20 | import { CONFIG } from '@server/initializers/config' |
21 | import { MAccountActor } from '@server/types/models' | 21 | import { MAccountActor } from '@server/types/models' |
22 | import { pick } from '@shared/core-utils' | 22 | import { forceNumber, pick } from '@shared/core-utils' |
23 | import { AttributesOnly } from '@shared/typescript-utils' | 23 | import { AttributesOnly } from '@shared/typescript-utils' |
24 | import { ActivityPubActor } from '../../../shared/models/activitypub' | 24 | import { ActivityPubActor } from '../../../shared/models/activitypub' |
25 | import { VideoChannel, VideoChannelSummary } from '../../../shared/models/videos' | 25 | import { VideoChannel, VideoChannelSummary } from '../../../shared/models/videos' |
@@ -280,7 +280,7 @@ export type SummaryOptions = { | |||
280 | ] | 280 | ] |
281 | }, | 281 | }, |
282 | [ScopeNames.WITH_STATS]: (options: AvailableWithStatsOptions = { daysPrior: 30 }) => { | 282 | [ScopeNames.WITH_STATS]: (options: AvailableWithStatsOptions = { daysPrior: 30 }) => { |
283 | const daysPrior = parseInt(options.daysPrior + '', 10) | 283 | const daysPrior = forceNumber(options.daysPrior) |
284 | 284 | ||
285 | return { | 285 | return { |
286 | attributes: { | 286 | attributes: { |
diff --git a/server/models/video/video-playlist-element.ts b/server/models/video/video-playlist-element.ts index b45f15bd6..7181b5599 100644 --- a/server/models/video/video-playlist-element.ts +++ b/server/models/video/video-playlist-element.ts | |||
@@ -23,6 +23,7 @@ import { | |||
23 | MVideoPlaylistElementVideoUrlPlaylistPrivacy, | 23 | MVideoPlaylistElementVideoUrlPlaylistPrivacy, |
24 | MVideoPlaylistVideoThumbnail | 24 | MVideoPlaylistVideoThumbnail |
25 | } from '@server/types/models/video/video-playlist-element' | 25 | } from '@server/types/models/video/video-playlist-element' |
26 | import { forceNumber } from '@shared/core-utils' | ||
26 | import { AttributesOnly } from '@shared/typescript-utils' | 27 | import { AttributesOnly } from '@shared/typescript-utils' |
27 | import { PlaylistElementObject } from '../../../shared/models/activitypub/objects/playlist-element-object' | 28 | import { PlaylistElementObject } from '../../../shared/models/activitypub/objects/playlist-element-object' |
28 | import { VideoPrivacy } from '../../../shared/models/videos' | 29 | import { VideoPrivacy } from '../../../shared/models/videos' |
@@ -185,7 +186,9 @@ export class VideoPlaylistElementModel extends Model<Partial<AttributesOnly<Vide | |||
185 | playlistId: number | string, | 186 | playlistId: number | string, |
186 | playlistElementId: number | 187 | playlistElementId: number |
187 | ): Promise<MVideoPlaylistElementVideoUrlPlaylistPrivacy> { | 188 | ): Promise<MVideoPlaylistElementVideoUrlPlaylistPrivacy> { |
188 | const playlistWhere = validator.isUUID('' + playlistId) ? { uuid: playlistId } : { id: playlistId } | 189 | const playlistWhere = validator.isUUID('' + playlistId) |
190 | ? { uuid: playlistId } | ||
191 | : { id: playlistId } | ||
189 | 192 | ||
190 | const query = { | 193 | const query = { |
191 | include: [ | 194 | include: [ |
@@ -262,13 +265,15 @@ export class VideoPlaylistElementModel extends Model<Partial<AttributesOnly<Vide | |||
262 | .then(position => position ? position + 1 : 1) | 265 | .then(position => position ? position + 1 : 1) |
263 | } | 266 | } |
264 | 267 | ||
265 | static reassignPositionOf ( | 268 | static reassignPositionOf (options: { |
266 | videoPlaylistId: number, | 269 | videoPlaylistId: number |
267 | firstPosition: number, | 270 | firstPosition: number |
268 | endPosition: number, | 271 | endPosition: number |
269 | newPosition: number, | 272 | newPosition: number |
270 | transaction?: Transaction | 273 | transaction?: Transaction |
271 | ) { | 274 | }) { |
275 | const { videoPlaylistId, firstPosition, endPosition, newPosition, transaction } = options | ||
276 | |||
272 | const query = { | 277 | const query = { |
273 | where: { | 278 | where: { |
274 | videoPlaylistId, | 279 | videoPlaylistId, |
@@ -281,7 +286,7 @@ export class VideoPlaylistElementModel extends Model<Partial<AttributesOnly<Vide | |||
281 | validate: false // We use a literal to update the position | 286 | validate: false // We use a literal to update the position |
282 | } | 287 | } |
283 | 288 | ||
284 | const positionQuery = Sequelize.literal(`${newPosition} + "position" - ${firstPosition}`) | 289 | const positionQuery = Sequelize.literal(`${forceNumber(newPosition)} + "position" - ${forceNumber(firstPosition)}`) |
285 | return VideoPlaylistElementModel.update({ position: positionQuery }, query) | 290 | return VideoPlaylistElementModel.update({ position: positionQuery }, query) |
286 | } | 291 | } |
287 | 292 | ||
diff --git a/server/models/video/video-share.ts b/server/models/video/video-share.ts index ca63bb2d9..f2190037e 100644 --- a/server/models/video/video-share.ts +++ b/server/models/video/video-share.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import { literal, Op, QueryTypes, Transaction } from 'sequelize' | 1 | import { literal, Op, QueryTypes, Transaction } from 'sequelize' |
2 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' | 2 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' |
3 | import { forceNumber } from '@shared/core-utils' | ||
3 | import { AttributesOnly } from '@shared/typescript-utils' | 4 | import { AttributesOnly } from '@shared/typescript-utils' |
4 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 5 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
5 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' | 6 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' |
@@ -123,7 +124,7 @@ export class VideoShareModel extends Model<Partial<AttributesOnly<VideoShareMode | |||
123 | } | 124 | } |
124 | 125 | ||
125 | static loadActorsWhoSharedVideosOf (actorOwnerId: number, t: Transaction): Promise<MActorDefault[]> { | 126 | static loadActorsWhoSharedVideosOf (actorOwnerId: number, t: Transaction): Promise<MActorDefault[]> { |
126 | const safeOwnerId = parseInt(actorOwnerId + '', 10) | 127 | const safeOwnerId = forceNumber(actorOwnerId) |
127 | 128 | ||
128 | // /!\ On actor model | 129 | // /!\ On actor model |
129 | const query = { | 130 | const query = { |
@@ -148,7 +149,7 @@ export class VideoShareModel extends Model<Partial<AttributesOnly<VideoShareMode | |||
148 | } | 149 | } |
149 | 150 | ||
150 | static loadActorsByVideoChannel (videoChannelId: number, t: Transaction): Promise<MActorDefault[]> { | 151 | static loadActorsByVideoChannel (videoChannelId: number, t: Transaction): Promise<MActorDefault[]> { |
151 | const safeChannelId = parseInt(videoChannelId + '', 10) | 152 | const safeChannelId = forceNumber(videoChannelId) |
152 | 153 | ||
153 | // /!\ On actor model | 154 | // /!\ On actor model |
154 | const query = { | 155 | const query = { |