diff --git a/packages/api/src/directives.ts b/packages/api/src/directives.ts index 292a546b8..15e212cb7 100644 --- a/packages/api/src/directives.ts +++ b/packages/api/src/directives.ts @@ -46,5 +46,43 @@ export const sanitizeDirectiveTransformer = (schema: GraphQLSchema) => { } return fieldConfig }, + [MapperKind.ARGUMENT]: (argConfig) => { + const sanitizeDirective = getDirective(schema, argConfig, 'sanitize')?.[0] + if (!sanitizeDirective) { + return argConfig + } + + const maxLength = sanitizeDirective.maxLength as number | undefined + const minLength = sanitizeDirective.minLength as number | undefined + const allowedTags = sanitizeDirective.allowedTags as string[] | undefined + const pattern = sanitizeDirective.pattern as string | undefined + + if ( + argConfig.type instanceof GraphQLNonNull && + argConfig.type.ofType instanceof GraphQLScalarType + ) { + argConfig.type = new GraphQLNonNull( + new SanitizedString( + argConfig.type.ofType, + allowedTags, + maxLength, + minLength, + pattern + ) + ) + } else if (argConfig.type instanceof GraphQLScalarType) { + argConfig.type = new SanitizedString( + argConfig.type, + allowedTags, + maxLength, + minLength, + pattern + ) + } else { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + throw new Error(`Not a scalar type: ${argConfig.type}`) + } + return argConfig + }, }) } diff --git a/packages/api/src/generated/schema.graphql b/packages/api/src/generated/schema.graphql index 7490fb535..2149a5ebd 100644 --- a/packages/api/src/generated/schema.graphql +++ b/packages/api/src/generated/schema.graphql @@ -1,4 +1,4 @@ -directive @sanitize(allowedTags: [String], maxLength: Int, minLength: Int, pattern: String) on INPUT_FIELD_DEFINITION +directive @sanitize(allowedTags: [String], maxLength: Int, minLength: Int, pattern: String) on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION type AddPopularReadError { errorCodes: [AddPopularReadErrorCode!]! diff --git a/packages/api/src/resolvers/article/index.ts b/packages/api/src/resolvers/article/index.ts index b87709e9a..defec536c 100644 --- a/packages/api/src/resolvers/article/index.ts +++ b/packages/api/src/resolvers/article/index.ts @@ -4,7 +4,6 @@ /* 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' @@ -73,7 +72,6 @@ import { } 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 { analytics } from '../../utils/analytics' @@ -953,14 +951,6 @@ export const searchResolver = authorized< } }) - // save query, including advanced search terms, in search history - if (params.query) { - const client = httpContext.get('client') as string | undefined - // don't save search history for rule based queries - client !== 'rule-handler' && - (await saveSearchHistory(claims.uid, params.query)) - } - return { edges, pageInfo: { diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index c409027c1..61f735b19 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -10,7 +10,7 @@ const schema = gql` maxLength: Int minLength: Int pattern: String - ) on INPUT_FIELD_DEFINITION + ) on INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION enum SortOrder { ASCENDING @@ -2542,7 +2542,7 @@ const schema = gql` search( after: String first: Int - query: String + query: String @sanitize(maxLength: 255) includeContent: Boolean format: String ): SearchResult! diff --git a/packages/api/test/resolvers/article.test.ts b/packages/api/test/resolvers/article.test.ts index 90047d3f7..def6ab376 100644 --- a/packages/api/test/resolvers/article.test.ts +++ b/packages/api/test/resolvers/article.test.ts @@ -20,7 +20,6 @@ import { PageContext, PageType, } from '../../src/elastic/types' -import { SearchHistory } from '../../src/entity/search_history' import { UploadFile } from '../../src/entity/upload_file' import { User } from '../../src/entity/user' import { getRepository } from '../../src/entity/utils' @@ -876,33 +875,6 @@ describe('Article API', () => { after(async () => { await deletePagesByParam({ userId: user.id }, ctx) - await getRepository(SearchHistory).delete({ user: { id: user.id } }) - }) - - context('when we search for a keyword', () => { - before(() => { - keyword = 'search api' - }) - - it('saves the term in search history', async () => { - await graphqlRequest(query, authToken).expect(200) - const searchHistories = await getRepository(SearchHistory).findBy({ - user: { id: user.id }, - }) - expect(searchHistories.length).to.eq(1) - expect(searchHistories[0].term).to.eq(keyword) - const searchHistory = searchHistories[0] - - // Check that the search history is updated - await graphqlRequest(query, authToken).expect(200) - const newSearchHistories = await getRepository(SearchHistory).findBy({ - user: { id: user.id }, - }) - expect(newSearchHistories.length).to.eq(1) - expect(newSearchHistories[0].createdAt).to.be.greaterThan( - searchHistory.createdAt - ) - }) }) context('when type:highlights is not in the query', () => {