From 453e83ea5d81d203ba34bc43cd5c2c750ba40568 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 15 Aug 2019 11:53:26 +0200 Subject: Stronger model typings --- server/helpers/activitypub.ts | 3 +- server/helpers/actor.ts | 9 +++-- server/helpers/captions-utils.ts | 6 +-- .../helpers/custom-validators/video-ownership.ts | 22 +++-------- server/helpers/middlewares/accounts.ts | 7 +++- server/helpers/middlewares/video-abuses.ts | 44 +++++++-------------- server/helpers/middlewares/video-captions.ts | 4 +- server/helpers/middlewares/video-channels.ts | 45 +++++++++++++++------- server/helpers/middlewares/video-playlists.ts | 35 +++++++++++------ server/helpers/middlewares/videos.ts | 26 ++++++++++--- server/helpers/peertube-crypto.ts | 9 +++-- server/helpers/video.ts | 29 +++++++++++++- server/helpers/webfinger.ts | 3 +- 13 files changed, 147 insertions(+), 95 deletions(-) (limited to 'server/helpers') diff --git a/server/helpers/activitypub.ts b/server/helpers/activitypub.ts index 951a25669..97c809a0c 100644 --- a/server/helpers/activitypub.ts +++ b/server/helpers/activitypub.ts @@ -7,6 +7,7 @@ import { ActorModel } from '../models/activitypub/actor' import { signJsonLDObject } from './peertube-crypto' import { pageToStartAndCount } from './core-utils' import { parse } from 'url' +import { MActor } from '../typings/models' function activityPubContextify (data: T) { return Object.assign(data, { @@ -143,7 +144,7 @@ async function activityPubCollectionPagination (baseUrl: string, handler: Activi } -function buildSignedActivity (byActor: ActorModel, data: Object) { +function buildSignedActivity (byActor: MActor, data: Object) { const activity = activityPubContextify(data) return signJsonLDObject(byActor, activity) as Promise diff --git a/server/helpers/actor.ts b/server/helpers/actor.ts index 12a7ace9f..117548a60 100644 --- a/server/helpers/actor.ts +++ b/server/helpers/actor.ts @@ -1,10 +1,13 @@ import { ActorModel } from '../models/activitypub/actor' +import * as Bluebird from 'bluebird' +import { MActorFull, MActorAccountChannelId } from '../typings/models' -type ActorFetchByUrlType = 'all' | 'actor-and-association-ids' -function fetchActorByUrl (url: string, fetchType: ActorFetchByUrlType) { +type ActorFetchByUrlType = 'all' | 'association-ids' + +function fetchActorByUrl (url: string, fetchType: ActorFetchByUrlType): Bluebird { if (fetchType === 'all') return ActorModel.loadByUrlAndPopulateAccountAndChannel(url) - if (fetchType === 'actor-and-association-ids') return ActorModel.loadByUrl(url) + if (fetchType === 'association-ids') return ActorModel.loadByUrl(url) } export { diff --git a/server/helpers/captions-utils.ts b/server/helpers/captions-utils.ts index 7174d4654..4f29058e5 100644 --- a/server/helpers/captions-utils.ts +++ b/server/helpers/captions-utils.ts @@ -1,10 +1,10 @@ import { join } from 'path' import { CONFIG } from '../initializers/config' -import { VideoCaptionModel } from '../models/video/video-caption' import * as srt2vtt from 'srt-to-vtt' -import { createReadStream, createWriteStream, remove, move } from 'fs-extra' +import { createReadStream, createWriteStream, move, remove } from 'fs-extra' +import { MVideoCaption } from '@server/typings/models' -async function moveAndProcessCaptionFile (physicalFile: { filename: string, path: string }, videoCaption: VideoCaptionModel) { +async function moveAndProcessCaptionFile (physicalFile: { filename: string, path: string }, videoCaption: MVideoCaption) { const videoCaptionsDir = CONFIG.STORAGE.CAPTIONS_DIR const destination = join(videoCaptionsDir, videoCaption.getCaptionName()) diff --git a/server/helpers/custom-validators/video-ownership.ts b/server/helpers/custom-validators/video-ownership.ts index a7771e07b..9570b2799 100644 --- a/server/helpers/custom-validators/video-ownership.ts +++ b/server/helpers/custom-validators/video-ownership.ts @@ -1,10 +1,10 @@ import { Response } from 'express' -import * as validator from 'validator' import { VideoChangeOwnershipModel } from '../../models/video/video-change-ownership' -import { UserModel } from '../../models/account/user' +import { MVideoChangeOwnershipFull } from '@server/typings/models/video/video-change-ownership' +import { MUserId } from '@server/typings/models' -export async function doesChangeVideoOwnershipExist (id: string, res: Response): Promise { - const videoChangeOwnership = await loadVideoChangeOwnership(id) +export async function doesChangeVideoOwnershipExist (id: number, res: Response) { + const videoChangeOwnership = await VideoChangeOwnershipModel.load(id) if (!videoChangeOwnership) { res.status(404) @@ -18,19 +18,7 @@ export async function doesChangeVideoOwnershipExist (id: string, res: Response): return true } -async function loadVideoChangeOwnership (id: string): Promise { - if (validator.isInt(id)) { - return VideoChangeOwnershipModel.load(parseInt(id, 10)) - } - - return undefined -} - -export function checkUserCanTerminateOwnershipChange ( - user: UserModel, - videoChangeOwnership: VideoChangeOwnershipModel, - res: Response -): boolean { +export function checkUserCanTerminateOwnershipChange (user: MUserId, videoChangeOwnership: MVideoChangeOwnershipFull, res: Response) { if (videoChangeOwnership.NextOwner.userId === user.id) { return true } diff --git a/server/helpers/middlewares/accounts.ts b/server/helpers/middlewares/accounts.ts index 791022b97..f5aa0bada 100644 --- a/server/helpers/middlewares/accounts.ts +++ b/server/helpers/middlewares/accounts.ts @@ -1,6 +1,7 @@ import { Response } from 'express' import { AccountModel } from '../../models/account/account' import * as Bluebird from 'bluebird' +import { MAccountDefault } from '../../typings/models' function doesAccountIdExist (id: number, res: Response, sendNotFound = true) { const promise = AccountModel.load(id) @@ -15,10 +16,12 @@ function doesLocalAccountNameExist (name: string, res: Response, sendNotFound = } function doesAccountNameWithHostExist (nameWithDomain: string, res: Response, sendNotFound = true) { - return doesAccountExist(AccountModel.loadByNameWithHost(nameWithDomain), res, sendNotFound) + const promise = AccountModel.loadByNameWithHost(nameWithDomain) + + return doesAccountExist(promise, res, sendNotFound) } -async function doesAccountExist (p: Bluebird, res: Response, sendNotFound: boolean) { +async function doesAccountExist (p: Bluebird, res: Response, sendNotFound: boolean) { const account = await p if (!account) { diff --git a/server/helpers/middlewares/video-abuses.ts b/server/helpers/middlewares/video-abuses.ts index b23f1f021..1b573ca37 100644 --- a/server/helpers/middlewares/video-abuses.ts +++ b/server/helpers/middlewares/video-abuses.ts @@ -1,41 +1,23 @@ -import * as express from 'express' -import { VideoChannelModel } from '../../models/video/video-channel' +import { Response } from 'express' +import { VideoAbuseModel } from '../../models/video/video-abuse' -async function doesLocalVideoChannelNameExist (name: string, res: express.Response) { - const videoChannel = await VideoChannelModel.loadLocalByNameAndPopulateAccount(name) +async function doesVideoAbuseExist (abuseId: number, videoId: number, res: Response) { + const videoAbuse = await VideoAbuseModel.loadByIdAndVideoId(abuseId, videoId) - return processVideoChannelExist(videoChannel, res) -} - -async function doesVideoChannelIdExist (id: number, res: express.Response) { - const videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id) - - return processVideoChannelExist(videoChannel, res) -} - -async function doesVideoChannelNameWithHostExist (nameWithDomain: string, res: express.Response) { - const videoChannel = await VideoChannelModel.loadByNameWithHostAndPopulateAccount(nameWithDomain) - - return processVideoChannelExist(videoChannel, res) -} - -// --------------------------------------------------------------------------- - -export { - doesLocalVideoChannelNameExist, - doesVideoChannelIdExist, - doesVideoChannelNameWithHostExist -} - -function processVideoChannelExist (videoChannel: VideoChannelModel, res: express.Response) { - if (!videoChannel) { + if (videoAbuse === null) { res.status(404) - .json({ error: 'Video channel not found' }) + .json({ error: 'Video abuse not found' }) .end() return false } - res.locals.videoChannel = videoChannel + res.locals.videoAbuse = videoAbuse return true } + +// --------------------------------------------------------------------------- + +export { + doesVideoAbuseExist +} diff --git a/server/helpers/middlewares/video-captions.ts b/server/helpers/middlewares/video-captions.ts index dc3d0144b..1b2513b60 100644 --- a/server/helpers/middlewares/video-captions.ts +++ b/server/helpers/middlewares/video-captions.ts @@ -1,8 +1,8 @@ -import { VideoModel } from '../../models/video/video' import { Response } from 'express' import { VideoCaptionModel } from '../../models/video/video-caption' +import { MVideoId } from '@server/typings/models' -async function doesVideoCaptionExist (video: VideoModel, language: string, res: Response) { +async function doesVideoCaptionExist (video: MVideoId, language: string, res: Response) { const videoCaption = await VideoCaptionModel.loadByVideoIdAndLanguage(video.id, language) if (!videoCaption) { diff --git a/server/helpers/middlewares/video-channels.ts b/server/helpers/middlewares/video-channels.ts index 1b573ca37..17b7692c5 100644 --- a/server/helpers/middlewares/video-channels.ts +++ b/server/helpers/middlewares/video-channels.ts @@ -1,23 +1,42 @@ -import { Response } from 'express' -import { VideoAbuseModel } from '../../models/video/video-abuse' +import * as express from 'express' +import { VideoChannelModel } from '../../models/video/video-channel' +import { MChannelActorAccountDefault } from '../../typings/models' -async function doesVideoAbuseExist (abuseId: number, videoId: number, res: Response) { - const videoAbuse = await VideoAbuseModel.loadByIdAndVideoId(abuseId, videoId) +async function doesLocalVideoChannelNameExist (name: string, res: express.Response) { + const videoChannel = await VideoChannelModel.loadLocalByNameAndPopulateAccount(name) - if (videoAbuse === null) { - res.status(404) - .json({ error: 'Video abuse not found' }) - .end() + return processVideoChannelExist(videoChannel, res) +} - return false - } +async function doesVideoChannelIdExist (id: number, res: express.Response) { + const videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id) - res.locals.videoAbuse = videoAbuse - return true + return processVideoChannelExist(videoChannel, res) +} + +async function doesVideoChannelNameWithHostExist (nameWithDomain: string, res: express.Response) { + const videoChannel = await VideoChannelModel.loadByNameWithHostAndPopulateAccount(nameWithDomain) + + return processVideoChannelExist(videoChannel, res) } // --------------------------------------------------------------------------- export { - doesVideoAbuseExist + doesLocalVideoChannelNameExist, + doesVideoChannelIdExist, + doesVideoChannelNameWithHostExist +} + +function processVideoChannelExist (videoChannel: MChannelActorAccountDefault, res: express.Response) { + if (!videoChannel) { + res.status(404) + .json({ error: 'Video channel not found' }) + .end() + + return false + } + + res.locals.videoChannel = videoChannel + return true } diff --git a/server/helpers/middlewares/video-playlists.ts b/server/helpers/middlewares/video-playlists.ts index 735bf362f..8e7484483 100644 --- a/server/helpers/middlewares/video-playlists.ts +++ b/server/helpers/middlewares/video-playlists.ts @@ -1,11 +1,31 @@ import * as express from 'express' import { VideoPlaylistModel } from '../../models/video/video-playlist' +import { MVideoPlaylist } from '../../typings/models/video/video-playlist' -async function doesVideoPlaylistExist (id: number | string, res: express.Response, fetchType: 'summary' | 'all' = 'summary') { - const videoPlaylist = fetchType === 'summary' - ? await VideoPlaylistModel.loadWithAccountAndChannelSummary(id, undefined) - : await VideoPlaylistModel.loadWithAccountAndChannel(id, undefined) +export type VideoPlaylistFetchType = 'summary' | 'all' +async function doesVideoPlaylistExist (id: number | string, res: express.Response, fetchType: VideoPlaylistFetchType = 'summary') { + if (fetchType === 'summary') { + const videoPlaylist = await VideoPlaylistModel.loadWithAccountAndChannelSummary(id, undefined) + res.locals.videoPlaylistSummary = videoPlaylist + return handleVideoPlaylist(videoPlaylist, res) + } + + const videoPlaylist = await VideoPlaylistModel.loadWithAccountAndChannel(id, undefined) + res.locals.videoPlaylistFull = videoPlaylist + + return handleVideoPlaylist(videoPlaylist, res) +} + +// --------------------------------------------------------------------------- + +export { + doesVideoPlaylistExist +} + +// --------------------------------------------------------------------------- + +function handleVideoPlaylist (videoPlaylist: MVideoPlaylist, res: express.Response) { if (!videoPlaylist) { res.status(404) .json({ error: 'Video playlist not found' }) @@ -14,12 +34,5 @@ async function doesVideoPlaylistExist (id: number | string, res: express.Respons return false } - res.locals.videoPlaylist = videoPlaylist return true } - -// --------------------------------------------------------------------------- - -export { - doesVideoPlaylistExist -} diff --git a/server/helpers/middlewares/videos.ts b/server/helpers/middlewares/videos.ts index ceb1058ec..964f0c91a 100644 --- a/server/helpers/middlewares/videos.ts +++ b/server/helpers/middlewares/videos.ts @@ -1,9 +1,8 @@ import { Response } from 'express' import { fetchVideo, VideoFetchType } from '../video' -import { UserModel } from '../../models/account/user' import { UserRight } from '../../../shared/models/users' import { VideoChannelModel } from '../../models/video/video-channel' -import { VideoModel } from '../../models/video/video' +import { MUser, MUserAccountId, MVideoAccountLight, MVideoFullLight, MVideoWithRights } from '@server/typings/models' async function doesVideoExist (id: number | string, res: Response, fetchType: VideoFetchType = 'all') { const userId = res.locals.oauth ? res.locals.oauth.token.User.id : undefined @@ -18,11 +17,28 @@ async function doesVideoExist (id: number | string, res: Response, fetchType: Vi return false } - if (fetchType !== 'none') res.locals.video = video + switch (fetchType) { + case 'all': + res.locals.videoAll = video as MVideoFullLight + break + + case 'id': + res.locals.videoId = video + break + + case 'only-video': + res.locals.onlyVideo = video + break + + case 'only-video-with-rights': + res.locals.onlyVideoWithRights = video as MVideoWithRights + break + } + return true } -async function doesVideoChannelOfAccountExist (channelId: number, user: UserModel, res: Response) { +async function doesVideoChannelOfAccountExist (channelId: number, user: MUserAccountId, res: Response) { if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) { const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId) if (videoChannel === null) { @@ -50,7 +66,7 @@ async function doesVideoChannelOfAccountExist (channelId: number, user: UserMode return true } -function checkUserCanManageVideo (user: UserModel, video: VideoModel, right: UserRight, res: Response) { +function checkUserCanManageVideo (user: MUser, video: MVideoAccountLight, right: UserRight, res: Response) { // Retrieve the user who did the request if (video.isOwned() === false) { res.status(403) diff --git a/server/helpers/peertube-crypto.ts b/server/helpers/peertube-crypto.ts index 1424949d0..085cd62c9 100644 --- a/server/helpers/peertube-crypto.ts +++ b/server/helpers/peertube-crypto.ts @@ -8,6 +8,7 @@ import { cloneDeep } from 'lodash' import { createVerify } from 'crypto' import { buildDigest } from '../lib/job-queue/handlers/utils/activitypub-http-utils' import * as bcrypt from 'bcrypt' +import { MActor } from '../typings/models' const bcryptComparePromise = promisify2(bcrypt.compare) const bcryptGenSaltPromise = promisify1(bcrypt.genSalt) @@ -46,7 +47,7 @@ function isHTTPSignatureDigestValid (rawBody: Buffer, req: Request): boolean { return true } -function isHTTPSignatureVerified (httpSignatureParsed: any, actor: ActorModel): boolean { +function isHTTPSignatureVerified (httpSignatureParsed: any, actor: MActor): boolean { return httpSignature.verifySignature(httpSignatureParsed, actor.publicKey) === true } @@ -56,7 +57,7 @@ function parseHTTPSignature (req: Request, clockSkew?: number) { // JSONLD -async function isJsonLDSignatureVerified (fromActor: ActorModel, signedDocument: any): Promise { +async function isJsonLDSignatureVerified (fromActor: MActor, signedDocument: any): Promise { if (signedDocument.signature.type === 'RsaSignature2017') { // Mastodon algorithm const res = await isJsonLDRSA2017Verified(fromActor, signedDocument) @@ -93,7 +94,7 @@ async function isJsonLDSignatureVerified (fromActor: ActorModel, signedDocument: } // Backward compatibility with "other" implementations -async function isJsonLDRSA2017Verified (fromActor: ActorModel, signedDocument: any) { +async function isJsonLDRSA2017Verified (fromActor: MActor, signedDocument: any) { function hash (obj: any): Promise { return jsonld.promises .normalize(obj, { @@ -130,7 +131,7 @@ async function isJsonLDRSA2017Verified (fromActor: ActorModel, signedDocument: a return verify.verify(fromActor.publicKey, signedDocument.signature.signatureValue, 'base64') } -function signJsonLDObject (byActor: ActorModel, data: any) { +function signJsonLDObject (byActor: MActor, data: any) { const options = { privateKeyPem: byActor.privateKey, creator: byActor.url, diff --git a/server/helpers/video.ts b/server/helpers/video.ts index c90fe06c7..26a72ac5c 100644 --- a/server/helpers/video.ts +++ b/server/helpers/video.ts @@ -1,8 +1,24 @@ import { VideoModel } from '../models/video/video' +import * as Bluebird from 'bluebird' +import { MVideoAccountAllFiles, MVideoFullLight, MVideoThumbnail, MVideoWithRights, MVideoIdThumbnail } from '@server/typings/models' +import { Response } from 'express' type VideoFetchType = 'all' | 'only-video' | 'only-video-with-rights' | 'id' | 'none' -function fetchVideo (id: number | string, fetchType: VideoFetchType, userId?: number) { +function fetchVideo (id: number | string, fetchType: 'all', userId?: number): Bluebird +function fetchVideo (id: number | string, fetchType: 'only-video', userId?: number): Bluebird +function fetchVideo (id: number | string, fetchType: 'only-video-with-rights', userId?: number): Bluebird +function fetchVideo (id: number | string, fetchType: 'id' | 'none', userId?: number): Bluebird +function fetchVideo ( + id: number | string, + fetchType: VideoFetchType, + userId?: number +): Bluebird +function fetchVideo ( + id: number | string, + fetchType: VideoFetchType, + userId?: number +): Bluebird { if (fetchType === 'all') return VideoModel.loadAndPopulateAccountAndServerAndTags(id, undefined, userId) if (fetchType === 'only-video-with-rights') return VideoModel.loadWithRights(id) @@ -13,15 +29,24 @@ function fetchVideo (id: number | string, fetchType: VideoFetchType, userId?: nu } type VideoFetchByUrlType = 'all' | 'only-video' -function fetchVideoByUrl (url: string, fetchType: VideoFetchByUrlType) { + +function fetchVideoByUrl (url: string, fetchType: 'all'): Bluebird +function fetchVideoByUrl (url: string, fetchType: 'only-video'): Bluebird +function fetchVideoByUrl (url: string, fetchType: VideoFetchByUrlType): Bluebird | Bluebird +function fetchVideoByUrl (url: string, fetchType: VideoFetchByUrlType): Bluebird | Bluebird { if (fetchType === 'all') return VideoModel.loadByUrlAndPopulateAccount(url) if (fetchType === 'only-video') return VideoModel.loadByUrl(url) } +function getVideo (res: Response) { + return res.locals.videoAll || res.locals.onlyVideo || res.locals.onlyVideoWithRights || res.locals.videoId +} + export { VideoFetchType, VideoFetchByUrlType, fetchVideo, + getVideo, fetchVideoByUrl } diff --git a/server/helpers/webfinger.ts b/server/helpers/webfinger.ts index d1229e28f..5443a266b 100644 --- a/server/helpers/webfinger.ts +++ b/server/helpers/webfinger.ts @@ -4,6 +4,7 @@ import { ActorModel } from '../models/activitypub/actor' import { isTestInstance } from './core-utils' import { isActivityPubUrlValid } from './custom-validators/activitypub/misc' import { WEBSERVER } from '../initializers/constants' +import { MActorFull } from '../typings/models' const webfinger = new WebFinger({ webfist_fallback: false, @@ -17,7 +18,7 @@ async function loadActorUrlOrGetFromWebfinger (uriArg: string) { const uri = uriArg.startsWith('@') ? uriArg.slice(1) : uriArg const [ name, host ] = uri.split('@') - let actor: ActorModel + let actor: MActorFull if (!host || host === WEBSERVER.HOST) { actor = await ActorModel.loadLocalByName(name) -- cgit v1.2.3