From 0658bc5ad68fa8c2a8ac6f29b2fdb6802c65ebf1 Mon Sep 17 00:00:00 2001 From: Arturo Ortega Date: Fri, 29 Nov 2019 18:50:25 -0600 Subject: [PATCH 1/6] Encrypted user (currentUser) -still need jest test --- package-lock.json | 769 ++++++++++++++++++++++++++++----------------- package.json | 1 + src/CoreManager.js | 4 +- src/Parse.js | 28 ++ src/ParseUser.js | 16 +- 5 files changed, 522 insertions(+), 296 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2a6a0d777..4804eaf66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,35 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@apollo/protobufjs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.0.3.tgz", + "integrity": "sha512-gqeT810Ect9WIqsrgfUvr+ljSB5m1PyBae9HGdrRyQ3HjHjTcjVvxpsMYXlUk4rUHnrfUqyoGvLSy2yLlRGEOw==", + "dev": true, + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "10.17.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.6.tgz", + "integrity": "sha512-0a2X6cgN3RdPBL2MIlR6Lt0KlM7fOFsutuXcdglcOq6WvLnYXgPQSh0Mx6tO1KCAE8MxbHSOSTWDoUxRq+l3DA==", + "dev": true + } + } + }, "@apollographql/apollo-tools": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@apollographql/apollo-tools/-/apollo-tools-0.4.0.tgz", @@ -2846,16 +2875,6 @@ "normalize-path": "^2.1.1" } }, - "apollo-cache-control": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/apollo-cache-control/-/apollo-cache-control-0.8.5.tgz", - "integrity": "sha512-2yQ1vKgJQ54SGkoQS/ZLZrDX3La6cluAYYdruFYJMJtL4zQrSdeOCy11CQliCMYEd6eKNyE70Rpln51QswW2Og==", - "dev": true, - "requires": { - "apollo-server-env": "^2.4.3", - "graphql-extensions": "^0.10.4" - } - }, "apollo-datasource": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-0.6.3.tgz", @@ -2866,30 +2885,6 @@ "apollo-server-env": "^2.4.3" } }, - "apollo-engine-reporting": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/apollo-engine-reporting/-/apollo-engine-reporting-1.4.7.tgz", - "integrity": "sha512-qsKDz9VkoctFhojM3Nj3nvRBO98t8TS2uTgtiIjUGs3Hln2poKMP6fIQ37Nm2Q2B3JJst76HQtpPwXmRJd1ZUg==", - "dev": true, - "requires": { - "apollo-engine-reporting-protobuf": "^0.4.1", - "apollo-graphql": "^0.3.4", - "apollo-server-caching": "^0.5.0", - "apollo-server-env": "^2.4.3", - "apollo-server-types": "^0.2.5", - "async-retry": "^1.2.1", - "graphql-extensions": "^0.10.4" - } - }, - "apollo-engine-reporting-protobuf": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/apollo-engine-reporting-protobuf/-/apollo-engine-reporting-protobuf-0.4.1.tgz", - "integrity": "sha512-d7vFFZ2oUrvGaN0Hpet8joe2ZG0X0lIGilN+SwgVP38dJnOuadjsaYMyrD9JudGQJg0bJA5wVQfYzcCVy0slrw==", - "dev": true, - "requires": { - "protobufjs": "^6.8.6" - } - }, "apollo-env": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/apollo-env/-/apollo-env-0.5.1.tgz", @@ -2932,46 +2927,6 @@ "lru-cache": "^5.0.0" } }, - "apollo-server-core": { - "version": "2.9.7", - "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.9.7.tgz", - "integrity": "sha512-EqKyROy+21sM93YHjGpy6wlnzK/vH0fnZh7RCf3uB69aQ3OjgdP4AQ5oWRQ62NDN+aoic7OLhChSDJeDonq/NQ==", - "dev": true, - "requires": { - "@apollographql/apollo-tools": "^0.4.0", - "@apollographql/graphql-playground-html": "1.6.24", - "@types/graphql-upload": "^8.0.0", - "@types/ws": "^6.0.0", - "apollo-cache-control": "^0.8.5", - "apollo-datasource": "^0.6.3", - "apollo-engine-reporting": "^1.4.7", - "apollo-server-caching": "^0.5.0", - "apollo-server-env": "^2.4.3", - "apollo-server-errors": "^2.3.4", - "apollo-server-plugin-base": "^0.6.5", - "apollo-server-types": "^0.2.5", - "apollo-tracing": "^0.8.5", - "fast-json-stable-stringify": "^2.0.0", - "graphql-extensions": "^0.10.4", - "graphql-tag": "^2.9.2", - "graphql-tools": "^4.0.0", - "graphql-upload": "^8.0.2", - "sha.js": "^2.4.11", - "subscriptions-transport-ws": "^0.9.11", - "ws": "^6.0.0" - }, - "dependencies": { - "ws": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", - "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } - } - } - }, "apollo-server-env": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/apollo-server-env/-/apollo-server-env-2.4.3.tgz", @@ -2988,60 +2943,6 @@ "integrity": "sha512-Y0PKQvkrb2Kd18d1NPlHdSqmlr8TgqJ7JQcNIfhNDgdb45CnqZlxL1abuIRhr8tiw8OhVOcFxz2KyglBi8TKdA==", "dev": true }, - "apollo-server-express": { - "version": "2.9.7", - "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.9.7.tgz", - "integrity": "sha512-+DuJk1oq34Zx0bLYzgBgJH/eXS0JNxw2JycHQvV0+PAQ0Qi01oomJRA2r1S5isnfnSAnHb2E9jyBTptoHdw3MQ==", - "dev": true, - "requires": { - "@apollographql/graphql-playground-html": "1.6.24", - "@types/accepts": "^1.3.5", - "@types/body-parser": "1.17.1", - "@types/cors": "^2.8.4", - "@types/express": "4.17.1", - "accepts": "^1.3.5", - "apollo-server-core": "^2.9.7", - "apollo-server-types": "^0.2.5", - "body-parser": "^1.18.3", - "cors": "^2.8.4", - "express": "^4.17.1", - "graphql-subscriptions": "^1.0.0", - "graphql-tools": "^4.0.0", - "parseurl": "^1.3.2", - "subscriptions-transport-ws": "^0.9.16", - "type-is": "^1.6.16" - } - }, - "apollo-server-plugin-base": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-0.6.5.tgz", - "integrity": "sha512-z2ve7HEPWmZI3EzL0iiY9qyt1i0hitT+afN5PzssCw594LB6DfUQWsI14UW+W+gcw8hvl8VQUpXByfUntAx5vw==", - "dev": true, - "requires": { - "apollo-server-types": "^0.2.5" - } - }, - "apollo-server-types": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/apollo-server-types/-/apollo-server-types-0.2.5.tgz", - "integrity": "sha512-6iJQsPh59FWu4K7ABrVmpnQVgeK8Ockx8BcawBh+saFYWTlVczwcLyGSZPeV1tPSKwFwKZutyEslrYSafcarXQ==", - "dev": true, - "requires": { - "apollo-engine-reporting-protobuf": "^0.4.1", - "apollo-server-caching": "^0.5.0", - "apollo-server-env": "^2.4.3" - } - }, - "apollo-tracing": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/apollo-tracing/-/apollo-tracing-0.8.5.tgz", - "integrity": "sha512-lZn10/GRBZUlMxVYLghLMFsGcLN0jTYDd98qZfBtxw+wEWUx+PKkZdljDT+XNoOm/kDvEutFGmi5tSLhArIzWQ==", - "dev": true, - "requires": { - "apollo-server-env": "^2.4.3", - "graphql-extensions": "^0.10.4" - } - }, "apollo-utilities": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.3.2.tgz", @@ -3569,6 +3470,15 @@ "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", "dev": true }, + "backoff": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", + "integrity": "sha1-9hbtqdPktmuMp/ynn2lXIsX44m8=", + "dev": true, + "requires": { + "precond": "0.2" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -3636,26 +3546,6 @@ "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", "dev": true }, - "bcrypt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-3.0.6.tgz", - "integrity": "sha512-taA5bCTfXe7FUjKroKky9EXpdhkVvhE5owfxfLYodbrAR1Ul3juLmIQmIQBK4L9a5BuUcE6cqmwT+Da20lF9tg==", - "dev": true, - "optional": true, - "requires": { - "nan": "2.13.2", - "node-pre-gyp": "0.12.0" - }, - "dependencies": { - "nan": { - "version": "2.13.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", - "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==", - "dev": true, - "optional": true - } - } - }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -4020,6 +3910,18 @@ "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", "dev": true }, + "bunyan": { + "version": "1.8.12", + "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz", + "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=", + "dev": true, + "requires": { + "dtrace-provider": "~0.8", + "moment": "^2.10.6", + "mv": "~2", + "safe-json-stringify": "~1" + } + }, "busboy": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.3.1.tgz", @@ -4722,6 +4624,11 @@ "randomfill": "^1.0.3" } }, + "crypto-js": { + "version": "3.1.9-1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz", + "integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg=" + }, "cssom": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", @@ -5274,6 +5181,16 @@ "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=", "dev": true }, + "dtrace-provider": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz", + "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.14.0" + } + }, "duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -6440,8 +6357,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -6462,14 +6378,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6484,20 +6398,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -6614,8 +6525,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -6627,7 +6537,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6642,7 +6551,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -6650,14 +6558,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -6676,7 +6582,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -6757,8 +6662,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -6770,7 +6674,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -6856,8 +6759,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -6893,7 +6795,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6913,7 +6814,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6957,14 +6857,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -7302,17 +7200,6 @@ "iterall": "^1.2.2" } }, - "graphql-extensions": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.10.4.tgz", - "integrity": "sha512-lE6MroluEYocbR/ICwccv39w+Pz4cBPadJ11z1rJkbZv5wstISEganbDOwl9qN21rcZGiWzh7QUNxUiFUXXEDw==", - "dev": true, - "requires": { - "@apollographql/apollo-tools": "^0.4.0", - "apollo-server-env": "^2.4.3", - "apollo-server-types": "^0.2.5" - } - }, "graphql-list-fields": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/graphql-list-fields/-/graphql-list-fields-2.0.2.tgz", @@ -9683,6 +9570,49 @@ "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", "dev": true }, + "ldap-filter": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ldap-filter/-/ldap-filter-0.2.2.tgz", + "integrity": "sha1-8rhCvguG2jNSeYUFsx68rlkNd9A=", + "dev": true, + "requires": { + "assert-plus": "0.1.5" + }, + "dependencies": { + "assert-plus": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", + "integrity": "sha1-7nQAlBMALYTOxyGcasgRgS5yMWA=", + "dev": true + } + } + }, + "ldapjs": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ldapjs/-/ldapjs-1.0.2.tgz", + "integrity": "sha1-VE/3Ayt7g8aPBwEyjZKXqmlDQPk=", + "dev": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "^1.0.0", + "backoff": "^2.5.0", + "bunyan": "^1.8.3", + "dashdash": "^1.14.0", + "dtrace-provider": "~0.8", + "ldap-filter": "0.2.2", + "once": "^1.4.0", + "vasync": "^1.6.4", + "verror": "^1.8.1" + }, + "dependencies": { + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + } + } + }, "lead": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", @@ -10294,7 +10224,6 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -10304,8 +10233,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "optional": true + "dev": true } } }, @@ -10459,6 +10387,44 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "mv": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", + "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", + "dev": true, + "optional": true, + "requires": { + "mkdirp": "~0.5.1", + "ncp": "~2.0.0", + "rimraf": "~2.4.0" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "dev": true, + "optional": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", + "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", + "dev": true, + "optional": true, + "requires": { + "glob": "^6.0.1" + } + } + } + }, "nan": { "version": "2.14.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", @@ -10491,6 +10457,13 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "ncp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", + "dev": true, + "optional": true + }, "needle": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", @@ -10582,25 +10555,6 @@ "which": "^1.3.0" } }, - "node-pre-gyp": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz", - "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==", - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, "node-releases": { "version": "1.1.41", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.41.tgz", @@ -10618,15 +10572,6 @@ } } }, - "node-rsa": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/node-rsa/-/node-rsa-1.0.6.tgz", - "integrity": "sha512-v42495lozKpuQmrcIzld9ds/Tn7pwjuh0BHSHnhPrKkAVSyTAyrZodFLFafOfWiUKamLt4lgWdngP8W/LzCm2w==", - "dev": true, - "requires": { - "asn1": "^0.2.4" - } - }, "nopt": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", @@ -11254,11 +11199,11 @@ "@parse/push-adapter": "3.2.0", "@parse/s3-files-adapter": "1.3.0", "@parse/simple-mailgun-adapter": "1.1.0", - "apollo-server-express": "2.9.7", - "bcrypt": "3.0.6", + "apollo-server-express": "2.9.12", + "bcrypt": "3.0.7", "bcryptjs": "2.4.3", "body-parser": "1.19.0", - "commander": "4.0.0", + "commander": "4.0.1", "cors": "2.8.5", "deepcopy": "2.0.0", "express": "4.17.1", @@ -11269,13 +11214,14 @@ "graphql-upload": "8.1.0", "intersect": "1.0.1", "jsonwebtoken": "8.5.1", + "ldapjs": "1.0.2", "lodash": "4.17.15", "lru-cache": "5.1.1", "mime": "2.4.4", "mongodb": "3.3.2", - "node-rsa": "1.0.6", - "parse": "2.8.0", - "pg-promise": "9.3.3", + "node-rsa": "1.0.7", + "parse": "2.9.1", + "pg-promise": "10.3.1", "pluralize": "^8.0.0", "redis": "2.8.0", "semver": "6.3.0", @@ -11287,18 +11233,279 @@ "ws": "7.2.0" }, "dependencies": { + "@babel/runtime": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.2.tgz", + "integrity": "sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, + "@babel/runtime-corejs3": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.7.2.tgz", + "integrity": "sha512-odQQZpujq0AHttKrvp4n2KGjK5b5cuq7LeEcsdadwZOemMkmJnlgTXMCf5fIixLLaBxUypwn0krKK51vVMA5cg==", + "dev": true, + "requires": { + "core-js-pure": "^3.0.0", + "regenerator-runtime": "^0.13.2" + } + }, + "apollo-cache-control": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/apollo-cache-control/-/apollo-cache-control-0.8.8.tgz", + "integrity": "sha512-hpIJg3Tmb6quA111lrVO+d3qcyYRlJ8JqbeQdcgwLT3fb2VQzk21SrBZYl2oMM4ZqSOWCZWg4/Cn9ARYqdWjKA==", + "dev": true, + "requires": { + "apollo-server-env": "^2.4.3", + "graphql-extensions": "^0.10.7" + } + }, + "apollo-engine-reporting": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/apollo-engine-reporting/-/apollo-engine-reporting-1.4.10.tgz", + "integrity": "sha512-0nEawO9cudbXHCxRvnDUWKqCxPAGEstghUFd5sB67lIGuh91MYeLuwN1iTfqUdwF1feEGHn636zVVUYlXGOlvQ==", + "dev": true, + "requires": { + "apollo-engine-reporting-protobuf": "^0.4.4", + "apollo-graphql": "^0.3.4", + "apollo-server-caching": "^0.5.0", + "apollo-server-env": "^2.4.3", + "apollo-server-types": "^0.2.8", + "async-retry": "^1.2.1", + "graphql-extensions": "^0.10.7" + } + }, + "apollo-engine-reporting-protobuf": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/apollo-engine-reporting-protobuf/-/apollo-engine-reporting-protobuf-0.4.4.tgz", + "integrity": "sha512-SGrIkUR7Q/VjU8YG98xcvo340C4DaNUhg/TXOtGsMlfiJDzHwVau/Bv6zifAzBafp2lj0XND6Daj5kyT/eSI/w==", + "dev": true, + "requires": { + "@apollo/protobufjs": "^1.0.3" + } + }, + "apollo-server-core": { + "version": "2.9.12", + "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.9.12.tgz", + "integrity": "sha512-jhGr2R655PSwUUBweXDl+0F3oa74Elu5xXF+88ymUUej34EwBUCqz97wPqR07BEuyxaAlRfZwPMvKaHhMUKg5g==", + "dev": true, + "requires": { + "@apollographql/apollo-tools": "^0.4.0", + "@apollographql/graphql-playground-html": "1.6.24", + "@types/graphql-upload": "^8.0.0", + "@types/ws": "^6.0.0", + "apollo-cache-control": "^0.8.8", + "apollo-datasource": "^0.6.3", + "apollo-engine-reporting": "^1.4.10", + "apollo-server-caching": "^0.5.0", + "apollo-server-env": "^2.4.3", + "apollo-server-errors": "^2.3.4", + "apollo-server-plugin-base": "^0.6.8", + "apollo-server-types": "^0.2.8", + "apollo-tracing": "^0.8.8", + "fast-json-stable-stringify": "^2.0.0", + "graphql-extensions": "^0.10.7", + "graphql-tag": "^2.9.2", + "graphql-tools": "^4.0.0", + "graphql-upload": "^8.0.2", + "sha.js": "^2.4.11", + "subscriptions-transport-ws": "^0.9.11", + "ws": "^6.0.0" + }, + "dependencies": { + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "apollo-server-express": { + "version": "2.9.12", + "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.9.12.tgz", + "integrity": "sha512-4Ev8MY7m23mSzwO/BvLTy97a/68IP/wZoCRBn2R81OoZt9/GxlvvYZGvozJCXYsQt1qAbIT4Sn05LmqawsI98w==", + "dev": true, + "requires": { + "@apollographql/graphql-playground-html": "1.6.24", + "@types/accepts": "^1.3.5", + "@types/body-parser": "1.17.1", + "@types/cors": "^2.8.4", + "@types/express": "4.17.1", + "accepts": "^1.3.5", + "apollo-server-core": "^2.9.12", + "apollo-server-types": "^0.2.8", + "body-parser": "^1.18.3", + "cors": "^2.8.4", + "express": "^4.17.1", + "graphql-subscriptions": "^1.0.0", + "graphql-tools": "^4.0.0", + "parseurl": "^1.3.2", + "subscriptions-transport-ws": "^0.9.16", + "type-is": "^1.6.16" + } + }, + "apollo-server-plugin-base": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-0.6.8.tgz", + "integrity": "sha512-0pKCjcg9gHBK8qlb280+N0jl99meixQtxXnMJFyIfD+45OpKQ+WolHIbO0oZgNEt7r/lNWwH8v3l5yYm1ghz1A==", + "dev": true, + "requires": { + "apollo-server-types": "^0.2.8" + } + }, + "apollo-server-types": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/apollo-server-types/-/apollo-server-types-0.2.8.tgz", + "integrity": "sha512-5OclxkAqjhuO75tTNHpSO/+doJZ+VlRtTefnrPJdK/uwVew9U/VUCWkYdryZWwEyVe1nvQ/4E7RYR4tGb8l8wA==", + "dev": true, + "requires": { + "apollo-engine-reporting-protobuf": "^0.4.4", + "apollo-server-caching": "^0.5.0", + "apollo-server-env": "^2.4.3" + } + }, + "apollo-tracing": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/apollo-tracing/-/apollo-tracing-0.8.8.tgz", + "integrity": "sha512-aIwT2PsH7VZZPaNrIoSjzLKMlG644d2Uf+GYcoMd3X6UEyg1sXdWqkKfCeoS6ChJKH2khO7MXAvOZC03UnCumQ==", + "dev": true, + "requires": { + "apollo-server-env": "^2.4.3", + "graphql-extensions": "^0.10.7" + } + }, + "bcrypt": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-3.0.7.tgz", + "integrity": "sha512-K5UglF9VQvBMHl/1elNyyFvAfOY9Bj+rpKrCSR9sFwcW8FywAYJSRwTURNej5TaAK2TEJkcJ6r6lh1YPmspx5Q==", + "dev": true, + "optional": true, + "requires": { + "nan": "2.14.0", + "node-pre-gyp": "0.13.0" + } + }, "commander": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.0.0.tgz", - "integrity": "sha512-SEa2abMBTZuEjLVYpNrAFoRgxPwG4rXP3+SGY6CM/HZGeDzIA7Pzp+7H3AHDukKEpyy2SoSGGPShKqqfH9T9AQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.0.1.tgz", + "integrity": "sha512-IPF4ouhCP+qdlcmCedhxX4xiGBPyigb8v5NeUp+0LyhwLgxMqyp3S0vl7TAPfS/hiP7FC3caI/PB9lTmP8r1NA==", "dev": true }, + "graphql-extensions": { + "version": "0.10.7", + "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.10.7.tgz", + "integrity": "sha512-YuP7VQxNePG4bWRQ5Vk+KRMbZ9r1IWCqCCogOMz/1ueeQ4gZe93eGRcb0vhpOdMFnCX6Vyvd4+sC+N6LR3YFOQ==", + "dev": true, + "requires": { + "@apollographql/apollo-tools": "^0.4.0", + "apollo-server-env": "^2.4.3", + "apollo-server-types": "^0.2.8" + } + }, "mime": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", "dev": true }, + "node-pre-gyp": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz", + "integrity": "sha512-Md1D3xnEne8b/HGVQkZZwV27WUi1ZRuZBij24TNaZwUPU3ZAFtvT6xxJGaUVillfmMKnn5oD1HoGsp2Ftik7SQ==", + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "optional": true + } + } + }, + "node-rsa": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/node-rsa/-/node-rsa-1.0.7.tgz", + "integrity": "sha512-idwRXma6scFufZmbaKkHpJoLL93yynRefP6yur13wZ5i9FR35ex451KCoF2OORDeJanyRVahmjjiwmUlCnTqJA==", + "dev": true, + "requires": { + "asn1": "^0.2.4" + } + }, + "parse": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/parse/-/parse-2.9.1.tgz", + "integrity": "sha512-vLuJEtkZQGQZk0sZqETWmEx6IOhQYowyV4+bd0z4Fn3/FalC+RgisGOJIRdlKfjCKcinDBMtEttcMB5pg4v44A==", + "dev": true, + "requires": { + "@babel/runtime": "7.7.2", + "@babel/runtime-corejs3": "7.7.2", + "uuid": "3.3.3", + "ws": "7.2.0", + "xmlhttprequest": "1.8.0" + } + }, + "pg": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-7.14.0.tgz", + "integrity": "sha512-TLsdOWKFu44vHdejml4Uoo8h0EwCjdIj9Z9kpz7pA5i8iQxOTwVb1+Fy+X86kW5AXKxQpYpYDs4j/qPDbro/lg==", + "dev": true, + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "0.1.3", + "pg-pool": "^2.0.7", + "pg-types": "^2.1.0", + "pgpass": "1.x", + "semver": "4.3.2" + }, + "dependencies": { + "semver": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz", + "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=", + "dev": true + } + } + }, + "pg-promise": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-10.3.1.tgz", + "integrity": "sha512-1b9Nx1UMV0SE5zJC92ckM+DHFGB5koly/AILd5DpV0Zx4Z9/iytnbdUGz9qnnqKt+XIuXjdizT2FIyGyV2AxTQ==", + "dev": true, + "requires": { + "assert-options": "0.6.0", + "manakin": "0.5.2", + "pg": "7.14.0", + "pg-minify": "1.5.1", + "spex": "3.0.0" + } + }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", + "dev": true + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -11433,29 +11640,6 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, - "pg": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/pg/-/pg-7.12.1.tgz", - "integrity": "sha512-l1UuyfEvoswYfcUe6k+JaxiN+5vkOgYcVSbSuw3FvdLqDbaoa2RJo1zfJKfPsSYPFVERd4GHvX3s2PjG1asSDA==", - "dev": true, - "requires": { - "buffer-writer": "2.0.0", - "packet-reader": "1.0.0", - "pg-connection-string": "0.1.3", - "pg-pool": "^2.0.4", - "pg-types": "^2.1.0", - "pgpass": "1.x", - "semver": "4.3.2" - }, - "dependencies": { - "semver": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz", - "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=", - "dev": true - } - } - }, "pg-connection-string": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz", @@ -11480,19 +11664,6 @@ "integrity": "sha512-UiJyO5B9zZpu32GSlP0tXy8J2NsJ9EFGFfz5v6PSbdz/1hBLX1rNiiy5+mAm5iJJYwfCv4A0EBcQLGWwjbpzZw==", "dev": true }, - "pg-promise": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-9.3.3.tgz", - "integrity": "sha512-C7Mj5RSUvK0cGOaJ0p1fcOk5jhS1n+HgY+DoE8s1+Zjzf6ta70zYDIlOmy6MtYWs4DFHhUW654hb0FmtGKkIkg==", - "dev": true, - "requires": { - "assert-options": "0.6.0", - "manakin": "0.5.2", - "pg": "7.12.1", - "pg-minify": "1.5.1", - "spex": "3.0.0" - } - }, "pg-types": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", @@ -11611,6 +11782,12 @@ "xtend": "^4.0.0" } }, + "precond": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", + "integrity": "sha1-qpWRvKokkj8eD0hJ0kD0fvwQdaw=", + "dev": true + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -11684,35 +11861,6 @@ "sisteransi": "^1.0.3" } }, - "protobufjs": { - "version": "6.8.8", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", - "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", - "dev": true, - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.0", - "@types/node": "^10.1.0", - "long": "^4.0.0" - }, - "dependencies": { - "@types/node": { - "version": "10.17.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.4.tgz", - "integrity": "sha512-F2pgg+LcIr/elguz+x+fdBX5KeZXGUOp7TV8M0TVIrDezYLFRNt8oMTyps0VQ1kj5WGGoR18RdxnRDHXrIFHMQ==", - "dev": true - } - } - }, "proxy-addr": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", @@ -12422,6 +12570,13 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, + "safe-json-stringify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", + "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", + "dev": true, + "optional": true + }, "safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", @@ -14027,6 +14182,32 @@ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", "dev": true }, + "vasync": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/vasync/-/vasync-1.6.4.tgz", + "integrity": "sha1-3+k2Fq0OeugBszKp2Iv8XNyOHR8=", + "dev": true, + "requires": { + "verror": "1.6.0" + }, + "dependencies": { + "extsprintf": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.2.0.tgz", + "integrity": "sha1-WtlGwi9bMrp/jNdCZxHG6KP8JSk=", + "dev": true + }, + "verror": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.6.0.tgz", + "integrity": "sha1-fROyex+swuLakEBetepuW90lLqU=", + "dev": true, + "requires": { + "extsprintf": "1.2.0" + } + } + } + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", diff --git a/package.json b/package.json index 19ce37a70..572368104 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "dependencies": { "@babel/runtime": "7.7.4", "@babel/runtime-corejs3": "7.7.4", + "crypto-js": "^3.1.9-1", "uuid": "3.3.3", "ws": "7.2.0", "xmlhttprequest": "1.8.0" diff --git a/src/CoreManager.js b/src/CoreManager.js index dc45d4314..be6bf25cf 100644 --- a/src/CoreManager.js +++ b/src/CoreManager.js @@ -175,13 +175,15 @@ const config: Config & { [key: string]: mixed } = { SERVER_AUTH_TYPE: null, SERVER_AUTH_TOKEN: null, LIVEQUERY_SERVER_URL: null, + ENCRYPTED_KEY: null, VERSION: 'js' + require('../package.json').version, APPLICATION_ID: null, JAVASCRIPT_KEY: null, MASTER_KEY: null, USE_MASTER_KEY: false, PERFORM_USER_REWRITE: true, - FORCE_REVOCABLE_SESSION: false + FORCE_REVOCABLE_SESSION: false, + ENCRYPTED_USER: false }; function requireMethods(name: string, methods: Array, controller: any) { diff --git a/src/Parse.js b/src/Parse.js index c38ef2a62..95154c1f8 100644 --- a/src/Parse.js +++ b/src/Parse.js @@ -169,6 +169,34 @@ Object.defineProperty(Parse, 'liveQueryServerURL', { CoreManager.set('LIVEQUERY_SERVER_URL', value); } }); + +/** + * @member Parse.encryptedKey + * @type string + * @static + */ +Object.defineProperty(Parse, 'encryptedKey', { + get() { + return CoreManager.get('ENCRYPTED_KEY'); + }, + set(value) { + CoreManager.set('ENCRYPTED_KEY', value); + } +}); + +/** + * @member Parse.encryptedUser + * @type boolean + * @static + */ +Object.defineProperty(Parse, 'encryptedUser', { + get() { + return CoreManager.get('ENCRYPTED_USER'); + }, + set(value) { + CoreManager.set('ENCRYPTED_USER', value); + } +}); /* End setters */ Parse.ACL = require('./ParseACL').default; diff --git a/src/ParseUser.js b/src/ParseUser.js index c778afaa6..680606d41 100644 --- a/src/ParseUser.js +++ b/src/ParseUser.js @@ -27,6 +27,11 @@ let canUseCurrentUser = !CoreManager.get('IS_NODE'); let currentUserCacheMatchesDisk = false; let currentUserCache = null; +let CryptoJS = null; +if (process.env.PARSE_BUILD === 'node' || process.env.PARSE_BUILD === 'browser') { + CryptoJS = require('crypto-js') +} + const authProviders = {}; /** @@ -873,7 +878,10 @@ const DefaultController = { json.className = user.constructor.name === ParseUser.name ? '_User' : user.constructor.name; return Storage.setItemAsync( - path, JSON.stringify(json) + path, + (!CoreManager.get('ENCRYPTED_USER')) + ? JSON.stringify(json) + : CryptoJS.AES.encrypt(JSON.stringify(json), CoreManager.get('ENCRYPTED_KEY')) ).then(() => { return user; }); @@ -913,6 +921,9 @@ const DefaultController = { } const path = Storage.generatePath(CURRENT_USER_KEY); let userData = Storage.getItem(path); + if (CoreManager.get('ENCRYPTED_USER')) { + userData = CryptoJS.AES.decrypt(userData.toString(), CoreManager.get('ENCRYPTED_KEY')).toString(CryptoJS.enc.Utf8); + } currentUserCacheMatchesDisk = true; if (!userData) { currentUserCache = null; @@ -954,6 +965,9 @@ const DefaultController = { currentUserCache = null; return Promise.resolve(null); } + if (CoreManager.get('ENCRYPTED_USER')) { + userData = CryptoJS.AES.decrypt(userData.toString(), CoreManager.get('ENCRYPTED_KEY')).toString(CryptoJS.enc.Utf8) + } userData = JSON.parse(userData); if (!userData.className) { userData.className = '_User'; From 5e6b781a507431fe26ec19ca2d3e533b01ed0b6c Mon Sep 17 00:00:00 2001 From: Arturo Ortega Date: Fri, 13 Dec 2019 14:34:40 -0600 Subject: [PATCH 2/6] all 'npm test' tests passed successfully --- src/Parse.js | 39 ++++++++++++++----- src/ParseUser.js | 20 +++++----- src/__tests__/Cloud-test.js | 1 + src/__tests__/Hooks-test.js | 1 + src/__tests__/LiveQueryClient-test.js | 1 + src/__tests__/ObjectStateMutations-test.js | 1 + src/__tests__/Parse-test.js | 15 +++++++ src/__tests__/ParseACL-test.js | 1 + src/__tests__/ParseConfig-test.js | 1 + src/__tests__/ParseLiveQuery-test.js | 1 + src/__tests__/ParseObject-test.js | 1 + src/__tests__/ParseOp-test.js | 1 + src/__tests__/ParseQuery-test.js | 1 + src/__tests__/ParseRelation-test.js | 1 + src/__tests__/ParseRole-test.js | 1 + src/__tests__/ParseUser-test.js | 23 +++++++++++ .../SingleInstanceStateController-test.js | 1 + .../UniqueInstanceStateController-test.js | 1 + src/__tests__/canBeSerialized-test.js | 1 + src/__tests__/decode-test.js | 1 + src/__tests__/encode-test.js | 1 + src/__tests__/unsavedChildren-test.js | 1 + 22 files changed, 95 insertions(+), 20 deletions(-) diff --git a/src/Parse.js b/src/Parse.js index 95154c1f8..f15f91da9 100644 --- a/src/Parse.js +++ b/src/Parse.js @@ -171,30 +171,30 @@ Object.defineProperty(Parse, 'liveQueryServerURL', { }); /** - * @member Parse.encryptedKey - * @type string + * @member Parse.encryptedUser + * @type boolean * @static */ -Object.defineProperty(Parse, 'encryptedKey', { +Object.defineProperty(Parse, 'encryptedUser', { get() { - return CoreManager.get('ENCRYPTED_KEY'); + return CoreManager.get('ENCRYPTED_USER'); }, set(value) { - CoreManager.set('ENCRYPTED_KEY', value); + CoreManager.set('ENCRYPTED_USER', value); } }); /** - * @member Parse.encryptedUser - * @type boolean + * @member Parse.encryptedKey + * @type string * @static */ -Object.defineProperty(Parse, 'encryptedUser', { +Object.defineProperty(Parse, 'encryptedKey', { get() { - return CoreManager.get('ENCRYPTED_USER'); + return CoreManager.get('ENCRYPTED_KEY'); }, set(value) { - CoreManager.set('ENCRYPTED_USER', value); + CoreManager.set('ENCRYPTED_KEY', value); } }); /* End setters */ @@ -283,6 +283,25 @@ Parse.dumpLocalDatastore = function() { return Parse.LocalDatastore._getAllContents(); } } + +/** + * Enable the current user encryption. + * This must be called before login any user. + * + * @static + */ +Parse.enableEncryptedUser = function() { + Parse.encryptedUser = true; +} +/** + * Flag that indicates whether Encrypted User is enabled. + * + * @static + */ +Parse.isEncryptedUserEnabled = function() { + return Parse.encryptedUser; +} + CoreManager.setInstallationController(InstallationController); CoreManager.setRESTController(RESTController); diff --git a/src/ParseUser.js b/src/ParseUser.js index 680606d41..7175f52d7 100644 --- a/src/ParseUser.js +++ b/src/ParseUser.js @@ -22,16 +22,16 @@ import type { RequestOptions, FullOptions } from './RESTController'; export type AuthData = ?{ [key: string]: mixed }; +let CryptoJS = null; +if (process.env.PARSE_BUILD === 'browser') { + CryptoJS = require('crypto-js'); +} + const CURRENT_USER_KEY = 'currentUser'; let canUseCurrentUser = !CoreManager.get('IS_NODE'); let currentUserCacheMatchesDisk = false; let currentUserCache = null; -let CryptoJS = null; -if (process.env.PARSE_BUILD === 'node' || process.env.PARSE_BUILD === 'browser') { - CryptoJS = require('crypto-js') -} - const authProviders = {}; /** @@ -879,7 +879,7 @@ const DefaultController = { json.className = user.constructor.name === ParseUser.name ? '_User' : user.constructor.name; return Storage.setItemAsync( path, - (!CoreManager.get('ENCRYPTED_USER')) + (!CoreManager.get('ENCRYPTED_USER') && process.env.PARSE_BUILD !== 'browser') ? JSON.stringify(json) : CryptoJS.AES.encrypt(JSON.stringify(json), CoreManager.get('ENCRYPTED_KEY')) ).then(() => { @@ -921,14 +921,14 @@ const DefaultController = { } const path = Storage.generatePath(CURRENT_USER_KEY); let userData = Storage.getItem(path); - if (CoreManager.get('ENCRYPTED_USER')) { - userData = CryptoJS.AES.decrypt(userData.toString(), CoreManager.get('ENCRYPTED_KEY')).toString(CryptoJS.enc.Utf8); - } currentUserCacheMatchesDisk = true; if (!userData) { currentUserCache = null; return null; } + if (CoreManager.get('ENCRYPTED_USER') && process.env.PARSE_BUILD === 'browser') { + userData = CryptoJS.AES.decrypt(userData.toString(), CoreManager.get('ENCRYPTED_KEY')).toString(CryptoJS.enc.Utf8); + } userData = JSON.parse(userData); if (!userData.className) { userData.className = '_User'; @@ -965,7 +965,7 @@ const DefaultController = { currentUserCache = null; return Promise.resolve(null); } - if (CoreManager.get('ENCRYPTED_USER')) { + if (CoreManager.get('ENCRYPTED_USER') && process.env.PARSE_BUILD === 'browser') { userData = CryptoJS.AES.decrypt(userData.toString(), CoreManager.get('ENCRYPTED_KEY')).toString(CryptoJS.enc.Utf8) } userData = JSON.parse(userData); diff --git a/src/__tests__/Cloud-test.js b/src/__tests__/Cloud-test.js index 2a5b9bfda..d2976937e 100644 --- a/src/__tests__/Cloud-test.js +++ b/src/__tests__/Cloud-test.js @@ -11,6 +11,7 @@ jest.dontMock('../Cloud'); jest.dontMock('../CoreManager'); jest.dontMock('../decode'); jest.dontMock('../encode'); +jest.dontMock('crypto-js'); const Cloud = require('../Cloud'); const CoreManager = require('../CoreManager'); diff --git a/src/__tests__/Hooks-test.js b/src/__tests__/Hooks-test.js index c81614f33..aa2c313b8 100644 --- a/src/__tests__/Hooks-test.js +++ b/src/__tests__/Hooks-test.js @@ -11,6 +11,7 @@ jest.dontMock('../ParseHooks'); jest.dontMock('../CoreManager'); jest.dontMock('../decode'); jest.dontMock('../encode'); +jest.dontMock('crypto-js'); const Hooks = require('../ParseHooks'); const CoreManager = require('../CoreManager'); diff --git a/src/__tests__/LiveQueryClient-test.js b/src/__tests__/LiveQueryClient-test.js index 46c9f65e9..0411a52ab 100644 --- a/src/__tests__/LiveQueryClient-test.js +++ b/src/__tests__/LiveQueryClient-test.js @@ -34,6 +34,7 @@ jest.dontMock('../ParseACL'); jest.dontMock('../ParseQuery'); jest.dontMock('../LiveQuerySubscription'); jest.dontMock('../LocalDatastore'); +jest.dontMock('crypto-js'); jest.useFakeTimers(); diff --git a/src/__tests__/ObjectStateMutations-test.js b/src/__tests__/ObjectStateMutations-test.js index 9f972d22e..93c7e04f0 100644 --- a/src/__tests__/ObjectStateMutations-test.js +++ b/src/__tests__/ObjectStateMutations-test.js @@ -15,6 +15,7 @@ jest.dontMock('../ParseGeoPoint'); jest.dontMock('../ParseOp'); jest.dontMock('../ParseRelation'); jest.dontMock('../TaskQueue'); +jest.dontMock('crypto-js'); const mockObject = function(className) { this.className = className; diff --git a/src/__tests__/Parse-test.js b/src/__tests__/Parse-test.js index de3a1bc28..5968b67ed 100644 --- a/src/__tests__/Parse-test.js +++ b/src/__tests__/Parse-test.js @@ -10,6 +10,7 @@ jest.dontMock('../CoreManager'); jest.dontMock('../Parse'); jest.dontMock('../LocalDatastore'); +jest.dontMock('crypto-js'); const CoreManager = require('../CoreManager'); const Parse = require('../Parse'); @@ -109,4 +110,18 @@ describe('Parse module', () => { LDS = await Parse.dumpLocalDatastore(); expect(LDS).toEqual({ key: 'value' }); }); + + it('can enable encrypter CurrentUser', () => { + jest.spyOn(console, 'log').mockImplementationOnce(() => {}); + Parse.encryptedUser = false; + Parse.enableEncryptedUser(); + expect(Parse.encryptedUser).toBe(true); + expect(Parse.isEncryptedUserEnabled()).toBe(true); + }); + + it('can set an encrypt token as String', () => { + Parse.encryptedKey = 'My Super secret key'; + expect(CoreManager.get('ENCRYPTED_KEY')).toBe('My Super secret key'); + expect(Parse.encryptedKey).toBe('My Super secret key'); + }); }); diff --git a/src/__tests__/ParseACL-test.js b/src/__tests__/ParseACL-test.js index 1fa63b356..8687d7cfe 100644 --- a/src/__tests__/ParseACL-test.js +++ b/src/__tests__/ParseACL-test.js @@ -8,6 +8,7 @@ */ jest.dontMock('../ParseACL'); +jest.dontMock('crypto-js'); const mockRole = function(name) { this.name = name; diff --git a/src/__tests__/ParseConfig-test.js b/src/__tests__/ParseConfig-test.js index 7f863dd9c..7a78c9a71 100644 --- a/src/__tests__/ParseConfig-test.js +++ b/src/__tests__/ParseConfig-test.js @@ -18,6 +18,7 @@ jest.dontMock('../ParseGeoPoint'); jest.dontMock('../RESTController'); jest.dontMock('../Storage'); jest.dontMock('../StorageController.default'); +jest.dontMock('crypto-js'); const CoreManager = require('../CoreManager'); const ParseConfig = require('../ParseConfig').default; diff --git a/src/__tests__/ParseLiveQuery-test.js b/src/__tests__/ParseLiveQuery-test.js index 366ced8f8..9841608de 100644 --- a/src/__tests__/ParseLiveQuery-test.js +++ b/src/__tests__/ParseLiveQuery-test.js @@ -16,6 +16,7 @@ jest.dontMock('../ParseObject'); jest.dontMock('../ParseQuery'); jest.dontMock('../EventEmitter'); jest.dontMock('../promiseUtils'); +jest.dontMock('crypto-js'); // Forces the loading const LiveQuery = require('../ParseLiveQuery').default; diff --git a/src/__tests__/ParseObject-test.js b/src/__tests__/ParseObject-test.js index 2f25e23ca..f78a60d02 100644 --- a/src/__tests__/ParseObject-test.js +++ b/src/__tests__/ParseObject-test.js @@ -31,6 +31,7 @@ jest.dontMock('../UniqueInstanceStateController'); jest.dontMock('../unsavedChildren'); jest.dontMock('../ParseACL'); jest.dontMock('../LocalDatastore'); +jest.dontMock('crypto-js'); jest.mock('uuid/v4', () => { let value = 0; diff --git a/src/__tests__/ParseOp-test.js b/src/__tests__/ParseOp-test.js index d600dfe4a..1d02e0f50 100644 --- a/src/__tests__/ParseOp-test.js +++ b/src/__tests__/ParseOp-test.js @@ -11,6 +11,7 @@ jest.dontMock('../arrayContainsObject'); jest.dontMock('../encode'); jest.dontMock('../ParseOp'); jest.dontMock('../unique'); +jest.dontMock('crypto-js'); let localCount = 0; const mockObject = function(className, id) { diff --git a/src/__tests__/ParseQuery-test.js b/src/__tests__/ParseQuery-test.js index 4452ec9f5..8979fa686 100644 --- a/src/__tests__/ParseQuery-test.js +++ b/src/__tests__/ParseQuery-test.js @@ -20,6 +20,7 @@ jest.dontMock('../ObjectStateMutations'); jest.dontMock('../LocalDatastore'); jest.dontMock('../OfflineQuery'); jest.dontMock('../LiveQuerySubscription'); +jest.dontMock('crypto-js'); jest.mock('uuid/v4', () => { let value = 0; diff --git a/src/__tests__/ParseRelation-test.js b/src/__tests__/ParseRelation-test.js index 326dc2cfc..c9e9b0ec9 100644 --- a/src/__tests__/ParseRelation-test.js +++ b/src/__tests__/ParseRelation-test.js @@ -11,6 +11,7 @@ jest.dontMock('../encode'); jest.dontMock('../ParseRelation'); jest.dontMock('../ParseOp'); jest.dontMock('../unique'); +jest.dontMock('crypto-js'); const mockStore = {}; const mockObject = function(className) { diff --git a/src/__tests__/ParseRole-test.js b/src/__tests__/ParseRole-test.js index 7ccb8e23d..05898f019 100644 --- a/src/__tests__/ParseRole-test.js +++ b/src/__tests__/ParseRole-test.js @@ -16,6 +16,7 @@ jest.dontMock('../ParseOp'); jest.dontMock('../ParseRole'); jest.dontMock('../SingleInstanceStateController'); jest.dontMock('../UniqueInstanceStateController'); +jest.dontMock('crypto-js'); const ParseACL = require('../ParseACL').default; const ParseError = require('../ParseError').default; diff --git a/src/__tests__/ParseUser-test.js b/src/__tests__/ParseUser-test.js index 21f4057d0..12fd76e66 100644 --- a/src/__tests__/ParseUser-test.js +++ b/src/__tests__/ParseUser-test.js @@ -26,6 +26,7 @@ jest.dontMock('../StorageController.default'); jest.dontMock('../TaskQueue'); jest.dontMock('../unique'); jest.dontMock('../UniqueInstanceStateController'); +jest.dontMock('crypto-js'); jest.mock('uuid/v4', () => { let value = 0; @@ -1009,4 +1010,26 @@ describe('ParseUser', () => { const authProvider = user.linkWith.mock.calls[0][0]; expect(authProvider).toBe('testProvider'); }); + + it('can get the current user even encrypted', async () => { + CoreManager.set('ENCRYPTED_USER', true); + CoreManager.set('ENCRYPTED_KEY', 'secret'); + let u = new ParseUser(); + expect(u.isCurrent()).toBe(false); + expect(u.className).toBe('_User'); + expect(u instanceof ParseObject).toBe(true); + + u = new ParseUser({ + username: 'andrew', + password: 'secret' + }); + expect(u.get('username')).toBe('andrew'); + expect(u.get('password')).toBe('secret'); + + expect(function() { + new ParseUser({ + $$$: 'invalid' + }); + }).toThrow('Can\'t create an invalid Parse User'); + }); }); diff --git a/src/__tests__/SingleInstanceStateController-test.js b/src/__tests__/SingleInstanceStateController-test.js index 5883b261e..e974dc98e 100644 --- a/src/__tests__/SingleInstanceStateController-test.js +++ b/src/__tests__/SingleInstanceStateController-test.js @@ -15,6 +15,7 @@ jest.dontMock('../ParseGeoPoint'); jest.dontMock('../ParseOp'); jest.dontMock('../SingleInstanceStateController'); jest.dontMock('../TaskQueue'); +jest.dontMock('crypto-js'); const mockObject = function() {}; mockObject.registerSubclass = function() {}; diff --git a/src/__tests__/UniqueInstanceStateController-test.js b/src/__tests__/UniqueInstanceStateController-test.js index 2f1dcf64f..b4ecbcae2 100644 --- a/src/__tests__/UniqueInstanceStateController-test.js +++ b/src/__tests__/UniqueInstanceStateController-test.js @@ -16,6 +16,7 @@ jest.dontMock('../ParseOp'); jest.dontMock('../UniqueInstanceStateController'); jest.dontMock('../TaskQueue'); jest.dontMock('../promiseUtils'); +jest.dontMock('crypto-js'); jest.useFakeTimers(); const mockObject = function(className) { diff --git a/src/__tests__/canBeSerialized-test.js b/src/__tests__/canBeSerialized-test.js index 954e32595..d19b9df59 100644 --- a/src/__tests__/canBeSerialized-test.js +++ b/src/__tests__/canBeSerialized-test.js @@ -8,6 +8,7 @@ */ jest.dontMock('../canBeSerialized'); +jest.dontMock('crypto-js'); function mockObject(id, attributes) { this.id = id; diff --git a/src/__tests__/decode-test.js b/src/__tests__/decode-test.js index 2397ccacf..8b9d3572c 100644 --- a/src/__tests__/decode-test.js +++ b/src/__tests__/decode-test.js @@ -10,6 +10,7 @@ jest.dontMock('../decode'); jest.dontMock('../ParseFile'); jest.dontMock('../ParseGeoPoint'); +jest.dontMock('crypto-js'); const decode = require('../decode').default; diff --git a/src/__tests__/encode-test.js b/src/__tests__/encode-test.js index 79d37caab..12f76a1cd 100644 --- a/src/__tests__/encode-test.js +++ b/src/__tests__/encode-test.js @@ -11,6 +11,7 @@ jest.dontMock('../encode'); jest.dontMock('../ParseACL'); jest.dontMock('../ParseFile'); jest.dontMock('../ParseGeoPoint'); +jest.dontMock('crypto-js'); const mockObject = function(className) { this.className = className; diff --git a/src/__tests__/unsavedChildren-test.js b/src/__tests__/unsavedChildren-test.js index 31084452e..854b1df88 100644 --- a/src/__tests__/unsavedChildren-test.js +++ b/src/__tests__/unsavedChildren-test.js @@ -9,6 +9,7 @@ jest.dontMock('../ParseFile'); jest.dontMock('../unsavedChildren'); +jest.dontMock('crypto-js'); function mockObject({ className, localId, id, attributes, dirty }) { this.className = className; From 47dd663b1b6ad8bf08e1424d2c8285579713dd73 Mon Sep 17 00:00:00 2001 From: Arturo Ortega Date: Tue, 17 Dec 2019 16:55:16 -0600 Subject: [PATCH 3/6] secret variable, tests improvement, only browser --- package.json | 2 +- src/Parse.js | 10 +++++-- src/ParseUser.js | 10 +++---- src/__tests__/Parse-test.js | 5 ++-- src/__tests__/ParseUser-test.js | 49 +++++++++++++++++++++++++++++++++ 5 files changed, 65 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 572368104..eb6fc85f3 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "dependencies": { "@babel/runtime": "7.7.4", "@babel/runtime-corejs3": "7.7.4", - "crypto-js": "^3.1.9-1", + "crypto-js": "3.1.9-1", "uuid": "3.3.3", "ws": "7.2.0", "xmlhttprequest": "1.8.0" diff --git a/src/Parse.js b/src/Parse.js index f15f91da9..01a3e61c4 100644 --- a/src/Parse.js +++ b/src/Parse.js @@ -185,11 +185,11 @@ Object.defineProperty(Parse, 'encryptedUser', { }); /** - * @member Parse.encryptedKey + * @member Parse.secret * @type string * @static */ -Object.defineProperty(Parse, 'encryptedKey', { +Object.defineProperty(Parse, 'secret', { get() { return CoreManager.get('ENCRYPTED_KEY'); }, @@ -291,7 +291,11 @@ Parse.dumpLocalDatastore = function() { * @static */ Parse.enableEncryptedUser = function() { - Parse.encryptedUser = true; + if(process.env.PARSE_BUILD === 'browser') { + Parse.encryptedUser = true; + } else { + console.log('This option is only valid in the browser'); + } } /** * Flag that indicates whether Encrypted User is enabled. diff --git a/src/ParseUser.js b/src/ParseUser.js index 7175f52d7..9814959dd 100644 --- a/src/ParseUser.js +++ b/src/ParseUser.js @@ -879,9 +879,9 @@ const DefaultController = { json.className = user.constructor.name === ParseUser.name ? '_User' : user.constructor.name; return Storage.setItemAsync( path, - (!CoreManager.get('ENCRYPTED_USER') && process.env.PARSE_BUILD !== 'browser') - ? JSON.stringify(json) - : CryptoJS.AES.encrypt(JSON.stringify(json), CoreManager.get('ENCRYPTED_KEY')) + (CoreManager.get('ENCRYPTED_USER') && CoreManager.get('ENCRYPTED_KEY') && process.env.PARSE_BUILD === 'browser') + ? CryptoJS.AES.encrypt(JSON.stringify(json), CoreManager.get('ENCRYPTED_KEY')) + : JSON.stringify(json) ).then(() => { return user; }); @@ -926,7 +926,7 @@ const DefaultController = { currentUserCache = null; return null; } - if (CoreManager.get('ENCRYPTED_USER') && process.env.PARSE_BUILD === 'browser') { + if (CoreManager.get('ENCRYPTED_USER') && CoreManager.get('ENCRYPTED_KEY') && process.env.PARSE_BUILD === 'browser') { userData = CryptoJS.AES.decrypt(userData.toString(), CoreManager.get('ENCRYPTED_KEY')).toString(CryptoJS.enc.Utf8); } userData = JSON.parse(userData); @@ -965,7 +965,7 @@ const DefaultController = { currentUserCache = null; return Promise.resolve(null); } - if (CoreManager.get('ENCRYPTED_USER') && process.env.PARSE_BUILD === 'browser') { + if (CoreManager.get('ENCRYPTED_USER') && CoreManager.get('ENCRYPTED_KEY') && process.env.PARSE_BUILD === 'browser') { userData = CryptoJS.AES.decrypt(userData.toString(), CoreManager.get('ENCRYPTED_KEY')).toString(CryptoJS.enc.Utf8) } userData = JSON.parse(userData); diff --git a/src/__tests__/Parse-test.js b/src/__tests__/Parse-test.js index 5968b67ed..222900d35 100644 --- a/src/__tests__/Parse-test.js +++ b/src/__tests__/Parse-test.js @@ -113,6 +113,7 @@ describe('Parse module', () => { it('can enable encrypter CurrentUser', () => { jest.spyOn(console, 'log').mockImplementationOnce(() => {}); + process.env.PARSE_BUILD = 'browser'; Parse.encryptedUser = false; Parse.enableEncryptedUser(); expect(Parse.encryptedUser).toBe(true); @@ -120,8 +121,8 @@ describe('Parse module', () => { }); it('can set an encrypt token as String', () => { - Parse.encryptedKey = 'My Super secret key'; + Parse.secret = 'My Super secret key'; expect(CoreManager.get('ENCRYPTED_KEY')).toBe('My Super secret key'); - expect(Parse.encryptedKey).toBe('My Super secret key'); + expect(Parse.secret).toBe('My Super secret key'); }); }); diff --git a/src/__tests__/ParseUser-test.js b/src/__tests__/ParseUser-test.js index 12fd76e66..31616a7e1 100644 --- a/src/__tests__/ParseUser-test.js +++ b/src/__tests__/ParseUser-test.js @@ -1011,9 +1011,58 @@ describe('ParseUser', () => { expect(authProvider).toBe('testProvider'); }); + it('Enable Encrypted User without secret token', async () => { + process.env.PARSE_BUILD = 'browser'; + CoreManager.set('ENCRYPTED_USER', true); + expect(CoreManager.get('ENCRYPTED_KEY')).toBe(null); + let u = new ParseUser(); + expect(u.isCurrent()).toBe(false); + expect(u.className).toBe('_User'); + expect(u instanceof ParseObject).toBe(true); + + u = new ParseUser({ + username: 'andrew', + password: 'secret' + }); + expect(u.get('username')).toBe('andrew'); + expect(u.get('password')).toBe('secret'); + + expect(function() { + new ParseUser({ + $$$: 'invalid' + }); + }).toThrow('Can\'t create an invalid Parse User'); + }); + it('can get the current user even encrypted', async () => { + process.env.PARSE_BUILD = 'browser'; + CoreManager.set('ENCRYPTED_USER', true); + CoreManager.set('ENCRYPTED_KEY', 'secret'); + let u = new ParseUser(); + expect(u.isCurrent()).toBe(false); + expect(u.className).toBe('_User'); + expect(u instanceof ParseObject).toBe(true); + + u = new ParseUser({ + username: 'andrew', + password: 'secret' + }); + expect(u.get('username')).toBe('andrew'); + expect(u.get('password')).toBe('secret'); + + expect(function() { + new ParseUser({ + $$$: 'invalid' + }); + }).toThrow('Can\'t create an invalid Parse User'); + }); + + it('Testing the encryption in other env build', async () => { + process.env.PARSE_BUILD = 'node'; CoreManager.set('ENCRYPTED_USER', true); + expect(CoreManager.get('ENCRYPTED_USER')).toBe(true); CoreManager.set('ENCRYPTED_KEY', 'secret'); + expect(CoreManager.get('ENCRYPTED_KEY')).toBe('secret'); let u = new ParseUser(); expect(u.isCurrent()).toBe(false); expect(u.className).toBe('_User'); From 4a8292c6798cd800f90bd5ea1af71d8ea4c8fa55 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Mon, 23 Dec 2019 13:55:11 -0600 Subject: [PATCH 4/6] fix conflicts --- package-lock.json | 22 ++++++++++++++-------- src/__tests__/ParseUser-test.js | 4 +--- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1ea837535..5899a8492 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3758,6 +3758,11 @@ "randomfill": "^1.0.3" } }, + "crypto-js": { + "version": "3.1.9-1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz", + "integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg=" + }, "cssom": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", @@ -10379,9 +10384,9 @@ "@apollographql/graphql-playground-html": "1.6.24", "@parse/fs-files-adapter": "1.0.1", "@parse/push-adapter": "3.2.0", - "@parse/s3-files-adapter": "1.3.0", + "@parse/s3-files-adapter": "1.4.0", "@parse/simple-mailgun-adapter": "1.1.0", - "apollo-server-express": "2.9.12", + "apollo-server-express": "2.9.14", "bcrypt": "3.0.7", "bcryptjs": "2.4.3", "body-parser": "1.19.0", @@ -10394,25 +10399,26 @@ "graphql-list-fields": "2.0.2", "graphql-relay": "^0.6.0", "graphql-tools": "^4.0.5", - "graphql-upload": "8.1.0", + "graphql-upload": "9.0.0", "intersect": "1.0.1", "jsonwebtoken": "8.5.1", "ldapjs": "1.0.2", "lodash": "4.17.15", "lru-cache": "5.1.1", "mime": "2.4.4", - "mongodb": "3.3.2", + "mongodb": "3.4.1", "node-rsa": "1.0.7", - "parse": "2.9.1", + "parse": "2.10.0", "pg-promise": "10.3.1", "pluralize": "^8.0.0", "redis": "2.8.0", - "semver": "6.3.0", + "semver": "7.1.1", "subscriptions-transport-ws": "0.9.16", "tv4": "1.3.0", "uuid": "3.3.3", "winston": "3.2.1", - "winston-daily-rotate-file": "3.10.0" + "winston-daily-rotate-file": "3.10.0", + "ws": "7.2.1" }, "dependencies": { "commander": { @@ -13864,4 +13870,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/__tests__/ParseUser-test.js b/src/__tests__/ParseUser-test.js index 4e5ac9b68..cfbb331bc 100644 --- a/src/__tests__/ParseUser-test.js +++ b/src/__tests__/ParseUser-test.js @@ -1056,7 +1056,7 @@ describe('ParseUser', () => { }); }).toThrow('Can\'t create an invalid Parse User'); }); - + it('Testing the encryption in other env build', async () => { process.env.PARSE_BUILD = 'node'; CoreManager.set('ENCRYPTED_USER', true); @@ -1090,7 +1090,6 @@ describe('ParseUser', () => { request(method, path, body, options) { expect(method).toBe('POST'); expect(path).toBe('users'); - console.log(options); expect(options.installationId).toBe(installationId); return Promise.resolve({ objectId: 'uid3', @@ -1115,7 +1114,6 @@ describe('ParseUser', () => { request(method, path, body, options) { expect(method).toBe('POST'); expect(path).toBe('users'); - console.log(options); expect(options.installationId).toBe(installationId); return Promise.resolve({ objectId: 'uid3', From b3f13855e62375742c2a967801a2fa067c8ee0e7 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Mon, 23 Dec 2019 16:02:59 -0600 Subject: [PATCH 5/6] improve test and cleanup --- integration/test/ParseUserTest.js | 26 +++++ src/CoreManager.js | 13 +++ src/CryptoController.js | 28 +++++ src/Parse.js | 9 +- src/ParseUser.js | 25 ++-- src/__tests__/Cloud-test.js | 1 - src/__tests__/Hooks-test.js | 1 - src/__tests__/LiveQueryClient-test.js | 1 - src/__tests__/ObjectStateMutations-test.js | 1 - src/__tests__/Parse-test.js | 3 +- src/__tests__/ParseACL-test.js | 1 - src/__tests__/ParseConfig-test.js | 1 - src/__tests__/ParseLiveQuery-test.js | 1 - src/__tests__/ParseObject-test.js | 1 - src/__tests__/ParseOp-test.js | 1 - src/__tests__/ParseQuery-test.js | 1 - src/__tests__/ParseRelation-test.js | 1 - src/__tests__/ParseRole-test.js | 1 - src/__tests__/ParseUser-test.js | 110 ++++++++---------- .../SingleInstanceStateController-test.js | 1 - .../UniqueInstanceStateController-test.js | 1 - src/__tests__/canBeSerialized-test.js | 1 - src/__tests__/decode-test.js | 1 - src/__tests__/encode-test.js | 1 - src/__tests__/unsavedChildren-test.js | 1 - 25 files changed, 131 insertions(+), 101 deletions(-) create mode 100644 src/CryptoController.js diff --git a/integration/test/ParseUserTest.js b/integration/test/ParseUserTest.js index 6590ac8f8..0f688b337 100644 --- a/integration/test/ParseUserTest.js +++ b/integration/test/ParseUserTest.js @@ -936,6 +936,32 @@ describe('Parse User', () => { expect(user.get('authData').facebook.id).toBe('test'); }); + it('can encrypt user', async () => { + Parse.User.enableUnsafeCurrentUser(); + Parse.enableEncryptedUser(); + Parse.secret = 'My Secret Key'; + const user = new Parse.User(); + user.setUsername('usernameENC'); + user.setPassword('passwordENC'); + await user.signUp(); + + const path = Parse.Storage.generatePath('currentUser'); + const encryptedUser = Parse.Storage.getItem(path); + + const crypto = Parse.CoreManager.getCryptoController(); + const decryptedUser = crypto.decrypt(encryptedUser, Parse.CoreManager.get('ENCRYPTED_KEY')) + expect(JSON.parse(decryptedUser).objectId).toBe(user.id); + + const currentUser = Parse.User.current(); + expect(currentUser).toEqual(user); + + const currentUserAsync = await Parse.User.currentAsync(); + expect(currentUserAsync).toEqual(user); + await Parse.User.logOut(); + Parse.CoreManager.set('ENCRYPTED_USER', false); + Parse.CoreManager.set('ENCRYPTED_KEY', null); + }); + it('fix GHSA-wvh7-5p38-2qfc', async () => { Parse.User.enableUnsafeCurrentUser(); const user = new Parse.User(); diff --git a/src/CoreManager.js b/src/CoreManager.js index 54809ac2b..73e863128 100644 --- a/src/CoreManager.js +++ b/src/CoreManager.js @@ -33,6 +33,10 @@ type ConfigController = { get: () => Promise; save: (attrs: { [key: string]: any }) => Promise; }; +type CryptoController = { + encrypt: (obj: any, secretKey: string) => string; + decrypt: (encryptedText: string, secretKey: any) => string; +}; type FileController = { saveFile: (name: string, source: FileSource, options: FullOptions) => Promise; saveBase64: (name: string, source: FileSource, options: FullOptions) => Promise; @@ -236,6 +240,15 @@ module.exports = { return config['ConfigController']; }, + setCryptoController(controller: CryptoController) { + requireMethods('CryptoController', ['encrypt', 'decrypt'], controller); + config['CryptoController'] = controller; + }, + + getCryptoController(): CryptoController { + return config['CryptoController']; + }, + setFileController(controller: FileController) { requireMethods('FileController', ['saveFile', 'saveBase64'], controller); config['FileController'] = controller; diff --git a/src/CryptoController.js b/src/CryptoController.js new file mode 100644 index 000000000..aebf9df24 --- /dev/null +++ b/src/CryptoController.js @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ + +import AES from 'crypto-js/aes'; +import ENC from 'crypto-js/enc-utf8'; + +const CryptoController = { + encrypt(obj: any, secretKey: string): ?string { + const encrypted = AES.encrypt(JSON.stringify(obj), secretKey); + + return encrypted.toString(); + }, + + decrypt(encryptedText: string, secretKey: string): ?string { + const decryptedStr = AES.decrypt(encryptedText, secretKey).toString(ENC); + return decryptedStr; + }, +}; + +module.exports = CryptoController; diff --git a/src/Parse.js b/src/Parse.js index 01a3e61c4..a3fc29da6 100644 --- a/src/Parse.js +++ b/src/Parse.js @@ -10,6 +10,7 @@ import decode from './decode'; import encode from './encode'; import CoreManager from './CoreManager'; +import CryptoController from './CryptoController'; import InstallationController from './InstallationController'; import * as ParseOp from './ParseOp'; import RESTController from './RESTController'; @@ -291,12 +292,9 @@ Parse.dumpLocalDatastore = function() { * @static */ Parse.enableEncryptedUser = function() { - if(process.env.PARSE_BUILD === 'browser') { - Parse.encryptedUser = true; - } else { - console.log('This option is only valid in the browser'); - } + Parse.encryptedUser = true; } + /** * Flag that indicates whether Encrypted User is enabled. * @@ -306,6 +304,7 @@ Parse.isEncryptedUserEnabled = function() { return Parse.encryptedUser; } +CoreManager.setCryptoController(CryptoController); CoreManager.setInstallationController(InstallationController); CoreManager.setRESTController(RESTController); diff --git a/src/ParseUser.js b/src/ParseUser.js index 17a8d9866..9de4bb73d 100644 --- a/src/ParseUser.js +++ b/src/ParseUser.js @@ -22,11 +22,6 @@ import type { RequestOptions, FullOptions } from './RESTController'; export type AuthData = ?{ [key: string]: mixed }; -let CryptoJS = null; -if (process.env.PARSE_BUILD === 'browser') { - CryptoJS = require('crypto-js'); -} - const CURRENT_USER_KEY = 'currentUser'; let canUseCurrentUser = !CoreManager.get('IS_NODE'); let currentUserCacheMatchesDisk = false; @@ -877,11 +872,13 @@ const DefaultController = { delete json.password; json.className = '_User'; + let userData = JSON.stringify(json); + if (CoreManager.get('ENCRYPTED_USER')) { + const crypto = CoreManager.getCryptoController(); + userData = crypto.encrypt(json, CoreManager.get('ENCRYPTED_KEY')) + } return Storage.setItemAsync( - path, - (CoreManager.get('ENCRYPTED_USER') && CoreManager.get('ENCRYPTED_KEY') && process.env.PARSE_BUILD === 'browser') - ? CryptoJS.AES.encrypt(JSON.stringify(json), CoreManager.get('ENCRYPTED_KEY')) - : JSON.stringify(json) + path, userData ).then(() => { return user; }); @@ -926,8 +923,9 @@ const DefaultController = { currentUserCache = null; return null; } - if (CoreManager.get('ENCRYPTED_USER') && CoreManager.get('ENCRYPTED_KEY') && process.env.PARSE_BUILD === 'browser') { - userData = CryptoJS.AES.decrypt(userData.toString(), CoreManager.get('ENCRYPTED_KEY')).toString(CryptoJS.enc.Utf8); + if (CoreManager.get('ENCRYPTED_USER')) { + const crypto = CoreManager.getCryptoController(); + userData = crypto.decrypt(userData.toString(), CoreManager.get('ENCRYPTED_KEY')); } userData = JSON.parse(userData); if (!userData.className) { @@ -965,8 +963,9 @@ const DefaultController = { currentUserCache = null; return Promise.resolve(null); } - if (CoreManager.get('ENCRYPTED_USER') && CoreManager.get('ENCRYPTED_KEY') && process.env.PARSE_BUILD === 'browser') { - userData = CryptoJS.AES.decrypt(userData.toString(), CoreManager.get('ENCRYPTED_KEY')).toString(CryptoJS.enc.Utf8) + if (CoreManager.get('ENCRYPTED_USER')) { + const crypto = CoreManager.getCryptoController(); + userData = crypto.decrypt(userData.toString(), CoreManager.get('ENCRYPTED_KEY')); } userData = JSON.parse(userData); if (!userData.className) { diff --git a/src/__tests__/Cloud-test.js b/src/__tests__/Cloud-test.js index d2976937e..2a5b9bfda 100644 --- a/src/__tests__/Cloud-test.js +++ b/src/__tests__/Cloud-test.js @@ -11,7 +11,6 @@ jest.dontMock('../Cloud'); jest.dontMock('../CoreManager'); jest.dontMock('../decode'); jest.dontMock('../encode'); -jest.dontMock('crypto-js'); const Cloud = require('../Cloud'); const CoreManager = require('../CoreManager'); diff --git a/src/__tests__/Hooks-test.js b/src/__tests__/Hooks-test.js index aa2c313b8..c81614f33 100644 --- a/src/__tests__/Hooks-test.js +++ b/src/__tests__/Hooks-test.js @@ -11,7 +11,6 @@ jest.dontMock('../ParseHooks'); jest.dontMock('../CoreManager'); jest.dontMock('../decode'); jest.dontMock('../encode'); -jest.dontMock('crypto-js'); const Hooks = require('../ParseHooks'); const CoreManager = require('../CoreManager'); diff --git a/src/__tests__/LiveQueryClient-test.js b/src/__tests__/LiveQueryClient-test.js index 0411a52ab..46c9f65e9 100644 --- a/src/__tests__/LiveQueryClient-test.js +++ b/src/__tests__/LiveQueryClient-test.js @@ -34,7 +34,6 @@ jest.dontMock('../ParseACL'); jest.dontMock('../ParseQuery'); jest.dontMock('../LiveQuerySubscription'); jest.dontMock('../LocalDatastore'); -jest.dontMock('crypto-js'); jest.useFakeTimers(); diff --git a/src/__tests__/ObjectStateMutations-test.js b/src/__tests__/ObjectStateMutations-test.js index 93c7e04f0..9f972d22e 100644 --- a/src/__tests__/ObjectStateMutations-test.js +++ b/src/__tests__/ObjectStateMutations-test.js @@ -15,7 +15,6 @@ jest.dontMock('../ParseGeoPoint'); jest.dontMock('../ParseOp'); jest.dontMock('../ParseRelation'); jest.dontMock('../TaskQueue'); -jest.dontMock('crypto-js'); const mockObject = function(className) { this.className = className; diff --git a/src/__tests__/Parse-test.js b/src/__tests__/Parse-test.js index 222900d35..cfdd10dcd 100644 --- a/src/__tests__/Parse-test.js +++ b/src/__tests__/Parse-test.js @@ -8,9 +8,10 @@ */ jest.dontMock('../CoreManager'); +jest.dontMock('../CryptoController'); jest.dontMock('../Parse'); jest.dontMock('../LocalDatastore'); -jest.dontMock('crypto-js'); +jest.dontMock('crypto-js/aes'); const CoreManager = require('../CoreManager'); const Parse = require('../Parse'); diff --git a/src/__tests__/ParseACL-test.js b/src/__tests__/ParseACL-test.js index 8687d7cfe..1fa63b356 100644 --- a/src/__tests__/ParseACL-test.js +++ b/src/__tests__/ParseACL-test.js @@ -8,7 +8,6 @@ */ jest.dontMock('../ParseACL'); -jest.dontMock('crypto-js'); const mockRole = function(name) { this.name = name; diff --git a/src/__tests__/ParseConfig-test.js b/src/__tests__/ParseConfig-test.js index 7a78c9a71..7f863dd9c 100644 --- a/src/__tests__/ParseConfig-test.js +++ b/src/__tests__/ParseConfig-test.js @@ -18,7 +18,6 @@ jest.dontMock('../ParseGeoPoint'); jest.dontMock('../RESTController'); jest.dontMock('../Storage'); jest.dontMock('../StorageController.default'); -jest.dontMock('crypto-js'); const CoreManager = require('../CoreManager'); const ParseConfig = require('../ParseConfig').default; diff --git a/src/__tests__/ParseLiveQuery-test.js b/src/__tests__/ParseLiveQuery-test.js index 9841608de..366ced8f8 100644 --- a/src/__tests__/ParseLiveQuery-test.js +++ b/src/__tests__/ParseLiveQuery-test.js @@ -16,7 +16,6 @@ jest.dontMock('../ParseObject'); jest.dontMock('../ParseQuery'); jest.dontMock('../EventEmitter'); jest.dontMock('../promiseUtils'); -jest.dontMock('crypto-js'); // Forces the loading const LiveQuery = require('../ParseLiveQuery').default; diff --git a/src/__tests__/ParseObject-test.js b/src/__tests__/ParseObject-test.js index f78a60d02..2f25e23ca 100644 --- a/src/__tests__/ParseObject-test.js +++ b/src/__tests__/ParseObject-test.js @@ -31,7 +31,6 @@ jest.dontMock('../UniqueInstanceStateController'); jest.dontMock('../unsavedChildren'); jest.dontMock('../ParseACL'); jest.dontMock('../LocalDatastore'); -jest.dontMock('crypto-js'); jest.mock('uuid/v4', () => { let value = 0; diff --git a/src/__tests__/ParseOp-test.js b/src/__tests__/ParseOp-test.js index 1d02e0f50..d600dfe4a 100644 --- a/src/__tests__/ParseOp-test.js +++ b/src/__tests__/ParseOp-test.js @@ -11,7 +11,6 @@ jest.dontMock('../arrayContainsObject'); jest.dontMock('../encode'); jest.dontMock('../ParseOp'); jest.dontMock('../unique'); -jest.dontMock('crypto-js'); let localCount = 0; const mockObject = function(className, id) { diff --git a/src/__tests__/ParseQuery-test.js b/src/__tests__/ParseQuery-test.js index 2bd8bd083..0e7807a7e 100644 --- a/src/__tests__/ParseQuery-test.js +++ b/src/__tests__/ParseQuery-test.js @@ -20,7 +20,6 @@ jest.dontMock('../ObjectStateMutations'); jest.dontMock('../LocalDatastore'); jest.dontMock('../OfflineQuery'); jest.dontMock('../LiveQuerySubscription'); -jest.dontMock('crypto-js'); jest.mock('uuid/v4', () => { let value = 0; diff --git a/src/__tests__/ParseRelation-test.js b/src/__tests__/ParseRelation-test.js index c9e9b0ec9..326dc2cfc 100644 --- a/src/__tests__/ParseRelation-test.js +++ b/src/__tests__/ParseRelation-test.js @@ -11,7 +11,6 @@ jest.dontMock('../encode'); jest.dontMock('../ParseRelation'); jest.dontMock('../ParseOp'); jest.dontMock('../unique'); -jest.dontMock('crypto-js'); const mockStore = {}; const mockObject = function(className) { diff --git a/src/__tests__/ParseRole-test.js b/src/__tests__/ParseRole-test.js index 05898f019..7ccb8e23d 100644 --- a/src/__tests__/ParseRole-test.js +++ b/src/__tests__/ParseRole-test.js @@ -16,7 +16,6 @@ jest.dontMock('../ParseOp'); jest.dontMock('../ParseRole'); jest.dontMock('../SingleInstanceStateController'); jest.dontMock('../UniqueInstanceStateController'); -jest.dontMock('crypto-js'); const ParseACL = require('../ParseACL').default; const ParseError = require('../ParseError').default; diff --git a/src/__tests__/ParseUser-test.js b/src/__tests__/ParseUser-test.js index cfbb331bc..b7141d0fa 100644 --- a/src/__tests__/ParseUser-test.js +++ b/src/__tests__/ParseUser-test.js @@ -9,6 +9,7 @@ jest.dontMock('../AnonymousUtils'); jest.dontMock('../CoreManager'); +jest.dontMock('../CryptoController'); jest.dontMock('../decode'); jest.dontMock('../encode'); jest.dontMock('../isRevocableSession'); @@ -26,7 +27,6 @@ jest.dontMock('../StorageController.default'); jest.dontMock('../TaskQueue'); jest.dontMock('../unique'); jest.dontMock('../UniqueInstanceStateController'); -jest.dontMock('crypto-js'); jest.mock('uuid/v4', () => { let value = 0; @@ -1011,75 +1011,57 @@ describe('ParseUser', () => { expect(authProvider).toBe('testProvider'); }); - it('Enable Encrypted User without secret token', async () => { - process.env.PARSE_BUILD = 'browser'; + it('can encrypt user', async () => { CoreManager.set('ENCRYPTED_USER', true); - expect(CoreManager.get('ENCRYPTED_KEY')).toBe(null); - let u = new ParseUser(); - expect(u.isCurrent()).toBe(false); - expect(u.className).toBe('_User'); - expect(u instanceof ParseObject).toBe(true); + CoreManager.set('ENCRYPTED_KEY', 'hello'); + const ENCRYPTED_DATA = 'encryptedString'; - u = new ParseUser({ - username: 'andrew', - password: 'secret' - }); - expect(u.get('username')).toBe('andrew'); - expect(u.get('password')).toBe('secret'); - - expect(function() { - new ParseUser({ - $$$: 'invalid' - }); - }).toThrow('Can\'t create an invalid Parse User'); - }); - - it('can get the current user even encrypted', async () => { - process.env.PARSE_BUILD = 'browser'; - CoreManager.set('ENCRYPTED_USER', true); - CoreManager.set('ENCRYPTED_KEY', 'secret'); - let u = new ParseUser(); - expect(u.isCurrent()).toBe(false); - expect(u.className).toBe('_User'); - expect(u instanceof ParseObject).toBe(true); + ParseUser.enableUnsafeCurrentUser(); + ParseUser._clearCache(); + Storage._clear(); + let u = null; + CoreManager.setRESTController({ + request(method, path, body) { + expect(method).toBe('GET'); + expect(path).toBe('login'); + expect(body.username).toBe('username'); + expect(body.password).toBe('password'); - u = new ParseUser({ - username: 'andrew', - password: 'secret' + return Promise.resolve({ + objectId: 'uid2', + username: 'username', + sessionToken: '123abc' + }, 200); + }, + ajax() {} }); - expect(u.get('username')).toBe('andrew'); - expect(u.get('password')).toBe('secret'); - - expect(function() { - new ParseUser({ - $$$: 'invalid' - }); - }).toThrow('Can\'t create an invalid Parse User'); - }); - - it('Testing the encryption in other env build', async () => { - process.env.PARSE_BUILD = 'node'; - CoreManager.set('ENCRYPTED_USER', true); - expect(CoreManager.get('ENCRYPTED_USER')).toBe(true); - CoreManager.set('ENCRYPTED_KEY', 'secret'); - expect(CoreManager.get('ENCRYPTED_KEY')).toBe('secret'); - let u = new ParseUser(); - expect(u.isCurrent()).toBe(false); - expect(u.className).toBe('_User'); - expect(u instanceof ParseObject).toBe(true); - - u = new ParseUser({ - username: 'andrew', - password: 'secret' + CoreManager.setCryptoController({ + encrypt(obj, secretKey) { + expect(secretKey).toBe('hello'); + return ENCRYPTED_DATA; + }, + decrypt(encryptedText, secretKey) { + expect(encryptedText).toBe(ENCRYPTED_DATA); + expect(secretKey).toBe('hello'); + return JSON.stringify(u.toJSON()); + }, }); - expect(u.get('username')).toBe('andrew'); - expect(u.get('password')).toBe('secret'); + u = await ParseUser.logIn('username', 'password'); + // Clear cache to read from disk + ParseUser._clearCache(); - expect(function() { - new ParseUser({ - $$$: 'invalid' - }); - }).toThrow('Can\'t create an invalid Parse User'); + expect(u.id).toBe('uid2'); + expect(u.getSessionToken()).toBe('123abc'); + expect(u.isCurrent()).toBe(true); + expect(u.authenticated()).toBe(true); + expect(ParseUser.current().id).toBe('uid2'); + + const path = Storage.generatePath('currentUser'); + const userStorage = Storage.getItem(path); + expect(userStorage).toBe(ENCRYPTED_DATA); + CoreManager.set('ENCRYPTED_USER', false); + CoreManager.set('ENCRYPTED_KEY', null); + Storage._clear(); }); it('can static signup a user with installationId', async () => { diff --git a/src/__tests__/SingleInstanceStateController-test.js b/src/__tests__/SingleInstanceStateController-test.js index e974dc98e..5883b261e 100644 --- a/src/__tests__/SingleInstanceStateController-test.js +++ b/src/__tests__/SingleInstanceStateController-test.js @@ -15,7 +15,6 @@ jest.dontMock('../ParseGeoPoint'); jest.dontMock('../ParseOp'); jest.dontMock('../SingleInstanceStateController'); jest.dontMock('../TaskQueue'); -jest.dontMock('crypto-js'); const mockObject = function() {}; mockObject.registerSubclass = function() {}; diff --git a/src/__tests__/UniqueInstanceStateController-test.js b/src/__tests__/UniqueInstanceStateController-test.js index b4ecbcae2..2f1dcf64f 100644 --- a/src/__tests__/UniqueInstanceStateController-test.js +++ b/src/__tests__/UniqueInstanceStateController-test.js @@ -16,7 +16,6 @@ jest.dontMock('../ParseOp'); jest.dontMock('../UniqueInstanceStateController'); jest.dontMock('../TaskQueue'); jest.dontMock('../promiseUtils'); -jest.dontMock('crypto-js'); jest.useFakeTimers(); const mockObject = function(className) { diff --git a/src/__tests__/canBeSerialized-test.js b/src/__tests__/canBeSerialized-test.js index d19b9df59..954e32595 100644 --- a/src/__tests__/canBeSerialized-test.js +++ b/src/__tests__/canBeSerialized-test.js @@ -8,7 +8,6 @@ */ jest.dontMock('../canBeSerialized'); -jest.dontMock('crypto-js'); function mockObject(id, attributes) { this.id = id; diff --git a/src/__tests__/decode-test.js b/src/__tests__/decode-test.js index 8b9d3572c..2397ccacf 100644 --- a/src/__tests__/decode-test.js +++ b/src/__tests__/decode-test.js @@ -10,7 +10,6 @@ jest.dontMock('../decode'); jest.dontMock('../ParseFile'); jest.dontMock('../ParseGeoPoint'); -jest.dontMock('crypto-js'); const decode = require('../decode').default; diff --git a/src/__tests__/encode-test.js b/src/__tests__/encode-test.js index 12f76a1cd..79d37caab 100644 --- a/src/__tests__/encode-test.js +++ b/src/__tests__/encode-test.js @@ -11,7 +11,6 @@ jest.dontMock('../encode'); jest.dontMock('../ParseACL'); jest.dontMock('../ParseFile'); jest.dontMock('../ParseGeoPoint'); -jest.dontMock('crypto-js'); const mockObject = function(className) { this.className = className; diff --git a/src/__tests__/unsavedChildren-test.js b/src/__tests__/unsavedChildren-test.js index 854b1df88..31084452e 100644 --- a/src/__tests__/unsavedChildren-test.js +++ b/src/__tests__/unsavedChildren-test.js @@ -9,7 +9,6 @@ jest.dontMock('../ParseFile'); jest.dontMock('../unsavedChildren'); -jest.dontMock('crypto-js'); function mockObject({ className, localId, id, attributes, dirty }) { this.className = className; From e1d9cd1d72e27d1e9ee74f509e3b19e9578a61be Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Tue, 24 Dec 2019 11:59:47 -0600 Subject: [PATCH 6/6] improve coverage --- integration/test/ParseUserTest.js | 2 +- src/CryptoController.js | 12 ------- src/ParseUser.js | 2 +- src/__tests__/ParseUser-test.js | 60 +++++++++++++++++++++++++++++-- 4 files changed, 60 insertions(+), 16 deletions(-) diff --git a/integration/test/ParseUserTest.js b/integration/test/ParseUserTest.js index 0f688b337..e5d5fdf52 100644 --- a/integration/test/ParseUserTest.js +++ b/integration/test/ParseUserTest.js @@ -949,7 +949,7 @@ describe('Parse User', () => { const encryptedUser = Parse.Storage.getItem(path); const crypto = Parse.CoreManager.getCryptoController(); - const decryptedUser = crypto.decrypt(encryptedUser, Parse.CoreManager.get('ENCRYPTED_KEY')) + const decryptedUser = crypto.decrypt(encryptedUser, Parse.CoreManager.get('ENCRYPTED_KEY')); expect(JSON.parse(decryptedUser).objectId).toBe(user.id); const currentUser = Parse.User.current(); diff --git a/src/CryptoController.js b/src/CryptoController.js index aebf9df24..555eb9736 100644 --- a/src/CryptoController.js +++ b/src/CryptoController.js @@ -1,21 +1,9 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - */ - import AES from 'crypto-js/aes'; import ENC from 'crypto-js/enc-utf8'; const CryptoController = { encrypt(obj: any, secretKey: string): ?string { const encrypted = AES.encrypt(JSON.stringify(obj), secretKey); - return encrypted.toString(); }, diff --git a/src/ParseUser.js b/src/ParseUser.js index 9de4bb73d..2752d890b 100644 --- a/src/ParseUser.js +++ b/src/ParseUser.js @@ -925,7 +925,7 @@ const DefaultController = { } if (CoreManager.get('ENCRYPTED_USER')) { const crypto = CoreManager.getCryptoController(); - userData = crypto.decrypt(userData.toString(), CoreManager.get('ENCRYPTED_KEY')); + userData = crypto.decrypt(userData, CoreManager.get('ENCRYPTED_KEY')); } userData = JSON.parse(userData); if (!userData.className) { diff --git a/src/__tests__/ParseUser-test.js b/src/__tests__/ParseUser-test.js index b7141d0fa..3331b5d6a 100644 --- a/src/__tests__/ParseUser-test.js +++ b/src/__tests__/ParseUser-test.js @@ -27,6 +27,8 @@ jest.dontMock('../StorageController.default'); jest.dontMock('../TaskQueue'); jest.dontMock('../unique'); jest.dontMock('../UniqueInstanceStateController'); +jest.dontMock('crypto-js/aes'); +jest.dontMock('crypto-js/enc-utf8'); jest.mock('uuid/v4', () => { let value = 0; @@ -35,6 +37,7 @@ jest.mock('uuid/v4', () => { jest.dontMock('./test_helpers/mockXHR'); const CoreManager = require('../CoreManager'); +const CryptoController = require('../CryptoController'); const LocalDatastore = require('../LocalDatastore'); const ParseObject = require('../ParseObject').default; const ParseUser = require('../ParseUser').default; @@ -44,6 +47,7 @@ const AnonymousUtils = require('../AnonymousUtils').default; CoreManager.set('APPLICATION_ID', 'A'); CoreManager.set('JAVASCRIPT_KEY', 'B'); +CoreManager.setCryptoController(CryptoController); function flushPromises() { return new Promise(resolve => setImmediate(resolve)); @@ -1014,6 +1018,57 @@ describe('ParseUser', () => { it('can encrypt user', async () => { CoreManager.set('ENCRYPTED_USER', true); CoreManager.set('ENCRYPTED_KEY', 'hello'); + + ParseUser.enableUnsafeCurrentUser(); + ParseUser._clearCache(); + Storage._clear(); + let u = null; + CoreManager.setRESTController({ + request(method, path, body) { + expect(method).toBe('GET'); + expect(path).toBe('login'); + expect(body.username).toBe('username'); + expect(body.password).toBe('password'); + + return Promise.resolve({ + objectId: 'uid2', + username: 'username', + sessionToken: '123abc' + }, 200); + }, + ajax() {} + }); + u = await ParseUser.logIn('username', 'password'); + // Clear cache to read from disk + ParseUser._clearCache(); + + expect(u.id).toBe('uid2'); + expect(u.getSessionToken()).toBe('123abc'); + expect(u.isCurrent()).toBe(true); + expect(u.authenticated()).toBe(true); + + const currentUser = ParseUser.current(); + expect(currentUser.id).toBe('uid2'); + + ParseUser._clearCache(); + + const currentUserAsync = await ParseUser.currentAsync(); + expect(currentUserAsync.id).toEqual('uid2'); + + const path = Storage.generatePath('currentUser'); + const encryptedUser = Storage.getItem(path); + const crypto = CoreManager.getCryptoController(); + const decryptedUser = crypto.decrypt(encryptedUser, 'hello'); + expect(JSON.parse(decryptedUser).objectId).toBe(u.id); + + CoreManager.set('ENCRYPTED_USER', false); + CoreManager.set('ENCRYPTED_KEY', null); + Storage._clear(); + }); + + it('can encrypt user with custom CryptoController', async () => { + CoreManager.set('ENCRYPTED_USER', true); + CoreManager.set('ENCRYPTED_KEY', 'hello'); const ENCRYPTED_DATA = 'encryptedString'; ParseUser.enableUnsafeCurrentUser(); @@ -1035,7 +1090,7 @@ describe('ParseUser', () => { }, ajax() {} }); - CoreManager.setCryptoController({ + const CustomCrypto = { encrypt(obj, secretKey) { expect(secretKey).toBe('hello'); return ENCRYPTED_DATA; @@ -1045,7 +1100,8 @@ describe('ParseUser', () => { expect(secretKey).toBe('hello'); return JSON.stringify(u.toJSON()); }, - }); + }; + CoreManager.setCryptoController(CustomCrypto); u = await ParseUser.logIn('username', 'password'); // Clear cache to read from disk ParseUser._clearCache();