diff --git a/keyserver/src/endpoints.js b/keyserver/src/endpoints.js index 339b4033b..619d16ef2 100644 --- a/keyserver/src/endpoints.js +++ b/keyserver/src/endpoints.js @@ -1,99 +1,101 @@ // @flow import type { Endpoint } from 'lib/types/endpoints'; import { updateActivityResponder, threadSetUnreadStatusResponder, } from './responders/activity-responders'; import { deviceTokenUpdateResponder } from './responders/device-responders'; import { entryFetchResponder, entryRevisionFetchResponder, entryCreationResponder, entryUpdateResponder, entryDeletionResponder, entryRestorationResponder, calendarQueryUpdateResponder, } from './responders/entry-responders'; import type { JSONResponder } from './responders/handlers'; import { getSessionPublicKeysResponder } from './responders/keys-responders'; +import { messageReportCreationResponder } from './responders/message-report-responder'; import { textMessageCreationResponder, messageFetchResponder, multimediaMessageCreationResponder, } from './responders/message-responders'; import { updateRelationshipsResponder } from './responders/relationship-responders'; import { reportCreationResponder, reportMultiCreationResponder, errorReportFetchInfosResponder, } from './responders/report-responders'; import { userSearchResponder } from './responders/search-responders'; import { threadDeletionResponder, roleUpdateResponder, memberRemovalResponder, threadLeaveResponder, threadUpdateResponder, threadCreationResponder, threadJoinResponder, } from './responders/thread-responders'; import { userSubscriptionUpdateResponder, passwordUpdateResponder, sendVerificationEmailResponder, sendPasswordResetEmailResponder, logOutResponder, accountDeletionResponder, accountCreationResponder, logInResponder, oldPasswordUpdateResponder, updateUserSettingsResponder, } from './responders/user-responders'; import { codeVerificationResponder } from './responders/verification-responders'; import { uploadDeletionResponder } from './uploads/uploads'; const jsonEndpoints: { [id: Endpoint]: JSONResponder } = { create_account: accountCreationResponder, create_entry: entryCreationResponder, create_error_report: reportCreationResponder, + create_message_report: messageReportCreationResponder, create_multimedia_message: multimediaMessageCreationResponder, create_report: reportCreationResponder, create_reports: reportMultiCreationResponder, create_text_message: textMessageCreationResponder, create_thread: threadCreationResponder, delete_account: accountDeletionResponder, delete_entry: entryDeletionResponder, delete_thread: threadDeletionResponder, delete_upload: uploadDeletionResponder, fetch_entries: entryFetchResponder, fetch_entry_revisions: entryRevisionFetchResponder, fetch_error_report_infos: errorReportFetchInfosResponder, fetch_messages: messageFetchResponder, get_session_public_keys: getSessionPublicKeysResponder, join_thread: threadJoinResponder, leave_thread: threadLeaveResponder, log_in: logInResponder, log_out: logOutResponder, remove_members: memberRemovalResponder, restore_entry: entryRestorationResponder, search_users: userSearchResponder, send_password_reset_email: sendPasswordResetEmailResponder, send_verification_email: sendVerificationEmailResponder, set_thread_unread_status: threadSetUnreadStatusResponder, update_account: passwordUpdateResponder, update_activity: updateActivityResponder, update_calendar_query: calendarQueryUpdateResponder, update_user_settings: updateUserSettingsResponder, update_device_token: deviceTokenUpdateResponder, update_entry: entryUpdateResponder, update_password: oldPasswordUpdateResponder, update_relationships: updateRelationshipsResponder, update_role: roleUpdateResponder, update_thread: threadUpdateResponder, update_user_subscription: userSubscriptionUpdateResponder, verify_code: codeVerificationResponder, }; export { jsonEndpoints }; diff --git a/keyserver/src/responders/message-report-responder.js b/keyserver/src/responders/message-report-responder.js new file mode 100644 index 000000000..5463edda5 --- /dev/null +++ b/keyserver/src/responders/message-report-responder.js @@ -0,0 +1,34 @@ +// @flow + +import t from 'tcomb'; + +import { + type MessageReportCreationRequest, + type MessageReportCreationResult, +} from 'lib/types/message-report-types'; +import { tShape } from 'lib/utils/validation-utils'; + +import createMessageReport from '../creators/message-report-creator'; +import type { Viewer } from '../session/viewer'; +import { validateInput } from '../utils/validation-utils'; + +const messageReportCreationRequestInputValidator = tShape({ + messageID: t.String, +}); + +async function messageReportCreationResponder( + viewer: Viewer, + input: any, +): Promise { + await validateInput( + viewer, + messageReportCreationRequestInputValidator, + input, + ); + const request: MessageReportCreationRequest = input; + + const rawMessageInfos = await createMessageReport(viewer, request); + return { messageInfo: rawMessageInfos[0] }; +} + +export { messageReportCreationResponder }; diff --git a/lib/types/endpoints.js b/lib/types/endpoints.js index df07e65b8..af59b61e0 100644 --- a/lib/types/endpoints.js +++ b/lib/types/endpoints.js @@ -1,109 +1,110 @@ // @flow export type APIRequest = { endpoint: Endpoint, input: Object, }; export type SocketAPIHandler = (request: APIRequest) => Promise; export type Endpoint = | HTTPOnlyEndpoint | SocketOnlyEndpoint | HTTPPreferredEndpoint | SocketPreferredEndpoint; // Endpoints that can cause session changes should occur over HTTP, since the // socket code does not currently support changing sessions. In the future they // could be made to work for native, but cookie changes on web require HTTP // since websockets aren't able to Set-Cookie. Note that technically any // endpoint can cause a sessionChange, and in that case the server will close // the socket with a specific error code, and the client will proceed via HTTP. const sessionChangingEndpoints = Object.freeze({ LOG_OUT: 'log_out', DELETE_ACCOUNT: 'delete_account', CREATE_ACCOUNT: 'create_account', LOG_IN: 'log_in', UPDATE_PASSWORD: 'update_password', }); type SessionChangingEndpoint = $Values; // We do uploads over HTTP as well. This is because Websockets use TCP, which // guarantees ordering. That means that if we start an upload, any messages we // try to send the server after the upload starts will have to wait until the // upload ends. To avoid blocking other messages we upload using HTTP // multipart/form-data. const uploadEndpoints = Object.freeze({ UPLOAD_MULTIMEDIA: 'upload_multimedia', }); type UploadEndpoint = $Values; type HTTPOnlyEndpoint = SessionChangingEndpoint | UploadEndpoint; const socketOnlyEndpoints = Object.freeze({ UPDATE_ACTIVITY: 'update_activity', UPDATE_CALENDAR_QUERY: 'update_calendar_query', }); type SocketOnlyEndpoint = $Values; const socketPreferredEndpoints = Object.freeze({ CREATE_ENTRY: 'create_entry', CREATE_ERROR_REPORT: 'create_error_report', + CREATE_MESSAGE_REPORT: 'create_message_report', CREATE_MULTIMEDIA_MESSAGE: 'create_multimedia_message', CREATE_TEXT_MESSAGE: 'create_text_message', CREATE_THREAD: 'create_thread', DELETE_ENTRY: 'delete_entry', DELETE_THREAD: 'delete_thread', DELETE_UPLOAD: 'delete_upload', FETCH_ENTRIES: 'fetch_entries', FETCH_ENTRY_REVISIONS: 'fetch_entry_revisions', FETCH_ERROR_REPORT_INFOS: 'fetch_error_report_infos', FETCH_MESSAGES: 'fetch_messages', GET_SESSION_PUBLIC_KEYS: 'get_session_public_keys', JOIN_THREAD: 'join_thread', LEAVE_THREAD: 'leave_thread', REMOVE_MEMBERS: 'remove_members', REQUEST_ACCESS: 'request_access', RESTORE_ENTRY: 'restore_entry', SEARCH_USERS: 'search_users', SEND_PASSWORD_RESET_EMAIL: 'send_password_reset_email', SEND_VERIFICATION_EMAIL: 'send_verification_email', SET_THREAD_UNREAD_STATUS: 'set_thread_unread_status', UPDATE_ACCOUNT: 'update_account', UPDATE_USER_SETTINGS: 'update_user_settings', UPDATE_DEVICE_TOKEN: 'update_device_token', UPDATE_ENTRY: 'update_entry', UPDATE_RELATIONSHIPS: 'update_relationships', UPDATE_ROLE: 'update_role', UPDATE_THREAD: 'update_thread', UPDATE_USER_SUBSCRIPTION: 'update_user_subscription', VERIFY_CODE: 'verify_code', }); type SocketPreferredEndpoint = $Values; const httpPreferredEndpoints = Object.freeze({ CREATE_REPORT: 'create_report', CREATE_REPORTS: 'create_reports', }); type HTTPPreferredEndpoint = $Values; const socketPreferredEndpointSet = new Set([ ...Object.values(socketOnlyEndpoints), ...Object.values(socketPreferredEndpoints), ]); export function endpointIsSocketPreferred(endpoint: Endpoint): boolean { return socketPreferredEndpointSet.has(endpoint); } const socketSafeEndpointSet = new Set([ ...Object.values(socketOnlyEndpoints), ...Object.values(socketPreferredEndpoints), ...Object.values(httpPreferredEndpoints), ]); export function endpointIsSocketSafe(endpoint: Endpoint): boolean { return socketSafeEndpointSet.has(endpoint); } const socketOnlyEndpointSet = new Set(Object.values(socketOnlyEndpoints)); export function endpointIsSocketOnly(endpoint: Endpoint): boolean { return socketOnlyEndpointSet.has(endpoint); }