@plusscommunities/pluss-newsletter-aws 2.0.2-beta.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,11 +2,12 @@ const uuid = require("uuid");
2
2
  const moment = require("moment");
3
3
  const initConfig = require("./initConfig");
4
4
  const { getRowId } = require("./common/helper");
5
+ const { isValidVideo } = require("./config/validVideoURLs");
5
6
  const generateJsonResponse = require("./common/helper/generateJsonResponse");
6
7
  const updateRef = require("./common/db/common/updateRef");
7
8
  const getRef = require("./common/db/common/getRef");
8
9
  const validateMasterAuth = require("./common/helper/auth/validateMasterAuth");
9
- const getSessionUser = require("./common/helper/auth/getSessionUser");
10
+ const getSessionUserFromReqAuthKey = require("@plusscommunities/pluss-core-aws/helper/auth/getSessionUserFromReqAuthKey");
10
11
  const getUserPreview = require("./common/helper/getUserPreview");
11
12
  const sendEmail = require("./common/helper/sendEmail");
12
13
  const newsletterSubmissionEmail = require("./common/templates/newsletterSubmissionEmail");
@@ -55,9 +56,21 @@ module.exports.addNewsletterEntry = (event, context, callback) => {
55
56
  data.update.IsFeaturedDate = null;
56
57
  }
57
58
 
59
+ if (data.update.Video) {
60
+ if (!isValidVideo(data.update.Video)) {
61
+ return callback(
62
+ null,
63
+ generateJsonResponse(400, {
64
+ message:
65
+ "The video URL is from a domain that is not recognized and therefore blocked for security reasons.",
66
+ })
67
+ );
68
+ }
69
+ }
70
+
58
71
  if (data.update.Notification) data.update.UnsentNotification = "X";
59
72
 
60
- getSessionUser(event.headers.authkey).then((uid) => {
73
+ getSessionUserFromReqAuthKey(event).then((uid) => {
61
74
  getUserPreview(uid).then((user) => {
62
75
  data.update.SubmittedBy = user;
63
76
  if (data.update.AuthorDisplay === "name") {
@@ -73,10 +86,8 @@ module.exports.addNewsletterEntry = (event, context, callback) => {
73
86
  console.error("Authorization not valid");
74
87
  callback(
75
88
  null,
76
- generateJsonResponse(422, {
77
- error: {
78
- message: "Authorization not valid.",
79
- },
89
+ generateJsonResponse(403, {
90
+ message: "Authorization not valid.",
80
91
  })
81
92
  );
82
93
  return;
@@ -95,7 +106,13 @@ module.exports.addNewsletterEntry = (event, context, callback) => {
95
106
  );
96
107
  })
97
108
  .catch((error) => {
98
- callback(null, generateJsonResponse(422, { error }));
109
+ console.log("error", error);
110
+ callback(
111
+ null,
112
+ generateJsonResponse(500, {
113
+ message: "Something went wrong.",
114
+ })
115
+ );
99
116
  });
100
117
  } else {
101
118
  updateRef(values.tableNameNewsletterSubmissions, data.update)
@@ -118,7 +135,13 @@ module.exports.addNewsletterEntry = (event, context, callback) => {
118
135
  );
119
136
  })
120
137
  .catch((error) => {
121
- callback(null, generateJsonResponse(422, { error }));
138
+ console.log("error", error);
139
+ callback(
140
+ null,
141
+ generateJsonResponse(500, {
142
+ message: "Something went wrong.",
143
+ })
144
+ );
122
145
  });
123
146
  }
124
147
  }
@@ -145,7 +168,13 @@ module.exports.addNewsletterEntry = (event, context, callback) => {
145
168
  );
146
169
  })
147
170
  .catch((error) => {
148
- callback(null, generateJsonResponse(422, { error }));
171
+ console.log("error", error);
172
+ callback(
173
+ null,
174
+ generateJsonResponse(500, {
175
+ message: "Something went wrong.",
176
+ })
177
+ );
149
178
  });
150
179
  }
151
180
  }
@@ -0,0 +1,40 @@
1
+ const _ = require("lodash");
2
+ const { log } = require("@plusscommunities/pluss-core-aws/helper");
3
+
4
+ const validVideoURLs = [
5
+ "youtube.com",
6
+ "youtu.be",
7
+ "vimeo.com",
8
+ `${process.env.tablePrefix}uploads.s3.ap-southeast-2.amazonaws.com`,
9
+ ];
10
+
11
+ /**
12
+ *
13
+ * @param {*} videoUrl Url of the video
14
+ * @returns {Boolean} true if the URL is valid. false if it should be blocked.
15
+ */
16
+ exports.isValidVideo = (videoUrl) => {
17
+ const logId = log("isValidVideo", "Start", videoUrl);
18
+ if (_.isEmpty(videoUrl)) {
19
+ log("isValidVideo", "Empty", videoUrl, logId);
20
+ return true;
21
+ }
22
+ try {
23
+ const host = new URL(videoUrl.toLowerCase()).host;
24
+ log("isValidVideo", "host", host, logId);
25
+
26
+ return _.some(validVideoURLs, (validUrl) => {
27
+ log("isValidVideo", "validUrl", validUrl, logId);
28
+ log(
29
+ "isValidVideo",
30
+ "isValid",
31
+ host === validUrl || host === `www.${validUrl}`,
32
+ logId
33
+ );
34
+ return host === validUrl || host === `www.${validUrl}`;
35
+ });
36
+ } catch (e) {
37
+ log("isValidVideo", "Error", e, logId);
38
+ }
39
+ return false;
40
+ };
@@ -1,5 +1,6 @@
1
1
  const moment = require("moment");
2
2
  const initConfig = require("./initConfig");
3
+ const { isValidVideo } = require("./config/validVideoURLs");
3
4
  const generateJsonResponse = require("./common/helper/generateJsonResponse");
4
5
  const editRef = require("./common/db/common/editRef");
5
6
  const getRef = require("./common/db/common/getRef");
@@ -21,15 +22,25 @@ module.exports.editNewsletterEntry = (event, context, callback) => {
21
22
  Number.MAX_SAFE_INTEGER - data.update.UnixTimestamp;
22
23
  }
23
24
 
25
+ if (data.update.Video) {
26
+ if (!isValidVideo(data.update.Video)) {
27
+ return callback(
28
+ null,
29
+ generateJsonResponse(400, {
30
+ message:
31
+ "The video URL is from a domain that is not recognized and therefore blocked for security reasons.",
32
+ })
33
+ );
34
+ }
35
+ }
36
+
24
37
  validateMasterAuth(event, values.permissionNewsletter).then((authorised) => {
25
38
  if (!authorised) {
26
39
  console.error("Authorization not valid");
27
40
  callback(
28
41
  null,
29
- generateJsonResponse(422, {
30
- error: {
31
- message: "Authorization not valid.",
32
- },
42
+ generateJsonResponse(403, {
43
+ message: "Authorization not valid.",
33
44
  })
34
45
  );
35
46
  return;
@@ -41,9 +52,7 @@ module.exports.editNewsletterEntry = (event, context, callback) => {
41
52
  return callback(
42
53
  null,
43
54
  generateJsonResponse(422, {
44
- error: {
45
- message: "Incorrect site.",
46
- },
55
+ message: "Incorrect site.",
47
56
  })
48
57
  );
49
58
  }
@@ -84,7 +93,11 @@ module.exports.editNewsletterEntry = (event, context, callback) => {
84
93
  return;
85
94
  })
86
95
  .catch((error) => {
87
- callback(null, generateJsonResponse(422, { error }));
96
+ console.log(error);
97
+ callback(
98
+ null,
99
+ generateJsonResponse(500, { message: "Something went wrong." })
100
+ );
88
101
  return;
89
102
  });
90
103
  }
package/feature.config.js CHANGED
@@ -13,3 +13,303 @@ exports.entity = {
13
13
  webPath: values.routeEntityPath,
14
14
  appPath: values.screenNewsletterPost,
15
15
  };
16
+
17
+ exports.serverless = {
18
+ name: values.serviceKey,
19
+ apis: [
20
+ {
21
+ name: "addNewsletterEntry",
22
+ file: "addNewsletterEntry",
23
+ function: "addNewsletterEntry",
24
+ memorySize: 1024,
25
+ timeout: 30,
26
+ path: "add",
27
+ method: "post",
28
+ headers: ["Content-Type", "authkey", "apikey"],
29
+ },
30
+ {
31
+ name: "editNewsletterEntry",
32
+ file: "editNewsletterEntry",
33
+ function: "editNewsletterEntry",
34
+ memorySize: 128,
35
+ timeout: 10,
36
+ path: "edit",
37
+ method: "post",
38
+ headers: ["Content-Type", "authkey", "apikey"],
39
+ },
40
+ {
41
+ name: "editNewsletterSubmission",
42
+ file: "editNewsletterSubmission",
43
+ function: "editNewsletterSubmission",
44
+ memorySize: 128,
45
+ timeout: 10,
46
+ path: "editSubmission",
47
+ method: "post",
48
+ headers: ["Content-Type", "authkey", "apikey"],
49
+ },
50
+ {
51
+ name: "getNewsletterEntry",
52
+ file: "getNewsletterEntry",
53
+ function: "getNewsletterEntry",
54
+ memorySize: 128,
55
+ timeout: 10,
56
+ path: "get/{id}",
57
+ method: "get",
58
+ headers: ["Content-Type", "authkey", "apikey"],
59
+ },
60
+ {
61
+ name: "getNews",
62
+ file: "getNews",
63
+ function: "getNews",
64
+ memorySize: 128,
65
+ timeout: 10,
66
+ path: "get2/{action}",
67
+ method: "get",
68
+ headers: ["Content-Type", "authkey", "apikey"],
69
+ },
70
+ {
71
+ name: "getNewsletterEntries",
72
+ file: "getNewsletterEntries",
73
+ function: "getNewsletterEntries",
74
+ memorySize: 1024,
75
+ timeout: 30,
76
+ path: "get",
77
+ method: "get",
78
+ headers: ["Content-Type", "authkey", "apikey"],
79
+ },
80
+ {
81
+ name: "getFeaturedNewsletterEntries",
82
+ file: "getFeaturedNewsletterEntries",
83
+ function: "getFeaturedNewsletterEntries",
84
+ memorySize: 128,
85
+ timeout: 10,
86
+ path: "getFeatured",
87
+ method: "get",
88
+ headers: ["Content-Type", "authkey", "apikey"],
89
+ },
90
+ {
91
+ name: "getRecentNewsletterEntries",
92
+ file: "getRecentNewsletterEntries",
93
+ function: "getRecentNewsletterEntries",
94
+ memorySize: 128,
95
+ timeout: 10,
96
+ path: "recent",
97
+ method: "get",
98
+ headers: ["Content-Type", "authkey", "apikey"],
99
+ },
100
+ {
101
+ name: "searchAvailableNews",
102
+ file: "searchAvailableNews",
103
+ function: "searchAvailableNews",
104
+ memorySize: 128,
105
+ timeout: 10,
106
+ path: "content/search",
107
+ method: "get",
108
+ headers: ["Content-Type", "authkey", "apikey"],
109
+ },
110
+ {
111
+ name: "getAvailableNews",
112
+ file: "getAvailableNews",
113
+ function: "getAvailableNews",
114
+ memorySize: 128,
115
+ timeout: 10,
116
+ path: "content/get",
117
+ method: "get",
118
+ headers: ["Content-Type", "authkey", "apikey"],
119
+ },
120
+ {
121
+ name: "getPublishedEntries",
122
+ file: "getPublishedEntries",
123
+ function: "getPublishedEntries",
124
+ memorySize: 128,
125
+ timeout: 10,
126
+ path: "content/specific",
127
+ method: "get",
128
+ headers: ["Content-Type", "authkey", "apikey"],
129
+ },
130
+ {
131
+ name: "getPublishedAvailableNews",
132
+ file: "getPublishedAvailableNews",
133
+ function: "getPublishedAvailableNews",
134
+ memorySize: 128,
135
+ timeout: 10,
136
+ path: "content/published",
137
+ method: "get",
138
+ headers: ["Content-Type", "authkey", "apikey"],
139
+ },
140
+ {
141
+ name: "deleteNewsletterEntry",
142
+ file: "deleteNewsletterEntry",
143
+ function: "deleteNewsletterEntry",
144
+ memorySize: 128,
145
+ timeout: 10,
146
+ path: "remove",
147
+ method: "post",
148
+ headers: ["Content-Type", "authkey", "apikey"],
149
+ },
150
+ {
151
+ name: "hasNewsletterAccess",
152
+ file: "hasNewsletterAccess",
153
+ function: "hasNewsletterAccess",
154
+ memorySize: 128,
155
+ timeout: 10,
156
+ path: "access",
157
+ method: "get",
158
+ headers: ["Content-Type", "authkey", "apikey"],
159
+ },
160
+ {
161
+ name: "getNewsletterSubmissions",
162
+ file: "getNewsletterSubmissions",
163
+ function: "getNewsletterSubmissions",
164
+ memorySize: 128,
165
+ timeout: 10,
166
+ path: "submissions/get",
167
+ method: "get",
168
+ headers: ["Content-Type", "authkey", "apikey"],
169
+ },
170
+ {
171
+ name: "getNewsletterSubmission",
172
+ file: "getNewsletterSubmission",
173
+ function: "getNewsletterSubmission",
174
+ memorySize: 128,
175
+ timeout: 10,
176
+ path: "submissions/get/{id}",
177
+ method: "get",
178
+ headers: ["Content-Type", "authkey", "apikey"],
179
+ },
180
+ {
181
+ name: "handleNewsletterSubmission",
182
+ file: "handleNewsletterSubmission",
183
+ function: "handleNewsletterSubmission",
184
+ memorySize: 128,
185
+ timeout: 10,
186
+ path: "submissions/handle",
187
+ method: "post",
188
+ headers: ["Content-Type", "authkey", "apikey"],
189
+ },
190
+ {
191
+ name: "getSubmissionCount",
192
+ file: "getSubmissionCount",
193
+ function: "getSubmissionCount",
194
+ memorySize: 128,
195
+ timeout: 10,
196
+ path: "submissions/count",
197
+ method: "get",
198
+ headers: ["Content-Type", "authkey", "apikey"],
199
+ },
200
+ {
201
+ name: "getTaggedNews",
202
+ file: "getTaggedNews",
203
+ function: "getTaggedNews",
204
+ memorySize: 128,
205
+ timeout: 10,
206
+ path: "tagged/get",
207
+ method: "get",
208
+ headers: ["Content-Type", "authkey", "apikey"],
209
+ },
210
+ ],
211
+ triggers: [
212
+ {
213
+ name: "newsletterChanged",
214
+ file: "newsletterChanged",
215
+ function: "newsletterChanged",
216
+ memorySize: 2048,
217
+ timeout: 30,
218
+ table: values.tableKeyNewsletterEntries,
219
+ },
220
+ ],
221
+ schedules: [
222
+ {
223
+ name: "watchNewsletter",
224
+ file: "watchNewsletter",
225
+ function: "watchNewsletter",
226
+ memorySize: "2048",
227
+ timeout: "300",
228
+ rate: "1/5 * * * ? *",
229
+ },
230
+ ],
231
+ tables: [
232
+ {
233
+ key: values.tableKeyNewsletterEntries,
234
+ name: values.tableNameNewsletterEntries,
235
+ attributes: [
236
+ { name: "RowId", type: "S" },
237
+ { name: "Site", type: "S" },
238
+ { name: "UnixTimestampReverse", type: "N" },
239
+ { name: "FeaturedExpiry", type: "N" },
240
+ { name: "SourceId", type: "S" },
241
+ { name: "UnsentNotification", type: "S" },
242
+ { name: "UnixTimestamp", type: "N" },
243
+ ],
244
+ id: "RowId",
245
+ indexes: [
246
+ {
247
+ name: "NewsletterEntriesSiteTimestampIndex",
248
+ keys: [
249
+ { name: "Site", type: "HASH" },
250
+ { name: "UnixTimestampReverse", type: "RANGE" },
251
+ ],
252
+ },
253
+ {
254
+ name: "NewsletterEntriesSiteFeaturedExpiryIndex",
255
+ keys: [
256
+ { name: "Site", type: "HASH" },
257
+ { name: "FeaturedExpiry", type: "RANGE" },
258
+ ],
259
+ },
260
+ {
261
+ name: "NewsletterEntriesSiteSourceIdIndex",
262
+ keys: [
263
+ { name: "Site", type: "HASH" },
264
+ { name: "SourceId", type: "RANGE" },
265
+ ],
266
+ },
267
+ {
268
+ name: "NewsletterEntriesUnsentNotiIndex",
269
+ keys: [
270
+ { name: "UnsentNotification", type: "HASH" },
271
+ { name: "UnixTimestamp", type: "RANGE" },
272
+ ],
273
+ },
274
+ ],
275
+ },
276
+ {
277
+ key: values.tableKeyNewsletterSubmissions,
278
+ name: values.tableNameNewsletterSubmissions,
279
+ attributes: [
280
+ { name: "RowId", type: "S" },
281
+ { name: "Site", type: "S" },
282
+ { name: "UnixTimestampReverse", type: "N" },
283
+ ],
284
+ id: "RowId",
285
+ indexes: [
286
+ {
287
+ name: "NewsletterSubmissionsSiteTimestampIndex",
288
+ keys: [
289
+ { name: "Site", type: "HASH" },
290
+ { name: "UnixTimestampReverse", type: "RANGE" },
291
+ ],
292
+ },
293
+ ],
294
+ },
295
+ {
296
+ key: values.tableKeyNewsletterUserEntries,
297
+ name: values.tableNameNewsletterUserEntries,
298
+ attributes: [
299
+ { name: "RowId", type: "S" },
300
+ { name: "UserId", type: "S" },
301
+ { name: "UnixTimestampReverse", type: "N" },
302
+ ],
303
+ id: "RowId",
304
+ indexes: [
305
+ {
306
+ name: "NewsletterUserEntriesUserIdTimestampIndex",
307
+ keys: [
308
+ { name: "UserId", type: "HASH" },
309
+ { name: "UnixTimestampReverse", type: "RANGE" },
310
+ ],
311
+ },
312
+ ],
313
+ },
314
+ ],
315
+ };