diff --git a/package-lock.json b/package-lock.json index a14ed57432..bd8a0b67ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -995,6 +995,14 @@ "node": ">= 8" } }, + "node_modules/@panva/asn1.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz", + "integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/@polka/url": { "version": "1.0.0-next.21", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", @@ -1355,7 +1363,6 @@ "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dev": true, "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -1389,11 +1396,16 @@ "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, "dependencies": { "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.1.tgz", + "integrity": "sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==", + "dev": true + }, "node_modules/@types/cookie-session": { "version": "2.0.44", "resolved": "https://registry.npmjs.org/@types/cookie-session/-/cookie-session-2.0.44.tgz", @@ -1404,6 +1416,15 @@ "@types/keygrip": "*" } }, + "node_modules/@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/css": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/@types/css/-/css-0.0.33.tgz", @@ -1420,7 +1441,6 @@ "version": "4.17.14", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", - "dev": true, "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.18", @@ -1432,7 +1452,6 @@ "version": "4.17.31", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", - "dev": true, "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -1450,6 +1469,14 @@ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" }, + "node_modules/@types/jsonwebtoken": { + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.9.tgz", + "integrity": "sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/keygrip": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.2.tgz", @@ -1502,14 +1529,12 @@ "node_modules/@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", - "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", - "dev": true + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" }, "node_modules/@types/node": { "version": "18.11.10", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.10.tgz", - "integrity": "sha512-juG3RWMBOqcOuXC643OAdSA525V44cVgGV6dUDuiFtss+8Fk5x1hI93Rsld43VeJVIeqlP9I7Fn9/qaVqoEAuQ==", - "dev": true + "integrity": "sha512-juG3RWMBOqcOuXC643OAdSA525V44cVgGV6dUDuiFtss+8Fk5x1hI93Rsld43VeJVIeqlP9I7Fn9/qaVqoEAuQ==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -1526,14 +1551,12 @@ "node_modules/@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "dev": true + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" }, "node_modules/@types/range-parser": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", - "dev": true + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "node_modules/@types/react": { "version": "18.0.25", @@ -1567,7 +1590,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", - "dev": true, "dependencies": { "@types/mime": "*", "@types/node": "*" @@ -1779,26 +1801,6 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "engines": { - "node": ">=4.0" - } - }, "node_modules/@typescript-eslint/utils/node_modules/semver": { "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", @@ -2129,6 +2131,11 @@ "node": ">=8" } }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -2205,6 +2212,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, "node_modules/azure-devops-node-api": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz", @@ -2361,6 +2376,15 @@ "node": ">=8" } }, + "node_modules/browser-tabs-lock": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/browser-tabs-lock/-/browser-tabs-lock-1.2.15.tgz", + "integrity": "sha512-J8K9vdivK0Di+b8SBdE7EZxDr88TnATing7XoLw6+nFkXMQ6sVBh92K3NQvZlZU91AIkFRi0w3sztk5Z+vsswA==", + "hasInstallScript": true, + "dependencies": { + "lodash": ">=4.17.21" + } + }, "node_modules/browserslist": { "version": "4.21.4", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", @@ -2422,6 +2446,11 @@ "node": "*" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -2695,6 +2724,17 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/co-body": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/co-body/-/co-body-6.1.0.tgz", + "integrity": "sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ==", + "dependencies": { + "inflation": "^2.0.0", + "qs": "^6.5.2", + "raw-body": "^2.3.3", + "type-is": "^1.6.16" + } + }, "node_modules/code-block-writer": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-11.0.3.tgz", @@ -2961,6 +3001,18 @@ "node": ">= 0.8" } }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/crc-32": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", @@ -3615,6 +3667,11 @@ "url": "https://opencollective.com/date-fns" } }, + "node_modules/dayjs": { + "version": "1.11.7", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", + "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -3918,6 +3975,14 @@ "node": ">=12" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -4608,15 +4673,23 @@ } }, "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "estraverse": "^4.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" } }, "node_modules/eslint-utils": { @@ -4663,6 +4736,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -5055,6 +5140,25 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -5619,6 +5723,14 @@ "node": ">=8" } }, + "node_modules/inflation": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/inflation/-/inflation-2.0.0.tgz", + "integrity": "sha512-m3xv4hJYR2oXw4o4Y5l6P5P16WYmazYof+el6Al3f+YlggGj6qT9kImBAnzDelRALnP5d3h4jGBPKzYCizjZZw==", + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -6215,6 +6327,35 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", @@ -6227,6 +6368,55 @@ "node": ">=4.0" } }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jwks-rsa": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-2.1.5.tgz", + "integrity": "sha512-IODtn1SwEm7n6GQZnQLY0oxKDrMh7n/jRH1MzE8mlxWMrh2NnMyOsXTebu8vJ1qCpmuTJcL4DdiE0E4h8jnwsA==", + "dependencies": { + "@types/express": "^4.17.14", + "@types/jsonwebtoken": "^8.5.9", + "debug": "^4.3.4", + "jose": "^2.0.6", + "limiter": "^1.1.5", + "lru-memoizer": "^2.1.4" + }, + "engines": { + "node": ">=10 < 13 || >=14" + } + }, + "node_modules/jwks-rsa/node_modules/jose": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.6.tgz", + "integrity": "sha512-FVoPY7SflDodE4lknJmbAHSUjLCzE2H1F6MS0RYKMQ8SR+lNccpMf8R4eqkNYyyUjR5qZReOzZo5C5YiHOCjjg==", + "dependencies": { + "@panva/asn1.js": "^1.0.0" + }, + "engines": { + "node": ">=10.13.0 < 13 || >=13.7.0" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/kebab-case": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/kebab-case/-/kebab-case-1.0.2.tgz", @@ -6300,6 +6490,11 @@ "node": ">= 0.8.0" } }, + "node_modules/libphonenumber-js": { + "version": "1.10.18", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.18.tgz", + "integrity": "sha512-NS4ZEgNhwbcPz1gfSXCGFnQm0xEiyTSPRthIuWytDzOiEG9xnZ2FbLyfJC4tI2BMAAXpoWbNxHYH75pa3Dq9og==" + }, "node_modules/lilconfig": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", @@ -6309,6 +6504,11 @@ "node": ">=10" } }, + "node_modules/limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -6380,8 +6580,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash-es": { "version": "4.17.21", @@ -6394,17 +6593,51 @@ "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", "dev": true }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/loupe": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", @@ -6430,6 +6663,29 @@ "node": ">=10" } }, + "node_modules/lru-memoizer": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.1.4.tgz", + "integrity": "sha512-IXAq50s4qwrOBrXJklY+KhgZF+5y98PDaNo0gi/v2KQBFLyWr+JyFvijZXkGKjQj/h9c0OwoE+JZbwUXce76hQ==", + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "lru-cache": "~4.0.0" + } + }, + "node_modules/lru-memoizer/node_modules/lru-cache": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", + "integrity": "sha512-uQw9OqphAGiZhkuPlpFGmdTU2tEuhxTourM/19qGJrxBPHAr/f8BT1a0i/lOclESnGatdJG/UCkP9kZB/Lh1iw==", + "dependencies": { + "pseudomap": "^1.0.1", + "yallist": "^2.0.0" + } + }, + "node_modules/lru-memoizer/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" + }, "node_modules/magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -6920,6 +7176,14 @@ "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", "dev": true }, + "node_modules/nodemailer": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.0.tgz", + "integrity": "sha512-jFaCEGTeT3E/m/5R2MHWiyQH3pSARECRUDM+1hokOYc3lQAAG7ASuy+2jIsYVf+RVa9zePopSQwKNVFH8DKUpA==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/non-layered-tidy-tree-layout": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz", @@ -7000,6 +7264,14 @@ "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==", "dev": true }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-hash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", @@ -7319,6 +7591,11 @@ "node": ">=4" } }, + "node_modules/pop-iterate": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pop-iterate/-/pop-iterate-1.0.1.tgz", + "integrity": "sha512-HRCx4+KJE30JhX84wBN4+vja9bNfysxg1y28l0DuJmkoaICiv2ZSilKddbS48pq50P8d2erAhqDLbp47yv3MbQ==" + }, "node_modules/postcss": { "version": "8.4.19", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", @@ -7513,6 +7790,11 @@ "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.3.0.tgz", "integrity": "sha512-c3L2CcAi7f7pvlD0D7xsF+2CQIW8C3HaYx2Pfgq8eA4HAl3GAH6/dVYsyBbYF/0XJs2ziGLrzmz5fmzPm6A0pQ==" }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -7537,6 +7819,16 @@ "node": ">=6" } }, + "node_modules/q": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/q/-/q-2.0.3.tgz", + "integrity": "sha512-gv6vLGcmAOg96/fgo3d9tvA4dJNZL3fMyBqVRrGxQ+Q/o4k9QzbJ3NQF9cOO/71wRodoXhaPgphvMFU68qVAJQ==", + "dependencies": { + "asap": "^2.0.0", + "pop-iterate": "^1.0.1", + "weak-map": "^1.0.5" + } + }, "node_modules/qr-creator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/qr-creator/-/qr-creator-1.0.0.tgz", @@ -7559,8 +7851,7 @@ "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" }, "node_modules/queue-microtask": { "version": "1.2.3", @@ -7847,8 +8138,7 @@ "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, "node_modules/resolve": { "version": "1.22.1", @@ -7960,6 +8250,11 @@ "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", "dev": true }, + "node_modules/rootpath": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/rootpath/-/rootpath-0.1.2.tgz", + "integrity": "sha512-R3wLbuAYejpxQjL/SjXo1Cjv4wcJECnMRT/FlcCfTwCBhaji9rWaRCoVEQ1SPiTJ4kKK+yh+bZLAV7SCafoDDw==" + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -8060,6 +8355,11 @@ "node": ">=v12.22.7" } }, + "node_modules/scmp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz", + "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==" + }, "node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -8497,6 +8797,62 @@ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" }, + "node_modules/supertokens-js-override": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/supertokens-js-override/-/supertokens-js-override-0.0.4.tgz", + "integrity": "sha512-r0JFBjkMIdep3Lbk3JA+MpnpuOtw4RSyrlRAbrzMcxwiYco3GFWl/daimQZ5b1forOiUODpOlXbSOljP/oyurg==" + }, + "node_modules/supertokens-node": { + "version": "12.1.5", + "resolved": "https://registry.npmjs.org/supertokens-node/-/supertokens-node-12.1.5.tgz", + "integrity": "sha512-X+098F/VsZzUrC06C8D8YQ8zq8lg8MqmGBxdxsmulYbLHtAAitMc9LMaWusMM3yclrYWo7H87TORbjH3M9/+jw==", + "dependencies": { + "axios": "0.21.4", + "body-parser": "1.20.1", + "co-body": "6.1.0", + "cookie": "0.4.0", + "debug": "^4.3.3", + "jsonwebtoken": "^8.5.1", + "jwks-rsa": "^2.0.5", + "libphonenumber-js": "^1.9.44", + "nodemailer": "^6.7.2", + "psl": "1.8.0", + "supertokens-js-override": "^0.0.4", + "twilio": "^3.76.0", + "verify-apple-id-token": "^2.1.0" + } + }, + "node_modules/supertokens-node/node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/supertokens-node/node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "node_modules/supertokens-web-js": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/supertokens-web-js/-/supertokens-web-js-0.3.0.tgz", + "integrity": "sha512-OWQt+KCzNrssmBOoMRDdQZ3TGM00HO98i0eQDANJKJbNOaJ+I80mCNV3i8dWLqO1AOClzPAt5oLJNimPjCn9TA==", + "dependencies": { + "supertokens-js-override": "0.0.4", + "supertokens-website": "^14.0.0" + } + }, + "node_modules/supertokens-website": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/supertokens-website/-/supertokens-website-14.0.3.tgz", + "integrity": "sha512-W/IvK1RjLbthunsMfq0gd9yeYZMGY00yncZ2Csh5kns435PbAr0hp+eKzQehOP/pO/Kmd3qM8GzA0Fod3k4D4A==", + "dependencies": { + "browser-tabs-lock": "^1.2.14", + "supertokens-js-override": "^0.0.4" + } + }, "node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -8996,6 +9352,43 @@ "win32" ] }, + "node_modules/twilio": { + "version": "3.84.1", + "resolved": "https://registry.npmjs.org/twilio/-/twilio-3.84.1.tgz", + "integrity": "sha512-Q/xaPoayTj+bgJdnUgpE+EiB/VoNOG+byDFdlDej0FgxiHLgXKliZfVv6boqHPWvC1k7Dt0AK96OBFZ0P55QQg==", + "dependencies": { + "axios": "^0.26.1", + "dayjs": "^1.8.29", + "https-proxy-agent": "^5.0.0", + "jsonwebtoken": "^8.5.1", + "lodash": "^4.17.21", + "q": "2.0.x", + "qs": "^6.9.4", + "rootpath": "^0.1.2", + "scmp": "^2.1.0", + "url-parse": "^1.5.9", + "xmlbuilder": "^13.0.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/twilio/node_modules/axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "dependencies": { + "follow-redirects": "^1.14.8" + } + }, + "node_modules/twilio/node_modules/xmlbuilder": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz", + "integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==", + "engines": { + "node": ">=6.0" + } + }, "node_modules/type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -9211,7 +9604,6 @@ "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -9278,6 +9670,15 @@ "node": ">= 0.8" } }, + "node_modules/verify-apple-id-token": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/verify-apple-id-token/-/verify-apple-id-token-2.2.0.tgz", + "integrity": "sha512-yV96h/6Wv9JY3Gcrg/3a+MyK8T5/RgNn4bVAkeuIwvCr4zanRsbrGKMgzD8UfH2Szr5veevmKdfLx8PfpING6Q==", + "dependencies": { + "jsonwebtoken": "^8.5.1", + "jwks-rsa": "^2.1.3" + } + }, "node_modules/vite": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.5.tgz", @@ -9581,6 +9982,11 @@ "node": ">=14" } }, + "node_modules/weak-map": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.8.tgz", + "integrity": "sha512-lNR9aAefbGPpHO7AEnY0hCFjz1eTkWCXYvkTRrTHs9qv8zJp+SkVYpzfLIFXQQiG3tVvbNFQgVg2bQS8YGgxyw==" + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -9981,6 +10387,7 @@ "@zag-js/solid": "^0.2.1", "compression": "^1.7.4", "cookie-session": "^2.0.0", + "cors": "^2.8.5", "date-fns": "^2.29.3", "dotenv": "^16.0.3", "express": "^4.18.2", @@ -9992,6 +10399,8 @@ "shiki": "^0.11.1", "sirv": "^2.0.2", "solid-js": "^1.6.9", + "supertokens-node": "^12.1.5", + "supertokens-web-js": "^0.3.0", "telefunc": "^0.1.41", "yaml": "^2.1.3", "zod": "^3.19.1" @@ -10003,12 +10412,15 @@ "@tailwindcss/forms": "^0.5.3", "@tailwindcss/typography": "^0.5.7", "@types/compression": "^1.7.2", + "@types/cookie": "^0.5.1", "@types/cookie-session": "^2.0.44", + "@types/cors": "^2.8.13", "@types/express": "^4.17.14", "@types/lodash-es": "^4.17.6", "@types/marked": "^4.0.8", "autoprefixer": "^10.4.12", "babel-preset-solid": "^1.6.2", + "cookie": "^0.5.0", "fast-glob": "^3.2.12", "postcss": "^8.4.18", "rollup-plugin-node-polyfills": "^0.2.1", @@ -10697,7 +11109,9 @@ "@tailwindcss/forms": "^0.5.3", "@tailwindcss/typography": "^0.5.7", "@types/compression": "^1.7.2", + "@types/cookie": "^0.5.1", "@types/cookie-session": "^2.0.44", + "@types/cors": "^2.8.13", "@types/express": "^4.17.14", "@types/lodash-es": "^4.17.6", "@types/marked": "^4.0.8", @@ -10708,7 +11122,9 @@ "autoprefixer": "^10.4.12", "babel-preset-solid": "^1.6.2", "compression": "^1.7.4", + "cookie": "^0.5.0", "cookie-session": "^2.0.0", + "cors": "^2.8.5", "date-fns": "^2.29.3", "dotenv": "^16.0.3", "express": "^4.18.2", @@ -10723,6 +11139,8 @@ "shiki": "^0.11.1", "sirv": "^2.0.2", "solid-js": "^1.6.9", + "supertokens-node": "^12.1.5", + "supertokens-web-js": "^0.3.0", "tailwindcss": "^3.2.1", "telefunc": "^0.1.41", "tsx": "^3.12.1", @@ -10838,6 +11256,11 @@ "fastq": "^1.6.0" } }, + "@panva/asn1.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz", + "integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==" + }, "@polka/url": { "version": "1.0.0-next.21", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", @@ -11118,7 +11541,6 @@ "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dev": true, "requires": { "@types/connect": "*", "@types/node": "*" @@ -11152,11 +11574,16 @@ "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, "requires": { "@types/node": "*" } }, + "@types/cookie": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.1.tgz", + "integrity": "sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==", + "dev": true + }, "@types/cookie-session": { "version": "2.0.44", "resolved": "https://registry.npmjs.org/@types/cookie-session/-/cookie-session-2.0.44.tgz", @@ -11167,6 +11594,15 @@ "@types/keygrip": "*" } }, + "@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/css": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/@types/css/-/css-0.0.33.tgz", @@ -11183,7 +11619,6 @@ "version": "4.17.14", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", - "dev": true, "requires": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.18", @@ -11195,7 +11630,6 @@ "version": "4.17.31", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", - "dev": true, "requires": { "@types/node": "*", "@types/qs": "*", @@ -11213,6 +11647,14 @@ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" }, + "@types/jsonwebtoken": { + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.9.tgz", + "integrity": "sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==", + "requires": { + "@types/node": "*" + } + }, "@types/keygrip": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.2.tgz", @@ -11265,14 +11707,12 @@ "@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", - "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", - "dev": true + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" }, "@types/node": { "version": "18.11.10", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.10.tgz", - "integrity": "sha512-juG3RWMBOqcOuXC643OAdSA525V44cVgGV6dUDuiFtss+8Fk5x1hI93Rsld43VeJVIeqlP9I7Fn9/qaVqoEAuQ==", - "dev": true + "integrity": "sha512-juG3RWMBOqcOuXC643OAdSA525V44cVgGV6dUDuiFtss+8Fk5x1hI93Rsld43VeJVIeqlP9I7Fn9/qaVqoEAuQ==" }, "@types/normalize-package-data": { "version": "2.4.1", @@ -11289,14 +11729,12 @@ "@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "dev": true + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" }, "@types/range-parser": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", - "dev": true + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "@types/react": { "version": "18.0.25", @@ -11330,7 +11768,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", - "dev": true, "requires": { "@types/mime": "*", "@types/node": "*" @@ -11452,20 +11889,6 @@ "semver": "^7.3.7" }, "dependencies": { - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" - }, "semver": { "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", @@ -11734,6 +12157,11 @@ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -11776,6 +12204,14 @@ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" }, + "axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "requires": { + "follow-redirects": "^1.14.0" + } + }, "azure-devops-node-api": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz", @@ -11903,6 +12339,14 @@ "fill-range": "^7.0.1" } }, + "browser-tabs-lock": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/browser-tabs-lock/-/browser-tabs-lock-1.2.15.tgz", + "integrity": "sha512-J8K9vdivK0Di+b8SBdE7EZxDr88TnATing7XoLw6+nFkXMQ6sVBh92K3NQvZlZU91AIkFRi0w3sztk5Z+vsswA==", + "requires": { + "lodash": ">=4.17.21" + } + }, "browserslist": { "version": "4.21.4", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", @@ -11931,6 +12375,11 @@ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -12122,6 +12571,17 @@ "wrap-ansi": "^7.0.0" } }, + "co-body": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/co-body/-/co-body-6.1.0.tgz", + "integrity": "sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ==", + "requires": { + "inflation": "^2.0.0", + "qs": "^6.5.2", + "raw-body": "^2.3.3", + "type-is": "^1.6.16" + } + }, "code-block-writer": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-11.0.3.tgz", @@ -12338,6 +12798,15 @@ "keygrip": "~1.1.0" } }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, "crc-32": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", @@ -12813,6 +13282,11 @@ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==" }, + "dayjs": { + "version": "1.11.7", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", + "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==" + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -13028,6 +13502,14 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -13398,6 +13880,15 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, "glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -13523,12 +14014,19 @@ } }, "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "requires": { "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + } } }, "eslint-utils": { @@ -13792,6 +14290,11 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -14192,6 +14695,11 @@ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true }, + "inflation": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/inflation/-/inflation-2.0.0.tgz", + "integrity": "sha512-m3xv4hJYR2oXw4o4Y5l6P5P16WYmazYof+el6Al3f+YlggGj6qT9kImBAnzDelRALnP5d3h4jGBPKzYCizjZZw==" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -14615,6 +15123,30 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, "jsx-ast-utils": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", @@ -14624,6 +15156,48 @@ "object.assign": "^4.1.3" } }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jwks-rsa": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-2.1.5.tgz", + "integrity": "sha512-IODtn1SwEm7n6GQZnQLY0oxKDrMh7n/jRH1MzE8mlxWMrh2NnMyOsXTebu8vJ1qCpmuTJcL4DdiE0E4h8jnwsA==", + "requires": { + "@types/express": "^4.17.14", + "@types/jsonwebtoken": "^8.5.9", + "debug": "^4.3.4", + "jose": "^2.0.6", + "limiter": "^1.1.5", + "lru-memoizer": "^2.1.4" + }, + "dependencies": { + "jose": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.6.tgz", + "integrity": "sha512-FVoPY7SflDodE4lknJmbAHSUjLCzE2H1F6MS0RYKMQ8SR+lNccpMf8R4eqkNYyyUjR5qZReOzZo5C5YiHOCjjg==", + "requires": { + "@panva/asn1.js": "^1.0.0" + } + } + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "kebab-case": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/kebab-case/-/kebab-case-1.0.2.tgz", @@ -14684,12 +15258,22 @@ "type-check": "~0.3.2" } }, + "libphonenumber-js": { + "version": "1.10.18", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.18.tgz", + "integrity": "sha512-NS4ZEgNhwbcPz1gfSXCGFnQm0xEiyTSPRthIuWytDzOiEG9xnZ2FbLyfJC4tI2BMAAXpoWbNxHYH75pa3Dq9og==" + }, "lilconfig": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", "dev": true }, + "limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" + }, "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -14749,8 +15333,7 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash-es": { "version": "4.17.21", @@ -14763,17 +15346,51 @@ "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", "dev": true }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, "lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "loupe": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", @@ -14796,6 +15413,31 @@ "yallist": "^4.0.0" } }, + "lru-memoizer": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.1.4.tgz", + "integrity": "sha512-IXAq50s4qwrOBrXJklY+KhgZF+5y98PDaNo0gi/v2KQBFLyWr+JyFvijZXkGKjQj/h9c0OwoE+JZbwUXce76hQ==", + "requires": { + "lodash.clonedeep": "^4.5.0", + "lru-cache": "~4.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", + "integrity": "sha512-uQw9OqphAGiZhkuPlpFGmdTU2tEuhxTourM/19qGJrxBPHAr/f8BT1a0i/lOclESnGatdJG/UCkP9kZB/Lh1iw==", + "requires": { + "pseudomap": "^1.0.1", + "yallist": "^2.0.0" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" + } + } + }, "magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -15155,6 +15797,11 @@ "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", "dev": true }, + "nodemailer": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.0.tgz", + "integrity": "sha512-jFaCEGTeT3E/m/5R2MHWiyQH3pSARECRUDM+1hokOYc3lQAAG7ASuy+2jIsYVf+RVa9zePopSQwKNVFH8DKUpA==" + }, "non-layered-tidy-tree-layout": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz", @@ -15222,6 +15869,11 @@ "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==", "dev": true }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, "object-hash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", @@ -15450,6 +16102,11 @@ "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "dev": true }, + "pop-iterate": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pop-iterate/-/pop-iterate-1.0.1.tgz", + "integrity": "sha512-HRCx4+KJE30JhX84wBN4+vja9bNfysxg1y28l0DuJmkoaICiv2ZSilKddbS48pq50P8d2erAhqDLbp47yv3MbQ==" + }, "postcss": { "version": "8.4.19", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", @@ -15562,6 +16219,11 @@ "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.3.0.tgz", "integrity": "sha512-c3L2CcAi7f7pvlD0D7xsF+2CQIW8C3HaYx2Pfgq8eA4HAl3GAH6/dVYsyBbYF/0XJs2ziGLrzmz5fmzPm6A0pQ==" }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" + }, "psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -15583,6 +16245,16 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, + "q": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/q/-/q-2.0.3.tgz", + "integrity": "sha512-gv6vLGcmAOg96/fgo3d9tvA4dJNZL3fMyBqVRrGxQ+Q/o4k9QzbJ3NQF9cOO/71wRodoXhaPgphvMFU68qVAJQ==", + "requires": { + "asap": "^2.0.0", + "pop-iterate": "^1.0.1", + "weak-map": "^1.0.5" + } + }, "qr-creator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/qr-creator/-/qr-creator-1.0.0.tgz", @@ -15599,8 +16271,7 @@ "querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" }, "queue-microtask": { "version": "1.2.3", @@ -15803,8 +16474,7 @@ "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, "resolve": { "version": "1.22.1", @@ -15894,6 +16564,11 @@ } } }, + "rootpath": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/rootpath/-/rootpath-0.1.2.tgz", + "integrity": "sha512-R3wLbuAYejpxQjL/SjXo1Cjv4wcJECnMRT/FlcCfTwCBhaji9rWaRCoVEQ1SPiTJ4kKK+yh+bZLAV7SCafoDDw==" + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -15960,6 +16635,11 @@ "xmlchars": "^2.2.0" } }, + "scmp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz", + "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==" + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -16306,6 +16986,61 @@ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" }, + "supertokens-js-override": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/supertokens-js-override/-/supertokens-js-override-0.0.4.tgz", + "integrity": "sha512-r0JFBjkMIdep3Lbk3JA+MpnpuOtw4RSyrlRAbrzMcxwiYco3GFWl/daimQZ5b1forOiUODpOlXbSOljP/oyurg==" + }, + "supertokens-node": { + "version": "12.1.5", + "resolved": "https://registry.npmjs.org/supertokens-node/-/supertokens-node-12.1.5.tgz", + "integrity": "sha512-X+098F/VsZzUrC06C8D8YQ8zq8lg8MqmGBxdxsmulYbLHtAAitMc9LMaWusMM3yclrYWo7H87TORbjH3M9/+jw==", + "requires": { + "axios": "0.21.4", + "body-parser": "1.20.1", + "co-body": "6.1.0", + "cookie": "0.4.0", + "debug": "^4.3.3", + "jsonwebtoken": "^8.5.1", + "jwks-rsa": "^2.0.5", + "libphonenumber-js": "^1.9.44", + "nodemailer": "^6.7.2", + "psl": "1.8.0", + "supertokens-js-override": "^0.0.4", + "twilio": "^3.76.0", + "verify-apple-id-token": "^2.1.0" + }, + "dependencies": { + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + } + } + }, + "supertokens-web-js": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/supertokens-web-js/-/supertokens-web-js-0.3.0.tgz", + "integrity": "sha512-OWQt+KCzNrssmBOoMRDdQZ3TGM00HO98i0eQDANJKJbNOaJ+I80mCNV3i8dWLqO1AOClzPAt5oLJNimPjCn9TA==", + "requires": { + "supertokens-js-override": "0.0.4", + "supertokens-website": "^14.0.0" + } + }, + "supertokens-website": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/supertokens-website/-/supertokens-website-14.0.3.tgz", + "integrity": "sha512-W/IvK1RjLbthunsMfq0gd9yeYZMGY00yncZ2Csh5kns435PbAr0hp+eKzQehOP/pO/Kmd3qM8GzA0Fod3k4D4A==", + "requires": { + "browser-tabs-lock": "^1.2.14", + "supertokens-js-override": "^0.0.4" + } + }, "supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -16653,6 +17388,39 @@ "dev": true, "optional": true }, + "twilio": { + "version": "3.84.1", + "resolved": "https://registry.npmjs.org/twilio/-/twilio-3.84.1.tgz", + "integrity": "sha512-Q/xaPoayTj+bgJdnUgpE+EiB/VoNOG+byDFdlDej0FgxiHLgXKliZfVv6boqHPWvC1k7Dt0AK96OBFZ0P55QQg==", + "requires": { + "axios": "^0.26.1", + "dayjs": "^1.8.29", + "https-proxy-agent": "^5.0.0", + "jsonwebtoken": "^8.5.1", + "lodash": "^4.17.21", + "q": "2.0.x", + "qs": "^6.9.4", + "rootpath": "^0.1.2", + "scmp": "^2.1.0", + "url-parse": "^1.5.9", + "xmlbuilder": "^13.0.2" + }, + "dependencies": { + "axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "requires": { + "follow-redirects": "^1.14.8" + } + }, + "xmlbuilder": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz", + "integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==" + } + } + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -16798,7 +17566,6 @@ "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -16853,6 +17620,15 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, + "verify-apple-id-token": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/verify-apple-id-token/-/verify-apple-id-token-2.2.0.tgz", + "integrity": "sha512-yV96h/6Wv9JY3Gcrg/3a+MyK8T5/RgNn4bVAkeuIwvCr4zanRsbrGKMgzD8UfH2Szr5veevmKdfLx8PfpING6Q==", + "requires": { + "jsonwebtoken": "^8.5.1", + "jwks-rsa": "^2.1.3" + } + }, "vite": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.5.tgz", @@ -17041,6 +17817,11 @@ "xml-name-validator": "^4.0.0" } }, + "weak-map": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.8.tgz", + "integrity": "sha512-lNR9aAefbGPpHO7AEnY0hCFjz1eTkWCXYvkTRrTHs9qv8zJp+SkVYpzfLIFXQQiG3tVvbNFQgVg2bQS8YGgxyw==" + }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/source-code/website/env.example b/source-code/website/env.example index b8cbe86338..0a690a02b6 100644 --- a/source-code/website/env.example +++ b/source-code/website/env.example @@ -6,12 +6,28 @@ # ------------------------------------ +# Exactly 32 characters long string which is base64 encoded. +# Example: `S2V5LU11c3QtQmUtMTYtb3ItMzItb3ItNjQtYnllZWU=` JWE_SECRET_KEY="" +# 50a45f4482cd28494437a0f128cd0b6158cf6176 GITHUB_APP_CLIENT_SECRET="" # url and port of of @inlang/cors-proxy VITE_GIT_REQUEST_PROXY_PATH="/git-proxy/" # https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps -VITE_GITHUB_APP_CLIENT_ID="" \ No newline at end of file +VITE_GITHUB_APP_CLIENT_ID="" + + +# If you want to work on the session logic uncomment the following variables +# Sign up for a free dev instance here: https://supertokens.com/docs/session/introduction +# SUPERTOKENS_CONNECTION_URI= +# SUPERTOKENS_API_KEY= + +# Probably http://localhost:3000 or http://127.0.0.1 or https://inlang.com +# Required for supertokens to work +# VITE_FRONTEND_BASE_URL= + +# Set to 'true' if you want to enable the supertokens session logic in the dev environment +# VITE_SUPERTOKENS_IN_DEV=true \ No newline at end of file diff --git a/source-code/website/env.ts b/source-code/website/env.ts index 9e902955dc..78e5bd132b 100644 --- a/source-code/website/env.ts +++ b/source-code/website/env.ts @@ -41,9 +41,16 @@ export type ServerSideEnv = ClientSideEnv & { GOOGLE_TRANSLATE_API_KEY?: string; /** - * The secret for signing cookies. + * The connection uri for super tokens. + * Only required in production or when using super tokens in dev by setting VITE_SUPERTOKENS_IN_DEV to 'true'. */ - COOKIE_SECRET: string; + SUPERTOKENS_CONNECTION_URI?: string; + + /** + * The API key for super tokens. + * Only required in production or when using super tokens in dev by setting VITE_SUPERTOKENS_IN_DEV to 'true'. + */ + SUPERTOKENS_API_KEY?: string; }; /** @@ -53,6 +60,11 @@ export type ServerSideEnv = ClientSideEnv & { * for more information. */ export type ClientSideEnv = { + /** + * The environment mode. + */ + NODE_ENV: "development" | "production" | "test"; + /** * The url of the proxy server for git requests. */ @@ -70,6 +82,26 @@ export type ClientSideEnv = { * Only available in production. */ VITE_SENTRY_DSN_CLIENT?: string; + + /** + * The name of the super tokens app. + * Defaults to `inlang`. + */ + VITE_SUPERTOKENS_APP_NAME?: string; + + /** + * Set to `true` to enable super tokens in your dev environment. + * + * Only affecting the dev. + */ + VITE_SUPERTOKENS_IN_DEV?: string; + + /** + * The bas url of the frontend + * @example http://localhost:3000 + * @example https://inlang.com + */ + VITE_FRONTEND_BASE_URL?: string; }; /** @@ -109,6 +141,24 @@ export async function serverSideEnv(): Promise { } } +/** + * Validate a single env variable. + * @param name The name of the env variable. + * @param value The value of the env variable. + * @throws Error if the env variable is invalid. + */ +const validateSingle = (name: string, value?: string) => { + if (value === undefined) { + throw Error(`Missing env variable ${name}`); + } +}; + +const validateSupertokens = (env: ServerSideEnv) => { + validateSingle("SUPERTOKENS_API_KEY", env.SUPERTOKENS_API_KEY); + validateSingle("SUPERTOKENS_CONNECTION_URI", env.SUPERTOKENS_CONNECTION_URI); + validateSingle("VITE_FRONTEND_BASE_URL", env.VITE_FRONTEND_BASE_URL); +}; + /** * Call this function as soon as possible to validate the env. * @@ -116,25 +166,30 @@ export async function serverSideEnv(): Promise { */ export async function validateEnv() { const env = await serverSideEnv(); - // VITE_GIT_REQUEST_PROXY_PATH - if (env.VITE_GIT_REQUEST_PROXY_PATH === undefined) { - throw Error("Missing env variable VITE_CORS_PROXY_URL"); - } else if ( + + validateSingle( + "VITE_GIT_REQUEST_PROXY_PATH", + env.VITE_GIT_REQUEST_PROXY_PATH + ); + validateSingle("VITE_GITHUB_APP_CLIENT_ID", env.VITE_GITHUB_APP_CLIENT_ID); + validateSingle("JWE_SECRET_KEY", env.JWE_SECRET_KEY); + validateSingle("GITHUB_APP_CLIENT_SECRET", env.GITHUB_APP_CLIENT_SECRET); + + if (env.NODE_ENV == "production") { + validateSupertokens(env); + } else { + if (env.VITE_SUPERTOKENS_IN_DEV !== undefined) { + validateSupertokens(env); + } + } + + // in depth validation + if ( env.VITE_GIT_REQUEST_PROXY_PATH.startsWith("/") === false || env.VITE_GIT_REQUEST_PROXY_PATH.endsWith("/") === false ) { throw Error( - "VITE_CORS_PROXY_URL must be a local path like that starts and ends with a slash `/` like `/git-proxy/`." + "VITE_GIT_REQUEST_PROXY_PATH must be a local path like that starts and ends with a slash `/` like `/git-proxy/`." ); } - // - else if (env.VITE_GITHUB_APP_CLIENT_ID === undefined) { - throw Error("Missing env variable VITE_GITHUB_APP_CLIENT_ID"); - } else if (env.JWE_SECRET_KEY === undefined) { - throw Error("Missing env variable JWE_SECRET_KEY"); - } else if (env.GITHUB_APP_CLIENT_SECRET === undefined) { - throw Error("Missing env variable GITHUB_APP_CLIENT_SECRET"); - } else if (env.COOKIE_SECRET === undefined) { - throw Error("Missing env variable COOKIE_SECRET"); - } } diff --git a/source-code/website/package.json b/source-code/website/package.json index 6f8f4c981c..52ececb915 100644 --- a/source-code/website/package.json +++ b/source-code/website/package.json @@ -29,6 +29,7 @@ "@zag-js/solid": "^0.2.1", "compression": "^1.7.4", "cookie-session": "^2.0.0", + "cors": "^2.8.5", "date-fns": "^2.29.3", "dotenv": "^16.0.3", "express": "^4.18.2", @@ -40,6 +41,8 @@ "shiki": "^0.11.1", "sirv": "^2.0.2", "solid-js": "^1.6.9", + "supertokens-node": "^12.1.5", + "supertokens-web-js": "^0.3.0", "telefunc": "^0.1.41", "yaml": "^2.1.3", "zod": "^3.19.1" @@ -51,12 +54,15 @@ "@tailwindcss/forms": "^0.5.3", "@tailwindcss/typography": "^0.5.7", "@types/compression": "^1.7.2", + "@types/cookie": "^0.5.1", "@types/cookie-session": "^2.0.44", + "@types/cors": "^2.8.13", "@types/express": "^4.17.14", "@types/lodash-es": "^4.17.6", "@types/marked": "^4.0.8", "autoprefixer": "^10.4.12", "babel-preset-solid": "^1.6.2", + "cookie": "^0.5.0", "fast-glob": "^3.2.12", "postcss": "^8.4.18", "rollup-plugin-node-polyfills": "^0.2.1", diff --git a/source-code/website/src/pages/editor/index.page.tsx b/source-code/website/src/pages/editor/index.page.tsx index a14ff2a862..8b57c1f597 100644 --- a/source-code/website/src/pages/editor/index.page.tsx +++ b/source-code/website/src/pages/editor/index.page.tsx @@ -97,7 +97,7 @@ export function Page() { /** * A card that displays a repository. */ -function RepositoryCard(props: { repository: (typeof repositories)[number] }) { +function RepositoryCard(props: { repository: typeof repositories[number] }) { const isExampleRepository = () => props.repository.owner === "inlang" && props.repository.repository === "example"; diff --git a/source-code/website/src/renderer/_default.page.client.tsx b/source-code/website/src/renderer/_default.page.client.tsx index 46e3c074e3..725bc3c78a 100644 --- a/source-code/website/src/renderer/_default.page.client.tsx +++ b/source-code/website/src/renderer/_default.page.client.tsx @@ -38,6 +38,11 @@ import "@shoelace-style/shoelace/dist/components/button-group/button-group.js"; import "@shoelace-style/shoelace/dist/components/spinner/spinner.js"; import { clientSideEnv } from "@env"; +import { initClientSession } from "@src/services/auth/lib/session/client.js"; + +// Initialize the session logic. +// This has to happen before the first API calls to routes that require the session logic are made. +await initClientSession(); // enable error logging via sentry in production if (import.meta.env.PROD) { diff --git a/source-code/website/src/server/git-proxy.ts b/source-code/website/src/server/git-proxy.ts index 8ebb6fcc17..37077da4af 100644 --- a/source-code/website/src/server/git-proxy.ts +++ b/source-code/website/src/server/git-proxy.ts @@ -9,41 +9,55 @@ */ // import { assert } from "@src/services/assert/index.js"; -import type { NextFunction, Request, Response } from "express"; +import { Router } from "express"; import { serverSideEnv } from "@env"; // @ts-ignore import createMiddleware from "@isomorphic-git/cors-proxy/middleware.js"; import { decryptAccessToken } from "@src/services/auth/logic.js"; +import { verifyInlangSession } from "@src/services/auth/lib/session/server.js"; +import type { InlangSessionRequest } from "@src/services/auth/lib/session/types.server.js"; const middleware = createMiddleware({}); const env = await serverSideEnv(); -export async function proxy( - request: Request, - response: Response, - next: NextFunction -) { - // TODO enable after https://github.com/brillout/vite-plugin-ssr/discussions/560#discussioncomment-4420315 - // TODO currently not using vite to bundle this file, hence the call below will not be pruned - // assert(request.url.startsWith(env.VITE_GIT_REQUEST_PROXY_PATH)); - if (request.path.includes("github") === false) { - response.status(500).send("Unsupported git hosting provider."); - } - try { - // decrypt the access token - const encryptedAccessToken = request.session?.encryptedAccessToken; - if (encryptedAccessToken) { - const decryptedAccessToken = await decryptAccessToken({ - JWE_SECRET_KEY: env.JWE_SECRET_KEY, - jwe: encryptedAccessToken, - }); - // set the authorization header (must be base64 encoded) - request.headers["authorization"] = `Basic ${btoa(decryptedAccessToken)}`; +export const gitProxyRouter = Router(); + +// forward git requests to the proxy with wildcard `*`. +gitProxyRouter.all( + env.VITE_GIT_REQUEST_PROXY_PATH + "*", + verifyInlangSession({ sessionRequired: false }), + async (request: InlangSessionRequest, response, next) => { + // TODO enable after https://github.com/brillout/vite-plugin-ssr/discussions/560#discussioncomment-4420315 + // TODO currently not using vite to bundle this file, hence the call below will not be pruned + // assert(request.url.startsWith(env.VITE_GIT_REQUEST_PROXY_PATH)); + + if (request.path.includes("github") === false) { + response.status(500).send("Unsupported git hosting provider."); + } + try { + // decrypt the access token if it exists + + let sessionData; + if (request.session != undefined) { + sessionData = await request.session.getSessionData(); + } + + const encryptedAccessToken = sessionData?.encryptedAccessToken; + if (encryptedAccessToken) { + const decryptedAccessToken = await decryptAccessToken({ + JWE_SECRET_KEY: env.JWE_SECRET_KEY, + jwe: encryptedAccessToken, + }); + // set the authorization header (must be base64 encoded) + request.headers["authorization"] = `Basic ${btoa( + decryptedAccessToken + )}`; + } + // remove the proxy path from the url + request.url = request.url.slice(env.VITE_GIT_REQUEST_PROXY_PATH.length); + middleware(request, response, next); + } catch (error) { + next(error); } - // remove the proxy path from the url - request.url = request.url.slice(env.VITE_GIT_REQUEST_PROXY_PATH.length); - middleware(request, response, next); - } catch (error) { - next(error); } -} +); diff --git a/source-code/website/src/server/main.ts b/source-code/website/src/server/main.ts index 4b4986749c..1127bf1d7f 100644 --- a/source-code/website/src/server/main.ts +++ b/source-code/website/src/server/main.ts @@ -18,23 +18,31 @@ import { createServer as createViteServer } from "vite"; import { renderPage } from "vite-plugin-ssr"; import { URL } from "url"; import { telefunc } from "telefunc"; -import { proxy } from "./git-proxy.js"; +import { gitProxyRouter } from "./git-proxy.js"; import { serverSideEnv, validateEnv } from "@env"; import sirv from "sirv"; import * as Sentry from "@sentry/node"; import * as Tracing from "@sentry/tracing"; -import cookieSession from "cookie-session"; import { router as authService } from "@src/services/auth/server.js"; import { decryptAccessToken } from "@src/services/auth/logic.js"; import { config } from "telefunc"; import { onBug as onTelefuncBug } from "telefunc"; - -// https://telefunc.com/disableNamingConvention -config.disableNamingConvention = true; +import { + sessionMiddleware, + verifyInlangSession, + initSession, + sessionErrorHandler, +} from "@src/services/auth/lib/session/server.js"; +import type { InlangSessionRequest } from "@src/services/auth/lib/session/types.server.js"; // validate the env variables. await validateEnv(); +await initSession(); + +// https://telefunc.com/disableNamingConvention +config.disableNamingConvention = true; + // the flag is set in the package.json scripts // via `NODE_ENV=production ` const isProduction = process.env.NODE_ENV === "production"; @@ -45,20 +53,12 @@ const env = await serverSideEnv(); const rootPath = new URL("../..", import.meta.url).pathname; const app = express(); + +app.use(sessionMiddleware()); + // compress responses with gzip app.use(compression()); -app.use( - cookieSession({ - name: "inlang-session", - httpOnly: true, - // secure: isProduction ? true : false, - // domain: isProduction ? "inlang.com" : undefined, - secret: env.COOKIE_SECRET, - maxAge: 7 * 24 * 3600 * 1000, // 1 week - }) -); - // setup sentry error tracking // must happen before the request handlers if (isProduction) { @@ -97,30 +97,40 @@ if (isProduction) { // ------------------------ START ROUTES ------------------------ // serving telefunc https://telefunc.com/ +// SuperTokens sessionData is used to retrieve the GitHub access token. app.all( "/_telefunc", // Parse & make HTTP request body available at `req.body` (required by telefunc) express.text(), - // handle the request - (request, response, next) => { + verifyInlangSession({ sessionRequired: false }), + async (request: InlangSessionRequest, response, next) => { // decrypting the access token if it exists - if (request.session?.encryptedAccessToken) { + + let sessionData; + if (request.session != undefined) { + sessionData = await request.session.getSessionData(); + } + + if (sessionData?.encryptedAccessToken) { decryptAccessToken({ - jwe: request.session.encryptedAccessToken, + jwe: sessionData.encryptedAccessToken, JWE_SECRET_KEY: env.JWE_SECRET_KEY, }) - .then((accessToken) => - telefunc({ + .then((accessToken) => { + return telefunc({ context: { githubAccessToken: accessToken }, url: request.originalUrl, method: request.method, body: request.body, - }) - ) + }); + }) .then(({ body, statusCode, contentType }) => { response.status(statusCode).type(contentType).send(body); }) - .catch(next); + .catch((e) => { + console.error(e); + next(); + }); } else { telefunc({ context: { githubAccessToken: undefined }, @@ -136,8 +146,7 @@ app.all( } ); -// forward git requests to the proxy with wildcard `*`. -app.all(env.VITE_GIT_REQUEST_PROXY_PATH + "*", proxy); +app.use(gitProxyRouter); app.use("/services/auth", authService); @@ -161,6 +170,7 @@ app.get("*", (request, response, next) => { }); // ------------------------ END ROUTES ------------------------ +app.use(sessionErrorHandler); const port = process.env.PORT ?? 3000; app.listen(port); diff --git a/source-code/website/src/services/auth/README.md b/source-code/website/src/services/auth/README.md index 79eca38adc..1515ade81d 100644 --- a/source-code/website/src/services/auth/README.md +++ b/source-code/website/src/services/auth/README.md @@ -7,20 +7,72 @@ Auth uses [(GitHub) OAuth](https://docs.github.com/en/developers/apps/building-o ### Using OAuth has the following benefits: - users already have GitHub accounts + - changes a user conducts are executed on behalf of the user ("samuelstroschein changed message X") + - no auth system needs to be implemented on inlang's side. GitHub auth and permissions can be used (little to no overhead when adopting inlang) ### Architecture -Client-side requests are tunneled through a server that adds authentification tokens based on a cookie session that contains an encrypted access token when making requests to git hosts like GitHub or GitLab. +Client-side requests are tunneled through a server that adds authentification tokens based on a cookie session that contains an encrypted access token when making requests to git hosts like GitHub or GitLab. -The nature of executing external JavaScript on the client via the config entails the requirement to never store, not even in memory for 1s, an access token from a git host. The chosen encryption algorithm is symmetric to ease implementation and because the client is not supposed to encrypt or decrypt anything. +The nature of executing external JavaScript on the client via the config entails the requirement to never store, not even in memory for 1s, an access token from a git host. The chosen encryption algorithm is symmetric to ease implementation and because the client is not supposed to encrypt or decrypt anything. ### Procedure 1. The user is prompted to log in and thereby forwarded to the git host via [LoginDialog](./components/LoginDialog.tsx). + 2. SERVER-SIDE: The git host redirects back to a site of inlang with an interim code after a successful login [server.ts](./server.ts). + 3. SERVER-SIDE: The interim code is exchanged for an encrypted JWT (JWE) that contains the access token [server.ts](./server.ts) + 4. SERVER-SIDE: The server stores the encrypted access token in a cookie session [server.ts](./server.ts). It is extremely important that step 3 never leaks the interim code client side and is, therefore, processed server-side. Otherwise, an attacker could intercept the interim code and exchange it for an access token. + +# Sessions + +The session logic is based on [supertokens](https://supertokens.com/docs/session/introduction) session recipe for the production environment and uses a simplified local solution for the development environment, so that you don't need to spin-up a supertokens instance if you don't need to work on the session logic itself. +Because we went this hybrid approach, not all of supertokens session capabilities can be used. If you find yourself needing an interface which is not yet implemented, DON'T directly use supertokens interfaces but extend the wrapper, so that the local supertokenless development keeps working. +**Never use supertokens interfaces directly** outside of the session wrapper logic. Always import session specific logic from the custom session implementation. + +## Integration into the OAuth Flow + +1. Navigate to the editor +2. Session frontend get's initalized +3. Frontend calls /services/auth/create-session route +4. User clicks on Sign-In +5. User gets redirected to OAuth provider +6. OAuth Provider redirects back to the inlang frontend +7. On the request the backend exchanges the interim token for the accessToken, encrypts it and saves it into the sessionData object, of the already created session, which is only available to the backend. Never comes into contact with the frontend and is not stored in the accessToken (not to be confused with the accessToken payload). +8. The frontend initializes the session logic and all upcoming api calls (including telefunc calls) can be linked with the sessionData and the encrypted auth provider accessToken. + +## Production + +Set the following environment variables: + +- `SUPERTOKENS_CONNECTION_URI`: e.g. `https://xxxxxxxxxx-eu-west-1.aws.supertokens.io:3569` +- `SUPERTOKENS_API_KEY`: e.g. `XXXXXXDqR4ZR0EnQmOonT-FVoDvD7V` + +[Learn more about the initialization parameters for supertokens](https://supertokens.com/docs/session/quick-setup/backend) + +## Development + +In development a really simple cache based approach is used: + +- 2 cookies are used to reproduce the capabilities of a supertokens session while not caring about security risks like CSRF + - `inlang-dev-session-id` which contains the handle of the session + - `inlang-dev-session-access-token-payload` which contains the serialized accessToken payload + +### Working on the session logic + +Set the environment variables required for production + + +- `VITE_SUPERTOKENS_IN_DEV` to `true` + +This disables the custom implementation for the development environment and enables the production session logic based on supertokens. + +## Splitting front end backend to different domains + +To prevent CORS based error we shouldn't switch to different domains, but use subdomains like api.inlang.com / app.inlang.com / ... Otherwise the session logic will no longer work. +If we switch to a subdomain based setup and no longer have everything on one domain, we'll need to add superbases CORS logic as a middleware to express. This can be added to the custom session middleware. diff --git a/source-code/website/src/services/auth/lib/session/client.ts b/source-code/website/src/services/auth/lib/session/client.ts new file mode 100644 index 0000000000..115491fc07 --- /dev/null +++ b/source-code/website/src/services/auth/lib/session/client.ts @@ -0,0 +1,88 @@ +/** + * Session logic for the frontend using supertokens for production and a simplified local version for simpler development. + * Opt in to supertokens in development by setting the env variable 'VITE_SUPERTOKENS_IN_DEV' to 'true'. + * Also check to set the other required env vars, which are listed in the development setup guid. + * @see + * @see https://supertokens.com/docs/session/introduction + * @author Leo Grützner + */ + +import SuperTokens from "supertokens-web-js"; +import Session from "supertokens-web-js/recipe/session"; +import { clientSideEnv } from "@env"; +import { onSignOut } from "../../onSignOut.js"; +import { getLocalSessionCookie } from "./shared.js"; +import { LOCAL_SESSION_COOKIE_NAME } from "./types.js"; +import { setLocalStorage } from "@src/services/local-storage/LocalStorageProvider.jsx"; + +const supertokensEnabled = + clientSideEnv.NODE_ENV == "production" || + clientSideEnv.VITE_SUPERTOKENS_IN_DEV !== undefined; + +const config = { + appInfo: { + apiDomain: clientSideEnv.VITE_FRONTEND_BASE_URL!, + appName: clientSideEnv.VITE_SUPERTOKENS_APP_NAME ?? "inlang", + apiBasePath: "/", + }, + recipeList: [ + Session.init({ + override: { + functions(originalImplementation) { + return { + ...originalImplementation, + signOut(input) { + onSignOut({ + // executing the correct sign out cleanup logic + setLocalStorage: setLocalStorage, + onlyClientSide: true, + }); + return originalImplementation.signOut(input); + }, + }; + }, + }, + }), + ], + enableDebugLogs: false, +}; + +/** + * Initializes the inlang session logic on the client side. This must happen before any other session logic is used and before any API calls to backend routes that rely on the session logic are made. + * For production, this initializes the supertokens session logic. + * For development, this initializes the simplified local session logic. + */ +export const initClientSession = async () => { + // init supertokens sesssion + if (typeof window != "undefined" && clientSideEnv.VITE_SUPERTOKENS_IN_DEV) { + SuperTokens.init(config); + await Session.attemptRefreshingSession(); + } +}; + +/** + * Calling the backend route to create a session. + * This function has to be called before the Oauth flow is started! + */ +export const tryCreateSession = async () => { + await fetch("/services/auth/create-session", { method: "POST" }); +}; + +/** + * Get the accessToken payload of the active session from the frontend. + * @returns The accessToken payload or undefined if no session is active + */ +export const getAccessTokenPayload = async () => { + if (supertokensEnabled) { + try { + return await Session.getAccessTokenPayloadSecurely(); + } catch { + return undefined; + } + } else { + return getLocalSessionCookie( + document.cookie, + LOCAL_SESSION_COOKIE_NAME.ACCESS_TOKEN_PAYLOAD + ); + } +}; diff --git a/source-code/website/src/services/auth/lib/session/server.ts b/source-code/website/src/services/auth/lib/session/server.ts new file mode 100644 index 0000000000..27254379f8 --- /dev/null +++ b/source-code/website/src/services/auth/lib/session/server.ts @@ -0,0 +1,264 @@ +/** + * Session logic for the backend using supertokens for production and a simplified local version for simpler development. + * Opt in to supertokens in development by setting the env variable 'VITE_SUPERTOKENS_IN_DEV' to 'true'. + * Also check to set the other required env vars, which are listed in the development setup guid. + * @see + * @see https://supertokens.com/docs/session/introduction + * @author Leo Grützner + */ + +import { verifySession } from "supertokens-node/recipe/session/framework/express/index.js"; +import { middleware as supertokensMiddleware } from "supertokens-node/framework/express/index.js"; +import cookie from "cookie"; +import Session from "supertokens-node/recipe/session"; +import crypto from "crypto"; +import { serverSideEnv } from "@env"; +import supertokens from "supertokens-node"; +import { errorHandler as supertokensErrorHandler } from "supertokens-node/framework/express"; +import type { TypeInput } from "supertokens-node/lib/build/types.js"; +import { LOCAL_SESSION_COOKIE_NAME } from "./types.js"; +import type { + InlangSession, + InlangSessionCacheEntry, + InlangSessionMiddleware, + InlangSessionRequest, +} from "./types.server.js"; +import type { Request, Response, NextFunction } from "express"; +import { getLocalSessionCookie } from "./shared.js"; + +const env = await serverSideEnv(); + +const config: TypeInput = { + framework: "express", + supertokens: { + // These are the connection details of the app you created on supertokens.com + connectionURI: env.SUPERTOKENS_CONNECTION_URI!, + apiKey: env.SUPERTOKENS_API_KEY!, + }, + appInfo: { + // learn more about this on https://supertokens.com/docs/session/appinfo + appName: env.VITE_SUPERTOKENS_APP_NAME ?? "inlang", + apiDomain: env.VITE_FRONTEND_BASE_URL!, + websiteDomain: env.VITE_FRONTEND_BASE_URL!, + apiBasePath: "/", + }, + recipeList: [Session.init({})], +}; + +let sessionStorage: Record; + +const supertokensEnabled = + env.NODE_ENV == "production" || env.VITE_SUPERTOKENS_IN_DEV !== undefined; + +/** + * Initializes the session logic, which must happen in the backend before any other supertokens functions are called. Check to set the required env vars, if working with supertokens, which is by disabled in the development environment by default. + */ +export const initSession = () => { + if (supertokensEnabled) { + supertokens.init(config); + } else { + console.info( + "Supertokens session disabled for the dev environment. Enable by setting the env var 'VITE_SUPERTOKENS_IN_DEV' to 'true'" + ); + } +}; + +/** + * Inlang session middleware for express + * Use in API routes when working with a session + * @param args sessionRequired: if true, the request will be rejected if no VALID session is linked to the request or if the + * @example app.use(verifyInlangSession({ sessionRequired: false })); + */ +export const verifyInlangSession = (args: { + sessionRequired: boolean; +}): InlangSessionMiddleware => { + return supertokensEnabled + ? (verifySession(args) as InlangSessionMiddleware) + : async (req: InlangSessionRequest, res: Response, next: NextFunction) => { + const handle = getLocalSessionCookie( + req.header("cookie") ?? "", + LOCAL_SESSION_COOKIE_NAME.SESSION_ID + ); + + const unauthorized = () => { + res.status(401).json({ message: "Unauthorized" }); + }; + + if (handle) { + req.session = getLocalSession(res, handle); + if (args.sessionRequired && !req.session) { + return unauthorized(); + } + } else if (args.sessionRequired) { + return unauthorized(); + } + + next(); + }; +}; + +/** Add this middleware before you use verifySession or getSession in an API route + * @returns Express middleware + * @example app.use(sessionMiddleware()); + */ +export const sessionMiddleware = () => { + if (supertokensEnabled) { + return [ + // if we'll need to add cors support, this would be the place to do it + // check: https://supertokens.com/docs/session/quick-setup/backend + supertokensMiddleware(), + ]; + } else { + return [ + async (req: Request, res: Response, next: NextFunction) => { + next(); + }, + ]; + } +}; + +/** + * Creates a session using supertokens for production and a simplified local session logic for development. + * @param res Express response object + * @param userId User id + * @param accessTokenPayload Access token payload + * @param sessionData Session data + * @returns Session object + * @throws Error if supertokens is enabled and the session creation fails + */ +export const createSession = ( + res: Response, + userId: string, + accessTokenPayload?: any, + sessionData?: any +) => { + return supertokensEnabled + ? Session.createNewSession(res, userId, accessTokenPayload, sessionData) + : createLocalSession(res, userId, accessTokenPayload, sessionData); +}; + +/** + * Creates a session object that can be attached to the request object (dev replacement for supertokens request.session) + * @param res Express response object + * @param userId User id + * @param accessTokenPayload Access token payload + * @param sessionData Session data + * @returns Cache session object + */ +const createLocalSession = ( + res: Response, + userId: string, + accessTokenPayload?: any, + sessionData?: any +): InlangSession => { + const handle = createCacheSession(userId, sessionData); + setLocalSessionCookieHeader( + res, + LOCAL_SESSION_COOKIE_NAME.SESSION_ID, + handle, + { httpOnly: true } + ); + + if (accessTokenPayload) { + setLocalSessionCookieHeader( + res, + LOCAL_SESSION_COOKIE_NAME.ACCESS_TOKEN_PAYLOAD, + accessTokenPayload, + { httpOnly: false } + ); + } + + return getLocalSession(res, handle); +}; + +/** + * Constructs a session object from a session chache entry that can be attached to the request object (dev replacement for supertokens request.session) + * @param res Express response object + * @param handle Session hanlde + * @returns Cache session object + */ +const getLocalSession = (res: Response, handle: string): InlangSession => { + if (!sessionStorage) { + sessionStorage = {}; + } + + const session: InlangSession = { + getSessionData: async () => { + return handle && sessionStorage[handle]; + }, + updateSessionData: async (data) => { + sessionStorage[handle] = data; + return handle && data; + }, + revokeSession: async () => { + delete sessionStorage[handle]; + }, + getHandle: () => handle, + updateAccessTokenPayload: async (payload: any) => { + setLocalSessionCookieHeader( + res, + LOCAL_SESSION_COOKIE_NAME.ACCESS_TOKEN_PAYLOAD, + payload, + { httpOnly: false } + ); + }, + }; + + return session; +}; + +/** + * Create a session in the cache (for dev environment) + * @param userId UserId for the session + * @param sessionData Unserialized session data + * @returns Session handle + */ +const createCacheSession = (userId: string, sessionData?: any) => { + const sessionEntry: InlangSessionCacheEntry = { + handle: crypto.randomBytes(20).toString("hex"), + userId, + data: sessionData ?? {}, + }; + + if (!sessionStorage) { + sessionStorage = {}; + } + + sessionStorage[sessionEntry.handle] = sessionEntry; + return sessionEntry.handle; +}; + +/** + * Express error handler for the inlang session implementation + * @returns Express error handler + */ +export const sessionErrorHandler = () => { + return supertokensEnabled + ? supertokensErrorHandler() + : async (err: any, req: Request, res: Response, next: NextFunction) => { + next(err); + }; +}; + +/** + * Add a cookie to the response header + * @param response Express response object + * @param type Cookie type form LOCAL_SESSION_COOKIE_NAME + * @param value Unserialized value + * @param options Cookie options like httpOnly + * @returns void + */ +const setLocalSessionCookieHeader = ( + res: Response, + type: LOCAL_SESSION_COOKIE_NAME, + value: string | undefined, + options: { httpOnly: boolean } +) => { + res.setHeader( + "Set-Cookie", + cookie.serialize(type, JSON.stringify(value ?? undefined), { + httpOnly: options.httpOnly, + path: "/", + }) + ); +}; diff --git a/source-code/website/src/services/auth/lib/session/shared.ts b/source-code/website/src/services/auth/lib/session/shared.ts new file mode 100644 index 0000000000..ec9e7b8476 --- /dev/null +++ b/source-code/website/src/services/auth/lib/session/shared.ts @@ -0,0 +1,25 @@ +/** + * Session logic which is shared by frontend and backend using supertokens for production and a simplified local version for simpler development. + * Opt in to supertokens in development by setting the env variable 'VITE_SUPERTOKENS_IN_DEV' to 'true'. + * Also check to set the other required env vars, which are listed in the development setup guid. + * @see + * @see https://supertokens.com/docs/session/introduction + * @author Leo Grützner + */ + +import type { LOCAL_SESSION_COOKIE_NAME } from "./types.js"; +import cookie from "cookie"; + +export const getLocalSessionCookie = ( + cookieString: string, + type: LOCAL_SESSION_COOKIE_NAME +) => { + const cookies = cookie.parse(cookieString || ""); + + try { + return JSON.parse(cookies[type] ?? "null"); + } catch (e) { + console.error("Error parsing session cookie of type", type, e); + return undefined; + } +}; diff --git a/source-code/website/src/services/auth/lib/session/types.server.ts b/source-code/website/src/services/auth/lib/session/types.server.ts new file mode 100644 index 0000000000..407fcd69b0 --- /dev/null +++ b/source-code/website/src/services/auth/lib/session/types.server.ts @@ -0,0 +1,34 @@ +/** + * Types for the session logic for the backend using supertokens for production and a simplified local version for simpler development. + * @see + * @see https://supertokens.com/docs/session/introduction + * @author Leo Grützner + */ + +import type { Request, Response, NextFunction } from "express"; +import type { SessionContainerInterface } from "supertokens-node/lib/build/recipe/session/types.js"; + +export interface InlangSessionRequest extends Request { + session?: InlangSession; +} + +export type InlangSessionMiddleware = ( + req: InlangSessionRequest, + res: Response>, + next: NextFunction +) => Promise; + +export type InlangSession = Pick< + SessionContainerInterface, + | "getSessionData" + | "updateSessionData" + | "revokeSession" + | "getHandle" + | "updateAccessTokenPayload" +>; + +export type InlangSessionCacheEntry = { + handle: string; + userId: string; + data: any; +}; diff --git a/source-code/website/src/services/auth/lib/session/types.ts b/source-code/website/src/services/auth/lib/session/types.ts new file mode 100644 index 0000000000..a9b8ce441a --- /dev/null +++ b/source-code/website/src/services/auth/lib/session/types.ts @@ -0,0 +1,11 @@ +/** + * Types for the session logic which are shared by frontend and backend using supertokens for production and a simplified local version for simpler development. + * @see + * @see https://supertokens.com/docs/session/introduction + * @author Leo Grützner + */ + +export const enum LOCAL_SESSION_COOKIE_NAME { + SESSION_ID = "inlang-dev-session-id", + ACCESS_TOKEN_PAYLOAD = "inlang-dev-session-access-token-payload", +} diff --git a/source-code/website/src/services/auth/logic.telefunc.ts b/source-code/website/src/services/auth/logic.telefunc.ts index f5cc7fc08e..c8cd5b8dda 100644 --- a/source-code/website/src/services/auth/logic.telefunc.ts +++ b/source-code/website/src/services/auth/logic.telefunc.ts @@ -5,13 +5,13 @@ import { getContext } from "telefunc"; * Get the user info from the GitHub API. * * Read https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#get-the-authenticated-user - * * @throws */ export async function getUserInfo(): Promise< LocalStorageSchema["user"] | undefined > { const context = getContext(); + if (context.githubAccessToken === undefined) { return undefined; } diff --git a/source-code/website/src/services/auth/logic.ts b/source-code/website/src/services/auth/logic.ts index a467a83485..3db38ceecd 100644 --- a/source-code/website/src/services/auth/logic.ts +++ b/source-code/website/src/services/auth/logic.ts @@ -92,3 +92,40 @@ export async function exchangeInterimCodeForAccessToken(args: { } return requestBody.access_token; } + +// /** +// * Get the user info from the GitHub API. +// * +// * Read https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#get-the-authenticated-user +// * @throws +// */ +// export async function getGithubUserInfo(args: { +// githubAccessToken: string; +// }): Promise { +// if (args.githubAccessToken === undefined) { +// return undefined; +// } + +// const request = await fetch("https://api.github.com/user", { +// headers: { +// Accept: "application/vnd.github+json", +// Authorization: `Bearer ${args.githubAccessToken}`, +// "X-GitHub-Api-Version": "2022-11-28", +// }, +// }); + +// if (request.ok === false) { +// throw Error("Failed to get user info " + request.statusText); +// } + +// const requestBody = await request.json(); +// return { +// username: requestBody.login, +// avatarUrl: requestBody.avatar_url, +// }; +// } + +// const getSessionData = async (args: {}) => { +// if (true) { +// } +// }; diff --git a/source-code/website/src/services/auth/onSignOut.ts b/source-code/website/src/services/auth/onSignOut.ts index 9a7a8ac613..6c1c2c938c 100644 --- a/source-code/website/src/services/auth/onSignOut.ts +++ b/source-code/website/src/services/auth/onSignOut.ts @@ -1,14 +1,17 @@ -import type { SetStoreFunction } from "solid-js/store"; -import type { LocalStorageSchema } from "../local-storage/schema.js"; +import type { SetLocalStorage } from "../local-storage/schema.js"; /** - * This function is called when the user clicks the "Sign Out" button. + * This function is called when the user clicks the "Sign Out" button + * or when supertokens.onSignOut is called. */ export async function onSignOut(args: { - setLocalStorage: SetStoreFunction; + setLocalStorage: SetLocalStorage; + onlyClientSide?: boolean; }) { - // sign out on the server - await fetch("/services/auth/sign-out", { method: "POST" }); - // sign out on the client by setting the user to undefined + if (!args.onlyClientSide) { + // sign out on the server + await fetch("/services/auth/sign-out", { method: "POST" }); + } + args.setLocalStorage("user", undefined); } diff --git a/source-code/website/src/services/auth/server.ts b/source-code/website/src/services/auth/server.ts index 64b03753b9..5240a2244b 100644 --- a/source-code/website/src/services/auth/server.ts +++ b/source-code/website/src/services/auth/server.ts @@ -4,6 +4,9 @@ import { encryptAccessToken, exchangeInterimCodeForAccessToken, } from "./logic.js"; +import crypto from "crypto"; +import { createSession, verifyInlangSession } from "./lib/session/server.js"; +import type { InlangSessionRequest } from "./lib/session/types.server.js"; export const router = express.Router(); @@ -15,28 +18,74 @@ const env = await serverSideEnv(); * Be aware that the route set here is prefixed with /services/auth * and that the route is set in the GitHub OAuth app settings. */ -router.get("/github-oauth-callback", async (request, response, next) => { - try { - const code = request.query.code as string; - const accessToken = await exchangeInterimCodeForAccessToken({ code, env }); - const encryptedAccessToken = await encryptAccessToken({ - accessToken, - JWE_SECRET_KEY: env.JWE_SECRET_KEY, - }); - // set the session - request.session = { - encryptedAccessToken, - }; - response.redirect("/services/auth/oauth-callback"); - } catch (error) { - next(error); +router.get( + "/github-oauth-callback", + verifyInlangSession({ sessionRequired: false }), + async (request: InlangSessionRequest, response, next) => { + try { + const code = request.query.code as string; + const accessToken = await exchangeInterimCodeForAccessToken({ + code, + env, + }); + + const encryptedAccessToken = await encryptAccessToken({ + accessToken, + JWE_SECRET_KEY: env.JWE_SECRET_KEY, + }); + + let session = request.session; + if (!session) { + session = await createSession( + response, + crypto.randomBytes(20).toString("hex") + ); + } + + const sessionData = await session.getSessionData(); + + // Update the supertokens session + session.updateSessionData({ + ...sessionData, + encryptedAccessToken, + }); + + response.redirect("/services/auth/oauth-callback"); + } catch (error) { + next(error); + } + } +); + +/** + * Sign out by revoking the session if one exists. + * Returns 401 if the accessToken is no longer valid. A correctly initialized frontend will then attempt to refresh the session and call the route again. + */ +router.post( + "/sign-out", + verifyInlangSession({ sessionRequired: false }), + async (req: InlangSessionRequest, res) => { + // This will delete the session from the db and from the frontend (cookies) + if (req.session) { + await req.session.revokeSession(); + } + + res.status(204).send("signed out"); } -}); +); /** - * Sign out by setting the session to undefined. + * Creates a new session if the requesting client doesn't already have one. + * Returns 401 if the accessToken is no longer valid. A correctly initialized frontend will then attempt to refresh the session and call the route again. */ -router.post("/sign-out", (request, response) => { - request.session = undefined; - response.status(201).send(); -}); +router.post( + "/create-session", + verifyInlangSession({ sessionRequired: false }), + async (req: InlangSessionRequest, res) => { + if (!req.session) { + await createSession(res, Math.random().toString()); + } + + res.status(201).send("Created session or session already existed."); + } +); diff --git a/source-code/website/src/services/local-storage/LocalStorageProvider.tsx b/source-code/website/src/services/local-storage/LocalStorageProvider.tsx index 3ca2636d6d..941d66f8e7 100644 --- a/source-code/website/src/services/local-storage/LocalStorageProvider.tsx +++ b/source-code/website/src/services/local-storage/LocalStorageProvider.tsx @@ -1,3 +1,9 @@ +/** + * This file contains the local storage provider and also non reactive versions. + * + * This custom implementation uses only one key in the actual local storage and works with JSON.stringify() / .parse() to emulate the behaviour of the normal localStorage interface. + */ + import { createContext, JSXElement, @@ -7,7 +13,11 @@ import { } from "solid-js"; import { createStore, reconcile, SetStoreFunction } from "solid-js/store"; import { getUserInfo } from "../auth/logic.telefunc.js"; -import { defaultLocalStorage, LocalStorageSchema } from "./schema.js"; +import { + defaultLocalStorage, + LocalStorageSchema, + SetLocalStorage, +} from "./schema.js"; const LocalStorageContext = createContext(); @@ -28,6 +38,27 @@ export function getLocalStorage(): LocalStorageSchema | undefined { } } +/** + * Updates a key using inlangs custom local storage structure. + * + * This is the non-reactive version of `useLocalStorage()` (regular JS/TS, not JSX). + * Use the reactive version if you are in a JSX environment. + * @param key The key to update + * @param value The value to update the key with + */ +export const setLocalStorage: SetLocalStorage = (key, value) => { + if (!key) { + return; + } + + const store = getLocalStorage(); + + localStorage.setItem( + LOCAL_STORAGE_KEY, + JSON.stringify({ ...store, [key]: value }) + ); +}; + /** * Store that provides access to the local storage. * @@ -82,10 +113,9 @@ export function LocalStorageProvider(props: { children: JSXElement }) { return console.warn( `unknown localStorage key "${event.key}" was changed by another tab.` ); - } - if (event.newValue === null) { + } else if (event.newValue === null) { return console.error( - 'localStorage key "store" was deleted by another tab. this should not happen.' + `localStorage key "${LOCAL_STORAGE_KEY}" was deleted by another tab. this should not happen.` ); } // setting the origin store to not trigger a loop diff --git a/source-code/website/src/services/local-storage/schema.ts b/source-code/website/src/services/local-storage/schema.ts index 4b477e22be..229526ec39 100644 --- a/source-code/website/src/services/local-storage/schema.ts +++ b/source-code/website/src/services/local-storage/schema.ts @@ -20,3 +20,10 @@ export type LocalStorageSchema = { export const defaultLocalStorage: LocalStorageSchema = { showMachineTranslationWarning: true, }; + +/** + * The setter for the custom localStorage logic. + */ +export interface SetLocalStorage { + (key: keyof LocalStorageSchema, value: any): void; +}