@devvit/ui-renderer 0.10.11-next-2023-12-12-e793f90f9.0 → 0.10.11-next-2023-12-12-ce6339b27.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.
@@ -486,7 +486,7 @@ export function imageStyle(url, resizeMode, width, height) {
486
486
  size['backgroundSize'] = `${width}px ${height}px`;
487
487
  }
488
488
  return {
489
- backgroundImage: `url(${url})`,
489
+ backgroundImage: `url('${url}')`,
490
490
  width: `${width}px`,
491
491
  height: `${height}px`,
492
492
  ...size,
@@ -1 +1 @@
1
- {"version":3,"file":"renderImageBlock.d.ts","sourceRoot":"","sources":["../../../library/src/blocks/templates/renderImageBlock.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AASvC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAA6B,YAAY,EAAE,MAAM,WAAW,CAAC;AAKpE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,aAAa,GAAG,YAAY,CAsD/E"}
1
+ {"version":3,"file":"renderImageBlock.d.ts","sourceRoot":"","sources":["../../../library/src/blocks/templates/renderImageBlock.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AASvC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAyD,YAAY,EAAE,MAAM,WAAW,CAAC;AAKhG,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,aAAa,GAAG,YAAY,CA0D/E"}
@@ -1,7 +1,7 @@
1
1
  import { nothing } from 'lit';
2
2
  import { getTemplateRenderingStrategy } from '@reddit/faceplate-ui/faceplateUIConfig.js';
3
3
  import { defaultClasses, defaultStyles, imageClasses, imageStyle, onClickAction, } from '../attributes.js';
4
- import { classMap, isValidImageURL } from './util.js';
4
+ import { classMap, isDataUrl, isValidImageURL, sanitizeDataUrl } from './util.js';
5
5
  import { VerifiedPublicImageHosts } from './constants.js';
6
6
  const FALLBACK_IMG_URL = 'https://i.redd.it/p1vmc5ulmpib1.png';
7
7
  export function renderImageBlock(block, ctx) {
@@ -17,6 +17,10 @@ export function renderImageBlock(block, ctx) {
17
17
  // Replace url with a fallback snoo
18
18
  imageUrl = FALLBACK_IMG_URL;
19
19
  }
20
+ else if (isDataUrl(imageUrl)) {
21
+ const sanitized = sanitizeDataUrl(imageUrl);
22
+ imageUrl = sanitized ?? FALLBACK_IMG_URL;
23
+ }
20
24
  const classes = {
21
25
  ...defaultClasses(block, ctx),
22
26
  ...imageClasses(resizeMode),
@@ -23,6 +23,10 @@ export declare function parseDataUrl(dataUrl: string): {
23
23
  isBase64: boolean;
24
24
  data: string;
25
25
  } | null;
26
+ /**
27
+ * Only supports SVG elements!
28
+ */
29
+ export declare function sanitizeDataUrl(dataUrl: string): string | undefined;
26
30
  export declare function isAcceptableDataUrl(maybeDataUrl: string): boolean;
27
31
  export declare function isValidImageURL(imageUrl: string): boolean;
28
32
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../library/src/blocks/templates/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,QAAQ,IAAI,cAAc,EAAE,MAAM,6BAA6B,CAAC;AACpF,OAAO,EAAE,GAAG,IAAI,SAAS,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAGxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAKnE,OAAO,EACL,KAAK,EACL,UAAU,EACV,UAAU,EACV,0BAA0B,EAC1B,aAAa,EACd,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,OAAO,OAAO,CAAC;AAE3D,wBAAgB,QAAQ,CACtB,SAAS,EAAE,SAAS,EACpB,WAAW,CAAC,EAAE,OAAO,GACpB,MAAM,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAiB5C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,CAAC,cAAc,CAAC,GAAG,YAAY,CAMxF;AAED,wBAAgB,GAAG,CAAC,GAAG,EAAE,aAAa,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,GAAG,MAAM,CAM7E;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,WAAW,GAAG,OAAO,GAAG,SAAS,GAAG,EAAE,IAAI,WAAW,CAEtF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAiBxD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,CASjE;AAcD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG;IAC7C,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,IAAI,CAWP;AASD,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAMjE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAazD;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,UAAU,GAAG,SAAS,CA2B7D;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,0BAA0B,GAAG,SAAS,EAC7C,QAAQ,GAAE,aAAa,GAAG,SAAqB,GAC9C,MAAM,GAAG,SAAS,CAKpB;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,GAAG,MAAM,CAUpE;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,UAAU,GAAG,SAAS,EAC9B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,GAC/B,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,CAIzD"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../library/src/blocks/templates/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,QAAQ,IAAI,cAAc,EAAE,MAAM,6BAA6B,CAAC;AACpF,OAAO,EAAE,GAAG,IAAI,SAAS,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAGxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAKnE,OAAO,EACL,KAAK,EACL,UAAU,EACV,UAAU,EACV,0BAA0B,EAC1B,aAAa,EACd,MAAM,gBAAgB,CAAC;AAGxB,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,OAAO,OAAO,CAAC;AAE3D,wBAAgB,QAAQ,CACtB,SAAS,EAAE,SAAS,EACpB,WAAW,CAAC,EAAE,OAAO,GACpB,MAAM,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAiB5C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,CAAC,cAAc,CAAC,GAAG,YAAY,CAMxF;AAED,wBAAgB,GAAG,CAAC,GAAG,EAAE,aAAa,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,GAAG,MAAM,CAM7E;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,WAAW,GAAG,OAAO,GAAG,SAAS,GAAG,EAAE,IAAI,WAAW,CAEtF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAiBxD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,CASjE;AAcD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG;IAC7C,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,IAAI,CAWP;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAmDnE;AASD,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAMjE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAazD;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,UAAU,GAAG,SAAS,CA2B7D;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,0BAA0B,GAAG,SAAS,EAC7C,QAAQ,GAAE,aAAa,GAAG,SAAqB,GAC9C,MAAM,GAAG,SAAS,CAKpB;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,GAAG,MAAM,CAUpE;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,UAAU,GAAG,SAAS,EAC9B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,GAC/B,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,CAIzD"}
@@ -6,6 +6,7 @@ import { getTemplateRenderingStrategy } from '@reddit/faceplate-ui/faceplateUICo
6
6
  import faceplateIcons from '@reddit/faceplate-ui/svgs/svg-manifest.js';
7
7
  import { REDD_IT, VerifiedImageHosts } from './constants.js';
8
8
  import { BlockSizeUnit, } from '@devvit/protos';
9
+ import { sanitizeSvg } from '@devvit/shared-types/sanitizeSvg.js';
9
10
  export function classMap(classInfo, forceString) {
10
11
  const { getType } = getTemplateRenderingStrategy();
11
12
  if (getType() === 'client' && forceString !== true) {
@@ -96,6 +97,57 @@ export function parseDataUrl(dataUrl) {
96
97
  data: matches[4].trim(),
97
98
  };
98
99
  }
100
+ /**
101
+ * Only supports SVG elements!
102
+ */
103
+ export function sanitizeDataUrl(dataUrl) {
104
+ const parsedDataUrl = parseDataUrl(dataUrl);
105
+ if (!parsedDataUrl || !parsedDataUrl.data || !parsedDataUrl.mimeType)
106
+ return undefined;
107
+ if (!isAcceptableDataUrlMimeType(parsedDataUrl.mimeType))
108
+ return undefined;
109
+ try {
110
+ let dataToSanitize;
111
+ if (parsedDataUrl.isBase64) {
112
+ dataToSanitize = decodeURIComponent(atob(parsedDataUrl.data));
113
+ }
114
+ else {
115
+ dataToSanitize = decodeURIComponent(parsedDataUrl.data);
116
+ }
117
+ // If you add more mimtypes in the future make sure to handle sanitizing them here!
118
+ const sanitized = sanitizeSvg(dataToSanitize);
119
+ // Break early if sanitizing failed!
120
+ if (sanitized === undefined) {
121
+ return undefined;
122
+ }
123
+ // eslint-disable-next-line @reddit/i18n-shreddit/no-unwrapped-strings
124
+ let sanitizedDataUrl = `data:${parsedDataUrl.mimeType}`;
125
+ if (parsedDataUrl.charset) {
126
+ sanitizedDataUrl += `;charset=${parsedDataUrl.charset}`;
127
+ }
128
+ if (parsedDataUrl.isBase64) {
129
+ // eslint-disable-next-line @reddit/i18n-shreddit/no-unwrapped-strings
130
+ sanitizedDataUrl += `;base64`;
131
+ }
132
+ /**
133
+ * In data url land there are characters that need to be encoded that
134
+ * a user may have passed in like hex-code colors that will break
135
+ * the image without giving any relevant messages. To be safe, we
136
+ * encode the entire sanitized string.
137
+ *
138
+ * More info:
139
+ * https://stackoverflow.com/questions/69216560/why-hexadecimal-color-dont-work-with-utf8-data-url-s-for-svg
140
+ *
141
+ * You may be able to get away with just replacing # with %23 in case
142
+ * people complain about the data url being hard to read.
143
+ */
144
+ sanitizedDataUrl += `,${parsedDataUrl.isBase64 ? btoa(sanitized) : encodeURIComponent(sanitized)}`;
145
+ return sanitizedDataUrl;
146
+ }
147
+ catch (error) {
148
+ return undefined;
149
+ }
150
+ }
99
151
  function isAcceptableDataUrlMimeType(mimeType) {
100
152
  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#image_types
101
153
  const ACCEPTABLE_MIME_TYPES = ['image/svg+xml'];
@@ -109,8 +161,8 @@ export function isAcceptableDataUrl(maybeDataUrl) {
109
161
  }
110
162
  export function isValidImageURL(imageUrl) {
111
163
  try {
112
- if (isDataUrl(imageUrl))
113
- return false;
164
+ if (isAcceptableDataUrl(imageUrl))
165
+ return true;
114
166
  // The second "base" param helps to handle relative paths to local files
115
167
  // https://developer.mozilla.org/en-US/docs/Web/API/URL/URL#parameters
116
168
  const hostName = new URL(imageUrl, `https://i.${REDD_IT}`)?.hostname;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devvit/ui-renderer",
3
- "version": "0.10.11-next-2023-12-12-e793f90f9.0",
3
+ "version": "0.10.11-next-2023-12-12-ce6339b27.0",
4
4
  "license": "BSD-3-Clause",
5
5
  "repository": {
6
6
  "type": "git",
@@ -54,9 +54,10 @@
54
54
  },
55
55
  "types": "./index.d.ts",
56
56
  "dependencies": {
57
- "@devvit/protos": "0.10.11-next-2023-12-12-e793f90f9.0",
58
- "@devvit/runtime-lite": "0.10.11-next-2023-12-12-e793f90f9.0",
59
- "@devvit/runtimes": "0.10.11-next-2023-12-12-e793f90f9.0",
57
+ "@devvit/protos": "0.10.11-next-2023-12-12-ce6339b27.0",
58
+ "@devvit/runtime-lite": "0.10.11-next-2023-12-12-ce6339b27.0",
59
+ "@devvit/runtimes": "0.10.11-next-2023-12-12-ce6339b27.0",
60
+ "@devvit/shared-types": "0.10.11-next-2023-12-12-ce6339b27.0",
60
61
  "@lottiefiles/lottie-player": "1.7.1",
61
62
  "p-queue": "7.3.4",
62
63
  "rxjs": "7.5.7"
@@ -83,7 +84,7 @@
83
84
  "devDependencies": {
84
85
  "@devvit/eslint-config": "0.10.10",
85
86
  "@devvit/repo-tools": "0.10.10",
86
- "@devvit/tsconfig": "0.10.11-next-2023-12-12-e793f90f9.0",
87
+ "@devvit/tsconfig": "0.10.11-next-2023-12-12-ce6339b27.0",
87
88
  "@lit-labs/ssr": "^2.2.3",
88
89
  "@lit/localize": "0.11.4",
89
90
  "@open-wc/testing-helpers": "2.3.0",
@@ -115,5 +116,5 @@
115
116
  "directory": "dist"
116
117
  },
117
118
  "source": "./src/index.ts",
118
- "gitHead": "0146cb7c5fbe2694fb7128b2056af2249810b4a7"
119
+ "gitHead": "6025e78ec3faa75e9fc159c5eede2090df2fc96e"
119
120
  }