Add FIDO2 web authn

This commit is contained in:
soruly 2022-06-18 11:55:20 +00:00
parent 8282f19c3b
commit 48f7f451d8
No known key found for this signature in database
GPG Key ID: EF971E90F3D2521F
15 changed files with 1101 additions and 24 deletions

View File

@ -1,6 +1,9 @@
SERVER_PORT=3000
SERVER_ADDR=127.0.0.1
#SERVER_NAME=localhost
#BLACKLIST_UA=Bot|MSIE|Bytespider|Baidu|Sogou|FB_AN|FB_IOS|FB_IAB|Instagram
#WHITELIST_COUNTRY=ZZ|HK|TW
#GEO_LITE_COUNTRY_PATH=/etc/GeoIP/GeoLite2-Country.mmdb
#GEO_LITE_ASN_PATH=/etc/GeoIP/GeoLite2-ASN.mmdb
#GEO_LITE_ASN_PATH=/etc/GeoIP/GeoLite2-ASN.mmdb
#ENABLE_FIDO2=1
#ALLOW_REGISTER=1

2
.gitignore vendored
View File

@ -62,3 +62,5 @@ typings/
# local data storage
data/
registered/
session/

741
package-lock.json generated
View File

@ -10,16 +10,23 @@
"license": "MIT",
"dependencies": {
"@maxmind/geoip2-node": "^3.4.0",
"cookie-parser": "^1.4.6",
"dotenv": "^16.0.1",
"ejs": "^3.1.8",
"express": "^4.18.1",
"express-rate-limit": "^6.4.0",
"fido2-lib": "^3.2.3",
"fs-extra": "^10.1.0"
},
"devDependencies": {
"prettier": "^2.7.1"
}
},
"node_modules/@hexagon/base64": {
"version": "1.0.19",
"resolved": "https://registry.npmjs.org/@hexagon/base64/-/base64-1.0.19.tgz",
"integrity": "sha512-+ZJdUaD9sthgMbdEiYZ5jwiTG/ZtILx0/LSDkdxi/pK/BSmJzIAT+IYuMYSKwjPdGk6odwbJVQ9H8HpepDZy9Q=="
},
"node_modules/@maxmind/geoip2-node": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@maxmind/geoip2-node/-/geoip2-node-3.4.0.tgz",
@ -31,6 +38,42 @@
"maxmind": "^4.2.0"
}
},
"node_modules/@peculiar/asn1-schema": {
"version": "2.1.9",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.1.9.tgz",
"integrity": "sha512-Ipio+pXGpL/Vb0qB4GnOgFMgc1RAhKHOVy24rQYLvmOAVp9z/aFb+VdIiQH09NjgvGVmaWOUqSWd9vRHk3xbrg==",
"dependencies": {
"asn1js": "^3.0.4",
"pvtsutils": "^1.3.2",
"tslib": "^2.4.0"
}
},
"node_modules/@peculiar/json-schema": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz",
"integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==",
"dependencies": {
"tslib": "^2.0.0"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/@peculiar/webcrypto": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.0.tgz",
"integrity": "sha512-U58N44b2m3OuTgpmKgf0LPDOmP3bhwNz01vAnj1mBwxBASRhptWYK+M3zG+HBkDqGQM+bFsoIihTW8MdmPXEqg==",
"dependencies": {
"@peculiar/asn1-schema": "^2.1.6",
"@peculiar/json-schema": "^1.1.12",
"pvtsutils": "^1.3.2",
"tslib": "^2.4.0",
"webcrypto-core": "^1.7.4"
},
"engines": {
"node": ">=10.12.0"
}
},
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@ -62,6 +105,19 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
},
"node_modules/asn1js": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz",
"integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==",
"dependencies": {
"pvtsutils": "^1.3.2",
"pvutils": "^1.1.3",
"tslib": "^2.4.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
@ -120,6 +176,14 @@
"node": ">= 0.8"
}
},
"node_modules/bytestreamjs": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.0.tgz",
"integrity": "sha512-TyOlxeS92FcMOaJwAVq5gwqW0vfkWUv5W+ErwdbBzolcUN/9XYpCKWvCV21jjzXU550D9Wt4GgE8Pr1vVbR+wQ==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@ -160,6 +224,28 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/cbor-extract": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/cbor-extract/-/cbor-extract-1.0.0.tgz",
"integrity": "sha512-2y71EsPT4dJjtS24JIZfzUodm7kNrJJouIL7U4YiO1bl5QJyCHz9j810x/d+A/L+1BWQCE0771TiBrVmDL0MOA==",
"hasInstallScript": true,
"optional": true,
"dependencies": {
"nan": "^2.14.2",
"node-gyp-build": "^4.2.3"
}
},
"node_modules/cbor-x": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/cbor-x/-/cbor-x-1.2.1.tgz",
"integrity": "sha512-vUgwxN/hCyMUuFsYaMTYhfpK0rwBpGho8CqCLEXSn3tGfaPL3fruB0lrZVGiq1v5EzTrqcrLVxJ2Ul9zqukhMw==",
"dependencies": {
"esbuild": "^0.13.15"
},
"optionalDependencies": {
"cbor-extract": "^1.0.0"
}
},
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@ -223,6 +309,26 @@
"node": ">= 0.6"
}
},
"node_modules/cookie-parser": {
"version": "1.4.6",
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz",
"integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==",
"dependencies": {
"cookie": "0.4.1",
"cookie-signature": "1.0.6"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/cookie-parser/node_modules/cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
@ -293,6 +399,238 @@
"node": ">= 0.8"
}
},
"node_modules/esbuild": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.13.15.tgz",
"integrity": "sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==",
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
},
"optionalDependencies": {
"esbuild-android-arm64": "0.13.15",
"esbuild-darwin-64": "0.13.15",
"esbuild-darwin-arm64": "0.13.15",
"esbuild-freebsd-64": "0.13.15",
"esbuild-freebsd-arm64": "0.13.15",
"esbuild-linux-32": "0.13.15",
"esbuild-linux-64": "0.13.15",
"esbuild-linux-arm": "0.13.15",
"esbuild-linux-arm64": "0.13.15",
"esbuild-linux-mips64le": "0.13.15",
"esbuild-linux-ppc64le": "0.13.15",
"esbuild-netbsd-64": "0.13.15",
"esbuild-openbsd-64": "0.13.15",
"esbuild-sunos-64": "0.13.15",
"esbuild-windows-32": "0.13.15",
"esbuild-windows-64": "0.13.15",
"esbuild-windows-arm64": "0.13.15"
}
},
"node_modules/esbuild-android-arm64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.13.15.tgz",
"integrity": "sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"android"
]
},
"node_modules/esbuild-darwin-64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.13.15.tgz",
"integrity": "sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
]
},
"node_modules/esbuild-darwin-arm64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.15.tgz",
"integrity": "sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
]
},
"node_modules/esbuild-freebsd-64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.15.tgz",
"integrity": "sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/esbuild-freebsd-arm64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.15.tgz",
"integrity": "sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/esbuild-linux-32": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.13.15.tgz",
"integrity": "sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"linux"
]
},
"node_modules/esbuild-linux-64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.13.15.tgz",
"integrity": "sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
]
},
"node_modules/esbuild-linux-arm": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.13.15.tgz",
"integrity": "sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux"
]
},
"node_modules/esbuild-linux-arm64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.15.tgz",
"integrity": "sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
]
},
"node_modules/esbuild-linux-mips64le": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.15.tgz",
"integrity": "sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==",
"cpu": [
"mips64el"
],
"optional": true,
"os": [
"linux"
]
},
"node_modules/esbuild-linux-ppc64le": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.15.tgz",
"integrity": "sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==",
"cpu": [
"ppc64"
],
"optional": true,
"os": [
"linux"
]
},
"node_modules/esbuild-netbsd-64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.15.tgz",
"integrity": "sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"netbsd"
]
},
"node_modules/esbuild-openbsd-64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.15.tgz",
"integrity": "sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"openbsd"
]
},
"node_modules/esbuild-sunos-64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.13.15.tgz",
"integrity": "sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"sunos"
]
},
"node_modules/esbuild-windows-32": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.15.tgz",
"integrity": "sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"win32"
]
},
"node_modules/esbuild-windows-64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.13.15.tgz",
"integrity": "sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"win32"
]
},
"node_modules/esbuild-windows-arm64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.15.tgz",
"integrity": "sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
]
},
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@ -366,6 +704,23 @@
"node >=0.6.0"
]
},
"node_modules/fido2-lib": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/fido2-lib/-/fido2-lib-3.2.3.tgz",
"integrity": "sha512-yERxwu3k8oh360I5s1ujc3k4ZQ2tHmjvcFD3kZHm+hvF4/TBFun39zz914krI1E8+pQgVbqCuxYJ+1HrTz2TFA==",
"dependencies": {
"@hexagon/base64": "^1.0.19",
"@peculiar/webcrypto": "^1.4.0",
"asn1js": "^3.0.2",
"cbor-x": "~1.2.1",
"jose": "^4.7.0",
"pkijs": "^3.0.5",
"tldts": "^5.7.81"
},
"engines": {
"node": ">=10"
}
},
"node_modules/filelist": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
@ -557,6 +912,14 @@
"node": ">=10"
}
},
"node_modules/jose": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/jose/-/jose-4.8.1.tgz",
"integrity": "sha512-+/hpTbRcCw9YC0TOfN1W47pej4a9lRmltdOVdRLz5FP5UvUq3CenhXjQK7u/8NdMIIShMXYAh9VLPhc7TjhvFw==",
"funding": {
"url": "https://github.com/sponsors/panva"
}
},
"node_modules/json-schema": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
@ -692,6 +1055,12 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/nan": {
"version": "2.16.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz",
"integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==",
"optional": true
},
"node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@ -700,6 +1069,17 @@
"node": ">= 0.6"
}
},
"node_modules/node-gyp-build": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz",
"integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==",
"optional": true,
"bin": {
"node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js",
"node-gyp-build-test": "build-test.js"
}
},
"node_modules/object-inspect": {
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
@ -732,6 +1112,21 @@
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
},
"node_modules/pkijs": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.0.5.tgz",
"integrity": "sha512-J6P30yzU7qSbuJIBaclwN93WbyoxjVlkYMgjQmE9wWkPUTHVu2cH6lkjWcIr2WAub5KH38BA1Eyeb4s9apUPTg==",
"dependencies": {
"asn1js": "^3.0.5",
"bytestreamjs": "^2.0.0",
"pvtsutils": "^1.3.2",
"pvutils": "^1.1.3",
"tslib": "^2.4.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/prettier": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
@ -759,6 +1154,22 @@
"node": ">= 0.10"
}
},
"node_modules/pvtsutils": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.2.tgz",
"integrity": "sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==",
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/pvutils": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz",
"integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/qs": {
"version": "6.10.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
@ -917,6 +1328,22 @@
"node": ">=6"
}
},
"node_modules/tldts": {
"version": "5.7.82",
"resolved": "https://registry.npmjs.org/tldts/-/tldts-5.7.82.tgz",
"integrity": "sha512-TMYZhjwjxoT5HprsYis5JNd0Y95XuPh5Ta+tkPTVI1RlCT+1RTK3Ejp+r9xoYbV8cF4b7+nuOzQ31fm+3laYNw==",
"dependencies": {
"tldts-core": "^5.7.82"
},
"bin": {
"tldts": "bin/cli.js"
}
},
"node_modules/tldts-core": {
"version": "5.7.82",
"resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-5.7.82.tgz",
"integrity": "sha512-cfUY8fjmfwJDcocXfFlUbngftKwzx7NzFLcVf8/FTLjRX9hgQE8MIls0KNTRsvYMD6x4oXgZipAAv0WyuDLCxw=="
},
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
@ -925,6 +1352,11 @@
"node": ">=0.6"
}
},
"node_modules/tslib": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
},
"node_modules/type-fest": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
@ -992,9 +1424,26 @@
"core-util-is": "1.0.2",
"extsprintf": "^1.2.0"
}
},
"node_modules/webcrypto-core": {
"version": "1.7.5",
"resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.5.tgz",
"integrity": "sha512-gaExY2/3EHQlRNNNVSrbG2Cg94Rutl7fAaKILS1w8ZDhGxdFOaw6EbCfHIxPy9vt/xwp5o0VQAx9aySPF6hU1A==",
"dependencies": {
"@peculiar/asn1-schema": "^2.1.6",
"@peculiar/json-schema": "^1.1.12",
"asn1js": "^3.0.1",
"pvtsutils": "^1.3.2",
"tslib": "^2.4.0"
}
}
},
"dependencies": {
"@hexagon/base64": {
"version": "1.0.19",
"resolved": "https://registry.npmjs.org/@hexagon/base64/-/base64-1.0.19.tgz",
"integrity": "sha512-+ZJdUaD9sthgMbdEiYZ5jwiTG/ZtILx0/LSDkdxi/pK/BSmJzIAT+IYuMYSKwjPdGk6odwbJVQ9H8HpepDZy9Q=="
},
"@maxmind/geoip2-node": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@maxmind/geoip2-node/-/geoip2-node-3.4.0.tgz",
@ -1006,6 +1455,36 @@
"maxmind": "^4.2.0"
}
},
"@peculiar/asn1-schema": {
"version": "2.1.9",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.1.9.tgz",
"integrity": "sha512-Ipio+pXGpL/Vb0qB4GnOgFMgc1RAhKHOVy24rQYLvmOAVp9z/aFb+VdIiQH09NjgvGVmaWOUqSWd9vRHk3xbrg==",
"requires": {
"asn1js": "^3.0.4",
"pvtsutils": "^1.3.2",
"tslib": "^2.4.0"
}
},
"@peculiar/json-schema": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz",
"integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==",
"requires": {
"tslib": "^2.0.0"
}
},
"@peculiar/webcrypto": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.0.tgz",
"integrity": "sha512-U58N44b2m3OuTgpmKgf0LPDOmP3bhwNz01vAnj1mBwxBASRhptWYK+M3zG+HBkDqGQM+bFsoIihTW8MdmPXEqg==",
"requires": {
"@peculiar/asn1-schema": "^2.1.6",
"@peculiar/json-schema": "^1.1.12",
"pvtsutils": "^1.3.2",
"tslib": "^2.4.0",
"webcrypto-core": "^1.7.4"
}
},
"accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@ -1028,6 +1507,16 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
},
"asn1js": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz",
"integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==",
"requires": {
"pvtsutils": "^1.3.2",
"pvutils": "^1.1.3",
"tslib": "^2.4.0"
}
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
@ -1076,6 +1565,11 @@
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
},
"bytestreamjs": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.0.tgz",
"integrity": "sha512-TyOlxeS92FcMOaJwAVq5gwqW0vfkWUv5W+ErwdbBzolcUN/9XYpCKWvCV21jjzXU550D9Wt4GgE8Pr1vVbR+wQ=="
},
"call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@ -1101,6 +1595,25 @@
"type-fest": "^1.2.1"
}
},
"cbor-extract": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/cbor-extract/-/cbor-extract-1.0.0.tgz",
"integrity": "sha512-2y71EsPT4dJjtS24JIZfzUodm7kNrJJouIL7U4YiO1bl5QJyCHz9j810x/d+A/L+1BWQCE0771TiBrVmDL0MOA==",
"optional": true,
"requires": {
"nan": "^2.14.2",
"node-gyp-build": "^4.2.3"
}
},
"cbor-x": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/cbor-x/-/cbor-x-1.2.1.tgz",
"integrity": "sha512-vUgwxN/hCyMUuFsYaMTYhfpK0rwBpGho8CqCLEXSn3tGfaPL3fruB0lrZVGiq1v5EzTrqcrLVxJ2Ul9zqukhMw==",
"requires": {
"cbor-extract": "^1.0.0",
"esbuild": "^0.13.15"
}
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@ -1146,6 +1659,22 @@
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
},
"cookie-parser": {
"version": "1.4.6",
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz",
"integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==",
"requires": {
"cookie": "0.4.1",
"cookie-signature": "1.0.6"
},
"dependencies": {
"cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
}
}
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
@ -1197,6 +1726,132 @@
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
},
"esbuild": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.13.15.tgz",
"integrity": "sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==",
"requires": {
"esbuild-android-arm64": "0.13.15",
"esbuild-darwin-64": "0.13.15",
"esbuild-darwin-arm64": "0.13.15",
"esbuild-freebsd-64": "0.13.15",
"esbuild-freebsd-arm64": "0.13.15",
"esbuild-linux-32": "0.13.15",
"esbuild-linux-64": "0.13.15",
"esbuild-linux-arm": "0.13.15",
"esbuild-linux-arm64": "0.13.15",
"esbuild-linux-mips64le": "0.13.15",
"esbuild-linux-ppc64le": "0.13.15",
"esbuild-netbsd-64": "0.13.15",
"esbuild-openbsd-64": "0.13.15",
"esbuild-sunos-64": "0.13.15",
"esbuild-windows-32": "0.13.15",
"esbuild-windows-64": "0.13.15",
"esbuild-windows-arm64": "0.13.15"
}
},
"esbuild-android-arm64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.13.15.tgz",
"integrity": "sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==",
"optional": true
},
"esbuild-darwin-64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.13.15.tgz",
"integrity": "sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==",
"optional": true
},
"esbuild-darwin-arm64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.15.tgz",
"integrity": "sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==",
"optional": true
},
"esbuild-freebsd-64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.15.tgz",
"integrity": "sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==",
"optional": true
},
"esbuild-freebsd-arm64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.15.tgz",
"integrity": "sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==",
"optional": true
},
"esbuild-linux-32": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.13.15.tgz",
"integrity": "sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==",
"optional": true
},
"esbuild-linux-64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.13.15.tgz",
"integrity": "sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==",
"optional": true
},
"esbuild-linux-arm": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.13.15.tgz",
"integrity": "sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==",
"optional": true
},
"esbuild-linux-arm64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.15.tgz",
"integrity": "sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==",
"optional": true
},
"esbuild-linux-mips64le": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.15.tgz",
"integrity": "sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==",
"optional": true
},
"esbuild-linux-ppc64le": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.15.tgz",
"integrity": "sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==",
"optional": true
},
"esbuild-netbsd-64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.15.tgz",
"integrity": "sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==",
"optional": true
},
"esbuild-openbsd-64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.15.tgz",
"integrity": "sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==",
"optional": true
},
"esbuild-sunos-64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.13.15.tgz",
"integrity": "sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==",
"optional": true
},
"esbuild-windows-32": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.15.tgz",
"integrity": "sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==",
"optional": true
},
"esbuild-windows-64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.13.15.tgz",
"integrity": "sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==",
"optional": true
},
"esbuild-windows-arm64": {
"version": "0.13.15",
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.15.tgz",
"integrity": "sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==",
"optional": true
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@ -1256,6 +1911,20 @@
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g=="
},
"fido2-lib": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/fido2-lib/-/fido2-lib-3.2.3.tgz",
"integrity": "sha512-yERxwu3k8oh360I5s1ujc3k4ZQ2tHmjvcFD3kZHm+hvF4/TBFun39zz914krI1E8+pQgVbqCuxYJ+1HrTz2TFA==",
"requires": {
"@hexagon/base64": "^1.0.19",
"@peculiar/webcrypto": "^1.4.0",
"asn1js": "^3.0.2",
"cbor-x": "~1.2.1",
"jose": "^4.7.0",
"pkijs": "^3.0.5",
"tldts": "^5.7.81"
}
},
"filelist": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
@ -1404,6 +2073,11 @@
"minimatch": "^3.0.4"
}
},
"jose": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/jose/-/jose-4.8.1.tgz",
"integrity": "sha512-+/hpTbRcCw9YC0TOfN1W47pej4a9lRmltdOVdRLz5FP5UvUq3CenhXjQK7u/8NdMIIShMXYAh9VLPhc7TjhvFw=="
},
"json-schema": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
@ -1499,11 +2173,23 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"nan": {
"version": "2.16.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz",
"integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==",
"optional": true
},
"negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
},
"node-gyp-build": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz",
"integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==",
"optional": true
},
"object-inspect": {
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
@ -1527,6 +2213,18 @@
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
},
"pkijs": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.0.5.tgz",
"integrity": "sha512-J6P30yzU7qSbuJIBaclwN93WbyoxjVlkYMgjQmE9wWkPUTHVu2cH6lkjWcIr2WAub5KH38BA1Eyeb4s9apUPTg==",
"requires": {
"asn1js": "^3.0.5",
"bytestreamjs": "^2.0.0",
"pvtsutils": "^1.3.2",
"pvutils": "^1.1.3",
"tslib": "^2.4.0"
}
},
"prettier": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
@ -1542,6 +2240,19 @@
"ipaddr.js": "1.9.1"
}
},
"pvtsutils": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.2.tgz",
"integrity": "sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==",
"requires": {
"tslib": "^2.4.0"
}
},
"pvutils": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz",
"integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ=="
},
"qs": {
"version": "6.10.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
@ -1652,11 +2363,29 @@
"resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-8.0.2.tgz",
"integrity": "sha512-ApGvZ6vVvTNdsmt676grvCkUCGwzG9IqXma5Z07xJgiC5L7akUMof5U8G2JTI9Rz/ovtVhJBlY6mNhEvtjzOIg=="
},
"tldts": {
"version": "5.7.82",
"resolved": "https://registry.npmjs.org/tldts/-/tldts-5.7.82.tgz",
"integrity": "sha512-TMYZhjwjxoT5HprsYis5JNd0Y95XuPh5Ta+tkPTVI1RlCT+1RTK3Ejp+r9xoYbV8cF4b7+nuOzQ31fm+3laYNw==",
"requires": {
"tldts-core": "^5.7.82"
}
},
"tldts-core": {
"version": "5.7.82",
"resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-5.7.82.tgz",
"integrity": "sha512-cfUY8fjmfwJDcocXfFlUbngftKwzx7NzFLcVf8/FTLjRX9hgQE8MIls0KNTRsvYMD6x4oXgZipAAv0WyuDLCxw=="
},
"toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
},
"tslib": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
},
"type-fest": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
@ -1700,6 +2429,18 @@
"core-util-is": "1.0.2",
"extsprintf": "^1.2.0"
}
},
"webcrypto-core": {
"version": "1.7.5",
"resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.5.tgz",
"integrity": "sha512-gaExY2/3EHQlRNNNVSrbG2Cg94Rutl7fAaKILS1w8ZDhGxdFOaw6EbCfHIxPy9vt/xwp5o0VQAx9aySPF6hU1A==",
"requires": {
"@peculiar/asn1-schema": "^2.1.6",
"@peculiar/json-schema": "^1.1.12",
"asn1js": "^3.0.1",
"pvtsutils": "^1.3.2",
"tslib": "^2.4.0"
}
}
}
}

View File

@ -28,10 +28,12 @@
"homepage": "https://github.com/soruly/2fa#readme",
"dependencies": {
"@maxmind/geoip2-node": "^3.4.0",
"cookie-parser": "^1.4.6",
"dotenv": "^16.0.1",
"ejs": "^3.1.8",
"express": "^4.18.1",
"express-rate-limit": "^6.4.0",
"fido2-lib": "^3.2.3",
"fs-extra": "^10.1.0"
},
"devDependencies": {

108
server.js
View File

@ -5,22 +5,51 @@ import crypto from "crypto";
import { performance } from "perf_hooks";
import express from "express";
import rateLimit from "express-rate-limit";
import cookieParser from "cookie-parser";
import { Fido2Lib } from "fido2-lib";
import getIpInfo from "./src/get-ip-info.js";
import getRegister from "./src/get-register.js";
import postRegister from "./src/post-register.js";
import getLogin from "./src/get-login.js";
import postLogin from "./src/post-login.js";
const {
SERVER_ADDR = "0.0.0.0",
SERVER_PORT = 3000,
SERVER_NAME,
BLACKLIST_UA,
WHITELIST_COUNTRY,
ENABLE_FIDO2,
ALLOW_REGISTER,
} = process.env;
if (!fs.existsSync("data/latest.json")) fs.outputFileSync("data/latest.json", JSON.stringify([]));
fs.ensureDirSync("registered");
fs.ensureDirSync("session");
const app = express();
app.disable("x-powered-by");
app.set("trust proxy", 1);
app.set("view engine", "ejs");
app.set("views", path.resolve("."));
app.set("views", path.resolve("./view"));
app.locals.f2l =
ENABLE_FIDO2 &&
new Fido2Lib({
timeout: 60000,
rpId: SERVER_NAME,
rpName: "ACME",
rpIcon: `https://${SERVER_NAME}/favicon.png`,
challengeSize: 128,
attestation: "direct",
cryptoParams: [-7],
// authenticatorAttachment: "cross-platform",
// authenticatorRequireResidentKey: false,
authenticatorUserVerification: "preferred",
});
app.use((req, res, next) => {
const { ASN, country } = getIpInfo(req.ip);
@ -63,27 +92,11 @@ app.use((req, res, next) => {
});
app.use(express.json());
app.use((req, res, next) => {
res.set("Access-Control-Allow-Origin", "*");
res.set("Access-Control-Allow-Methods", "GET, OPTIONS");
res.set("Referrer-Policy", "no-referrer");
res.set("X-Content-Type-Options", "nosniff");
res.set(
"Content-Security-Policy",
[
"default-src 'self'",
"base-uri 'none'",
"frame-ancestors 'none'",
"block-all-mixed-content",
].join("; ")
);
next();
});
app.use(cookieParser());
app.use(
rateLimit({
max: 120, // 120 requests per IP address (per node.js process)
max: 600, // 600 requests per IP address (per node.js process)
windowMs: 60 * 1000, // per 1 minute
})
);
@ -91,6 +104,15 @@ app.use(
app.get(/[^\/]+\.[^\/]+$/, express.static("./static", { maxAge: 1000 * 60 * 60 * 24 }));
app.delete("/", (req, res) => {
if (
ENABLE_FIDO2 &&
!fs
.readdirSync("session")
.map((e) => e.replace(".json", ""))
.includes(req.cookies.session)
) {
return res.status(403);
}
fs.copyFileSync("data/latest.json", `data/${Date.now()}.json`);
fs.writeFileSync(
"data/latest.json",
@ -104,6 +126,15 @@ app.delete("/", (req, res) => {
});
app.post("/", (req, res) => {
if (
ENABLE_FIDO2 &&
!fs
.readdirSync("session")
.map((e) => e.replace(".json", ""))
.includes(req.cookies.session)
) {
return res.status(403);
}
fs.copyFileSync("data/latest.json", `data/${Date.now()}.json`);
fs.writeFileSync(
"data/latest.json",
@ -112,7 +143,42 @@ app.post("/", (req, res) => {
return res.sendStatus(204);
});
app.get("/login", rateLimit({ max: 5, windowMs: 60 * 1000 }), getLogin);
app.post("/login", rateLimit({ max: 5, windowMs: 60 * 1000 }), postLogin);
app.get("/register", rateLimit({ max: 5, windowMs: 60 * 1000 }), getRegister);
app.post("/register", rateLimit({ max: 5, windowMs: 60 * 1000 }), postRegister);
app.get("/reg", async (req, res) => {
if (ENABLE_FIDO2 && ALLOW_REGISTER) return res.render("register");
return res.status(403).send("Registration disabled");
});
app.get("/", async (req, res) => {
res.set("Access-Control-Allow-Origin", "*");
res.set("Access-Control-Allow-Methods", "GET, OPTIONS");
res.set("Referrer-Policy", "no-referrer");
res.set("X-Content-Type-Options", "nosniff");
res.set(
"Content-Security-Policy",
[
"default-src 'self'",
"base-uri 'none'",
"frame-ancestors 'none'",
"block-all-mixed-content",
].join("; ")
);
if (
ENABLE_FIDO2 &&
!fs
.readdirSync("session")
.map((e) => e.replace(".json", ""))
.includes(req.cookies.session)
) {
return res.render("login", { ALLOW_REGISTER });
}
if (req.headers.accept?.toLowerCase() === "text/event-stream") {
res.set({
"Cache-Control": "no-cache",
@ -143,13 +209,11 @@ app.get("/", async (req, res) => {
return res.render("index", {
list: JSON.parse(fs.readFileSync("data/latest.json")).map(({ name, otp }) => ({
name,
otp: getOtp(otp),
otp: "",
})),
});
});
if (!fs.existsSync("data/latest.json")) fs.outputFileSync("data/latest.json", JSON.stringify([]));
app.listen(SERVER_PORT, SERVER_ADDR, () =>
console.log(`Media server listening on ${SERVER_ADDR}:${SERVER_PORT}`)
);

20
src/get-login.js Normal file
View File

@ -0,0 +1,20 @@
import fs from "fs-extra";
const { ENABLE_FIDO2 } = process.env;
export default async (req, res) => {
if (!ENABLE_FIDO2) return res.status(403).send("FIDO2 disabled");
const assertionOptions = await req.app.locals.f2l.assertionOptions();
req.app.locals.assertionOptions = assertionOptions;
return res.send({
...assertionOptions,
allowCredentials: fs
.readdirSync("registered")
.filter((e) => e.match(/\.pem$/))
.map((e) => ({
type: "public-key",
id: Buffer.from(e.replace(".pem", ""), "base64url").toString("base64"),
})),
challenge: Buffer.from(assertionOptions.challenge).toString("base64"),
});
};

11
src/get-register.js Normal file
View File

@ -0,0 +1,11 @@
const { ENABLE_FIDO2, ALLOW_REGISTER } = process.env;
export default async (req, res) => {
if (!ENABLE_FIDO2 || !ALLOW_REGISTER) return res.status(403).send("Registration disabled");
const registrationOptions = await req.app.locals.f2l.attestationOptions();
req.app.locals.registrationOptions = registrationOptions;
return res.send({
...registrationOptions,
challenge: Buffer.from(registrationOptions.challenge).toString("base64"),
});
};

60
src/post-login.js Normal file
View File

@ -0,0 +1,60 @@
import fs from "fs-extra";
import crypto from "crypto";
const { SERVER_NAME, ENABLE_FIDO2 } = process.env;
export default async (req, res) => {
if (!ENABLE_FIDO2) return res.status(403).send("FIDO2 disabled");
try {
const authnResult = await req.app.locals.f2l.assertionResult(
{
id: req.body.id,
rawId: new Uint8Array(Buffer.from(req.body.rawId, "base64")).buffer,
response: {
authenticatorData: new Uint8Array(
Buffer.from(req.body.response.authenticatorData, "base64")
).buffer,
clientDataJSON: req.body.response.clientDataJSON,
signature: req.body.response.signature,
},
},
{
userHandle: null,
challenge: req.app.locals.assertionOptions.challenge,
origin: `https://${SERVER_NAME}`,
factor: "either",
publicKey: fs.readFileSync(`registered/${req.body.id}.pem`, "utf8"),
prevCounter: 0,
}
);
req.app.locals.assertionOptions = null;
console.log(authnResult);
const uuid = crypto.webcrypto.randomUUID();
fs.outputFileSync(
`session/${uuid}.json`,
JSON.stringify(
{
id: req.body.id,
uuid,
ip: req.ip,
ASN: res.locals.ASN,
country: res.locals.country,
agent: req.headers["user-agent"],
},
null,
2
)
);
// session cookie
res.setHeader("Set-Cookie", `session=${uuid}; Path=/; Secure; HttpOnly; SameSite=Strict`);
// res.setHeader(
// "Set-Cookie",
// `session=${uuid}; Path=/; Expires=${new Date(
// Date.now() + 1000 * 60 * 60 * 24 * 365
// ).toGMTString()}; Secure; HttpOnly; SameSite=Strict`
// );
return res.sendStatus(204);
} catch (e) {
return res.status(400).send(e.toString());
}
};

47
src/post-register.js Normal file
View File

@ -0,0 +1,47 @@
import fs from "fs-extra";
const { SERVER_NAME, ENABLE_FIDO2, ALLOW_REGISTER } = process.env;
export default async (req, res) => {
if (!ENABLE_FIDO2 || !ALLOW_REGISTER) return res.status(403).send("Registration disabled");
try {
const regResult = await req.app.locals.f2l.attestationResult(
{
id: req.body.id,
rawId: new Uint8Array(Buffer.from(req.body.rawId, "base64")).buffer,
response: {
attestationObject: new Uint8Array(
Buffer.from(req.body.response.attestationObject, "base64")
).buffer,
clientDataJSON: req.body.response.clientDataJSON,
},
},
{
challenge: req.app.locals.registrationOptions.challenge,
origin: `https://${SERVER_NAME}`,
factor: "either",
}
);
req.app.locals.registrationOptions = null;
console.log(regResult);
fs.outputFileSync(
`registered/${req.body.id}.pem`,
regResult.authnrData.get("credentialPublicKeyPem")
);
fs.outputFileSync(
`registered/${req.body.id}.json`,
JSON.stringify(
{
ip: req.ip,
ASN: res.locals.ASN,
country: res.locals.country,
agent: req.headers["user-agent"],
},
null,
2
)
);
return res.sendStatus(204);
} catch (e) {
return res.status(400).send(e.toString());
}
};

44
static/login.js Normal file
View File

@ -0,0 +1,44 @@
const arrayBufferToBase64 = (ab) => btoa(String.fromCharCode(...new Uint8Array(ab)));
const base64ToArrayBuffer = (str) => Uint8Array.from(atob(str), (c) => c.charCodeAt(0)).buffer;
(async (e) => {
const assertionOptions = await fetch("/login").then((e) => e.json());
assertionOptions.challenge = base64ToArrayBuffer(assertionOptions.challenge);
try {
const {
authenticatorAttachment,
id,
rawId,
response: { authenticatorData, clientDataJSON, signature, userHandle },
type,
} = await navigator.credentials.get({
publicKey: {
...assertionOptions,
allowCredentials: assertionOptions.allowCredentials.map(({ type, id }) => ({
type,
id: base64ToArrayBuffer(id),
})),
},
});
const res = await fetch("/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
authenticatorAttachment,
id,
rawId: arrayBufferToBase64(rawId),
response: {
authenticatorData: arrayBufferToBase64(authenticatorData),
clientDataJSON: arrayBufferToBase64(clientDataJSON),
signature: arrayBufferToBase64(signature),
userHandle,
},
type,
}),
});
if (res.status === 204) window.location.reload();
} catch (e) {
document.body.innerText = e;
}
})();

41
static/register.js Normal file
View File

@ -0,0 +1,41 @@
const arrayBufferToBase64 = (ab) => btoa(String.fromCharCode(...new Uint8Array(ab)));
const base64ToArrayBuffer = (str) => Uint8Array.from(atob(str), (c) => c.charCodeAt(0)).buffer;
(async (e) => {
try {
const registrationOptions = await fetch("/register").then((e) => e.json());
registrationOptions.challenge = base64ToArrayBuffer(registrationOptions.challenge);
registrationOptions.user = {
id: new Uint8Array(16),
name: "soruly",
displayName: "soruly",
};
const {
authenticatorAttachment,
id,
rawId,
response: { attestationObject, clientDataJSON },
type,
} = await navigator.credentials.create({
publicKey: registrationOptions,
});
const res = await fetch("/register", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
authenticatorAttachment,
id,
rawId: arrayBufferToBase64(rawId),
response: {
attestationObject: arrayBufferToBase64(attestationObject),
clientDataJSON: arrayBufferToBase64(clientDataJSON),
},
type,
}),
});
if (res.status === 204) window.location.href = "/";
} catch (e) {
document.body.innerText = e;
}
})();

View File

@ -38,5 +38,5 @@
</label>
<input type="submit" />
</form>
<script src="client.js" defer></script>
<script src="/index.js" defer></script>
</html>

21
view/login.ejs Normal file
View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html translate="no">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
/>
<meta name="google" content="notranslate" />
<meta name="robots" content="noindex, nofollow" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<title>Authenticator</title>
<link rel="manifest" href="/manifest.json" />
<link rel="icon" type="image/png" href="/favicon.png" />
<link rel="apple-touch-icon" href="/favicon.png" />
<link rel="stylesheet" href="/style.css" />
<script src="/login.js" defer></script>
</html>

21
view/register.ejs Normal file
View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html translate="no">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
/>
<meta name="google" content="notranslate" />
<meta name="robots" content="noindex, nofollow" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<title>Authenticator</title>
<link rel="manifest" href="/manifest.json" />
<link rel="icon" type="image/png" href="/favicon.png" />
<link rel="apple-touch-icon" href="/favicon.png" />
<link rel="stylesheet" href="/style.css" />
<script src="/register.js" defer></script>
</html>