From f93148fcdd52e7cb06401d54e2188a4a782afab6 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Tue, 21 Mar 2023 13:02:38 +0800 Subject: [PATCH 1/8] Add BAD_DATA to the saving request error code --- packages/api/src/generated/graphql.ts | 1 + packages/api/src/generated/schema.graphql | 1 + packages/api/src/schema.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/packages/api/src/generated/graphql.ts b/packages/api/src/generated/graphql.ts index 23c756a50..2a14ee746 100644 --- a/packages/api/src/generated/graphql.ts +++ b/packages/api/src/generated/graphql.ts @@ -180,6 +180,7 @@ export type ArticleSavingRequestError = { }; export enum ArticleSavingRequestErrorCode { + BadData = 'BAD_DATA', NotFound = 'NOT_FOUND', Unauthorized = 'UNAUTHORIZED' } diff --git a/packages/api/src/generated/schema.graphql b/packages/api/src/generated/schema.graphql index d4b123d73..989f65764 100644 --- a/packages/api/src/generated/schema.graphql +++ b/packages/api/src/generated/schema.graphql @@ -145,6 +145,7 @@ type ArticleSavingRequestError { } enum ArticleSavingRequestErrorCode { + BAD_DATA NOT_FOUND UNAUTHORIZED } diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index 22828bbc1..5fbf077dc 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -1084,6 +1084,7 @@ const schema = gql` enum ArticleSavingRequestErrorCode { UNAUTHORIZED NOT_FOUND + BAD_DATA } type ArticleSavingRequestError { errorCodes: [ArticleSavingRequestErrorCode!]! From f053b60cbeb29810542b6f43497765fe5007d5c2 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Tue, 21 Mar 2023 13:03:23 +0800 Subject: [PATCH 2/8] Allow array values in page filters --- packages/api/src/elastic/pages.ts | 39 ++++++++++++++----------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/packages/api/src/elastic/pages.ts b/packages/api/src/elastic/pages.ts index 0f866b700..77f6b492a 100644 --- a/packages/api/src/elastic/pages.ts +++ b/packages/api/src/elastic/pages.ts @@ -328,33 +328,30 @@ export const deletePage = async ( } export const getPageByParam = async ( - param: Record, + params: Record, includeOriginalHtml = false ): Promise => { try { - const params = { - query: { - bool: { - filter: Object.keys(param) - .filter( - (key) => param[key as K] !== undefined && param[key as K] !== null - ) // filter out undefined and null values - .map((key) => ({ - term: { - [key]: param[key as K], - }, - })), - }, - }, - size: 1, - _source: { + let builder = esBuilder() + .size(1) + .rawOption('_source', { excludes: includeOriginalHtml ? [] : ['originalHtml'], - }, - } - + }) + // filter out undefined and null values and empty arrays + // and build the query + Object.entries(params) + .filter( + ([, value]) => + value != null && !(Array.isArray(value) && value.length === 0) + ) + .forEach(([key, value]) => { + Array.isArray(value) + ? (builder = builder.query('terms', key, value)) + : (builder = builder.query('term', key, value)) + }) const { body } = await client.search>({ index: INDEX_ALIAS, - body: params, + body: builder.build(), }) if (body.hits.total.value === 0) { From 5af9d9266cef666ede3ab9c5dae494875c604e87 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Tue, 21 Mar 2023 13:03:53 +0800 Subject: [PATCH 3/8] Do not fetch deleted article in saving request --- .../resolvers/article_saving_request/index.ts | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/api/src/resolvers/article_saving_request/index.ts b/packages/api/src/resolvers/article_saving_request/index.ts index ea7008fe6..a6ce2a8ba 100644 --- a/packages/api/src/resolvers/article_saving_request/index.ts +++ b/packages/api/src/resolvers/article_saving_request/index.ts @@ -57,22 +57,28 @@ export const articleSavingRequestResolver = authorized< ArticleSavingRequestError, QueryArticleSavingRequestArgs >(async (_, { id, url }, { models, claims }) => { + if (!id && !url) { + return { errorCodes: [ArticleSavingRequestErrorCode.BadData] } + } + const user = await models.user.get(claims.uid) + if (!user) { + return { errorCodes: [ArticleSavingRequestErrorCode.Unauthorized] } + } const params = { _id: id || undefined, url: url || undefined, userId: claims.uid, + state: [ + ArticleSavingRequestStatus.Succeeded, + ArticleSavingRequestStatus.Processing, + ], } const page = await getPageByParam(params) if (!page) { return { errorCodes: [ArticleSavingRequestErrorCode.NotFound] } } - const user = await models.user.get(page.userId) - if (user && page) { - if (isParsingTimeout(page)) { - page.state = ArticleSavingRequestStatus.Succeeded - } - return { articleSavingRequest: pageToArticleSavingRequest(user, page) } + if (isParsingTimeout(page)) { + page.state = ArticleSavingRequestStatus.Succeeded } - - return { errorCodes: [ArticleSavingRequestErrorCode.NotFound] } + return { articleSavingRequest: pageToArticleSavingRequest(user, page) } }) From d733576e416c5268106a47d24e307e0eb5346044 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Tue, 21 Mar 2023 13:04:22 +0800 Subject: [PATCH 4/8] Do not check for deleted article in saving request in web --- .../web/lib/networking/queries/useGetArticleSavingStatus.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web/lib/networking/queries/useGetArticleSavingStatus.tsx b/packages/web/lib/networking/queries/useGetArticleSavingStatus.tsx index 9ab686311..f75101914 100644 --- a/packages/web/lib/networking/queries/useGetArticleSavingStatus.tsx +++ b/packages/web/lib/networking/queries/useGetArticleSavingStatus.tsx @@ -131,7 +131,7 @@ export function useGetArticleSavingStatus({ } } - if (status === 'PROCESSING' || status === 'DELETED') { + if (status === 'PROCESSING') { return {} } From bc9ba1d976bd80ab3df2f03b3319010cc07e48c6 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Tue, 21 Mar 2023 13:05:00 +0800 Subject: [PATCH 5/8] Reset state to processing when creating articles --- packages/api/src/resolvers/article/index.ts | 86 ++++++++----------- .../src/services/create_page_save_request.ts | 24 +++++- 2 files changed, 59 insertions(+), 51 deletions(-) diff --git a/packages/api/src/resolvers/article/index.ts b/packages/api/src/resolvers/article/index.ts index f3b2ac4bb..8a7c242d7 100644 --- a/packages/api/src/resolvers/article/index.ts +++ b/packages/api/src/resolvers/article/index.ts @@ -3,6 +3,26 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-floating-promises */ +import { Readability } from '@omnivore/readability' +import * as httpContext from 'express-http-context' +import graphqlFields from 'graphql-fields' +import normalizeUrl from 'normalize-url' +import { searchHighlights } from '../../elastic/highlights' +import { + createPage, + getPageByParam, + searchAsYouType, + searchPages, + updatePage, + updatePagesAsync, +} from '../../elastic/pages' +import { + ArticleSavingRequestStatus, + Page, + PageType, + SearchItem as SearchItemData, +} from '../../elastic/types' +import { env } from '../../env' import { Article, ArticleError, @@ -51,11 +71,13 @@ import { UpdatesSinceErrorCode, UpdatesSinceSuccess, } from '../../generated/graphql' +import { createPageSaveRequest } from '../../services/create_page_save_request' +import { parsedContentToPage } from '../../services/save_page' +import { saveSearchHistory } from '../../services/search_history' +import { traceAs } from '../../tracing' import { Merge } from '../../util' -import { - getStorageFileDetails, - makeStorageFilePublic, -} from '../../utils/uploads' +import { analytics } from '../../utils/analytics' +import { isSiteBlockedForParse } from '../../utils/blocked' import { ContentParseError } from '../../utils/errors' import { authorized, @@ -67,45 +89,19 @@ import { userDataToUser, validatedDate, } from '../../utils/helpers' +import { createImageProxyUrl } from '../../utils/imageproxy' import { getDistillerResult, htmlToMarkdown, ParsedContentPuppeteer, parsePreparedContent, } from '../../utils/parser' -import { isSiteBlockedForParse } from '../../utils/blocked' -import { Readability } from '@omnivore/readability' -import { traceAs } from '../../tracing' - -import { createImageProxyUrl } from '../../utils/imageproxy' -import normalizeUrl from 'normalize-url' -import { WithDataSourcesContext } from '../types' - import { parseSearchQuery, SortBy, SortOrder } from '../../utils/search' -import { createPageSaveRequest } from '../../services/create_page_save_request' -import { analytics } from '../../utils/analytics' -import { env } from '../../env' -import graphqlFields from 'graphql-fields' - import { - ArticleSavingRequestStatus, - Page, - PageType, - SearchItem as SearchItemData, -} from '../../elastic/types' -import { - createPage, - getPageById, - getPageByParam, - searchAsYouType, - searchPages, - updatePage, - updatePagesAsync, -} from '../../elastic/pages' -import { searchHighlights } from '../../elastic/highlights' -import { saveSearchHistory } from '../../services/search_history' -import { parsedContentToPage } from '../../services/save_page' -import * as httpContext from 'express-http-context' + getStorageFileDetails, + makeStorageFilePublic, +} from '../../utils/uploads' +import { WithDataSourcesContext } from '../types' enum ArticleFormat { Markdown = 'markdown', @@ -649,24 +645,18 @@ export const setBookmarkArticleResolver = authorized< { input: { articleID, bookmark } }, { claims: { uid }, log, pubsub } ) => { - const page = await getPageById(articleID) + const page = await getPageByParam({ + userId: uid, + _id: articleID, + }) if (!page) { return { errorCodes: [SetBookmarkArticleErrorCode.NotFound] } } if (!bookmark) { - const pageRemoved = await getPageByParam({ - userId: uid, - _id: articleID, - }) - - if (!pageRemoved) { - return { errorCodes: [SetBookmarkArticleErrorCode.NotFound] } - } - // delete the page and its metadata const deleted = await updatePage( - pageRemoved.id, + page.id, { state: ArticleSavingRequestStatus.Deleted, labels: [], @@ -684,7 +674,7 @@ export const setBookmarkArticleResolver = authorized< userId: uid, event: 'link_removed', properties: { - url: pageRemoved.url, + url: page.url, env: env.server.apiEnv, }, }) @@ -704,7 +694,7 @@ export const setBookmarkArticleResolver = authorized< // Make sure article.id instead of userArticle.id has passed. We use it for cache updates return { bookmarkedArticle: { - ...pageRemoved, + ...page, isArchived: false, savedByViewer: false, postedByViewer: false, diff --git a/packages/api/src/services/create_page_save_request.ts b/packages/api/src/services/create_page_save_request.ts index 17727bd8d..7d2b504a5 100644 --- a/packages/api/src/services/create_page_save_request.ts +++ b/packages/api/src/services/create_page_save_request.ts @@ -2,7 +2,12 @@ import normalizeUrl from 'normalize-url' import * as privateIpLib from 'private-ip' import { v4 as uuidv4 } from 'uuid' import { createPubSubClient, PubsubClient } from '../datalayer/pubsub' -import { countByCreatedAt, createPage, getPageByParam } from '../elastic/pages' +import { + countByCreatedAt, + createPage, + getPageByParam, + updatePage, +} from '../elastic/pages' import { ArticleSavingRequestStatus, PageType } from '../elastic/types' import { ArticleSavingRequest, @@ -87,6 +92,10 @@ export const createPageSaveRequest = async ( stripWWW: false, }) + const ctx = { + pubsub, + uid: userId, + } let page = await getPageByParam({ userId, url: normalizedUrl, @@ -110,7 +119,7 @@ export const createPageSaveRequest = async ( } // create processing page - const pageId = await createPage(page, { pubsub, uid: userId }) + const pageId = await createPage(page, ctx) if (!pageId) { console.log('Failed to create page', page) return Promise.reject({ @@ -118,7 +127,16 @@ export const createPageSaveRequest = async ( }) } } - + // reset state to processing + if (page.state !== ArticleSavingRequestStatus.Processing) { + await updatePage( + page.id, + { + state: ArticleSavingRequestStatus.Processing, + }, + ctx + ) + } // enqueue task to parse page await enqueueParseRequest(url, userId, page.id, priority) From 81484535031d5fab793ade287cd88b88c7d09b4a Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Tue, 21 Mar 2023 13:44:00 +0800 Subject: [PATCH 6/8] When saving an existing page, update the content --- packages/api/src/services/save_file.ts | 7 ++----- packages/api/src/services/save_page.ts | 15 ++++++++------- packages/api/src/utils/uploads.ts | 9 +-------- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/packages/api/src/services/save_file.ts b/packages/api/src/services/save_file.ts index 64233aab6..3664d71ad 100644 --- a/packages/api/src/services/save_file.ts +++ b/packages/api/src/services/save_file.ts @@ -34,12 +34,9 @@ export const saveFile = async ( } } - const uploadFileDetails = await getStorageFileDetails( - input.uploadFileId, - uploadFile.fileName - ) + await getStorageFileDetails(input.uploadFileId, uploadFile.fileName) - const uploadFileData = await ctx.authTrx(async (tx) => { + await ctx.authTrx(async (tx) => { return ctx.models.uploadFile.setFileUploadComplete(input.uploadFileId, tx) }) diff --git a/packages/api/src/services/save_page.ts b/packages/api/src/services/save_page.ts index cc8513678..de052d10d 100644 --- a/packages/api/src/services/save_page.ts +++ b/packages/api/src/services/save_page.ts @@ -101,20 +101,23 @@ export const savePage = async ( originalHtml: parseResult.domContent, canonicalUrl: parseResult.canonicalUrl, }) - + // check if the page already exists const existingPage = await getPageByParam({ userId: saver.userId, url: articleToSave.url, - state: ArticleSavingRequestStatus.Succeeded, }) - if (existingPage) { + pageId = existingPage.id + slug = existingPage.slug if ( !(await updatePage( existingPage.id, { - savedAt: new Date(), - archivedAt: null, + // update the page with the new content + ...articleToSave, + archivedAt: null, // unarchive if it was archived + id: pageId, // we don't want to update the id + slug, // we don't want to update the slug }, ctx )) @@ -124,8 +127,6 @@ export const savePage = async ( message: 'Failed to update existing page', } } - pageId = existingPage.id - slug = existingPage.slug } else if (shouldParseInBackend(input)) { try { await createPageSaveRequest( diff --git a/packages/api/src/utils/uploads.ts b/packages/api/src/utils/uploads.ts index 814acc143..4c73c8780 100644 --- a/packages/api/src/utils/uploads.ts +++ b/packages/api/src/utils/uploads.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { env } from '../env' import { File, GetSignedUrlConfig, Storage } from '@google-cloud/storage' +import { env } from '../env' /* On GAE/Prod, we shall rely on default app engine service account credentials. * Two changes needed: 1) add default service account to our uploads GCS Bucket @@ -83,13 +83,6 @@ export const getStorageFileDetails = async ( id: string, fileName: string ): Promise<{ md5Hash: string; fileUrl: string }> => { - // if (env.dev.isLocal) { - // return { - // md5Hash: 'some_md5_hash', - // fileUrl: 'http://localhost:3000/public/' + id + '/' + fileName, - // } - // } - const filePathName = generateUploadFilePathName(id, fileName) const file = storage.bucket(bucketName).file(filePathName) const [metadata] = await file.getMetadata() From e84b517493b2ad0049a87430064c0932f5aa2866 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Tue, 21 Mar 2023 13:57:57 +0800 Subject: [PATCH 7/8] Do not update createdAt for existing page --- packages/api/src/services/save_page.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/api/src/services/save_page.ts b/packages/api/src/services/save_page.ts index de052d10d..1acb6ea17 100644 --- a/packages/api/src/services/save_page.ts +++ b/packages/api/src/services/save_page.ts @@ -118,6 +118,7 @@ export const savePage = async ( archivedAt: null, // unarchive if it was archived id: pageId, // we don't want to update the id slug, // we don't want to update the slug + createdAt: existingPage.createdAt, // we don't want to update the createdAt }, ctx )) @@ -236,7 +237,7 @@ export const parsedContentToPage = ({ hash: uploadFileHash || stringToHash(parsedContent?.content || url), image: parsedContent?.previewImage ?? undefined, publishedAt: validatedDate(parsedContent?.publishedDate ?? undefined), - uploadFileId: uploadFileId, + uploadFileId, readingProgressPercent: 0, readingProgressAnchorIndex: 0, state: ArticleSavingRequestStatus.Succeeded, From 013b460e39de774bd773c90e2adefca20a8b0955 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Tue, 21 Mar 2023 15:56:30 +0800 Subject: [PATCH 8/8] Check the permission to access page in elasticsearch --- packages/api/src/resolvers/highlight/index.ts | 50 +++++++++++-------- packages/api/src/resolvers/reminders/index.ts | 22 ++++---- packages/api/src/routers/article_router.ts | 7 +++ packages/api/src/routers/svc/integrations.ts | 12 +++-- packages/api/src/routers/text_to_speech.ts | 31 ++++++------ 5 files changed, 74 insertions(+), 48 deletions(-) diff --git a/packages/api/src/resolvers/highlight/index.ts b/packages/api/src/resolvers/highlight/index.ts index 55c2a7879..ec5c4f787 100644 --- a/packages/api/src/resolvers/highlight/index.ts +++ b/packages/api/src/resolvers/highlight/index.ts @@ -1,7 +1,15 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/require-await */ /* eslint-disable @typescript-eslint/no-floating-promises */ -import { authorized, unescapeHtml } from '../../utils/helpers' +import { + addHighlightToPage, + deleteHighlight, + getHighlightById, + updateHighlight, +} from '../../elastic/highlights' +import { getPageById, updatePage } from '../../elastic/pages' +import { Highlight as HighlightData } from '../../elastic/types' +import { env } from '../../env' import { CreateHighlightError, CreateHighlightErrorCode, @@ -26,16 +34,8 @@ import { UpdateHighlightSuccess, User, } from '../../generated/graphql' -import { env } from '../../env' import { analytics } from '../../utils/analytics' -import { Highlight as HighlightData } from '../../elastic/types' -import { getPageById, updatePage } from '../../elastic/pages' -import { - addHighlightToPage, - deleteHighlight, - getHighlightById, - updateHighlight, -} from '../../elastic/highlights' +import { authorized, unescapeHtml } from '../../utils/helpers' const highlightDataToHighlight = (highlight: HighlightData): Highlight => ({ ...highlight, @@ -58,16 +58,11 @@ export const createHighlightResolver = authorized< errorCodes: [CreateHighlightErrorCode.NotFound], } } - - analytics.track({ - userId: claims.uid, - event: 'highlight_created', - properties: { - pageId, - env: env.server.apiEnv, - }, - }) - + if (page.userId !== claims.uid) { + return { + errorCodes: [CreateHighlightErrorCode.Unauthorized], + } + } if (input.annotation && input.annotation.length > 4000) { return { errorCodes: [CreateHighlightErrorCode.BadData], @@ -108,6 +103,15 @@ export const createHighlightResolver = authorized< }, }) + analytics.track({ + userId: claims.uid, + event: 'highlight_created', + properties: { + pageId, + env: env.server.apiEnv, + }, + }) + return { highlight: highlightDataToHighlight(highlight) } } catch (err) { log.error('Error creating highlight', err) @@ -130,7 +134,11 @@ export const mergeHighlightResolver = authorized< errorCodes: [MergeHighlightErrorCode.NotFound], } } - + if (page.userId !== claims.uid) { + return { + errorCodes: [MergeHighlightErrorCode.Unauthorized], + } + } const articleHighlights = page.highlights /* Compute merged annotation form the order of highlights appearing on page */ diff --git a/packages/api/src/resolvers/reminders/index.ts b/packages/api/src/resolvers/reminders/index.ts index 66bc76a71..02c5cd236 100644 --- a/packages/api/src/resolvers/reminders/index.ts +++ b/packages/api/src/resolvers/reminders/index.ts @@ -1,4 +1,7 @@ -import { authorized } from '../../utils/helpers' +import { DateTime } from 'luxon' +import { getPageById } from '../../elastic/pages' +import { Page } from '../../elastic/types' +import { env } from '../../env' import { CreateReminderError, CreateReminderErrorCode, @@ -17,14 +20,11 @@ import { UpdateReminderErrorCode, UpdateReminderSuccess, } from '../../generated/graphql' -import { deleteTask, enqueueReminder } from '../../utils/createTask' -import { analytics } from '../../utils/analytics' -import { env } from '../../env' -import { DataModels } from '../types' -import { DateTime } from 'luxon' import { setLinkArchived } from '../../services/archive_link' -import { getPageById } from '../../elastic/pages' -import { Page } from '../../elastic/types' +import { analytics } from '../../utils/analytics' +import { deleteTask, enqueueReminder } from '../../utils/createTask' +import { authorized } from '../../utils/helpers' +import { DataModels } from '../types' const validScheduleTime = (str: string): Date | undefined => { const scheduleTime = DateTime.fromISO(str, { setZone: true }).set({ @@ -166,7 +166,11 @@ export const reminderResolver = authorized< errorCodes: [ReminderErrorCode.NotFound], } } - + if (page.userId !== uid) { + return { + errorCodes: [ReminderErrorCode.Unauthorized], + } + } const reminder = await models.reminder.getCreatedByParameters(uid, { elasticPageId: page.id, }) diff --git a/packages/api/src/routers/article_router.ts b/packages/api/src/routers/article_router.ts index d3543ab0f..988a94a2b 100644 --- a/packages/api/src/routers/article_router.ts +++ b/packages/api/src/routers/article_router.ts @@ -111,6 +111,13 @@ export function articleRouter() { if (!page) { return res.status(404).send('Page not found') } + if (page.userId !== uid) { + logger.info('User is not allowed to access speech of the article', { + userId: uid, + articleId, + }) + return res.status(401).send({ errorCode: 'UNAUTHORIZED' }) + } const speechFile = htmlToSpeechFile({ title: page.title, content: page.content, diff --git a/packages/api/src/routers/svc/integrations.ts b/packages/api/src/routers/svc/integrations.ts index 108c5efc7..03ccea762 100644 --- a/packages/api/src/routers/svc/integrations.ts +++ b/packages/api/src/routers/svc/integrations.ts @@ -3,12 +3,12 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ import express from 'express' import { EntityType, readPushSubscription } from '../../datalayer/pubsub' -import { getRepository } from '../../entity/utils' -import { Integration, IntegrationType } from '../../entity/integration' -import { buildLogger } from '../../utils/logger' -import { syncWithIntegration } from '../../services/integrations' import { getPageById, searchPages } from '../../elastic/pages' import { Page } from '../../elastic/types' +import { Integration, IntegrationType } from '../../entity/integration' +import { getRepository } from '../../entity/utils' +import { syncWithIntegration } from '../../services/integrations' +import { buildLogger } from '../../utils/logger' import { DateFilter } from '../../utils/search' export interface Message { @@ -89,6 +89,10 @@ export function integrationsServiceRouter() { res.status(200).send('No page found') return } + if (page.userId !== userId) { + logger.info('Page does not belong to user', { id, userId }) + return res.status(200).send('Page does not belong to user') + } // sync updated page with integration logger.info('syncing updated page with integration', { integrationId: integration.id, diff --git a/packages/api/src/routers/text_to_speech.ts b/packages/api/src/routers/text_to_speech.ts index 24cbcd0cf..4c86e7250 100644 --- a/packages/api/src/routers/text_to_speech.ts +++ b/packages/api/src/routers/text_to_speech.ts @@ -1,22 +1,22 @@ /* eslint-disable @typescript-eslint/no-misused-promises */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import express from 'express' -import cors from 'cors' -import { corsConfig } from '../utils/corsConfig' -import { getRepository, setClaims } from '../entity/utils' -import { getPageById } from '../elastic/pages' -import { Speech, SpeechState } from '../entity/speech' -import { buildLogger } from '../utils/logger' -import { getClaimsByToken } from '../utils/auth' -import { shouldSynthesize } from '../services/speech' -import { readPushSubscription } from '../datalayer/pubsub' -import { AppDataSource } from '../server' -import { enqueueTextToSpeech } from '../utils/createTask' import { htmlToSpeechFile } from '@omnivore/text-to-speech-handler' -import { UserPersonalization } from '../entity/user_personalization' +import cors from 'cors' +import express from 'express' +import { readPushSubscription } from '../datalayer/pubsub' +import { getPageById } from '../elastic/pages' import { ArticleSavingRequestStatus } from '../elastic/types' +import { Speech, SpeechState } from '../entity/speech' +import { UserPersonalization } from '../entity/user_personalization' +import { getRepository, setClaims } from '../entity/utils' +import { AppDataSource } from '../server' import { FeatureName, getFeature } from '../services/features' +import { shouldSynthesize } from '../services/speech' +import { getClaimsByToken } from '../utils/auth' +import { corsConfig } from '../utils/corsConfig' +import { enqueueTextToSpeech } from '../utils/createTask' +import { buildLogger } from '../utils/logger' const DEFAULT_VOICE = 'Larry' const DEFAULT_COMPLIMENTARY_VOICE = 'Evelyn' @@ -59,7 +59,10 @@ export function textToSpeechRouter() { logger.info('No page found', { id }) return res.status(200).send('No page found') } - + if (page.userId !== userId) { + logger.info('Page does not belong to user', { id, userId }) + return res.status(200).send('Page does not belong to user') + } if (page.state === ArticleSavingRequestStatus.Processing) { logger.info('Page is still processing, try again later', { id }) return res.status(400).send('Page is still processing')