@devvit/public-api 0.11.5-next-2024-12-16-92b65c499.0 → 0.11.5-next-2024-12-16-1e32d9060.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../../../src/devvit/internals/csrf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAGjF,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAO7E,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,WAAW,GAAG,iBAAiB,EACxC,GAAG,EAAE,oBAAoB,iBA6D1B;AAiBD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,WAAW,GAAG,iBAAiB,EACxC,GAAG,EAAE,oBAAoB,iBAc1B"}
1
+ {"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../../../src/devvit/internals/csrf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAGjF,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAuB7E,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,WAAW,GAAG,iBAAiB,EACxC,GAAG,EAAE,oBAAoB,iBAmF1B;AAWD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,WAAW,GAAG,iBAAiB,EACxC,GAAG,EAAE,oBAAoB,iBAc1B"}
@@ -1,6 +1,32 @@
1
1
  import { Header } from '@devvit/shared-types/Header.js';
2
2
  import { getMenuItemById } from './menu-items.js';
3
+ function getUserHeader(context) {
4
+ const userHeader = context.debug.metadata[Header.User].values[0];
5
+ if (!userHeader) {
6
+ throw new Error('User missing from context');
7
+ }
8
+ return userHeader;
9
+ }
10
+ function getSubredditHeader(context) {
11
+ const subredditHeader = context.debug.metadata[Header.Subreddit].values[0];
12
+ if (!subredditHeader) {
13
+ throw new Error('Subreddit missing from context');
14
+ }
15
+ return subredditHeader;
16
+ }
3
17
  export async function addCSRFTokenToContext(context, req) {
18
+ /**
19
+ * These headers represent the canonical user and subreddit for the current context. The user is validated by gateway against
20
+ * the edge context, so we trust it.
21
+ */
22
+ const userHeader = getUserHeader(context);
23
+ const subredditHeader = getSubredditHeader(context);
24
+ if (!userHeader || !subredditHeader) {
25
+ throw new Error('User or subreddit missing from context');
26
+ }
27
+ /**
28
+ * These are the target ids for the action. They are provided by the user, but we need to validate them.
29
+ */
4
30
  const commentId = req.comment?.id && `t1_${req.comment.id}`;
5
31
  const postId = req.post?.id && `t3_${req.post.id}`;
6
32
  const subredditId = req.subreddit?.id && `t5_${req.subreddit.id}`;
@@ -8,32 +34,39 @@ export async function addCSRFTokenToContext(context, req) {
8
34
  if (!targetId) {
9
35
  throw new Error('targetId is missing from ContextActionRequest');
10
36
  }
11
- const currentUser = context.debug.metadata[Header.User].values[0];
12
- const subredditHeader = context.debug.metadata[Header.Subreddit].values[0];
13
- if (!currentUser || !subredditHeader) {
14
- throw new Error('User or subreddit missing from context');
15
- }
37
+ /**
38
+ * Validate user-provided commentId
39
+ */
16
40
  if (commentId) {
17
41
  const comment = await context.reddit.getCommentById(commentId);
18
42
  if (!comment) {
19
43
  throw new Error(`Comment ${commentId} not found`);
20
44
  }
21
- if (comment.subredditId !== subredditId) {
22
- throw new Error('Comment does not belong to the subreddit');
45
+ if (comment.subredditId !== subredditHeader) {
46
+ throw new Error(`Comment does not belong to the subreddit`);
23
47
  }
24
48
  }
49
+ /**
50
+ * Validate user-provided postId
51
+ */
25
52
  if (postId) {
26
53
  const post = await context.reddit.getPostById(postId);
27
54
  if (!post) {
28
55
  throw new Error(`Post ${postId} not found`);
29
56
  }
30
- if (post.subredditId !== subredditId) {
31
- throw new Error('Post does not belong to the subreddit');
57
+ if (post.subredditId !== subredditHeader) {
58
+ throw new Error(`Post does not belong to the subreddit`);
32
59
  }
33
60
  }
61
+ /**
62
+ * Validate user-provided subredditId
63
+ */
34
64
  if (subredditId && subredditId !== subredditHeader) {
35
65
  throw new Error(`Subreddit ${subredditId} ${subredditHeader} not found`);
36
66
  }
67
+ /**
68
+ * Validate moderator status if needed
69
+ */
37
70
  const thisItem = getMenuItemById(req.actionId);
38
71
  if (!thisItem) {
39
72
  throw new Error('Action not found');
@@ -45,34 +78,31 @@ export async function addCSRFTokenToContext(context, req) {
45
78
  const val = {
46
79
  needsModCheck,
47
80
  };
48
- await context.redis.set(`${currentUser}${subredditHeader}${targetId}${req.actionId}`, JSON.stringify(val));
49
- await context.redis.expire(`${currentUser}${subredditHeader}${targetId}${req.actionId}`, 600);
81
+ /**
82
+ * Store a CSRF token in redis for this action. There's no way to pass this along, so we need to store it in redis.
83
+ */
84
+ await context.redis.set(`${userHeader}${subredditHeader}${targetId}${req.actionId}`, JSON.stringify(val));
85
+ await context.redis.expire(`${userHeader}${subredditHeader}${targetId}${req.actionId}`, 600);
50
86
  console.debug('CSRF token added: ' + JSON.stringify(val));
51
87
  }
52
88
  async function isModerator(context) {
53
- const currentUser = context.debug.metadata[Header.User].values[0];
54
- if (!currentUser) {
55
- throw new Error('User missing from context');
56
- }
57
- const subredditHeader = context.debug.metadata[Header.Subreddit].values[0];
58
- if (!subredditHeader) {
59
- throw new Error('Subreddit missing from context');
60
- }
89
+ const userHeader = getUserHeader(context);
90
+ const subredditHeader = getSubredditHeader(context);
61
91
  const subreddit = await context.reddit.getSubredditInfoById(subredditHeader);
62
92
  const mods = await context.reddit.getModerators({ subredditName: subreddit.name }).all();
63
- return !!mods.find((mod) => mod.id === currentUser);
93
+ return !!mods.find((mod) => mod.id === userHeader);
64
94
  }
65
95
  export async function validateCSRFToken(context, req) {
66
- const currentUser = context.debug.metadata[Header.User].values[0];
67
- const subredditHeader = context.debug.metadata[Header.Subreddit].values[0];
96
+ const userHeader = getUserHeader(context);
97
+ const subredditHeader = getSubredditHeader(context);
68
98
  const { actionId, thingId } = req.state?.__contextAction ?? {};
69
- const csrfData = await context.redis.get(`${currentUser}${subredditHeader}${thingId}${actionId}`);
99
+ const csrfData = await context.redis.get(`${userHeader}${subredditHeader}${thingId}${actionId}`);
70
100
  if (!csrfData) {
71
101
  throw new Error('CSRF token not found');
72
102
  }
73
103
  const csrf = JSON.parse(csrfData);
74
104
  if (csrf.needsModCheck && !(await isModerator(context))) {
75
- throw new Error('User is not a moderator: ' + currentUser + '; ' + subredditHeader);
105
+ throw new Error('User is not a moderator: ' + userHeader + '; ' + subredditHeader);
76
106
  }
77
107
  console.debug('CSRF token validated: ' + csrfData);
78
108
  }
package/meta.json CHANGED
@@ -10411,7 +10411,7 @@
10411
10411
  "format": "esm"
10412
10412
  },
10413
10413
  "src/devvit/internals/csrf.ts": {
10414
- "bytes": 3712,
10414
+ "bytes": 4559,
10415
10415
  "imports": [
10416
10416
  {
10417
10417
  "path": "../shared-types/dist/Header.js",
@@ -12797,7 +12797,7 @@
12797
12797
  "bytesInOutput": 663
12798
12798
  },
12799
12799
  "src/devvit/internals/csrf.ts": {
12800
- "bytesInOutput": 3359
12800
+ "bytesInOutput": 3505
12801
12801
  },
12802
12802
  "src/devvit/internals/menu-items.ts": {
12803
12803
  "bytesInOutput": 2374
@@ -12944,7 +12944,7 @@
12944
12944
  "bytesInOutput": 370
12945
12945
  }
12946
12946
  },
12947
- "bytes": 12713357
12947
+ "bytes": 12714715
12948
12948
  }
12949
12949
  }
12950
12950
  }
package/meta.min.json CHANGED
@@ -3271,7 +3271,7 @@
3271
3271
  "format": "esm"
3272
3272
  },
3273
3273
  "src/devvit/internals/csrf.ts": {
3274
- "bytes": 3712,
3274
+ "bytes": 4559,
3275
3275
  "imports": [
3276
3276
  {
3277
3277
  "path": "../shared-types/dist/Header.js",
@@ -4815,7 +4815,7 @@
4815
4815
  "imports": [],
4816
4816
  "exports": [],
4817
4817
  "inputs": {},
4818
- "bytes": 1240229
4818
+ "bytes": 1241211
4819
4819
  },
4820
4820
  "dist/public-api.min.js": {
4821
4821
  "imports": [
@@ -5522,7 +5522,7 @@
5522
5522
  "bytesInOutput": 1322
5523
5523
  },
5524
5524
  "src/devvit/internals/csrf.ts": {
5525
- "bytesInOutput": 1864
5525
+ "bytesInOutput": 1802
5526
5526
  },
5527
5527
  "src/devvit/internals/plugins.ts": {
5528
5528
  "bytesInOutput": 47
@@ -5621,7 +5621,7 @@
5621
5621
  "bytesInOutput": 4081
5622
5622
  },
5623
5623
  "src/apis/reddit/models/Post.ts": {
5624
- "bytesInOutput": 14649
5624
+ "bytesInOutput": 14651
5625
5625
  },
5626
5626
  "src/apis/reddit/helpers/textFallbackToRichtext.ts": {
5627
5627
  "bytesInOutput": 114
@@ -5663,7 +5663,7 @@
5663
5663
  "bytesInOutput": 178
5664
5664
  }
5665
5665
  },
5666
- "bytes": 264865
5666
+ "bytes": 264805
5667
5667
  }
5668
5668
  }
5669
5669
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devvit/public-api",
3
- "version": "0.11.5-next-2024-12-16-92b65c499.0",
3
+ "version": "0.11.5-next-2024-12-16-1e32d9060.0",
4
4
  "license": "BSD-3-Clause",
5
5
  "repository": {
6
6
  "type": "git",
@@ -30,8 +30,8 @@
30
30
  },
31
31
  "types": "./index.d.ts",
32
32
  "dependencies": {
33
- "@devvit/protos": "0.11.5-next-2024-12-16-92b65c499.0",
34
- "@devvit/shared-types": "0.11.5-next-2024-12-16-92b65c499.0",
33
+ "@devvit/protos": "0.11.5-next-2024-12-16-1e32d9060.0",
34
+ "@devvit/shared-types": "0.11.5-next-2024-12-16-1e32d9060.0",
35
35
  "base64-js": "1.5.1",
36
36
  "clone-deep": "4.0.1",
37
37
  "core-js": "3.27.2",
@@ -39,8 +39,8 @@
39
39
  },
40
40
  "devDependencies": {
41
41
  "@ampproject/filesize": "4.3.0",
42
- "@devvit/repo-tools": "0.11.5-next-2024-12-16-92b65c499.0",
43
- "@devvit/tsconfig": "0.11.5-next-2024-12-16-92b65c499.0",
42
+ "@devvit/repo-tools": "0.11.5-next-2024-12-16-1e32d9060.0",
43
+ "@devvit/tsconfig": "0.11.5-next-2024-12-16-1e32d9060.0",
44
44
  "@microsoft/api-extractor": "7.41.0",
45
45
  "@reddit/faceplate-ui": "18.0.1",
46
46
  "@types/clone-deep": "4.0.1",
@@ -63,5 +63,5 @@
63
63
  }
64
64
  },
65
65
  "source": "./src/index.ts",
66
- "gitHead": "63602e268b86ed7509c35c24f98027ada87858bf"
66
+ "gitHead": "c88bcd7a5e1b8e57514e956d8ecfa710fc0f67b1"
67
67
  }