From 2e8a492e8843aa958c53636b24cf4d344e7ca47d Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Sun, 25 Feb 2018 03:16:11 +0900 Subject: Raise Mastodon::HostValidationError when host for HTTP request is private (#6410) --- app/lib/exceptions.rb | 1 + app/lib/request.rb | 19 ++++++++++++++++++- app/lib/sidekiq_error_handler.rb | 11 +++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 app/lib/sidekiq_error_handler.rb (limited to 'app/lib') diff --git a/app/lib/exceptions.rb b/app/lib/exceptions.rb index b2489711d..95e3365c2 100644 --- a/app/lib/exceptions.rb +++ b/app/lib/exceptions.rb @@ -4,6 +4,7 @@ module Mastodon class Error < StandardError; end class NotPermittedError < Error; end class ValidationError < Error; end + class HostValidationError < ValidationError; end class RaceConditionError < Error; end class UnexpectedResponseError < Error diff --git a/app/lib/request.rb b/app/lib/request.rb index 7671f4ffc..5776b3d78 100644 --- a/app/lib/request.rb +++ b/app/lib/request.rb @@ -1,5 +1,8 @@ # frozen_string_literal: true +require 'ipaddr' +require 'socket' + class Request REQUEST_TARGET = '(request-target)' @@ -8,7 +11,7 @@ class Request def initialize(verb, url, **options) @verb = verb @url = Addressable::URI.parse(url).normalize - @options = options + @options = options.merge(socket_class: Socket) @headers = {} set_common_headers! @@ -87,4 +90,18 @@ class Request def http_client HTTP.timeout(:per_operation, timeout).follow(max_hops: 2) end + + class Socket < TCPSocket + class << self + def open(host, *args) + address = IPSocket.getaddress(host) + raise Mastodon::HostValidationError if PrivateAddressCheck.private_address? IPAddr.new(address) + super address, *args + end + + alias new open + end + end + + private_constant :Socket end diff --git a/app/lib/sidekiq_error_handler.rb b/app/lib/sidekiq_error_handler.rb new file mode 100644 index 000000000..23785cf05 --- /dev/null +++ b/app/lib/sidekiq_error_handler.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class SidekiqErrorHandler + def call(*) + yield + rescue Mastodon::HostValidationError => e + Rails.logger.error "#{e.class}: #{e.message}" + Rails.logger.error e.backtrace.join("\n") + # Do not retry + end +end -- cgit From 41a01bec2337e7021634f2e9c78d86a1c3002fcf Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 28 Feb 2018 06:54:55 +0100 Subject: Federated reports (#6570) * Fix #2176: Federated reports * UI for federated reports * Add spec for ActivityPub Flag handler * Add spec for ReportService --- app/controllers/api/v1/reports_controller.rb | 12 ++-- app/javascript/mastodon/actions/reports.js | 9 +++ .../features/ui/components/report_modal.js | 44 ++++++++---- app/javascript/mastodon/reducers/reports.js | 4 ++ app/javascript/styles/mastodon/components.scss | 84 ++++++++++++++++++++-- app/lib/activitypub/activity.rb | 2 + app/lib/activitypub/activity/flag.rb | 25 +++++++ app/models/report.rb | 4 ++ app/serializers/activitypub/flag_serializer.rb | 27 +++++++ app/services/report_service.rb | 54 ++++++++++++++ db/schema.rb | 1 + spec/lib/activitypub/activity/flag_spec.rb | 37 ++++++++++ spec/services/report_service_spec.rb | 25 +++++++ 13 files changed, 306 insertions(+), 22 deletions(-) create mode 100644 app/lib/activitypub/activity/flag.rb create mode 100644 app/serializers/activitypub/flag_serializer.rb create mode 100644 app/services/report_service.rb create mode 100644 spec/lib/activitypub/activity/flag_spec.rb create mode 100644 spec/services/report_service_spec.rb (limited to 'app/lib') diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb index 22828217d..f5095e073 100644 --- a/app/controllers/api/v1/reports_controller.rb +++ b/app/controllers/api/v1/reports_controller.rb @@ -13,14 +13,14 @@ class Api::V1::ReportsController < Api::BaseController end def create - @report = current_account.reports.create!( - target_account: reported_account, + @report = ReportService.new.call( + current_account, + reported_account, status_ids: reported_status_ids, - comment: report_params[:comment] + comment: report_params[:comment], + forward: report_params[:forward] ) - User.staff.includes(:account).each { |u| AdminMailer.new_report(u.account, @report).deliver_later } - render json: @report, serializer: REST::ReportSerializer end @@ -39,6 +39,6 @@ class Api::V1::ReportsController < Api::BaseController end def report_params - params.permit(:account_id, :comment, status_ids: []) + params.permit(:account_id, :comment, :forward, status_ids: []) end end diff --git a/app/javascript/mastodon/actions/reports.js b/app/javascript/mastodon/actions/reports.js index b19a07285..afa0c3412 100644 --- a/app/javascript/mastodon/actions/reports.js +++ b/app/javascript/mastodon/actions/reports.js @@ -10,6 +10,7 @@ export const REPORT_SUBMIT_FAIL = 'REPORT_SUBMIT_FAIL'; export const REPORT_STATUS_TOGGLE = 'REPORT_STATUS_TOGGLE'; export const REPORT_COMMENT_CHANGE = 'REPORT_COMMENT_CHANGE'; +export const REPORT_FORWARD_CHANGE = 'REPORT_FORWARD_CHANGE'; export function initReport(account, status) { return dispatch => { @@ -45,6 +46,7 @@ export function submitReport() { account_id: getState().getIn(['reports', 'new', 'account_id']), status_ids: getState().getIn(['reports', 'new', 'status_ids']), comment: getState().getIn(['reports', 'new', 'comment']), + forward: getState().getIn(['reports', 'new', 'forward']), }).then(response => { dispatch(closeModal()); dispatch(submitReportSuccess(response.data)); @@ -78,3 +80,10 @@ export function changeReportComment(comment) { comment, }; }; + +export function changeReportForward(forward) { + return { + type: REPORT_FORWARD_CHANGE, + forward, + }; +}; diff --git a/app/javascript/mastodon/features/ui/components/report_modal.js b/app/javascript/mastodon/features/ui/components/report_modal.js index b5dfa422e..3a7e4df76 100644 --- a/app/javascript/mastodon/features/ui/components/report_modal.js +++ b/app/javascript/mastodon/features/ui/components/report_modal.js @@ -1,6 +1,6 @@ import React from 'react'; import { connect } from 'react-redux'; -import { changeReportComment, submitReport } from '../../../actions/reports'; +import { changeReportComment, changeReportForward, submitReport } from '../../../actions/reports'; import { refreshAccountTimeline } from '../../../actions/timelines'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; @@ -10,6 +10,7 @@ import StatusCheckBox from '../../report/containers/status_check_box_container'; import { OrderedSet } from 'immutable'; import ImmutablePureComponent from 'react-immutable-pure-component'; import Button from '../../../components/button'; +import Toggle from 'react-toggle'; const messages = defineMessages({ placeholder: { id: 'report.placeholder', defaultMessage: 'Additional comments' }, @@ -26,6 +27,7 @@ const makeMapStateToProps = () => { isSubmitting: state.getIn(['reports', 'new', 'isSubmitting']), account: getAccount(state, accountId), comment: state.getIn(['reports', 'new', 'comment']), + forward: state.getIn(['reports', 'new', 'forward']), statusIds: OrderedSet(state.getIn(['timelines', `account:${accountId}`, 'items'])).union(state.getIn(['reports', 'new', 'status_ids'])), }; }; @@ -42,14 +44,19 @@ export default class ReportModal extends ImmutablePureComponent { account: ImmutablePropTypes.map, statusIds: ImmutablePropTypes.orderedSet.isRequired, comment: PropTypes.string.isRequired, + forward: PropTypes.bool, dispatch: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, }; - handleCommentChange = (e) => { + handleCommentChange = e => { this.props.dispatch(changeReportComment(e.target.value)); } + handleForwardChange = e => { + this.props.dispatch(changeReportForward(e.target.checked)); + } + handleSubmit = () => { this.props.dispatch(submitReport()); } @@ -65,12 +72,14 @@ export default class ReportModal extends ImmutablePureComponent { } render () { - const { account, comment, intl, statusIds, isSubmitting } = this.props; + const { account, comment, intl, statusIds, isSubmitting, forward } = this.props; if (!account) { return null; } + const domain = account.get('acct').split('@')[1]; + return (
@@ -78,13 +87,9 @@ export default class ReportModal extends ImmutablePureComponent {
-
-
- {statusIds.map(statusId => )} -
-
-
+

+