From f2ac807486a00db4ba8486133d567e392f0fe98a Mon Sep 17 00:00:00 2001 From: vnugent Date: Sat, 9 Mar 2024 16:28:52 -0500 Subject: fix: #1 logout redirection updated to support social methods --- lib/vnlib.browser/package-lock.json | 388 ++++++++++---------- lib/vnlib.browser/package.json | 3 +- lib/vnlib.browser/src/helpers/lastPage.ts | 122 ------- lib/vnlib.browser/src/helpers/pageGuard.ts | 53 --- lib/vnlib.browser/src/index.ts | 2 - lib/vnlib.browser/src/social/index.ts | 394 +++++++++++++-------- .../src/Auth0Portal.cs | 16 +- .../src/Endpoints/LogoutEndpoint.cs | 40 ++- .../src/DiscordPortal.cs | 11 +- .../src/GithubPortal.cs | 13 +- 10 files changed, 464 insertions(+), 578 deletions(-) delete mode 100644 lib/vnlib.browser/src/helpers/lastPage.ts delete mode 100644 lib/vnlib.browser/src/helpers/pageGuard.ts diff --git a/lib/vnlib.browser/package-lock.json b/lib/vnlib.browser/package-lock.json index 9ca3ed0..acb1b62 100644 --- a/lib/vnlib.browser/package-lock.json +++ b/lib/vnlib.browser/package-lock.json @@ -21,8 +21,7 @@ "jose": "^5.x", "lodash-es": "^4.x", "universal-cookie": "^7.0.x", - "vue": "^3.x", - "vue-router": "^4.x" + "vue": "^3.x" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -53,9 +52,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", - "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz", + "integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==", "peer": true, "bin": { "parser": "bin/babel-parser.js" @@ -65,9 +64,9 @@ } }, "node_modules/@babel/types": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", - "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.23.4", @@ -146,22 +145,22 @@ } }, "node_modules/@eslint/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "peer": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -204,9 +203,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "peer": true }, "node_modules/@jridgewell/sourcemap-codec": { @@ -275,18 +274,18 @@ } }, "node_modules/@types/node": { - "version": "20.10.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.6.tgz", - "integrity": "sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==", + "version": "20.11.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz", + "integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==", "dev": true, "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/@types/semver": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@types/web-bluetooth": { @@ -296,16 +295,16 @@ "peer": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.0.tgz", - "integrity": "sha512-3lqEvQUdCozi6d1mddWqd+kf8KxmGq2Plzx36BlkjuQe3rSTm/O98cLf0A4uDO+a5N1KD2SeEEl6fW97YHY+6w==", + "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==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.18.0", - "@typescript-eslint/type-utils": "6.18.0", - "@typescript-eslint/utils": "6.18.0", - "@typescript-eslint/visitor-keys": "6.18.0", + "@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", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -331,16 +330,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.0.tgz", - "integrity": "sha512-v6uR68SFvqhNQT41frCMCQpsP+5vySy6IdgjlzUWoo7ALCnpaWYcz/Ij2k4L8cEsL0wkvOviCMpjmtRtHNOKzA==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.18.0", - "@typescript-eslint/types": "6.18.0", - "@typescript-eslint/typescript-estree": "6.18.0", - "@typescript-eslint/visitor-keys": "6.18.0", + "@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", "debug": "^4.3.4" }, "engines": { @@ -360,13 +359,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.0.tgz", - "integrity": "sha512-o/UoDT2NgOJ2VfHpfr+KBY2ErWvCySNUIX/X7O9g8Zzt/tXdpfEU43qbNk8LVuWUT2E0ptzTWXh79i74PP0twA==", + "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==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.18.0", - "@typescript-eslint/visitor-keys": "6.18.0" + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -377,13 +376,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.0.tgz", - "integrity": "sha512-ZeMtrXnGmTcHciJN1+u2CigWEEXgy1ufoxtWcHORt5kGvpjjIlK9MUhzHm4RM8iVy6dqSaZA/6PVkX6+r+ChjQ==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.18.0", - "@typescript-eslint/utils": "6.18.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -404,9 +403,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.0.tgz", - "integrity": "sha512-/RFVIccwkwSdW/1zeMx3hADShWbgBxBnV/qSrex6607isYjj05t36P6LyONgqdUrNLl5TYU8NIKdHUYpFvExkA==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -417,13 +416,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.0.tgz", - "integrity": "sha512-klNvl+Ql4NsBNGB4W9TZ2Od03lm7aGvTbs0wYaFYsplVPhr+oeXjlPZCDI4U9jgJIDK38W1FKhacCFzCC+nbIg==", + "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==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.18.0", - "@typescript-eslint/visitor-keys": "6.18.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -445,17 +444,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.0.tgz", - "integrity": "sha512-wiKKCbUeDPGaYEYQh1S580dGxJ/V9HI7K5sbGAVklyf+o5g3O+adnS4UNJajplF4e7z2q0uVBaTdT/yLb4XAVA==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", "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.18.0", - "@typescript-eslint/types": "6.18.0", - "@typescript-eslint/typescript-estree": "6.18.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" }, "engines": { @@ -470,12 +469,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.0.tgz", - "integrity": "sha512-1wetAlSZpewRDb2h9p/Q8kRjdGuqdTAQbkJIOUMLug2LBLG+QOjiWoSj6/3B/hA9/tVTFFdtiKvAYoYnSRW/RA==", + "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==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/types": "6.21.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -493,129 +492,123 @@ "peer": true }, "node_modules/@vue/compiler-core": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.5.tgz", - "integrity": "sha512-Daka7P1z2AgKjzuueWXhwzIsKu0NkLB6vGbNVEV2iJ8GJTrzraZo/Sk4GWCMRtd/qVi3zwnk+Owbd/xSZbwHtQ==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.21.tgz", + "integrity": "sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==", "peer": true, "dependencies": { - "@babel/parser": "^7.23.6", - "@vue/shared": "3.4.5", + "@babel/parser": "^7.23.9", + "@vue/shared": "3.4.21", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.0.2" } }, "node_modules/@vue/compiler-dom": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.5.tgz", - "integrity": "sha512-J8YlxknJVd90SXFJ4HwGANSAXsx5I0lK30sO/zvYV7s5gXf7gZR7r/1BmZ2ju7RGH1lnc6bpBc6nL61yW+PsAQ==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.21.tgz", + "integrity": "sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==", "peer": true, "dependencies": { - "@vue/compiler-core": "3.4.5", - "@vue/shared": "3.4.5" + "@vue/compiler-core": "3.4.21", + "@vue/shared": "3.4.21" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.5.tgz", - "integrity": "sha512-jauvkDuSSUbP0ebhfNqljhShA90YEfX/0wZ+w40oZF43IjGyWYjqYaJbvMJwGOd+9+vODW6eSvnk28f0SGV7OQ==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.21.tgz", + "integrity": "sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==", "peer": true, "dependencies": { - "@babel/parser": "^7.23.6", - "@vue/compiler-core": "3.4.5", - "@vue/compiler-dom": "3.4.5", - "@vue/compiler-ssr": "3.4.5", - "@vue/shared": "3.4.5", + "@babel/parser": "^7.23.9", + "@vue/compiler-core": "3.4.21", + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-ssr": "3.4.21", + "@vue/shared": "3.4.21", "estree-walker": "^2.0.2", - "magic-string": "^0.30.5", - "postcss": "^8.4.32", + "magic-string": "^0.30.7", + "postcss": "^8.4.35", "source-map-js": "^1.0.2" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.5.tgz", - "integrity": "sha512-DDdEcDzj2lWTMfUMMtEpLDhURai9LhM0zSZ219jCt7b2Vyl0/jy3keFgCPMitG0V1S1YG4Cmws3lWHWdxHQOpg==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.21.tgz", + "integrity": "sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==", "peer": true, "dependencies": { - "@vue/compiler-dom": "3.4.5", - "@vue/shared": "3.4.5" + "@vue/compiler-dom": "3.4.21", + "@vue/shared": "3.4.21" } }, - "node_modules/@vue/devtools-api": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.1.tgz", - "integrity": "sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==", - "peer": true - }, "node_modules/@vue/reactivity": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.5.tgz", - "integrity": "sha512-BcWkKvjdvqJwb7BhhFkXPLDCecX4d4a6GATvCduJQDLv21PkPowAE5GKuIE5p6RC07/Lp9FMkkq4AYCTVF5KlQ==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.21.tgz", + "integrity": "sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==", "peer": true, "dependencies": { - "@vue/shared": "3.4.5" + "@vue/shared": "3.4.21" } }, "node_modules/@vue/runtime-core": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.5.tgz", - "integrity": "sha512-wh9ELIOQKeWT9SaUPdLrsxRkZv14jp+SJm9aiQGWio+/MWNM3Lib0wE6CoKEqQ9+SCYyGjDBhTOTtO47kCgbkg==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.21.tgz", + "integrity": "sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==", "peer": true, "dependencies": { - "@vue/reactivity": "3.4.5", - "@vue/shared": "3.4.5" + "@vue/reactivity": "3.4.21", + "@vue/shared": "3.4.21" } }, "node_modules/@vue/runtime-dom": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.5.tgz", - "integrity": "sha512-n5ewvOjyG3IEpqGBahdPXODFSpVlSz3H4LF76Sx0XAqpIOqyJ5bIb2PrdYuH2ogBMAQPh+o5tnoH4nJpBr8U0Q==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.21.tgz", + "integrity": "sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==", "peer": true, "dependencies": { - "@vue/runtime-core": "3.4.5", - "@vue/shared": "3.4.5", + "@vue/runtime-core": "3.4.21", + "@vue/shared": "3.4.21", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.5.tgz", - "integrity": "sha512-jOFc/VE87yvifQpNju12VcqimH8pBLxdcT+t3xMeiED1K6DfH9SORyhFEoZlW5TG2Vwfn3Ul5KE+1aC99xnSBg==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.21.tgz", + "integrity": "sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==", "peer": true, "dependencies": { - "@vue/compiler-ssr": "3.4.5", - "@vue/shared": "3.4.5" + "@vue/compiler-ssr": "3.4.21", + "@vue/shared": "3.4.21" }, "peerDependencies": { - "vue": "3.4.5" + "vue": "3.4.21" } }, "node_modules/@vue/shared": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.5.tgz", - "integrity": "sha512-6XptuzlMvN4l4cDnDw36pdGEV+9njYkQ1ZE0Q6iZLwrKefKaOJyiFmcP3/KBDHbt72cJZGtllAc1GaHe6XGAyg==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.21.tgz", + "integrity": "sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==", "peer": true }, "node_modules/@vueuse/core": { - "version": "10.7.1", - "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.7.1.tgz", - "integrity": "sha512-74mWHlaesJSWGp1ihg76vAnfVq9NTv1YT0SYhAQ6zwFNdBkkP+CKKJmVOEHcdSnLXCXYiL5e7MaewblfiYLP7g==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.9.0.tgz", + "integrity": "sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==", "peer": true, "dependencies": { "@types/web-bluetooth": "^0.0.20", - "@vueuse/metadata": "10.7.1", - "@vueuse/shared": "10.7.1", - "vue-demi": ">=0.14.6" + "@vueuse/metadata": "10.9.0", + "@vueuse/shared": "10.9.0", + "vue-demi": ">=0.14.7" }, "funding": { "url": "https://github.com/sponsors/antfu" } }, "node_modules/@vueuse/core/node_modules/vue-demi": { - "version": "0.14.6", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", - "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", + "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", "hasInstallScript": true, "peer": true, "bin": { @@ -639,30 +632,30 @@ } }, "node_modules/@vueuse/metadata": { - "version": "10.7.1", - "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.7.1.tgz", - "integrity": "sha512-jX8MbX5UX067DYVsbtrmKn6eG6KMcXxLRLlurGkZku5ZYT3vxgBjui2zajvUZ18QLIjrgBkFRsu7CqTAg18QFw==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.9.0.tgz", + "integrity": "sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA==", "peer": true, "funding": { "url": "https://github.com/sponsors/antfu" } }, "node_modules/@vueuse/shared": { - "version": "10.7.1", - "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.7.1.tgz", - "integrity": "sha512-v0jbRR31LSgRY/C5i5X279A/WQjD6/JsMzGa+eqt658oJ75IvQXAeONmwvEMrvJQKnRElq/frzBR7fhmWY5uLw==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.9.0.tgz", + "integrity": "sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==", "peer": true, "dependencies": { - "vue-demi": ">=0.14.6" + "vue-demi": ">=0.14.7" }, "funding": { "url": "https://github.com/sponsors/antfu" } }, "node_modules/@vueuse/shared/node_modules/vue-demi": { - "version": "0.14.6", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", - "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", + "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", "hasInstallScript": true, "peer": true, "bin": { @@ -768,9 +761,9 @@ "peer": true }, "node_modules/axios": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", - "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", + "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", "peer": true, "dependencies": { "follow-redirects": "^1.15.4", @@ -974,16 +967,16 @@ } }, "node_modules/eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -1189,9 +1182,9 @@ "peer": true }, "node_modules/fastq": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dependencies": { "reusify": "^1.0.4" } @@ -1251,15 +1244,15 @@ } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "peer": true }, "node_modules/follow-redirects": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", - "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", "funding": [ { "type": "individual", @@ -1400,9 +1393,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" } @@ -1492,9 +1485,9 @@ "peer": true }, "node_modules/jose": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/jose/-/jose-5.2.0.tgz", - "integrity": "sha512-oW3PCnvyrcm1HMvGTzqjxxfnEs9EoFOFWi2HsEGhlFVOXxTE3K9GKWVMFoFw06yPUqwpvEWic1BmtUZBI/tIjw==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.2.3.tgz", + "integrity": "sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA==", "peer": true, "funding": { "url": "https://github.com/sponsors/panva" @@ -1592,9 +1585,9 @@ } }, "node_modules/magic-string": { - "version": "0.30.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", - "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", "peer": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" @@ -1812,9 +1805,9 @@ } }, "node_modules/postcss": { - "version": "8.4.33", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", - "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", "funding": [ { "type": "opencollective", @@ -1938,9 +1931,9 @@ } }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -2055,12 +2048,12 @@ } }, "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.2.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", + "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", "dev": true, "engines": { - "node": ">=16.13.0" + "node": ">=16" }, "peerDependencies": { "typescript": ">=4.2.0" @@ -2091,9 +2084,9 @@ } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "devOptional": true, "peer": true, "bin": { @@ -2111,9 +2104,9 @@ "dev": true }, "node_modules/universal-cookie": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-7.0.1.tgz", - "integrity": "sha512-6OuX9xELF6dsVJeADJAYNDOxQf/NR3Na5bGCRd+hkysMDkSt79jJ4tdv5OBe+ZgAks3ExHBdCXkD2SjqLyK59w==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-7.1.0.tgz", + "integrity": "sha512-LCLHwP0whxTqkBYMptW1dzNS0xxIVJmU6c51N5CfPNheVxuJW7fVxPa6MUGX7boUSyOlpMveBO96hMs5Gee6Fg==", "peer": true, "dependencies": { "@types/cookie": "^0.6.0", @@ -2130,16 +2123,16 @@ } }, "node_modules/vue": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.5.tgz", - "integrity": "sha512-VH6nHFhLPjgu2oh5vEBXoNZxsGHuZNr3qf4PHClwJWw6IDqw6B3x+4J+ABdoZ0aJuT8Zi0zf3GpGlLQCrGWHrw==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.21.tgz", + "integrity": "sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==", "peer": true, "dependencies": { - "@vue/compiler-dom": "3.4.5", - "@vue/compiler-sfc": "3.4.5", - "@vue/runtime-dom": "3.4.5", - "@vue/server-renderer": "3.4.5", - "@vue/shared": "3.4.5" + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-sfc": "3.4.21", + "@vue/runtime-dom": "3.4.21", + "@vue/server-renderer": "3.4.21", + "@vue/shared": "3.4.21" }, "peerDependencies": { "typescript": "*" @@ -2150,21 +2143,6 @@ } } }, - "node_modules/vue-router": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.5.tgz", - "integrity": "sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==", - "peer": true, - "dependencies": { - "@vue/devtools-api": "^6.5.0" - }, - "funding": { - "url": "https://github.com/sponsors/posva" - }, - "peerDependencies": { - "vue": "^3.2.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/lib/vnlib.browser/package.json b/lib/vnlib.browser/package.json index 1c63ba1..056b187 100644 --- a/lib/vnlib.browser/package.json +++ b/lib/vnlib.browser/package.json @@ -11,7 +11,7 @@ "typings": "./dist/index.d.ts", "output":"bin", "scripts": { - "lint": "eslint --ext .js,.ts --ignore-path .gitignore src", + "lint": "eslint --ext .js,.ts src", "build": "tsc", "clean": "if exist dist ( rd /S /Q lib)" }, @@ -27,7 +27,6 @@ "@vueuse/core": "^10.x", "lodash-es": "^4.x", "vue": "^3.x", - "vue-router": "^4.x", "axios": "^1.x", "eslint": "^8.39.0", "jose": "^5.x", diff --git a/lib/vnlib.browser/src/helpers/lastPage.ts b/lib/vnlib.browser/src/helpers/lastPage.ts deleted file mode 100644 index b3c7103..0000000 --- a/lib/vnlib.browser/src/helpers/lastPage.ts +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) 2024 Vaughn Nugent -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import { defaultTo } from "lodash-es"; -import { useRouter } from "vue-router" - -export interface ILastPage{ - /** - * Pushes the current page into the last-page stack - */ - push(): void; - /** - * Stores the current page and navigates to the desired route - * @param route The route to navigate to - */ - pushAndNavigate(route: object): void; - /** - * Navigates to the last page if it exists - */ - gotoLastPage(): void; -} - -export interface ILastPageStorage { - - /** - * Pushes the current page into the last-page stack - */ - push(route: string): void; - - /** - * Pops the last page from the last-page stack storage - * @returns {any} The last page route object stored - */ - pop(): string | null; -} - -/** - * Represents a router-like object that can be used - * to navigate to a desired route - */ -export interface RouterLike{ - currentRoute: { - value: { - fullPath: string; - } - } - push(route: object | string): void; -} - -const storageKey = "lastPage"; - -//Storage impl -const defaultStack = (): ILastPageStorage => { - const storage = sessionStorage; - - const push = (route: string) => { - //Serialize the route data and store it - storage?.setItem(storageKey, route); - } - - const pop = (): string | null => { - //Get the route data and deserialize it - const route = storage?.getItem(storageKey); - if (route) { - storage?.removeItem(storageKey); - return route; - } - return null; - } - return { push, pop } -} - -/** - * Gets the configuration for the last page the user was on - * when the page guard was called. This is used to return to the - * last page after login. - * @returns { gotoLastPage: Function } - */ -export const useLastPage = (storage?: ILastPageStorage, router?: RouterLike): ILastPage => { - - //fallback to default storage - const _storage = defaultTo(storage, defaultStack()); - - //Get the current router instance - const _router = defaultTo(router, useRouter()); - - //Store the current page to the last page stack - const push = () => _storage.push(_router.currentRoute.value.fullPath); - - const pushAndNavigate = (route: object) => { - //Store the current page to the last page stack - push(); - //Navigate to the desired route - _router.push(route); - }; - - const gotoLastPage = () => { - //Get the last stored page and navigate to it - const lp = _storage.pop(); - if (lp) { - _router.push(lp); - } - }; - - return { push, pushAndNavigate, gotoLastPage } -} \ No newline at end of file diff --git a/lib/vnlib.browser/src/helpers/pageGuard.ts b/lib/vnlib.browser/src/helpers/pageGuard.ts deleted file mode 100644 index e6a92c6..0000000 --- a/lib/vnlib.browser/src/helpers/pageGuard.ts +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2024 Vaughn Nugent -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import { watch } from 'vue' -import { useSession } from "../session"; -import { useLastPage } from './lastPage'; -import type { ILastPageStorage, RouterLike } from "./lastPage"; - -export interface PageGuardOptions { - readonly stack: ILastPageStorage; - readonly router: RouterLike; -} - -/** - * When called, configures the component to - * only be visible when the user is logged in. If the user is - * not logged in, the user is redirected to the login page. - * @remarks Once called, if the user is logged-in changes will be - * watch to redirect if the user becomes logged out. -*/ -export const usePageGuard = (loginRoute = { name: 'Login' }, options?: Partial): void => { - //Get the session state - const session = useSession(); - - //Get last page controller, fall back to default session storage stack - const { pushAndNavigate } = useLastPage(options?.stack, options?.router) - - // Initial check for logged in to guard the page - if (!session.loggedIn.value) { - //Store last route and redirect to login - pushAndNavigate(loginRoute); - } - - // setup watcher on session login value - // If the login value changes to false, redirect to login page - watch(session.loggedIn, value => value === false ? pushAndNavigate(loginRoute) : null) -} diff --git a/lib/vnlib.browser/src/index.ts b/lib/vnlib.browser/src/index.ts index 0072092..47cd9e9 100644 --- a/lib/vnlib.browser/src/index.ts +++ b/lib/vnlib.browser/src/index.ts @@ -51,9 +51,7 @@ export * from './helpers/apiCall' export * from './helpers/autoHeartbeat' export * from './helpers/confirm' export * from './helpers/envSize' -export * from './helpers/lastPage' export * from './helpers/message' -export * from './helpers/pageGuard' export * from './helpers/serverObjectBuffer' export * from './helpers/validation' export * from './helpers/wait' diff --git a/lib/vnlib.browser/src/social/index.ts b/lib/vnlib.browser/src/social/index.ts index d4f9f2a..dac3cc9 100644 --- a/lib/vnlib.browser/src/social/index.ts +++ b/lib/vnlib.browser/src/social/index.ts @@ -1,6 +1,5 @@ -import { find, isEqual, map } from "lodash-es"; -import { get } from "@vueuse/core"; -import { MaybeRef } from "vue"; +import { find, first, isArray, isEqual, map } from "lodash-es"; +import { Mutable, get } from "@vueuse/core"; import Cookies from "universal-cookie"; import { useUser } from "../user"; import { useAxios } from "../axios"; @@ -10,29 +9,12 @@ import { type AxiosRequestConfig } from "axios"; export type SocialServerSetQuery = 'invalid' | 'expired' | 'authorized'; -export interface OAuthMethod{ - /** - * Gets the url to the login endpoint for this method - */ - readonly Id: string - /** - * The endpoint to submit the authentication request to - */ - loginUrl(): string - /** - * Called when the login to this method was successful - */ - onSuccessfulLogin?:() => void - /** - * Called when the logout to this method was successful - */ - onSuccessfulLogout?:(responseData: unknown) => void - /** - * Gets the data to send to the logout endpoint, if this method - * is undefined, then the logout will be handled by the normal user logout - */ - getLogoutData?: () => { readonly url: string; readonly args: unknown } -} +/** + * A continuation function that is called after a successful logout + */ +export type SocialLogoutContinuation = () => Promise + + export interface SocialLoginApi{ /** @@ -75,153 +57,122 @@ export interface SocialOAuthPortal { readonly logout?: string; } +/** + * An social OAuth2 authentication method that can be used to + * authenticate against a server for external connections + */ +export interface OAuthMethod { + /** + * The unique id of the method + */ + readonly id: string; + /** + * Determines if the current flow is active for this method + */ + isActiveLogin(): boolean + /** + * Begins the login flow for this method + */ + beginLoginFlow(): Promise + /** + * Completes the login flow for this method + */ + completeLogin(): Promise + /** + * Logs out of the current session + */ + logout(): Promise +} + +export interface SocialOauthMethod { + /** + * Gets the url to the login endpoint for this method + */ + readonly id: string + /** + * The endpoint to submit the authentication request to + */ + loginUrl(): string + /** + * Called when the login to this method was successful + */ + onSuccessfulLogin?: () => void + /** + * Called when the logout to this method was successful + */ + onSuccessfulLogout?: (responseData: unknown) => SocialLogoutContinuation | void + /** + * Gets the data to send to the logout endpoint, if this method + * is undefined, then the logout will be handled by the normal user logout + */ + getLogoutData?: () => { readonly url: string; readonly args: unknown } +} + + +interface SocialLogoutResult{ + readonly url: string | undefined; +} + /** * Creates a new social login api for the given methods */ -export const useSocialOauthLogin = (methods: T[], axiosConfig?: Partial): SocialLoginApi =>{ +export const useOauthLogin = (methods: T[]): SocialLoginApi => { const cookieName = 'active-social-login'; - const { loggedIn, KeyStore } = useSession(); - const { prepareLogin, logout:userLogout } = useUser(); - const axios = useAxios(axiosConfig); + const { loggedIn } = useSession(); //A cookie will hold the status of the current login method - const c = new Cookies(null, { sameSite: 'strict', httpOnly:false }); - - const getNonceQuery = () => new URLSearchParams(window.location.search).get('nonce'); - const getResultQuery = () => new URLSearchParams(window.location.search).get('result'); - const selectMethodForCurrentUrl = () => find(methods, method => { - const loginUrl = method.loginUrl(); - //Check for absolute url, then check if the path is the same - if(loginUrl.startsWith('http')){ - const asUrl = new URL(loginUrl); - return isEqual(asUrl.pathname, window.location.pathname); - } - //Relative url - return isEqual(loginUrl, window.location.pathname); - }) + const c = new Cookies(null, { sameSite: 'strict', httpOnly: false }); const getActiveMethod = (): T | undefined => { - const methodName = c.get(cookieName) - return find(methods, method => isEqual(method.Id, methodName)) + const methodName = c.get(cookieName) + return find(methods, method => isEqual(method.id, methodName)) } - const beginLoginFlow = async (method: T): Promise => { - //Prepare the login claim` - const claim = await prepareLogin() - const { data } = await axios.put>(method.loginUrl(), claim) - - const encDat = data.getResultOrThrow() - // Decrypt the result which should be a redirect url - const result = await KeyStore.decryptDataAsync(encDat) - // get utf8 text - const text = new TextDecoder('utf-8').decode(result) - // Recover url - const redirect = new URL(text) - // Force https - redirect.protocol = 'https:' - // redirect to the url - window.location.href = redirect.href + const beginLoginFlow = (method: T): Promise => { + return method.beginLoginFlow() } const completeLogin = async () => { - //Get auth result from query params - const result = getResultQuery(); - switch(result){ - case 'invalid': - throw new Error('The request was invalid, and you could not be logged in. Please try again.'); - case 'expired': - throw new Error('The request has expired. Please try again.'); - - //Continue with login - case 'authorized': - break; - - default: - throw new Error('There was an error processing the login request. Please try again.') - } + const method = find(methods, method => method.isActiveLogin()); - const method = selectMethodForCurrentUrl(); - - if(!method){ + if (!method) { throw new Error('The current url is not a valid social login url'); } - //Recover the nonce from query params - const nonce = getNonceQuery(); - if(!nonce){ - throw new Error('The current session has not been initialized for social login'); - } - - const loginUrl = method.loginUrl(); - - //Prepare the session for a new login - const login = await prepareLogin(); - - //Send a post request to the endpoint to complete the login and pass the nonce argument - const { data } = await axios.post(loginUrl, { ...login, nonce }) - - //Verify result - data.getResultOrThrow() - - //Complete login authorization - await login.finalize(data); - - //Signal the method that the login was successful - if(method.onSuccessfulLogin){ - method.onSuccessfulLogin(); - } + await method.completeLogin(); //Set the cookie to the method id - c.set(cookieName, method.Id, { path: loginUrl }); + c.set(cookieName, method.id); } const logout = async (): Promise => { - if(!get(loggedIn)){ + if (!get(loggedIn)) { return false; } - //see if any methods are active + //see if any methods are active, then call logout on the active method const method = getActiveMethod(); if(!method){ - return false; + return false; } - /** - * If no logout data method is defined, then the logout - * is handled by a normal account logout - */ - if(!method.getLogoutData){ - //Normal user logout - const result = await userLogout(); - - if(method.onSuccessfulLogout){ - method.onSuccessfulLogout(result); - } - - return true; - } - - const { url, args } = method.getLogoutData(); - - //Exec logout post request against the url - const { data } = await axios.post(url, args); + const result = await method.logout(); //clear cookie on success c.remove(cookieName); - //Signal the method that the logout was successful - if (method.onSuccessfulLogout) { - method.onSuccessfulLogout(data); + if (result) { + await result(); } return true; } - return{ + return { beginLoginFlow, completeLogin, getActiveMethod, @@ -231,29 +182,176 @@ export const useSocialOauthLogin = (methods: T[], axiosCo } /** - * Creates a new simple social OAuth method used for login - * @example - * const google = createSocialMethod('google', 'https://accounts.google.com/o/oauth2/v2/auth') - * const facebook = createSocialMethod('facebook', 'https://www.facebook.com/v2.10/dialog/oauth') + * Creates a new oauth2 login api for the given methods */ -export const createSocialMethod = (id: string, path: MaybeRef): OAuthMethod => { - return{ - Id: id, - loginUrl: () => get(path), +export const fromSocialConnections = (methods: T[], axiosConfig?: Partial): OAuthMethod[] =>{ + + const { KeyStore } = useSession(); + const { prepareLogin, logout:userLogout } = useUser(); + const axios = useAxios(axiosConfig); + + const getNonceQuery = () => new URLSearchParams(window.location.search).get('nonce'); + const getResultQuery = () => new URLSearchParams(window.location.search).get('result'); + + const checkForValidResult = () => { + //Get auth result from query params + const result = getResultQuery(); + switch (result) { + case 'invalid': + throw new Error('The request was invalid, and you could not be logged in. Please try again.'); + case 'expired': + throw new Error('The request has expired. Please try again.'); + + //Continue with login + case 'authorized': + break; + + default: + throw new Error('There was an error processing the login request. Please try again.') + } } + + return map(methods, method => { + return{ + id: method.id, + + async beginLoginFlow() { + //Prepare the login claim` + const claim = await prepareLogin() + const { data } = await axios.put>(method.loginUrl(), claim) + const encDat = data.getResultOrThrow() + // Decrypt the result which should be a redirect url + const result = await KeyStore.decryptDataAsync(encDat) + // get utf8 text + const text = new TextDecoder('utf-8').decode(result) + // Recover url + const redirect = new URL(text) + // Force https + redirect.protocol = 'https:' + // redirect to the url + window.location.href = redirect.href + }, + async completeLogin() { + checkForValidResult(); + + //Recover the nonce from query params + const nonce = getNonceQuery(); + if (!nonce) { + throw new Error('The current session has not been initialized for social login'); + } + + //Prepare the session for a new login + const login = await prepareLogin(); + + //Send a post request to the endpoint to complete the login and pass the nonce argument + const { data } = await axios.post(method.loginUrl(), { ...login, nonce }) + + //Verify result + data.getResultOrThrow() + + //Complete login authorization + await login.finalize(data); + }, + isActiveLogin() { + const loginUrl = method.loginUrl(); + //Check for absolute url, then check if the path is the same + if (loginUrl.startsWith('http')) { + const asUrl = new URL(loginUrl); + return isEqual(asUrl.pathname, window.location.pathname); + } + //Relative url + return isEqual(loginUrl, window.location.pathname); + }, + async logout() { + /** + * If no logout data method is defined, then the logout + * is handled by a normal account logout + */ + if (!method.getLogoutData) { + //Normal user logout + const result = await userLogout(); + + if (method.onSuccessfulLogout) { + method.onSuccessfulLogout(result); + } + + return; + } + + const { url, args } = method.getLogoutData(); + + //Exec logout post request against the url + const { data } = await axios.post(url, args); + + //Signal the method that the logout was successful + return method.onSuccessfulLogout ? method.onSuccessfulLogout(data) : undefined; + }, + } as OAuthMethod + }); } /** - * Creates social OAuth methods from the given portals (usually captured from the server) + * Adds a default logout function to the social login api that will + * call the user supplied logout function if the social logout does not + * have a registered logout method */ -export const fromPortals = (portals: SocialOAuthPortal[]): OAuthMethod[] => { - return map(portals, p => { - const method = createSocialMethod(p.id, p.login); - - //If a logout url is defined, then add it to the method - if(p.logout){ - method.getLogoutData = () => ({ url: p.logout!, args: {} }) +export const useSocialDefaultLogout = (socialOauth: SocialLoginApi, logout: () => Promise): SocialLoginApi => { + //Store old logout function for later use + const logoutFunc = socialOauth.logout; + + (socialOauth as Mutable>).logout = async (): Promise => { + //If no logout was handled by social, fall back to user supplied logout + if (await logoutFunc() === false) { + await logout() } - return method; + return true; + } + + return socialOauth; +} + +export const fromSocialPortals = (portals: SocialOAuthPortal[]): SocialOauthMethod[] => { + return map(portals, p => { + return { + id: p.id, + loginUrl : () => p.login, + //Get the logout data from the server + getLogoutData: () => ({ url: p.logout!, args: {}}), + //Redirect to the logout url returned by the server + onSuccessfulLogout: (data: SocialLogoutResult) => { + if (data.url) { + return () => { + window.location.assign(data.url!); + return Promise.resolve(); + } + } + }, + onSuccessfulLogin: () => {} + } as SocialOauthMethod }) } + +export const fetchSocialPortals = async (portalEndpoint: string, axiosConfig?: Partial): Promise => { + //Get axios instance + const axios = useAxios(axiosConfig) + + //Get all enabled portals + const { data } = await axios.get(portalEndpoint); + + /** + * See if the response was a json array. + * + * Sometimes axios will parse HTML as json and still + * return an object array, so if its an array, then + * verify that at least one element is a valid portal + */ + if (isArray(data)) { + if(data.length === 0){ + return []; + } + + return first(data)?.id ? data : []; + } + + throw new Error('The response from the server was not a valid json array'); +} \ No newline at end of file diff --git a/plugins/providers/VNLib.Plugins.Essentials.Auth.Auth0/src/Auth0Portal.cs b/plugins/providers/VNLib.Plugins.Essentials.Auth.Auth0/src/Auth0Portal.cs index 0ae92f4..2fcc477 100644 --- a/plugins/providers/VNLib.Plugins.Essentials.Auth.Auth0/src/Auth0Portal.cs +++ b/plugins/providers/VNLib.Plugins.Essentials.Auth.Auth0/src/Auth0Portal.cs @@ -22,8 +22,6 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ -using System; - using VNLib.Plugins.Extensions.Loading; using VNLib.Plugins.Extensions.Loading.Routing; using VNLib.Plugins.Essentials.Auth.Social; @@ -35,24 +33,16 @@ namespace VNLib.Plugins.Essentials.Auth.Auth0 [ServiceExport] [ConfigurationName(ConfigKey)] - public sealed class Auth0Portal : IOAuthProvider + public sealed class Auth0Portal(PluginBase plugin) : IOAuthProvider { internal const string ConfigKey = "auth0"; - private readonly LoginEndpoint _loginEndpoint; - private readonly LogoutEndpoint _logoutEndpoint; - - public Auth0Portal(PluginBase plugin, IConfigScope config) - { - //Init the login endpoint - _loginEndpoint = plugin.Route(); - _logoutEndpoint = plugin.Route(); - } + private readonly LoginEndpoint _loginEndpoint = plugin.Route(); + private readonly LogoutEndpoint _logoutEndpoint = plugin.Route(); /// public SocialOAuthPortal[] GetPortals() { - //Return the Auth0 portal return [ new SocialOAuthPortal( diff --git a/plugins/providers/VNLib.Plugins.Essentials.Auth.Auth0/src/Endpoints/LogoutEndpoint.cs b/plugins/providers/VNLib.Plugins.Essentials.Auth.Auth0/src/Endpoints/LogoutEndpoint.cs index 497357a..5a92968 100644 --- a/plugins/providers/VNLib.Plugins.Essentials.Auth.Auth0/src/Endpoints/LogoutEndpoint.cs +++ b/plugins/providers/VNLib.Plugins.Essentials.Auth.Auth0/src/Endpoints/LogoutEndpoint.cs @@ -22,12 +22,14 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ -using VNLib.Utils; +using System.Net; +using System.Text.Json; +using System.Text.Json.Serialization; +using VNLib.Utils.IO; using VNLib.Plugins.Extensions.Loading; using VNLib.Plugins.Essentials.Accounts; using VNLib.Plugins.Essentials.Endpoints; -using VNLib.Plugins.Essentials.Extensions; namespace VNLib.Plugins.Essentials.Auth.Auth0.Endpoints @@ -35,7 +37,7 @@ namespace VNLib.Plugins.Essentials.Auth.Auth0.Endpoints [ConfigurationName(Auth0Portal.ConfigKey)] internal sealed class LogoutEndpoint : ProtectedWebEndpoint { - private readonly IAsyncLazy ReturnUrl; + private readonly IAsyncLazy ReturnUrl; public LogoutEndpoint(PluginBase plugin, IConfigScope config) { @@ -48,23 +50,35 @@ namespace VNLib.Plugins.Essentials.Auth.Auth0.Endpoints //Build the return url once the client id is available ReturnUrl = plugin.GetSecretAsync("auth0_client_id").ToLazy(sr => { - return $"{logoutUrl}?client_id={sr.Result.ToString()}&returnTo={returnToUrl}"; - }); - } + //The result we will send to users on logout so then can properly redirect their clients + LogoutResult json = new() + { + Url = $"{logoutUrl}?client_id={sr.Result.ToString()}&returnTo={returnToUrl}" + }; - protected override ERRNO PreProccess(HttpEntity entity) - { - //Client required to be fully authorized - return base.PreProccess(entity) - && entity.IsClientAuthorized(AuthorzationCheckLevel.Critical); + VnMemoryStream vms = new(); + JsonSerializer.Serialize(vms, json); + return VnMemoryStream.CreateReadonly(vms); + }); } protected override VfReturnType Post(HttpEntity entity) { //Invalidate the login before redirecting the client entity.InvalidateLogin(); - entity.Redirect(RedirectType.Temporary, ReturnUrl.Value); - return VfReturnType.VirtualSkip; + + return VirtualClose( + entity, + HttpStatusCode.OK, + Net.Http.ContentType.Json, + ReturnUrl.Value.GetReadonlyShallowCopy() //Return stream shallow copy to avoid alloc and copy + ); + } + + sealed class LogoutResult + { + [JsonPropertyName("url")] + public string? Url { get; set; } } } } \ No newline at end of file diff --git a/plugins/providers/VNLib.Plugins.Essentials.Auth.Discord/src/DiscordPortal.cs b/plugins/providers/VNLib.Plugins.Essentials.Auth.Discord/src/DiscordPortal.cs index 5b0503e..ed3940f 100644 --- a/plugins/providers/VNLib.Plugins.Essentials.Auth.Discord/src/DiscordPortal.cs +++ b/plugins/providers/VNLib.Plugins.Essentials.Auth.Discord/src/DiscordPortal.cs @@ -35,22 +35,15 @@ namespace VNLib.Plugins.Essentials.Auth.Discord [ServiceExport] [ConfigurationName(ConfigKey)] - public sealed class DiscordPortal : IOAuthProvider + public sealed class DiscordPortal(PluginBase plugin) : IOAuthProvider { internal const string ConfigKey = "discord"; - private readonly DiscordOauth _loginEndpoint; - - public DiscordPortal(PluginBase plugin, IConfigScope config) - { - //Init the login endpoint - _loginEndpoint = plugin.Route(); - } + private readonly DiscordOauth _loginEndpoint = plugin.Route(); /// public SocialOAuthPortal[] GetPortals() { - //Return the Discord portal return [ new SocialOAuthPortal( diff --git a/plugins/providers/VNLib.Plugins.Essentials.Auth.Github/src/GithubPortal.cs b/plugins/providers/VNLib.Plugins.Essentials.Auth.Github/src/GithubPortal.cs index 99b0ebf..946531d 100644 --- a/plugins/providers/VNLib.Plugins.Essentials.Auth.Github/src/GithubPortal.cs +++ b/plugins/providers/VNLib.Plugins.Essentials.Auth.Github/src/GithubPortal.cs @@ -22,8 +22,6 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ -using System; - using VNLib.Plugins.Extensions.Loading; using VNLib.Plugins.Extensions.Loading.Routing; using VNLib.Plugins.Essentials.Auth.Social; @@ -35,22 +33,15 @@ namespace VNLib.Plugins.Essentials.Auth.Github [ServiceExport] [ConfigurationName(ConfigKey)] - public sealed class GithubPortal : IOAuthProvider + public sealed class GithubPortal(PluginBase plugin) : IOAuthProvider { internal const string ConfigKey = "github"; - private readonly GitHubOauth _loginEndpoint; - - public GithubPortal(PluginBase plugin, IConfigScope config) - { - //Init the login endpoint - _loginEndpoint = plugin.Route(); - } + private readonly GitHubOauth _loginEndpoint = plugin.Route(); /// public SocialOAuthPortal[] GetPortals() { - //Return the github portal return [ new SocialOAuthPortal( -- cgit