mirror of
https://gitlab.com/psono/psono-client
synced 2025-04-19 03:22:16 +03:00
some more progress
Signed-off-by: Sascha Pfeiffer <sascha.pfeiffer@psono.com>
This commit is contained in:
parent
9b9ede2f21
commit
78698f0001
4
.babelrc
4
.babelrc
@ -1,8 +1,10 @@
|
||||
{
|
||||
"presets": [
|
||||
"@babel/preset-env", "@babel/preset-react"
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react"
|
||||
],
|
||||
"plugins": [
|
||||
["@babel/plugin-transform-runtime"],
|
||||
[
|
||||
"@babel/plugin-proposal-class-properties"
|
||||
]
|
||||
|
168
package-lock.json
generated
168
package-lock.json
generated
@ -9,11 +9,13 @@
|
||||
"version": "0.1.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.16.7",
|
||||
"@date-io/date-fns": "^1.3.13",
|
||||
"@material-ui/core": "^4.12.3",
|
||||
"@material-ui/icons": "^4.11.2",
|
||||
"@material-ui/lab": "^4.0.0-alpha.60",
|
||||
"@material-ui/pickers": "^3.3.10",
|
||||
"@openpgp/hkp-client": "^0.0.2",
|
||||
"axios": "^0.24.0",
|
||||
"babel-preset-react-app": "3",
|
||||
"clientjs": "^0.2.1",
|
||||
@ -33,11 +35,13 @@
|
||||
"js-sha512": "^0.8.0",
|
||||
"localforage": "^1.10.0",
|
||||
"mui-datatables": "^3.8.2",
|
||||
"openpgp": "^5.0.1",
|
||||
"otpauth": "^7.0.7",
|
||||
"papaparse": "^5.3.1",
|
||||
"qrcode": "^1.5.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-fastclick": "^3.0.2",
|
||||
"react-fontawesome": "^1.6.1",
|
||||
"react-i18next": "^11.13.0",
|
||||
"react-redux": "^7.2.6",
|
||||
@ -51,6 +55,7 @@
|
||||
"uuid-js": "^0.7.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-transform-runtime": "^7.16.7",
|
||||
"@babel/preset-env": "^7.16.0",
|
||||
"@babel/preset-react": "^7.16.0",
|
||||
"babel-cli": "^6.26.0",
|
||||
@ -457,10 +462,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-module-imports": {
|
||||
"version": "7.16.0",
|
||||
"license": "MIT",
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
|
||||
"integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.16.0"
|
||||
"@babel/types": "^7.16.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@ -496,9 +502,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-plugin-utils": {
|
||||
"version": "7.16.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz",
|
||||
"integrity": "sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ==",
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz",
|
||||
"integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@ -562,8 +568,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.15.7",
|
||||
"license": "MIT",
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
|
||||
"integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@ -1674,12 +1681,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-runtime": {
|
||||
"version": "7.16.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.5.tgz",
|
||||
"integrity": "sha512-gxpfS8XQWDbQ8oP5NcmpXxtEgCJkbO+W9VhZlOhr0xPyVaRjAQPOv7ZDj9fg0d5s9+NiVvMCE6gbkEkcsxwGRw==",
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.7.tgz",
|
||||
"integrity": "sha512-2FoHiSAWkdq4L06uaDN3rS43i6x28desUVxq+zAFuE6kbWYQeiLPJI5IC7Sg9xKYVcrBKSQkVUfH6aeQYbl9QA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-module-imports": "^7.16.0",
|
||||
"@babel/helper-plugin-utils": "^7.16.5",
|
||||
"@babel/helper-module-imports": "^7.16.7",
|
||||
"@babel/helper-plugin-utils": "^7.16.7",
|
||||
"babel-plugin-polyfill-corejs2": "^0.3.0",
|
||||
"babel-plugin-polyfill-corejs3": "^0.4.0",
|
||||
"babel-plugin-polyfill-regenerator": "^0.3.0",
|
||||
@ -1959,9 +1966,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.16.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz",
|
||||
"integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==",
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
|
||||
"integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
},
|
||||
@ -2047,10 +2054,11 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.16.0",
|
||||
"license": "MIT",
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.7.tgz",
|
||||
"integrity": "sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.15.7",
|
||||
"@babel/helper-validator-identifier": "^7.16.7",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -3249,6 +3257,14 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@openpgp/hkp-client": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@openpgp/hkp-client/-/hkp-client-0.0.2.tgz",
|
||||
"integrity": "sha512-hA71RhqfLfNltZsy/USTQehE2QAVB3eK4xx8p76XtFJy5Zg6gK2XbZvOC/x/yG8i2Ipbyul1DMTMxH9v8rfPKw==",
|
||||
"dependencies": {
|
||||
"node-fetch": "^2.6.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.3.tgz",
|
||||
@ -4882,6 +4898,17 @@
|
||||
"safer-buffer": "~2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/asn1.js": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
|
||||
"integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
|
||||
"dependencies": {
|
||||
"bn.js": "^4.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"minimalistic-assert": "^1.0.0",
|
||||
"safer-buffer": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"dev": true,
|
||||
@ -6245,6 +6272,11 @@
|
||||
"version": "3.7.2",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bn.js": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.19.0",
|
||||
"license": "MIT",
|
||||
@ -17419,6 +17451,17 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/openpgp": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/openpgp/-/openpgp-5.0.1.tgz",
|
||||
"integrity": "sha512-J9HGIcXumwczJwX3JvgshWYtkhsOJHm5ZPd1ipJ1BqrZL06NgqV/EfJyF3ThOlNV2rY0MGWdS8L8/kKyeo3sXg==",
|
||||
"dependencies": {
|
||||
"asn1.js": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
|
||||
@ -19799,6 +19842,17 @@
|
||||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz",
|
||||
"integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA=="
|
||||
},
|
||||
"node_modules/react-fastclick": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-fastclick/-/react-fastclick-3.0.2.tgz",
|
||||
"integrity": "sha1-KZTGAIjNqQsLLL+sS258a8c9ajo=",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-fontawesome": {
|
||||
"version": "1.6.1",
|
||||
"license": "MIT",
|
||||
@ -25007,9 +25061,11 @@
|
||||
}
|
||||
},
|
||||
"@babel/helper-module-imports": {
|
||||
"version": "7.16.0",
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
|
||||
"integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.16.0"
|
||||
"@babel/types": "^7.16.7"
|
||||
}
|
||||
},
|
||||
"@babel/helper-module-transforms": {
|
||||
@ -25036,9 +25092,9 @@
|
||||
}
|
||||
},
|
||||
"@babel/helper-plugin-utils": {
|
||||
"version": "7.16.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz",
|
||||
"integrity": "sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ=="
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz",
|
||||
"integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA=="
|
||||
},
|
||||
"@babel/helper-remap-async-to-generator": {
|
||||
"version": "7.16.5",
|
||||
@ -25081,7 +25137,9 @@
|
||||
}
|
||||
},
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.15.7"
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
|
||||
"integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw=="
|
||||
},
|
||||
"@babel/helper-validator-option": {
|
||||
"version": "7.14.5"
|
||||
@ -25768,12 +25826,12 @@
|
||||
}
|
||||
},
|
||||
"@babel/plugin-transform-runtime": {
|
||||
"version": "7.16.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.5.tgz",
|
||||
"integrity": "sha512-gxpfS8XQWDbQ8oP5NcmpXxtEgCJkbO+W9VhZlOhr0xPyVaRjAQPOv7ZDj9fg0d5s9+NiVvMCE6gbkEkcsxwGRw==",
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.7.tgz",
|
||||
"integrity": "sha512-2FoHiSAWkdq4L06uaDN3rS43i6x28desUVxq+zAFuE6kbWYQeiLPJI5IC7Sg9xKYVcrBKSQkVUfH6aeQYbl9QA==",
|
||||
"requires": {
|
||||
"@babel/helper-module-imports": "^7.16.0",
|
||||
"@babel/helper-plugin-utils": "^7.16.5",
|
||||
"@babel/helper-module-imports": "^7.16.7",
|
||||
"@babel/helper-plugin-utils": "^7.16.7",
|
||||
"babel-plugin-polyfill-corejs2": "^0.3.0",
|
||||
"babel-plugin-polyfill-corejs3": "^0.4.0",
|
||||
"babel-plugin-polyfill-regenerator": "^0.3.0",
|
||||
@ -25973,9 +26031,9 @@
|
||||
}
|
||||
},
|
||||
"@babel/runtime": {
|
||||
"version": "7.16.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz",
|
||||
"integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==",
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
|
||||
"integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
},
|
||||
@ -26037,9 +26095,11 @@
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.16.0",
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.7.tgz",
|
||||
"integrity": "sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg==",
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.15.7",
|
||||
"@babel/helper-validator-identifier": "^7.16.7",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -26852,6 +26912,14 @@
|
||||
"fastq": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"@openpgp/hkp-client": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@openpgp/hkp-client/-/hkp-client-0.0.2.tgz",
|
||||
"integrity": "sha512-hA71RhqfLfNltZsy/USTQehE2QAVB3eK4xx8p76XtFJy5Zg6gK2XbZvOC/x/yG8i2Ipbyul1DMTMxH9v8rfPKw==",
|
||||
"requires": {
|
||||
"node-fetch": "^2.6.1"
|
||||
}
|
||||
},
|
||||
"@pmmmwh/react-refresh-webpack-plugin": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.3.tgz",
|
||||
@ -27919,6 +27987,17 @@
|
||||
"safer-buffer": "~2.1.0"
|
||||
}
|
||||
},
|
||||
"asn1.js": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
|
||||
"integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
|
||||
"requires": {
|
||||
"bn.js": "^4.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"minimalistic-assert": "^1.0.0",
|
||||
"safer-buffer": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"dev": true
|
||||
@ -29005,6 +29084,11 @@
|
||||
"bluebird": {
|
||||
"version": "3.7.2"
|
||||
},
|
||||
"bn.js": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
|
||||
},
|
||||
"body-parser": {
|
||||
"version": "1.19.0",
|
||||
"requires": {
|
||||
@ -36764,6 +36848,14 @@
|
||||
"is-wsl": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"openpgp": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/openpgp/-/openpgp-5.0.1.tgz",
|
||||
"integrity": "sha512-J9HGIcXumwczJwX3JvgshWYtkhsOJHm5ZPd1ipJ1BqrZL06NgqV/EfJyF3ThOlNV2rY0MGWdS8L8/kKyeo3sXg==",
|
||||
"requires": {
|
||||
"asn1.js": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"optionator": {
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
|
||||
@ -38281,6 +38373,12 @@
|
||||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz",
|
||||
"integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA=="
|
||||
},
|
||||
"react-fastclick": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-fastclick/-/react-fastclick-3.0.2.tgz",
|
||||
"integrity": "sha1-KZTGAIjNqQsLLL+sS258a8c9ajo=",
|
||||
"requires": {}
|
||||
},
|
||||
"react-fontawesome": {
|
||||
"version": "1.6.1",
|
||||
"requires": {
|
||||
|
@ -22,11 +22,13 @@
|
||||
"keywords": [],
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.16.7",
|
||||
"@date-io/date-fns": "^1.3.13",
|
||||
"@material-ui/core": "^4.12.3",
|
||||
"@material-ui/icons": "^4.11.2",
|
||||
"@material-ui/lab": "^4.0.0-alpha.60",
|
||||
"@material-ui/pickers": "^3.3.10",
|
||||
"@openpgp/hkp-client": "^0.0.2",
|
||||
"axios": "^0.24.0",
|
||||
"babel-preset-react-app": "3",
|
||||
"clientjs": "^0.2.1",
|
||||
@ -46,11 +48,13 @@
|
||||
"js-sha512": "^0.8.0",
|
||||
"localforage": "^1.10.0",
|
||||
"mui-datatables": "^3.8.2",
|
||||
"openpgp": "^5.0.1",
|
||||
"otpauth": "^7.0.7",
|
||||
"papaparse": "^5.3.1",
|
||||
"qrcode": "^1.5.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-fastclick": "^3.0.2",
|
||||
"react-fontawesome": "^1.6.1",
|
||||
"react-i18next": "^11.13.0",
|
||||
"react-redux": "^7.2.6",
|
||||
@ -64,6 +68,7 @@
|
||||
"uuid-js": "^0.7.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-transform-runtime": "^7.16.7",
|
||||
"@babel/preset-env": "^7.16.0",
|
||||
"@babel/preset-react": "^7.16.0",
|
||||
"babel-cli": "^6.26.0",
|
||||
|
@ -84,8 +84,7 @@ body {
|
||||
border-color: #151f2b; }
|
||||
|
||||
.path_box_parent {
|
||||
margin-bottom: 5px;
|
||||
font-family: 'Fira Code', monospace; }
|
||||
margin-bottom: 5px; }
|
||||
.path_box_parent .path_box_breadcrumb {
|
||||
cursor: pointer; }
|
||||
.path_box_parent .disabled {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*fbfbfc*/
|
||||
/* Generic styles */
|
||||
html {
|
||||
height: 100%; }
|
||||
height: 100%;}
|
||||
body {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
position: relative;
|
||||
@ -14,6 +14,10 @@ body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
html, body {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
font-size: 20px;
|
||||
margin: 0; }
|
||||
@ -48,9 +52,6 @@ a {
|
||||
.btn-link {
|
||||
color: #151f2b; }
|
||||
|
||||
.monospace {
|
||||
font-family: 'Fira Code', monospace; }
|
||||
|
||||
p.horizontalline {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
@ -313,10 +314,6 @@ p.horizontalline span {
|
||||
border-top-color: #2ba880;
|
||||
border-left-color: #2ba880; }
|
||||
|
||||
|
||||
.text-center {
|
||||
text-align: center; }
|
||||
|
||||
.progress-box {
|
||||
width: 340px;
|
||||
padding: 20px;
|
||||
|
@ -1,4 +1,14 @@
|
||||
{
|
||||
"EDIT_WEBSITE_PASSWORD": "Webseiten Passwort bearbeiten",
|
||||
"EDIT_APPLICATION_PASSWORD": "Applikations Passwort bearbeiten",
|
||||
"EDIT_TOTP_AUTHENTICATOR": "TOTP Authenticator bearbeiten",
|
||||
"EDIT_NOTE": "Notiz bearbeiten",
|
||||
"EDIT_ENVIRONMENT_VARIABLES": "Umgebungsvariablen bearbeiten",
|
||||
"EDIT_GPG_KEY": "GPG Key bearbeiten",
|
||||
"EDIT_BOOKMARK": "Bookmark bearbeiten",
|
||||
"EDIT_FILE": "Datei bearbeiten",
|
||||
"USER_NOT_FOUND": "Benutzer nicht gefunden",
|
||||
"ACCEPT_SHARE": "Share annehmen",
|
||||
"DATE_TIME_YYYY_MM_DD_HH_MM": "dd.MM.yyyy HH:mm",
|
||||
"TABLE_BODY_NO_MATCH": "Entschulding, keine übereinstimmenden Einträge gefunden",
|
||||
"TABLE_BODY_TOOL_TIP": "Sortieren",
|
||||
|
@ -1,4 +1,14 @@
|
||||
{
|
||||
"EDIT_WEBSITE_PASSWORD": "Edit Website Password",
|
||||
"EDIT_APPLICATION_PASSWORD": "Edit Application Password",
|
||||
"EDIT_TOTP_AUTHENTICATOR": "Edit TOTP Authenticator",
|
||||
"EDIT_NOTE": "Edit Note",
|
||||
"EDIT_ENVIRONMENT_VARIABLES": "Edit Environment Variables",
|
||||
"EDIT_GPG_KEY": "Edit GPG Key",
|
||||
"EDIT_BOOKMARK": "Edit Bookmark",
|
||||
"EDIT_FILE": "Edit File",
|
||||
"USER_NOT_FOUND": "User not found",
|
||||
"ACCEPT_SHARE": "Accept Share",
|
||||
"DATE_TIME_YYYY_MM_DD_HH_MM": "yyyy/MM/dd HH:mm",
|
||||
"TABLE_BODY_NO_MATCH": "Sorry, no matching records found",
|
||||
"TABLE_BODY_TOOL_TIP": "Sort",
|
||||
|
@ -23,6 +23,7 @@ import {
|
||||
SET_REMOTE_CONFIG_JSON,
|
||||
SET_FINGERPRINT,
|
||||
SET_EMAIL,
|
||||
SET_HIDE_DOWNLOAD_BANNER,
|
||||
} from "./action-types";
|
||||
|
||||
import datastoreSettingService from "../services/datastore-setting";
|
||||
@ -163,6 +164,14 @@ function setDisableBrowserPm(disableBrowserPm) {
|
||||
});
|
||||
};
|
||||
}
|
||||
function setHideDownloadBanner(hideDownloadBanner) {
|
||||
return (dispatch) => {
|
||||
dispatch({
|
||||
type: SET_HIDE_DOWNLOAD_BANNER,
|
||||
hideDownloadBanner,
|
||||
});
|
||||
};
|
||||
}
|
||||
function settingsDatastoreLoaded(data) {
|
||||
return (dispatch) => {
|
||||
dispatch({
|
||||
@ -285,6 +294,7 @@ const actionCreators = {
|
||||
enableOfflineMode,
|
||||
setNotificationOnCopy,
|
||||
setDisableBrowserPm,
|
||||
setHideDownloadBanner,
|
||||
setPasswordConfig,
|
||||
setGpgConfig,
|
||||
settingsDatastoreLoaded,
|
||||
|
@ -16,6 +16,7 @@ export const ENABLE_OFFLINE_MODE = "ENABLE_OFFLINE_MODE";
|
||||
export const DISABLE_OFFLINE_MODE = "DISABLE_OFFLINE_MODE";
|
||||
export const SET_NOTIFICATION_ON_COPY = "SET_NOTIFICATION_ON_COPY";
|
||||
export const SET_DISABLE_BROWSER_PM = "SET_DISABLE_BROWSER_PM";
|
||||
export const SET_HIDE_DOWNLOAD_BANNER = "SET_HIDE_DOWNLOAD_BANNER";
|
||||
export const SETTINGS_DATASTORE_LOADED = "SETTINGS_DATASTORE_LOADED";
|
||||
export const SET_PASSWORD_CONFIG = "SET_PASSWORD_CONFIG";
|
||||
export const SET_GPG_CONFIG = "SET_GPG_CONFIG";
|
||||
|
@ -12,28 +12,34 @@ import { PersistGate } from "redux-persist/integration/react";
|
||||
import { Provider } from "react-redux";
|
||||
import { MuiPickersUtilsProvider } from "@material-ui/pickers";
|
||||
import DateFnsUtils from "@date-io/date-fns";
|
||||
|
||||
import initReactFastclick from "react-fastclick";
|
||||
import store from "./services/store";
|
||||
import datastoreSettingService from "./services/datastore-setting";
|
||||
import i18n from "./i18n";
|
||||
import theme from "./theme";
|
||||
|
||||
import IndexView from "./views/index";
|
||||
import DownloadBanner from "./containers/download-banner";
|
||||
|
||||
/**
|
||||
* Loads the datastore
|
||||
* @param dispatch
|
||||
* @param getState
|
||||
*/
|
||||
function fetchTodos(dispatch, getState) {
|
||||
datastoreSettingService.getSettingsDatastore();
|
||||
function loadSettingsDatastore(dispatch, getState) {
|
||||
const state = getState();
|
||||
if (state.user.isLoggedIn) {
|
||||
datastoreSettingService.getSettingsDatastore();
|
||||
}
|
||||
}
|
||||
|
||||
let persistor = persistStore(store, null, () => {
|
||||
store.dispatch(fetchTodos);
|
||||
store.dispatch(loadSettingsDatastore);
|
||||
});
|
||||
const customHistory = createBrowserHistory();
|
||||
|
||||
initReactFastclick();
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<MuiPickersUtilsProvider utils={DateFnsUtils}>
|
||||
@ -44,6 +50,7 @@ const App = () => {
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
<HashRouter history={customHistory} hashType={"hashbang"}>
|
||||
<DownloadBanner />
|
||||
<IndexView />
|
||||
</HashRouter>
|
||||
</ThemeProvider>
|
||||
|
@ -13,6 +13,7 @@ import Typography from "@material-ui/core/Typography";
|
||||
import EditIcon from "@material-ui/icons/Edit";
|
||||
import CreateNewFolderIcon from "@material-ui/icons/CreateNewFolder";
|
||||
import AddIcon from "@material-ui/icons/Add";
|
||||
import PersonAddIcon from "@material-ui/icons/PersonAdd";
|
||||
import OpenWithIcon from "@material-ui/icons/OpenWith";
|
||||
import DeleteIcon from "@material-ui/icons/Delete";
|
||||
import Divider from "@material-ui/core/Divider";
|
||||
@ -28,14 +29,18 @@ const useStyles = makeStyles((theme) => ({
|
||||
icon: {
|
||||
fontSize: "18px",
|
||||
},
|
||||
listItemIcon: {
|
||||
minWidth: theme.spacing(4),
|
||||
},
|
||||
}));
|
||||
|
||||
const DatastoreTreeFolder = (props) => {
|
||||
const { t } = useTranslation();
|
||||
const { content, search, offline, isExpandedDefault } = props;
|
||||
const { content, offline, isExpandedDefault, nodePath } = props;
|
||||
const classes = useStyles();
|
||||
const [isExpanded, setIsExpanded] = React.useState(isExpandedDefault);
|
||||
const [anchorEl, setAnchorEl] = React.useState(null);
|
||||
const isSelectable = props.isSelectable ? props.isSelectable(content) : true;
|
||||
|
||||
const openMenu = (event) => {
|
||||
event.preventDefault();
|
||||
@ -56,7 +61,7 @@ const DatastoreTreeFolder = (props) => {
|
||||
}
|
||||
|
||||
registrations["read_share_rights"](content.share_id).then(function (share_details) {
|
||||
var modalInstance = $uibModal.open({
|
||||
const modalInstance = $uibModal.open({
|
||||
templateUrl: "view/modal/display-share-rights.html",
|
||||
controller: "ModalDisplayShareRightsCtrl",
|
||||
backdrop: "static",
|
||||
@ -78,7 +83,7 @@ const DatastoreTreeFolder = (props) => {
|
||||
|
||||
const onEdit = (event) => {
|
||||
handleClose(event);
|
||||
// TODO editNode
|
||||
props.onEditFolder(content, content.path);
|
||||
};
|
||||
|
||||
const onNewFolder = (event) => {
|
||||
@ -93,7 +98,12 @@ const DatastoreTreeFolder = (props) => {
|
||||
|
||||
const onNewEntry = (event) => {
|
||||
handleClose(event);
|
||||
// TODO newEntryNode
|
||||
props.onNewEntry(content, content.path);
|
||||
};
|
||||
|
||||
const onNewUser = (event) => {
|
||||
handleClose(event);
|
||||
props.onNewUser(content, content.path);
|
||||
};
|
||||
|
||||
const onMove = (event) => {
|
||||
@ -104,27 +114,32 @@ const DatastoreTreeFolder = (props) => {
|
||||
const selectNode = (event) => {
|
||||
event.stopPropagation();
|
||||
setIsExpanded(!isExpanded);
|
||||
if (props.onSelectNode && isSelectable) {
|
||||
props.onSelectNode(content, content.path, nodePath);
|
||||
}
|
||||
};
|
||||
React.useEffect(() => {
|
||||
setIsExpanded(isExpandedDefault);
|
||||
}, [isExpandedDefault]);
|
||||
|
||||
const hideShare = offline || (content.hasOwnProperty("share_rights") && content.share_rights.grant === false);
|
||||
const hideShare = offline || (content.hasOwnProperty("share_rights") && content.share_rights.grant === false) || !props.onNewShare;
|
||||
const hideRightsOverview =
|
||||
offline ||
|
||||
(content.hasOwnProperty("share_rights") && content.share_rights.grant === false) ||
|
||||
!content.hasOwnProperty("share_id") ||
|
||||
typeof content.share_id === "undefined";
|
||||
const hideEdit = offline || content.share_rights.write === false;
|
||||
const hideNewFolder = offline || content.share_rights.write === false;
|
||||
const hideNewEntry = offline || content.share_rights.write === false;
|
||||
const hideMove = offline || content.share_rights.delete === false;
|
||||
const hideDelete = offline || content.share_rights.delete === false;
|
||||
const hideEdit = offline || (content.hasOwnProperty("share_rights") && content.share_rights.write === false) || !props.onEditFolder;
|
||||
const hideNewFolder = offline || (content.hasOwnProperty("share_rights") && content.share_rights.write === false) || !props.onNewFolder;
|
||||
const hideNewEntry = offline || (content.hasOwnProperty("share_rights") && content.share_rights.write === false) || !props.onNewEntry;
|
||||
const hideNewUser = offline || (content.hasOwnProperty("share_rights") && content.share_rights.write === false) || !props.onNewUser;
|
||||
const hideMove = offline || (content.hasOwnProperty("share_rights") && content.share_rights.delete === false);
|
||||
const hideDelete = offline || (content.hasOwnProperty("share_rights") && content.share_rights.delete === false);
|
||||
const disableMenu = hideShare && hideRightsOverview && hideEdit && hideNewFolder && hideNewEntry && hideNewUser && hideMove && hideDelete;
|
||||
|
||||
return (
|
||||
<div className={"tree-folder"}>
|
||||
<div className={"tree-folder-title"}>
|
||||
<div className={"tree-folder-header"} onClick={selectNode}>
|
||||
<div className={"tree-folder-header" + (isSelectable ? "" : " notSelectable")} onClick={selectNode}>
|
||||
<span className="fa-stack">
|
||||
{isExpanded && <i className="fa fa-folder-open" />}
|
||||
{!isExpanded && <i className="fa fa-folder" />}
|
||||
@ -133,14 +148,14 @@ const DatastoreTreeFolder = (props) => {
|
||||
</span>
|
||||
<span className="tree-folder-name ng-binding">{content.name}</span>
|
||||
<ButtonGroup variant="text" aria-label="text button group" className={"node-open-link"}>
|
||||
<Button aria-label="settings" onClick={openMenu}>
|
||||
<Button aria-label="settings" onClick={openMenu} disabled={disableMenu}>
|
||||
<SettingsIcon fontSize="small" />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<Menu id="simple-menu" anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose}>
|
||||
{!hideShare && onNewShare && (
|
||||
<MenuItem onClick={onNewShare}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<ShareIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
@ -150,7 +165,7 @@ const DatastoreTreeFolder = (props) => {
|
||||
)}
|
||||
{!hideRightsOverview && (
|
||||
<MenuItem onClick={onRightsOverview}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<ListIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
@ -161,7 +176,7 @@ const DatastoreTreeFolder = (props) => {
|
||||
{(!hideShare || !hideRightsOverview) && <Divider className={classes.divider} />}
|
||||
{!hideEdit && (
|
||||
<MenuItem onClick={onEdit}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<EditIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
@ -171,7 +186,7 @@ const DatastoreTreeFolder = (props) => {
|
||||
)}
|
||||
{!hideNewFolder && (
|
||||
<MenuItem onClick={onNewFolder}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<CreateNewFolderIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
@ -181,7 +196,7 @@ const DatastoreTreeFolder = (props) => {
|
||||
)}
|
||||
{!hideNewEntry && (
|
||||
<MenuItem onClick={onNewEntry}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<AddIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
@ -189,9 +204,19 @@ const DatastoreTreeFolder = (props) => {
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
)}
|
||||
{!hideNewUser && (
|
||||
<MenuItem onClick={onNewUser}>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<PersonAddIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
{t("NEW_USER")}
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
)}
|
||||
{!hideMove && (
|
||||
<MenuItem onClick={onMove}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<OpenWithIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
@ -202,7 +227,7 @@ const DatastoreTreeFolder = (props) => {
|
||||
{!hideDelete && <Divider className={classes.divider} />}
|
||||
{!hideDelete && (
|
||||
<MenuItem onClick={onMove}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<DeleteIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
@ -219,11 +244,22 @@ const DatastoreTreeFolder = (props) => {
|
||||
content.folders
|
||||
.filter((folder) => !folder["hidden"] && !folder["deleted"])
|
||||
.map(function (content, i) {
|
||||
const nodePathClone = Array.from(nodePath);
|
||||
nodePathClone.push(content);
|
||||
return (
|
||||
<DatastoreTreeFolder
|
||||
isSelectable={props.isSelectable}
|
||||
onSelectItem={props.onSelectItem}
|
||||
onSelectNode={props.onSelectNode}
|
||||
onEditFolder={props.onEditFolder}
|
||||
onEditEntry={props.onEditEntry}
|
||||
onLinkItem={props.onLinkItem}
|
||||
onNewFolder={props.onNewFolder}
|
||||
search={search}
|
||||
onNewUser={props.onNewUser}
|
||||
onNewEntry={props.onNewEntry}
|
||||
onNewShare={props.onNewShare}
|
||||
key={i}
|
||||
nodePath={nodePathClone}
|
||||
content={content}
|
||||
offline={offline}
|
||||
isExpandedDefault={Boolean(content["is_expanded"])}
|
||||
@ -234,7 +270,21 @@ const DatastoreTreeFolder = (props) => {
|
||||
content.items
|
||||
.filter((item) => !item["hidden"] && !item["deleted"])
|
||||
.map(function (content, i) {
|
||||
return <DatastoreTreeItem onNewShare={props.onNewShare} search={search} key={i} content={content} offline={offline} />;
|
||||
const nodePathClone = Array.from(nodePath);
|
||||
nodePathClone.push(content);
|
||||
return (
|
||||
<DatastoreTreeItem
|
||||
isSelectable={props.isSelectable}
|
||||
onSelectItem={props.onSelectItem}
|
||||
onEditEntry={props.onEditEntry}
|
||||
onLinkItem={props.onLinkItem}
|
||||
onNewShare={props.onNewShare}
|
||||
key={i}
|
||||
nodePath={nodePathClone}
|
||||
content={content}
|
||||
offline={offline}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
@ -243,12 +293,20 @@ const DatastoreTreeFolder = (props) => {
|
||||
};
|
||||
|
||||
DatastoreTreeFolder.propTypes = {
|
||||
search: PropTypes.string.isRequired,
|
||||
isSelectable: PropTypes.func,
|
||||
isExpandedDefault: PropTypes.bool.isRequired,
|
||||
content: PropTypes.object,
|
||||
nodePath: PropTypes.array.isRequired,
|
||||
offline: PropTypes.bool.isRequired,
|
||||
onNewFolder: PropTypes.func.isRequired,
|
||||
onNewShare: PropTypes.func,
|
||||
onNewUser: PropTypes.func,
|
||||
onNewEntry: PropTypes.func,
|
||||
onEditEntry: PropTypes.func,
|
||||
onLinkItem: PropTypes.func,
|
||||
onEditFolder: PropTypes.func,
|
||||
onSelectNode: PropTypes.func,
|
||||
onSelectItem: PropTypes.func,
|
||||
};
|
||||
|
||||
export default DatastoreTreeFolder;
|
||||
|
@ -14,6 +14,7 @@ import ShareIcon from "@material-ui/icons/Share";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import LinkIcon from "@material-ui/icons/Link";
|
||||
import EditIcon from "@material-ui/icons/Edit";
|
||||
import VisibilityIcon from "@material-ui/icons/Visibility";
|
||||
import OpenWithIcon from "@material-ui/icons/OpenWith";
|
||||
import DeleteIcon from "@material-ui/icons/Delete";
|
||||
import FileCopyIcon from "@material-ui/icons/FileCopy";
|
||||
@ -23,7 +24,6 @@ import { makeStyles } from "@material-ui/core/styles";
|
||||
import ContentCopy from "./icons/ContentCopy";
|
||||
|
||||
import secretService from "../services/secret";
|
||||
import fileTransferService from "../services/file-transfer";
|
||||
import store from "../services/store";
|
||||
import widgetService from "../services/widget";
|
||||
|
||||
@ -35,13 +35,17 @@ const useStyles = makeStyles((theme) => ({
|
||||
icon: {
|
||||
fontSize: "18px",
|
||||
},
|
||||
listItemIcon: {
|
||||
minWidth: theme.spacing(4),
|
||||
},
|
||||
}));
|
||||
|
||||
const DatastoreTreeItem = (props) => {
|
||||
const { t } = useTranslation();
|
||||
const { content, search, offline } = props;
|
||||
const { content, offline } = props;
|
||||
const classes = useStyles();
|
||||
const [anchorEl, setAnchorEl] = React.useState(null);
|
||||
const isSelectable = props.isSelectable ? props.isSelectable(content) : true;
|
||||
|
||||
const openMenu = (event) => {
|
||||
event.preventDefault();
|
||||
@ -66,11 +70,11 @@ const DatastoreTreeItem = (props) => {
|
||||
*
|
||||
* @param content
|
||||
*/
|
||||
var on_modal_close_success = function (content) {
|
||||
const on_modal_close_success = function (content) {
|
||||
console.log(content);
|
||||
};
|
||||
|
||||
var modalInstance = $uibModal.open({
|
||||
const modalInstance = $uibModal.open({
|
||||
templateUrl: "view/modal/create-link-share.html",
|
||||
controller: "ModalCreateLinkShareCtrl",
|
||||
backdrop: "static",
|
||||
@ -94,7 +98,7 @@ const DatastoreTreeItem = (props) => {
|
||||
}
|
||||
|
||||
registrations["read_share_rights"](content.share_id).then(function (share_details) {
|
||||
var modalInstance = $uibModal.open({
|
||||
const modalInstance = $uibModal.open({
|
||||
templateUrl: "view/modal/display-share-rights.html",
|
||||
controller: "ModalDisplayShareRightsCtrl",
|
||||
backdrop: "static",
|
||||
@ -131,7 +135,7 @@ const DatastoreTreeItem = (props) => {
|
||||
|
||||
const onEdit = (event) => {
|
||||
handleClose(event);
|
||||
// TODO editNode
|
||||
props.onEditEntry(content, content.path, props.nodePath);
|
||||
};
|
||||
|
||||
const onNewShare = (event) => {
|
||||
@ -143,20 +147,26 @@ const DatastoreTreeItem = (props) => {
|
||||
handleClose(event);
|
||||
// TODO moveNode
|
||||
};
|
||||
const clickItem = function () {
|
||||
if (content.type === "file") {
|
||||
return fileTransferService.onItemClick(content, content.path);
|
||||
} else {
|
||||
return secretService.onItemClick(content);
|
||||
const selectItem = function (event) {
|
||||
event.stopPropagation();
|
||||
if (props.onSelectItem && isSelectable) {
|
||||
props.onSelectItem(content, content.path, props.nodePath);
|
||||
}
|
||||
};
|
||||
const linkItem = function (event) {
|
||||
event.stopPropagation();
|
||||
if (props.onLinkItem) {
|
||||
props.onLinkItem(content, content.path, props.nodePath);
|
||||
}
|
||||
};
|
||||
|
||||
const hideShare = offline || (content.hasOwnProperty("share_rights") && content.share_rights.grant === false);
|
||||
const hideShare = offline || (content.hasOwnProperty("share_rights") && content.share_rights.grant === false) || content.type === "user";
|
||||
const hideLinkShare =
|
||||
offline ||
|
||||
!content.hasOwnProperty("type") ||
|
||||
(content.hasOwnProperty("share_rights") && content.share_rights.grant === false) ||
|
||||
store.getState().server.complianceDisableLinkShares;
|
||||
store.getState().server.complianceDisableLinkShares ||
|
||||
content.type === "user";
|
||||
const hideRightsOverview =
|
||||
offline ||
|
||||
(content.hasOwnProperty("share_rights") && content.share_rights.grant === false) ||
|
||||
@ -174,7 +184,8 @@ const DatastoreTreeItem = (props) => {
|
||||
(content.hasOwnProperty("share_rights") && content.share_rights.read !== true) ||
|
||||
!content.hasOwnProperty("type") ||
|
||||
!["website_password", "application_password"].includes(content["type"]);
|
||||
const hideEdit = offline || content.share_rights.write === false;
|
||||
const hideEdit = offline || content.share_rights.write === false || !props.onEditEntry;
|
||||
const hideShow = !hideEdit || content.share_rights.read === false || !props.onEditEntry;
|
||||
const hideClone =
|
||||
offline || content.share_rights.write === false || content.share_rights.read === false || content.type === "file" || content.type === "user";
|
||||
const hideMove = offline || content.share_rights.delete === false;
|
||||
@ -182,7 +193,7 @@ const DatastoreTreeItem = (props) => {
|
||||
|
||||
return (
|
||||
<div className={"tree-item"}>
|
||||
<div className={"tree-item-object"}>
|
||||
<div className={"tree-item-object" + (isSelectable ? "" : " notSelectable")} onClick={selectItem}>
|
||||
<span className="fa-stack">
|
||||
<i className={widgetService.itemIcon(content)} />
|
||||
{content.share_id && <i className="fa fa-circle fa-stack-2x text-danger is-shared" />}
|
||||
@ -190,13 +201,13 @@ const DatastoreTreeItem = (props) => {
|
||||
</span>
|
||||
<span className="tree-item-name">{content.name}</span>
|
||||
<ButtonGroup variant="text" aria-label="outlined button group" className={"node-open-link"}>
|
||||
{["bookmark", "website_password"].indexOf(content.type) !== -1 && (
|
||||
<Button aria-label="open" onClick={clickItem}>
|
||||
{Boolean(props.onLinkItem) && ["bookmark", "website_password"].indexOf(content.type) !== -1 && (
|
||||
<Button aria-label="open" onClick={linkItem}>
|
||||
<OpenInNewIcon fontSize="small" />
|
||||
</Button>
|
||||
)}
|
||||
{["file"].indexOf(content.type) !== -1 && (
|
||||
<Button aria-label="open" onClick={clickItem}>
|
||||
{Boolean(props.onLinkItem) && ["file"].indexOf(content.type) !== -1 && (
|
||||
<Button aria-label="open" onClick={linkItem}>
|
||||
<GetAppIcon fontSize="small" />
|
||||
</Button>
|
||||
)}
|
||||
@ -207,7 +218,7 @@ const DatastoreTreeItem = (props) => {
|
||||
<Menu id="simple-menu" anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose}>
|
||||
{!hideShare && (
|
||||
<MenuItem onClick={onNewShare}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<ShareIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
@ -217,7 +228,7 @@ const DatastoreTreeItem = (props) => {
|
||||
)}
|
||||
{!hideLinkShare && (
|
||||
<MenuItem onClick={onLinkShare}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<LinkIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
@ -227,7 +238,7 @@ const DatastoreTreeItem = (props) => {
|
||||
)}
|
||||
{!hideRightsOverview && (
|
||||
<MenuItem onClick={onRightsOverview}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<ListIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
@ -237,7 +248,7 @@ const DatastoreTreeItem = (props) => {
|
||||
)}
|
||||
{!hideCopyTotpToken && (
|
||||
<MenuItem onClick={onCopyTotpToken}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<ContentCopy className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
@ -247,7 +258,7 @@ const DatastoreTreeItem = (props) => {
|
||||
)}
|
||||
{!hideCopyUsername && (
|
||||
<MenuItem onClick={onCopyUsername}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<ContentCopy className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
@ -257,7 +268,7 @@ const DatastoreTreeItem = (props) => {
|
||||
)}
|
||||
{!hideCopyPassword && (
|
||||
<MenuItem onClick={onCopyPassword}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<ContentCopy className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
@ -265,20 +276,32 @@ const DatastoreTreeItem = (props) => {
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
)}
|
||||
<Divider className={classes.divider} />
|
||||
{(!hideShare || !hideLinkShare || !hideRightsOverview || !hideCopyTotpToken || !hideCopyUsername || !hideCopyPassword) && (
|
||||
<Divider className={classes.divider} />
|
||||
)}
|
||||
{!hideEdit && (
|
||||
<MenuItem onClick={onEdit}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<EditIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
{content.type === "user" ? t("SHOW") : t("SHOW_OR_EDIT")}
|
||||
{t("SHOW_OR_EDIT")}
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
)}
|
||||
{!hideShow && (
|
||||
<MenuItem onClick={onEdit}>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<VisibilityIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
{t("SHOW")}
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
)}
|
||||
{!hideClone && (
|
||||
<MenuItem onClick={onEdit}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<FileCopyIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
@ -288,7 +311,7 @@ const DatastoreTreeItem = (props) => {
|
||||
)}
|
||||
{!hideMove && (
|
||||
<MenuItem onClick={onMove}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<OpenWithIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
@ -299,7 +322,7 @@ const DatastoreTreeItem = (props) => {
|
||||
{!hideDelete && <Divider className={classes.divider} />}
|
||||
{!hideDelete && (
|
||||
<MenuItem onClick={onMove}>
|
||||
<ListItemIcon>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<DeleteIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
@ -314,9 +337,13 @@ const DatastoreTreeItem = (props) => {
|
||||
};
|
||||
|
||||
DatastoreTreeItem.propTypes = {
|
||||
search: PropTypes.string.isRequired,
|
||||
isSelectable: PropTypes.func,
|
||||
nodePath: PropTypes.array.isRequired,
|
||||
content: PropTypes.object,
|
||||
offline: PropTypes.bool.isRequired,
|
||||
onNewShare: PropTypes.func,
|
||||
onEditEntry: PropTypes.func,
|
||||
onLinkItem: PropTypes.func,
|
||||
onSelectItem: PropTypes.func,
|
||||
};
|
||||
export default DatastoreTreeItem;
|
||||
|
@ -3,11 +3,14 @@ import PropTypes from "prop-types";
|
||||
import offlineCache from "../services/offline-cache";
|
||||
import DatastoreTreeItem from "./datastore-tree-item";
|
||||
import DatastoreTreeFolder from "./datastore-tree-folder";
|
||||
import datastorePassword from "../services/datastore-password";
|
||||
|
||||
const DatastoreTree = (props) => {
|
||||
const { datastore, search, onNewFolder, onNewShare } = props;
|
||||
const { datastore, search } = props;
|
||||
const offline = offlineCache.isActive();
|
||||
|
||||
datastorePassword.modifyTreeForSearch(search, datastore);
|
||||
|
||||
return (
|
||||
<div className={"tree"}>
|
||||
{datastore.folders &&
|
||||
@ -16,10 +19,18 @@ const DatastoreTree = (props) => {
|
||||
.map(function (content, i) {
|
||||
return (
|
||||
<DatastoreTreeFolder
|
||||
onNewFolder={onNewFolder}
|
||||
onNewShare={onNewShare}
|
||||
search={search}
|
||||
isSelectable={props.isSelectable}
|
||||
onSelectItem={props.onSelectItem}
|
||||
onSelectNode={props.onSelectNode}
|
||||
onEditFolder={props.onEditFolder}
|
||||
onEditEntry={props.onEditEntry}
|
||||
onLinkItem={props.onLinkItem}
|
||||
onNewFolder={props.onNewFolder}
|
||||
onNewUser={props.onNewUser}
|
||||
onNewEntry={props.onNewEntry}
|
||||
onNewShare={props.onNewShare}
|
||||
key={i}
|
||||
nodePath={[content]}
|
||||
content={content}
|
||||
offline={offline}
|
||||
isExpandedDefault={Boolean(content["is_expanded"])}
|
||||
@ -30,17 +41,37 @@ const DatastoreTree = (props) => {
|
||||
datastore.items
|
||||
.filter((item) => !item["hidden"] && !item["deleted"])
|
||||
.map(function (content, i) {
|
||||
return <DatastoreTreeItem onNewShare={onNewShare} search={search} key={i} content={content} offline={offline} />;
|
||||
return (
|
||||
<DatastoreTreeItem
|
||||
isSelectable={props.isSelectable}
|
||||
onSelectItem={props.onSelectItem}
|
||||
onEditEntry={props.onEditEntry}
|
||||
onLinkItem={props.onLinkItem}
|
||||
onNewShare={props.onNewShare}
|
||||
key={i}
|
||||
nodePath={[content]}
|
||||
content={content}
|
||||
offline={offline}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
DatastoreTree.propTypes = {
|
||||
search: PropTypes.string.isRequired,
|
||||
search: PropTypes.string,
|
||||
datastore: PropTypes.object.isRequired,
|
||||
onNewFolder: PropTypes.func.isRequired,
|
||||
onNewUser: PropTypes.func,
|
||||
onNewShare: PropTypes.func,
|
||||
onNewEntry: PropTypes.func,
|
||||
onEditEntry: PropTypes.func,
|
||||
onLinkItem: PropTypes.func,
|
||||
onEditFolder: PropTypes.func,
|
||||
onSelectItem: PropTypes.func,
|
||||
onSelectNode: PropTypes.func,
|
||||
isSelectable: PropTypes.func,
|
||||
};
|
||||
|
||||
export default DatastoreTree;
|
||||
|
374
src/js/components/dialogs/accept-share.js
Normal file
374
src/js/components/dialogs/accept-share.js
Normal file
@ -0,0 +1,374 @@
|
||||
import React, { useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Dialog from "@material-ui/core/Dialog";
|
||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
import DialogContent from "@material-ui/core/DialogContent";
|
||||
import DialogActions from "@material-ui/core/DialogActions";
|
||||
import Button from "@material-ui/core/Button";
|
||||
|
||||
import { Grid } from "@material-ui/core";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import MuiAlert from "@material-ui/lab/Alert";
|
||||
|
||||
import datastoreUserService from "../../services/datastore-user";
|
||||
import cryptoLibrary from "../../services/crypto-library";
|
||||
import DatastoreTree from "../datastore-tree";
|
||||
import widget from "../../services/widget";
|
||||
import datastorePassword from "../../services/datastore-password";
|
||||
import DialogNewFolder from "./new-folder";
|
||||
import TextFieldPath from "../text-field-path";
|
||||
import shareService from "../../services/share";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
textField: {
|
||||
width: "100%",
|
||||
},
|
||||
checked: {
|
||||
color: "#9c27b0",
|
||||
},
|
||||
checkedIcon: {
|
||||
width: "20px",
|
||||
height: "20px",
|
||||
border: "1px solid #666",
|
||||
borderRadius: "3px",
|
||||
},
|
||||
uncheckedIcon: {
|
||||
width: "0px",
|
||||
height: "0px",
|
||||
padding: "9px",
|
||||
border: "1px solid #666",
|
||||
borderRadius: "3px",
|
||||
},
|
||||
tree: {
|
||||
marginTop: "8px",
|
||||
marginBottom: "8px",
|
||||
},
|
||||
}));
|
||||
|
||||
const DialogAcceptShare = (props) => {
|
||||
const { open, onClose, item, hideUser } = props;
|
||||
const { t } = useTranslation();
|
||||
const classes = useStyles();
|
||||
const [path, setPath] = useState([]);
|
||||
const [newFolderOpen, setNewFolderOpen] = useState(false);
|
||||
const [newFolderData, setNewFolderData] = useState({});
|
||||
|
||||
const [datastore, setDatastore] = useState(null);
|
||||
const [userIsTrusted, setUserIsTrusted] = useState(false);
|
||||
const [user, setUser] = useState({
|
||||
data: {
|
||||
user_name: "",
|
||||
user_username: "",
|
||||
user_public_key: "",
|
||||
},
|
||||
});
|
||||
|
||||
let isSubscribed = true;
|
||||
React.useEffect(() => {
|
||||
datastorePassword.getPasswordDatastore().then(onNewDatastoreLoaded);
|
||||
datastoreUserService.searchUserDatastore(item.share_right_create_user_id, item.share_right_create_user_username).then(function (user) {
|
||||
if (!isSubscribed) {
|
||||
return;
|
||||
}
|
||||
if (user !== null) {
|
||||
setUserIsTrusted(true);
|
||||
setUser(user);
|
||||
return;
|
||||
}
|
||||
|
||||
const onSuccess = function (data) {
|
||||
const users = data.data;
|
||||
if (Object.prototype.toString.call(users) === "[object Array]") {
|
||||
users.map((user) => {
|
||||
if (user.username === item.share_right_create_user_username) {
|
||||
setUser({
|
||||
data: {
|
||||
user_id: user.id,
|
||||
user_username: user.username,
|
||||
user_public_key: user.public_key,
|
||||
},
|
||||
name: user.username,
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
setUser({
|
||||
data: {
|
||||
user_id: users.id,
|
||||
user_username: users.username,
|
||||
user_public_key: users.public_key,
|
||||
},
|
||||
name: users.username,
|
||||
});
|
||||
}
|
||||
};
|
||||
const onError = function (data) {
|
||||
//pass
|
||||
};
|
||||
return datastoreUserService.searchUser(item.share_right_create_user_username).then(onSuccess, onError);
|
||||
});
|
||||
// cancel subscription to useEffect
|
||||
return () => (isSubscribed = false);
|
||||
}, []);
|
||||
|
||||
const onNewDatastoreLoaded = (data) => {
|
||||
if (!isSubscribed) {
|
||||
return;
|
||||
}
|
||||
setDatastore(data);
|
||||
};
|
||||
|
||||
const trust = () => {
|
||||
const onSuccess = function (user_data_store) {
|
||||
if (typeof user_data_store.items === "undefined") {
|
||||
user_data_store.items = [];
|
||||
}
|
||||
|
||||
const userObject = {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
name: "",
|
||||
type: "user",
|
||||
data: user.data,
|
||||
};
|
||||
|
||||
if (user.data.user_name) {
|
||||
userObject.name += user.data.user_name;
|
||||
} else {
|
||||
userObject.name += user.data.user_username;
|
||||
}
|
||||
userObject.name += " (" + user.data.user_public_key + ")";
|
||||
|
||||
user_data_store.items.push(userObject);
|
||||
|
||||
datastoreUserService.saveDatastoreContent(user_data_store);
|
||||
setUserIsTrusted(true);
|
||||
};
|
||||
const onError = function (data) {
|
||||
//pass
|
||||
};
|
||||
|
||||
datastoreUserService.getUserDatastore().then(onSuccess, onError);
|
||||
};
|
||||
|
||||
const onNewFolderCreate = (name) => {
|
||||
// called once someone clicked the CREATE button in the dialog closes with the new name
|
||||
setNewFolderOpen(false);
|
||||
widget.openNewFolder(newFolderData["parent"], newFolderData["path"], datastore, datastorePassword, name);
|
||||
};
|
||||
const onNewFolder = (parent, path) => {
|
||||
// called whenever someone clicks on a new folder Icon
|
||||
setNewFolderOpen(true);
|
||||
setNewFolderData({
|
||||
parent: parent,
|
||||
path: path,
|
||||
});
|
||||
};
|
||||
|
||||
const onSelectNode = (parent, path, nodePath) => {
|
||||
setPath(Array.from(nodePath));
|
||||
};
|
||||
|
||||
const isSelectable = (node) => {
|
||||
// filter out all targets that are a share if the item is not allowed to be shared
|
||||
if (!item.share_right_grant && node.share_id) {
|
||||
return false;
|
||||
}
|
||||
// filter out all targets that are inside of a share if the item is not allowed to be shared
|
||||
if (!item.share_right_grant && node.parent_share_id) {
|
||||
return false;
|
||||
}
|
||||
//
|
||||
if (!node.hasOwnProperty("share_rights")) {
|
||||
return true;
|
||||
}
|
||||
// we need both read and write permission on the target folder in order to update it with the new content
|
||||
if (!!(node.share_rights.read && node.share_rights.write)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const onConfirm = () => {
|
||||
const onSuccess = function (datastore) {
|
||||
const breadcrumbs = { id_breadcrumbs: path.map((node) => node.id) };
|
||||
|
||||
console.log(breadcrumbs);
|
||||
|
||||
const analyzedBreadcrumbs = datastorePassword.analyzeBreadcrumbs(breadcrumbs, datastore);
|
||||
|
||||
if (item.share_right_grant === false && typeof analyzedBreadcrumbs["parent_share_id"] !== "undefined") {
|
||||
// No grant right, yet the parent is a a share?!?
|
||||
alert("Wups, this should not happen. Error: 781f3da7-d38b-470e-a3c8-dd5787642230");
|
||||
}
|
||||
|
||||
const onSuccess = function (share) {
|
||||
if (typeof share.name === "undefined") {
|
||||
share.name = item.share_right_title;
|
||||
}
|
||||
|
||||
const shares = [share];
|
||||
|
||||
const onSuccess = function () {
|
||||
onClose();
|
||||
};
|
||||
const onError = function (data) {
|
||||
console.log(data);
|
||||
};
|
||||
|
||||
return datastorePassword
|
||||
.createShareLinksInDatastore(
|
||||
shares,
|
||||
analyzedBreadcrumbs["target"],
|
||||
analyzedBreadcrumbs["parent_path"],
|
||||
analyzedBreadcrumbs["path"],
|
||||
analyzedBreadcrumbs["parent_share_id"],
|
||||
analyzedBreadcrumbs["parent_datastore_id"],
|
||||
datastore,
|
||||
analyzedBreadcrumbs["parent_share"]
|
||||
)
|
||||
.then(onSuccess, onError);
|
||||
};
|
||||
|
||||
const onError = function (data) {
|
||||
//pass
|
||||
console.log(data);
|
||||
};
|
||||
console.log(item);
|
||||
return shareService
|
||||
.acceptShareRight(item.share_right_id, item.share_right_key, item.share_right_key_nonce, user.data.user_public_key)
|
||||
.then(onSuccess, onError);
|
||||
};
|
||||
const onError = function (data) {
|
||||
//pass
|
||||
console.log(data);
|
||||
};
|
||||
|
||||
return datastorePassword.getPasswordDatastore().then(onSuccess, onError);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
fullWidth
|
||||
maxWidth={"sm"}
|
||||
open={open}
|
||||
onClose={() => {
|
||||
onClose();
|
||||
}}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">{t("ACCEPT_SHARE")}</DialogTitle>
|
||||
<DialogContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<TextFieldPath className={classes.textField} variant="outlined" margin="dense" value={path} setPath={setPath} />
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12} className={classes.tree}>
|
||||
{datastore && <DatastoreTree datastore={datastore} onNewFolder={onNewFolder} onSelectNode={onSelectNode} isSelectable={isSelectable} />}
|
||||
{newFolderOpen && <DialogNewFolder open={newFolderOpen} onClose={() => setNewFolderOpen(false)} onCreate={onNewFolderCreate} />}
|
||||
</Grid>
|
||||
{!hideUser && (
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
{t("SHARED_BY")}:
|
||||
</Grid>
|
||||
)}
|
||||
{!hideUser && Boolean(user.data.user_name) && (
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<TextField
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
id="username"
|
||||
label={t("USERNAME") + " " + (userIsTrusted ? "" : t("NOT_TRUSTED_BRACKETS"))}
|
||||
name="username"
|
||||
autoComplete="username"
|
||||
value={user.data.user_name}
|
||||
disabled
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{!hideUser && !Boolean(user.data.user_name) && (
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<TextField
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
id="username"
|
||||
label={t("USERNAME") + " " + (userIsTrusted ? "" : t("NOT_TRUSTED_BRACKETS"))}
|
||||
name="username"
|
||||
autoComplete="username"
|
||||
value={user.data.user_username}
|
||||
disabled
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{!hideUser && (
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<TextField
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
id="publicKey"
|
||||
label={t("PUBLIC_KEY") + " " + (userIsTrusted ? "" : t("NOT_TRUSTED_BRACKETS"))}
|
||||
name="publicKey"
|
||||
autoComplete="publicKey"
|
||||
value={user.data.user_public_key}
|
||||
disabled
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{!userIsTrusted && !hideUser && (
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<MuiAlert
|
||||
severity="warning"
|
||||
style={{
|
||||
marginBottom: "5px",
|
||||
marginTop: "5px",
|
||||
}}
|
||||
>
|
||||
{t("YOU_NEVER_CONFIRMED_THIS_USERS_IDENTITY")}{" "}
|
||||
<a
|
||||
href="#"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
trust();
|
||||
}}
|
||||
>
|
||||
{t("ADD_TO_TRUSTED_USERS")}
|
||||
</a>
|
||||
</MuiAlert>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t("CLOSE")}
|
||||
</Button>
|
||||
<Button onClick={onConfirm} variant="contained" color="primary">
|
||||
{t("OK")}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
DialogAcceptShare.defaultProps = {
|
||||
hideUser: false,
|
||||
};
|
||||
|
||||
DialogAcceptShare.propTypes = {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
open: PropTypes.bool.isRequired,
|
||||
item: PropTypes.object.isRequired,
|
||||
hideUser: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default DialogAcceptShare;
|
166
src/js/components/dialogs/decrypt-gpg-message.js
Normal file
166
src/js/components/dialogs/decrypt-gpg-message.js
Normal file
@ -0,0 +1,166 @@
|
||||
import React, { useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Dialog from "@material-ui/core/Dialog";
|
||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
import DialogContent from "@material-ui/core/DialogContent";
|
||||
import DialogActions from "@material-ui/core/DialogActions";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import { Grid } from "@material-ui/core";
|
||||
|
||||
import HKP from "@openpgp/hkp-client";
|
||||
import * as openpgp from "openpgp";
|
||||
|
||||
import { BarLoader } from "react-spinners";
|
||||
|
||||
import GridContainerErrors from "../grid-container-errors";
|
||||
import store from "../../services/store";
|
||||
import datastorePasswordService from "../../services/datastore-password";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
textField: {
|
||||
width: "100%",
|
||||
},
|
||||
}));
|
||||
|
||||
const DialogDecryptGpgMessage = (props) => {
|
||||
const classes = useStyles();
|
||||
const { open, onClose } = props;
|
||||
const { t } = useTranslation();
|
||||
const [encryptedMessage, setEncryptedMessage] = useState("");
|
||||
const [decryptedMessage, setDecryptedMessage] = useState("");
|
||||
const [decrypting, setDecrypting] = useState(false);
|
||||
const [decryptingComplete, setDecryptingComplete] = useState(false);
|
||||
const [errors, setErrors] = useState([]);
|
||||
|
||||
const decrypt = () => {
|
||||
setDecrypting(true);
|
||||
|
||||
const pgpSender = [];
|
||||
|
||||
function decrypt(publicKey) {
|
||||
return datastorePasswordService.getAllOwnPgpKeys().then(async function (privateKeys) {
|
||||
const privateKeysArray = [];
|
||||
|
||||
for (let i = 0; i < privateKeys.length; i++) {
|
||||
const privateKey = await openpgp.readPrivateKey({ armoredKey: privateKeys[i] });
|
||||
privateKeysArray.push(privateKey);
|
||||
}
|
||||
|
||||
//console.log(pgpSender);
|
||||
const message = await openpgp.readMessage({
|
||||
armoredMessage: encryptedMessage, // parse armored message
|
||||
});
|
||||
let options;
|
||||
if (publicKey) {
|
||||
options = {
|
||||
message: message, // parse armored message
|
||||
verificationKeys: await openpgp.readKey({ armoredKey: publicKey }),
|
||||
decryptionKeys: privateKeysArray,
|
||||
};
|
||||
} else {
|
||||
options = {
|
||||
message: message, // parse armored message
|
||||
decryptionKeys: privateKeysArray,
|
||||
};
|
||||
}
|
||||
|
||||
openpgp.decrypt(options).then(
|
||||
function (plaintext) {
|
||||
setDecryptedMessage(plaintext.data);
|
||||
setDecryptingComplete(true);
|
||||
setDecrypting(false);
|
||||
},
|
||||
function (error) {
|
||||
console.log(error);
|
||||
setErrors([error.message]);
|
||||
setDecrypting(false);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
const gpgHkpSearch = store.getState().settingsDatastore.gpgHkpSearch;
|
||||
if (gpgHkpSearch && pgpSender && pgpSender.length) {
|
||||
const hkp = new HKP(store.getState().settingsDatastore.gpgHkpKeyServer);
|
||||
const options = {
|
||||
query: pgpSender,
|
||||
};
|
||||
hkp.lookup(options).then(
|
||||
function (public_key) {
|
||||
decrypt(public_key);
|
||||
},
|
||||
function (error) {
|
||||
console.log(error);
|
||||
console.log(error.message);
|
||||
decrypt();
|
||||
}
|
||||
);
|
||||
} else {
|
||||
decrypt();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog fullWidth maxWidth={"sm"} open={open} onClose={onClose} aria-labelledby="alert-dialog-title" aria-describedby="alert-dialog-description">
|
||||
<DialogTitle id="alert-dialog-title">{t("DECRYPT_MESSAGE")}</DialogTitle>
|
||||
<DialogContent>
|
||||
<Grid container>
|
||||
<GridContainerErrors errors={errors} setErrors={setErrors} />
|
||||
{!decryptingComplete && (
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<TextField
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
id="encryptedMessage"
|
||||
label={t("ENCRYPTED_MESSAGE")}
|
||||
name="encryptedMessage"
|
||||
autoComplete="encryptedMessage"
|
||||
value={encryptedMessage}
|
||||
onChange={(event) => {
|
||||
setEncryptedMessage(event.target.value);
|
||||
}}
|
||||
disabled={decrypting}
|
||||
multiline
|
||||
minRows={3}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{decryptingComplete && (
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<TextField
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
id="decryptedMessage"
|
||||
label={t("DECRYPTED_MESSAGE")}
|
||||
name="decryptedMessage"
|
||||
autoComplete="decryptedMessage"
|
||||
value={decryptedMessage}
|
||||
multiline
|
||||
readonly
|
||||
minRows={3}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onClose}>{t("CLOSE")}</Button>
|
||||
<Button onClick={decrypt} variant="contained" color="primary" disabled={!encryptedMessage || decrypting}>
|
||||
<span style={!decrypting ? {} : { display: "none" }}>{t("DECRYPT")}</span>
|
||||
<BarLoader color={"#FFF"} height={17} width={37} loading={decrypting} />
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
DialogDecryptGpgMessage.propTypes = {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
open: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default DialogDecryptGpgMessage;
|
1309
src/js/components/dialogs/edit-entry.js
Normal file
1309
src/js/components/dialogs/edit-entry.js
Normal file
File diff suppressed because it is too large
Load Diff
104
src/js/components/dialogs/edit-folder.js
Normal file
104
src/js/components/dialogs/edit-folder.js
Normal file
@ -0,0 +1,104 @@
|
||||
import React, { useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Dialog from "@material-ui/core/Dialog";
|
||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
import DialogContent from "@material-ui/core/DialogContent";
|
||||
import DialogActions from "@material-ui/core/DialogActions";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import { Grid } from "@material-ui/core";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
textField: {
|
||||
width: "100%",
|
||||
},
|
||||
checked: {
|
||||
color: "#9c27b0",
|
||||
},
|
||||
checkedIcon: {
|
||||
width: "20px",
|
||||
height: "20px",
|
||||
border: "1px solid #666",
|
||||
borderRadius: "3px",
|
||||
},
|
||||
uncheckedIcon: {
|
||||
width: "0px",
|
||||
height: "0px",
|
||||
padding: "9px",
|
||||
border: "1px solid #666",
|
||||
borderRadius: "3px",
|
||||
},
|
||||
}));
|
||||
|
||||
const DialogEditFolder = (props) => {
|
||||
const { open, onClose, node } = props;
|
||||
const { t } = useTranslation();
|
||||
const classes = useStyles();
|
||||
const [folderName, setFolderName] = useState(node.name);
|
||||
|
||||
const onSave = (event) => {
|
||||
node.name = folderName;
|
||||
props.onSave(node);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
fullWidth
|
||||
maxWidth={"sm"}
|
||||
open={open}
|
||||
onClose={() => {
|
||||
onClose();
|
||||
}}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">{t("EDIT_FOLDER")}</DialogTitle>
|
||||
<DialogContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<TextField
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
id="folderName"
|
||||
label={t("FOLDER_NAME")}
|
||||
name="folderName"
|
||||
autoComplete="folderName"
|
||||
value={folderName}
|
||||
required
|
||||
onChange={(event) => {
|
||||
setFolderName(event.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
{t("FOLDER_LINK")}: <a href={"index.html#!/datastore/search/" + node.id}>{node.id}</a>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t("CLOSE")}
|
||||
</Button>
|
||||
<Button onClick={onSave} variant="contained" color="primary" disabled={!folderName}>
|
||||
{t("SAVE")}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
DialogEditFolder.propTypes = {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onSave: PropTypes.func.isRequired,
|
||||
open: PropTypes.bool.isRequired,
|
||||
node: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default DialogEditFolder;
|
164
src/js/components/dialogs/edit-user.js
Normal file
164
src/js/components/dialogs/edit-user.js
Normal file
@ -0,0 +1,164 @@
|
||||
import React, { useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Dialog from "@material-ui/core/Dialog";
|
||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
import DialogContent from "@material-ui/core/DialogContent";
|
||||
import DialogActions from "@material-ui/core/DialogActions";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import CheckBoxOutlineBlankIcon from "@material-ui/icons/CheckBoxOutlineBlank";
|
||||
import { Grid } from "@material-ui/core";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import InputAdornment from "@material-ui/core/InputAdornment";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
|
||||
import GridContainerErrors from "../grid-container-errors";
|
||||
import Table from "../table";
|
||||
import helperService from "../../services/helper";
|
||||
import store from "../../services/store";
|
||||
import browserClient from "../../services/browser-client";
|
||||
import datastoreUserService from "../../services/datastore-user";
|
||||
import cryptoLibrary from "../../services/crypto-library";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
textField: {
|
||||
width: "100%",
|
||||
},
|
||||
checked: {
|
||||
color: "#9c27b0",
|
||||
},
|
||||
checkedIcon: {
|
||||
width: "20px",
|
||||
height: "20px",
|
||||
border: "1px solid #666",
|
||||
borderRadius: "3px",
|
||||
},
|
||||
uncheckedIcon: {
|
||||
width: "0px",
|
||||
height: "0px",
|
||||
padding: "9px",
|
||||
border: "1px solid #666",
|
||||
borderRadius: "3px",
|
||||
},
|
||||
}));
|
||||
|
||||
const DialogEditUser = (props) => {
|
||||
const { open, onClose, item } = props;
|
||||
const { t } = useTranslation();
|
||||
const classes = useStyles();
|
||||
const [errors, setErrors] = useState([]);
|
||||
const [visualUsername, setVisualUsername] = useState(item.data.user_name || "");
|
||||
const [username, setUsername] = useState(item.data.user_username);
|
||||
const [userId, setFoundUserId] = useState(item.data.user_id);
|
||||
const [publicKey, setFoundPublicKey] = useState(item.data.user_public_key);
|
||||
|
||||
const onSave = (event) => {
|
||||
if (item.data.user_name) {
|
||||
delete item.data.user_name;
|
||||
}
|
||||
if (visualUsername) {
|
||||
item.data.user_name = visualUsername;
|
||||
}
|
||||
|
||||
item.name = "";
|
||||
if (item.data.user_name) {
|
||||
item.name += item.data.user_name;
|
||||
} else {
|
||||
item.name += item.data.user_username;
|
||||
}
|
||||
item.name += " (" + item.data.user_public_key + ")";
|
||||
|
||||
props.onSave(item);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
fullWidth
|
||||
maxWidth={"sm"}
|
||||
open={open}
|
||||
onClose={() => {
|
||||
onClose();
|
||||
}}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">{t("EDIT_USER")}</DialogTitle>
|
||||
<DialogContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<TextField
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
id="visualUsername"
|
||||
label={t("NAME_OPTIONAL")}
|
||||
name="visualUsername"
|
||||
autoComplete="visualUsername"
|
||||
value={visualUsername}
|
||||
onChange={(event) => {
|
||||
setVisualUsername(event.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<TextField
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
id="username"
|
||||
label={t("USERNAME")}
|
||||
name="username"
|
||||
autoComplete="username"
|
||||
value={username}
|
||||
disabled
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<TextField
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
id="publicKey"
|
||||
label={t("PUBLIC_KEY")}
|
||||
name="publicKey"
|
||||
autoComplete="publicKey"
|
||||
helperText={t("TO_VERIFY_PUBLIC_KEY")}
|
||||
value={publicKey}
|
||||
disabled
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<GridContainerErrors errors={errors} setErrors={setErrors} />
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t("CLOSE")}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onSave(visualUsername, userId, username, publicKey);
|
||||
}}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={!userId || !username || !publicKey}
|
||||
>
|
||||
{t("SAVE")}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
DialogEditUser.propTypes = {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onSave: PropTypes.func.isRequired,
|
||||
open: PropTypes.bool.isRequired,
|
||||
item: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default DialogEditUser;
|
114
src/js/components/dialogs/new-entry.js
Normal file
114
src/js/components/dialogs/new-entry.js
Normal file
@ -0,0 +1,114 @@
|
||||
import React, { useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Dialog from "@material-ui/core/Dialog";
|
||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
import DialogContent from "@material-ui/core/DialogContent";
|
||||
import DialogActions from "@material-ui/core/DialogActions";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import { Grid } from "@material-ui/core";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import SelectFieldEntryType from "../select-field/entry-type";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
textField: {
|
||||
width: "100%",
|
||||
},
|
||||
checked: {
|
||||
color: "#9c27b0",
|
||||
},
|
||||
checkedIcon: {
|
||||
width: "20px",
|
||||
height: "20px",
|
||||
border: "1px solid #666",
|
||||
borderRadius: "3px",
|
||||
},
|
||||
uncheckedIcon: {
|
||||
width: "0px",
|
||||
height: "0px",
|
||||
padding: "9px",
|
||||
border: "1px solid #666",
|
||||
borderRadius: "3px",
|
||||
},
|
||||
}));
|
||||
|
||||
const DialogNewEntry = (props) => {
|
||||
const { open, onClose, onCreate } = props;
|
||||
const { t } = useTranslation();
|
||||
const classes = useStyles();
|
||||
const [folderName, setDescription] = useState("");
|
||||
const [entryType, setEntryType] = useState("website_password");
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
fullWidth
|
||||
maxWidth={"sm"}
|
||||
open={open}
|
||||
onClose={() => {
|
||||
onClose();
|
||||
}}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">{t("NEW_ENTRY")}</DialogTitle>
|
||||
<DialogContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<SelectFieldEntryType
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
required
|
||||
value={entryType}
|
||||
onChange={setEntryType}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<TextField
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
id="folderName"
|
||||
label={t("FOLDER_NAME")}
|
||||
name="folderName"
|
||||
autoComplete="folderName"
|
||||
value={folderName}
|
||||
required
|
||||
onChange={(event) => {
|
||||
setDescription(event.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t("CLOSE")}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onCreate(folderName);
|
||||
}}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={!folderName}
|
||||
>
|
||||
{t("CREATE")}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
DialogNewEntry.propTypes = {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onCreate: PropTypes.func.isRequired,
|
||||
open: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default DialogNewEntry;
|
373
src/js/components/dialogs/new-user.js
Normal file
373
src/js/components/dialogs/new-user.js
Normal file
@ -0,0 +1,373 @@
|
||||
import React, { useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Dialog from "@material-ui/core/Dialog";
|
||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
import DialogContent from "@material-ui/core/DialogContent";
|
||||
import DialogActions from "@material-ui/core/DialogActions";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import CheckBoxOutlineBlankIcon from "@material-ui/icons/CheckBoxOutlineBlank";
|
||||
import { Grid } from "@material-ui/core";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import InputAdornment from "@material-ui/core/InputAdornment";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
|
||||
import GridContainerErrors from "../grid-container-errors";
|
||||
import Table from "../table";
|
||||
import helperService from "../../services/helper";
|
||||
import store from "../../services/store";
|
||||
import browserClient from "../../services/browser-client";
|
||||
import datastoreUserService from "../../services/datastore-user";
|
||||
import cryptoLibrary from "../../services/crypto-library";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
textField: {
|
||||
width: "100%",
|
||||
},
|
||||
checked: {
|
||||
color: "#9c27b0",
|
||||
},
|
||||
checkedIcon: {
|
||||
width: "20px",
|
||||
height: "20px",
|
||||
border: "1px solid #666",
|
||||
borderRadius: "3px",
|
||||
},
|
||||
uncheckedIcon: {
|
||||
width: "0px",
|
||||
height: "0px",
|
||||
padding: "9px",
|
||||
border: "1px solid #666",
|
||||
borderRadius: "3px",
|
||||
},
|
||||
}));
|
||||
|
||||
const DialogNewUser = (props) => {
|
||||
const { open, onClose } = props;
|
||||
const { t } = useTranslation();
|
||||
const classes = useStyles();
|
||||
const [username, setUsername] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [domain, setDomain] = useState("");
|
||||
const allowUserSearchByUsernamePartial = store.getState().server.allowUserSearchByUsernamePartial;
|
||||
const allowUserSearchByEmail = store.getState().server.allowUserSearchByEmail;
|
||||
const [errors, setErrors] = useState([]);
|
||||
const [visualUsername, setVisualUsername] = useState("");
|
||||
const [foundUsername, setFoundUsername] = useState("");
|
||||
const [foundUserId, setFoundUserId] = useState("");
|
||||
const [foundPublicKey, setFoundPublicKey] = useState("");
|
||||
const [users, setUsers] = useState([]);
|
||||
|
||||
let isSubscribed = true;
|
||||
React.useEffect(() => {
|
||||
const onError = function (data) {
|
||||
console.log(data);
|
||||
};
|
||||
|
||||
browserClient.getConfig().then(onNewConfigLoaded, onError);
|
||||
return () => (isSubscribed = false);
|
||||
}, []);
|
||||
|
||||
const onNewConfigLoaded = (configJson) => {
|
||||
if (!isSubscribed) {
|
||||
return;
|
||||
}
|
||||
const domain = configJson["backend_servers"][0]["domain"];
|
||||
setDomain(domain);
|
||||
};
|
||||
|
||||
const showUser = (userId, username, publicKey) => {
|
||||
setUsers([]);
|
||||
setFoundUserId(userId);
|
||||
setFoundUsername(username);
|
||||
setFoundPublicKey(publicKey);
|
||||
};
|
||||
|
||||
const onSearch = (event) => {
|
||||
setErrors([]);
|
||||
setVisualUsername("");
|
||||
setFoundUserId("");
|
||||
setFoundUsername("");
|
||||
setFoundPublicKey("");
|
||||
|
||||
let searchUsername = username;
|
||||
let searchEmail = email;
|
||||
|
||||
if (!allowUserSearchByUsernamePartial) {
|
||||
searchUsername = helperService.formFullUsername(searchUsername, domain);
|
||||
}
|
||||
|
||||
const onSuccess = function (data) {
|
||||
data = data.data;
|
||||
|
||||
if (Object.prototype.toString.call(data) === "[object Array]") {
|
||||
setUsers(
|
||||
data.map((user) => {
|
||||
return [user.id, user.username, user.public_key];
|
||||
})
|
||||
);
|
||||
} else {
|
||||
showUser(data.id, data.username, data.public_key);
|
||||
}
|
||||
};
|
||||
|
||||
const onError = function (data) {
|
||||
if (data.status === 400) {
|
||||
setErrors(["USER_NOT_FOUND"]);
|
||||
} else {
|
||||
console.log(data);
|
||||
}
|
||||
};
|
||||
datastoreUserService.searchUser(searchUsername, searchEmail).then(onSuccess, onError);
|
||||
};
|
||||
|
||||
const onCreate = (event) => {
|
||||
const userObject = {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
type: "user",
|
||||
name: "",
|
||||
data: {
|
||||
user_id: foundUserId,
|
||||
user_public_key: foundPublicKey,
|
||||
user_username: foundUsername,
|
||||
},
|
||||
};
|
||||
if (visualUsername) {
|
||||
userObject["data"]["user_name"] = visualUsername;
|
||||
}
|
||||
|
||||
if (userObject.data.user_name) {
|
||||
userObject.name += userObject.data.user_name;
|
||||
} else {
|
||||
userObject.name += userObject.data.user_username;
|
||||
}
|
||||
userObject.name += " (" + userObject.data.user_public_key + ")";
|
||||
|
||||
props.onCreate(userObject);
|
||||
};
|
||||
|
||||
if (users.length > 0) {
|
||||
const columns = [
|
||||
{ name: t("ID"), options: { display: false } },
|
||||
{
|
||||
name: "",
|
||||
options: {
|
||||
filter: false,
|
||||
sort: false,
|
||||
empty: false,
|
||||
customBodyRender: (value, tableMeta, updateValue) => {
|
||||
return (
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
showUser(tableMeta.rowData[0], tableMeta.rowData[1], tableMeta.rowData[2]);
|
||||
}}
|
||||
>
|
||||
<CheckBoxOutlineBlankIcon />
|
||||
</IconButton>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: t("USERNAME"),
|
||||
options: {
|
||||
filter: true,
|
||||
sort: true,
|
||||
empty: false,
|
||||
customBodyRender: (value, tableMeta, updateValue) => {
|
||||
let username = tableMeta.rowData[1].substring(0, 20);
|
||||
if (tableMeta.rowData[1].length > 20) {
|
||||
username = username + "...";
|
||||
}
|
||||
return username;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: t("PUBLIC_KEY"),
|
||||
options: {
|
||||
filter: true,
|
||||
sort: true,
|
||||
empty: false,
|
||||
customBodyRender: (value, tableMeta, updateValue) => {
|
||||
let publicKey = tableMeta.rowData[2].substring(0, 50);
|
||||
if (tableMeta.rowData[2].length > 50) {
|
||||
publicKey = publicKey + "...";
|
||||
}
|
||||
return publicKey;
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const options = {
|
||||
filterType: "checkbox",
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
fullWidth
|
||||
maxWidth={"sm"}
|
||||
open={open}
|
||||
onClose={() => {
|
||||
setUsers([]);
|
||||
}}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">{t("PICK_USER")}</DialogTitle>
|
||||
<DialogContent>
|
||||
<Table data={users} columns={columns} options={options} />
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setUsers([]);
|
||||
}}
|
||||
>
|
||||
{t("CLOSE")}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Dialog
|
||||
fullWidth
|
||||
maxWidth={"sm"}
|
||||
open={open}
|
||||
onClose={() => {
|
||||
onClose();
|
||||
}}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">{t("NEW_USER")}</DialogTitle>
|
||||
<DialogContent>
|
||||
<Grid container>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<TextField
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
id="username"
|
||||
label={t("USERNAME")}
|
||||
InputProps={{
|
||||
endAdornment:
|
||||
domain && !allowUserSearchByUsernamePartial && !username.includes("@") ? (
|
||||
<InputAdornment position="end">{"@" + domain}</InputAdornment>
|
||||
) : null,
|
||||
}}
|
||||
name="username"
|
||||
autoComplete="username"
|
||||
value={username}
|
||||
onChange={(event) => {
|
||||
setUsername(event.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
{allowUserSearchByEmail && (
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<TextField
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
id="email"
|
||||
label={t("EMAIL")}
|
||||
name="email"
|
||||
autoComplete="email"
|
||||
value={email}
|
||||
onChange={(event) => {
|
||||
setEmail(event.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item xs={12} sm={12} md={12} style={{ marginBottom: "8px" }}>
|
||||
<Button onClick={onSearch} variant="contained" color="primary" disabled={!username && !email}>
|
||||
{t("SEARCH")}
|
||||
</Button>
|
||||
</Grid>
|
||||
{Boolean(foundUserId) && (
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<TextField
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
id="visualUsername"
|
||||
label={t("NAME_OPTIONAL")}
|
||||
name="visualUsername"
|
||||
autoComplete="visualUsername"
|
||||
value={visualUsername}
|
||||
onChange={(event) => {
|
||||
setVisualUsername(event.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{Boolean(foundUserId) && (
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<TextField
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
id="foundUsername"
|
||||
label={t("USERNAME")}
|
||||
name="foundUsername"
|
||||
autoComplete="foundUsername"
|
||||
value={foundUsername}
|
||||
disabled
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{Boolean(foundUserId) && (
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<TextField
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
id="foundPublicKey"
|
||||
label={t("PUBLIC_KEY")}
|
||||
name="foundPublicKey"
|
||||
autoComplete="foundPublicKey"
|
||||
helperText={t("TO_VERIFY_PUBLIC_KEY")}
|
||||
value={foundPublicKey}
|
||||
disabled
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
<GridContainerErrors errors={errors} setErrors={setErrors} />
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t("CLOSE")}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onCreate(visualUsername, foundUserId, foundUsername, foundPublicKey);
|
||||
}}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={!foundUserId || !foundUsername || !foundPublicKey}
|
||||
>
|
||||
{t("CREATE")}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
DialogNewUser.propTypes = {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onCreate: PropTypes.func.isRequired,
|
||||
open: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default DialogNewUser;
|
@ -9,7 +9,7 @@ import MuiAlert from "@material-ui/lab/Alert";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import { Grid } from "@material-ui/core";
|
||||
|
||||
const VerifyDialog = (props) => {
|
||||
const DialogVerify = (props) => {
|
||||
const { open, onClose, onConfirm, entries, affectedEntriesText, title, description } = props;
|
||||
const { t } = useTranslation();
|
||||
|
||||
@ -55,7 +55,7 @@ const VerifyDialog = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
VerifyDialog.propTypes = {
|
||||
DialogVerify.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
description: PropTypes.string.isRequired,
|
||||
affectedEntriesText: PropTypes.string,
|
||||
@ -65,4 +65,4 @@ VerifyDialog.propTypes = {
|
||||
open: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default VerifyDialog;
|
||||
export default DialogVerify;
|
9
src/js/components/icons/Rule.js
Normal file
9
src/js/components/icons/Rule.js
Normal file
@ -0,0 +1,9 @@
|
||||
import * as React from "react";
|
||||
import { createSvgIcon } from "@material-ui/core/utils";
|
||||
|
||||
export default createSvgIcon(
|
||||
<React.Fragment>
|
||||
<path d="M16.54,11L13,7.46l1.41-1.41l2.12,2.12l4.24-4.24l1.41,1.41L16.54,11z M11,7H2v2h9V7z M21,13.41L19.59,12L17,14.59 L14.41,12L13,13.41L15.59,16L13,18.59L14.41,20L17,17.41L19.59,20L21,18.59L18.41,16L21,13.41z M11,15H2v2h9V15z" />
|
||||
</React.Fragment>,
|
||||
"ContentCopy"
|
||||
);
|
98
src/js/components/select-field/entry-type.js
Normal file
98
src/js/components/select-field/entry-type.js
Normal file
@ -0,0 +1,98 @@
|
||||
import React from "react";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import Autocomplete from "@material-ui/lab/Autocomplete";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import PropTypes from "prop-types";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
|
||||
import itemBlueprintService from "../../services/item-blueprint";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
option: {
|
||||
fontSize: 15,
|
||||
"& > span": {
|
||||
marginRight: 10,
|
||||
fontSize: 18,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const SelectFieldEntryType = (props) => {
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { fullWidth, variant, margin, helperText, error, required, onChange, value, className } = props;
|
||||
|
||||
const entryTypes = itemBlueprintService.getEntryTypes();
|
||||
|
||||
let defaultValue = null;
|
||||
if (value) {
|
||||
defaultValue = entryTypes.find(function (country) {
|
||||
return country.value === value;
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Autocomplete
|
||||
options={entryTypes}
|
||||
classes={{
|
||||
option: classes.option,
|
||||
}}
|
||||
autoHighlight
|
||||
getOptionLabel={(option) => {
|
||||
return option ? t(option.title) : "";
|
||||
}}
|
||||
renderOption={(option) => <>{option ? t(option.title) : ""}</>}
|
||||
onChange={(event, newValue) => {
|
||||
if (newValue) {
|
||||
onChange(newValue.value);
|
||||
} else {
|
||||
onChange("");
|
||||
}
|
||||
}}
|
||||
getOptionSelected={(option, value) => {
|
||||
if (option) {
|
||||
return option.value === value.value;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}}
|
||||
value={defaultValue}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
className={className}
|
||||
{...params}
|
||||
label={t("TYPE")}
|
||||
required={required}
|
||||
margin={margin}
|
||||
variant={variant}
|
||||
helperText={helperText}
|
||||
error={error}
|
||||
fullWidth={fullWidth}
|
||||
inputProps={{
|
||||
...params.inputProps,
|
||||
autoComplete: "new-password", // disable autocomplete and autofill
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
SelectFieldEntryType.defaultProps = {
|
||||
error: false,
|
||||
};
|
||||
|
||||
SelectFieldEntryType.propTypes = {
|
||||
value: PropTypes.string,
|
||||
fullWidth: PropTypes.bool,
|
||||
error: PropTypes.bool,
|
||||
required: PropTypes.bool,
|
||||
helperText: PropTypes.string,
|
||||
variant: PropTypes.string,
|
||||
margin: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
export default SelectFieldEntryType;
|
@ -3,7 +3,7 @@ import TextField from "@material-ui/core/TextField";
|
||||
import Autocomplete from "@material-ui/lab/Autocomplete";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import PropTypes from "prop-types";
|
||||
import fileRepository from "../services/file-repository";
|
||||
import fileRepository from "../../services/file-repository";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
@ -16,7 +16,7 @@ const useStyles = makeStyles((theme) => ({
|
||||
},
|
||||
}));
|
||||
|
||||
const FileRepositoryTypeSelectField = (props) => {
|
||||
const SelectFieldFileRepositoryType = (props) => {
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslation();
|
||||
|
||||
@ -78,11 +78,11 @@ const FileRepositoryTypeSelectField = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
FileRepositoryTypeSelectField.defaultProps = {
|
||||
SelectFieldFileRepositoryType.defaultProps = {
|
||||
error: false,
|
||||
};
|
||||
|
||||
FileRepositoryTypeSelectField.propTypes = {
|
||||
SelectFieldFileRepositoryType.propTypes = {
|
||||
value: PropTypes.string,
|
||||
fullWidth: PropTypes.bool,
|
||||
error: PropTypes.bool,
|
||||
@ -94,4 +94,4 @@ FileRepositoryTypeSelectField.propTypes = {
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
export default FileRepositoryTypeSelectField;
|
||||
export default SelectFieldFileRepositoryType;
|
@ -5,7 +5,7 @@ import { useTranslation } from "react-i18next";
|
||||
import PropTypes from "prop-types";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
|
||||
import { languages } from "../i18n";
|
||||
import { languages } from "../../i18n";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
option: {
|
||||
@ -17,12 +17,10 @@ const useStyles = makeStyles((theme) => ({
|
||||
},
|
||||
}));
|
||||
|
||||
const LanguageSelectField = (props) => {
|
||||
const SelectFieldLanguage = (props) => {
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslation();
|
||||
|
||||
//const lngs = fileRepository.getPossibleTypes();
|
||||
|
||||
const lngs = [];
|
||||
|
||||
Object.entries(languages).forEach(([key, value]) => {
|
||||
@ -33,9 +31,9 @@ const LanguageSelectField = (props) => {
|
||||
|
||||
const { fullWidth, variant, margin, helperText, error, required, onChange, value, className } = props;
|
||||
|
||||
let defaulValue = null;
|
||||
let defaultValue = null;
|
||||
if (value && lngs && lngs.length) {
|
||||
defaulValue = lngs.find(function (country) {
|
||||
defaultValue = lngs.find(function (country) {
|
||||
return country.value === value;
|
||||
});
|
||||
}
|
||||
@ -65,7 +63,7 @@ const LanguageSelectField = (props) => {
|
||||
return "";
|
||||
}
|
||||
}}
|
||||
value={defaulValue}
|
||||
value={defaultValue}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
className={className}
|
||||
@ -87,11 +85,11 @@ const LanguageSelectField = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
LanguageSelectField.defaultProps = {
|
||||
SelectFieldLanguage.defaultProps = {
|
||||
error: false,
|
||||
};
|
||||
|
||||
LanguageSelectField.propTypes = {
|
||||
SelectFieldLanguage.propTypes = {
|
||||
value: PropTypes.string,
|
||||
fullWidth: PropTypes.bool,
|
||||
error: PropTypes.bool,
|
||||
@ -103,4 +101,4 @@ LanguageSelectField.propTypes = {
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
export default LanguageSelectField;
|
||||
export default SelectFieldLanguage;
|
@ -22,7 +22,7 @@ class Table extends Component {
|
||||
};
|
||||
componentDidMount() {
|
||||
if (this.props.dataFunction) {
|
||||
var rowsPerPage = 10;
|
||||
let rowsPerPage = 10;
|
||||
if (this.props.options.hasOwnProperty("rowsPerPage")) {
|
||||
rowsPerPage = this.props.options["rowsPerPage"];
|
||||
}
|
||||
@ -99,9 +99,9 @@ class Table extends Component {
|
||||
defaultOptions["serverSide"] = true;
|
||||
defaultOptions["count"] = this.state.count;
|
||||
defaultOptions["onTableChange"] = (action, tableState) => {
|
||||
var ordering;
|
||||
let ordering;
|
||||
if (tableState.sortOrder.hasOwnProperty("name")) {
|
||||
for (var i = 0; i < tableState.columns.length; i++) {
|
||||
for (let i = 0; i < tableState.columns.length; i++) {
|
||||
if (tableState.columns[i].name === tableState.sortOrder["name"]) {
|
||||
if (tableState.sortOrder["direction"] === "asc") {
|
||||
ordering = tableState.columns[i].id;
|
||||
@ -113,7 +113,7 @@ class Table extends Component {
|
||||
}
|
||||
}
|
||||
if (["changePage", "sort", "search", "changeRowsPerPage", "changePage", "filterChange"].includes(action)) {
|
||||
var params = {
|
||||
const params = {
|
||||
page: tableState.page,
|
||||
page_size: tableState.rowsPerPage,
|
||||
};
|
||||
|
65
src/js/components/text-field-path.js
Normal file
65
src/js/components/text-field-path.js
Normal file
@ -0,0 +1,65 @@
|
||||
import * as React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import InputLabel from "@material-ui/core/InputLabel";
|
||||
import FormControl from "@material-ui/core/FormControl";
|
||||
import InputAdornment from "@material-ui/core/InputAdornment";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import OutlinedInput from "@material-ui/core/OutlinedInput";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import ClearIcon from "@material-ui/icons/Clear";
|
||||
|
||||
const TextFieldPath = (props) => {
|
||||
const { value, setPath, ...other } = props;
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<FormControl {...other}>
|
||||
<InputLabel shrink htmlFor="component-simple">
|
||||
{t("PATH")}
|
||||
</InputLabel>
|
||||
<OutlinedInput
|
||||
id="component-simple"
|
||||
margin="dense"
|
||||
inputComponent="div"
|
||||
notched
|
||||
value
|
||||
label={t("PATH")}
|
||||
inputProps={{
|
||||
children: (
|
||||
<>
|
||||
\
|
||||
{value.map((path, index) => {
|
||||
return (
|
||||
<span
|
||||
key={index}
|
||||
onClick={() => {
|
||||
setPath(value.slice(0, index + 1));
|
||||
}}
|
||||
>
|
||||
{path.name + "\\"}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
),
|
||||
}}
|
||||
endAdornment={
|
||||
value.length > 0 && (
|
||||
<InputAdornment position="end">
|
||||
<IconButton aria-label="clear path" onClick={() => setPath([])} edge="end">
|
||||
<ClearIcon />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
TextFieldPath.propTypes = {
|
||||
value: PropTypes.array.isRequired,
|
||||
setPath: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default TextFieldPath;
|
52
src/js/components/totp-circle.js
Normal file
52
src/js/components/totp-circle.js
Normal file
@ -0,0 +1,52 @@
|
||||
import React, { useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Box from "@material-ui/core/Box";
|
||||
|
||||
import ContentCopy from "./icons/ContentCopy";
|
||||
import cryptoLibraryService from "../services/crypto-library";
|
||||
import browserClientService from "../services/browser-client";
|
||||
|
||||
const TotpCircle = (props) => {
|
||||
const { period, digits, algorithm, code, ...rest } = props;
|
||||
const [progress, setProgress] = React.useState(10);
|
||||
const [token, setToken] = useState("");
|
||||
|
||||
React.useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
setToken(cryptoLibraryService.getTotpToken(code, period, algorithm, digits));
|
||||
const percentage = 100 - (((period || 30) - (Math.round(new Date().getTime() / 1000.0) % (period || 30))) / (period || 30)) * 100;
|
||||
setProgress(percentage);
|
||||
}, 500);
|
||||
return () => {
|
||||
clearInterval(timer);
|
||||
};
|
||||
}, []);
|
||||
return (
|
||||
<Box position="relative" display="inline-flex" {...rest}>
|
||||
<CircularProgress variant="determinate" value={progress} size={"100%"} />
|
||||
<Box top={0} left={0} bottom={0} right={0} position="absolute" display="flex" alignItems="center" justifyContent="center">
|
||||
<Button endIcon={<ContentCopy>copy</ContentCopy>} onClick={() => browserClientService.copyToClipboard(token)}>
|
||||
{token}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
TotpCircle.defaultProps = {
|
||||
period: 30,
|
||||
digits: 6,
|
||||
algorithm: "SHA1",
|
||||
code: "",
|
||||
};
|
||||
|
||||
TotpCircle.propTypes = {
|
||||
period: PropTypes.number,
|
||||
digits: PropTypes.number,
|
||||
algorithm: PropTypes.string,
|
||||
code: PropTypes.string,
|
||||
};
|
||||
|
||||
export default TotpCircle;
|
146
src/js/containers/download-banner.js
Normal file
146
src/js/containers/download-banner.js
Normal file
@ -0,0 +1,146 @@
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useSelector } from "react-redux";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import GetAppIcon from "@material-ui/icons/GetApp";
|
||||
|
||||
import browserClient from "../services/browser-client";
|
||||
import deviceService from "../services/device";
|
||||
import action from "../actions/bound-action-creators";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
overlay: {
|
||||
width: "100%",
|
||||
position: "fixed",
|
||||
zIndex: 1400,
|
||||
top: 0,
|
||||
left: 0,
|
||||
backgroundColor: "#2dbb93",
|
||||
overflowY: "hidden",
|
||||
transition: "0.5s",
|
||||
"& a": {
|
||||
padding: "8px",
|
||||
textDecoration: "none",
|
||||
display: "block",
|
||||
transition: "0.3s",
|
||||
},
|
||||
"& a:hover": {
|
||||
color: "#fff",
|
||||
},
|
||||
"& a:focus": {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
overlayContent: {
|
||||
position: "relative",
|
||||
width: "90%",
|
||||
textAlign: "center",
|
||||
paddingLeft: "5%",
|
||||
},
|
||||
closeBtn: {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
right: "5px",
|
||||
},
|
||||
wrapIcon: {
|
||||
verticalAlign: "middle",
|
||||
display: "inline-flex",
|
||||
},
|
||||
downloadIcon: {
|
||||
fontSize: "1.2rem",
|
||||
},
|
||||
}));
|
||||
|
||||
const DownloadBanner = (props) => {
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslation();
|
||||
const [disableDownloadBanner, setDisableDownloadBanner] = useState(false);
|
||||
const isDownloadBannerHidden = useSelector((state) => state.client.hideDownloadBanner);
|
||||
const showAndroidDownload = deviceService.isMobileAndroid();
|
||||
const showIosDownload = deviceService.isMobileIos();
|
||||
const showChromeDownload = !deviceService.isMobile() && deviceService.isChrome() && browserClient.getClientType() === "webclient";
|
||||
const showFirefoxDownload = !deviceService.isMobile() && deviceService.isFirefox() && browserClient.getClientType() === "webclient";
|
||||
|
||||
React.useEffect(() => {
|
||||
browserClient.getConfig().then(onNewConfigLoaded);
|
||||
// cancel subscription to useEffect
|
||||
return () => (isSubscribed = false);
|
||||
}, []);
|
||||
|
||||
let isSubscribed = true;
|
||||
const onNewConfigLoaded = (configJson) => {
|
||||
if (!isSubscribed) {
|
||||
return;
|
||||
}
|
||||
setDisableDownloadBanner(Boolean(configJson["disable_download_bar"]));
|
||||
};
|
||||
|
||||
const hideDownloadBanner = (event) => {
|
||||
action.setHideDownloadBanner(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<div id="PsonoDownloadBanner">
|
||||
{!disableDownloadBanner && !isDownloadBannerHidden && showAndroidDownload && (
|
||||
<div className={classes.overlay}>
|
||||
<a href="#" className={classes.closeBtn} onClick={hideDownloadBanner}>
|
||||
<i className="fa fa-times" aria-hidden="true" />
|
||||
</a>
|
||||
<div className={classes.overlayContent}>
|
||||
<a href="https://play.google.com/store/apps/details?id=com.psono.psono" target="_blank" rel="noopener">
|
||||
{t("DOWNLOAD_PSONO")}
|
||||
<i className="fa fa-download" aria-hidden="true" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!disableDownloadBanner && !isDownloadBannerHidden && showIosDownload && (
|
||||
<div className={classes.overlay}>
|
||||
<a href="#" className={classes.closeBtn} onClick={hideDownloadBanner}>
|
||||
<i className="fa fa-times" aria-hidden="true" />
|
||||
</a>
|
||||
<div className={classes.overlayContent}>
|
||||
<a href="https://apps.apple.com/us/app/psono-password-manager/id1545581224" target="_blank" rel="noopener">
|
||||
{t("DOWNLOAD_PSONO")}
|
||||
<i className="fa fa-download" aria-hidden="true" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!disableDownloadBanner && !isDownloadBannerHidden && showChromeDownload && (
|
||||
<div className={classes.overlay}>
|
||||
<a href="#" className={classes.closeBtn} onClick={hideDownloadBanner}>
|
||||
<i className="fa fa-times" aria-hidden="true" />
|
||||
</a>
|
||||
<div className={classes.overlayContent}>
|
||||
<a
|
||||
href="https://chrome.google.com/webstore/detail/psono-free-password-manag/eljmjmgjkbmpmfljlmklcfineebidmlo"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<Typography variant="body2" className={classes.wrapIcon}>
|
||||
{t("DOWNLOAD_PSONO")} <GetAppIcon className={classes.downloadIcon} />
|
||||
</Typography>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!disableDownloadBanner && !isDownloadBannerHidden && showFirefoxDownload && (
|
||||
<div className={classes.overlay}>
|
||||
<a href="#" className={classes.closeBtn} onClick={hideDownloadBanner}>
|
||||
<i className="fa fa-times" aria-hidden="true" />
|
||||
</a>
|
||||
<div className={classes.overlayContent}>
|
||||
<a href="https://addons.mozilla.org/de/firefox/addon/psono-pw-password-manager/" target="_blank" rel="noopener">
|
||||
{t("DOWNLOAD_PSONO")}
|
||||
<i className="fa fa-download" aria-hidden="true" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DownloadBanner;
|
@ -1,394 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import datastorePassword from "../services/datastore-password";
|
||||
import widget from "../services/widget";
|
||||
import { ClipLoader } from "react-spinners";
|
||||
import DatastoreTree from "../components/datastore-tree";
|
||||
import DialogNewFolder from "../components/dialogs/new-folder";
|
||||
import DialogNewShare from "../components/dialogs/new-share";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
loader: {
|
||||
marginTop: "30px",
|
||||
marginBottom: "30px",
|
||||
margin: "auto",
|
||||
},
|
||||
}));
|
||||
|
||||
const PasswordDatastore = (props) => {
|
||||
const classes = useStyles();
|
||||
const { search } = props;
|
||||
let isSubscribed = true;
|
||||
const [datastore, setDatastore] = useState(null);
|
||||
const [newFolderOpen, setNewFolderOpen] = useState(false);
|
||||
const [newFolderData, setNewFolderData] = useState({});
|
||||
const [newShareOpen, setNewShareOpen] = useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
datastorePassword.getPasswordDatastore().then(onNewDatastoreLoaded);
|
||||
return () => (isSubscribed = false);
|
||||
}, []);
|
||||
|
||||
const onNewDatastoreLoaded = (data) => {
|
||||
if (!isSubscribed) {
|
||||
return;
|
||||
}
|
||||
setDatastore(data);
|
||||
};
|
||||
|
||||
const onNewFolderCreate = (name) => {
|
||||
// called once someone clicked the CREATE button in the dialog closes with the new name
|
||||
setNewFolderOpen(false);
|
||||
widget.openNewFolder(newFolderData["parent"], newFolderData["path"], datastore, datastorePassword, name);
|
||||
};
|
||||
const onNewFolder = (parent, path) => {
|
||||
// called whenever someone clicks on a new folder Icon
|
||||
setNewFolderOpen(true);
|
||||
setNewFolderData({
|
||||
parent: parent,
|
||||
path: path,
|
||||
});
|
||||
};
|
||||
|
||||
const onNewShareCreate = (name) => {
|
||||
// called once someone clicked the CREATE button in the dialog closes with the new name
|
||||
setNewFolderOpen(false);
|
||||
|
||||
// const onShare = (event) => {
|
||||
// handleClose(event);
|
||||
// if (content.hasOwnProperty("share_rights") && content.share_rights.grant === false) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * little wrapper to create the share rights from the selected users / groups and rights for a given nonce and
|
||||
// * a given share_id and key
|
||||
// *
|
||||
// * @param share_id
|
||||
// * @param share_secret_key
|
||||
// * @param node
|
||||
// * @param users
|
||||
// * @param groups
|
||||
// * @param selected_users
|
||||
// * @param selected_groups
|
||||
// * @param selected_rights
|
||||
// */
|
||||
// var create_share_rights = function (share_id, share_secret_key, node, users, groups, selected_users, selected_groups, selected_rights) {
|
||||
// var i;
|
||||
// var modalInstance;
|
||||
//
|
||||
// // found a user that has been selected, lets create the rights for him
|
||||
// var rights = {
|
||||
// read: selected_rights.indexOf("read") > -1,
|
||||
// write: selected_rights.indexOf("write") > -1,
|
||||
// grant: selected_rights.indexOf("grant") > -1,
|
||||
// };
|
||||
//
|
||||
// // generate the title
|
||||
// // TODO create form field with this default value and read value from form
|
||||
//
|
||||
// var title = "";
|
||||
// if (typeof node.type === "undefined") {
|
||||
// // we have a folder
|
||||
// title = "Folder with title '" + node.name + "'";
|
||||
// } else {
|
||||
// // we have an item
|
||||
// title = _blueprints[node.type].name + " with title '" + node.name + "'";
|
||||
// }
|
||||
//
|
||||
// // get the type
|
||||
// var type = "";
|
||||
// if (typeof node.type === "undefined") {
|
||||
// // we have a folder
|
||||
// type = "folder";
|
||||
// } else {
|
||||
// // we have an item
|
||||
// type = node.type;
|
||||
// }
|
||||
//
|
||||
// function create_user_share_right(user) {
|
||||
// var onSuccess = function (data) {
|
||||
// // pass
|
||||
// };
|
||||
// var onError = function (result) {
|
||||
// var title;
|
||||
// var description;
|
||||
// if (result.data === null) {
|
||||
// title = "UNKNOWN_ERROR";
|
||||
// description = "UNKNOWN_ERROR_CHECK_BROWSER_CONSOLE";
|
||||
// } else if (
|
||||
// result.data.hasOwnProperty("non_field_errors") &&
|
||||
// (result.data["non_field_errors"].indexOf("USER_DOES_NOT_EXIST_PROBABLY_DELETED") !== -1 ||
|
||||
// result.data["non_field_errors"].indexOf("Target user does not exist.") !== -1)
|
||||
// ) {
|
||||
// title = "UNKNOWN_USER";
|
||||
// description = _translations.USER_DOES_NOT_EXIST_PROBABLY_DELETED + " " + user.name;
|
||||
// } else if (result.data.hasOwnProperty("non_field_errors")) {
|
||||
// title = "ERROR";
|
||||
// description = result.data["non_field_errors"][0];
|
||||
// } else {
|
||||
// title = "UNKNOWN_ERROR";
|
||||
// description = "UNKNOWN_ERROR_CHECK_BROWSER_CONSOLE";
|
||||
// }
|
||||
//
|
||||
// modalInstance = $uibModal.open({
|
||||
// templateUrl: "view/modal/error.html",
|
||||
// controller: "ModalErrorCtrl",
|
||||
// resolve: {
|
||||
// title: function () {
|
||||
// return title;
|
||||
// },
|
||||
// description: function () {
|
||||
// return description;
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
//
|
||||
// modalInstance.result.then(
|
||||
// function (breadcrumbs) {
|
||||
// // pass
|
||||
// },
|
||||
// function () {
|
||||
// // cancel triggered
|
||||
// }
|
||||
// );
|
||||
// };
|
||||
//
|
||||
// return registrations["create_share_right"](
|
||||
// title,
|
||||
// type,
|
||||
// share_id,
|
||||
// user.data.user_id,
|
||||
// undefined,
|
||||
// user.data.user_public_key,
|
||||
// undefined,
|
||||
// share_secret_key,
|
||||
// rights["read"],
|
||||
// rights["write"],
|
||||
// rights["grant"]
|
||||
// ).then(onSuccess, onError);
|
||||
// }
|
||||
//
|
||||
// for (i = 0; i < users.length; i++) {
|
||||
// if (selected_users.indexOf(users[i].id) < 0) {
|
||||
// continue;
|
||||
// }
|
||||
// create_user_share_right(users[i]);
|
||||
// }
|
||||
//
|
||||
// function create_group_share_right(group) {
|
||||
// var onSuccess = function (data) {
|
||||
// // pass
|
||||
// };
|
||||
// var onError = function (result) {
|
||||
// var title;
|
||||
// var description;
|
||||
// if (result.data === null) {
|
||||
// title = "UNKNOWN_ERROR";
|
||||
// description = "UNKNOWN_ERROR_CHECK_BROWSER_CONSOLE";
|
||||
// } else if (result.data.hasOwnProperty("non_field_errors")) {
|
||||
// title = "ERROR";
|
||||
// description = result.data["non_field_errors"][0];
|
||||
// } else {
|
||||
// title = "UNKNOWN_ERROR";
|
||||
// description = "UNKNOWN_ERROR_CHECK_BROWSER_CONSOLE";
|
||||
// }
|
||||
//
|
||||
// modalInstance = $uibModal.open({
|
||||
// templateUrl: "view/modal/error.html",
|
||||
// controller: "ModalErrorCtrl",
|
||||
// resolve: {
|
||||
// title: function () {
|
||||
// return title;
|
||||
// },
|
||||
// description: function () {
|
||||
// return description;
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
//
|
||||
// modalInstance.result.then(
|
||||
// function (breadcrumbs) {
|
||||
// // pass
|
||||
// },
|
||||
// function () {
|
||||
// // cancel triggered
|
||||
// }
|
||||
// );
|
||||
// };
|
||||
//
|
||||
// var group_secret_key = registrations["get_group_secret_key"](
|
||||
// group.group_id,
|
||||
// group.secret_key,
|
||||
// group.secret_key_nonce,
|
||||
// group.secret_key_type,
|
||||
// group.public_key
|
||||
// );
|
||||
// return registrations["create_share_right"](
|
||||
// title,
|
||||
// type,
|
||||
// share_id,
|
||||
// undefined,
|
||||
// group.group_id,
|
||||
// undefined,
|
||||
// group_secret_key,
|
||||
// share_secret_key,
|
||||
// rights["read"],
|
||||
// rights["write"],
|
||||
// rights["grant"]
|
||||
// ).then(onSuccess, onError);
|
||||
// }
|
||||
//
|
||||
// for (i = 0; i < groups.length; i++) {
|
||||
// if (selected_groups.indexOf(groups[i].group_id) < 0) {
|
||||
// continue;
|
||||
// }
|
||||
// create_group_share_right(groups[i]);
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// /**
|
||||
// * Users and or / shares have been selected in the modal and the final "Share Now" button was
|
||||
// * clicked
|
||||
// *
|
||||
// * @param content
|
||||
// */
|
||||
// var on_modal_close_success = function (content) {
|
||||
// // content = { node: "...", path: "...", selected_users: "...", users: "..."}
|
||||
//
|
||||
// var has_no_users = !content.users || content.users.length < 1 || !content.selected_users || content.selected_users.length < 1;
|
||||
//
|
||||
// var has_no_groups = !content.groups || content.groups.length < 1 || !content.selected_groups || content.selected_groups.length < 1;
|
||||
//
|
||||
// if (has_no_users && has_no_groups) {
|
||||
// // TODO echo not shared message because no user / group selected
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (content.node.hasOwnProperty("share_id")) {
|
||||
// // its already a share, so generate only the share_rights
|
||||
//
|
||||
// create_share_rights(
|
||||
// content.node.share_id,
|
||||
// content.node.share_secret_key,
|
||||
// content.node,
|
||||
// content.users,
|
||||
// content.groups,
|
||||
// content.selected_users,
|
||||
// content.selected_groups,
|
||||
// content.selected_rights
|
||||
// );
|
||||
// } else {
|
||||
// // its not yet a share, so generate the share, generate the share_rights and update
|
||||
// // the datastore
|
||||
//
|
||||
// registrations["get_password_datastore"]().then(function (datastore) {
|
||||
// var path = content.path.slice();
|
||||
// var closest_share_info = registrations["get_closest_parent_share"](path, datastore, null, 1);
|
||||
// var parent_share = closest_share_info["closest_share"];
|
||||
// var parent_share_id;
|
||||
// var parent_datastore_id;
|
||||
//
|
||||
// if (parent_share !== false && parent_share !== null) {
|
||||
// parent_share_id = parent_share.share_id;
|
||||
// } else {
|
||||
// parent_datastore_id = datastore.datastore_id;
|
||||
// }
|
||||
//
|
||||
// // create the share
|
||||
// registrations["create_share"](content.node, parent_share_id, parent_datastore_id, content.node.id).then(function (share_details) {
|
||||
// var item_path = content.path.slice();
|
||||
// var item_path_copy = content.path.slice();
|
||||
// var item_path_copy2 = content.path.slice();
|
||||
//
|
||||
// // create the share right
|
||||
// create_share_rights(
|
||||
// share_details.share_id,
|
||||
// share_details.secret_key,
|
||||
// content.node,
|
||||
// content.users,
|
||||
// content.groups,
|
||||
// content.selected_users,
|
||||
// content.selected_groups,
|
||||
// content.selected_rights
|
||||
// );
|
||||
//
|
||||
// // update datastore and / or possible parent shares
|
||||
// var search = registrations["find_in_datastore"](item_path, datastore);
|
||||
//
|
||||
// if (typeof content.node.type === "undefined") {
|
||||
// // we have an item
|
||||
// delete search[0][search[1]].secret_id;
|
||||
// delete search[0][search[1]].secret_key;
|
||||
// }
|
||||
// search[0][search[1]].share_id = share_details.share_id;
|
||||
// search[0][search[1]].share_secret_key = share_details.secret_key;
|
||||
//
|
||||
// // update node in our displayed datastore
|
||||
// content.node.share_id = share_details.share_id;
|
||||
// content.node.share_secret_key = share_details.secret_key;
|
||||
//
|
||||
// var changed_paths = registrations["on_share_added"](share_details.share_id, item_path_copy, datastore, 1);
|
||||
//
|
||||
// var parent_path = item_path_copy2.slice();
|
||||
// parent_path.pop();
|
||||
//
|
||||
// changed_paths.push(parent_path);
|
||||
//
|
||||
// registrations["save_datastore_content"](datastore, changed_paths);
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// var modalInstance = $uibModal.open({
|
||||
// templateUrl: "view/modal/share-entry.html",
|
||||
// controller: "ModalShareEntryCtrl",
|
||||
// backdrop: "static",
|
||||
// resolve: {
|
||||
// node: function () {
|
||||
// return item;
|
||||
// },
|
||||
// path: function () {
|
||||
// return path;
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
//
|
||||
// // User clicked the final share button
|
||||
// modalInstance.result.then(on_modal_close_success, function () {
|
||||
// // cancel triggered
|
||||
// });
|
||||
// };
|
||||
};
|
||||
const onNewShare = (parent, path) => {
|
||||
// called whenever someone clicks on a new folder Icon
|
||||
setNewFolderOpen(true);
|
||||
setNewFolderData({
|
||||
parent: parent,
|
||||
path: path,
|
||||
});
|
||||
};
|
||||
|
||||
datastorePassword.modifyTreeForSearch(search, datastore);
|
||||
|
||||
return (
|
||||
<>
|
||||
{!datastore && (
|
||||
<div className={classes.loader}>
|
||||
<ClipLoader />
|
||||
</div>
|
||||
)}
|
||||
{datastore && <DatastoreTree datastore={datastore} search={search} onNewFolder={onNewFolder} onNewShare={onNewShare} />}
|
||||
{newFolderOpen && <DialogNewFolder open={newFolderOpen} onClose={() => setNewFolderOpen(false)} onCreate={onNewFolderCreate} />}
|
||||
{newShareOpen && <DialogNewShare open={newShareOpen} onClose={() => setNewShareOpen(false)} onShare={onNewShareCreate} />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
PasswordDatastore.propTypes = {
|
||||
search: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default PasswordDatastore;
|
@ -8,7 +8,6 @@ import HomeIcon from "@material-ui/icons/Home";
|
||||
import ShareIcon from "@material-ui/icons/Share";
|
||||
import PersonIcon from "@material-ui/icons/Person";
|
||||
import GroupIcon from "@material-ui/icons/Group";
|
||||
import AssignmentIcon from "@material-ui/icons/Assignment";
|
||||
import LinkIcon from "@material-ui/icons/Link";
|
||||
import List from "@material-ui/core/List";
|
||||
import ListItem from "@material-ui/core/ListItem";
|
||||
@ -23,6 +22,7 @@ import { Link } from "react-router-dom";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import RuleIcon from "../components/icons/Rule";
|
||||
import browserClient from "../services/browser-client";
|
||||
|
||||
const drawerWidth = 240;
|
||||
@ -76,7 +76,7 @@ const useStyles = makeStyles((theme) => ({
|
||||
listItemText: {
|
||||
fontSize: "14px",
|
||||
"& .MuiBadge-badge": {
|
||||
fontSize: "0.50rem",
|
||||
fontSize: "0.75rem",
|
||||
height: "15px",
|
||||
minWidth: "15px",
|
||||
color: "#fff",
|
||||
@ -86,11 +86,11 @@ const useStyles = makeStyles((theme) => ({
|
||||
},
|
||||
listItemIcon: {
|
||||
color: "#b1b6c1",
|
||||
minWidth: "36px",
|
||||
minWidth: theme.spacing(4),
|
||||
},
|
||||
listItemIconSelected: {
|
||||
color: "#fff",
|
||||
minWidth: "36px",
|
||||
minWidth: theme.spacing(4),
|
||||
},
|
||||
icon: {
|
||||
fontSize: "18px",
|
||||
@ -222,7 +222,7 @@ const Sidebar = (props) => {
|
||||
selected={isSelected(/^\/security-report$/)}
|
||||
>
|
||||
<ListItemIcon className={`${isSelected(/^\/security-report$/) ? classes.listItemIconSelected : classes.listItemIcon}`}>
|
||||
<AssignmentIcon className={classes.icon} />
|
||||
<RuleIcon className={classes.icon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
classes={{ primary: classes.listItemText }}
|
||||
|
@ -56,7 +56,7 @@ const useStyles = makeStyles((theme) => ({
|
||||
},
|
||||
},
|
||||
listItemIcon: {
|
||||
minWidth: "36px",
|
||||
minWidth: theme.spacing(4),
|
||||
},
|
||||
icon: {
|
||||
fontSize: "18px",
|
||||
|
@ -1,72 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import datastoreUser from "../services/datastore-user";
|
||||
import datastorePassword from "../services/datastore-password";
|
||||
import { ClipLoader } from "react-spinners";
|
||||
import DatastoreTree from "../components/datastore-tree";
|
||||
import widget from "../services/widget";
|
||||
import DialogNewFolder from "../components/dialogs/new-folder";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
loader: {
|
||||
marginTop: "30px",
|
||||
marginBottom: "30px",
|
||||
margin: "auto",
|
||||
},
|
||||
}));
|
||||
|
||||
const UserDatastore = (props) => {
|
||||
const classes = useStyles();
|
||||
const { search } = props;
|
||||
let isSubscribed = true;
|
||||
const [datastore, setDatastore] = useState(null);
|
||||
const [newFolderOpen, setNewFolderOpen] = useState(false);
|
||||
const [newFolderData, setNewFolderData] = useState({});
|
||||
|
||||
React.useEffect(() => {
|
||||
datastoreUser.getUserDatastore().then(onNewDatastoreLoaded);
|
||||
return () => (isSubscribed = false);
|
||||
}, []);
|
||||
|
||||
const onNewDatastoreLoaded = (data) => {
|
||||
if (!isSubscribed) {
|
||||
return;
|
||||
}
|
||||
setDatastore(data);
|
||||
};
|
||||
|
||||
const onNewFolderCreate = (name) => {
|
||||
// called once someone clicked the CREATE button in the dialog closes with the new name
|
||||
setNewFolderOpen(false);
|
||||
widget.openNewFolder(newFolderData["parent"], newFolderData["path"], datastore, datastorePassword, name);
|
||||
};
|
||||
const onNewFolder = (parent, path) => {
|
||||
// called whenever someone clicks on a new folder Icon
|
||||
setNewFolderOpen(true);
|
||||
setNewFolderData({
|
||||
parent: parent,
|
||||
path: path,
|
||||
});
|
||||
};
|
||||
|
||||
datastorePassword.modifyTreeForSearch(search, datastore);
|
||||
|
||||
return (
|
||||
<>
|
||||
{!datastore && (
|
||||
<div className={classes.loader}>
|
||||
<ClipLoader />
|
||||
</div>
|
||||
)}
|
||||
{datastore && <DatastoreTree datastore={datastore} search={search} onNewFolder={onNewFolder} />}
|
||||
{newFolderOpen && <DialogNewFolder open={newFolderOpen} onClose={() => setNewFolderOpen(false)} onCreate={onNewFolderCreate} />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
UserDatastore.propTypes = {
|
||||
search: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default UserDatastore;
|
@ -1,4 +1,12 @@
|
||||
import { LOGOUT, SET_CLIENT_URL, ENABLE_OFFLINE_MODE, DISABLE_OFFLINE_MODE, SET_NOTIFICATION_ON_COPY, SET_DISABLE_BROWSER_PM } from "../actions/action-types";
|
||||
import {
|
||||
LOGOUT,
|
||||
SET_CLIENT_URL,
|
||||
ENABLE_OFFLINE_MODE,
|
||||
DISABLE_OFFLINE_MODE,
|
||||
SET_NOTIFICATION_ON_COPY,
|
||||
SET_DISABLE_BROWSER_PM,
|
||||
SET_HIDE_DOWNLOAD_BANNER,
|
||||
} from "../actions/action-types";
|
||||
|
||||
const default_url = "";
|
||||
|
||||
@ -8,6 +16,7 @@ function client(
|
||||
offlineMode: false,
|
||||
notificationOnCopy: true,
|
||||
disableBrowserPm: true,
|
||||
hideDownloadBanner: false,
|
||||
},
|
||||
action
|
||||
) {
|
||||
@ -36,6 +45,10 @@ function client(
|
||||
return Object.assign({}, state, {
|
||||
disableBrowserPm: action.disableBrowserPm,
|
||||
});
|
||||
case SET_HIDE_DOWNLOAD_BANNER:
|
||||
return Object.assign({}, state, {
|
||||
hideDownloadBanner: action.hideDownloadBanner,
|
||||
});
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
import axios from "axios";
|
||||
import converterService from "./converter";
|
||||
|
||||
const call = function (fileserverUrl, method, endpoint, data, headers, transformRequest, responseType) {
|
||||
function call(fileserverUrl, method, endpoint, data, headers, transformRequest, responseType) {
|
||||
if (!transformRequest) {
|
||||
transformRequest = $http.defaults.transformRequest;
|
||||
}
|
||||
@ -31,7 +31,7 @@ const call = function (fileserverUrl, method, endpoint, data, headers, transform
|
||||
|
||||
axios(req).then(onSuccess, onError);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax PUT request to upload a file chunk to AWS S3
|
||||
@ -42,7 +42,7 @@ const call = function (fileserverUrl, method, endpoint, data, headers, transform
|
||||
*
|
||||
* @returns {Promise} promise
|
||||
*/
|
||||
const upload = function (signedUrl, fields, chunk) {
|
||||
function upload(signedUrl, fields, chunk) {
|
||||
const endpoint = ""; // the signed url already has everything
|
||||
const method = "POST";
|
||||
const data = new FormData();
|
||||
@ -58,7 +58,7 @@ const upload = function (signedUrl, fields, chunk) {
|
||||
};
|
||||
|
||||
return call(signedUrl, method, endpoint, data, headers, angular.identity);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax GET request to download a file chunk from AWS S3
|
||||
@ -67,7 +67,7 @@ const upload = function (signedUrl, fields, chunk) {
|
||||
*
|
||||
* @returns {Promise} promise with the data
|
||||
*/
|
||||
const download = function (signedUrl) {
|
||||
function download(signedUrl) {
|
||||
const endpoint = ""; // the signed url already has everything
|
||||
const method = "GET";
|
||||
const data = null;
|
||||
@ -82,14 +82,14 @@ const download = function (signedUrl) {
|
||||
if (data.status === 400) {
|
||||
data.data = JSON.parse(converterService.bytesToString(data.data));
|
||||
}
|
||||
return $q.reject(data);
|
||||
return Promise.reject(data);
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const service = {
|
||||
const apiAwsService = {
|
||||
upload: upload,
|
||||
download: download,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default apiAwsService;
|
||||
|
@ -5,14 +5,14 @@
|
||||
import axios from "axios";
|
||||
import converterService from "./converter";
|
||||
|
||||
function call(signed_url, method, endpoint, data, headers, transformRequest, responseType) {
|
||||
function call(signedUrl, method, endpoint, data, headers, transformRequest, responseType) {
|
||||
if (!transformRequest) {
|
||||
transformRequest = $http.defaults.transformRequest;
|
||||
}
|
||||
|
||||
const req = {
|
||||
method: method,
|
||||
url: signed_url + endpoint,
|
||||
url: signedUrl + endpoint,
|
||||
data: data,
|
||||
transformRequest: transformRequest,
|
||||
responseType: responseType,
|
||||
@ -36,38 +36,38 @@ function call(signed_url, method, endpoint, data, headers, transformRequest, res
|
||||
/**
|
||||
* Ajax PUT request to upload a file chunk to Azure Blob Storage
|
||||
*
|
||||
* @param {string} signed_url The signed ulr
|
||||
* @param {string} signedUrl The signed ulr
|
||||
* @param {Blob} chunk The content of the chunk to upload
|
||||
*
|
||||
* @returns {Promise} promise
|
||||
*/
|
||||
function upload(signed_url, chunk) {
|
||||
var endpoint = ""; // the signed url already has everything
|
||||
var method = "PUT";
|
||||
function upload(signedUrl, chunk) {
|
||||
const endpoint = ""; // the signed url already has everything
|
||||
const method = "PUT";
|
||||
|
||||
var headers = {
|
||||
const headers = {
|
||||
"x-ms-blob-type": "BlockBlob",
|
||||
"Content-Type": undefined,
|
||||
};
|
||||
|
||||
return call(signed_url, method, endpoint, chunk, headers, angular.identity);
|
||||
return call(signedUrl, method, endpoint, chunk, headers, angular.identity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax GET request to download a file chunk from Azure Blob Storage
|
||||
*
|
||||
* @param {string} signed_url The signed ulr
|
||||
* @param {string} signedUrl The signed ulr
|
||||
*
|
||||
* @returns {Promise} promise with the data
|
||||
*/
|
||||
function download(signed_url) {
|
||||
var endpoint = ""; // the signed url already has everything
|
||||
var method = "GET";
|
||||
var data = null;
|
||||
function download(signedUrl) {
|
||||
const endpoint = ""; // the signed url already has everything
|
||||
const method = "GET";
|
||||
const data = null;
|
||||
|
||||
var headers = {};
|
||||
const headers = {};
|
||||
|
||||
return call(signed_url, method, endpoint, data, headers, undefined, "arraybuffer").then(
|
||||
return call(signedUrl, method, endpoint, data, headers, undefined, "arraybuffer").then(
|
||||
function (data) {
|
||||
return data;
|
||||
},
|
||||
@ -75,14 +75,14 @@ function download(signed_url) {
|
||||
if (data.status === 400) {
|
||||
data.data = JSON.parse(converterService.bytesToString(data.data));
|
||||
}
|
||||
return $q.reject(data);
|
||||
return Promise.reject(data);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const apiAzureBlobService = {
|
||||
upload: upload,
|
||||
download: download,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default apiAzureBlobService;
|
||||
|
@ -5,14 +5,14 @@
|
||||
import axios from "axios";
|
||||
import converterService from "./converter";
|
||||
|
||||
function call(signed_url, method, endpoint, data, headers, transformRequest, responseType) {
|
||||
function call(signedUrl, method, endpoint, data, headers, transformRequest, responseType) {
|
||||
if (!transformRequest) {
|
||||
transformRequest = $http.defaults.transformRequest;
|
||||
}
|
||||
|
||||
const req = {
|
||||
method: method,
|
||||
url: signed_url + endpoint,
|
||||
url: signedUrl + endpoint,
|
||||
data: data,
|
||||
transformRequest: transformRequest,
|
||||
responseType: responseType,
|
||||
@ -36,16 +36,16 @@ function call(signed_url, method, endpoint, data, headers, transformRequest, res
|
||||
/**
|
||||
* Ajax PUT request to upload a file chunk to AWS S3
|
||||
*
|
||||
* @param {string} signed_url The signed ulr
|
||||
* @param {string} signedUrl The signed ulr
|
||||
* @param {object} fields Array of fields that need to be part of the request
|
||||
* @param {Blob} chunk The content of the chunk to upload
|
||||
*
|
||||
* @returns {Promise} promise
|
||||
*/
|
||||
function upload(signed_url, fields, chunk) {
|
||||
var endpoint = ""; // the signed url already has everything
|
||||
var method = "POST";
|
||||
var data = new FormData();
|
||||
function upload(signedUrl, fields, chunk) {
|
||||
const endpoint = ""; // the signed url already has everything
|
||||
const method = "POST";
|
||||
const data = new FormData();
|
||||
for (let field_name in fields) {
|
||||
if (!fields.hasOwnProperty(field_name)) {
|
||||
continue;
|
||||
@ -53,28 +53,28 @@ function upload(signed_url, fields, chunk) {
|
||||
data.append(field_name, fields[field_name]);
|
||||
}
|
||||
data.append("file", chunk);
|
||||
var headers = {
|
||||
const headers = {
|
||||
"Content-Type": undefined,
|
||||
};
|
||||
|
||||
return call(signed_url, method, endpoint, data, headers, angular.identity);
|
||||
return call(signedUrl, method, endpoint, data, headers, angular.identity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax GET request to download a file chunk from AWS S3
|
||||
*
|
||||
* @param {string} signed_url The signed ulr
|
||||
* @param {string} signedUrl The signed ulr
|
||||
*
|
||||
* @returns {Promise} promise with the data
|
||||
*/
|
||||
function download(signed_url) {
|
||||
var endpoint = ""; // the signed url already has everything
|
||||
var method = "GET";
|
||||
var data = null;
|
||||
function download(signedUrl) {
|
||||
const endpoint = ""; // the signed url already has everything
|
||||
const method = "GET";
|
||||
const data = null;
|
||||
|
||||
var headers = {};
|
||||
const headers = {};
|
||||
|
||||
return call(signed_url, method, endpoint, data, headers, undefined, "arraybuffer").then(
|
||||
return call(signedUrl, method, endpoint, data, headers, undefined, "arraybuffer").then(
|
||||
function (data) {
|
||||
return data;
|
||||
},
|
||||
@ -82,14 +82,14 @@ function download(signed_url) {
|
||||
if (data.status === 400) {
|
||||
data.data = JSON.parse(converterService.bytesToString(data.data));
|
||||
}
|
||||
return $q.reject(data);
|
||||
return Promise.reject(data);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const apiBackblazeService = {
|
||||
upload: upload,
|
||||
download: download,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default apiBackblazeService;
|
||||
|
@ -2964,7 +2964,7 @@ const sendSecurityReport = function (token, sessionSecretKey, entries, check_hav
|
||||
return call(method, endpoint, data, headers, sessionSecretKey);
|
||||
};
|
||||
|
||||
const service = {
|
||||
const apiClientService = {
|
||||
info: info,
|
||||
login: login,
|
||||
samlInitiateLogin: samlInitiateLogin,
|
||||
@ -3070,4 +3070,4 @@ const service = {
|
||||
sendSecurityReport: sendSecurityReport,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default apiClientService;
|
||||
|
@ -53,9 +53,9 @@ function call(signed_url, method, endpoint, data, headers, transformRequest, res
|
||||
*/
|
||||
function upload(signed_url, fields, chunk) {
|
||||
|
||||
var endpoint = ''; // the signed url already has everything
|
||||
var method = "POST";
|
||||
var data = new FormData();
|
||||
const endpoint = ''; // the signed url already has everything
|
||||
const method = "POST";
|
||||
const data = new FormData();
|
||||
for (let field_name in fields) {
|
||||
if (!fields.hasOwnProperty(field_name)) {
|
||||
continue;
|
||||
@ -63,12 +63,12 @@ function upload(signed_url, fields, chunk) {
|
||||
data.append(field_name, fields[field_name]);
|
||||
}
|
||||
data.append('file', chunk);
|
||||
var headers = {
|
||||
const headers = {
|
||||
'Content-Type': undefined
|
||||
};
|
||||
|
||||
return call(signed_url, method, endpoint, data, headers, angular.identity);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc
|
||||
@ -84,11 +84,11 @@ function upload(signed_url, fields, chunk) {
|
||||
*/
|
||||
function download(signed_url) {
|
||||
|
||||
var endpoint = ''; // the signed url already has everything
|
||||
var method = "GET";
|
||||
var data = null;
|
||||
const endpoint = ''; // the signed url already has everything
|
||||
const method = "GET";
|
||||
const data = null;
|
||||
|
||||
var headers = {
|
||||
const headers = {
|
||||
};
|
||||
|
||||
return call(signed_url, method, endpoint, data, headers, undefined, 'arraybuffer').then(function(data) {
|
||||
@ -97,14 +97,14 @@ function download(signed_url) {
|
||||
if (data.status === 400) {
|
||||
data.data = JSON.parse(converterService.bytesToString(data.data));
|
||||
}
|
||||
return $q.reject(data)
|
||||
return Promise.reject(data)
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
const service = {
|
||||
const apiDoService = {
|
||||
upload: upload,
|
||||
download: download
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default apiDoService;
|
@ -5,7 +5,7 @@
|
||||
import axios from "axios";
|
||||
import converterService from './converter';
|
||||
|
||||
function call(fileserver_url, method, endpoint, data, headers, transformRequest, responseType) {
|
||||
function call(fileserverUrl, method, endpoint, data, headers, transformRequest, responseType) {
|
||||
|
||||
if (!transformRequest) {
|
||||
transformRequest = $http.defaults.transformRequest;
|
||||
@ -13,7 +13,7 @@ function call(fileserver_url, method, endpoint, data, headers, transformRequest,
|
||||
|
||||
const req = {
|
||||
method: method,
|
||||
url: fileserver_url + endpoint,
|
||||
url: fileserverUrl + endpoint,
|
||||
data: data,
|
||||
transformRequest: transformRequest,
|
||||
responseType: responseType
|
||||
@ -40,84 +40,84 @@ function call(fileserver_url, method, endpoint, data, headers, transformRequest,
|
||||
/**
|
||||
* Ajax POST request to upload a file chunk
|
||||
*
|
||||
* @param {string} fileserver_url The url of the target fileserver
|
||||
* @param {string} file_transfer_id The file transfer id
|
||||
* @param {string} fileserverUrl The url of the target fileserver
|
||||
* @param {string} fileTransferId The file transfer id
|
||||
* @param {Blob} chunk The content of the chunk to upload
|
||||
* @param {string} ticket The ticket to authenticate the upload
|
||||
* @param {string} ticket_nonce The nonce of the ticket
|
||||
* @param {string} ticketNonce The nonce of the ticket
|
||||
*
|
||||
* @returns {Promise} promise
|
||||
*/
|
||||
function upload(fileserver_url, file_transfer_id, chunk, ticket, ticket_nonce) {
|
||||
function upload(fileserverUrl, fileTransferId, chunk, ticket, ticketNonce) {
|
||||
|
||||
var endpoint = '/upload/';
|
||||
var method = "POST";
|
||||
var data = new FormData();
|
||||
data.append('file_transfer_id', file_transfer_id);
|
||||
const endpoint = '/upload/';
|
||||
const method = "POST";
|
||||
const data = new FormData();
|
||||
data.append('file_transfer_id', fileTransferId);
|
||||
data.append('chunk', chunk);
|
||||
data.append('ticket', ticket);
|
||||
data.append('ticket_nonce', ticket_nonce);
|
||||
var headers = {
|
||||
data.append('ticket_nonce', ticketNonce);
|
||||
const headers = {
|
||||
'Content-Type': undefined
|
||||
};
|
||||
|
||||
return call(fileserver_url, method, endpoint, data, headers, angular.identity);
|
||||
};
|
||||
return call(fileserverUrl, method, endpoint, data, headers, angular.identity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax POST request to download a file chunk
|
||||
*
|
||||
* @param {string} fileserver_url The url of the target fileserver
|
||||
* @param {string} file_transfer_id The file transfer id
|
||||
* @param {string} fileserverUrl The url of the target fileserver
|
||||
* @param {string} fileTransferId The file transfer id
|
||||
* @param {string} ticket The ticket to authenticate the download
|
||||
* @param {string} ticket_nonce The nonce of the ticket
|
||||
* @param {string} ticketNonce The nonce of the ticket
|
||||
*
|
||||
* @returns {Promise} promise
|
||||
*/
|
||||
function download(fileserver_url, file_transfer_id, ticket, ticket_nonce) {
|
||||
function download(fileserverUrl, fileTransferId, ticket, ticketNonce) {
|
||||
|
||||
var endpoint = '/download/';
|
||||
var method = "POST";
|
||||
var data = {
|
||||
file_transfer_id: file_transfer_id,
|
||||
const endpoint = '/download/';
|
||||
const method = "POST";
|
||||
const data = {
|
||||
file_transfer_id: fileTransferId,
|
||||
ticket: ticket,
|
||||
ticket_nonce: ticket_nonce
|
||||
ticket_nonce: ticketNonce
|
||||
};
|
||||
|
||||
var headers = {
|
||||
const headers = {
|
||||
};
|
||||
|
||||
return call(fileserver_url, method, endpoint, data, headers, undefined, 'arraybuffer').then(function(data) {
|
||||
return call(fileserverUrl, method, endpoint, data, headers, undefined, 'arraybuffer').then(function(data) {
|
||||
return data
|
||||
},function(data) {
|
||||
if (data.status === 400) {
|
||||
data.data = JSON.parse(converterService.bytesToString(data.data));
|
||||
}
|
||||
return $q.reject(data)
|
||||
return Promise.reject(data)
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax GET request to get the server info
|
||||
*
|
||||
* @param {string} fileserver_url The url of the target fileserver
|
||||
* @param {string} fileserverUrl The url of the target fileserver
|
||||
*
|
||||
* @returns {Promise} promise
|
||||
*/
|
||||
var info = function (fileserver_url) {
|
||||
function info(fileserverUrl) {
|
||||
|
||||
var endpoint = '/info/';
|
||||
var method = "GET";
|
||||
var data = null;
|
||||
var headers = null;
|
||||
const endpoint = '/info/';
|
||||
const method = "GET";
|
||||
const data = null;
|
||||
const headers = null;
|
||||
|
||||
return call(fileserver_url, method, endpoint, data, headers);
|
||||
};
|
||||
return call(fileserverUrl, method, endpoint, data, headers);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const apiFileserverService = {
|
||||
info: info,
|
||||
upload: upload,
|
||||
download: download
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default apiFileserverService;
|
@ -36,37 +36,37 @@ function call(signed_url, method, endpoint, data, headers, transformRequest, res
|
||||
/**
|
||||
* Ajax PUT request to upload a file chunk to GCP storage
|
||||
*
|
||||
* @param {string} signed_url The signed ulr
|
||||
* @param {string} signedUrl The signed ulr
|
||||
* @param {Blob} chunk The content of the chunk to upload
|
||||
*
|
||||
* @returns {Promise} promise
|
||||
*/
|
||||
function upload(signed_url, chunk) {
|
||||
var endpoint = ""; // the signed url already has everything
|
||||
var method = "PUT";
|
||||
function upload(signedUrl, chunk) {
|
||||
const endpoint = ""; // the signed url already has everything
|
||||
const method = "PUT";
|
||||
|
||||
var headers = {
|
||||
const headers = {
|
||||
"Content-Type": "application/octet-stream",
|
||||
};
|
||||
|
||||
return call(signed_url, method, endpoint, chunk, headers, angular.identity);
|
||||
return call(signedUrl, method, endpoint, chunk, headers, angular.identity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax GET request to download a file chunk from GCP storage
|
||||
*
|
||||
* @param {string} signed_url The signed ulr
|
||||
* @param {string} signedUrl The signed ulr
|
||||
*
|
||||
* @returns {Promise} promise with the data
|
||||
*/
|
||||
function download(signed_url) {
|
||||
var endpoint = ""; // the signed url already has everything
|
||||
var method = "GET";
|
||||
var data = null;
|
||||
function download(signedUrl) {
|
||||
const endpoint = ""; // the signed url already has everything
|
||||
const method = "GET";
|
||||
const data = null;
|
||||
|
||||
var headers = {};
|
||||
const headers = {};
|
||||
|
||||
return call(signed_url, method, endpoint, data, headers, undefined, "arraybuffer").then(
|
||||
return call(signedUrl, method, endpoint, data, headers, undefined, "arraybuffer").then(
|
||||
function (data) {
|
||||
return data;
|
||||
},
|
||||
@ -79,9 +79,9 @@ function download(signed_url) {
|
||||
);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const apiGcpService = {
|
||||
upload: upload,
|
||||
download: download,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default apiGcpService;
|
||||
|
@ -140,19 +140,19 @@ function createApiKey(title, restrictToSecrets, allowInsecureAccess, allowReadAc
|
||||
const token = store.getState().user.token;
|
||||
const sessionSecretKey = store.getState().user.sessionSecretKey;
|
||||
|
||||
var apiKeySecretKey = cryptoLibrary.generateSecretKey();
|
||||
var api_key_public_private_key_pair = cryptoLibrary.generatePublicPrivateKeypair();
|
||||
const apiKeySecretKey = cryptoLibrary.generateSecretKey();
|
||||
const api_key_public_private_key_pair = cryptoLibrary.generatePublicPrivateKeypair();
|
||||
|
||||
var api_key_private_key_enc = cryptoLibrary.encryptSecretKey(api_key_public_private_key_pair.private_key);
|
||||
var apiKeySecretKey_enc = cryptoLibrary.encryptSecretKey(apiKeySecretKey);
|
||||
const api_key_private_key_enc = cryptoLibrary.encryptSecretKey(api_key_public_private_key_pair.private_key);
|
||||
const apiKeySecretKey_enc = cryptoLibrary.encryptSecretKey(apiKeySecretKey);
|
||||
|
||||
var user_private_key_enc = cryptoLibrary.encryptData(store.getState().user.userPrivateKey, apiKeySecretKey);
|
||||
var user_secret_key_enc = cryptoLibrary.encryptData(store.getState().user.userSecretKey, apiKeySecretKey);
|
||||
const user_private_key_enc = cryptoLibrary.encryptData(store.getState().user.userPrivateKey, apiKeySecretKey);
|
||||
const user_secret_key_enc = cryptoLibrary.encryptData(store.getState().user.userSecretKey, apiKeySecretKey);
|
||||
|
||||
var verify_key = cryptoLibrary.getVerifyKey(api_key_public_private_key_pair.private_key);
|
||||
const verify_key = cryptoLibrary.getVerifyKey(api_key_public_private_key_pair.private_key);
|
||||
|
||||
const onSuccess = function (result) {
|
||||
var apiKeyId = result.data["api_key_id"];
|
||||
const apiKeyId = result.data["api_key_id"];
|
||||
return addSecretsToApiKey(apiKeyId, apiKeySecretKey, secrets).then(function () {
|
||||
return {
|
||||
api_key_id: apiKeyId,
|
||||
@ -266,7 +266,7 @@ function getServerParameter() {
|
||||
};
|
||||
}
|
||||
|
||||
const service = {
|
||||
const apiKeysService = {
|
||||
readApiKey: readApiKey,
|
||||
readApiKeys: readApiKeys,
|
||||
readApiKeySecrets: readApiKeySecrets,
|
||||
@ -279,4 +279,4 @@ const service = {
|
||||
apiKeysDisabled: apiKeysDisabled,
|
||||
getServerParameter: getServerParameter,
|
||||
};
|
||||
export default service;
|
||||
export default apiKeysService;
|
||||
|
@ -43,9 +43,9 @@ function call(signed_url, method, endpoint, data, headers, transformRequest, res
|
||||
* @returns {Promise} promise
|
||||
*/
|
||||
function upload(signed_url, fields, chunk) {
|
||||
var endpoint = ""; // the signed url already has everything
|
||||
var method = "POST";
|
||||
var data = new FormData();
|
||||
const endpoint = ""; // the signed url already has everything
|
||||
const method = "POST";
|
||||
const data = new FormData();
|
||||
for (let field_name in fields) {
|
||||
if (!fields.hasOwnProperty(field_name)) {
|
||||
continue;
|
||||
@ -53,7 +53,7 @@ function upload(signed_url, fields, chunk) {
|
||||
data.append(field_name, fields[field_name]);
|
||||
}
|
||||
data.append("file", chunk);
|
||||
var headers = {
|
||||
const headers = {
|
||||
"Content-Type": undefined,
|
||||
};
|
||||
|
||||
@ -68,11 +68,11 @@ function upload(signed_url, fields, chunk) {
|
||||
* @returns {Promise} promise with the data
|
||||
*/
|
||||
function download(signed_url) {
|
||||
var endpoint = ""; // the signed url already has everything
|
||||
var method = "GET";
|
||||
var data = null;
|
||||
const endpoint = ""; // the signed url already has everything
|
||||
const method = "GET";
|
||||
const data = null;
|
||||
|
||||
var headers = {};
|
||||
const headers = {};
|
||||
|
||||
return call(signed_url, method, endpoint, data, headers, undefined, "arraybuffer").then(
|
||||
function (data) {
|
||||
@ -82,14 +82,14 @@ function download(signed_url) {
|
||||
if (data.status === 400) {
|
||||
data.data = JSON.parse(converterService.bytesToString(data.data));
|
||||
}
|
||||
return $q.reject(data);
|
||||
return Promise.reject(data);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const apiOtherS3Service = {
|
||||
upload: upload,
|
||||
download: download,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default apiOtherS3Service;
|
||||
|
@ -54,8 +54,8 @@ function range(hash_chars) {
|
||||
}
|
||||
|
||||
|
||||
const service = {
|
||||
const apiPwnedpasswordsService = {
|
||||
range: range
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default apiPwnedpasswordsService;
|
@ -338,10 +338,12 @@ function loadConfig() {
|
||||
|
||||
if (newConfig.hasOwnProperty("backend_servers")) {
|
||||
for (let i = 0; i < newConfig["backend_servers"].length; i++) {
|
||||
if (newConfig["backend_servers"][i].hasOwnProperty("url")) {
|
||||
continue;
|
||||
if (!newConfig["backend_servers"][i].hasOwnProperty("url")) {
|
||||
newConfig["backend_servers"][i]["url"] = parsed_url["base_url"] + "/server";
|
||||
}
|
||||
if (!newConfig["backend_servers"][i].hasOwnProperty("domain")) {
|
||||
newConfig["backend_servers"][i]["domain"] = helperService.getDomain(newConfig["backend_servers"][i]["url"]);
|
||||
}
|
||||
newConfig["backend_servers"][i]["url"] = parsed_url["base_url"] + "/server";
|
||||
}
|
||||
}
|
||||
|
||||
@ -777,7 +779,7 @@ function getOfflineCacheEncryptionKey(fnc) {
|
||||
}
|
||||
}
|
||||
|
||||
const service = {
|
||||
const browserClientService = {
|
||||
registerAuthRequiredListener: registerAuthRequiredListener,
|
||||
getClientType: getClientType,
|
||||
openTab: openTab,
|
||||
@ -806,4 +808,4 @@ const service = {
|
||||
getOfflineCacheEncryptionKey: getOfflineCacheEncryptionKey,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default browserClientService;
|
||||
|
@ -413,7 +413,7 @@ function bytesToString(srcBytes, encoding) {
|
||||
return new TextDecoder(tmp_encoding).decode(srcBytes);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const converterService = {
|
||||
// Conversion functions
|
||||
encodeUtf8: encodeUtf8,
|
||||
encodeLatin1: encodeLatin1,
|
||||
@ -434,4 +434,4 @@ const service = {
|
||||
bytesToString: bytesToString,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default converterService;
|
||||
|
@ -565,7 +565,7 @@ function decryptSecretKey(text, nonce) {
|
||||
return decryptData(text, nonce, store.getState().user.userSecretKey);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const cryptoLibraryService = {
|
||||
random: random,
|
||||
randomBytes: randomBytes,
|
||||
sha1: sha1,
|
||||
@ -597,4 +597,4 @@ const service = {
|
||||
decryptSecretKey: decryptSecretKey,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default cryptoLibraryService;
|
||||
|
@ -22,10 +22,10 @@ describe('Service: cryptoLibraryService test suite #2', function() {
|
||||
|
||||
/*
|
||||
it("randomBytes doesn't return the the same in 1000 repetitions", function () {
|
||||
var num, numbers, random_numbers;
|
||||
let num, numbers, random_numbers;
|
||||
numbers = 1000;
|
||||
random_numbers = (function () {
|
||||
var i, ref, results;
|
||||
let i, ref, results;
|
||||
results = [];
|
||||
for (num = i = 1, ref = numbers; 1 <= ref ? i <= ref : i >= ref; num = 1 <= ref ? ++i : --i) {
|
||||
results.push(cryptoLibraryService.randomBytes(32));
|
||||
|
@ -565,6 +565,7 @@ function saveDatastoreContent(datastore, paths) {
|
||||
}
|
||||
}
|
||||
|
||||
const promises = [];
|
||||
for (let prop in closest_shares) {
|
||||
if (!closest_shares.hasOwnProperty(prop)) {
|
||||
continue;
|
||||
@ -574,7 +575,7 @@ function saveDatastoreContent(datastore, paths) {
|
||||
hideSubShareContent(duplicate);
|
||||
|
||||
if (prop === "datastore") {
|
||||
datastoreService.saveDatastoreContent(type, description, duplicate);
|
||||
promises.push(datastoreService.saveDatastoreContent(type, description, duplicate));
|
||||
} else {
|
||||
const share_id = duplicate.share_id;
|
||||
const secret_key = duplicate.share_secret_key;
|
||||
@ -583,9 +584,11 @@ function saveDatastoreContent(datastore, paths) {
|
||||
delete duplicate.secret_key;
|
||||
delete duplicate.share_rights;
|
||||
|
||||
shareService.writeShare(share_id, duplicate, secret_key);
|
||||
promises.push(shareService.writeShare(share_id, duplicate, secret_key));
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1262,7 +1265,7 @@ function analyzeBreadcrumbs(breadcrumbs, datastore) {
|
||||
let parent_share_id;
|
||||
let parent_datastore_id;
|
||||
|
||||
if (typeof breadcrumbs.id_breadcrumbs !== "undefined") {
|
||||
if (typeof breadcrumbs.id_breadcrumbs !== "undefined" && breadcrumbs.id_breadcrumbs.length > 0) {
|
||||
path = breadcrumbs.id_breadcrumbs.slice();
|
||||
const path_copy = breadcrumbs.id_breadcrumbs.slice();
|
||||
parent_path = breadcrumbs.id_breadcrumbs.slice();
|
||||
@ -1509,7 +1512,7 @@ function getAllOwnPgpKeys() {
|
||||
};
|
||||
|
||||
for (let i = 0; i < own_pgp_secrets.length; i++) {
|
||||
secretService.read_secret(own_pgp_secrets[i].secret_id, own_pgp_secrets[i].secret_key).then(onSuccess, onError);
|
||||
secretService.readSecret(own_pgp_secrets[i].secret_id, own_pgp_secrets[i].secret_key).then(onSuccess, onError);
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -1523,7 +1526,7 @@ function getAllOwnPgpKeys() {
|
||||
shareService.register("get_all_child_shares", getAllChildShares);
|
||||
settingsService.register("get_password_datastore", getPasswordDatastore);
|
||||
|
||||
const service = {
|
||||
const datastorePasswordService = {
|
||||
generate: generate,
|
||||
getPasswordDatastore: getPasswordDatastore,
|
||||
getDatastoreWithId: getDatastoreWithId,
|
||||
@ -1553,4 +1556,4 @@ const service = {
|
||||
updatePathsRecursive: updatePathsRecursive,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default datastorePasswordService;
|
||||
|
@ -41,8 +41,8 @@ function saveSettingsDatastore(content) {
|
||||
return datastore.saveDatastoreContent(type, description, content);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const datastoreSettingService = {
|
||||
getSettingsDatastore: getSettingsDatastore,
|
||||
saveSettingsDatastore: saveSettingsDatastore,
|
||||
};
|
||||
export default service;
|
||||
export default datastoreSettingService;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -599,7 +599,7 @@ function onLogout() {
|
||||
|
||||
browserClient.on("logout", onLogout);
|
||||
|
||||
const service = {
|
||||
const datastoreService = {
|
||||
getDatastoreOverview: getDatastoreOverview,
|
||||
getDatastoreId: getDatastoreId,
|
||||
getDatastoreWithId: getDatastoreWithId,
|
||||
@ -618,4 +618,4 @@ const service = {
|
||||
filterDatastoreContent: filterDatastoreContent,
|
||||
register: register,
|
||||
};
|
||||
export default service;
|
||||
export default datastoreService;
|
||||
|
@ -105,7 +105,7 @@ function isOpera() {
|
||||
* @returns {string} Returns the device's description
|
||||
*/
|
||||
function getDeviceDescription() {
|
||||
var description = "";
|
||||
let description = "";
|
||||
if (typeof clientJs.getDeviceVendor() !== "undefined") {
|
||||
description = description + clientJs.getDeviceVendor() + " ";
|
||||
}
|
||||
@ -127,7 +127,7 @@ function getDeviceDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
const service = {
|
||||
const deviceService = {
|
||||
getDeviceFingerprint: getDeviceFingerprint,
|
||||
isMobileAndroid: isMobileAndroid,
|
||||
isMobileIos: isMobileIos,
|
||||
@ -139,4 +139,4 @@ const service = {
|
||||
isOpera: isOpera,
|
||||
getDeviceDescription: getDeviceDescription,
|
||||
};
|
||||
export default service;
|
||||
export default deviceService;
|
||||
|
@ -89,11 +89,11 @@ function deleteDuo(duoId) {
|
||||
return apiClient.deleteDuo(token, sessionSecretKey, duoId).then(onSuccess, onError);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const duoService = {
|
||||
createDuo,
|
||||
readDuo,
|
||||
activateDuo,
|
||||
deleteDuo,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default duoService;
|
||||
|
@ -83,10 +83,10 @@ function deleteEmergencyCode(emergencyCodeId) {
|
||||
return apiClient.deleteEmergencyCode(token, sessionSecretKey, emergencyCodeId).then(onSuccess, onError);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const emergencyCodeService = {
|
||||
readEmergencyCodes,
|
||||
createEmergencyCode,
|
||||
deleteEmergencyCode,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default emergencyCodeService;
|
||||
|
@ -472,7 +472,7 @@ function getDoSpacesRegions() {
|
||||
return doSpacesRegions;
|
||||
}
|
||||
|
||||
const service = {
|
||||
const fileRepositoryService = {
|
||||
accept: accept,
|
||||
decline: decline,
|
||||
createFileRepositoryRight: createFileRepositoryRight,
|
||||
@ -489,4 +489,4 @@ const service = {
|
||||
getAwsRegions: getAwsRegions,
|
||||
getDoSpacesRegions: getDoSpacesRegions,
|
||||
};
|
||||
export default service;
|
||||
export default fileRepositoryService;
|
||||
|
@ -718,7 +718,7 @@ function register(key, func) {
|
||||
registrations[key] = func;
|
||||
}
|
||||
|
||||
const service = {
|
||||
const fileTransferService = {
|
||||
readFile: readFile,
|
||||
createFile: createFile,
|
||||
upload: upload,
|
||||
@ -729,4 +729,4 @@ const service = {
|
||||
downloadFile: downloadFile,
|
||||
register: register,
|
||||
};
|
||||
export default service;
|
||||
export default fileTransferService;
|
||||
|
@ -90,11 +90,11 @@ function deleteGa(googleAuthenticatorId) {
|
||||
return apiClientService.deleteGa(token, sessionSecretKey, googleAuthenticatorId).then(onSuccess, onError);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const googleAuthenticatorService = {
|
||||
createGa,
|
||||
readGa,
|
||||
activateGa,
|
||||
deleteGa,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default googleAuthenticatorService;
|
||||
|
@ -511,7 +511,7 @@ function declineMembership(c) {
|
||||
|
||||
//itemBlueprint.register('getGroupSecretKey', getGroupSecretKey);
|
||||
|
||||
const service = {
|
||||
const groupsService = {
|
||||
getGroupSecretKey: getGroupSecretKey,
|
||||
getGroupPrivateKey: getGroupPrivateKey,
|
||||
decryptSecretKey: decryptSecretKey,
|
||||
@ -530,4 +530,4 @@ const service = {
|
||||
acceptMembership: acceptMembership,
|
||||
declineMembership: declineMembership,
|
||||
};
|
||||
export default service;
|
||||
export default groupsService;
|
||||
|
@ -523,7 +523,7 @@ function getPasswordFilter(test) {
|
||||
return filter;
|
||||
}
|
||||
|
||||
const service = {
|
||||
const helperService = {
|
||||
parseUrl: parseUrl,
|
||||
isValidUrl: isValidUrl,
|
||||
isValidJson: isValidJson,
|
||||
@ -543,4 +543,4 @@ const service = {
|
||||
getPasswordFilter: getPasswordFilter,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default helperService;
|
||||
|
@ -236,7 +236,7 @@ function deleteKnownHost(fingerprint) {
|
||||
updateKnownHosts(known_hosts);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const hostService = {
|
||||
getKnownHosts: getKnownHosts,
|
||||
getCurrentHost: getCurrentHost,
|
||||
getCurrentHostUrl: getCurrentHostUrl,
|
||||
@ -249,4 +249,4 @@ const service = {
|
||||
updateKnownHosts: updateKnownHosts,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default hostService;
|
||||
|
@ -22,7 +22,7 @@ let INDEX_TYPE = 5;
|
||||
*/
|
||||
function identifyRows(line) {
|
||||
for (let i = 0; i < line.length; i++) {
|
||||
var column_description = line[i].toLowerCase();
|
||||
const column_description = line[i].toLowerCase();
|
||||
if (column_description === "notes") {
|
||||
INDEX_NOTES = i;
|
||||
} else if(column_description === "password") {
|
||||
@ -55,7 +55,7 @@ function identifyRows(line) {
|
||||
* @returns {string} Returns the appropriate type (note or website_password)
|
||||
*/
|
||||
function getType(line) {
|
||||
var type = line[INDEX_TYPE].toLowerCase();
|
||||
const type = line[INDEX_TYPE].toLowerCase();
|
||||
if (type === 'secure note') {
|
||||
return 'note'
|
||||
}
|
||||
@ -89,7 +89,7 @@ function getType(line) {
|
||||
*/
|
||||
function transferIntoNote(line) {
|
||||
|
||||
var note_notes = '';
|
||||
let note_notes = '';
|
||||
if (line[INDEX_USERNAME]) {
|
||||
note_notes = note_notes + line[INDEX_USERNAME] + "\n";
|
||||
}
|
||||
@ -125,7 +125,7 @@ function transferIntoNote(line) {
|
||||
*/
|
||||
function transferIntoWebsitePassword(line) {
|
||||
|
||||
var parsed_url = helperService.parseUrl(line[INDEX_URL]);
|
||||
const parsed_url = helperService.parseUrl(line[INDEX_URL]);
|
||||
|
||||
return {
|
||||
id : cryptoLibrary.generateUuid(),
|
||||
@ -169,7 +169,7 @@ function transferIntoApplicationPassword(line) {
|
||||
* @returns {*} The secrets object
|
||||
*/
|
||||
function transformToSecret(line) {
|
||||
var type = getType(line);
|
||||
const type = getType(line);
|
||||
if (type === 'note') {
|
||||
return transferIntoNote(line);
|
||||
} else if (type === 'website_password') {
|
||||
@ -189,7 +189,7 @@ function transformToSecret(line) {
|
||||
*/
|
||||
function gather_secrets(datastore, secrets, csv) {
|
||||
|
||||
var line;
|
||||
let line;
|
||||
|
||||
for (let i = 0; i < csv.length; i++) {
|
||||
line = csv[i];
|
||||
@ -203,7 +203,7 @@ function gather_secrets(datastore, secrets, csv) {
|
||||
continue
|
||||
}
|
||||
|
||||
var secret = transformToSecret(line);
|
||||
const secret = transformToSecret(line);
|
||||
|
||||
if (secret === null) {
|
||||
//empty line
|
||||
@ -221,7 +221,7 @@ function gather_secrets(datastore, secrets, csv) {
|
||||
* @returns {Array} The array of arrays representing the CSV
|
||||
*/
|
||||
function parse_csv(data) {
|
||||
var csv = Papa.parse(data);
|
||||
const csv = Papa.parse(data);
|
||||
|
||||
if (csv['errors'].length > 0) {
|
||||
throw new Error(csv['errors'][0]['message']);
|
||||
@ -246,18 +246,19 @@ function parse_csv(data) {
|
||||
*/
|
||||
function parser(data) {
|
||||
|
||||
var d = new Date();
|
||||
var n = d.toISOString();
|
||||
const d = new Date();
|
||||
const n = d.toISOString();
|
||||
|
||||
var secrets = [];
|
||||
var datastore = {
|
||||
const secrets = [];
|
||||
const datastore = {
|
||||
'id': cryptoLibrary.generateUuid(),
|
||||
'name': 'Import ' + n,
|
||||
'items': []
|
||||
};
|
||||
|
||||
let csv;
|
||||
try {
|
||||
var csv = parse_csv(data);
|
||||
csv = parse_csv(data);
|
||||
} catch(err) {
|
||||
return null;
|
||||
}
|
||||
@ -270,8 +271,8 @@ function parser(data) {
|
||||
}
|
||||
}
|
||||
|
||||
const service = {
|
||||
const import1passwordCsvService = {
|
||||
parser,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default import1passwordCsvService;
|
||||
|
@ -18,8 +18,8 @@ const INDEX_PASSWORD = 3;
|
||||
*
|
||||
* @returns {*} The secrets object
|
||||
*/
|
||||
var transform_to_secret = function (line) {
|
||||
var parsed_url = helperService.parseUrl(line[INDEX_URL]);
|
||||
function transformToSecret(line) {
|
||||
const parsed_url = helperService.parseUrl(line[INDEX_URL]);
|
||||
|
||||
return {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
@ -33,7 +33,7 @@ var transform_to_secret = function (line) {
|
||||
website_password_url: line[INDEX_URL],
|
||||
website_password_title: line[INDEX_NAME],
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the datastore with their content, together with the secrets object
|
||||
@ -42,8 +42,8 @@ var transform_to_secret = function (line) {
|
||||
* @param {[]} secrets The array containing all the found secrets
|
||||
* @param {[]} csv The array containing all the found secrets
|
||||
*/
|
||||
function gather_secrets(datastore, secrets, csv) {
|
||||
var line;
|
||||
function gatherSecrets(datastore, secrets, csv) {
|
||||
let line;
|
||||
for (let i = 0; i < csv.length; i++) {
|
||||
line = csv[i];
|
||||
if (i === 0) {
|
||||
@ -53,7 +53,7 @@ function gather_secrets(datastore, secrets, csv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var secret = transform_to_secret(line);
|
||||
const secret = transformToSecret(line);
|
||||
if (secret === null) {
|
||||
//empty line
|
||||
continue;
|
||||
@ -69,8 +69,8 @@ function gather_secrets(datastore, secrets, csv) {
|
||||
* @param {string} data The raw data to parse
|
||||
* @returns {Array} The array of arrays representing the CSV
|
||||
*/
|
||||
function parse_csv(data) {
|
||||
var csv = Papa.parse(data);
|
||||
function parseCsv(data) {
|
||||
const csv = Papa.parse(data);
|
||||
|
||||
if (csv["errors"].length > 0) {
|
||||
throw new Error(csv["errors"][0]["message"]);
|
||||
@ -94,24 +94,25 @@ function parse_csv(data) {
|
||||
* @returns {{datastore, secrets: Array} | null}
|
||||
*/
|
||||
function parser(data) {
|
||||
var d = new Date();
|
||||
var n = d.toISOString();
|
||||
const d = new Date();
|
||||
const n = d.toISOString();
|
||||
|
||||
var secrets = [];
|
||||
var datastore = {
|
||||
const secrets = [];
|
||||
const datastore = {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
name: "Import " + n,
|
||||
folders: [],
|
||||
items: [],
|
||||
};
|
||||
|
||||
let csv;
|
||||
try {
|
||||
var csv = parse_csv(data);
|
||||
csv = parseCsv(data);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
|
||||
gather_secrets(datastore, secrets, csv);
|
||||
gatherSecrets(datastore, secrets, csv);
|
||||
|
||||
return {
|
||||
datastore: datastore,
|
||||
@ -119,8 +120,8 @@ function parser(data) {
|
||||
};
|
||||
}
|
||||
|
||||
const service = {
|
||||
const importChromeCsvService = {
|
||||
parser,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default importChromeCsvService;
|
||||
|
@ -46,8 +46,8 @@ function detect_type(item) {
|
||||
*
|
||||
* @param {object} item The item to analyze
|
||||
*/
|
||||
function contains_totp(item) {
|
||||
var contains_totp_field = false;
|
||||
function containsTotp(item) {
|
||||
let contains_totp_field = false;
|
||||
if (item.hasOwnProperty("fields")) {
|
||||
for (let i = 0; i < item["fields"].length; i++) {
|
||||
if (item["fields"][i]["type"] === "totp" && item["fields"][i]["value"] !== "") {
|
||||
@ -65,15 +65,15 @@ function contains_totp(item) {
|
||||
*
|
||||
* @returns {*} The secrets object
|
||||
*/
|
||||
var transform_to_website_password = function (item) {
|
||||
var name = "";
|
||||
var urlfilter = "";
|
||||
var website_password_url_filter = "";
|
||||
var website_password_password = "";
|
||||
var website_password_username = "";
|
||||
var website_password_notes = "";
|
||||
var website_password_url = "";
|
||||
var website_password_title = "";
|
||||
function transformToWebsitePassword(item) {
|
||||
let name = "";
|
||||
let urlfilter = "";
|
||||
let website_password_url_filter = "";
|
||||
let website_password_password = "";
|
||||
let website_password_username = "";
|
||||
let website_password_notes = "";
|
||||
let website_password_url = "";
|
||||
let website_password_title = "";
|
||||
|
||||
if (item.hasOwnProperty("title")) {
|
||||
name = item["title"];
|
||||
@ -114,7 +114,7 @@ var transform_to_website_password = function (item) {
|
||||
website_password_url: website_password_url,
|
||||
website_password_title: website_password_title,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an item and transforms it into a application password entry
|
||||
@ -123,12 +123,12 @@ var transform_to_website_password = function (item) {
|
||||
*
|
||||
* @returns {*} The secrets object
|
||||
*/
|
||||
var transform_to_application_password = function (item) {
|
||||
var name = "";
|
||||
var application_password_password = "";
|
||||
var application_password_username = "";
|
||||
var application_password_notes = "";
|
||||
var application_password_title = "";
|
||||
function transformToApplicationPassword(item) {
|
||||
let name = "";
|
||||
let application_password_password = "";
|
||||
let application_password_username = "";
|
||||
let application_password_notes = "";
|
||||
let application_password_title = "";
|
||||
|
||||
if (item.hasOwnProperty("title")) {
|
||||
name = item["title"];
|
||||
@ -164,7 +164,7 @@ var transform_to_application_password = function (item) {
|
||||
application_password_notes: application_password_notes,
|
||||
application_password_title: application_password_title,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an item and transforms it into a bookmark entry
|
||||
@ -173,13 +173,13 @@ var transform_to_application_password = function (item) {
|
||||
*
|
||||
* @returns {*} The secrets object
|
||||
*/
|
||||
var transform_to_bookmark = function (item) {
|
||||
var name = "";
|
||||
var urlfilter = "";
|
||||
var bookmark_url_filter = "";
|
||||
var bookmark_notes = "";
|
||||
var bookmark_url = "";
|
||||
var bookmark_title = "";
|
||||
function transformToBookmark(item) {
|
||||
let name = "";
|
||||
let urlfilter = "";
|
||||
let bookmark_url_filter = "";
|
||||
let bookmark_notes = "";
|
||||
let bookmark_url = "";
|
||||
let bookmark_title = "";
|
||||
|
||||
if (item.hasOwnProperty("title")) {
|
||||
name = item["title"];
|
||||
@ -214,7 +214,7 @@ var transform_to_bookmark = function (item) {
|
||||
bookmark_url: bookmark_url,
|
||||
bookmark_title: bookmark_title,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an item and transforms it into a note
|
||||
@ -223,10 +223,10 @@ var transform_to_bookmark = function (item) {
|
||||
*
|
||||
* @returns {*} The secrets object
|
||||
*/
|
||||
var transform_to_note = function (item) {
|
||||
var name = "";
|
||||
var note_notes = "";
|
||||
var note_title = "";
|
||||
function transformToNote(item) {
|
||||
let name = "";
|
||||
let note_notes = "";
|
||||
let note_title = "";
|
||||
|
||||
if (item.hasOwnProperty("title")) {
|
||||
name = item["title"];
|
||||
@ -256,7 +256,7 @@ var transform_to_note = function (item) {
|
||||
note_notes: note_notes,
|
||||
note_title: note_title,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an item and transforms it into a note
|
||||
@ -265,11 +265,11 @@ var transform_to_note = function (item) {
|
||||
*
|
||||
* @returns {*} The secrets object
|
||||
*/
|
||||
var transform_to_totp_code = function (item) {
|
||||
var name = "";
|
||||
var totp_notes = "";
|
||||
var totp_code = "";
|
||||
var totp_title = "";
|
||||
function transformToTotpCode(item) {
|
||||
let name = "";
|
||||
let totp_notes = "";
|
||||
let totp_code = "";
|
||||
let totp_title = "";
|
||||
|
||||
if (item.hasOwnProperty("title")) {
|
||||
name = item["title"];
|
||||
@ -300,7 +300,7 @@ var transform_to_totp_code = function (item) {
|
||||
totp_code: totp_code,
|
||||
totp_title: totp_title,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches a given parsedData recursive and puts them all into the provided secrets array
|
||||
@ -309,9 +309,9 @@ var transform_to_totp_code = function (item) {
|
||||
* @param {[]} secrets The array containing all the found secrets
|
||||
* @param {object} parsedData The objects
|
||||
*/
|
||||
function gather_secrets(datastore, secrets, parsedData) {
|
||||
var i;
|
||||
var folder_index = {};
|
||||
function gatherSecrets(datastore, secrets, parsedData) {
|
||||
let i;
|
||||
const folder_index = {};
|
||||
|
||||
if (parsedData.hasOwnProperty("folders")) {
|
||||
for (i = 0; i < parsedData["folders"].length; i++) {
|
||||
@ -325,26 +325,26 @@ function gather_secrets(datastore, secrets, parsedData) {
|
||||
|
||||
if (parsedData.hasOwnProperty("items")) {
|
||||
for (i = 0; i < parsedData["items"].length; i++) {
|
||||
var detected_type = detect_type(parsedData["items"][i]);
|
||||
var contains_totp_code = contains_totp(parsedData["items"][i]);
|
||||
const detected_type = detect_type(parsedData["items"][i]);
|
||||
const contains_totp_code = containsTotp(parsedData["items"][i]);
|
||||
|
||||
var crafted_secrets = [];
|
||||
const crafted_secrets = [];
|
||||
|
||||
if (detected_type === "website_password") {
|
||||
crafted_secrets.push(transform_to_website_password(parsedData["items"][i]));
|
||||
crafted_secrets.push(transformToWebsitePassword(parsedData["items"][i]));
|
||||
} else if (detected_type === "application_password") {
|
||||
crafted_secrets.push(transform_to_application_password(parsedData["items"][i]));
|
||||
crafted_secrets.push(transformToApplicationPassword(parsedData["items"][i]));
|
||||
} else if (detected_type === "bookmark") {
|
||||
crafted_secrets.push(transform_to_bookmark(parsedData["items"][i]));
|
||||
crafted_secrets.push(transformToBookmark(parsedData["items"][i]));
|
||||
} else {
|
||||
crafted_secrets.push(transform_to_note(parsedData["items"][i]));
|
||||
crafted_secrets.push(transformToNote(parsedData["items"][i]));
|
||||
}
|
||||
|
||||
if (contains_totp_code) {
|
||||
crafted_secrets.push(transform_to_totp_code(parsedData["items"][i]));
|
||||
crafted_secrets.push(transformToTotpCode(parsedData["items"][i]));
|
||||
}
|
||||
|
||||
var parent_folder = null;
|
||||
let parent_folder = null;
|
||||
if (parsedData["items"][i].hasOwnProperty("folders")) {
|
||||
for (let ii = 0; ii < parsedData["items"][i]["folders"].length; ii++) {
|
||||
if (folder_index.hasOwnProperty(parsedData["items"][i]["folders"][ii])) {
|
||||
@ -384,24 +384,25 @@ function gather_secrets(datastore, secrets, parsedData) {
|
||||
* @returns {{datastore, secrets: Array} | null}
|
||||
*/
|
||||
function parser(data) {
|
||||
var d = new Date();
|
||||
var n = d.toISOString();
|
||||
const d = new Date();
|
||||
const n = d.toISOString();
|
||||
|
||||
var secrets = [];
|
||||
var datastore = {
|
||||
const secrets = [];
|
||||
const datastore = {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
name: "Import " + n,
|
||||
folders: [],
|
||||
items: [],
|
||||
};
|
||||
|
||||
let parsedData;
|
||||
try {
|
||||
var parsedData = JSON.parse(data);
|
||||
parsedData = JSON.parse(data);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
|
||||
gather_secrets(datastore, secrets, parsedData);
|
||||
gatherSecrets(datastore, secrets, parsedData);
|
||||
|
||||
return {
|
||||
datastore: datastore,
|
||||
@ -409,8 +410,8 @@ function parser(data) {
|
||||
};
|
||||
}
|
||||
|
||||
const service = {
|
||||
const importEnpassJsonService = {
|
||||
parser,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default importEnpassJsonService;
|
||||
|
@ -19,8 +19,8 @@ const INDEX_COMMENTS = 4;
|
||||
*
|
||||
* @returns {*} The secrets object
|
||||
*/
|
||||
var transform_to_secret = function (line) {
|
||||
var parsed_url = helperService.parseUrl(line[INDEX_WEB_SITE]);
|
||||
function transformToSecret(line) {
|
||||
const parsed_url = helperService.parseUrl(line[INDEX_WEB_SITE]);
|
||||
|
||||
return {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
@ -34,7 +34,7 @@ var transform_to_secret = function (line) {
|
||||
website_password_url: line[INDEX_WEB_SITE],
|
||||
website_password_title: line[INDEX_ACCOUNT].replace(/(?:\\(.))/g, "$1"),
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the datastore with folders their content and together with the secrets object
|
||||
@ -44,7 +44,7 @@ var transform_to_secret = function (line) {
|
||||
* @param {[]} csv The array containing all the found secrets
|
||||
*/
|
||||
function gather_secrets(datastore, secrets, csv) {
|
||||
var line;
|
||||
let line;
|
||||
|
||||
for (let i = 0; i < csv.length; i++) {
|
||||
line = csv[i];
|
||||
@ -55,7 +55,7 @@ function gather_secrets(datastore, secrets, csv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var secret = transform_to_secret(line);
|
||||
const secret = transformToSecret(line);
|
||||
if (secret === null) {
|
||||
//empty line
|
||||
continue;
|
||||
@ -72,7 +72,7 @@ function gather_secrets(datastore, secrets, csv) {
|
||||
* @returns {Array} The array of arrays representing the CSV
|
||||
*/
|
||||
function parse_csv(data) {
|
||||
var csv = Papa.parse(data);
|
||||
const csv = Papa.parse(data);
|
||||
|
||||
if (csv["errors"].length > 0) {
|
||||
throw new Error(csv["errors"][0]["message"]);
|
||||
@ -96,18 +96,19 @@ function parse_csv(data) {
|
||||
* @returns {{datastore, secrets: Array} | null}
|
||||
*/
|
||||
function parser(data) {
|
||||
var d = new Date();
|
||||
var n = d.toISOString();
|
||||
const d = new Date();
|
||||
const n = d.toISOString();
|
||||
|
||||
var secrets = [];
|
||||
var datastore = {
|
||||
const secrets = [];
|
||||
const datastore = {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
name: "Import " + n,
|
||||
items: [],
|
||||
};
|
||||
|
||||
let csv;
|
||||
try {
|
||||
var csv = parse_csv(data);
|
||||
csv = parse_csv(data);
|
||||
} catch (err) {
|
||||
console.log(data);
|
||||
console.log(err);
|
||||
@ -122,8 +123,8 @@ function parser(data) {
|
||||
};
|
||||
}
|
||||
|
||||
const service = {
|
||||
const importKeepassInfoCsv = {
|
||||
parser,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default importKeepassInfoCsv;
|
||||
|
@ -15,7 +15,7 @@ describe('Service: importKeePassInfoCsv test suite', function () {
|
||||
cryptoLibrary.generateUuid = jest.fn();
|
||||
cryptoLibrary.generateUuid.mockImplementation(() => generic_uuid);
|
||||
|
||||
var input = "\"Account\",\"Login Name\",\"Password\",\"Web Site\",\"Comments\"\n" +
|
||||
const input = "\"Account\",\"Login Name\",\"Password\",\"Web Site\",\"Comments\"\n" +
|
||||
"\"Sample Entry Title\",\"Greg\",\"ycXfARD2G1AOBzLlhtbn\",\"http://www.somepage.net\",\"Some notes...\"\n" +
|
||||
"\"Yet Another Sample Entry\",\"Michael\",\"qgyXFZ1iGgNqzg+eZter\",\"http://www.anotherpage.org\",\"More notes...\"\n" +
|
||||
"\"Entry To Test Special Characters\",\"!§$%&/()=?´`_#²³{[]}\\\\\",\"öäüÖÄÜ߀@<>µ©®\",\"http://www.website.com\",\"The user name and password fields contain special characters.\"\n" +
|
||||
@ -28,9 +28,9 @@ describe('Service: importKeePassInfoCsv test suite', function () {
|
||||
"This is a multi-line comment.\"\n" +
|
||||
"";
|
||||
|
||||
var output = importKeePassInfoCsv.parser(input);
|
||||
const output = importKeePassInfoCsv.parser(input);
|
||||
|
||||
var expected_output = {
|
||||
const expected_output = {
|
||||
"datastore": {
|
||||
"id": generic_uuid,
|
||||
"name": output.datastore.name,
|
||||
|
@ -5,7 +5,7 @@ import cryptoLibrary from "./crypto-library";
|
||||
import helperService from "./helper";
|
||||
const fastXmlParser = require("fast-xml-parser");
|
||||
|
||||
function unescape_value(value) {
|
||||
function unescapeValue(value) {
|
||||
value = value.replace(/</g, "<");
|
||||
value = value.replace(/>/g, ">");
|
||||
value = value.replace(/&/g, "&");
|
||||
@ -20,11 +20,11 @@ function unescape_value(value) {
|
||||
*
|
||||
* @returns {*} The secrets object
|
||||
*/
|
||||
var transform_to_secret = function (line) {
|
||||
function transformToSecret(line) {
|
||||
if (!line.hasOwnProperty("String") || !line.String) {
|
||||
return null;
|
||||
}
|
||||
var secret = {
|
||||
const secret = {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
type: "website_password",
|
||||
name: "",
|
||||
@ -38,15 +38,15 @@ var transform_to_secret = function (line) {
|
||||
};
|
||||
|
||||
for (let i = 0; i < line.String.length; i++) {
|
||||
var value = line.String[i];
|
||||
const value = line.String[i];
|
||||
if (!value.hasOwnProperty("Key")) {
|
||||
continue;
|
||||
}
|
||||
if (!value.hasOwnProperty("Value")) {
|
||||
continue;
|
||||
}
|
||||
var key = value["Key"];
|
||||
var val = unescape_value(value["Value"]);
|
||||
const key = value["Key"];
|
||||
const val = unescapeValue(value["Value"]);
|
||||
|
||||
if (key === "Notes") {
|
||||
secret["website_password_notes"] = val;
|
||||
@ -62,7 +62,7 @@ var transform_to_secret = function (line) {
|
||||
}
|
||||
|
||||
if (key === "URL") {
|
||||
var parsed_url = helperService.parseUrl(val);
|
||||
const parsed_url = helperService.parseUrl(val);
|
||||
secret["urlfilter"] = parsed_url.authority || "";
|
||||
secret["website_password_url_filter"] = parsed_url.authority || "";
|
||||
secret["website_password_url"] = val;
|
||||
@ -74,7 +74,7 @@ var transform_to_secret = function (line) {
|
||||
}
|
||||
|
||||
return secret;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the datastore with folders their content and together with the secrets object
|
||||
@ -83,10 +83,10 @@ var transform_to_secret = function (line) {
|
||||
* @param {[]} secrets The array containing all the found secrets
|
||||
* @param {Document} xml The parsed XML document
|
||||
*/
|
||||
function gather_secrets(datastore, secrets, xml) {
|
||||
var i;
|
||||
var next_folder;
|
||||
var entries;
|
||||
function gatherSecrets(datastore, secrets, xml) {
|
||||
let i;
|
||||
let next_folder;
|
||||
let entries;
|
||||
if (xml.hasOwnProperty("Entry")) {
|
||||
if (Object.prototype.toString.call(xml.Entry) === "[object Array]") {
|
||||
entries = xml.Entry;
|
||||
@ -95,7 +95,7 @@ function gather_secrets(datastore, secrets, xml) {
|
||||
}
|
||||
|
||||
for (i = 0; i < entries.length; i++) {
|
||||
var secret = transform_to_secret(entries[i]);
|
||||
const secret = transformToSecret(entries[i]);
|
||||
if (secret === null) {
|
||||
//empty line
|
||||
continue;
|
||||
@ -122,7 +122,7 @@ function gather_secrets(datastore, secrets, xml) {
|
||||
folders: [],
|
||||
items: [],
|
||||
};
|
||||
gather_secrets(next_folder, secrets, entries[i]);
|
||||
gatherSecrets(next_folder, secrets, entries[i]);
|
||||
datastore["folders"].push(next_folder);
|
||||
}
|
||||
}
|
||||
@ -136,9 +136,9 @@ function gather_secrets(datastore, secrets, xml) {
|
||||
* @param {string} xmlString The raw data to parse
|
||||
* @returns {object} The array of arrays representing the XML
|
||||
*/
|
||||
function parse_xml(xmlString) {
|
||||
function parseXml(xmlString) {
|
||||
fastXmlParser.validate(xmlString); // Throws sometimes an error if its no valid xml
|
||||
var parsed_xml = fastXmlParser.parse(xmlString, { parseNodeValue: false });
|
||||
const parsed_xml = fastXmlParser.parse(xmlString, { parseNodeValue: false });
|
||||
if (
|
||||
!parsed_xml.hasOwnProperty("KeePassFile") ||
|
||||
!parsed_xml["KeePassFile"].hasOwnProperty("Root") ||
|
||||
@ -164,24 +164,25 @@ function parse_xml(xmlString) {
|
||||
* @returns {{datastore, secrets: Array} | null}
|
||||
*/
|
||||
function parser(data) {
|
||||
var d = new Date();
|
||||
var n = d.toISOString();
|
||||
const d = new Date();
|
||||
const n = d.toISOString();
|
||||
|
||||
var secrets = [];
|
||||
var datastore = {
|
||||
const secrets = [];
|
||||
const datastore = {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
name: "Import " + n,
|
||||
items: [],
|
||||
folders: [],
|
||||
};
|
||||
|
||||
let xml;
|
||||
try {
|
||||
var xml = parse_xml(data);
|
||||
xml = parseXml(data);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
|
||||
gather_secrets(datastore, secrets, xml);
|
||||
gatherSecrets(datastore, secrets, xml);
|
||||
|
||||
return {
|
||||
datastore: datastore,
|
||||
@ -189,8 +190,8 @@ function parser(data) {
|
||||
};
|
||||
}
|
||||
|
||||
const service = {
|
||||
const importKeepassInfoXmlService = {
|
||||
parser,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default importKeepassInfoXmlService;
|
||||
|
@ -22,9 +22,9 @@ const INDEX_NOTES = 5;
|
||||
*
|
||||
* @returns {*} Returns the specified folder object, containing items and folders
|
||||
*/
|
||||
function get_folder_helper(path, folder) {
|
||||
var next_folder_name;
|
||||
var next_folder;
|
||||
function getFolderHelper(path, folder) {
|
||||
let next_folder_name;
|
||||
let next_folder;
|
||||
|
||||
if (path.length === 0) {
|
||||
return folder;
|
||||
@ -48,7 +48,7 @@ function get_folder_helper(path, folder) {
|
||||
folder["folders"].push(next_folder);
|
||||
}
|
||||
|
||||
return get_folder_helper(path, next_folder);
|
||||
return getFolderHelper(path, next_folder);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,11 +59,11 @@ function get_folder_helper(path, folder) {
|
||||
*
|
||||
* @returns {object} Returns the folder
|
||||
*/
|
||||
function get_folder(line, datastore) {
|
||||
var path = line[INDEX_GROUP].split("/");
|
||||
function getFolder(line, datastore) {
|
||||
let path = line[INDEX_GROUP].split("/");
|
||||
path.shift(); // Drop "Root" element
|
||||
|
||||
return get_folder_helper(path, datastore);
|
||||
return getFolderHelper(path, datastore);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,8 +73,8 @@ function get_folder(line, datastore) {
|
||||
*
|
||||
* @returns {*} The secrets object
|
||||
*/
|
||||
var transform_to_secret = function (line) {
|
||||
var parsed_url = helperService.parseUrl(line[INDEX_URL]);
|
||||
function transformToSecret(line) {
|
||||
const parsed_url = helperService.parseUrl(line[INDEX_URL]);
|
||||
|
||||
return {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
@ -88,7 +88,7 @@ var transform_to_secret = function (line) {
|
||||
website_password_url: line[INDEX_URL],
|
||||
website_password_title: line[INDEX_TITLE],
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the datastore with folders their content and together with the secrets object
|
||||
@ -98,8 +98,8 @@ var transform_to_secret = function (line) {
|
||||
* @param {[]} csv The array containing all the found secrets
|
||||
*/
|
||||
function gather_secrets(datastore, secrets, csv) {
|
||||
var line;
|
||||
var folder;
|
||||
let line;
|
||||
let folder;
|
||||
|
||||
for (let i = 0; i < csv.length; i++) {
|
||||
line = csv[i];
|
||||
@ -110,8 +110,8 @@ function gather_secrets(datastore, secrets, csv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
folder = get_folder(line, datastore);
|
||||
var secret = transform_to_secret(line);
|
||||
folder = getFolder(line, datastore);
|
||||
const secret = transformToSecret(line);
|
||||
if (secret === null) {
|
||||
//empty line
|
||||
continue;
|
||||
@ -127,8 +127,8 @@ function gather_secrets(datastore, secrets, csv) {
|
||||
* @param {string} data The raw data to parse
|
||||
* @returns {Array} The array of arrays representing the CSV
|
||||
*/
|
||||
function parse_csv(data) {
|
||||
var csv = Papa.parse(data);
|
||||
function parseCsv(data) {
|
||||
const csv = Papa.parse(data);
|
||||
|
||||
if (csv["errors"].length > 0) {
|
||||
throw new Error(csv["errors"][0]["message"]);
|
||||
@ -152,19 +152,20 @@ function parse_csv(data) {
|
||||
* @returns {{datastore, secrets: Array} | null}
|
||||
*/
|
||||
function parser(data) {
|
||||
var d = new Date();
|
||||
var n = d.toISOString();
|
||||
const d = new Date();
|
||||
const n = d.toISOString();
|
||||
|
||||
var secrets = [];
|
||||
var datastore = {
|
||||
const secrets = [];
|
||||
const datastore = {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
name: "Import " + n,
|
||||
folders: [],
|
||||
items: [],
|
||||
};
|
||||
|
||||
let csv;
|
||||
try {
|
||||
var csv = parse_csv(data);
|
||||
csv = parseCsv(data);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
@ -177,8 +178,8 @@ function parser(data) {
|
||||
};
|
||||
}
|
||||
|
||||
const service = {
|
||||
const importKeepassxOrgCsvService = {
|
||||
parser,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default importKeepassxOrgCsvService;
|
||||
|
@ -13,7 +13,7 @@ describe('Service: importKeePassXOrgCsv test suite', function () {
|
||||
cryptoLibrary.generateUuid = jest.fn();
|
||||
cryptoLibrary.generateUuid.mockImplementation(() => generic_uuid);
|
||||
|
||||
var input = "\"Group\",\"Title\",\"Username\",\"Password\",\"URL\",\"Notes\"\n" +
|
||||
const input = "\"Group\",\"Title\",\"Username\",\"Password\",\"URL\",\"Notes\"\n" +
|
||||
"\"Root\",\"home dir \",\"meldron\",\"xxxx\",\"\",\"xxx\"\n" +
|
||||
"\"Root\",\"CA\",\"\",\"xxx\"\"xxx\",\"\",\"\"\n" +
|
||||
"\"Root/Internet\",\"tunnelbroker\",\"xxx\",\"xxx\",\"tunnelbroker.net\",\"\"\n" +
|
||||
@ -36,9 +36,9 @@ describe('Service: importKeePassXOrgCsv test suite', function () {
|
||||
"\"Root/Company/ABC API\",\"MusicService_v1\",\"abctest\",\"5/a5F3asdas\",\"https://park.company-technologies.com/AWasdasdS/asdas\",\"SOAP\"\n" +
|
||||
"";
|
||||
|
||||
var output = importKeePassXOrgCsv.parser(input);
|
||||
const output = importKeePassXOrgCsv.parser(input);
|
||||
|
||||
var expected_output = {
|
||||
const expected_output = {
|
||||
"datastore": {
|
||||
"id": generic_uuid,
|
||||
"name": output.datastore.name,
|
||||
|
@ -35,7 +35,7 @@ function get_folder_name(line) {
|
||||
*
|
||||
* @returns {string} Returns the appropriate type (note or website_password)
|
||||
*/
|
||||
var get_type = function (line) {
|
||||
function getType(line) {
|
||||
if (line[INDEX_URL] === "http://sn") {
|
||||
// its a license, so lets return a note as we don't have this object class yet
|
||||
return "note";
|
||||
@ -47,7 +47,7 @@ var get_type = function (line) {
|
||||
// Should have an url, so should be a password
|
||||
return "website_password";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a line that should represent a note and transforms it into a proper secret object
|
||||
@ -56,8 +56,8 @@ var get_type = function (line) {
|
||||
*
|
||||
* @returns {*} The note secret object
|
||||
*/
|
||||
var transfor_into_note = function (line) {
|
||||
var note_notes = "";
|
||||
function transformIntoNote(line) {
|
||||
let note_notes = "";
|
||||
if (line[INDEX_USERNAME]) {
|
||||
note_notes = note_notes + line[INDEX_USERNAME] + "\n";
|
||||
}
|
||||
@ -79,7 +79,7 @@ var transfor_into_note = function (line) {
|
||||
note_title: line[INDEX_NAME],
|
||||
note_notes: note_notes,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a line that should represent a website passwords and transforms it into a proper secret object
|
||||
@ -88,8 +88,8 @@ var transfor_into_note = function (line) {
|
||||
*
|
||||
* @returns {*} The website_password secret object
|
||||
*/
|
||||
var transfor_into_website_password = function (line) {
|
||||
var parsed_url = helperService.parseUrl(line[INDEX_URL]);
|
||||
function transformIntoWebsitePassword(line) {
|
||||
const parsed_url = helperService.parseUrl(line[INDEX_URL]);
|
||||
|
||||
return {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
@ -103,7 +103,7 @@ var transfor_into_website_password = function (line) {
|
||||
website_password_url: line[INDEX_URL],
|
||||
website_password_title: line[INDEX_NAME],
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a line, checks its type and transforms it into a proper secret object
|
||||
@ -112,14 +112,14 @@ var transfor_into_website_password = function (line) {
|
||||
*
|
||||
* @returns {*} The secrets object
|
||||
*/
|
||||
var transform_to_secret = function (line) {
|
||||
var type = get_type(line);
|
||||
function transformToSecret(line) {
|
||||
const type = getType(line);
|
||||
if (type === "note") {
|
||||
return transfor_into_note(line);
|
||||
return transformIntoNote(line);
|
||||
} else {
|
||||
return transfor_into_website_password(line);
|
||||
return transformIntoWebsitePassword(line);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the datastore with folders their content and together with the secrets object
|
||||
@ -128,10 +128,10 @@ var transform_to_secret = function (line) {
|
||||
* @param {[]} secrets The array containing all the found secrets
|
||||
* @param {[]} csv The array containing all the found secrets
|
||||
*/
|
||||
function gather_secrets(datastore, secrets, csv) {
|
||||
var line;
|
||||
var folder_name;
|
||||
var folder_index = {};
|
||||
function gatherSecrets(datastore, secrets, csv) {
|
||||
let line;
|
||||
let folder_name;
|
||||
const folder_index = {};
|
||||
|
||||
for (let i = 0; i < csv.length; i++) {
|
||||
line = csv[i];
|
||||
@ -140,7 +140,7 @@ function gather_secrets(datastore, secrets, csv) {
|
||||
}
|
||||
|
||||
folder_name = get_folder_name(line);
|
||||
var secret = transform_to_secret(line);
|
||||
const secret = transformToSecret(line);
|
||||
if (secret === null) {
|
||||
//empty line
|
||||
continue;
|
||||
@ -168,8 +168,8 @@ function gather_secrets(datastore, secrets, csv) {
|
||||
* @param {string} data The raw data to parse
|
||||
* @returns {Array} The array of arrays representing the CSV
|
||||
*/
|
||||
function parse_csv(data) {
|
||||
var csv = Papa.parse(data);
|
||||
function parseCsv(data) {
|
||||
const csv = Papa.parse(data);
|
||||
|
||||
if (csv["errors"].length > 0) {
|
||||
throw new Error(csv["errors"][0]["message"]);
|
||||
@ -193,23 +193,24 @@ function parse_csv(data) {
|
||||
* @returns {{datastore, secrets: Array} | null}
|
||||
*/
|
||||
function parser(data) {
|
||||
var d = new Date();
|
||||
var n = d.toISOString();
|
||||
const d = new Date();
|
||||
const n = d.toISOString();
|
||||
|
||||
var secrets = [];
|
||||
var datastore = {
|
||||
const secrets = [];
|
||||
const datastore = {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
name: "Import " + n,
|
||||
folders: [],
|
||||
};
|
||||
|
||||
let csv;
|
||||
try {
|
||||
var csv = parse_csv(data);
|
||||
csv = parseCsv(data);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
|
||||
gather_secrets(datastore, secrets, csv);
|
||||
gatherSecrets(datastore, secrets, csv);
|
||||
|
||||
return {
|
||||
datastore: datastore,
|
||||
@ -217,8 +218,8 @@ function parser(data) {
|
||||
};
|
||||
}
|
||||
|
||||
const service = {
|
||||
const importLastpassComCsvService = {
|
||||
parser,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default importLastpassComCsvService;
|
||||
|
@ -10,8 +10,8 @@ import cryptoLibrary from "./crypto-library";
|
||||
* @param {[]} secrets The array containing all the found secrets
|
||||
*/
|
||||
function gather_secrets(folder, secrets) {
|
||||
var i;
|
||||
var subitem;
|
||||
let i;
|
||||
let subitem;
|
||||
|
||||
folder["id"] = cryptoLibrary.generateUuid();
|
||||
|
||||
@ -46,15 +46,16 @@ function gather_secrets(folder, secrets) {
|
||||
* @returns {{datastore, secrets: Array} | null}
|
||||
*/
|
||||
function parser(data) {
|
||||
let datastore;
|
||||
try {
|
||||
var datastore = JSON.parse(data);
|
||||
datastore = JSON.parse(data);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
var secrets = [];
|
||||
const secrets = [];
|
||||
|
||||
var d = new Date();
|
||||
var n = d.toISOString();
|
||||
const d = new Date();
|
||||
const n = d.toISOString();
|
||||
datastore["name"] = "Import " + n;
|
||||
|
||||
gather_secrets(datastore, secrets);
|
||||
@ -65,8 +66,8 @@ function parser(data) {
|
||||
};
|
||||
}
|
||||
|
||||
const service = {
|
||||
const importPsonoPwJsonService = {
|
||||
parser,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default importPsonoPwJsonService;
|
||||
|
@ -15,11 +15,11 @@ describe('Service: importPsonoPwJson test suite', function () {
|
||||
cryptoLibrary.generateUuid = jest.fn();
|
||||
cryptoLibrary.generateUuid.mockImplementation(() => generic_uuid);
|
||||
|
||||
var input = '{"folders":[{"name":"A Folder"},{"name":"Company Passwords","folders":[{"name":"bla","items":[{"type":"website_password","urlfilter":"facebook.com","name":"Facebook","website_password_url_filter":"facebook.com","website_password_auto_submit":true,"website_password_password":"mypassword","website_password_username":"myusername","website_password_url":"https://de-de.facebook.com/","website_password_title":"Facebook"}]}]}],"items":[{"type":"website_password","urlfilter":"amazon.de","name":"Amazon.de","website_password_url_filter":"amazon.de","website_password_password":"mypw","website_password_username":"myuser","website_password_url":"https://www.amazon.de","website_password_title":"Amazon.de"},{"type":"note","name":"My secret note","note_notes":"Some nice secrets go in here!","note_title":"My secret note"}]}';
|
||||
const input = '{"folders":[{"name":"A Folder"},{"name":"Company Passwords","folders":[{"name":"bla","items":[{"type":"website_password","urlfilter":"facebook.com","name":"Facebook","website_password_url_filter":"facebook.com","website_password_auto_submit":true,"website_password_password":"mypassword","website_password_username":"myusername","website_password_url":"https://de-de.facebook.com/","website_password_title":"Facebook"}]}]}],"items":[{"type":"website_password","urlfilter":"amazon.de","name":"Amazon.de","website_password_url_filter":"amazon.de","website_password_password":"mypw","website_password_username":"myuser","website_password_url":"https://www.amazon.de","website_password_title":"Amazon.de"},{"type":"note","name":"My secret note","note_notes":"Some nice secrets go in here!","note_title":"My secret note"}]}';
|
||||
|
||||
var output = importPsonoPwJson.parser(input);
|
||||
const output = importPsonoPwJson.parser(input);
|
||||
|
||||
var expected_output = {
|
||||
const expected_output = {
|
||||
"datastore": {
|
||||
"folders": [{
|
||||
"name": "A Folder",
|
||||
|
@ -17,7 +17,7 @@ const INDEX_INFORMATIONS = 4;
|
||||
*
|
||||
* @returns {*} The secrets object
|
||||
*/
|
||||
var transform_to_secret = function (line) {
|
||||
function transformToSecret(line) {
|
||||
return {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
type: "website_password",
|
||||
@ -30,7 +30,7 @@ var transform_to_secret = function (line) {
|
||||
website_password_url: "",
|
||||
website_password_title: line[INDEX_DESCRIPTION],
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the folder if it doesn't exists and returns it.
|
||||
@ -40,9 +40,9 @@ var transform_to_secret = function (line) {
|
||||
*
|
||||
* @returns {object} Returns the folder
|
||||
*/
|
||||
function get_folder(line, datastore) {
|
||||
var next_folder_name;
|
||||
var next_folder;
|
||||
function getFolder(line, datastore) {
|
||||
let next_folder_name;
|
||||
let next_folder;
|
||||
|
||||
next_folder_name = line[INDEX_ORGANISATION_UNIT];
|
||||
|
||||
@ -73,9 +73,9 @@ function get_folder(line, datastore) {
|
||||
* @param {[]} secrets The array containing all the found secrets
|
||||
* @param {[]} csv The array containing all the found secrets
|
||||
*/
|
||||
function gather_secrets(datastore, secrets, csv) {
|
||||
var line;
|
||||
var folder;
|
||||
function gatherSecrets(datastore, secrets, csv) {
|
||||
let line;
|
||||
let folder;
|
||||
|
||||
for (let i = 0; i < csv.length; i++) {
|
||||
line = csv[i];
|
||||
@ -86,8 +86,8 @@ function gather_secrets(datastore, secrets, csv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
folder = get_folder(line, datastore);
|
||||
var secret = transform_to_secret(line);
|
||||
folder = getFolder(line, datastore);
|
||||
const secret = transformToSecret(line);
|
||||
if (secret === null) {
|
||||
//empty line
|
||||
continue;
|
||||
@ -103,8 +103,8 @@ function gather_secrets(datastore, secrets, csv) {
|
||||
* @param {string} data The raw data to parse
|
||||
* @returns {Array} The array of arrays representing the CSV
|
||||
*/
|
||||
function parse_csv(data) {
|
||||
var csv = Papa.parse(data);
|
||||
function parseCsv(data) {
|
||||
const csv = Papa.parse(data);
|
||||
|
||||
if (csv["errors"].length > 0) {
|
||||
throw new Error(csv["errors"][0]["message"]);
|
||||
@ -128,24 +128,25 @@ function parse_csv(data) {
|
||||
* @returns {{datastore, secrets: Array} | null}
|
||||
*/
|
||||
function parser(data) {
|
||||
var d = new Date();
|
||||
var n = d.toISOString();
|
||||
const d = new Date();
|
||||
const n = d.toISOString();
|
||||
|
||||
var secrets = [];
|
||||
var datastore = {
|
||||
const secrets = [];
|
||||
const datastore = {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
name: "Import " + n,
|
||||
items: [],
|
||||
folders: [],
|
||||
};
|
||||
|
||||
let csv;
|
||||
try {
|
||||
var csv = parse_csv(data);
|
||||
csv = parseCsv(data);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
|
||||
gather_secrets(datastore, secrets, csv);
|
||||
gatherSecrets(datastore, secrets, csv);
|
||||
|
||||
return {
|
||||
datastore: datastore,
|
||||
@ -153,8 +154,8 @@ function parser(data) {
|
||||
};
|
||||
}
|
||||
|
||||
const service = {
|
||||
const importPwsafeOrgCsvService = {
|
||||
parser,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default importPwsafeOrgCsvService;
|
||||
|
@ -14,7 +14,7 @@ const INDEX_PASSWORD = 5;
|
||||
const INDEX_NOTES = 6;
|
||||
const INDEX_TAGS = 7;
|
||||
const INDEX_CUSTOM_FIELDS = 8;
|
||||
var CUSTOM_FIELD_OFFSET = 9;
|
||||
const CUSTOM_FIELD_OFFSET = 9;
|
||||
|
||||
/**
|
||||
* Takes a line and returns the correct description
|
||||
@ -23,13 +23,13 @@ var CUSTOM_FIELD_OFFSET = 9;
|
||||
*
|
||||
* @returns {*} The description
|
||||
*/
|
||||
var get_description = function (line) {
|
||||
var description = line[INDEX_DESCRIPTION];
|
||||
function getDescription(line) {
|
||||
let description = line[INDEX_DESCRIPTION];
|
||||
if (line[INDEX_TAGS]) {
|
||||
description = description + " (" + line[INDEX_TAGS] + ")";
|
||||
}
|
||||
return description;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a line and returns the correct notes
|
||||
@ -40,15 +40,15 @@ var get_description = function (line) {
|
||||
*
|
||||
* @returns {*} The description
|
||||
*/
|
||||
var get_notes = function (line) {
|
||||
var notes = line[INDEX_NOTES] + "\n";
|
||||
function getNotes(line) {
|
||||
let notes = line[INDEX_NOTES] + "\n";
|
||||
|
||||
if (line[INDEX_EMAIL]) {
|
||||
notes = notes + "Email: " + line[INDEX_EMAIL] + "\n";
|
||||
}
|
||||
|
||||
if (line[INDEX_CUSTOM_FIELDS]) {
|
||||
var custom_fields = line[INDEX_CUSTOM_FIELDS].split(",");
|
||||
const custom_fields = line[INDEX_CUSTOM_FIELDS].split(",");
|
||||
for (let i = 0; i < custom_fields.length; i++) {
|
||||
//checks if the corresponding value is not empty
|
||||
if (!line[CUSTOM_FIELD_OFFSET + i]) {
|
||||
@ -59,7 +59,7 @@ var get_notes = function (line) {
|
||||
}
|
||||
|
||||
return notes;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a line and transforms it into a website password entry
|
||||
@ -68,11 +68,11 @@ var get_notes = function (line) {
|
||||
*
|
||||
* @returns {*} The secrets object
|
||||
*/
|
||||
var transform_to_website_password = function (line) {
|
||||
var parsed_url = helperService.parseUrl(line[INDEX_URL]);
|
||||
function transformToWebsitePassword(line) {
|
||||
const parsed_url = helperService.parseUrl(line[INDEX_URL]);
|
||||
|
||||
var description = get_description(line);
|
||||
var notes = get_notes(line);
|
||||
const description = getDescription(line);
|
||||
const notes = getNotes(line);
|
||||
|
||||
return {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
@ -86,7 +86,7 @@ var transform_to_website_password = function (line) {
|
||||
website_password_url: line[INDEX_URL],
|
||||
website_password_title: description,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a line and transforms it into a application password entry
|
||||
@ -95,9 +95,9 @@ var transform_to_website_password = function (line) {
|
||||
*
|
||||
* @returns {*} The secrets object
|
||||
*/
|
||||
var transform_to_application_password = function (line) {
|
||||
var description = get_description(line);
|
||||
var notes = get_notes(line);
|
||||
function transformToApplicationPassword(line) {
|
||||
const description = getDescription(line);
|
||||
const notes = getNotes(line);
|
||||
|
||||
return {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
@ -108,7 +108,7 @@ var transform_to_application_password = function (line) {
|
||||
application_password_notes: notes,
|
||||
application_password_title: description,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a line and transforms it into a bookmark entry
|
||||
@ -117,11 +117,11 @@ var transform_to_application_password = function (line) {
|
||||
*
|
||||
* @returns {*} The secrets object
|
||||
*/
|
||||
var transform_to_bookmark = function (line) {
|
||||
var parsed_url = helperService.parseUrl(line[INDEX_URL]);
|
||||
function transformToBookmark(line) {
|
||||
const parsed_url = helperService.parseUrl(line[INDEX_URL]);
|
||||
|
||||
var description = get_description(line);
|
||||
var notes = get_notes(line);
|
||||
const description = getDescription(line);
|
||||
const notes = getNotes(line);
|
||||
|
||||
return {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
@ -133,7 +133,7 @@ var transform_to_bookmark = function (line) {
|
||||
bookmark_url: line[INDEX_URL],
|
||||
bookmark_title: description,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a line and transforms it into a note entry
|
||||
@ -142,9 +142,9 @@ var transform_to_bookmark = function (line) {
|
||||
*
|
||||
* @returns {*} The secrets object
|
||||
*/
|
||||
var transform_to_note = function (line) {
|
||||
var description = get_description(line);
|
||||
var notes = get_notes(line);
|
||||
function transformToNote(line) {
|
||||
const description = getDescription(line);
|
||||
const notes = getNotes(line);
|
||||
|
||||
return {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
@ -153,17 +153,17 @@ var transform_to_note = function (line) {
|
||||
note_notes: notes,
|
||||
note_title: description,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes an item and return its types
|
||||
*
|
||||
* @param {object} line The line to analyze
|
||||
*/
|
||||
function detect_type(line) {
|
||||
var contains_url = line[INDEX_URL];
|
||||
var contains_username = line[INDEX_USERNAME];
|
||||
var contains_password = line[INDEX_PASSWORD];
|
||||
function detectType(line) {
|
||||
const contains_url = line[INDEX_URL];
|
||||
const contains_username = line[INDEX_USERNAME];
|
||||
const contains_password = line[INDEX_PASSWORD];
|
||||
|
||||
if (contains_url && (contains_username || contains_password)) {
|
||||
return "website_password";
|
||||
@ -186,9 +186,9 @@ function detect_type(line) {
|
||||
*
|
||||
* @returns {object} Returns the folder
|
||||
*/
|
||||
function get_folder(line, datastore) {
|
||||
var next_folder_name;
|
||||
var next_folder;
|
||||
function getFolder(line, datastore) {
|
||||
let next_folder_name;
|
||||
let next_folder;
|
||||
|
||||
next_folder_name = line[INDEX_PROJECT_NAME];
|
||||
|
||||
@ -219,9 +219,9 @@ function get_folder(line, datastore) {
|
||||
* @param {[]} secrets The array containing all the found secrets
|
||||
* @param {[]} csv The array containing all the found secrets
|
||||
*/
|
||||
function gather_secrets(datastore, secrets, csv) {
|
||||
var line;
|
||||
var folder;
|
||||
function gatherSecrets(datastore, secrets, csv) {
|
||||
let line;
|
||||
let folder;
|
||||
|
||||
for (let i = 0; i < csv.length; i++) {
|
||||
line = csv[i];
|
||||
@ -232,19 +232,19 @@ function gather_secrets(datastore, secrets, csv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
folder = get_folder(line, datastore);
|
||||
folder = getFolder(line, datastore);
|
||||
|
||||
var detected_type = detect_type(line);
|
||||
const detected_type = detectType(line);
|
||||
|
||||
var secret = null;
|
||||
let secret = null;
|
||||
if (detected_type === "website_password") {
|
||||
secret = transform_to_website_password(line);
|
||||
secret = transformToWebsitePassword(line);
|
||||
} else if (detected_type === "application_password") {
|
||||
secret = transform_to_application_password(line);
|
||||
secret = transformToApplicationPassword(line);
|
||||
} else if (detected_type === "bookmark") {
|
||||
secret = transform_to_bookmark(line);
|
||||
secret = transformToBookmark(line);
|
||||
} else {
|
||||
secret = transform_to_note(line);
|
||||
secret = transformToNote(line);
|
||||
}
|
||||
|
||||
if (secret === null) {
|
||||
@ -262,8 +262,8 @@ function gather_secrets(datastore, secrets, csv) {
|
||||
* @param {string} data The raw data to parse
|
||||
* @returns {Array} The array of arrays representing the CSV
|
||||
*/
|
||||
function parse_csv(data) {
|
||||
var csv = Papa.parse(data);
|
||||
function parseCsv(data) {
|
||||
const csv = Papa.parse(data);
|
||||
|
||||
if (csv["errors"].length > 0) {
|
||||
throw new Error(csv["errors"][0]["message"]);
|
||||
@ -287,32 +287,33 @@ function parse_csv(data) {
|
||||
* @returns {{datastore, secrets: Array} | null}
|
||||
*/
|
||||
function parser(data) {
|
||||
var d = new Date();
|
||||
var n = d.toISOString();
|
||||
const d = new Date();
|
||||
const n = d.toISOString();
|
||||
|
||||
var secrets = [];
|
||||
var datastore = {
|
||||
const secrets = [];
|
||||
const datastore = {
|
||||
id: cryptoLibrary.generateUuid(),
|
||||
name: "Import " + n,
|
||||
items: [],
|
||||
folders: [],
|
||||
};
|
||||
|
||||
let csv;
|
||||
try {
|
||||
var csv = parse_csv(data);
|
||||
csv = parseCsv(data);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
|
||||
gather_secrets(datastore, secrets, csv);
|
||||
gatherSecrets(datastore, secrets, csv);
|
||||
|
||||
return {
|
||||
datastore: datastore,
|
||||
secrets: secrets,
|
||||
};
|
||||
}
|
||||
const service = {
|
||||
const importTeampassNetCsvService = {
|
||||
parser,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default importTeampassNetCsvService;
|
||||
|
@ -13,17 +13,17 @@ describe('Service: importTeampassNetCsv test suite', function () {
|
||||
const generic_uuid = '1fce01f4-6411-47a9-885c-a80bf4c654aa'
|
||||
cryptoLibrary.generateUuid = jest.fn();
|
||||
cryptoLibrary.generateUuid.mockImplementation(() => generic_uuid);
|
||||
|
||||
var input = "\"Project name\",\"Name\",\"Access information\",\"Username\",\"E-mail\",\"Password\",\"Notes\",\"Tags\",\"Custom fields\",\"Custom 1\",\"Custom 2\",\"Custom 4\",\"Custom 5\",\"Custom 6\",\"Custom 7\",\"Custom 8\",\"Custom 9\",\"Custom 10\",\"Expiry date (mm-dd-yyyy)\"\n" +
|
||||
|
||||
const input = "\"Project name\",\"Name\",\"Access information\",\"Username\",\"E-mail\",\"Password\",\"Notes\",\"Tags\",\"Custom fields\",\"Custom 1\",\"Custom 2\",\"Custom 4\",\"Custom 5\",\"Custom 6\",\"Custom 7\",\"Custom 8\",\"Custom 9\",\"Custom 10\",\"Expiry date (mm-dd-yyyy)\"\n" +
|
||||
"\"Software\",\"Database user\",\"http://192.168.0.34/phpma\",\"john\",\"john@company.com\",\"doe\",\"\",\"db,mydb\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"10-01-2014\"\n" +
|
||||
"\"Software\",\"Server admin\",\"192.168.0.34\",\"admin\",\"\",\"test\",\"sample notes\",\"tag1,tag2\",\"custom1,custom2\",\"custom value 1\",\"custom value 2\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"\n" +
|
||||
"\"Hardware\",\"Router\",\"192.168.0.1\",\"admin\",\"\",\"easypwd\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"10-30-2015\"\n" +
|
||||
"\"Hardware\",\"Server room code\",\"\",\"\",\"\",\"1234\",\"\",\"pin\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\""
|
||||
|
||||
|
||||
var output = importTeampassNetCsv.parser(input);
|
||||
|
||||
var expected_output = {
|
||||
const output = importTeampassNetCsv.parser(input);
|
||||
|
||||
const expected_output = {
|
||||
"datastore": {
|
||||
"id": generic_uuid,
|
||||
"name": output.datastore.name,
|
||||
|
35
src/js/services/item-blueprint.js
Normal file
35
src/js/services/item-blueprint.js
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* linkShare collects all functions to edit / update / create link shares and to work with them.
|
||||
*/
|
||||
|
||||
import helperService from "./helper";
|
||||
import store from "./store";
|
||||
|
||||
const _entryTypes = [
|
||||
{ value: "website_password", title: "WEBSITE_PASSWORD", edit_title: "EDIT_WEBSITE_PASSWORD" },
|
||||
{ value: "application_password", title: "APPLICATION_PASSWORD", edit_title: "EDIT_APPLICATION_PASSWORD" },
|
||||
{ value: "totp", title: "TOTP_AUTHENTICATOR", edit_title: "EDIT_TOTP_AUTHENTICATOR" },
|
||||
{ value: "note", title: "NOTE", edit_title: "EDIT_NOTE" },
|
||||
{ value: "environment_variables", title: "ENVIRONMENT_VARIABLES", edit_title: "EDIT_ENVIRONMENT_VARIABLES" },
|
||||
{ value: "mail_gpg_own_key", title: "GPG_KEY", edit_title: "EDIT_GPG_KEY" },
|
||||
{ value: "bookmark", title: "BOOKMARK", edit_title: "EDIT_BOOKMARK" },
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns all entry types
|
||||
*
|
||||
* @returns {array} List of all entry types
|
||||
*/
|
||||
function getEntryTypes() {
|
||||
const entryTypes = helperService.duplicateObject(_entryTypes);
|
||||
|
||||
if (store.getState().server.files) {
|
||||
entryTypes.push({ value: "file", title: "FILE", edit_title: "EDIT_FILE" });
|
||||
}
|
||||
return entryTypes;
|
||||
}
|
||||
|
||||
const itemBlueprintService = {
|
||||
getEntryTypes: getEntryTypes,
|
||||
};
|
||||
export default itemBlueprintService;
|
@ -62,9 +62,9 @@ function readLinkShares() {
|
||||
*/
|
||||
function readSecretWithLinkShare(encryptedSecret, shareLinkData) {
|
||||
// normal secret
|
||||
var secret_data = JSON.parse(cryptoLibrary.decrypt_data(encryptedSecret.secret_data, encryptedSecret.secret_data_nonce, shareLinkData.secret_key));
|
||||
const secret_data = JSON.parse(cryptoLibrary.decrypt_data(encryptedSecret.secret_data, encryptedSecret.secret_data_nonce, shareLinkData.secret_key));
|
||||
|
||||
var modalInstance = $uibModal.open({
|
||||
const modalInstance = $uibModal.open({
|
||||
templateUrl: "view/modal/show-entry.html",
|
||||
controller: "ModalEditEntryCtrl",
|
||||
backdrop: "static",
|
||||
@ -114,7 +114,7 @@ function readFileWithLinkShare(encryptedFileMeta, shareLinkData) {
|
||||
*/
|
||||
function linkShareAccess(linkShareId, linkShareSecret, passphrase) {
|
||||
const onSuccess = function (result) {
|
||||
var share_link_data = JSON.parse(cryptoLibrary.decrypt_data(result.data.node, result.data.node_nonce, linkShareSecret));
|
||||
const share_link_data = JSON.parse(cryptoLibrary.decrypt_data(result.data.node, result.data.node_nonce, linkShareSecret));
|
||||
|
||||
if (share_link_data.type === "file") {
|
||||
return readFileWithLinkShare(result.data, share_link_data);
|
||||
|
@ -64,7 +64,7 @@ function push(notificationType, notificationContent) {
|
||||
}
|
||||
}
|
||||
|
||||
const service = {
|
||||
const notificationService = {
|
||||
infoSend,
|
||||
errorSend,
|
||||
reset,
|
||||
@ -72,4 +72,4 @@ const service = {
|
||||
push,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default notificationService;
|
||||
|
@ -225,7 +225,7 @@ function onSetEncryptionKey(fnc) {
|
||||
onSetEncryptionKeyRegistrations.push(fnc);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const offlineCacheService = {
|
||||
isActive: isActive,
|
||||
get: get,
|
||||
set: set,
|
||||
@ -240,4 +240,4 @@ const service = {
|
||||
save: save,
|
||||
onSetEncryptionKey: onSetEncryptionKey,
|
||||
};
|
||||
export default service;
|
||||
export default offlineCacheService;
|
||||
|
@ -38,8 +38,8 @@ function recoveryGenerateInformation() {
|
||||
return apiClient.writeRecoverycode(token, sessionSecretKey, recoveryAuthkey, recovery_data.text, recovery_data.nonce, recoverySauce).then(onSuccess);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const passwordRecoveryCodeService = {
|
||||
recoveryGenerateInformation,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default passwordRecoveryCodeService;
|
||||
|
@ -133,7 +133,7 @@ function onSecretDeleted(linkId) {
|
||||
return deleteSecretLink(linkId);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const secretLinkService = {
|
||||
moveSecretLinks: moveSecretLinks,
|
||||
resetSecretLinkTimeout: resetSecretLinkTimeout,
|
||||
moveSecretLink: moveSecretLink,
|
||||
@ -141,4 +141,4 @@ const service = {
|
||||
onSecretMoved: onSecretMoved,
|
||||
onSecretDeleted: onSecretDeleted,
|
||||
};
|
||||
export default service;
|
||||
export default secretLinkService;
|
||||
|
@ -172,7 +172,7 @@ function redirectSecret(type, secretId) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles item clicks and triggers behaviour
|
||||
* Handles item clicks and triggers redirects for website passwords and bookmarks
|
||||
*
|
||||
* @param {object} item The item one has clicked on
|
||||
*/
|
||||
|
@ -305,7 +305,7 @@ function register(key, func) {
|
||||
registrations[key] = func;
|
||||
}
|
||||
|
||||
const service = {
|
||||
const settingsService = {
|
||||
getSetting: getSetting,
|
||||
getSettings: getSettings,
|
||||
setSettings: setSettings,
|
||||
@ -313,4 +313,4 @@ const service = {
|
||||
register: register,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default settingsService;
|
||||
|
@ -3,18 +3,21 @@
|
||||
*/
|
||||
|
||||
import apiClient from "./api-client";
|
||||
import store from "./store";
|
||||
|
||||
/**
|
||||
* Create a link between a share and a datastore or another (parent-)share
|
||||
*
|
||||
* @param {uuid} link_id the link id
|
||||
* @param {uuid} share_id the share ID
|
||||
* @param {uuid|undefined} [parent_share_id=null] (optional) parent share ID, necessary if no datastore_id is provided
|
||||
* @param {uuid|undefined} [parent_datastore_id=null] (optional) datastore ID, necessary if no parent_share_id is provided
|
||||
* @param {uuid} linkId the link id
|
||||
* @param {uuid} shareId the share ID
|
||||
* @param {uuid|undefined} [parentShareId=null] (optional) parent share ID, necessary if no datastore_id is provided
|
||||
* @param {uuid|undefined} [parentDatastoreId=null] (optional) datastore ID, necessary if no parentShareId is provided
|
||||
*
|
||||
* @returns {promise} Returns a promise withe the new share link id
|
||||
*/
|
||||
function createShareLink(link_id, share_id, parent_share_id, parent_datastore_id) {
|
||||
function createShareLink(linkId, shareId, parentShareId, parentDatastoreId) {
|
||||
const token = store.getState().user.token;
|
||||
const sessionSecretKey = store.getState().user.sessionSecretKey;
|
||||
const onError = function (result) {
|
||||
// pass
|
||||
};
|
||||
@ -23,21 +26,21 @@ function createShareLink(link_id, share_id, parent_share_id, parent_datastore_id
|
||||
return result;
|
||||
};
|
||||
|
||||
return apiClient
|
||||
.createShareLink(managerBase.get_token(), managerBase.get_session_secret_key(), link_id, share_id, parent_share_id, parent_datastore_id)
|
||||
.then(onSuccess, onError);
|
||||
return apiClient.createShareLink(token, sessionSecretKey, linkId, shareId, parentShareId, parentDatastoreId).then(onSuccess, onError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a link between a share and a datastore or another (parent-)share
|
||||
*
|
||||
* @param {uuid} link_id The link id
|
||||
* @param {uuid|undefined} [new_parent_share_id] (optional) new parent share ID, necessary if no new_datastore_id is provided
|
||||
* @param {uuid|undefined} [new_parent_datastore_id] (optional) new datastore ID, necessary if no new_parent_share_id is provided
|
||||
* @param {uuid} linkId The link id
|
||||
* @param {uuid|undefined} [newParentShareId] (optional) new parent share ID, necessary if no new_datastore_id is provided
|
||||
* @param {uuid|undefined} [newParentDatastoreId] (optional) new datastore ID, necessary if no newParentShareId is provided
|
||||
*
|
||||
* @returns {promise} Returns a promise with the status of the move
|
||||
*/
|
||||
function moveShareLink(link_id, new_parent_share_id, new_parent_datastore_id) {
|
||||
function moveShareLink(linkId, newParentShareId, newParentDatastoreId) {
|
||||
const token = store.getState().user.token;
|
||||
const sessionSecretKey = store.getState().user.sessionSecretKey;
|
||||
const onError = function (result) {
|
||||
// pass
|
||||
};
|
||||
@ -46,18 +49,18 @@ function moveShareLink(link_id, new_parent_share_id, new_parent_datastore_id) {
|
||||
return result;
|
||||
};
|
||||
|
||||
return apiClient
|
||||
.moveShareLink(managerBase.get_token(), managerBase.get_session_secret_key(), link_id, new_parent_share_id, new_parent_datastore_id)
|
||||
.then(onSuccess, onError);
|
||||
return apiClient.moveShareLink(token, sessionSecretKey, linkId, newParentShareId, newParentDatastoreId).then(onSuccess, onError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a share link
|
||||
*
|
||||
* @param {uuid} link_id The link id one wants to delete
|
||||
* @param {uuid} linkId The link id one wants to delete
|
||||
* @returns {promise} Returns a promise with the status of the delete operation
|
||||
*/
|
||||
function deleteShareLink(link_id) {
|
||||
function deleteShareLink(linkId) {
|
||||
const token = store.getState().user.token;
|
||||
const sessionSecretKey = store.getState().user.sessionSecretKey;
|
||||
const onError = function (result) {
|
||||
// pass
|
||||
};
|
||||
@ -66,19 +69,19 @@ function deleteShareLink(link_id) {
|
||||
return result;
|
||||
};
|
||||
|
||||
return apiClient.deleteShareLink(managerBase.get_token(), managerBase.get_session_secret_key(), link_id).then(onSuccess, onError);
|
||||
return apiClient.deleteShareLink(token, sessionSecretKey, linkId).then(onSuccess, onError);
|
||||
}
|
||||
|
||||
/**
|
||||
* triggered once a share moved. handles the update of links
|
||||
*
|
||||
* @param {uuid} link_id The link id that has moved
|
||||
* @param {uuid} linkId The link id that has moved
|
||||
* @param {TreeObject} parent The parent (either a share or a datastore)
|
||||
*
|
||||
* @returns {promise} Returns a promise with the status of the move
|
||||
*/
|
||||
function onShareMoved(link_id, parent) {
|
||||
var new_parent_share_id = undefined,
|
||||
function onShareMoved(linkId, parent) {
|
||||
let new_parent_share_id = undefined,
|
||||
new_parent_datastore_id = undefined;
|
||||
|
||||
if (parent.hasOwnProperty("share_id")) {
|
||||
@ -92,7 +95,7 @@ function onShareMoved(link_id, parent) {
|
||||
});
|
||||
}
|
||||
|
||||
return moveShareLink(link_id, new_parent_share_id, new_parent_datastore_id);
|
||||
return moveShareLink(linkId, new_parent_share_id, new_parent_datastore_id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,11 +107,11 @@ function onShareDeleted(link_id) {
|
||||
return deleteShareLink(link_id);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const shareLinkService = {
|
||||
createShareLink: createShareLink,
|
||||
moveShareLink: moveShareLink,
|
||||
deleteShareLink: deleteShareLink,
|
||||
onShareMoved: onShareMoved,
|
||||
onShareDeleted: onShareDeleted,
|
||||
};
|
||||
export default service;
|
||||
export default shareLinkService;
|
||||
|
@ -322,7 +322,7 @@ function deleteShareRight(userShareRightId, groupShareRightId) {
|
||||
* @returns {object} The decrypted share
|
||||
*/
|
||||
function decryptShare(encryptedShare, secretKey) {
|
||||
const share = {};
|
||||
let share = {};
|
||||
|
||||
if (typeof encryptedShare.share_data !== "undefined") {
|
||||
share = JSON.parse(cryptoLibrary.decryptData(encryptedShare.share_data, encryptedShare.share_data_nonce, secretKey));
|
||||
@ -469,7 +469,7 @@ function register(key, func) {
|
||||
// itemBlueprint.register('create_share_right', create_share_right);
|
||||
// itemBlueprint.register('get_closest_parent_share', get_closest_parent_share);
|
||||
|
||||
const service = {
|
||||
const shareService = {
|
||||
readShare: readShare,
|
||||
readShares: readShares,
|
||||
writeShare: writeShare,
|
||||
@ -485,4 +485,4 @@ const service = {
|
||||
getClosestParentShare: getClosestParentShare,
|
||||
register: register,
|
||||
};
|
||||
export default service;
|
||||
export default shareService;
|
||||
|
@ -270,7 +270,7 @@ function emit(key, payload) {
|
||||
}
|
||||
}
|
||||
|
||||
const service = {
|
||||
const storageService = {
|
||||
insert: insert,
|
||||
update: update,
|
||||
upsert: upsert,
|
||||
@ -285,4 +285,4 @@ const service = {
|
||||
register: register,
|
||||
emit: emit,
|
||||
};
|
||||
export default service;
|
||||
export default storageService;
|
||||
|
@ -615,8 +615,8 @@ function updateUser(email, authkey, authkeyOld, privateKey, privateKeyNonce, sec
|
||||
function saveNewPassword(newPassword, newPasswordRepeat, oldPassword) {
|
||||
return host.info().then(
|
||||
function (info) {
|
||||
var authkeyOld, newAuthkey, userPrivateKey, userSecretKey, userSauce, privKeyEnc, secretKeyEnc, onSuccess, onError;
|
||||
var test_error = helperService.isValidPassword(
|
||||
let authkeyOld, newAuthkey, userPrivateKey, userSecretKey, userSauce, privKeyEnc, secretKeyEnc, onSuccess, onError;
|
||||
const test_error = helperService.isValidPassword(
|
||||
newPassword,
|
||||
newPasswordRepeat,
|
||||
info.data["decoded_info"]["compliance_min_master_password_length"],
|
||||
@ -695,7 +695,7 @@ function recoveryEnable(username, recoveryCode, server) {
|
||||
action.setServerUrl(server);
|
||||
|
||||
const onSuccess = function (data) {
|
||||
var recovery_data = JSON.parse(
|
||||
const recovery_data = JSON.parse(
|
||||
cryptoLibrary.decryptSecret(data.data.recovery_data, data.data.recovery_data_nonce, recoveryCode, data.data.recovery_sauce)
|
||||
);
|
||||
|
||||
@ -747,7 +747,7 @@ function setPassword(username, recoveryCode, password, userPrivateKey, userSecre
|
||||
return data;
|
||||
};
|
||||
|
||||
var recovery_authkey = cryptoLibrary.generateAuthkey(username, recoveryCode);
|
||||
const recovery_authkey = cryptoLibrary.generateAuthkey(username, recoveryCode);
|
||||
|
||||
return apiClientService.setPassword(username, recovery_authkey, updateRequestEnc.text, updateRequestEnc.nonce).then(onSuccess, onError);
|
||||
}
|
||||
@ -796,7 +796,7 @@ function armEmergencyCode(username, emergencyCode, server, serverInfo, verifyKey
|
||||
const update_request_enc = cryptoLibrary.encryptDataPublicKey(loginInfo, data.data.verifier_public_key, emergency_data.user_private_key);
|
||||
|
||||
const onSuccess = function (data) {
|
||||
var loginInfo = JSON.parse(
|
||||
const loginInfo = JSON.parse(
|
||||
cryptoLibrary.decryptDataPublicKey(data.data.login_info, data.data.login_info_nonce, serverInfo["public_key"], sessionKey.private_key)
|
||||
);
|
||||
|
||||
@ -856,7 +856,7 @@ function deleteSession(sessionId) {
|
||||
return apiClientService.logout(token, sessionSecretKey, sessionId).then(onSuccess, onError);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const userService = {
|
||||
initiateLogin,
|
||||
samlLogin,
|
||||
initiateSamlLogin,
|
||||
@ -885,4 +885,4 @@ const service = {
|
||||
deleteSession,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default userService;
|
||||
|
@ -17,15 +17,15 @@ import datastoreUserService from "./datastore-user";
|
||||
*
|
||||
* @param {TreeObject} parent The parent of the new folder
|
||||
* @param {Array} path The path to the parent of the new folder
|
||||
* @param {TreeObject} data_structure the data structure
|
||||
* @param {TreeObject} dataStructure the data structure
|
||||
* @param {Object} manager manager responsible for
|
||||
* @param {String} name The name of the new folder
|
||||
*/
|
||||
function openNewFolder(parent, path, data_structure, manager, name) {
|
||||
function openNewFolder(parent, path, dataStructure, manager, name) {
|
||||
let onSuccess, onError;
|
||||
|
||||
if (typeof parent === "undefined") {
|
||||
parent = data_structure;
|
||||
parent = dataStructure;
|
||||
}
|
||||
|
||||
if (typeof parent.folders === "undefined") {
|
||||
@ -41,7 +41,7 @@ function openNewFolder(parent, path, data_structure, manager, name) {
|
||||
|
||||
parent["expanded"] = true;
|
||||
|
||||
const closest_share_info = shareService.getClosestParentShare(path.slice(), data_structure, data_structure, 0);
|
||||
const closest_share_info = shareService.getClosestParentShare(path.slice(), dataStructure, dataStructure, 0);
|
||||
|
||||
const closest_share = closest_share_info["closest_share"];
|
||||
|
||||
@ -67,7 +67,7 @@ function openNewFolder(parent, path, data_structure, manager, name) {
|
||||
};
|
||||
}
|
||||
|
||||
datastorePasswordService.updatePathsRecursive(data_structure, []);
|
||||
datastorePasswordService.updatePathsRecursive(dataStructure, []);
|
||||
|
||||
if (closest_share.hasOwnProperty("share_id")) {
|
||||
// refresh share content before updating the share
|
||||
@ -86,7 +86,7 @@ function openNewFolder(parent, path, data_structure, manager, name) {
|
||||
parent.folders.push(datastore_object);
|
||||
shareService.writeShare(closest_share["share_id"], content.data, closest_share["share_secret_key"]);
|
||||
|
||||
manager.handleDatastoreContentChanged(data_structure);
|
||||
manager.handleDatastoreContentChanged(dataStructure);
|
||||
};
|
||||
|
||||
onError = function (e) {
|
||||
@ -114,7 +114,7 @@ function openNewFolder(parent, path, data_structure, manager, name) {
|
||||
parent.folders.push(datastore_object);
|
||||
manager.saveDatastoreContent(datastore, [path]);
|
||||
|
||||
manager.handleDatastoreContentChanged(data_structure);
|
||||
manager.handleDatastoreContentChanged(dataStructure);
|
||||
};
|
||||
|
||||
return manager.getDatastoreWithId(closest_share["datastore_id"]).then(onSuccess, onError);
|
||||
@ -126,82 +126,56 @@ function openNewFolder(parent, path, data_structure, manager, name) {
|
||||
*
|
||||
* @param {object} node The node you want to edit
|
||||
* @param {Array} path The path to the node
|
||||
* @param {TreeObject} data_structure the data structure
|
||||
* @param {TreeObject} dataStructure the data structure
|
||||
* @param {Object} manager manager responsible for
|
||||
* @param {string} size The size of the modal
|
||||
*/
|
||||
function openEditFolder(node, path, data_structure, manager, size) {
|
||||
const modalInstance = $uibModal.open({
|
||||
templateUrl: "view/modal/edit-folder.html",
|
||||
controller: "ModalEditFolderCtrl",
|
||||
backdrop: "static",
|
||||
size: size,
|
||||
resolve: {
|
||||
node: function () {
|
||||
return node;
|
||||
},
|
||||
path: function () {
|
||||
return path;
|
||||
},
|
||||
},
|
||||
});
|
||||
function openEditFolder(node, path, dataStructure, manager) {
|
||||
let onSuccess, onError;
|
||||
|
||||
modalInstance.result.then(
|
||||
function (name) {
|
||||
let onSuccess, onError;
|
||||
const closest_share_info = shareService.getClosestParentShare(path.slice(), dataStructure, dataStructure, 0);
|
||||
const closest_share = closest_share_info["closest_share"];
|
||||
|
||||
// change visual representation
|
||||
node.name = name;
|
||||
|
||||
const closest_share_info = shareService.getClosestParentShare(path.slice(), data_structure, data_structure, 0);
|
||||
const closest_share = closest_share_info["closest_share"];
|
||||
|
||||
if (closest_share.hasOwnProperty("share_id")) {
|
||||
// refresh share content before updating the share
|
||||
onSuccess = function (content) {
|
||||
let folder;
|
||||
if (closest_share_info["relative_path"].length === 0) {
|
||||
folder = content.data;
|
||||
} else {
|
||||
const search = datastorePasswordService.findInDatastore(closest_share_info["relative_path"], content.data);
|
||||
folder = search[0][search[1]];
|
||||
}
|
||||
folder.name = name;
|
||||
shareService.writeShare(closest_share["share_id"], content.data, closest_share["share_secret_key"]);
|
||||
manager.handleDatastoreContentChanged(data_structure);
|
||||
};
|
||||
|
||||
onError = function (e) {
|
||||
// pass
|
||||
};
|
||||
shareService.readShare(closest_share["share_id"], closest_share["share_secret_key"]).then(onSuccess, onError);
|
||||
if (closest_share.hasOwnProperty("share_id")) {
|
||||
// refresh share content before updating the share
|
||||
onSuccess = function (content) {
|
||||
let folder;
|
||||
if (closest_share_info["relative_path"].length === 0) {
|
||||
folder = content.data;
|
||||
} else {
|
||||
// refresh datastore content before updating it
|
||||
onError = function (result) {
|
||||
// pass
|
||||
};
|
||||
|
||||
onSuccess = function (datastore) {
|
||||
let folder;
|
||||
if (closest_share_info["relative_path"].length === 0) {
|
||||
folder = datastore;
|
||||
} else {
|
||||
const search = datastorePasswordService.findInDatastore(closest_share_info["relative_path"], datastore);
|
||||
folder = search[0][search[1]];
|
||||
}
|
||||
|
||||
folder.name = name;
|
||||
manager.saveDatastoreContent(datastore, [path]);
|
||||
manager.handleDatastoreContentChanged(data_structure);
|
||||
};
|
||||
|
||||
return datastoreService.getDatastoreWithId(closest_share["datastore_id"]).then(onSuccess, onError);
|
||||
const search = datastorePasswordService.findInDatastore(closest_share_info["relative_path"], content.data);
|
||||
folder = search[0][search[1]];
|
||||
}
|
||||
},
|
||||
function () {
|
||||
// cancel triggered
|
||||
}
|
||||
);
|
||||
folder.name = node.name;
|
||||
shareService.writeShare(closest_share["share_id"], content.data, closest_share["share_secret_key"]);
|
||||
manager.handleDatastoreContentChanged(dataStructure);
|
||||
};
|
||||
|
||||
onError = function (e) {
|
||||
// pass
|
||||
};
|
||||
shareService.readShare(closest_share["share_id"], closest_share["share_secret_key"]).then(onSuccess, onError);
|
||||
} else {
|
||||
// refresh datastore content before updating it
|
||||
onError = function (result) {
|
||||
// pass
|
||||
};
|
||||
|
||||
onSuccess = function (datastore) {
|
||||
let folder;
|
||||
if (closest_share_info["relative_path"].length === 0) {
|
||||
folder = datastore;
|
||||
} else {
|
||||
const search = datastorePasswordService.findInDatastore(closest_share_info["relative_path"], datastore);
|
||||
folder = search[0][search[1]];
|
||||
}
|
||||
|
||||
folder.name = node.name;
|
||||
manager.saveDatastoreContent(datastore, [path]);
|
||||
manager.handleDatastoreContentChanged(dataStructure);
|
||||
};
|
||||
|
||||
return datastoreService.getDatastoreWithId(closest_share["datastore_id"]).then(onSuccess, onError);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -274,11 +248,11 @@ function openNewItem(datastore, parent, path, size, manager) {
|
||||
// pass
|
||||
};
|
||||
|
||||
var closest_share_info = shareService.getClosestParentShare(path.slice(), datastore, datastore, 0);
|
||||
const closest_share_info = shareService.getClosestParentShare(path.slice(), datastore, datastore, 0);
|
||||
|
||||
var closest_share = closest_share_info["closest_share"];
|
||||
const closest_share = closest_share_info["closest_share"];
|
||||
|
||||
var parent_share_id, parent_datastore_id;
|
||||
let parent_share_id, parent_datastore_id;
|
||||
|
||||
if (closest_share.hasOwnProperty("share_id")) {
|
||||
parent_share_id = closest_share["share_id"];
|
||||
@ -304,7 +278,7 @@ function openNewItem(datastore, parent, path, size, manager) {
|
||||
};
|
||||
}
|
||||
|
||||
var save_datastore = function () {
|
||||
const save_datastore = function () {
|
||||
let onSuccess, onError;
|
||||
|
||||
// update visual representation
|
||||
@ -318,11 +292,11 @@ function openNewItem(datastore, parent, path, size, manager) {
|
||||
if (closest_share.hasOwnProperty("share_id")) {
|
||||
// refresh share content before updating the share
|
||||
onSuccess = function (content) {
|
||||
var parent;
|
||||
let parent;
|
||||
if (closest_share_info["relative_path"].length === 0) {
|
||||
parent = content.data;
|
||||
} else {
|
||||
var search = datastorePasswordService.findInDatastore(closest_share_info["relative_path"], content.data);
|
||||
const search = datastorePasswordService.findInDatastore(closest_share_info["relative_path"], content.data);
|
||||
parent = search[0][search[1]];
|
||||
}
|
||||
|
||||
@ -346,11 +320,11 @@ function openNewItem(datastore, parent, path, size, manager) {
|
||||
};
|
||||
|
||||
onSuccess = function (datastore) {
|
||||
var parent;
|
||||
let parent;
|
||||
if (closest_share_info["relative_path"].length === 0) {
|
||||
parent = datastore;
|
||||
} else {
|
||||
var search = datastorePasswordService.findInDatastore(closest_share_info["relative_path"], datastore);
|
||||
const search = datastorePasswordService.findInDatastore(closest_share_info["relative_path"], datastore);
|
||||
parent = search[0][search[1]];
|
||||
}
|
||||
|
||||
@ -420,7 +394,7 @@ function openEditItem(datastore, node, path, size, manager) {
|
||||
const onSuccess = function (data) {
|
||||
function onSave(new_content) {
|
||||
// update visual representation
|
||||
var secret_object = {};
|
||||
const secret_object = {};
|
||||
for (let i = new_content.fields.length - 1; i >= 0; i--) {
|
||||
if (!new_content.fields[i].hasOwnProperty("value")) {
|
||||
continue;
|
||||
@ -444,14 +418,14 @@ function openEditItem(datastore, node, path, size, manager) {
|
||||
const onSuccess = function (e) {
|
||||
let onSuccess, onError;
|
||||
|
||||
var closest_share_info = shareService.getClosestParentShare(path.slice(), datastore, datastore, 0);
|
||||
const closest_share_info = shareService.getClosestParentShare(path.slice(), datastore, datastore, 0);
|
||||
|
||||
var closest_share = closest_share_info["closest_share"];
|
||||
const closest_share = closest_share_info["closest_share"];
|
||||
|
||||
if (closest_share.hasOwnProperty("share_id")) {
|
||||
// refresh share content before updating the share
|
||||
onSuccess = function (content) {
|
||||
var search = datastorePasswordService.findInDatastore(closest_share_info["relative_path"], content.data);
|
||||
const search = datastorePasswordService.findInDatastore(closest_share_info["relative_path"], content.data);
|
||||
node = search[0][search[1]];
|
||||
|
||||
for (let i = new_content.fields.length - 1; i >= 0; i--) {
|
||||
@ -730,17 +704,17 @@ function check_if_parent_changed(element, target) {
|
||||
* Move an item (or folder) from one position to anther
|
||||
*
|
||||
* @param {TreeObject} datastore The datastore
|
||||
* @param {Array} item_path the current path of the item
|
||||
* @param {Array} target_path the path where we want to put the item
|
||||
* @param {Array} itemPath the current path of the item
|
||||
* @param {Array} targetPath the path where we want to put the item
|
||||
* @param {string} type type of the item ('items' or 'folders')
|
||||
* @param {string} datastore_type The type of the datastore (e.g. 'password' or 'user')
|
||||
* @param {string} datastoreType The type of the datastore (e.g. 'password' or 'user')
|
||||
*/
|
||||
function moveItem(datastore, item_path, target_path, type, datastore_type) {
|
||||
function moveItem(datastore, itemPath, targetPath, type, datastoreType) {
|
||||
let i;
|
||||
let closest_parent;
|
||||
let closest_share_info;
|
||||
|
||||
const orig_item_path = item_path.slice();
|
||||
const orig_item_path = itemPath.slice();
|
||||
orig_item_path.pop();
|
||||
|
||||
let orig_target_path;
|
||||
@ -750,23 +724,23 @@ function moveItem(datastore, item_path, target_path, type, datastore_type) {
|
||||
}
|
||||
|
||||
const onSuccess = function (datastore) {
|
||||
if (target_path === null || typeof target_path === "undefined") {
|
||||
if (targetPath === null || typeof targetPath === "undefined") {
|
||||
orig_target_path = [];
|
||||
} else {
|
||||
orig_target_path = target_path.slice();
|
||||
orig_target_path = targetPath.slice();
|
||||
}
|
||||
|
||||
let target = datastore;
|
||||
if (target_path !== null && typeof target_path !== "undefined") {
|
||||
if (targetPath !== null && typeof targetPath !== "undefined") {
|
||||
// find drop zone
|
||||
const val1 = datastorePasswordService.findInDatastore(target_path, datastore);
|
||||
const val1 = datastorePasswordService.findInDatastore(targetPath, datastore);
|
||||
target = val1[0][val1[1]];
|
||||
}
|
||||
|
||||
let element;
|
||||
// find element
|
||||
try {
|
||||
const val2 = datastorePasswordService.findInDatastore(item_path, datastore);
|
||||
const val2 = datastorePasswordService.findInDatastore(itemPath, datastore);
|
||||
element = val2[0][val2[1]];
|
||||
} catch (e) {
|
||||
return;
|
||||
@ -824,7 +798,7 @@ function moveItem(datastore, item_path, target_path, type, datastore_type) {
|
||||
datastorePasswordService.updatePathsRecursive(datastore, []);
|
||||
|
||||
// and save everything (before we update the links and might lose some necessary rights)
|
||||
if (datastore_type === "password") {
|
||||
if (datastoreType === "password") {
|
||||
datastorePasswordService.handleDatastoreContentChanged(datastore);
|
||||
datastorePasswordService.saveDatastoreContent(datastore, [orig_item_path, orig_target_path]);
|
||||
} else {
|
||||
@ -893,7 +867,7 @@ function moveItem(datastore, item_path, target_path, type, datastore_type) {
|
||||
datastorePasswordService.updateParents(element, new_parent_share_id, new_parent_datastore_id);
|
||||
};
|
||||
|
||||
if (datastore_type === "password") {
|
||||
if (datastoreType === "password") {
|
||||
return datastorePasswordService.getPasswordDatastore(datastore.datastore_id).then(onSuccess);
|
||||
} else {
|
||||
return datastoreService.getDatastoreWithId(datastore.datastore_id).then(onSuccess);
|
||||
@ -912,13 +886,13 @@ function moveItem(datastore, item_path, target_path, type, datastore_type) {
|
||||
* @param {TreeObject} datastore The datastore
|
||||
* @param {object} item The item to delete
|
||||
* @param {Array} path The path to the item
|
||||
* @param {string} datastore_type The type of the datastore (e.g. 'password' or 'user')
|
||||
* @param {string} datastoreType The type of the datastore (e.g. 'password' or 'user')
|
||||
*/
|
||||
function deleteItem(datastore, item, path, datastore_type) {
|
||||
if (datastore_type === "user" || (item.hasOwnProperty("deleted") && item["deleted"])) {
|
||||
delete_item_permanent(datastore, item, path, datastore_type);
|
||||
function deleteItem(datastore, item, path, datastoreType) {
|
||||
if (datastoreType === "user" || (item.hasOwnProperty("deleted") && item["deleted"])) {
|
||||
deleteItemPermanent(datastore, item, path, datastoreType);
|
||||
} else {
|
||||
mark_item_as_deleted(datastore, item, path, datastore_type);
|
||||
markItemAsDeleted(datastore, item, path, datastoreType);
|
||||
}
|
||||
}
|
||||
|
||||
@ -928,9 +902,9 @@ function deleteItem(datastore, item, path, datastore_type) {
|
||||
* @param {TreeObject} datastore The datastore
|
||||
* @param {object} item The item to delete
|
||||
* @param {Array} path The path to the item
|
||||
* @param {string} datastore_type The type of the datastore (e.g. 'password' or 'user')
|
||||
* @param {string} datastoreType The type of the datastore (e.g. 'password' or 'user')
|
||||
*/
|
||||
function mark_item_as_deleted(datastore, item, path, datastore_type) {
|
||||
function markItemAsDeleted(datastore, item, path, datastoreType) {
|
||||
let onSuccess, onError;
|
||||
const element_path_that_changed = path.slice();
|
||||
element_path_that_changed.pop();
|
||||
@ -944,7 +918,7 @@ function mark_item_as_deleted(datastore, item, path, datastore_type) {
|
||||
|
||||
const closest_share = closest_share_info["closest_share"];
|
||||
|
||||
if (datastore_type === "password") {
|
||||
if (datastoreType === "password") {
|
||||
if (closest_share.hasOwnProperty("share_id")) {
|
||||
// refresh share content before updating the share
|
||||
onSuccess = function (content) {
|
||||
@ -979,7 +953,7 @@ function mark_item_as_deleted(datastore, item, path, datastore_type) {
|
||||
|
||||
datastoreService.getDatastoreWithId(closest_share["datastore_id"]).then(onSuccess, onError);
|
||||
}
|
||||
} else if (datastore_type === "user") {
|
||||
} else if (datastoreType === "user") {
|
||||
datastoreUserService.saveDatastoreContent(datastore, [element_path_that_changed]);
|
||||
}
|
||||
}
|
||||
@ -990,9 +964,9 @@ function mark_item_as_deleted(datastore, item, path, datastore_type) {
|
||||
* @param {TreeObject} datastore The datastore
|
||||
* @param {object} item The item to delete
|
||||
* @param {Array} path The path to the item
|
||||
* @param {string} datastore_type The type of the datastore (e.g. 'password' or 'user')
|
||||
* @param {string} datastoreType The type of the datastore (e.g. 'password' or 'user')
|
||||
*/
|
||||
function reverseMarkItemAsDeleted(datastore, item, path, datastore_type) {
|
||||
function reverseMarkItemAsDeleted(datastore, item, path, datastoreType) {
|
||||
let onSuccess, onError;
|
||||
const element_path_that_changed = path.slice();
|
||||
element_path_that_changed.pop();
|
||||
@ -1006,7 +980,7 @@ function reverseMarkItemAsDeleted(datastore, item, path, datastore_type) {
|
||||
|
||||
const closest_share = closest_share_info["closest_share"];
|
||||
|
||||
if (datastore_type === "password") {
|
||||
if (datastoreType === "password") {
|
||||
if (closest_share.hasOwnProperty("share_id")) {
|
||||
// refresh share content before updating the share
|
||||
onSuccess = function (content) {
|
||||
@ -1041,7 +1015,7 @@ function reverseMarkItemAsDeleted(datastore, item, path, datastore_type) {
|
||||
|
||||
datastoreService.getDatastoreWithId(closest_share["datastore_id"]).then(onSuccess, onError);
|
||||
}
|
||||
} else if (datastore_type === "user") {
|
||||
} else if (datastoreType === "user") {
|
||||
datastoreUserService.saveDatastoreContent(datastore, [element_path_that_changed]);
|
||||
}
|
||||
}
|
||||
@ -1197,9 +1171,9 @@ function cloneItem(datastore, item, path) {
|
||||
* @param {TreeObject} datastore The datastore
|
||||
* @param {object} item The item to delete
|
||||
* @param {Array} path The path to the item
|
||||
* @param {string} datastore_type The type of the datastore (e.g. 'password' or 'user')
|
||||
* @param {string} datastoreType The type of the datastore (e.g. 'password' or 'user')
|
||||
*/
|
||||
function delete_item_permanent(datastore, item, path, datastore_type) {
|
||||
function deleteItemPermanent(datastore, item, path, datastoreType) {
|
||||
let i;
|
||||
let onSuccess, onError;
|
||||
|
||||
@ -1222,7 +1196,7 @@ function delete_item_permanent(datastore, item, path, datastore_type) {
|
||||
const child_shares = [];
|
||||
|
||||
// and save everything (before we update the links and might lose some necessary rights)
|
||||
if (datastore_type === "password") {
|
||||
if (datastoreType === "password") {
|
||||
if (closest_share.hasOwnProperty("share_id")) {
|
||||
// refresh share content before updating the share
|
||||
onSuccess = function (content) {
|
||||
@ -1372,7 +1346,7 @@ function delete_item_permanent(datastore, item, path, datastore_type) {
|
||||
|
||||
return datastoreService.getDatastoreWithId(closest_share["datastore_id"]).then(onSuccess, onError);
|
||||
}
|
||||
} else if (datastore_type === "user") {
|
||||
} else if (datastoreType === "user") {
|
||||
return datastoreUserService.saveDatastoreContent(datastore, [element_path_that_changed]);
|
||||
}
|
||||
}
|
||||
@ -1514,7 +1488,7 @@ function itemIcon(item) {
|
||||
return iconClassMap[ext] || defaultIconClass;
|
||||
}
|
||||
|
||||
const service = {
|
||||
const widgetService = {
|
||||
openNewFolder: openNewFolder,
|
||||
openEditFolder: openEditFolder,
|
||||
findInStructure: findInStructure,
|
||||
@ -1527,4 +1501,4 @@ const service = {
|
||||
itemIcon: itemIcon,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default widgetService;
|
||||
|
@ -86,11 +86,11 @@ function deleteYubikeyOtp(yubikeyOtpId) {
|
||||
return apiClient.deleteYubikeyOtp(token, sessionSecretKey, yubikeyOtpId).then(onSuccess, onError);
|
||||
}
|
||||
|
||||
const service = {
|
||||
const yubikeyOtpService = {
|
||||
createYubikeyOtp,
|
||||
readYubikeyOtp,
|
||||
activateYubikeyOtp,
|
||||
deleteYubikeyOtp,
|
||||
};
|
||||
|
||||
export default service;
|
||||
export default yubikeyOtpService;
|
||||
|
@ -25,6 +25,10 @@ const useStyles = makeStyles((theme) => ({
|
||||
textField: {
|
||||
width: "100%",
|
||||
},
|
||||
code: {
|
||||
fontFamily: "'Fira Code', monospace",
|
||||
textAlign: "center",
|
||||
},
|
||||
}));
|
||||
|
||||
const EmergencyCodesDialog = (props) => {
|
||||
@ -207,25 +211,25 @@ const EmergencyCodesDialog = (props) => {
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<strong>{t("URL")}</strong>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12} className="text-center monospace">
|
||||
<Grid item xs={12} sm={12} md={12} className={classes.code}>
|
||||
<p>{newEmergencyCode.url}</p>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<strong>{t("USERNAME")}</strong>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12} className="text-center monospace">
|
||||
<Grid item xs={12} sm={12} md={12} className={classes.code}>
|
||||
<p>{newEmergencyCode.username}</p>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<strong>{t("CODE")}</strong>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12} className="text-center monospace">
|
||||
<Grid item xs={12} sm={12} md={12} className={classes.code}>
|
||||
<p>{newEmergencyCode.emergency_password}</p>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<strong>{t("OR")}</strong>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12} className="text-center monospace">
|
||||
<Grid item xs={12} sm={12} md={12} className={classes.code}>
|
||||
<p>{newEmergencyCode.emergency_words}</p>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
|
@ -1,10 +1,9 @@
|
||||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import PropTypes from "prop-types";
|
||||
import { bindActionCreators } from "redux";
|
||||
import { compose } from "redux";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Box from "@material-ui/core/Box";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Dialog from "@material-ui/core/Dialog";
|
||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
import DialogContent from "@material-ui/core/DialogContent";
|
||||
@ -16,8 +15,16 @@ import actionCreators from "../../actions/action-creators";
|
||||
import passwordRecoveryCode from "../../services/password-recovery-code";
|
||||
import MuiAlert from "@material-ui/lab/Alert";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
code: {
|
||||
fontFamily: "'Fira Code', monospace",
|
||||
textAlign: "center",
|
||||
},
|
||||
}));
|
||||
|
||||
const PasswordRecoveryCodesDialog = (props) => {
|
||||
const { open, onClose } = props;
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslation();
|
||||
const [newPasswordRecoveryCode, setNewPasswordRecoveryCode] = React.useState({});
|
||||
|
||||
@ -40,19 +47,19 @@ const PasswordRecoveryCodesDialog = (props) => {
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<strong>{t("USERNAME")}</strong>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12} className="text-center monospace">
|
||||
<Grid item xs={12} sm={12} md={12} className={classes.code}>
|
||||
<p>{newPasswordRecoveryCode.username}</p>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<strong>{t("CODE")}</strong>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12} className="text-center monospace">
|
||||
<Grid item xs={12} sm={12} md={12} className={classes.code}>
|
||||
<p>{newPasswordRecoveryCode.recovery_password}</p>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<strong>{t("OR")}</strong>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12} className="text-center monospace">
|
||||
<Grid item xs={12} sm={12} md={12} className={classes.code}>
|
||||
<p>{newPasswordRecoveryCode.recovery_words}</p>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
|
@ -1,8 +1,9 @@
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import { connect, useSelector } from "react-redux";
|
||||
import { bindActionCreators } from "redux";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { differenceInSeconds } from "date-fns";
|
||||
import { ClipLoader } from "react-spinners";
|
||||
import { alpha, makeStyles } from "@material-ui/core/styles";
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
import AppBar from "@material-ui/core/AppBar";
|
||||
@ -14,22 +15,49 @@ import MenuOpenIcon from "@material-ui/icons/MenuOpen";
|
||||
import Divider from "@material-ui/core/Divider";
|
||||
import ClearIcon from "@material-ui/icons/Clear";
|
||||
import MuiAlert from "@material-ui/lab/Alert";
|
||||
import Menu from "@material-ui/core/Menu";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
import ListItemIcon from "@material-ui/core/ListItemIcon";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import CreateNewFolderIcon from "@material-ui/icons/CreateNewFolder";
|
||||
import AddIcon from "@material-ui/icons/Add";
|
||||
|
||||
import actionCreators from "../../actions/action-creators";
|
||||
|
||||
import PasswordDatastore from "../../containers/password-datastore";
|
||||
import Base from "../../containers/base";
|
||||
import BaseTitle from "../../containers/base-title";
|
||||
import BaseContent from "../../containers/base-content";
|
||||
import widget from "../../services/widget";
|
||||
import datastorePassword from "../../services/datastore-password";
|
||||
import DialogNewFolder from "../../components/dialogs/new-folder";
|
||||
import DialogNewEntry from "../../components/dialogs/new-entry";
|
||||
import DatastoreTree from "../../components/datastore-tree";
|
||||
import DialogNewShare from "../../components/dialogs/new-share";
|
||||
import DialogEditFolder from "../../components/dialogs/edit-folder";
|
||||
import DialogEditEntry from "../../components/dialogs/edit-entry";
|
||||
import fileTransferService from "../../services/file-transfer";
|
||||
import secretService from "../../services/secret";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
display: "flex",
|
||||
padding: "15px",
|
||||
},
|
||||
loader: {
|
||||
marginTop: "30px",
|
||||
marginBottom: "30px",
|
||||
margin: "auto",
|
||||
},
|
||||
toolbarRoot: {
|
||||
display: "flex",
|
||||
},
|
||||
toolbarTitle: {
|
||||
display: "none",
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
display: "block",
|
||||
},
|
||||
},
|
||||
search: {
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
backgroundColor: alpha(theme.palette.common.white, 0.25),
|
||||
@ -37,6 +65,8 @@ const useStyles = makeStyles((theme) => ({
|
||||
backgroundColor: alpha(theme.palette.common.white, 0.45),
|
||||
},
|
||||
marginLeft: "auto",
|
||||
position: "absolute",
|
||||
right: 0,
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
marginRight: theme.spacing(1),
|
||||
},
|
||||
@ -52,7 +82,7 @@ const useStyles = makeStyles((theme) => ({
|
||||
transition: theme.transitions.create("width"),
|
||||
width: "100%",
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
width: "12ch",
|
||||
width: "10ch",
|
||||
"&:focus": {
|
||||
width: "20ch",
|
||||
},
|
||||
@ -71,14 +101,52 @@ const useStyles = makeStyles((theme) => ({
|
||||
topMessage: {
|
||||
marginBottom: 20,
|
||||
},
|
||||
icon: {
|
||||
fontSize: "18px",
|
||||
},
|
||||
listItemIcon: {
|
||||
minWidth: theme.spacing(4),
|
||||
},
|
||||
}));
|
||||
|
||||
const DatastoreView = (props) => {
|
||||
let { defaultSearch } = useParams();
|
||||
const serverStatus = useSelector((state) => state.server.status);
|
||||
const recurrenceInterval = useSelector((state) => state.server.complianceCentralSecurityReportsRecurrenceInterval);
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslation();
|
||||
const [search, setSearch] = React.useState("");
|
||||
const [search, setSearch] = useState(defaultSearch || "");
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
|
||||
const [newFolderOpen, setNewFolderOpen] = useState(false);
|
||||
const [newFolderData, setNewFolderData] = useState({});
|
||||
|
||||
const [newEntryOpen, setNewEntryOpen] = useState(false);
|
||||
const [newEntryData, setNewEntryData] = useState({});
|
||||
|
||||
const [editFolderOpen, setEditFolderOpen] = useState(false);
|
||||
const [editFolderData, setEditFolderData] = useState({});
|
||||
|
||||
const [editEntryOpen, setEditEntryOpen] = useState(false);
|
||||
const [editEntryData, setEditEntryData] = useState({});
|
||||
|
||||
const [newShareOpen, setNewShareOpen] = useState(false);
|
||||
const [newShareData, setNewShareData] = useState({});
|
||||
|
||||
const [datastore, setDatastore] = useState(null);
|
||||
|
||||
let isSubscribed = true;
|
||||
React.useEffect(() => {
|
||||
datastorePassword.getPasswordDatastore().then(onNewDatastoreLoaded);
|
||||
return () => (isSubscribed = false);
|
||||
}, []);
|
||||
|
||||
const onNewDatastoreLoaded = (data) => {
|
||||
if (!isSubscribed) {
|
||||
return;
|
||||
}
|
||||
setDatastore(data);
|
||||
};
|
||||
|
||||
const onClear = () => {
|
||||
setSearch("");
|
||||
@ -96,8 +164,8 @@ const DatastoreView = (props) => {
|
||||
if (lastSecurityReportAgeSeconds > recurrenceInterval) {
|
||||
newSecurityReport = "REQUIRED";
|
||||
} else {
|
||||
var days_28 = 28 * 24 * 3600;
|
||||
var days_14 = 14 * 24 * 3600;
|
||||
const days_28 = 28 * 24 * 3600;
|
||||
const days_14 = 14 * 24 * 3600;
|
||||
if (recurrenceInterval >= days_28 && lastSecurityReportAgeSeconds > recurrenceInterval - days_14) {
|
||||
newSecurityReport = "SOON_REQUIRED";
|
||||
} else {
|
||||
@ -109,6 +177,400 @@ const DatastoreView = (props) => {
|
||||
}
|
||||
}
|
||||
|
||||
const onNewShareCreate = (name) => {
|
||||
// called once someone clicked the CREATE button in the dialog closes with the new name
|
||||
setNewShareOpen(false);
|
||||
|
||||
// const onShare = (event) => {
|
||||
// handleClose(event);
|
||||
// if (content.hasOwnProperty("share_rights") && content.share_rights.grant === false) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * little wrapper to create the share rights from the selected users / groups and rights for a given nonce and
|
||||
// * a given share_id and key
|
||||
// *
|
||||
// * @param share_id
|
||||
// * @param share_secret_key
|
||||
// * @param node
|
||||
// * @param users
|
||||
// * @param groups
|
||||
// * @param selected_users
|
||||
// * @param selected_groups
|
||||
// * @param selected_rights
|
||||
// */
|
||||
// var create_share_rights = function (share_id, share_secret_key, node, users, groups, selected_users, selected_groups, selected_rights) {
|
||||
// var i;
|
||||
// var modalInstance;
|
||||
//
|
||||
// // found a user that has been selected, lets create the rights for him
|
||||
// var rights = {
|
||||
// read: selected_rights.indexOf("read") > -1,
|
||||
// write: selected_rights.indexOf("write") > -1,
|
||||
// grant: selected_rights.indexOf("grant") > -1,
|
||||
// };
|
||||
//
|
||||
// // generate the title
|
||||
// // TODO create form field with this default value and read value from form
|
||||
//
|
||||
// var title = "";
|
||||
// if (typeof node.type === "undefined") {
|
||||
// // we have a folder
|
||||
// title = "Folder with title '" + node.name + "'";
|
||||
// } else {
|
||||
// // we have an item
|
||||
// title = _blueprints[node.type].name + " with title '" + node.name + "'";
|
||||
// }
|
||||
//
|
||||
// // get the type
|
||||
// var type = "";
|
||||
// if (typeof node.type === "undefined") {
|
||||
// // we have a folder
|
||||
// type = "folder";
|
||||
// } else {
|
||||
// // we have an item
|
||||
// type = node.type;
|
||||
// }
|
||||
//
|
||||
// function create_user_share_right(user) {
|
||||
// var onSuccess = function (data) {
|
||||
// // pass
|
||||
// };
|
||||
// var onError = function (result) {
|
||||
// var title;
|
||||
// var description;
|
||||
// if (result.data === null) {
|
||||
// title = "UNKNOWN_ERROR";
|
||||
// description = "UNKNOWN_ERROR_CHECK_BROWSER_CONSOLE";
|
||||
// } else if (
|
||||
// result.data.hasOwnProperty("non_field_errors") &&
|
||||
// (result.data["non_field_errors"].indexOf("USER_DOES_NOT_EXIST_PROBABLY_DELETED") !== -1 ||
|
||||
// result.data["non_field_errors"].indexOf("Target user does not exist.") !== -1)
|
||||
// ) {
|
||||
// title = "UNKNOWN_USER";
|
||||
// description = _translations.USER_DOES_NOT_EXIST_PROBABLY_DELETED + " " + user.name;
|
||||
// } else if (result.data.hasOwnProperty("non_field_errors")) {
|
||||
// title = "ERROR";
|
||||
// description = result.data["non_field_errors"][0];
|
||||
// } else {
|
||||
// title = "UNKNOWN_ERROR";
|
||||
// description = "UNKNOWN_ERROR_CHECK_BROWSER_CONSOLE";
|
||||
// }
|
||||
//
|
||||
// modalInstance = $uibModal.open({
|
||||
// templateUrl: "view/modal/error.html",
|
||||
// controller: "ModalErrorCtrl",
|
||||
// resolve: {
|
||||
// title: function () {
|
||||
// return title;
|
||||
// },
|
||||
// description: function () {
|
||||
// return description;
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
//
|
||||
// modalInstance.result.then(
|
||||
// function (breadcrumbs) {
|
||||
// // pass
|
||||
// },
|
||||
// function () {
|
||||
// // cancel triggered
|
||||
// }
|
||||
// );
|
||||
// };
|
||||
//
|
||||
// return registrations["create_share_right"](
|
||||
// title,
|
||||
// type,
|
||||
// share_id,
|
||||
// user.data.user_id,
|
||||
// undefined,
|
||||
// user.data.user_public_key,
|
||||
// undefined,
|
||||
// share_secret_key,
|
||||
// rights["read"],
|
||||
// rights["write"],
|
||||
// rights["grant"]
|
||||
// ).then(onSuccess, onError);
|
||||
// }
|
||||
//
|
||||
// for (i = 0; i < users.length; i++) {
|
||||
// if (selected_users.indexOf(users[i].id) < 0) {
|
||||
// continue;
|
||||
// }
|
||||
// create_user_share_right(users[i]);
|
||||
// }
|
||||
//
|
||||
// function create_group_share_right(group) {
|
||||
// var onSuccess = function (data) {
|
||||
// // pass
|
||||
// };
|
||||
// var onError = function (result) {
|
||||
// var title;
|
||||
// var description;
|
||||
// if (result.data === null) {
|
||||
// title = "UNKNOWN_ERROR";
|
||||
// description = "UNKNOWN_ERROR_CHECK_BROWSER_CONSOLE";
|
||||
// } else if (result.data.hasOwnProperty("non_field_errors")) {
|
||||
// title = "ERROR";
|
||||
// description = result.data["non_field_errors"][0];
|
||||
// } else {
|
||||
// title = "UNKNOWN_ERROR";
|
||||
// description = "UNKNOWN_ERROR_CHECK_BROWSER_CONSOLE";
|
||||
// }
|
||||
//
|
||||
// modalInstance = $uibModal.open({
|
||||
// templateUrl: "view/modal/error.html",
|
||||
// controller: "ModalErrorCtrl",
|
||||
// resolve: {
|
||||
// title: function () {
|
||||
// return title;
|
||||
// },
|
||||
// description: function () {
|
||||
// return description;
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
//
|
||||
// modalInstance.result.then(
|
||||
// function (breadcrumbs) {
|
||||
// // pass
|
||||
// },
|
||||
// function () {
|
||||
// // cancel triggered
|
||||
// }
|
||||
// );
|
||||
// };
|
||||
//
|
||||
// var group_secret_key = registrations["get_group_secret_key"](
|
||||
// group.group_id,
|
||||
// group.secret_key,
|
||||
// group.secret_key_nonce,
|
||||
// group.secret_key_type,
|
||||
// group.public_key
|
||||
// );
|
||||
// return registrations["create_share_right"](
|
||||
// title,
|
||||
// type,
|
||||
// share_id,
|
||||
// undefined,
|
||||
// group.group_id,
|
||||
// undefined,
|
||||
// group_secret_key,
|
||||
// share_secret_key,
|
||||
// rights["read"],
|
||||
// rights["write"],
|
||||
// rights["grant"]
|
||||
// ).then(onSuccess, onError);
|
||||
// }
|
||||
//
|
||||
// for (i = 0; i < groups.length; i++) {
|
||||
// if (selected_groups.indexOf(groups[i].group_id) < 0) {
|
||||
// continue;
|
||||
// }
|
||||
// create_group_share_right(groups[i]);
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// /**
|
||||
// * Users and or / shares have been selected in the modal and the final "Share Now" button was
|
||||
// * clicked
|
||||
// *
|
||||
// * @param content
|
||||
// */
|
||||
// var on_modal_close_success = function (content) {
|
||||
// // content = { node: "...", path: "...", selected_users: "...", users: "..."}
|
||||
//
|
||||
// var has_no_users = !content.users || content.users.length < 1 || !content.selected_users || content.selected_users.length < 1;
|
||||
//
|
||||
// var has_no_groups = !content.groups || content.groups.length < 1 || !content.selected_groups || content.selected_groups.length < 1;
|
||||
//
|
||||
// if (has_no_users && has_no_groups) {
|
||||
// // TODO echo not shared message because no user / group selected
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (content.node.hasOwnProperty("share_id")) {
|
||||
// // its already a share, so generate only the share_rights
|
||||
//
|
||||
// create_share_rights(
|
||||
// content.node.share_id,
|
||||
// content.node.share_secret_key,
|
||||
// content.node,
|
||||
// content.users,
|
||||
// content.groups,
|
||||
// content.selected_users,
|
||||
// content.selected_groups,
|
||||
// content.selected_rights
|
||||
// );
|
||||
// } else {
|
||||
// // its not yet a share, so generate the share, generate the share_rights and update
|
||||
// // the datastore
|
||||
//
|
||||
// registrations["get_password_datastore"]().then(function (datastore) {
|
||||
// var path = content.path.slice();
|
||||
// var closest_share_info = registrations["get_closest_parent_share"](path, datastore, null, 1);
|
||||
// var parent_share = closest_share_info["closest_share"];
|
||||
// var parent_share_id;
|
||||
// var parent_datastore_id;
|
||||
//
|
||||
// if (parent_share !== false && parent_share !== null) {
|
||||
// parent_share_id = parent_share.share_id;
|
||||
// } else {
|
||||
// parent_datastore_id = datastore.datastore_id;
|
||||
// }
|
||||
//
|
||||
// // create the share
|
||||
// registrations["create_share"](content.node, parent_share_id, parent_datastore_id, content.node.id).then(function (share_details) {
|
||||
// var item_path = content.path.slice();
|
||||
// var item_path_copy = content.path.slice();
|
||||
// var item_path_copy2 = content.path.slice();
|
||||
//
|
||||
// // create the share right
|
||||
// create_share_rights(
|
||||
// share_details.share_id,
|
||||
// share_details.secret_key,
|
||||
// content.node,
|
||||
// content.users,
|
||||
// content.groups,
|
||||
// content.selected_users,
|
||||
// content.selected_groups,
|
||||
// content.selected_rights
|
||||
// );
|
||||
//
|
||||
// // update datastore and / or possible parent shares
|
||||
// var search = registrations["find_in_datastore"](item_path, datastore);
|
||||
//
|
||||
// if (typeof content.node.type === "undefined") {
|
||||
// // we have an item
|
||||
// delete search[0][search[1]].secret_id;
|
||||
// delete search[0][search[1]].secret_key;
|
||||
// }
|
||||
// search[0][search[1]].share_id = share_details.share_id;
|
||||
// search[0][search[1]].share_secret_key = share_details.secret_key;
|
||||
//
|
||||
// // update node in our displayed datastore
|
||||
// content.node.share_id = share_details.share_id;
|
||||
// content.node.share_secret_key = share_details.secret_key;
|
||||
//
|
||||
// var changed_paths = registrations["on_share_added"](share_details.share_id, item_path_copy, datastore, 1);
|
||||
//
|
||||
// var parent_path = item_path_copy2.slice();
|
||||
// parent_path.pop();
|
||||
//
|
||||
// changed_paths.push(parent_path);
|
||||
//
|
||||
// registrations["save_datastore_content"](datastore, changed_paths);
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// var modalInstance = $uibModal.open({
|
||||
// templateUrl: "view/modal/share-entry.html",
|
||||
// controller: "ModalShareEntryCtrl",
|
||||
// backdrop: "static",
|
||||
// resolve: {
|
||||
// node: function () {
|
||||
// return item;
|
||||
// },
|
||||
// path: function () {
|
||||
// return path;
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
//
|
||||
// // User clicked the final share button
|
||||
// modalInstance.result.then(on_modal_close_success, function () {
|
||||
// // cancel triggered
|
||||
// });
|
||||
// };
|
||||
};
|
||||
const onNewShare = (parent, path) => {
|
||||
// called whenever someone clicks on a new folder Icon
|
||||
setNewShareOpen(true);
|
||||
setNewShareData({
|
||||
parent: parent,
|
||||
path: path,
|
||||
});
|
||||
};
|
||||
|
||||
const onNewFolderCreate = (name) => {
|
||||
// called once someone clicked the CREATE button in the dialog closes with the new name
|
||||
setNewFolderOpen(false);
|
||||
widget.openNewFolder(newFolderData["parent"], newFolderData["path"], datastore, datastorePassword, name);
|
||||
};
|
||||
const onNewFolder = (parent, path) => {
|
||||
setAnchorEl(null);
|
||||
// called whenever someone clicks on a new folder Icon
|
||||
setNewFolderOpen(true);
|
||||
setNewFolderData({
|
||||
parent: parent,
|
||||
path: path,
|
||||
});
|
||||
};
|
||||
|
||||
const onNewEntryCreate = (name) => {
|
||||
// called once someone clicked the CREATE button in the dialog closes with the new name
|
||||
setNewEntryOpen(false);
|
||||
widget.openNewEntry(newEntryData["parent"], newEntryData["path"], datastore, datastorePassword, name);
|
||||
};
|
||||
const onNewEntry = (parent, path) => {
|
||||
setAnchorEl(null);
|
||||
// called whenever someone clicks on a new folder Icon
|
||||
setNewEntryOpen(true);
|
||||
setNewEntryData({
|
||||
parent: parent,
|
||||
path: path,
|
||||
});
|
||||
};
|
||||
|
||||
const onEditFolderSave = (node) => {
|
||||
setEditFolderOpen(false);
|
||||
widget.openEditFolder(node, editFolderData.path, datastore, datastorePassword);
|
||||
};
|
||||
const onEditFolder = (node, path) => {
|
||||
setEditFolderData({
|
||||
node: node,
|
||||
path: path,
|
||||
});
|
||||
setEditFolderOpen(true);
|
||||
};
|
||||
|
||||
const onEditEntrySave = (node) => {
|
||||
setEditEntryOpen(false);
|
||||
widget.openEditEntry(node, editEntryData.path, datastore, datastorePassword);
|
||||
};
|
||||
|
||||
const onEditEntry = (item, path) => {
|
||||
setEditEntryData({
|
||||
item: item,
|
||||
path: path,
|
||||
});
|
||||
setEditEntryOpen(true);
|
||||
};
|
||||
|
||||
const onLinkItem = (item, path) => {
|
||||
if (item.type === "file") {
|
||||
return fileTransferService.onItemClick(item);
|
||||
} else {
|
||||
return secretService.onItemClick(item);
|
||||
}
|
||||
};
|
||||
const openMenu = (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<Base {...props}>
|
||||
<BaseTitle>{t("DATASTORE")}</BaseTitle>
|
||||
@ -129,7 +591,7 @@ const DatastoreView = (props) => {
|
||||
<Paper square>
|
||||
<AppBar elevation={0} position="static" color="default">
|
||||
<Toolbar className={classes.toolbarRoot}>
|
||||
{t("DATASTORE")}
|
||||
<span className={classes.toolbarTitle}>{t("DATASTORE")}</span>
|
||||
<div className={classes.search}>
|
||||
<InputBase
|
||||
placeholder={t("SEARCH")}
|
||||
@ -147,9 +609,27 @@ const DatastoreView = (props) => {
|
||||
<ClearIcon />
|
||||
</IconButton>
|
||||
<Divider className={classes.divider} orientation="vertical" />
|
||||
<IconButton color="primary" className={classes.iconButton} aria-label="menu">
|
||||
<IconButton color="primary" className={classes.iconButton} aria-label="menu" onClick={openMenu}>
|
||||
<MenuOpenIcon />
|
||||
</IconButton>
|
||||
<Menu id="simple-menu" anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose}>
|
||||
<MenuItem onClick={() => onNewFolder(datastore, [])}>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<CreateNewFolderIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
{t("NEW_FOLDER")}
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => onNewEntry(datastore, [])}>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<AddIcon className={classes.icon} fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" noWrap>
|
||||
{t("NEW_ENTRY")}
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<Divider className={classes.divider} orientation="vertical" />
|
||||
<IconButton className={classes.iconButton} aria-label="trash bin">
|
||||
<DeleteSweepIcon />
|
||||
@ -158,7 +638,38 @@ const DatastoreView = (props) => {
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
<div className={classes.root}>
|
||||
<PasswordDatastore search={search} />
|
||||
{!datastore && (
|
||||
<div className={classes.loader}>
|
||||
<ClipLoader />
|
||||
</div>
|
||||
)}
|
||||
{datastore && (
|
||||
<DatastoreTree
|
||||
datastore={datastore}
|
||||
search={search}
|
||||
onNewFolder={onNewFolder}
|
||||
onNewEntry={onNewEntry}
|
||||
onNewShare={onNewShare}
|
||||
onEditEntry={onEditEntry}
|
||||
onEditFolder={onEditFolder}
|
||||
onSelectItem={onEditEntry}
|
||||
onLinkItem={onLinkItem}
|
||||
/>
|
||||
)}
|
||||
{newShareOpen && <DialogNewShare open={newShareOpen} onClose={() => setNewShareOpen(false)} onShare={onNewShareCreate} />}
|
||||
{newFolderOpen && <DialogNewFolder open={newFolderOpen} onClose={() => setNewFolderOpen(false)} onCreate={onNewFolderCreate} />}
|
||||
{editFolderOpen && (
|
||||
<DialogEditFolder
|
||||
open={editFolderOpen}
|
||||
onClose={() => setEditFolderOpen(false)}
|
||||
onSave={onEditFolderSave}
|
||||
node={editFolderData.node}
|
||||
/>
|
||||
)}
|
||||
{editEntryOpen && (
|
||||
<DialogEditEntry open={editEntryOpen} onClose={() => setEditEntryOpen(false)} onSave={onEditEntrySave} item={editEntryData.item} />
|
||||
)}
|
||||
{newEntryOpen && <DialogNewEntry open={newEntryOpen} onClose={() => setNewEntryOpen(false)} onCreate={onNewEntryCreate} />}
|
||||
</div>
|
||||
</Paper>
|
||||
</BaseContent>
|
||||
@ -172,4 +683,4 @@ function mapStateToProps(state) {
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return { actions: bindActionCreators(actionCreators, dispatch) };
|
||||
}
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(DatastoreView);
|
||||
export default DatastoreView;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import MuiAlert from "@material-ui/lab/Alert";
|
||||
import Box from "@material-ui/core/Box";
|
||||
import LinearProgress from "@material-ui/core/LinearProgress";
|
||||
@ -7,8 +8,15 @@ import { useParams } from "react-router-dom";
|
||||
import store from "../../services/store";
|
||||
import fileTransferService from "../../services/file-transfer";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
textCenter: {
|
||||
textAlign: "center",
|
||||
},
|
||||
}));
|
||||
|
||||
const DownloadFileView = (props) => {
|
||||
const { t } = useTranslation();
|
||||
const classes = useStyles();
|
||||
const [percentageComplete, setPercentageComplete] = React.useState(0);
|
||||
const [nextStep, setNextStep] = React.useState("");
|
||||
const [processing, setProcessing] = React.useState(false);
|
||||
@ -65,7 +73,7 @@ const DownloadFileView = (props) => {
|
||||
// }, []);
|
||||
|
||||
return (
|
||||
<div className="progress-box text-center">
|
||||
<div className={"progress-box " + classes.textCenter}>
|
||||
<img src="img/logo.png" alt="Psono Web Client" id="logo" />
|
||||
<a href="https://psono.com/" target="_blank" rel="noopener" className="infolabel">
|
||||
<i className="fa fa-info-circle" aria-hidden="true" />
|
||||
|
@ -76,10 +76,11 @@ const EmergencyCodeViewForm = (props) => {
|
||||
|
||||
const onNewConfigLoaded = (configJson) => {
|
||||
const serverUrl = configJson["backend_servers"][0]["url"];
|
||||
const domain = configJson["backend_servers"][0]["domain"];
|
||||
const allowCustomServer = configJson.allow_custom_server;
|
||||
|
||||
setServer(serverUrl);
|
||||
setDomain(helperService.getDomain(serverUrl));
|
||||
setDomain(domain);
|
||||
setAllowCustomServer(allowCustomServer);
|
||||
};
|
||||
|
||||
|
@ -16,7 +16,7 @@ import Table from "../../components/table";
|
||||
import groupsService from "../../services/groups";
|
||||
import format from "../../services/date";
|
||||
import CreateGroupDialog from "./create-group-dialog";
|
||||
import VerifyDialog from "../../containers/verify-dialog";
|
||||
import DialogVerify from "../../components/dialogs/verify";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
@ -300,7 +300,7 @@ const GroupsView = (props) => {
|
||||
</Paper>
|
||||
{createOpen && <CreateGroupDialog {...props} open={createOpen} onClose={closeCreateModal} />}
|
||||
{verifyDeleteGroupOpen && (
|
||||
<VerifyDialog
|
||||
<DialogVerify
|
||||
title={"DELETE_GROUP"}
|
||||
description={"DELETE_GROUP_WARNING"}
|
||||
entries={[groupNameBeingDeleted]}
|
||||
|
@ -116,6 +116,9 @@ const IndexView = (props) => {
|
||||
<Route path="/active-link-shares">
|
||||
<ActiveLinkShareView {...props} />
|
||||
</Route>
|
||||
<Route path="/datastore/search/:defaultSearch">
|
||||
<DatastoreView {...props} />
|
||||
</Route>
|
||||
<Route path="/">
|
||||
<DatastoreView {...props} />
|
||||
</Route>
|
||||
|
@ -357,6 +357,7 @@ const LoginViewForm = (props) => {
|
||||
|
||||
const onNewConfigLoaded = (configJson) => {
|
||||
const serverUrl = configJson["backend_servers"][0]["url"];
|
||||
const domain = configJson["backend_servers"][0]["domain"];
|
||||
const allowRegistration =
|
||||
!configJson.hasOwnProperty("allow_registration") || (configJson.hasOwnProperty("allow_registration") && configJson["allow_registration"]);
|
||||
const allowLostPassword =
|
||||
@ -375,7 +376,7 @@ const LoginViewForm = (props) => {
|
||||
setAllowLostPassword(allowLostPassword);
|
||||
setAllowRegistration(allowRegistration);
|
||||
setServer(serverUrl);
|
||||
setDomain(helperService.getDomain(serverUrl));
|
||||
setDomain(domain);
|
||||
setSamlProvider(samlProvider);
|
||||
setOidcProvider(oidcProvider);
|
||||
setAuthenticationMethods(authenticationMethods);
|
||||
|
@ -124,6 +124,7 @@ const LostPasswordViewForm = (props) => {
|
||||
|
||||
const onNewConfigLoaded = (configJson) => {
|
||||
const serverUrl = configJson["backend_servers"][0]["url"];
|
||||
const domain = configJson["backend_servers"][0]["domain"];
|
||||
const allowLostPassword =
|
||||
(!configJson.hasOwnProperty("allow_lost_password") || (configJson.hasOwnProperty("allow_lost_password") && configJson["allow_lost_password"])) &&
|
||||
configJson["authentication_methods"].indexOf("AUTHKEY") !== -1;
|
||||
@ -131,7 +132,7 @@ const LostPasswordViewForm = (props) => {
|
||||
|
||||
setAllowLostPassword(allowLostPassword);
|
||||
setServer(serverUrl);
|
||||
setDomain(helperService.getDomain(serverUrl));
|
||||
setDomain(domain);
|
||||
setAllowCustomServer(allowCustomServer);
|
||||
};
|
||||
|
||||
|
@ -16,7 +16,7 @@ import actionCreators from "../../actions/action-creators";
|
||||
import GridContainerErrors from "../../components/grid-container-errors";
|
||||
import fileRepository from "../../services/file-repository";
|
||||
import helperService from "../../services/helper";
|
||||
import FileRepositoryTypeSelectField from "../../containers/file-repository-type-select-field";
|
||||
import SelectFieldFileRepositoryType from "../../components/select-field/file-repository-type";
|
||||
import TextFieldAWSRegion from "../../components/text-field-aws-region";
|
||||
import TextFieldDoRegion from "../../components/text-field-do-region";
|
||||
|
||||
@ -156,7 +156,7 @@ const CreateFileRepositoriesDialog = (props) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<FileRepositoryTypeSelectField
|
||||
<SelectFieldFileRepositoryType
|
||||
className={classes.textField}
|
||||
variant="outlined"
|
||||
margin="dense"
|
||||
|
@ -2,10 +2,8 @@ import React, { useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import PropTypes from "prop-types";
|
||||
import { bindActionCreators } from "redux";
|
||||
import { compose } from "redux";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Box from "@material-ui/core/Box";
|
||||
import Dialog from "@material-ui/core/Dialog";
|
||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
import DialogContent from "@material-ui/core/DialogContent";
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user