diff --git a/Changelog.md b/Changelog.md index 3ad23f1f..b595f415 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,11 @@ This page contains information about changes to the PowerBI Visual Tools (pbiviz). +## 5.5.0 +* Changed path for storing certificates. It allows the certificate to be reused regardless of tools version. New path is `({home directory}/pbiviz-certs)`. +* Windows version lower 10 is deprecated. +* Resolve of symlinks is disabled. + ## 5.4.3 * Fixed bug with missing plugins for Eslint. * New flag `--use-default` for `pbiviz package` and `pbiviz lint` commands. Use this command to lint files according to recommended lint config. diff --git a/config.json b/config.json index 67a7dcfe..dc9c0362 100644 --- a/config.json +++ b/config.json @@ -17,9 +17,11 @@ "package": { "dropFolder": "dist" }, "server": { "assetsRoute": "/assets", - "privateKey": "certs/PowerBICustomVisualTest_private.key", - "certificate": "certs/PowerBICustomVisualTest_public.crt", - "pfx": "certs/PowerBICustomVisualTest_public.pfx" + "certificateFolder": "pbiviz-certs", + "privateKey": "PowerBICustomVisualTest_private.key", + "certificate": "PowerBICustomVisualTest_public.crt", + "pfx": "PowerBICustomVisualTest_public.pfx", + "passphrase": "PowerBICustomVisualTestPass.txt" }, "visualTemplates": { "circlecard": "https://codeload.github.com/microsoft/powerbi-visuals-circlecard-react/zip/master" diff --git a/package-lock.json b/package-lock.json index 5d5ded87..44d4c235 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "powerbi-visuals-tools", - "version": "5.4.3", + "version": "5.5.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "powerbi-visuals-tools", - "version": "5.4.3", + "version": "5.5.0", "license": "MIT", "dependencies": { - "@typescript-eslint/parser": "^6.21.0", + "@typescript-eslint/parser": "^7.12.0", "assert": "^2.1.0", "async": "^3.2.5", "browserify-zlib": "^0.2.0", @@ -20,7 +20,7 @@ "console-browserify": "^1.2.0", "constants-browserify": "^1.0.0", "crypto-browserify": "^3.12.0", - "css-loader": "^6.10.0", + "css-loader": "^6.11.0", "domain-browser": "^5.7.0", "events": "^3.3.0", "extra-watch-webpack-plugin": "^1.0.3", @@ -30,12 +30,12 @@ "json-loader": "0.5.7", "jszip": "^3.10.1", "less": "^4.2.0", - "less-loader": "^11.1.4", + "less-loader": "^12.2.0", "lodash.clonedeep": "4.5.0", "lodash.defaults": "4.2.0", "lodash.isequal": "4.5.0", "lodash.ismatch": "^4.4.0", - "mini-css-extract-plugin": "^2.8.1", + "mini-css-extract-plugin": "^2.9.0", "os-browserify": "^0.3.0", "path-browserify": "^1.0.1", "powerbi-visuals-webpack-plugin": "4.1.0", @@ -55,19 +55,19 @@ "util": "^0.12.5", "vm-browserify": "^1.1.2", "webpack": "^5.91.0", - "webpack-bundle-analyzer": "4.10.1", + "webpack-bundle-analyzer": "4.10.2", "webpack-dev-server": "^4.15.2" }, "bin": { "pbiviz": "bin/pbiviz.js" }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/eslint-plugin": "^7.12.0", "eslint": "^8.57.0", "eslint-plugin-powerbi-visuals": "^0.8.1", "jasmine": "5.1.0", "jasmine-spec-reporter": "7.0.0", - "semver": "7.6.0", + "semver": "7.6.2", "tree-kill": "1.2.2", "webpack-cli": "^5.1.4" }, @@ -457,12 +457,6 @@ "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true - }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", @@ -507,33 +501,31 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.12.0.tgz", + "integrity": "sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/type-utils": "7.12.0", + "@typescript-eslint/utils": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", "graphemer": "^1.4.0", - "ignore": "^5.2.4", + "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -542,25 +534,25 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", - "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.12.0.tgz", + "integrity": "sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==", + "dependencies": { + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/typescript-estree": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", "debug": "^4.3.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -569,15 +561,15 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.12.0.tgz", + "integrity": "sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -585,25 +577,25 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.12.0.tgz", + "integrity": "sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/typescript-estree": "7.12.0", + "@typescript-eslint/utils": "7.12.0", "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -612,11 +604,11 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.12.0.tgz", + "integrity": "sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==", "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -624,21 +616,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.12.0.tgz", + "integrity": "sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -659,9 +651,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -673,40 +665,37 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.12.0.tgz", + "integrity": "sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/typescript-estree": "7.12.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.12.0.tgz", + "integrity": "sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/types": "7.12.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1176,12 +1165,12 @@ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -1189,7 +1178,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -1263,11 +1252,11 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1495,7 +1484,7 @@ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dependencies": { "anymatch": "~3.1.2", - "braces": "~3.0.2", + "braces": "~3.0.3", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", @@ -1698,9 +1687,9 @@ } }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -1800,15 +1789,15 @@ } }, "node_modules/css-loader": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.10.0.tgz", - "integrity": "sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.33", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.4", - "postcss-modules-scope": "^3.1.1", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", "semver": "^7.5.4" @@ -2354,16 +2343,16 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -2451,7 +2440,7 @@ "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.6" }, "engines": { "node": ">=8.6.0" @@ -2518,9 +2507,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -3064,7 +3053,7 @@ "http-proxy": "^1.18.1", "is-glob": "^4.0.1", "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" + "micromatch": "^4.0.6" }, "engines": { "node": ">=12.0.0" @@ -3134,9 +3123,9 @@ ] }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "engines": { "node": ">= 4" } @@ -3386,14 +3375,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -3696,19 +3677,28 @@ } }, "node_modules/less-loader": { - "version": "11.1.4", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.4.tgz", - "integrity": "sha512-6/GrYaB6QcW6Vj+/9ZPgKKs6G10YZai/l/eJ4SLwbzqNTBsAqt5hSLVF47TgsiBxV1P6eAU0GYRH3YRuQU9V3A==", + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-12.2.0.tgz", + "integrity": "sha512-MYUxjSQSBUQmowc0l5nPieOYwMzGPUaTzB6inNW/bdPEG9zOL3eAAD1Qw5ZxSPk7we5dMojHwNODYMV1hq4EVg==", "engines": { - "node": ">= 14.15.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { + "@rspack/core": "0.x || 1.x", "less": "^3.5.0 || ^4.0.0", "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, "node_modules/less/node_modules/source-map": { @@ -3792,17 +3782,6 @@ "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/make-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", @@ -3881,11 +3860,11 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -3948,9 +3927,9 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.8.1.tgz", - "integrity": "sha512-/1HDlyFRxWIZPI1ZpgqlZ8jMw/1Dp/dl3P0L1jtZ+zVcHqwPhGwaJwKL00WVgfnBy6PWCde9W65or7IIETImuA==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.0.tgz", + "integrity": "sha512-Zs1YsZVfemekSZG+44vBsYTLQORkPMwnlv+aehcxK/NLKC+EGhDB39/YePYYqx/sTk6NnYpuqikhSn7+JIevTA==", "dependencies": { "schema-utils": "^4.0.0", "tapable": "^2.2.1" @@ -4600,9 +4579,9 @@ } }, "node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -4611,9 +4590,9 @@ } }, "node_modules/postcss-modules-local-by-default": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.4.tgz", - "integrity": "sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", "dependencies": { "icss-utils": "^5.0.0", "postcss-selector-parser": "^6.0.2", @@ -4627,9 +4606,9 @@ } }, "node_modules/postcss-modules-scope": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.1.tgz", - "integrity": "sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", "dependencies": { "postcss-selector-parser": "^6.0.4" }, @@ -4655,9 +4634,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.16", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", - "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz", + "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -4896,9 +4875,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -5147,12 +5126,9 @@ } }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "bin": { "semver": "bin/semver.js" }, @@ -5825,11 +5801,11 @@ } }, "node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "engines": { - "node": ">=16.13.0" + "node": ">=16" }, "peerDependencies": { "typescript": ">=4.2.0" @@ -5842,7 +5818,7 @@ "dependencies": { "chalk": "^4.1.0", "enhanced-resolve": "^5.0.0", - "micromatch": "^4.0.0", + "micromatch": "^4.0.6", "semver": "^7.3.4", "source-map": "^0.7.4" }, @@ -6129,9 +6105,9 @@ } }, "node_modules/webpack-bundle-analyzer": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz", - "integrity": "sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==", + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", "dependencies": { "@discoveryjs/json-ext": "0.5.7", "acorn": "^8.0.4", @@ -6141,7 +6117,6 @@ "escape-string-regexp": "^4.0.0", "gzip-size": "^6.0.0", "html-escaper": "^2.0.2", - "is-plain-object": "^5.0.0", "opener": "^1.5.2", "picocolors": "^1.0.0", "sirv": "^2.0.3", @@ -6659,11 +6634,6 @@ "node": ">=0.4" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 399e774d..ddb3ddca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "powerbi-visuals-tools", - "version": "5.4.3", + "version": "5.5.0", "description": "Command line tool for creating and publishing visuals for Power BI", "main": "./bin/pbiviz.js", "type": "module", @@ -29,7 +29,7 @@ }, "homepage": "https://github.com/Microsoft/PowerBI-visuals-tools#readme", "dependencies": { - "@typescript-eslint/parser": "^6.21.0", + "@typescript-eslint/parser": "^7.12.0", "assert": "^2.1.0", "async": "^3.2.5", "browserify-zlib": "^0.2.0", @@ -40,7 +40,7 @@ "console-browserify": "^1.2.0", "constants-browserify": "^1.0.0", "crypto-browserify": "^3.12.0", - "css-loader": "^6.10.0", + "css-loader": "^6.11.0", "domain-browser": "^5.7.0", "events": "^3.3.0", "extra-watch-webpack-plugin": "^1.0.3", @@ -50,12 +50,12 @@ "json-loader": "0.5.7", "jszip": "^3.10.1", "less": "^4.2.0", - "less-loader": "^11.1.4", + "less-loader": "^12.2.0", "lodash.clonedeep": "4.5.0", "lodash.defaults": "4.2.0", "lodash.isequal": "4.5.0", "lodash.ismatch": "^4.4.0", - "mini-css-extract-plugin": "^2.8.1", + "mini-css-extract-plugin": "^2.9.0", "os-browserify": "^0.3.0", "path-browserify": "^1.0.1", "powerbi-visuals-webpack-plugin": "4.1.0", @@ -75,16 +75,16 @@ "util": "^0.12.5", "vm-browserify": "^1.1.2", "webpack": "^5.91.0", - "webpack-bundle-analyzer": "4.10.1", + "webpack-bundle-analyzer": "4.10.2", "webpack-dev-server": "^4.15.2" }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/eslint-plugin": "^7.12.0", "eslint": "^8.57.0", "eslint-plugin-powerbi-visuals": "^0.8.1", "jasmine": "5.1.0", "jasmine-spec-reporter": "7.0.0", - "semver": "7.6.0", + "semver": "7.6.2", "tree-kill": "1.2.2", "webpack-cli": "^5.1.4" }, diff --git a/spec/e2e/pbivizCertSpec.js b/spec/e2e/pbivizCertSpec.js index 9da4629f..a8ac01ad 100644 --- a/spec/e2e/pbivizCertSpec.js +++ b/spec/e2e/pbivizCertSpec.js @@ -28,7 +28,8 @@ import fs from 'fs-extra'; import path from 'path'; -import { getRootPath, readJsonFromRoot } from '../../lib/utils.js'; +import os from 'os'; +import { readJsonFromRoot } from '../../lib/utils.js'; import { createCertFile } from '../../lib/CertificateTools.js'; const config = readJsonFromRoot('config.json'); @@ -40,10 +41,10 @@ describe("E2E - pbiviz install-cert", () => { describe("pbiviz", () => { it("pbiviz install-cert command should generate certificate", (done) => { - const rootPath = getRootPath(); - const certPath = path.join(rootPath, config.server.certificate); - const keyPath = path.join(rootPath, config.server.privateKey); - const pfxPath = path.join(rootPath, config.server.pfx); + const pathToCertFolder = path.join(os.homedir(), config.server.certificateFolder); + const certPath = path.join(pathToCertFolder, config.server.certificate); + const keyPath = path.join(pathToCertFolder, config.server.privateKey); + const pfxPath = path.join(pathToCertFolder, config.server.pfx); const certExists = fs.existsSync(certPath); const keyExists = fs.existsSync(keyPath); const pfxExists = fs.existsSync(pfxPath); diff --git a/src/CertificateTools.ts b/src/CertificateTools.ts index a2736818..5add279f 100644 --- a/src/CertificateTools.ts +++ b/src/CertificateTools.ts @@ -32,12 +32,18 @@ import fs from 'fs-extra'; import os from 'os'; import path from 'path'; import crypto from "crypto" -import { getRootPath, readJsonFromRoot } from './utils.js'; +import { readJsonFromRoot } from './utils.js'; import ConsoleWriter from './ConsoleWriter.js'; const certSafePeriod = 1000 * 60 * 60 * 24; // 24 hours -const rootPath = getRootPath(); -const confPath = '/config.json'; +const config = readJsonFromRoot('config.json'); +const pathToCertFolder = path.join(os.homedir(), config.server.certificateFolder); +const secretFilesPath = { + certPath: path.join(pathToCertFolder, config.server.certificate), + keyPath: path.join(pathToCertFolder, config.server.privateKey), + pfxPath: path.join(pathToCertFolder, config.server.pfx), + passphrasePath: path.join(pathToCertFolder, config.server.passphrase) +}; interface CertificateOptions { passphrase?: string; @@ -48,202 +54,132 @@ interface CertificateOptions { privateKey?: string; } -function exec(command, callback?): Promise { +function exec(command, options?, callback?): Promise { return new Promise((resolve, reject) => { - nodeExec(command, callback ? callback : (err, stdout: string, stderr) => { + const defaultCallback = (err, stdout: string, stderr) => { if (err) { reject(stderr); } resolve(stdout); - }); + }; + nodeExec(command, options, callback ? callback : defaultCallback); }); } export async function createCertificate() { - const config = readJsonFromRoot('config.json'); - const certPath = await getCertFile(config, true); + const certPath = await getCertFile(true); if (!certPath) { ConsoleWriter.error("Certificate not found. The new certificate will be generated"); - await createCertFile(config, true); + await createCertFile(true); } else { - await openCertFile(config); + await openCertFile(); } } -export async function createCertFile(config, open) { +export async function createCertFile(open = false) { ConsoleWriter.info(`Generating a new certificate...`); const subject = "localhost"; const keyLength = 2048; - const algorithm = "sha256"; const validPeriod = 365; - - if (typeof open === 'undefined') { - open = false; - } - - const certPath = path.join(rootPath, config.server.certificate); - const keyPath = path.join(rootPath, config.server.privateKey); - const pfxPath = path.join(rootPath, config.server.pfx); + const { certPath, keyPath, pfxPath } = secretFilesPath; const openCmds = { linux: 'openssl', darwin: 'openssl', - win32: 'powershell' + win32: 'pwsh' }; let startCmd = openCmds[os.platform()]; - if (startCmd) { - try { - let createCertCommand = ""; - switch (os.platform()) { - case "linux": - await removeCertFiles(certPath, keyPath); - createCertCommand = - ` req -newkey rsa:${keyLength}` + - ` -nodes` + - ` -keyout ${keyPath}` + - ` -x509 ` + - ` -days ${validPeriod} ` + - ` -out ${certPath} ` + - ` -subj "/CN=${subject}"`; - await exec(`${startCmd} ${createCertCommand}`); - if (await fs.exists(certPath)) { - ConsoleWriter.info(`Certificate generated. Location is ${certPath}`); - if (open) { - await openCertFile(config); - } - } - break; - case "darwin": - await removeCertFiles(certPath, keyPath); - createCertCommand = - ` req -newkey rsa:${keyLength}` + - ` -nodes` + - ` -keyout ${keyPath}` + - ` -x509 ` + - ` -days ${validPeriod} ` + - ` -out ${certPath} ` + - ` -subj "/CN=${subject}"`; - await exec(`${startCmd} ${createCertCommand}`); - if (await fs.exists(certPath)) { - ConsoleWriter.info(`Certificate generated. Location is ${certPath}`); - if (open) { - await openCertFile(config); - } - } - break; - case "win32": - // for windows 7 and others - // 6.1 - Windows 7 - const osVersion = os.release().split("."); - if ((Number(osVersion[0]) === 6 && Number(osVersion[1]) === 1) || Number(osVersion[0]) < 6) { - await removeCertFiles(certPath, keyPath, pfxPath); - startCmd = "openssl"; - createCertCommand = - ` req -newkey rsa:${keyLength}` + - ` -nodes` + - ` -keyout ${keyPath}` + - ` -x509 ` + - ` -days ${validPeriod} ` + - ` -out ${certPath} ` + - ` -subj "/CN=${subject}"`; - await exec(`${startCmd} ${createCertCommand}`); - if (await fs.exists(certPath)) { - ConsoleWriter.info(`Certificate generated. Location is ${certPath}`); - if (open) { - await openCertFile(config); - } - } - break; - } - let randomValues: Uint32Array; - if(crypto.getRandomValues !== undefined){ - randomValues = crypto.getRandomValues(new Uint32Array(1)); - } else { - randomValues = crypto.webcrypto.getRandomValues(new Uint32Array(1)); - } - const passphrase = randomValues[0].toString().substring(2); - config.server.passphrase = passphrase; - fs.writeFileSync(path.join(rootPath, confPath), JSON.stringify(config)); - // for windows 8 / 8.1 / server 2012 R2 / - if (Number(osVersion[0]) === 6 && (Number(osVersion[1]) === 2 || Number(osVersion[1]) === 3)) { - // for 10 - createCertCommand = `$cert = ('Cert:\\CurrentUser\\My\\' + (` + - ` New-SelfSignedCertificate ` + - ` -DnsName localhost ` + - ` -CertStoreLocation Cert:\\CurrentUser\\My ` + - ` | select Thumbprint | ` + - ` ForEach-Object { $_.Thumbprint.ToString() }).toString()); ` + - ` Export-PfxCertificate -Cert $cert` + - ` -FilePath '${pfxPath}' ` + - ` -Password (ConvertTo-SecureString -String '${passphrase}' -Force -AsPlainText)`; - - await exec(`${startCmd} "${createCertCommand}"`); - } else { - // for window 10 / server 2016 - createCertCommand = `$cert = ('Cert:\\CurrentUser\\My\\' + (` + - ` New-SelfSignedCertificate ` + - ` -DnsName localhost ` + - ` -HashAlgorithm ${algorithm} ` + - ` -Type Custom ` + - ` -Subject ${subject} ` + - ` -KeyAlgorithm RSA ` + - ` -KeyLength ${keyLength} ` + - ` -KeyExportPolicy Exportable ` + - ` -CertStoreLocation Cert:\\CurrentUser\\My ` + - ` -NotAfter (get-date).AddDays(${validPeriod}) ` + - ` | select Thumbprint | ` + - ` ForEach-Object { $_.Thumbprint.ToString() }).toString()); ` + - ` Export-PfxCertificate -Cert $cert` + - ` -FilePath '${pfxPath}' ` + - ` -Password (ConvertTo-SecureString -String '${passphrase}' -Force -AsPlainText)`; - - await exec(`${startCmd} "${createCertCommand}"`); - } - if (await fs.exists(pfxPath)) { - ConsoleWriter.info(`Certificate generated. Location is ${pfxPath}. Passphrase is '${passphrase}'`); + if (!startCmd) { + ConsoleWriter.error(['Unknown platform. Please place a custom-generated certificate in:', certPath]) + return; + } + + try { + let createCertCommand = ""; + let passphrase = ""; + fs.ensureDirSync(path.dirname(certPath)); + switch (os.platform()) { + case "linux": + case "darwin": + createCertCommand = + ` req -newkey rsa:${keyLength}` + + ` -nodes` + + ` -keyout ${keyPath}` + + ` -x509 ` + + ` -days ${validPeriod} ` + + ` -out ${certPath} ` + + ` -subj "/CN=${subject}"`; + await Promise.all([ + removeCertFiles(certPath, keyPath), + exec(`${startCmd} ${createCertCommand}`) + ]); + if (await fs.exists(certPath)) { + ConsoleWriter.info(`Certificate generated. Location is ${certPath}`); + if (open) { + await openCertFile(); } - break; - default: - ConsoleWriter.error('Unknown platform'); - } - } catch (e) { - if (e && e.message && e.message.indexOf("'openssl' is not recognized as an internal or external command") > 0) { - ConsoleWriter.warning('Create certificate error:'); - ConsoleWriter.warning('OpenSSL is not installed or not available from command line'); - ConsoleWriter.info('Install OpenSSL from https://www.openssl.org or https://wiki.openssl.org/index.php/Binaries'); - ConsoleWriter.info('and try again'); - - ConsoleWriter.info('Read more at'); - ConsoleWriter.info('https://github.com/Microsoft/PowerBI-visuals/blob/master/tools/CreateCertificate.md#manual'); - } else { - ConsoleWriter.error(['Create certificate error:', e]); - } + } + break; + case "win32": + passphrase = getRandomValues()[0].toString().substring(2); + createCertCommand = `$cert = ('Cert:\\CurrentUser\\My\\' + (` + + ` New-SelfSignedCertificate ` + + ` -DnsName localhost ` + + ` -Type Custom ` + + ` -Subject 'CN=${subject}' ` + + ` -KeyAlgorithm RSA ` + + ` -KeyLength ${keyLength} ` + + ` -KeyExportPolicy Exportable ` + + ` -CertStoreLocation Cert:\\CurrentUser\\My ` + + ` -NotAfter (get-date).AddDays(${validPeriod}) ` + + ` | select Thumbprint | ` + + ` ForEach-Object { $_.Thumbprint.ToString() }).toString()); ` + + ` Export-PfxCertificate -Cert $cert` + + ` -FilePath '${pfxPath}' ` + + ` -Password (ConvertTo-SecureString -String '${passphrase}' -Force -AsPlainText)`; + await Promise.all([ + removeCertFiles(certPath, keyPath, pfxPath), + exec(`${startCmd} -Command "${createCertCommand}"`), + savePassphrase(passphrase) + ]); + if (await fs.exists(pfxPath)) { + ConsoleWriter.info(`Certificate generated. Location is ${pfxPath}. Passphrase is ${passphrase}`); + } + break; + default: + ConsoleWriter.error('Unknown platform'); + break; + } + } catch (e) { + if (e && e.message && e.message.indexOf("'openssl' is not recognized as an internal or external command") > 0) { + ConsoleWriter.warning('Create certificate error:'); + ConsoleWriter.warning('OpenSSL is not installed or not available from command line'); + ConsoleWriter.info('Install OpenSSL from https://www.openssl.org or https://wiki.openssl.org/index.php/Binaries'); + ConsoleWriter.info('and try again'); + + ConsoleWriter.info('Read more at'); + ConsoleWriter.info('https://github.com/Microsoft/PowerBI-visuals/blob/master/tools/CreateCertificate.md#manual'); + } else { + ConsoleWriter.error(['Create certificate error:', e]); } - } else { - ConsoleWriter.error(['Unknown platform. Please place a custom-generated certificate in:', certPath]); } } -async function getCertFile(config, silent?) { - if (typeof silent === "undefined") { - silent = false; +async function getCertFile(silent = false) { + const { certPath, pfxPath, passphrasePath } = secretFilesPath; + if (await fs.exists(certPath)) { + return certPath; } - const cert = path.join(rootPath, config.server.certificate); - const pfx = path.join(rootPath, config.server.pfx); - if (await fs.exists(cert)) { - return cert; - } - if (await fs.exists(pfx)) { - if (config.server.passphrase) { - if (!silent) { - ConsoleWriter.info(`Use '${config.server.passphrase}' passphrase to install PFX certificate.`); - } + if (await fs.exists(pfxPath)) { + if (!silent && await fs.exists(passphrasePath)) { + const passphrase = await fs.readFile(passphrasePath, 'utf8') + ConsoleWriter.info(`Use '${passphrase}' passphrase to install PFX certificate.`); } - return pfx; + return pfxPath; } if (!silent) { @@ -252,88 +188,45 @@ async function getCertFile(config, silent?) { return null; } -async function openCertFile(config) { - const certPath = await getCertFile(config); - - if (!certPath) { - return null; - } - +async function openCertFile() { const openCmds = { linux: 'xdg-open', darwin: 'open', win32: 'powershell start' }; const startCmd = openCmds[os.platform()]; - if (startCmd) { - try { - await exec(`${startCmd} "${certPath}"`); - } catch (e) { - ConsoleWriter.info(['Certificate path:', certPath]); - } - } else { - ConsoleWriter.info(['Certificate path:', certPath]); - } -} - -export async function removeCertFiles(certPath, keyPath, pfxPath?) { - try { - await fs.unlink(certPath); - } catch (e) { - if (!e.message.indexOf("no such file or directory")) { - throw e; - } - } + const certPath = await getCertFile(); try { - await fs.unlink(keyPath); - } catch (e) { - if (!e.message.indexOf("no such file or directory")) { - throw e; + if (!startCmd || !certPath) { + throw new Error(); } - } - try { - await fs.unlink(pfxPath); + await exec(`${startCmd} "${certPath}"`); } catch (e) { - if (!e.message.indexOf("no such file or directory")) { - throw e; - } + ConsoleWriter.info(['Certificate path:', certPath]); } } -async function getGlobalPbivizCerts(config) { - const options: CertificateOptions = {}; - try { - const location = (await exec('npm ls -g powerbi-visuals-tools')).split("\n")[0]; - const certPath = path.join(location, "node_modules", "powerbi-visuals-tools", config.server.certificate); - const keyPath = path.join(location, "node_modules", "powerbi-visuals-tools", config.server.privateKey); - const pfxPath = path.join(location, "node_modules", "powerbi-visuals-tools", config.server.pfx); - const globalPbivizConfig = path.join(location, "node_modules", "powerbi-visuals-tools", "config.json"); - options.passphrase = fs.existsSync(globalPbivizConfig) && fs.readJSONSync(globalPbivizConfig).server.passphrase; - - const CertFileVerified = await verifyCertFile(keyPath, certPath, pfxPath, options.passphrase); - - options.cert = fs.existsSync(certPath) && certPath; - options.key = fs.existsSync(keyPath) && keyPath; - options.pfx = fs.existsSync(pfxPath) && CertFileVerified && pfxPath; - } - catch (err) { - ConsoleWriter.warning(`Global certificate error: ${err}`); - } - if (!options.cert && !options.pfx) { - ConsoleWriter.warning(`Global instance of valid pbiviz certificate not found.`); - } - return options; +export async function removeCertFiles(...paths) { + paths.forEach(async (path) => { + try { + await fs.unlink(path); + } catch (e) { + if (!e.message.indexOf("no such file or directory")) { + throw e; + } + } + }); } export async function resolveCertificate() { - const config = readJsonFromRoot('config.json'); const options: CertificateOptions = {}; - const keyPath = path.join(rootPath, config.server.privateKey); - const certPath = path.join(rootPath, config.server.certificate); - const pfxPath = path.join(rootPath, config.server.pfx); - - if (config.server.passphrase) { - options.passphrase = config.server.passphrase; + const { certPath, keyPath, pfxPath, passphrasePath } = secretFilesPath; + const isCertificateValid = await verifyCertFile(keyPath, certPath, pfxPath, passphrasePath); + if (!isCertificateValid) { + await createCertFile(); + } + if (await fs.exists(passphrasePath)) { + options.passphrase = await fs.readFile(passphrasePath, 'utf8'); } if (await fs.exists(keyPath)) { options.key = await fs.readFile(keyPath); @@ -344,77 +237,25 @@ export async function resolveCertificate() { if (await fs.exists(pfxPath)) { options.pfx = await fs.readFile(pfxPath); } - - const CertFileVerified = await verifyCertFile(keyPath, certPath, pfxPath, options.passphrase); - - if ((!options.cert && !options.pfx) || !CertFileVerified) { - ConsoleWriter.warning("Local valid certificate not found."); - ConsoleWriter.info("Checking global instance of pbiviz certificate..."); - const globalPbivizOptions = await getGlobalPbivizCerts(config); - - if (!globalPbivizOptions.cert && !globalPbivizOptions.pfx) { - await createCertFile(config, true); - if (!(await getCertFile(config, true))) { - ConsoleWriter.error('Certificate wasn\'t created'); - throw new Error("Call `pbiviz install-cert` command to create the new certificate"); - } - else { - if (config.server.passphrase) { - options.passphrase = config.server.passphrase; - } - if (await fs.exists(keyPath)) { - options.key = await fs.readFile(keyPath); - } - if (await fs.exists(certPath)) { - options.cert = await fs.readFile(certPath); - } - if (await fs.exists(pfxPath)) { - options.pfx = await fs.readFile(pfxPath); - } - } - } - else { - // copy certs to local instance - ConsoleWriter.info("Copy server certificate from global instance of pbiviz..."); - if (globalPbivizOptions.cert) { - await fs.copyFile(globalPbivizOptions.cert, path.join(rootPath, config.server.certificate)); - options.certificate = config.server.certificate; - } - if (globalPbivizOptions.key) { - await fs.copyFile(globalPbivizOptions.key, path.join(rootPath, config.server.privateKey)); - options.privateKey = config.server.privateKey; - } - if (globalPbivizOptions.pfx) { - await fs.copyFile(globalPbivizOptions.pfx, path.join(rootPath, config.server.pfx)); - // need to pass whole file instead path to file - options.pfx = await fs.readFile(path.join(rootPath, config.server.pfx)); - options.passphrase = globalPbivizOptions.passphrase; - // eslint-disable-next-line require-atomic-updates - config.server.passphrase = globalPbivizOptions.passphrase; - } - await fs.writeFile(path.join(rootPath, confPath), JSON.stringify(config)); - } - } return options; } -export async function verifyCertFile(keyPath, certPath, pfxPath, passphrase) { - let verifyCertDate; +export async function verifyCertFile(keyPath, certPath, pfxPath, passphrasePath) { + let verifyCertDate = false; try { let endDateStr; - // For Windows OS: if (os.platform() === "win32") { - if (!fs.existsSync(pfxPath) || !passphrase) { - return false; + if (!fs.existsSync(pfxPath) || !fs.existsSync(passphrasePath)) { + throw new Error('PFX or passphrase file not found'); } - const certStr = await exec(`powershell.exe (New-Object System.Security.Cryptography.X509Certificates.X509Certificate2('${pfxPath}','${passphrase}')).NotAfter.ToString('yyyy-MM-dd HH:mm:ss')`); + const passphrase = await fs.readFile(passphrasePath, 'utf8'); + const command = `(New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("${pfxPath}",'${passphrase}')).NotAfter.ToString('yyyy-MM-dd HH:mm:ss')`; + const certStr = await exec(command, { shell: 'powershell.exe' }); endDateStr = certStr.trim(); - } - // For Linux and Mac/darwin OS: - else if (os.platform() === "linux" || os.platform() === "darwin") { - if (!fs.existsSync(certPath)) { - return false; + } else if (os.platform() === "linux" || os.platform() === "darwin") { + if (!(await fs.exists(certPath))) { + throw new Error('Certificate file not found'); } endDateStr = await exec(`openssl x509 -enddate -noout -in ${certPath} | cut -d = -f 2`); } @@ -424,12 +265,23 @@ export async function verifyCertFile(keyPath, certPath, pfxPath, passphrase) { if (verifyCertDate) { ConsoleWriter.info(`Certificate is valid.`); } else { - ConsoleWriter.warning(`Certificate is invalid!`); - removeCertFiles(certPath, keyPath, pfxPath); + throw new Error('Certificate is invalid'); } } catch (err) { ConsoleWriter.warning(`Certificate verification error: ${err}`); - removeCertFiles(certPath, keyPath, pfxPath); + removeCertFiles(certPath, keyPath, pfxPath, passphrasePath); } return verifyCertDate; } + +const getRandomValues = () => { + if(crypto.getRandomValues !== undefined){ + return crypto.getRandomValues(new Uint32Array(1)); + } + return crypto.webcrypto.getRandomValues(new Uint32Array(1)); +} + +const savePassphrase = async (passphrase) => { + const { passphrasePath } = secretFilesPath; + await fs.writeFileSync(passphrasePath, passphrase); +} \ No newline at end of file diff --git a/src/LintValidator.ts b/src/LintValidator.ts index 99cd1ba6..b5c0fb45 100644 --- a/src/LintValidator.ts +++ b/src/LintValidator.ts @@ -1,10 +1,10 @@ import { ESLint } from "eslint"; import path from 'path'; -import fs from 'fs'; +import fs from 'fs-extra'; import ConsoleWriter from "./ConsoleWriter.js"; import { LintOptions } from "./CommandManager.js"; -import { fileExists, getRootPath } from "./utils.js"; +import { getRootPath } from "./utils.js"; export class LintValidator { @@ -70,7 +70,7 @@ export class LintValidator { resolvePluginsRelativeTo: this.getPluginPath() } const eslintrcExtensions = ['.json', '.js', '.cjs', '.ts', ''] - if (!this.useDefault && eslintrcExtensions.some(el => fileExists(this.visualPath, `.eslintrc${el}`))){ + if (!this.useDefault && eslintrcExtensions.some(el => fs.existsSync(path.join(this.visualPath, `.eslintrc${el}`)))) { this.config = requiredConfig } else { ConsoleWriter.warning("Using recommended eslint config.") diff --git a/src/utils.ts b/src/utils.ts index b1a09172..b85b882c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -26,7 +26,7 @@ export function getRootPath(): string { return path.join(pathToDirectory, "..", ".."); } -export function readFileFromRoot(filePath: string) { +function readFileFromRoot(filePath: string) { return fs.readFileSync(path.join(getRootPath(), filePath), "utf8") } @@ -36,8 +36,4 @@ export function readJsonFromRoot(filePath: string) { export function readJsonFromVisual(filePath: string, visualPath?: string) { return JSON.parse(fs.readFileSync(path.join(visualPath ?? process.cwd(), filePath), "utf8")); -} - -export function fileExists(pathToFile: string, fileName: string) { - return fs.existsSync(path.join(pathToFile, fileName)); } \ No newline at end of file diff --git a/src/webpack.config.ts b/src/webpack.config.ts index 0826d4c2..3e534d2f 100644 --- a/src/webpack.config.ts +++ b/src/webpack.config.ts @@ -75,6 +75,7 @@ const webpackConfig = { "powerbi-visuals-api": 'null' }, resolve: { + symlinks: false, extensions: ['.tsx', '.ts', '.jsx', '.js', '.mjs', '.css'], modules: ['node_modules', path.resolve(rootPath, 'node_modules')], fallback: {