0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00

Added newsletter payload serializer

refs https://github.com/TryGhost/Arch/issues/87

- The newsletters in members payload have leaked internal properties from Public Members API. The code skipped the output serialization step, which is now in place.
- The newsletter resource returned from the API consistently returns these properties:
id,
name,
description,
sort_order
This commit is contained in:
Naz 2023-09-12 20:46:27 +08:00 committed by naz
parent a284e8275d
commit 282de7f0b4
5 changed files with 30 additions and 119 deletions

View file

@ -5,7 +5,10 @@ const emailSuppressionList = require('../email-suppression-list');
const models = require('../../models');
const urlUtils = require('../../../shared/url-utils');
const spamPrevention = require('../../web/shared/middleware/api/spam-prevention');
const {formattedMemberResponse} = require('./utils');
const {
formattedMemberResponse,
formatNewsletterResponse
} = require('./utils');
const errors = require('@tryghost/errors');
const tpl = require('@tryghost/tpl');
@ -144,6 +147,11 @@ const getMemberNewsletters = async function getMemberNewsletters(req, res) {
}
const data = _.pick(memberData.toJSON(), 'uuid', 'email', 'name', 'newsletters', 'enable_comment_notifications', 'status');
if (data.newsletters) {
data.newsletters = formatNewsletterResponse(data.newsletters);
}
return res.json(data);
} catch (err) {
res.writeHead(400);
@ -175,6 +183,11 @@ const updateMemberNewsletters = async function updateMemberNewsletters(req, res)
const updatedMember = await membersService.api.members.update(data, options);
const updatedMemberData = _.pick(updatedMember.toJSON(), ['uuid', 'email', 'name', 'newsletters', 'enable_comment_notifications', 'status']);
if (updatedMemberData.newsletters) {
updatedMemberData.newsletters = formatNewsletterResponse(updatedMemberData.newsletters);
}
res.json(updatedMemberData);
} catch (err) {
res.writeHead(400);

View file

@ -4,6 +4,7 @@ function formatNewsletterResponse(newsletters) {
});
}
module.exports.formatNewsletterResponse = formatNewsletterResponse;
module.exports.formattedMemberResponse = function formattedMemberResponse(member) {
if (!member) {
return null;

View file

@ -178,72 +178,16 @@ Object {
"name": "Test User",
"newsletters": Array [
Object {
"background_color": "light",
"body_font_category": "sans_serif",
"border_color": null,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": null,
"feedback_enabled": false,
"footer_content": null,
"header_image": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Default Newsletter",
"sender_email": null,
"sender_name": null,
"sender_reply_to": "newsletter",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
"show_header_icon": true,
"show_header_name": true,
"show_header_title": true,
"show_latest_posts": false,
"show_post_title_section": true,
"show_subscription_details": false,
"slug": "default-newsletter",
"sort_order": 0,
"status": "active",
"subscribe_on_signup": true,
"title_alignment": "center",
"title_color": null,
"title_font_category": "sans_serif",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "members",
},
Object {
"background_color": "light",
"body_font_category": "serif",
"border_color": null,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": null,
"feedback_enabled": false,
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Weekly newsletter",
"sender_email": "jamie@example.com",
"sender_name": "Jamie",
"sender_reply_to": "newsletter",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
"show_header_icon": true,
"show_header_name": true,
"show_header_title": true,
"show_latest_posts": false,
"show_post_title_section": true,
"show_subscription_details": false,
"slug": "weekly-newsletter",
"sort_order": 2,
"status": "active",
"subscribe_on_signup": true,
"title_alignment": "center",
"title_color": null,
"title_font_category": "serif",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "members",
},
],
"status": "free",
@ -255,7 +199,7 @@ exports[`Comments API when authenticated can update comment notifications 4: [he
Object {
"access-control-allow-origin": "*",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "1918",
"content-length": "354",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Encoding",
@ -408,38 +352,10 @@ Object {
"name": "Mr Egg",
"newsletters": Array [
Object {
"background_color": "light",
"body_font_category": "serif",
"border_color": null,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": null,
"feedback_enabled": false,
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": "jamie@example.com",
"sender_name": "Jamie",
"sender_reply_to": "newsletter",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
"show_header_icon": true,
"show_header_name": true,
"show_header_title": true,
"show_latest_posts": false,
"show_post_title_section": true,
"show_subscription_details": false,
"slug": "daily-newsletter",
"sort_order": 1,
"status": "active",
"subscribe_on_signup": false,
"title_alignment": "center",
"title_color": null,
"title_font_category": "serif",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "members",
},
],
"status": "free",
@ -451,7 +367,7 @@ exports[`Comments API when not authenticated but enabled can update comment noti
Object {
"access-control-allow-origin": "*",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "1064",
"content-length": "253",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Encoding",

View file

@ -23,10 +23,7 @@ const memberMatcherUnserialised = (newslettersCount) => {
uuid: anyUuid,
newsletters: new Array(newslettersCount).fill(
{
id: anyObjectId,
uuid: anyUuid,
created_at: anyISODateTime,
updated_at: anyISODateTime
id: anyObjectId
}
)
};

View file

@ -186,6 +186,15 @@ describe('Front-end members behavior', function () {
getJsonResponse.should.not.have.property('id');
getJsonResponse.newsletters.should.have.length(1);
// NOTE: these should be snapshots not code
Object.keys(getJsonResponse.newsletters[0]).should.have.length(4);
getJsonResponse.newsletters[0].should.have.properties([
'id',
'name',
'description',
'sort_order'
]);
// Can update newsletter subscription
const originalNewsletters = getJsonResponse.newsletters;
const originalNewsletterName = originalNewsletters[0].name;
@ -215,36 +224,12 @@ describe('Front-end members behavior', function () {
restoreJsonResponse.should.not.have.property('id');
restoreJsonResponse.newsletters.should.have.length(1);
// @NOTE: this seems like too much exposed information, needs a review
Object.keys(restoreJsonResponse.newsletters[0]).should.have.length(4);
restoreJsonResponse.newsletters[0].should.have.properties([
'id',
'uuid',
'name',
'description',
'feedback_enabled',
'slug',
'sender_name',
'sender_email',
'sender_reply_to',
'status',
'visibility',
'subscribe_on_signup',
'sort_order',
'header_image',
'show_header_icon',
'show_header_title',
'title_font_category',
'title_alignment',
'show_feature_image',
'body_font_category',
'footer_content',
'show_badge',
'show_header_name',
'show_post_title_section',
'show_comment_cta',
'show_subscription_details',
'show_latest_posts',
'created_at',
'updated_at'
'sort_order'
]);
should.equal(restoreJsonResponse.newsletters[0].name, originalNewsletterName);
@ -516,12 +501,11 @@ describe('Front-end members behavior', function () {
memberData.newsletters.should.have.length(1);
// @NOTE: this should be a snapshot test not code
Object.keys(memberData.newsletters[0]).should.have.length(5);
Object.keys(memberData.newsletters[0]).should.have.length(4);
memberData.newsletters[0].should.have.properties([
'id',
'name',
'description',
'status',
'sort_order'
]);
});