@devvit/ui-renderer 0.10.11-next-2023-12-12-cf8c3ab72.0 → 0.10.11-next-2023-12-12-18892f76e.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.
package/blocks/attributes.js
CHANGED
|
@@ -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,
|
|
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;
|
|
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"}
|
package/blocks/templates/util.js
CHANGED
|
@@ -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 (
|
|
113
|
-
return
|
|
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-
|
|
3
|
+
"version": "0.10.11-next-2023-12-12-18892f76e.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-
|
|
58
|
-
"@devvit/runtime-lite": "0.10.11-next-2023-12-12-
|
|
59
|
-
"@devvit/runtimes": "0.10.11-next-2023-12-12-
|
|
57
|
+
"@devvit/protos": "0.10.11-next-2023-12-12-18892f76e.0",
|
|
58
|
+
"@devvit/runtime-lite": "0.10.11-next-2023-12-12-18892f76e.0",
|
|
59
|
+
"@devvit/runtimes": "0.10.11-next-2023-12-12-18892f76e.0",
|
|
60
|
+
"@devvit/shared-types": "0.10.11-next-2023-12-12-18892f76e.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-
|
|
87
|
+
"@devvit/tsconfig": "0.10.11-next-2023-12-12-18892f76e.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": "
|
|
119
|
+
"gitHead": "47b9cf6ab8ac33d8c553176a04f470cf9ec6f236"
|
|
119
120
|
}
|