Skip to content

Commit b1e7886

Browse files
author
Evgeny Kuzyakov
authored
Merge pull request #158 from NearSocial/release-2.5.3
## 2.5.3 - FIX: Replace url-sanitize library with dompurify. Reported by BrunoModificato from OtterSec. - FIX: Replace internal usage of `in` operator with `hasOwnProperty` on dictionaries to avoid exposing certain built-in methods and properties. Reported by BrunoModificato from OtterSec. - FIX: `atob` and `btoa` are working correctly now.
2 parents 9fe2d4e + 31d509f commit b1e7886

File tree

7 files changed

+41
-29
lines changed

7 files changed

+41
-29
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## 2.5.3
4+
5+
- FIX: Remove `cachedPropery` from `elliptic.utils`. Reported by BrunoModificato from OtterSec.
6+
- FIX: Replace url-sanitize library with dompurify. Reported by BrunoModificato from OtterSec.
7+
- FIX: Replace internal usage of `in` operator with `hasOwnProperty` on dictionaries to avoid exposing certain built-in methods and properties. Reported by BrunoModificato from OtterSec.
8+
- FIX: `atob` and `btoa` are working correctly now.
9+
310
## 2.5.2
411

512
- Use `styled-components` in combination with `customElements` like `Link`:

dist/index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
{
22
"name": "near-social-vm",
3-
"version": "2.5.2",
3+
"version": "2.5.3",
44
"description": "Near Social VM",
55
"main": "dist/index.js",
66
"files": [
77
"dist"
88
],
99
"dependencies": {
10-
"@braintree/sanitize-url": "6.0.0",
1110
"@radix-ui/react-accordion": "^1.1.1",
1211
"@radix-ui/react-alert-dialog": "^1.0.3",
1312
"@radix-ui/react-aspect-ratio": "^1.0.2",
@@ -43,6 +42,7 @@
4342
"bootstrap-icons": "^1.9.0",
4443
"collections": "^5.1.12",
4544
"deep-equal": "^2.2.0",
45+
"dompurify": "^3.0.6",
4646
"elliptic": "^6.5.4",
4747
"ethers": "^5.7.2",
4848
"idb": "^7.1.1",

src/lib/data/near.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const SupportedApiMethods = {
4545
};
4646

4747
const apiCall = async (config, methodName, args, blockId, fallback) => {
48-
if (!config.apiUrl || !(methodName in SupportedApiMethods)) {
48+
if (!config.apiUrl || !SupportedApiMethods.hasOwnProperty(methodName)) {
4949
return fallback();
5050
}
5151
args = args || {};
@@ -214,7 +214,7 @@ async function web4ViewCall(contractId, methodName, args, fallback) {
214214
/**
215215
* Current VM Features:
216216
* - enableComponentSrcDataKey: Allows enabling the component source `data-component` attribute for rendered DOM elements. Disabled by default.
217-
**/
217+
**/
218218
async function _initNear({
219219
networkId,
220220
config,
@@ -255,7 +255,7 @@ async function _initNear({
255255
selector,
256256
keyStore,
257257
nearConnection,
258-
features
258+
features,
259259
};
260260

261261
_near.nearArchivalConnection = nearAPI.Connection.fromConfig({

src/lib/data/utils.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ const matchGet = (obj, keys) => {
248248
const values =
249249
matchKey === "*" || isRecursiveMatch
250250
? Object.values(obj)
251-
: matchKey in obj
251+
: obj.hasOwnProperty(matchKey)
252252
? [obj[matchKey]]
253253
: [];
254254

@@ -266,7 +266,7 @@ const matchKeys = (obj, keys) => {
266266
const values =
267267
matchKey === "*"
268268
? Object.values(obj)
269-
: matchKey in obj
269+
: obj.hasOwnProperty(matchKey)
270270
? [obj[matchKey]]
271271
: [];
272272

@@ -311,7 +311,7 @@ export const computeWritePermission = (previousPermissions, data) => {
311311

312312
if (isObject(data)) {
313313
Object.entries(data).forEach(([key, value]) => {
314-
if (key in KnownSecondLevelKeys) {
314+
if (KnownSecondLevelKeys.hasOwnProperty(key)) {
315315
if (isObject(value)) {
316316
const subPermissions = (permissions[key] = permissions[key] || {});
317317
Object.keys(value).forEach((key) => {

src/lib/vm/vm.js

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {
1717
ReactKey,
1818
} from "../data/utils";
1919
import Files from "react-files";
20-
import { sanitizeUrl } from "@braintree/sanitize-url";
2120
import { Markdown } from "../components/Markdown";
2221
import InfiniteScroll from "react-infinite-scroller";
2322
import { CommitButton } from "../components/Commit";
@@ -35,6 +34,7 @@ import { Parser } from "acorn";
3534
import jsx from "acorn-jsx";
3635
import { ethers } from "ethers";
3736
import { Web3ConnectButton } from "../components/ethers";
37+
import { isValidAttribute } from "dompurify";
3838

3939
// Radix:
4040
import * as Accordion from "@radix-ui/react-accordion";
@@ -215,8 +215,8 @@ const GlobalInjected = deepFreeze(
215215
parseInt,
216216
parseFloat,
217217
isFinite,
218-
btoa,
219-
atob,
218+
btoa: (s) => btoa(s),
219+
atob: (s) => atob(s),
220220
decodeURI,
221221
encodeURI,
222222

@@ -281,14 +281,16 @@ const AcornOptions = {
281281
allowReturnOutsideFunction: true,
282282
};
283283

284-
const ParsedCodeCache = {};
284+
const ParsedCodeCache = new Map();
285285
const JsxParser = Parser.extend(jsx());
286286

287287
const parseCode = (code) => {
288-
if (code in ParsedCodeCache) {
289-
return ParsedCodeCache[code];
288+
if (ParsedCodeCache.has(code)) {
289+
return ParsedCodeCache.get(code);
290290
}
291-
return (ParsedCodeCache[code] = JsxParser.parse(code, AcornOptions));
291+
const parsedCode = JsxParser.parse(code, AcornOptions);
292+
ParsedCodeCache.set(code, parsedCode);
293+
return parsedCode;
292294
};
293295

294296
const assertNotReservedKey = (key) => {
@@ -344,7 +346,7 @@ const requireIdentifier = (id) => {
344346
}
345347
const name = id.name;
346348
assertNotReservedKey(name);
347-
if (name in Keywords) {
349+
if (Keywords.hasOwnProperty(name)) {
348350
throw new Error("Cannot use keyword: " + name);
349351
}
350352
return {
@@ -418,14 +420,14 @@ class Stack {
418420
}
419421

420422
findObj(name) {
421-
if (name in this.state) {
423+
if (this.state.hasOwnProperty(name)) {
422424
return this.state;
423425
}
424426
return this.prevStack ? this.prevStack.findObj(name) : undefined;
425427
}
426428

427429
get(name) {
428-
if (name in this.state) {
430+
if (this.state.hasOwnProperty(name)) {
429431
return this.state[name];
430432
}
431433
return this.prevStack ? this.prevStack.get(name) : undefined;
@@ -609,7 +611,9 @@ class VmStack {
609611
} else if (basicElement === "a") {
610612
Object.entries(attributes).forEach(([name, value]) => {
611613
if (name.toLowerCase() === "href") {
612-
attributes[name] = sanitizeUrl(value);
614+
attributes[name] = isValidAttribute("a", "href", value)
615+
? value
616+
: "about:blank";
613617
}
614618
});
615619
} else if (element === "Widget") {
@@ -751,15 +755,15 @@ class VmStack {
751755
const obj = this.stack.findObj(key) ?? this.stack.state;
752756
assertNotReactObject(obj);
753757
if (obj === this.stack.state) {
754-
if (key in Keywords) {
758+
if (Keywords.hasOwnProperty(key)) {
755759
if (options?.left) {
756760
throw new Error("Cannot assign to keyword '" + key + "'");
757761
}
758762
return { obj, key, keyword: key };
759763
}
760764
}
761765
if (options?.left) {
762-
if (!obj || !(key in obj)) {
766+
if (!obj || !obj.hasOwnProperty(key)) {
763767
throw new Error(`Accessing undeclared identifier '${code.name}'`);
764768
}
765769
}
@@ -773,7 +777,7 @@ class VmStack {
773777
code.object?.type === "JSXIdentifier"
774778
) {
775779
const keyword = code.object.name;
776-
if (keyword in Keywords) {
780+
if (Keywords.hasOwnProperty(keyword)) {
777781
if (!options?.callee) {
778782
throw new Error(
779783
"Cannot dereference keyword '" +
@@ -1025,7 +1029,7 @@ class VmStack {
10251029
} else {
10261030
if (key === "keyframes") {
10271031
styledTemplate = keyframes;
1028-
} else if (key in ApprovedTagsSimple) {
1032+
} else if (ApprovedTagsSimple.hasOwnProperty(key)) {
10291033
styledTemplate = styled(key);
10301034
} else {
10311035
throw new Error("Unsupported styled tag: " + key);
@@ -2254,6 +2258,7 @@ export default class VM {
22542258
get elliptic() {
22552259
delete this.elliptic;
22562260
this.elliptic = cloneDeep(elliptic);
2261+
delete this.elliptic.utils.cachedProperty;
22572262
return this.elliptic;
22582263
},
22592264
};

yarn.lock

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -962,11 +962,6 @@
962962
"@babel/helper-validator-identifier" "^7.19.1"
963963
to-fast-properties "^2.0.0"
964964

965-
"@braintree/[email protected]":
966-
version "6.0.0"
967-
resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.0.tgz#fe364f025ba74f6de6c837a84ef44bdb1d61e68f"
968-
integrity sha512-mgmE7XBYY/21erpzhexk4Cj1cyTQ9LzvnTxtzM17BJ7ERMNE6W72mQRo0I1Ud8eFJ+RVVIcBNhLFZ3GX4XFz5w==
969-
970965
"@discoveryjs/[email protected]", "@discoveryjs/json-ext@^0.5.0":
971966
version "0.5.7"
972967
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
@@ -4028,6 +4023,11 @@ domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1:
40284023
dependencies:
40294024
domelementtype "^2.2.0"
40304025

4026+
dompurify@^3.0.6:
4027+
version "3.0.6"
4028+
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.0.6.tgz#925ebd576d54a9531b5d76f0a5bef32548351dae"
4029+
integrity sha512-ilkD8YEnnGh1zJ240uJsW7AzE+2qpbOUYjacomn3AvJ6J4JhKGSZ2nh4wUIXPZrEPppaCLx5jFe8T89Rk8tQ7w==
4030+
40314031
domutils@^2.5.2, domutils@^2.8.0:
40324032
version "2.8.0"
40334033
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"

0 commit comments

Comments
 (0)