From 9c751fb7253dbb2789a997e5259204c48dc50fae Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sun, 28 Dec 2025 10:28:09 +0700 Subject: [PATCH] feat: provider checks protection --- .../providers/bluesky/bluesky.provider.tsx | 6 ++--- .../providers/dribbble/dribbble.provider.tsx | 8 +++--- .../new-launch/providers/gmb/gmb.provider.tsx | 10 +++---- .../instagram/instagram.collaborators.tsx | 18 ++++++------- .../providers/lemmy/lemmy.provider.tsx | 12 ++++----- .../providers/linkedin/linkedin.provider.tsx | 14 +++++----- .../pinterest/pinterest.provider.tsx | 26 +++++++++---------- .../providers/reddit/reddit.provider.tsx | 6 ++--- .../providers/threads/threads.provider.tsx | 10 +++---- .../providers/tiktok/tiktok.provider.tsx | 12 ++++----- .../providers/warpcast/warpcast.provider.tsx | 2 +- .../new-launch/providers/x/x.provider.tsx | 10 +++---- .../providers/youtube/youtube.provider.tsx | 6 ++--- 13 files changed, 70 insertions(+), 70 deletions(-) diff --git a/apps/frontend/src/components/new-launch/providers/bluesky/bluesky.provider.tsx b/apps/frontend/src/components/new-launch/providers/bluesky/bluesky.provider.tsx index 8b2d7d0b..b3408970 100644 --- a/apps/frontend/src/components/new-launch/providers/bluesky/bluesky.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/bluesky/bluesky.provider.tsx @@ -18,14 +18,14 @@ export default withProvider({ dto: undefined, checkValidity: async (posts) => { if ( - posts.some( - (p) => p.some((a) => a.path.indexOf('mp4') > -1) && p.length > 1 + posts?.some( + (p) => p?.some((a) => (a?.path?.indexOf?.('mp4') ?? -1) > -1) && (p?.length ?? 0) > 1 ) ) { return 'You can only upload one video per post.'; } - if (posts.some((p) => p.length > 4)) { + if (posts?.some((p) => (p?.length ?? 0) > 4)) { return 'There can be maximum 4 pictures in a post.'; } return true; diff --git a/apps/frontend/src/components/new-launch/providers/dribbble/dribbble.provider.tsx b/apps/frontend/src/components/new-launch/providers/dribbble/dribbble.provider.tsx index ddc040c3..741aaa1f 100644 --- a/apps/frontend/src/components/new-launch/providers/dribbble/dribbble.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/dribbble/dribbble.provider.tsx @@ -24,9 +24,9 @@ export default withProvider({ SettingsComponent: DribbbleSettings, CustomPreviewComponent: undefined, dto: DribbbleDto, - checkValidity: async ([firstItem, ...otherItems]) => { - const isMp4 = firstItem?.find((item) => item.path.indexOf('mp4') > -1); - if (firstItem.length !== 1) { + checkValidity: async ([firstItem, ...otherItems] = []) => { + const isMp4 = firstItem?.find((item) => (item?.path?.indexOf?.('mp4') ?? -1) > -1); + if (firstItem?.length !== 1) { return 'Requires one item'; } if (isMp4) { @@ -41,7 +41,7 @@ export default withProvider({ // @ts-ignore resolve({ width: this.width, height: this.height }); }; - url.src = firstItem[0].path; + url.src = firstItem?.[0]?.path; }); if ( (details?.width === 400 && details?.height === 300) || diff --git a/apps/frontend/src/components/new-launch/providers/gmb/gmb.provider.tsx b/apps/frontend/src/components/new-launch/providers/gmb/gmb.provider.tsx index edb05772..ba008a1a 100644 --- a/apps/frontend/src/components/new-launch/providers/gmb/gmb.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/gmb/gmb.provider.tsx @@ -167,20 +167,20 @@ export default withProvider({ dto: GmbSettingsDto, checkValidity: async (items, settings: any) => { // GMB posts can have text only, or text with one image - if (items.length > 0 && items[0].length > 1) { + if ((items?.length ?? 0) > 0 && (items?.[0]?.length ?? 0) > 1) { return 'Google My Business posts can only have one image'; } // Check for video - GMB doesn't support video in local posts - if (items.length > 0 && items[0].length > 0) { - const media = items[0][0]; - if (media.path.indexOf('mp4') > -1) { + if ((items?.length ?? 0) > 0 && (items?.[0]?.length ?? 0) > 0) { + const media = items?.[0]?.[0]; + if ((media?.path?.indexOf?.('mp4') ?? -1) > -1) { return 'Google My Business posts do not support video attachments'; } } // Event posts require a title - if (settings.topicType === 'EVENT' && !settings.eventTitle) { + if (settings?.topicType === 'EVENT' && !settings?.eventTitle) { return 'Event posts require an event title'; } diff --git a/apps/frontend/src/components/new-launch/providers/instagram/instagram.collaborators.tsx b/apps/frontend/src/components/new-launch/providers/instagram/instagram.collaborators.tsx index 14c6e901..6ca7b088 100644 --- a/apps/frontend/src/components/new-launch/providers/instagram/instagram.collaborators.tsx +++ b/apps/frontend/src/components/new-launch/providers/instagram/instagram.collaborators.tsx @@ -60,18 +60,18 @@ export default withProvider({ SettingsComponent: InstagramCollaborators, CustomPreviewComponent: InstagramPreview, dto: InstagramDto, - checkValidity: async ([firstPost, ...otherPosts], settings) => { - if (!firstPost.length) { + checkValidity: async ([firstPost, ...otherPosts] = [], settings) => { + if (!firstPost?.length) { return 'Should have at least one media'; } - if (firstPost.length > 1 && settings.post_type === 'story') { + if ((firstPost?.length ?? 0) > 1 && settings?.post_type === 'story') { return 'Stories can only have one media'; } const checkVideosLength = await Promise.all( firstPost - .filter((f) => f.path.indexOf('mp4') > -1) - .flatMap((p) => p.path) - .map((p) => { + ?.filter((f) => (f?.path?.indexOf?.('mp4') ?? -1) > -1) + ?.flatMap((p) => p?.path) + ?.map((p) => { return new Promise((res) => { const video = document.createElement('video'); video.preload = 'metadata'; @@ -80,13 +80,13 @@ export default withProvider({ res(video.duration); }); }); - }) + }) ?? [] ); for (const video of checkVideosLength) { - if (video > 60 && settings.post_type === 'story') { + if (video > 60 && settings?.post_type === 'story') { return 'Stories should be maximum 60 seconds'; } - if (video > 180 && settings.post_type === 'post') { + if (video > 180 && settings?.post_type === 'post') { return 'Reel should be maximum 180 seconds'; } } diff --git a/apps/frontend/src/components/new-launch/providers/lemmy/lemmy.provider.tsx b/apps/frontend/src/components/new-launch/providers/lemmy/lemmy.provider.tsx index ac8dd6de..74bbb294 100644 --- a/apps/frontend/src/components/new-launch/providers/lemmy/lemmy.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/lemmy/lemmy.provider.tsx @@ -73,13 +73,13 @@ export default withProvider({ CustomPreviewComponent: undefined, dto: LemmySettingsDto, checkValidity: async (items) => { - const [firstItems] = items; + const [firstItems] = items ?? []; if ( - firstItems.length && - firstItems[0].path.indexOf('png') === -1 && - firstItems[0].path.indexOf('jpg') === -1 && - firstItems[0].path.indexOf('jpef') === -1 && - firstItems[0].path.indexOf('gif') === -1 + firstItems?.length && + (firstItems?.[0]?.path?.indexOf?.('png') ?? -1) === -1 && + (firstItems?.[0]?.path?.indexOf?.('jpg') ?? -1) === -1 && + (firstItems?.[0]?.path?.indexOf?.('jpef') ?? -1) === -1 && + (firstItems?.[0]?.path?.indexOf?.('gif') ?? -1) === -1 ) { return 'You can set only one picture for a cover'; } diff --git a/apps/frontend/src/components/new-launch/providers/linkedin/linkedin.provider.tsx b/apps/frontend/src/components/new-launch/providers/linkedin/linkedin.provider.tsx index a5d25386..d558ccb6 100644 --- a/apps/frontend/src/components/new-launch/providers/linkedin/linkedin.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/linkedin/linkedin.provider.tsx @@ -33,23 +33,23 @@ export default withProvider({ CustomPreviewComponent: LinkedinPreview, dto: LinkedinDto, checkValidity: async (posts, vals) => { - const [firstPost, ...restPosts] = posts; + const [firstPost, ...restPosts] = posts ?? []; if ( - vals.post_as_images_carousel && - (firstPost.length < 2 || - firstPost.some((p) => p.path.indexOf('mp4') > -1)) + vals?.post_as_images_carousel && + ((firstPost?.length ?? 0) < 2 || + firstPost?.some((p) => (p?.path?.indexOf?.('mp4') ?? -1) > -1)) ) { return 'Carousel can only be created with 2 or more images and no videos.'; } if ( - firstPost.length > 1 && - firstPost.some((p) => p.path.indexOf('mp4') > -1) + (firstPost?.length ?? 0) > 1 && + firstPost?.some((p) => (p?.path?.indexOf?.('mp4') ?? -1) > -1) ) { return 'Can have maximum 1 media when selecting a video.'; } - if (restPosts.some((p) => p.length > 0)) { + if (restPosts?.some((p) => (p?.length ?? 0) > 0)) { return 'Comments can only contain text.'; } return true; diff --git a/apps/frontend/src/components/new-launch/providers/pinterest/pinterest.provider.tsx b/apps/frontend/src/components/new-launch/providers/pinterest/pinterest.provider.tsx index 02a3a359..db03ea64 100644 --- a/apps/frontend/src/components/new-launch/providers/pinterest/pinterest.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/pinterest/pinterest.provider.tsx @@ -34,42 +34,42 @@ export default withProvider({ SettingsComponent: PinterestSettings, CustomPreviewComponent: PinterestPreview, dto: PinterestSettingsDto, - checkValidity: async ([firstItem, ...otherItems]) => { - const isMp4 = firstItem?.find((item) => item.path.indexOf('mp4') > -1); + checkValidity: async ([firstItem, ...otherItems] = []) => { + const isMp4 = firstItem?.find((item) => (item?.path?.indexOf?.('mp4') ?? -1) > -1); const isPicture = firstItem?.find( - (item) => item.path.indexOf('mp4') === -1 + (item) => (item?.path?.indexOf?.('mp4') ?? -1) === -1 ); - if (firstItem.length === 0) { + if ((firstItem?.length ?? 0) === 0) { return 'Requires at least one media'; } - if (isMp4 && firstItem.length !== 2 && !isPicture) { + if (isMp4 && firstItem?.length !== 2 && !isPicture) { return 'If posting a video you have to also include a cover image as second media'; } - if (isMp4 && firstItem.length > 2) { + if (isMp4 && (firstItem?.length ?? 0) > 2) { return 'If posting a video you can only have two media items'; } if ( - firstItem.length > 1 && - firstItem.every((p) => p.path.indexOf('mp4') == -1) + (firstItem?.length ?? 0) > 1 && + firstItem?.every((p) => (p?.path?.indexOf?.('mp4') ?? -1) == -1) ) { const loadAll: Array<{ width: number; height: number; }> = (await Promise.all( - firstItem.map((p) => { + firstItem?.map((p) => { return new Promise((resolve, reject) => { const url = new Image(); url.onload = function () { // @ts-ignore resolve({ width: this.width, height: this.height }); }; - url.src = p.path; + url.src = p?.path; }); - }) + }) ?? [] )) as any; - const checkAllTheSameWidthHeight = loadAll.every((p, i, arr) => { - return p.width === arr[0].width && p.height === arr[0].height; + const checkAllTheSameWidthHeight = loadAll?.every((p, i, arr) => { + return p?.width === arr?.[0]?.width && p?.height === arr?.[0]?.height; }); if (!checkAllTheSameWidthHeight) { return 'Requires all images to have the same width and height'; diff --git a/apps/frontend/src/components/new-launch/providers/reddit/reddit.provider.tsx b/apps/frontend/src/components/new-launch/providers/reddit/reddit.provider.tsx index 18ce5cae..51572ecc 100644 --- a/apps/frontend/src/components/new-launch/providers/reddit/reddit.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/reddit/reddit.provider.tsx @@ -218,15 +218,15 @@ export default withProvider({ if ( settings?.subreddit?.some( (p: any, index: number) => - p?.value?.type === 'media' && posts[0].length !== 1 + p?.value?.type === 'media' && posts?.[0]?.length !== 1 ) ) { return 'When posting a media post, you must attached exactly one media file.'; } if ( - posts.some((p) => - p.some((a) => !a.thumbnail && a.path.indexOf('mp4') > -1) + posts?.some((p) => + p?.some((a) => !a?.thumbnail && (a?.path?.indexOf?.('mp4') ?? -1) > -1) ) ) { return 'You must attach a thumbnail to your video post.'; diff --git a/apps/frontend/src/components/new-launch/providers/threads/threads.provider.tsx b/apps/frontend/src/components/new-launch/providers/threads/threads.provider.tsx index 01ebc718..7b930d26 100644 --- a/apps/frontend/src/components/new-launch/providers/threads/threads.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/threads/threads.provider.tsx @@ -15,12 +15,12 @@ export default withProvider({ SettingsComponent: SettingsComponent, CustomPreviewComponent: undefined, dto: undefined, - checkValidity: async ([firstPost, ...otherPosts], settings) => { + checkValidity: async ([firstPost, ...otherPosts] = [], settings) => { const checkVideosLength = await Promise.all( firstPost - .filter((f) => f.path.indexOf('mp4') > -1) - .flatMap((p) => p.path) - .map((p) => { + ?.filter((f) => (f?.path?.indexOf?.('mp4') ?? -1) > -1) + ?.flatMap((p) => p?.path) + ?.map((p) => { return new Promise((res) => { const video = document.createElement('video'); video.preload = 'metadata'; @@ -29,7 +29,7 @@ export default withProvider({ res(video.duration); }); }); - }) + }) ?? [] ); for (const video of checkVideosLength) { diff --git a/apps/frontend/src/components/new-launch/providers/tiktok/tiktok.provider.tsx b/apps/frontend/src/components/new-launch/providers/tiktok/tiktok.provider.tsx index d163ed1d..5059223f 100644 --- a/apps/frontend/src/components/new-launch/providers/tiktok/tiktok.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/tiktok/tiktok.provider.tsx @@ -26,7 +26,7 @@ const TikTokSettings: FC<{ const t = useT(); const isTitle = useMemo(() => { - return value?.[0].image.some((p) => p.path.indexOf('mp4') === -1); + return value?.[0]?.image?.some((p) => (p?.path?.indexOf?.('mp4') ?? -1) === -1); }, [value]); const disclose = watch('disclose'); @@ -300,18 +300,18 @@ export default withProvider({ CustomPreviewComponent: TiktokPreview, dto: TikTokDto, checkValidity: async (items) => { - const [firstItems] = items; - if (firstItems.length === 0) { + const [firstItems] = items ?? []; + if ((firstItems?.length ?? 0) === 0) { return 'No video / images selected'; } if ( - firstItems.length > 1 && - firstItems?.some((p) => p?.path?.indexOf('mp4') > -1) + (firstItems?.length ?? 0) > 1 && + firstItems?.some((p) => (p?.path?.indexOf?.('mp4') ?? -1) > -1) ) { return 'Only pictures are supported when selecting multiple items'; } else if ( firstItems?.length !== 1 && - firstItems?.[0]?.path?.indexOf('mp4') > -1 + (firstItems?.[0]?.path?.indexOf?.('mp4') ?? -1) > -1 ) { return 'You need one media'; } diff --git a/apps/frontend/src/components/new-launch/providers/warpcast/warpcast.provider.tsx b/apps/frontend/src/components/new-launch/providers/warpcast/warpcast.provider.tsx index 1d3e25ef..efb372c5 100644 --- a/apps/frontend/src/components/new-launch/providers/warpcast/warpcast.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/warpcast/warpcast.provider.tsx @@ -65,7 +65,7 @@ export default withProvider({ dto: undefined, checkValidity: async (list) => { if ( - list.some((item) => item.some((field) => field.path.indexOf('mp4') > -1)) + list?.some((item) => item?.some((field) => (field?.path?.indexOf?.('mp4') ?? -1) > -1)) ) { return 'Can only accept images'; } diff --git a/apps/frontend/src/components/new-launch/providers/x/x.provider.tsx b/apps/frontend/src/components/new-launch/providers/x/x.provider.tsx index 2ddc7e71..da7f3083 100644 --- a/apps/frontend/src/components/new-launch/providers/x/x.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/x/x.provider.tsx @@ -80,18 +80,18 @@ export default withProvider({ const premium = additionalSettings?.find((p: any) => p?.title === 'Verified')?.value || false; - if (posts.some((p) => p.length > 4)) { + if (posts?.some((p) => (p?.length ?? 0) > 4)) { return 'There can be maximum 4 pictures in a post.'; } if ( - posts.some( - (p) => p.some((m) => m.path.indexOf('mp4') > -1) && p.length > 1 + posts?.some( + (p) => p?.some((m) => (m?.path?.indexOf?.('mp4') ?? -1) > -1) && (p?.length ?? 0) > 1 ) ) { return 'There can be maximum 1 video in a post.'; } - for (const load of posts.flatMap((p) => p.flatMap((a) => a.path))) { - if (load.indexOf('mp4') > -1) { + for (const load of posts?.flatMap((p) => p?.flatMap((a) => a?.path)) ?? []) { + if ((load?.indexOf?.('mp4') ?? -1) > -1) { const isValid = await checkVideoDuration(load, premium); if (!isValid) { return 'Video duration must be less than or equal to 140 seconds.'; diff --git a/apps/frontend/src/components/new-launch/providers/youtube/youtube.provider.tsx b/apps/frontend/src/components/new-launch/providers/youtube/youtube.provider.tsx index 99de4177..9509d1ef 100644 --- a/apps/frontend/src/components/new-launch/providers/youtube/youtube.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/youtube/youtube.provider.tsx @@ -88,11 +88,11 @@ export default withProvider({ CustomPreviewComponent: YoutubePreview, dto: YoutubeSettingsDto, checkValidity: async (items) => { - const [firstItems] = items; - if (items[0].length !== 1) { + const [firstItems] = items ?? []; + if (items?.[0]?.length !== 1) { return 'You need one media'; } - if (firstItems[0].path.indexOf('mp4') === -1) { + if ((firstItems?.[0]?.path?.indexOf?.('mp4') ?? -1) === -1) { return 'Item must be a video'; } return true;