diff --git a/.env.example b/.env.example
index c6efa8d..22730df 100644
--- a/.env.example
+++ b/.env.example
@@ -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
\ No newline at end of file
+#GEO_LITE_ASN_PATH=/etc/GeoIP/GeoLite2-ASN.mmdb
+#ENABLE_FIDO2=1
+#ALLOW_REGISTER=1
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 3674626..5ddcaa0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,3 +62,5 @@ typings/
# local data storage
data/
+registered/
+session/
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 6cfeae9..499b1e1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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"
+ }
}
}
}
diff --git a/package.json b/package.json
index 9bbf803..7f51281 100644
--- a/package.json
+++ b/package.json
@@ -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": {
diff --git a/server.js b/server.js
index ad986f2..c2c77c2 100644
--- a/server.js
+++ b/server.js
@@ -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}`)
);
diff --git a/src/get-login.js b/src/get-login.js
new file mode 100644
index 0000000..087addc
--- /dev/null
+++ b/src/get-login.js
@@ -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"),
+ });
+};
diff --git a/src/get-register.js b/src/get-register.js
new file mode 100644
index 0000000..869e678
--- /dev/null
+++ b/src/get-register.js
@@ -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"),
+ });
+};
diff --git a/src/post-login.js b/src/post-login.js
new file mode 100644
index 0000000..dbea152
--- /dev/null
+++ b/src/post-login.js
@@ -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());
+ }
+};
diff --git a/src/post-register.js b/src/post-register.js
new file mode 100644
index 0000000..4349730
--- /dev/null
+++ b/src/post-register.js
@@ -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());
+ }
+};
diff --git a/static/client.js b/static/index.js
similarity index 100%
rename from static/client.js
rename to static/index.js
diff --git a/static/login.js b/static/login.js
new file mode 100644
index 0000000..1088545
--- /dev/null
+++ b/static/login.js
@@ -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;
+ }
+})();
diff --git a/static/register.js b/static/register.js
new file mode 100644
index 0000000..894a6d1
--- /dev/null
+++ b/static/register.js
@@ -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;
+ }
+})();
diff --git a/index.ejs b/view/index.ejs
similarity index 96%
rename from index.ejs
rename to view/index.ejs
index 465bed1..87e24d1 100644
--- a/index.ejs
+++ b/view/index.ejs
@@ -38,5 +38,5 @@
-
+