aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2024-03-09 16:28:52 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2024-03-09 16:28:52 -0500
commitf2ac807486a00db4ba8486133d567e392f0fe98a (patch)
tree79ed35b19211300164f13329e1d36bbf616474c2
parent7f3067b8fc4416d46af9b8b005a18a71770c98fe (diff)
fix: #1 logout redirection updated to support social methods
-rw-r--r--lib/vnlib.browser/package-lock.json388
-rw-r--r--lib/vnlib.browser/package.json3
-rw-r--r--lib/vnlib.browser/src/helpers/lastPage.ts122
-rw-r--r--lib/vnlib.browser/src/helpers/pageGuard.ts53
-rw-r--r--lib/vnlib.browser/src/index.ts2
-rw-r--r--lib/vnlib.browser/src/social/index.ts394
-rw-r--r--plugins/providers/VNLib.Plugins.Essentials.Auth.Auth0/src/Auth0Portal.cs16
-rw-r--r--plugins/providers/VNLib.Plugins.Essentials.Auth.Auth0/src/Endpoints/LogoutEndpoint.cs40
-rw-r--r--plugins/providers/VNLib.Plugins.Essentials.Auth.Discord/src/DiscordPortal.cs11
-rw-r--r--plugins/providers/VNLib.Plugins.Essentials.Auth.Github/src/GithubPortal.cs13
10 files changed, 464 insertions, 578 deletions
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<PageGuardOptions>): 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<void>
+
+
export interface SocialLoginApi<T>{
/**
@@ -76,152 +58,121 @@ export interface SocialOAuthPortal {
}
/**
+ * 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<void>
+ /**
+ * Completes the login flow for this method
+ */
+ completeLogin(): Promise<void>
+ /**
+ * Logs out of the current session
+ */
+ logout(): Promise<SocialLogoutContinuation | void>
+}
+
+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 = <T extends OAuthMethod>(methods: T[], axiosConfig?: Partial<AxiosRequestConfig>): SocialLoginApi<T> =>{
+export const useOauthLogin = <T extends OAuthMethod>(methods: T[]): SocialLoginApi<T> => {
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<void> => {
- //Prepare the login claim`
- const claim = await prepareLogin()
- const { data } = await axios.put<WebMessage<string>>(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<void> => {
+ 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<ITokenResponse>(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<boolean> => {
- 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 = <T extends OAuthMethod>(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<string>): OAuthMethod => {
- return{
- Id: id,
- loginUrl: () => get(path),
+export const fromSocialConnections = <T extends SocialOauthMethod>(methods: T[], axiosConfig?: Partial<AxiosRequestConfig>): 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<WebMessage<string>>(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<ITokenResponse>(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 = <T>(socialOauth: SocialLoginApi<T>, logout: () => Promise<unknown>): SocialLoginApi<T> => {
+ //Store old logout function for later use
+ const logoutFunc = socialOauth.logout;
+
+ (socialOauth as Mutable<SocialLoginApi<T>>).logout = async (): Promise<boolean> => {
+ //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<AxiosRequestConfig>): Promise<SocialOAuthPortal[]> => {
+ //Get axios instance
+ const axios = useAxios(axiosConfig)
+
+ //Get all enabled portals
+ const { data } = await axios.get<SocialOAuthPortal[]>(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<LoginEndpoint>();
- _logoutEndpoint = plugin.Route<LogoutEndpoint>();
- }
+ private readonly LoginEndpoint _loginEndpoint = plugin.Route<LoginEndpoint>();
+ private readonly LogoutEndpoint _logoutEndpoint = plugin.Route<LogoutEndpoint>();
///<inheritdoc/>
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<string> ReturnUrl;
+ private readonly IAsyncLazy<VnMemoryStream> 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<DiscordOauth>();
- }
+ private readonly DiscordOauth _loginEndpoint = plugin.Route<DiscordOauth>();
///<inheritdoc/>
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<GitHubOauth>();
- }
+ private readonly GitHubOauth _loginEndpoint = plugin.Route<GitHubOauth>();
///<inheritdoc/>
public SocialOAuthPortal[] GetPortals()
{
-
//Return the github portal
return [
new SocialOAuthPortal(