Use SecurityID in destructive campaign actions

Using POST rather than PUT because SecurityToken->checkRequest()
doesn't accept PUT data (it's only in the request body, not
in $_POST and HTTPRequest->requestVars()).
This commit is contained in:
Ingo Schommer 2016-04-18 08:26:24 +12:00 committed by Damian Mooyman
parent 572d8427e0
commit e840ba805e
3 changed files with 25 additions and 10 deletions

View File

@ -27,9 +27,9 @@ class CampaignAdmin extends LeftAndMain implements PermissionProvider {
private static $url_handlers = [
'GET sets' => 'readCampaigns',
'POST set/$ID/publish' => 'publishCampaign',
'POST set/$ID' => 'createCampaign',
'GET set/$ID/$Name' => 'readCampaign',
'PUT set/$ID/publish' => 'publishCampaign',
'PUT set/$ID' => 'updateCampaign',
'DELETE set/$ID' => 'deleteCampaign',
];
@ -66,7 +66,7 @@ class CampaignAdmin extends LeftAndMain implements PermissionProvider {
'itemListViewEndpoint' => $this->Link('set/:id/show'),
'publishEndpoint' => [
'url' => $this->Link('set/:id/publish'),
'method' => 'put'
'method' => 'post'
]
]);
}
@ -431,6 +431,12 @@ JSON;
* @return SS_HTTPResponse
*/
public function publishCampaign(SS_HTTPRequest $request) {
// Protect against CSRF on destructive action
if(!SecurityToken::inst()->checkRequest($request)) {
return (new SS_HTTPResponse(json_encode(['status' => 'error']), 400))
->addHeader('Content-Type', 'application/json');
}
$id = $request->param('ID');
if(!$id || !is_numeric($id)) {
return (new SS_HTTPResponse(json_encode(['status' => 'error']), 400))

View File

@ -194,6 +194,10 @@ class LeftAndMain extends Controller implements PermissionProvider {
$combinedClientConfig['sections'][$className] = Injector::inst()->get($className)->getClientConfig();
}
// Get "global" CSRF token for use in JavaScript
$token = new SecurityToken();
$combinedClientConfig[$token->getName()] = $token->getValue();
return Convert::raw2json($combinedClientConfig);
}

View File

@ -18,8 +18,9 @@ class CampaignAdminContainer extends SilverStripeComponent {
this.addCampaign = this.addCampaign.bind(this);
this.createFn = this.createFn.bind(this);
this.publishApi = backend.createEndpointFetcher({
url: this.props.config.publishEndpoint.url,
method: this.props.config.publishEndpoint.method,
url: this.props.sectionConfig.publishEndpoint.url,
method: this.props.sectionConfig.publishEndpoint.method,
defaultData: { SecurityID: this.props.config.SecurityID },
payloadSchema: {
id: { urlReplacement: ':id', remove: true },
},
@ -27,7 +28,7 @@ class CampaignAdminContainer extends SilverStripeComponent {
}
componentDidMount() {
window.ss.router(`/${this.props.config.campaignViewRoute}`, (ctx) => {
window.ss.router(`/${this.props.sectionConfig.campaignViewRoute}`, (ctx) => {
this.props.actions.showCampaignView(ctx.params.id, ctx.params.view);
});
}
@ -55,7 +56,7 @@ class CampaignAdminContainer extends SilverStripeComponent {
* @return object
*/
renderIndexView() {
const schemaUrl = this.props.config.forms.editForm.schemaUrl;
const schemaUrl = this.props.sectionConfig.forms.editForm.schemaUrl;
return (
<div className="cms-middle no-preview">
@ -80,7 +81,7 @@ class CampaignAdminContainer extends SilverStripeComponent {
renderItemListView() {
const props = {
campaignId: this.props.campaignId,
itemListViewEndpoint: this.props.config.itemListViewEndpoint,
itemListViewEndpoint: this.props.sectionConfig.itemListViewEndpoint,
publishApi: this.publishApi,
};
@ -105,7 +106,7 @@ class CampaignAdminContainer extends SilverStripeComponent {
* @return object - Instanciated React component
*/
createFn(Component, props) {
const campaignViewRoute = this.props.config.campaignViewRoute;
const campaignViewRoute = this.props.sectionConfig.campaignViewRoute;
if (props.component === 'GridField') {
const extendedProps = Object.assign({}, props, {
@ -149,19 +150,23 @@ class CampaignAdminContainer extends SilverStripeComponent {
}
CampaignAdminContainer.propTypes = {
config: React.PropTypes.shape({
sectionConfig: React.PropTypes.shape({
forms: React.PropTypes.shape({
editForm: React.PropTypes.shape({
schemaUrl: React.PropTypes.string,
}),
}),
}),
config: React.PropTypes.shape({
SecurityID: React.PropTypes.string,
}),
sectionConfigKey: React.PropTypes.string.isRequired,
};
function mapStateToProps(state, ownProps) {
return {
config: state.config.sections[ownProps.sectionConfigKey],
config: state.config,
sectionConfig: state.config.sections[ownProps.sectionConfigKey],
campaignId: state.campaign.campaignId,
view: state.campaign.view,
};