diff --git a/cypress/e2e/AsStudent/signIn.cy.js b/cypress/e2e/AsStudent/signIn.cy.js index 65f3f19852..cbc6ff9a24 100644 --- a/cypress/e2e/AsStudent/signIn.cy.js +++ b/cypress/e2e/AsStudent/signIn.cy.js @@ -1,24 +1,7 @@ describe("Student Sign-In Test", function () { const userId = "cyuserId"; - // const studentUserId = "cyStudentUserId"; const courseId = "courseid1"; - // const doenetId = "activity1id"; - // const pageDoenetId = "_page1id"; - before(() => { - cy.signin({ userId }); - cy.clearAllOfAUsersCoursesAndItems({ userId }); - // cy.clearAllOfAUsersCoursesAndItems({ userId: studentUserId }); - cy.createCourse({ userId, courseId }); - }); - beforeEach(() => { - cy.signin({ userId }); - cy.clearIndexedDB(); - cy.clearAllOfAUsersActivities({ userId }); - // cy.clearAllOfAUsersActivities({ userId: studentUserId }); - // cy.createActivity({ courseId, doenetId, parentDoenetId:courseId, pageDoenetId }); - cy.visit(`/course?tool=people&courseId=${courseId}`); - }); Cypress.on("uncaught:exception", (err, runnable) => { // Returning false here prevents Cypress from failing the test @@ -26,6 +9,12 @@ describe("Student Sign-In Test", function () { }); it("Student can sign in after being added to a course", () => { + cy.createCourse({ userId, courseId }); + cy.signin({ userId }); + cy.clearIndexedDB(); + cy.clearAllOfAUsersActivities({ userId }); + cy.visit(`/course?tool=people&courseId=${courseId}`); + const emailAddress = "scoobydoo@doenet.org"; cy.get('[data-test="First"]').type("Scooby"); cy.get('[data-test="Last"]').type("Doo"); @@ -42,8 +31,17 @@ describe("Student Sign-In Test", function () { `SELECT signInCode FROM user_device ORDER BY id DESC LIMIT 1`, ).then((result) => { const code = result[0].signInCode; - cy.get('[data-test="signinCodeInput"]').type(code); - cy.get('[data-test="signInButton"]').click(); + // cy.get('[data-test="signinCodeInput"]').type(code); + cy.get('[data-test="code-input-0"]').type(code.charAt(0)); + cy.get('[data-test="code-input-1"]').type(code.charAt(1)); + cy.get('[data-test="code-input-2"]').type(code.charAt(2)); + cy.get('[data-test="code-input-3"]').type(code.charAt(3)); + cy.get('[data-test="code-input-4"]').type(code.charAt(4)); + cy.get('[data-test="code-input-5"]').type(code.charAt(5)); + cy.get('[data-test="code-input-6"]').type(code.charAt(6)); + cy.get('[data-test="code-input-7"]').type(code.charAt(7)); + cy.get('[data-test="code-input-8"]').type(code.charAt(8)); + cy.get('[data-test="submitCodeButton"]').click(); cy.get('[data-test="My Courses"]').click(); cy.get('[data-test="Course Label"]').should( "have.text", @@ -53,4 +51,56 @@ describe("Student Sign-In Test", function () { cy.document().should("contain.text", "Welcome"); }); }); + + it("Signed out to in to out with all entry errors", () => { + const emailAddress = "scrapydoo@doenet.org"; + const firstName = "Scrapy"; + const lastName = "Doo"; + //Delete entry so we will need to enter the name + cy.task( + "queryDb", + `DELETE FROM user WHERE email='${emailAddress}'`, + ).then(() => { + cy.visit(`/`); + cy.get('[data-test="Nav to signin"]').click(); + cy.get('[data-test="email input"]').type(emailAddress); + cy.get('[data-test="sendEmailButton"]').click(); + cy.wait(500); //Wait for it to be stored in db + cy.task( + "queryDb", + `SELECT signInCode FROM user_device ORDER BY id DESC LIMIT 1`, + ).then((result) => { + const code = result[0].signInCode; + //Try no code + cy.get('[data-test="submitCodeButton"]').click(); + cy.get('[data-test="code-err"]').should('contain', "Please enter the nine digits sent to your email."); + //Try only one number + cy.get('[data-test="code-input-0"]').type(code.charAt(0)); + cy.get('[data-test="submitCodeButton"]').click(); + cy.get('[data-test="code-err"]').should('contain', "Please enter all nine digits."); + + cy.get('[data-test="code-input-0"]').type(code.charAt(0)); + cy.get('[data-test="code-input-1"]').type(code.charAt(1)); + cy.get('[data-test="code-input-2"]').type(code.charAt(2)); + cy.get('[data-test="code-input-3"]').type(code.charAt(3)); + cy.get('[data-test="code-input-4"]').type(code.charAt(4)); + cy.get('[data-test="code-input-5"]').type(code.charAt(5)); + cy.get('[data-test="code-input-6"]').type(code.charAt(6)); + cy.get('[data-test="code-input-7"]').type(code.charAt(7)); + cy.get('[data-test="code-input-8"]').type(code.charAt(8)); + cy.get('[data-test="submitCodeButton"]').click(); + //Try no names + cy.get('[data-test="submitName"]').click(); + cy.get('[data-test="firstNameError"]').should('contain', 'Please enter your first name.') + cy.get('[data-test="lastNameError"]').should('contain', 'Please enter your last name.') + + cy.get('[data-test="firstNameInput"]').type(firstName); + cy.get('[data-test="lastNameInput"]').type(lastName); + cy.get('[data-test="submitName"]').click(); + cy.get('[data-test="AvatarMenuButton"]').click(); + cy.get('[data-test="AvatarMenuSignOut"]').click(); + cy.get('[data-test="homepage button"]').click(); + }); + }); + }); }); diff --git a/package-lock.json b/package-lock.json index 3c3e504443..3f4f3a4c52 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,7 @@ "crypto-js": "^3.3.0", "cssesc": "^3.0.0", "csv-parse": "^5.3.6", + "cypress": "^13.3.3", "esm-seedrandom": "^3.0.5", "framer-motion": "^10.12.10", "handsontable": "^12.1.2", @@ -109,7 +110,7 @@ }, "optionalDependencies": { "@esbuild/linux-arm64": "^0.17.19", - "cypress": "^12.12.0", + "cypress": "^13.3.3", "cypress-file-upload": "^5.0.8", "cypress-parallel": "^0.13.0", "cypress-plugin-tab": "^1.0.5", @@ -1973,8 +1974,9 @@ } }, "node_modules/@cypress/request": { - "version": "2.88.10", - "license": "Apache-2.0", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz", + "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==", "optional": true, "dependencies": { "aws-sign2": "~0.7.0", @@ -1990,9 +1992,9 @@ "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "performance-now": "^2.1.0", - "qs": "~6.5.2", + "qs": "6.10.4", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", + "tough-cookie": "^4.1.3", "tunnel-agent": "^0.6.0", "uuid": "^8.3.2" }, @@ -2002,7 +2004,8 @@ }, "node_modules/@cypress/request/node_modules/form-data": { "version": "2.3.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "optional": true, "dependencies": { "asynckit": "^0.4.0", @@ -2014,11 +2017,18 @@ } }, "node_modules/@cypress/request/node_modules/qs": { - "version": "6.5.3", - "license": "BSD-3-Clause", + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", + "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", "optional": true, + "dependencies": { + "side-channel": "^1.0.4" + }, "engines": { "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/@cypress/xvfb": { @@ -3443,8 +3453,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "18.11.4", - "license": "MIT" + "version": "18.18.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.6.tgz", + "integrity": "sha512-wf3Vz+jCmOQ2HV1YUJuCWdL64adYxumkrxtc+H1VUQlnQI04+5HtH+qZCOE21lBE7gIrt+CwX2Wv8Acrw5Ak6w==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -4213,7 +4224,8 @@ }, "node_modules/asn1": { "version": "0.2.6", - "license": "MIT", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "optional": true, "dependencies": { "safer-buffer": "~2.1.0" @@ -4221,7 +4233,8 @@ }, "node_modules/assert-plus": { "version": "1.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "optional": true, "engines": { "node": ">=0.8" @@ -4291,15 +4304,17 @@ }, "node_modules/aws-sign2": { "version": "0.7.0", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "optional": true, "engines": { "node": "*" } }, "node_modules/aws4": { - "version": "1.11.0", - "license": "MIT", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", "optional": true }, "node_modules/axe-core": { @@ -4734,7 +4749,8 @@ }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", - "license": "BSD-3-Clause", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "optional": true, "dependencies": { "tweetnacl": "^0.14.3" @@ -4942,7 +4958,7 @@ }, "node_modules/call-bind": { "version": "1.0.2", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.1", @@ -4997,7 +5013,8 @@ }, "node_modules/caseless": { "version": "0.12.0", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "optional": true }, "node_modules/chai": { @@ -5508,6 +5525,12 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "optional": true + }, "node_modules/cors": { "version": "2.8.5", "license": "MIT", @@ -5603,15 +5626,15 @@ "license": "MIT" }, "node_modules/cypress": { - "version": "12.12.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-12.12.0.tgz", - "integrity": "sha512-UU5wFQ7SMVCR/hyKok/KmzG6fpZgBHHfrXcHzDmPHWrT+UUetxFzQgt7cxCszlwfozckzwkd22dxMwl/vNkWRw==", + "version": "13.3.3", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.3.3.tgz", + "integrity": "sha512-mbdkojHhKB1xbrj7CrKWHi22uFx9P9vQFiR0sYDZZoK99OMp9/ZYN55TO5pjbXmV7xvCJ4JwBoADXjOJK8aCJw==", "hasInstallScript": true, "optional": true, "dependencies": { - "@cypress/request": "^2.88.10", + "@cypress/request": "^3.0.0", "@cypress/xvfb": "^1.2.4", - "@types/node": "^14.14.31", + "@types/node": "^18.17.5", "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", "arch": "^2.2.0", @@ -5644,9 +5667,10 @@ "minimist": "^1.2.8", "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", + "process": "^0.11.10", "proxy-from-env": "1.0.0", "request-progress": "^3.0.0", - "semver": "^7.3.2", + "semver": "^7.5.3", "supports-color": "^8.1.1", "tmp": "~0.2.1", "untildify": "^4.0.0", @@ -5656,7 +5680,7 @@ "cypress": "bin/cypress" }, "engines": { - "node": "^14.0.0 || ^16.0.0 || >=18.0.0" + "node": "^16.0.0 || ^18.0.0 || >=20.0.0" } }, "node_modules/cypress-file-upload": { @@ -6112,11 +6136,6 @@ "license": "MIT", "optional": true }, - "node_modules/cypress/node_modules/@types/node": { - "version": "14.18.32", - "license": "MIT", - "optional": true - }, "node_modules/cypress/node_modules/ansi-styles": { "version": "4.3.0", "license": "MIT", @@ -6205,8 +6224,9 @@ } }, "node_modules/cypress/node_modules/semver": { - "version": "7.3.8", - "license": "ISC", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "optional": true, "dependencies": { "lru-cache": "^6.0.0" @@ -6239,7 +6259,8 @@ }, "node_modules/dashdash": { "version": "1.14.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "optional": true, "dependencies": { "assert-plus": "^1.0.0" @@ -6479,7 +6500,8 @@ }, "node_modules/ecc-jsbn": { "version": "0.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "optional": true, "dependencies": { "jsbn": "~0.1.0", @@ -7772,7 +7794,8 @@ }, "node_modules/extend": { "version": "3.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "optional": true }, "node_modules/extend-shallow": { @@ -7865,10 +7888,11 @@ }, "node_modules/extsprintf": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "engines": [ "node >=0.6.0" ], - "license": "MIT", "optional": true }, "node_modules/fast-deep-equal": { @@ -8059,7 +8083,8 @@ }, "node_modules/forever-agent": { "version": "0.6.1", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "optional": true, "engines": { "node": "*" @@ -8232,7 +8257,7 @@ }, "node_modules/get-intrinsic": { "version": "1.1.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.1", @@ -8298,7 +8323,8 @@ }, "node_modules/getpass": { "version": "0.1.7", - "license": "MIT", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "optional": true, "dependencies": { "assert-plus": "^1.0.0" @@ -8461,7 +8487,7 @@ }, "node_modules/has-symbols": { "version": "1.0.3", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8627,7 +8653,8 @@ }, "node_modules/http-signature": { "version": "1.3.6", - "license": "MIT", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", "optional": true, "dependencies": { "assert-plus": "^1.0.0", @@ -9178,7 +9205,8 @@ }, "node_modules/is-typedarray": { "version": "1.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "optional": true }, "node_modules/is-unicode-supported": { @@ -9249,7 +9277,8 @@ }, "node_modules/isstream": { "version": "0.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "optional": true }, "node_modules/istanbul-lib-coverage": { @@ -9366,7 +9395,8 @@ }, "node_modules/jsbn": { "version": "0.1.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "optional": true }, "node_modules/jsesc": { @@ -9385,7 +9415,8 @@ }, "node_modules/json-schema": { "version": "0.4.0", - "license": "(AFL-2.1 OR BSD-3-Clause)", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", "optional": true }, "node_modules/json-schema-traverse": { @@ -9407,7 +9438,8 @@ }, "node_modules/json-stringify-safe": { "version": "5.0.1", - "license": "ISC", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "optional": true }, "node_modules/json5": { @@ -9433,10 +9465,11 @@ }, "node_modules/jsprim": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", "engines": [ "node >=0.6.0" ], - "license": "MIT", "optional": true, "dependencies": { "assert-plus": "1.0.0", @@ -10613,7 +10646,7 @@ }, "node_modules/object-inspect": { "version": "1.12.2", - "dev": true, + "devOptional": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10955,7 +10988,8 @@ }, "node_modules/performance-now": { "version": "2.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "optional": true }, "node_modules/picocolors": { @@ -11210,6 +11244,15 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "optional": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/progress": { "version": "2.0.3", "dev": true, @@ -11238,7 +11281,8 @@ }, "node_modules/psl": { "version": "1.9.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "optional": true }, "node_modules/pump": { @@ -11294,6 +11338,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "optional": true + }, "node_modules/queue-microtask": { "version": "1.2.3", "devOptional": true, @@ -11872,7 +11922,7 @@ }, "node_modules/requires-port": { "version": "1.0.0", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/resize-observer-polyfill": { @@ -12322,7 +12372,7 @@ }, "node_modules/side-channel": { "version": "1.0.4", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.0", @@ -12720,8 +12770,9 @@ } }, "node_modules/sshpk": { - "version": "1.17.0", - "license": "MIT", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "optional": true, "dependencies": { "asn1": "~0.2.3", @@ -13226,15 +13277,27 @@ } }, "node_modules/tough-cookie": { - "version": "2.5.0", - "license": "BSD-3-Clause", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "optional": true, "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" }, "engines": { - "node": ">=0.8" + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "optional": true, + "engines": { + "node": ">= 4.0.0" } }, "node_modules/tr46": { @@ -13285,7 +13348,8 @@ }, "node_modules/tunnel-agent": { "version": "0.6.0", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "optional": true, "dependencies": { "safe-buffer": "^5.0.1" @@ -13296,7 +13360,8 @@ }, "node_modules/tweetnacl": { "version": "0.14.5", - "license": "Unlicense", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "optional": true }, "node_modules/type-check": { @@ -13532,6 +13597,16 @@ "version": "0.1.0", "license": "MIT" }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "optional": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/use": { "version": "3.1.1", "license": "MIT", @@ -13600,7 +13675,8 @@ }, "node_modules/uuid": { "version": "8.3.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "optional": true, "bin": { "uuid": "dist/bin/uuid" @@ -13636,10 +13712,11 @@ }, "node_modules/verror": { "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "engines": [ "node >=0.6.0" ], - "license": "MIT", "optional": true, "dependencies": { "assert-plus": "^1.0.0", @@ -13647,11 +13724,6 @@ "extsprintf": "^1.2.0" } }, - "node_modules/verror/node_modules/core-util-is": { - "version": "1.0.2", - "license": "MIT", - "optional": true - }, "node_modules/vite": { "version": "4.2.1", "dev": true, @@ -15568,7 +15640,9 @@ "optional": true }, "@cypress/request": { - "version": "2.88.10", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz", + "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==", "optional": true, "requires": { "aws-sign2": "~0.7.0", @@ -15584,15 +15658,17 @@ "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "performance-now": "^2.1.0", - "qs": "~6.5.2", + "qs": "6.10.4", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", + "tough-cookie": "^4.1.3", "tunnel-agent": "^0.6.0", "uuid": "^8.3.2" }, "dependencies": { "form-data": { "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "optional": true, "requires": { "asynckit": "^0.4.0", @@ -15601,8 +15677,13 @@ } }, "qs": { - "version": "6.5.3", - "optional": true + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", + "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", + "optional": true, + "requires": { + "side-channel": "^1.0.4" + } } } }, @@ -16532,7 +16613,9 @@ "dev": true }, "@types/node": { - "version": "18.11.4" + "version": "18.18.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.6.tgz", + "integrity": "sha512-wf3Vz+jCmOQ2HV1YUJuCWdL64adYxumkrxtc+H1VUQlnQI04+5HtH+qZCOE21lBE7gIrt+CwX2Wv8Acrw5Ak6w==" }, "@types/normalize-package-data": { "version": "2.4.1" @@ -17058,6 +17141,8 @@ }, "asn1": { "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "optional": true, "requires": { "safer-buffer": "~2.1.0" @@ -17065,6 +17150,8 @@ }, "assert-plus": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "optional": true }, "assertion-error": { @@ -17101,10 +17188,14 @@ }, "aws-sign2": { "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "optional": true }, "aws4": { - "version": "1.11.0", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", "optional": true }, "axe-core": { @@ -17395,6 +17486,8 @@ }, "bcrypt-pbkdf": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "optional": true, "requires": { "tweetnacl": "^0.14.3" @@ -17524,7 +17617,7 @@ }, "call-bind": { "version": "1.0.2", - "dev": true, + "devOptional": true, "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -17548,6 +17641,8 @@ }, "caseless": { "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "optional": true }, "chai": { @@ -17880,6 +17975,12 @@ "version": "3.26.0", "dev": true }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "optional": true + }, "cors": { "version": "2.8.5", "requires": { @@ -17947,14 +18048,14 @@ "version": "5.3.6" }, "cypress": { - "version": "12.12.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-12.12.0.tgz", - "integrity": "sha512-UU5wFQ7SMVCR/hyKok/KmzG6fpZgBHHfrXcHzDmPHWrT+UUetxFzQgt7cxCszlwfozckzwkd22dxMwl/vNkWRw==", + "version": "13.3.3", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.3.3.tgz", + "integrity": "sha512-mbdkojHhKB1xbrj7CrKWHi22uFx9P9vQFiR0sYDZZoK99OMp9/ZYN55TO5pjbXmV7xvCJ4JwBoADXjOJK8aCJw==", "optional": true, "requires": { - "@cypress/request": "^2.88.10", + "@cypress/request": "^3.0.0", "@cypress/xvfb": "^1.2.4", - "@types/node": "^14.14.31", + "@types/node": "^18.17.5", "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", "arch": "^2.2.0", @@ -17987,19 +18088,16 @@ "minimist": "^1.2.8", "ospath": "^1.2.2", "pretty-bytes": "^5.6.0", + "process": "^0.11.10", "proxy-from-env": "1.0.0", "request-progress": "^3.0.0", - "semver": "^7.3.2", + "semver": "^7.5.3", "supports-color": "^8.1.1", "tmp": "~0.2.1", "untildify": "^4.0.0", "yauzl": "^2.10.0" }, "dependencies": { - "@types/node": { - "version": "14.18.32", - "optional": true - }, "ansi-styles": { "version": "4.3.0", "optional": true, @@ -18048,7 +18146,9 @@ "optional": true }, "semver": { - "version": "7.3.8", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "optional": true, "requires": { "lru-cache": "^6.0.0" @@ -18405,6 +18505,8 @@ }, "dashdash": { "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "optional": true, "requires": { "assert-plus": "^1.0.0" @@ -18550,6 +18652,8 @@ }, "ecc-jsbn": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "optional": true, "requires": { "jsbn": "~0.1.0", @@ -19337,6 +19441,8 @@ }, "extend": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "optional": true }, "extend-shallow": { @@ -19397,6 +19503,8 @@ }, "extsprintf": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "optional": true }, "fast-deep-equal": { @@ -19519,6 +19627,8 @@ }, "forever-agent": { "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "optional": true }, "form-data": { @@ -19625,7 +19735,7 @@ }, "get-intrinsic": { "version": "1.1.3", - "dev": true, + "devOptional": true, "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -19664,6 +19774,8 @@ }, "getpass": { "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "optional": true, "requires": { "assert-plus": "^1.0.0" @@ -19768,7 +19880,7 @@ }, "has-symbols": { "version": "1.0.3", - "dev": true + "devOptional": true }, "has-tostringtag": { "version": "1.0.0", @@ -19880,6 +19992,8 @@ }, "http-signature": { "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", "optional": true, "requires": { "assert-plus": "^1.0.0", @@ -20191,6 +20305,8 @@ }, "is-typedarray": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "optional": true }, "is-unicode-supported": { @@ -20229,6 +20345,8 @@ }, "isstream": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "optional": true }, "istanbul-lib-coverage": { @@ -20309,6 +20427,8 @@ }, "jsbn": { "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "optional": true }, "jsesc": { @@ -20319,6 +20439,8 @@ }, "json-schema": { "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", "optional": true }, "json-schema-traverse": { @@ -20334,6 +20456,8 @@ }, "json-stringify-safe": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "optional": true }, "json5": { @@ -20349,6 +20473,8 @@ }, "jsprim": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", "optional": true, "requires": { "assert-plus": "1.0.0", @@ -21169,7 +21295,7 @@ }, "object-inspect": { "version": "1.12.2", - "dev": true + "devOptional": true }, "object-keys": { "version": "1.1.1", @@ -21372,6 +21498,8 @@ }, "performance-now": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "optional": true }, "picocolors": { @@ -21529,6 +21657,12 @@ } } }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "optional": true + }, "progress": { "version": "2.0.3", "dev": true @@ -21552,6 +21686,8 @@ }, "psl": { "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "optional": true }, "pump": { @@ -21591,6 +21727,12 @@ "side-channel": "^1.0.4" } }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "optional": true + }, "queue-microtask": { "version": "1.2.3", "devOptional": true @@ -21942,7 +22084,7 @@ }, "requires-port": { "version": "1.0.0", - "dev": true + "devOptional": true }, "resize-observer-polyfill": { "version": "1.5.1" @@ -22231,7 +22373,7 @@ }, "side-channel": { "version": "1.0.4", - "dev": true, + "devOptional": true, "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -22506,7 +22648,9 @@ "dev": true }, "sshpk": { - "version": "1.17.0", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "optional": true, "requires": { "asn1": "~0.2.3", @@ -22849,11 +22993,23 @@ "dev": true }, "tough-cookie": { - "version": "2.5.0", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "optional": true, "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "dependencies": { + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "optional": true + } } }, "tr46": { @@ -22893,6 +23049,8 @@ }, "tunnel-agent": { "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "optional": true, "requires": { "safe-buffer": "^5.0.1" @@ -22900,6 +23058,8 @@ }, "tweetnacl": { "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "optional": true }, "type-check": { @@ -23037,6 +23197,16 @@ "urix": { "version": "0.1.0" }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "optional": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "use": { "version": "3.1.1" }, @@ -23069,6 +23239,8 @@ }, "uuid": { "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "optional": true }, "v8-to-istanbul": { @@ -23092,17 +23264,13 @@ }, "verror": { "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "optional": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "optional": true - } } }, "vite": { diff --git a/package.json b/package.json index 1bd4fd65d0..2ed0964a8b 100644 --- a/package.json +++ b/package.json @@ -127,7 +127,7 @@ }, "optionalDependencies": { "@esbuild/linux-arm64": "^0.17.19", - "cypress": "^12.12.0", + "cypress": "^13.3.3", "cypress-file-upload": "^5.0.8", "cypress-parallel": "^0.13.0", "cypress-plugin-tab": "^1.0.5", diff --git a/public/api/baseModel.php b/public/api/baseModel.php index 12235e448a..e74c27cf96 100644 --- a/public/api/baseModel.php +++ b/public/api/baseModel.php @@ -28,11 +28,14 @@ public static function runQuery($conn, $query) { public static function queryFetchAssoc($conn, $query) { $result = Base_Model::runQuery($conn, $query); if ($result->num_rows > 0) { - $rows = []; + $data = []; while($row = $result->fetch_assoc()){ - $rows[] = $row; + $data['rows'] = $row; + foreach($row as $key => $value){ + $data[$key][] = $value; + } } - return $rows; + return $data; } else { return []; } @@ -45,18 +48,23 @@ public static function queryFetchAssoc($conn, $query) { * * If more than one row is returned, throws an exception. */ - public static function queryExpectingOneRow($conn, $query) { - $rows = Base_Model::queryFetchAssoc($conn, $query); - - if (count($rows) == 1) { - return $rows[0]; - } else if (count($rows) == 0) { + public static function queryOneRowOrError($conn, $query) { + $data = Base_Model::queryFetchAssoc($conn, $query); + + if (count($data['rows']) == 1) { + return $data; + } else if (count($data['rows']) == 0) { return null; } else { + throw new Exception("Unexpected error, only expected one row from this query."); + error_log("Unexpected error, only expected one row from this query." . + "\n " . $conn->error . + "\n" . $query); } } + /** * Validate that a list of keys are present in a given associative array. * diff --git a/public/api/checkCredentials.php b/public/api/checkCredentials.php index 4efc6852aa..15213e03ad 100644 --- a/public/api/checkCredentials.php +++ b/public/api/checkCredentials.php @@ -6,70 +6,74 @@ header('Content-Type: application/json'); include "db_connection.php"; - +include "baseModel.php"; $emailaddress = mysqli_real_escape_string($conn,$_REQUEST["emailaddress"]); $nineCode = mysqli_real_escape_string($conn,$_REQUEST["nineCode"]); $deviceName = mysqli_real_escape_string($conn,$_REQUEST["deviceName"]); -//Check if expired -$sql = "SELECT TIMESTAMPDIFF(MINUTE, timestampOfSignInCode, NOW()) AS minutes -FROM user_device -WHERE email='$emailaddress' AND deviceName='$deviceName'"; +$response_arr; +try { + Base_Model::checkForRequiredInputs($_REQUEST,["emailaddress","nineCode","deviceName"]); -$result = $conn->query($sql); -$row = $result->fetch_assoc(); + //Check if expired + $sql = "SELECT TIMESTAMPDIFF(MINUTE, timestampOfSignInCode, NOW()) AS minutes + FROM user_device + WHERE email='$emailaddress' AND deviceName='$deviceName' + ORDER BY timestampOfSignInCode DESC + LIMIT 1 + "; -//Assume success and it already exists + $row = Base_Model::runQuery($conn,$sql)->fetch_assoc(); + //Assume it already exists + $existed = true; + $hasFullName = false; + $reason = ""; -$success = 1; -$existed = 1; -$hasFullName = 0; -$reason = ""; + // throw new Exception("Code expired"); //DELETE ME!!! -//Check if it took longer than 10 minutes to enter the code -if ($row['minutes'] > 10){ - $success = 0; - $reason = "Code expired"; -}else{ + //Check if it took longer than 10 minutes to enter the code + if ($row['minutes'] > 10){ + throw new Exception("Code expired"); + } + + //Only the most recent one $sql = "SELECT signInCode AS nineCode FROM user_device - WHERE email='$emailaddress' AND deviceName='$deviceName'"; - $result = $conn->query($sql); - $row = $result->fetch_assoc(); + WHERE email='$emailaddress' AND deviceName='$deviceName' + ORDER BY timestampOfSignInCode DESC + LIMIT 1 + "; + $row = Base_Model::runQuery($conn,$sql)->fetch_assoc(); if ($row["nineCode"] != $nineCode){ - $success = 0; - $reason = "Invalid Code"; - - }else{ + throw new Exception("Invalid Code"); + } //Valid code and not expired //Update signedIn on user_device table $sql = "UPDATE user_device SET signedIn='1' WHERE email='$emailaddress' AND deviceName='$deviceName'"; - $result = $conn->query($sql); + Base_Model::runQuery($conn,$sql); //Test if it's a new account - $sql = "SELECT firstName,lastName, screenName FROM user WHERE email='$emailaddress' "; - $result = $conn->query($sql); - $row = $result->fetch_assoc(); + $row = Base_Model::runQuery($conn,$sql)->fetch_assoc(); if ($row["firstName"] != "" && $row["lastName"] != ""){ - $hasFullName = 1; + $hasFullName = true; } //Only new accounts won't have a screen name if ($row["screenName"] === null){ // New Account! - $existed = 0; + $existed = false; // Make a new profile // Random screen name @@ -83,28 +87,41 @@ $profile_pic = $profile_pics[$randomNumber]; // Store screen name and profile picture $sql = "UPDATE user SET screenName='$screen_name',profilePicture='$profile_pic' WHERE email='$emailaddress' "; - $result = $conn->query($sql); - } - - - - } - - -} + Base_Model::runQuery($conn,$sql); + } + $sql = "SELECT c.courseId + FROM course AS c + LEFT JOIN user AS u + ON u.userId = c.portfolioCourseForUserId + WHERE u.email = '$emailaddress'"; + $result = Base_Model::runQuery($conn,$sql); + $row = $result->fetch_assoc(); + $portfolioCourseId = "not_created"; + if ($result->num_rows > 0) { + $portfolioCourseId = $row['courseId']; + } $response_arr = array( - "success" => $success, + "success" => true, "existed" => $existed, "hasFullName" => $hasFullName, - "reason" => $reason, + "portfolioCourseId" => $portfolioCourseId, ); http_response_code(200); -// make it json format -echo json_encode($response_arr); -$conn->close(); +} catch (Exception $e) { + $response_arr = [ + 'success' => false, + 'message' => $e->getMessage(), + ]; + http_response_code(400); +} finally { + // make it json format + echo json_encode($response_arr); + $conn->close(); +} +?> diff --git a/public/api/getQuickCheckSignedIn.php b/public/api/getQuickCheckSignedIn.php index 56afe122f0..3fac4436e1 100644 --- a/public/api/getQuickCheckSignedIn.php +++ b/public/api/getQuickCheckSignedIn.php @@ -5,14 +5,18 @@ header('Access-Control-Allow-Credentials: true'); header('Content-Type: application/json'); -//ONLY TESTING IF THE SECURE SIGNED IN (JWT) COOKIE EXISTS -$signedIn = false; - +$secureCookieExists = false; if ($_COOKIE["JWT"] != NULL){ - $signedIn = true; + $secureCookieExists = true; +} +$unsecureCookieExists = false; +if ($_COOKIE["JWT_JS"] != NULL){ + $unsecureCookieExists = true; } -$response_arr = ['signedIn' => $signedIn]; +$response_arr = ['secureCookieExists' => $secureCookieExists, +'unsecureCookieExists' => $unsecureCookieExists, +]; // set response code - 200 OK http_response_code(200); diff --git a/public/api/jwt.php b/public/api/jwt.php index 7114779b3d..9f7e63f1e0 100644 --- a/public/api/jwt.php +++ b/public/api/jwt.php @@ -1,11 +1,6 @@ query($sql); -$row = $result->fetch_assoc(); + $row = Base_Model::runQuery($conn,$sql)->fetch_assoc(); -//Check if it took longer than 10 minutes to enter the code -if ($row['minutes'] > 10) { - echo 'Code expired'; -} else { - $sql = "SELECT signInCode AS nineCode, userId - FROM user_device - WHERE email='$emailaddress' AND deviceName='$deviceName'"; - $result = $conn->query($sql); - $row = $result->fetch_assoc(); + //Check if it took longer than 10 minutes to enter the code + if ($row['minutes'] > 10) { + throw new Exception("Code expired."); + } + $sql = "SELECT signInCode AS nineCode,userId + FROM user_device + WHERE email='$emailaddress' AND deviceName='$deviceName' + ORDER BY timestampOfSignInCode DESC + LIMIT 1"; + $row = Base_Model::runQuery($conn,$sql)->fetch_assoc(); $userId = $row['userId']; if ($row['nineCode'] != $nineCode) { - echo 'Invalid Code'; - } else { - //Valid code and not expired - http_response_code(200); + throw new Exception("Invalid Code."); + } + //Valid code and not expired + http_response_code(200); - $expirationTime = 0; - if ($stay == 1) { - $expirationTime = 2147483647; - } + $expirationTime = 0; + if ($stay == 1) { + $expirationTime = 2147483647; + } - $payload = [ - // "email" => $emailaddress, - 'userId' => $userId, - 'deviceName' => $deviceName, - // "expires" => $expirationTime - ]; - $jwt = JWT::encode($payload, $key); + $payload = [ + // "email" => $emailaddress, + 'userId' => $userId, + 'deviceName' => $deviceName, + // "expires" => $expirationTime + ]; + $jwt = JWT::encode($payload, $key); - $sql = "UPDATE user_device - SET signedIn = '1' - WHERE userId='$userId' AND deviceName='$deviceName'"; - $result = $conn->query($sql); + $sql = "UPDATE user_device + SET signedIn = '1' + WHERE userId='$userId' AND deviceName='$deviceName'"; + Base_Model::runQuery($conn,$sql); - $value = $jwt; + $value = $jwt; - $path = '/'; - //$domain = $ini_array['dbhost']; - $domain = $_SERVER["SERVER_NAME"]; - if ($domain == 'apache'){$domain = 'localhost';} - $isSecure = true; - if ($domain == 'apache') { - $domain = 'localhost'; - } - if ($domain == 'localhost') { - $isSecure = false; - } - $isHttpOnly = true; - setcookie( - 'JWT', - $value, - $expirationTime, - $path, - $domain, - $isSecure, - $isHttpOnly - ); - setcookie( - 'JWT_JS', - 1, - $expirationTime, - $path, - $domain, - $isSecure, - false - ); - header('Location: /signin'); //needs to store profile into localstorage + $path = '/'; + //$domain = $ini_array['dbhost']; + $domain = $_SERVER["SERVER_NAME"]; + if ($domain == 'apache'){$domain = 'localhost';} + $isSecure = true; + if ($domain == 'apache') { + $domain = 'localhost'; + } + if ($domain == 'localhost') { + $isSecure = false; + } + $isHttpOnly = true; + setcookie( + 'JWT', + $value, + $expirationTime, + $path, + $domain, + $isSecure, + $isHttpOnly + ); + setcookie( + 'JWT_JS', + 1, + $expirationTime, + $path, + $domain, + $isSecure, + false + ); - // setcookie("JWT", $value, array("expires"=>$expirationTime, "path"=>$path, "domain"=>$domain, "secure"=>$isSecure, "httponly"=>$isHttpOnly, "samesite"=>"strict")); - // setcookie("JWT_JS", 1, array("expires"=>$expirationTime, "path"=>$path, "domain"=>$domain, "secure"=>$isSecure, "httponly"=>false, "samesite"=>"strict")); + $response_arr = [ + 'success' => true, + ]; - // if ($newAccount == 1){ - // // header("Location: /accountsettings"); - // header("Location: /library"); - // }else{ - // // header("Location: /dashboard"); - // header("Location: /course"); - // } - } + http_response_code(200); + +} catch (Exception $e) { + $response_arr = [ + 'success' => false, + 'message' => $e->getMessage(), + ]; + http_response_code(400); + +} finally { + // make it json format + echo json_encode($response_arr); + $conn->close(); } -$conn->close(); +?> diff --git a/public/api/saveUsersName.php b/public/api/saveUsersName.php index 06a704848e..0f1fbbabe8 100644 --- a/public/api/saveUsersName.php +++ b/public/api/saveUsersName.php @@ -6,34 +6,39 @@ header('Content-Type: application/json'); include "db_connection.php"; - - -$success = true; -$message = ''; - +include "baseModel.php"; $email = mysqli_real_escape_string($conn,$_REQUEST["email"]); $firstName = mysqli_real_escape_string($conn,$_REQUEST["firstName"]); $lastName = mysqli_real_escape_string($conn,$_REQUEST["lastName"]); - -$sql = " -UPDATE user -SET firstName='$firstName', -lastName='$lastName' -WHERE email='$email' -"; -$conn->query($sql); - -$response_arr = array( - 'success' => $success, - 'message' => $message, -); - -// set response code - 200 OK -http_response_code(200); - -// make it json format -echo json_encode($response_arr); - -$conn->close(); -?> +$response_arr; +try { + Base_Model::checkForRequiredInputs($_REQUEST,["email","firstName","lastName"]); + + $sql = " + UPDATE user + SET firstName='$firstName', + lastName='$lastName' + WHERE email='$email' + "; + Base_Model::runQuery($conn,$sql); + + $response_arr = array( + 'success' => true, + ); + + http_response_code(200); + +} catch (Exception $e) { + $response_arr = [ + 'success' => false, + 'message' => $e->getMessage(), + ]; + http_response_code(400); + +} finally { + // make it json format + echo json_encode($response_arr); + $conn->close(); +} +?> \ No newline at end of file diff --git a/public/api/sendSignInEmail.php b/public/api/sendSignInEmail.php index 3e8ccba30e..d2e903d3e1 100644 --- a/public/api/sendSignInEmail.php +++ b/public/api/sendSignInEmail.php @@ -6,88 +6,120 @@ header('Content-Type: application/json'); include "db_connection.php"; +include "baseModel.php"; $emailaddress = mysqli_real_escape_string($conn,$_REQUEST["emailaddress"]); +$deviceName = mysqli_real_escape_string($conn,$_REQUEST["deviceName"]); -$deviceNames = include "deviceNames.php"; - -//Nine digit random number -$signInCode = rand(100000000,999999999); - -$sql = "SELECT email, userId -FROM user -WHERE email='$emailaddress'"; - -$result = $conn->query($sql); - -if ($result->num_rows > 0){ - //Already have an email with this account - $row = $result->fetch_assoc(); - $user_id = $row['userId']; - //unique deviceName - //Remove device names which are already in use - $sql = " - SELECT deviceName - FROM user_device - WHERE userId='$user_id' - "; - - $result = $conn->query($sql); - $used_deviceNames = array(); - while($row = $result->fetch_assoc()){ - array_push($used_deviceNames,$row['deviceName']); - } - $deviceNames = array_values(array_diff($deviceNames,$used_deviceNames)); - if (count($deviceNames) < 1){ - //Ran out of device names - $deviceName = include 'randomId.php'; + +$response_arr; +try { + Base_Model::checkForRequiredInputs($_REQUEST,["emailaddress"]); + + //Create a nine digit random number + $signInCode = rand(100000000,999999999); + + //Do we have an account with this email? + $sql = "SELECT email, userId + FROM user + WHERE email='$emailaddress'"; + + $userEmailArray = Base_Model::queryFetchAssoc($conn, $sql); + if (count($userEmailArray) < 1){ + //We need an account created + $user_id = include "randomId.php"; + $sql = "INSERT INTO user (userId,email) VALUE ('$user_id','$emailaddress')"; + Base_Model::runQuery($conn,$sql); }else{ - //Pick from what is left - $randomNumber = rand(0,(count($deviceNames) - 1)); - $deviceName = $deviceNames[$randomNumber]; + $user_id = $userEmailArray['userId'][0]; } + if (array_key_exists("deviceName",$_REQUEST)){ + //Already have a device name + //Just update the signInCode and timestampOfSignInCode + //of the latest entry of that device name + $sql = "UPDATE user_device + SET signInCode = '$signInCode', timestampOfSignInCode = NOW() + WHERE (userId, email, deviceName, timestampOfSignInCode) = ( + SELECT userId, email, deviceName, MAX(timestampOfSignInCode) + FROM ( + SELECT * FROM user_device + ) AS temp + WHERE userId = '$user_id' AND email = '$emailaddress' AND deviceName = '$deviceName' + ) + "; + Base_Model::runQuery($conn,$sql); -}else{ - //New email address - $user_id = include "randomId.php"; - $sql = "INSERT INTO user (userId,email) VALUE ('$user_id','$emailaddress')"; - $result = $conn->query($sql); - //Define device name - $randomNumber = rand(0,(count($deviceNames) - 1)); - $deviceName = $deviceNames[$randomNumber]; -} -$sql = "INSERT INTO user_device (userId,email,signInCode,timestampOfSignInCode, deviceName) - VALUE ('$user_id','$emailaddress','$signInCode',NOW(),'$deviceName')"; - $result = $conn->query($sql); + }else{ + //Select a device name + $deviceNames = include "deviceNames.php"; + //In order to maintain unique deviceNames + //remove device names which are already in use + $sql = " + SELECT deviceName + FROM user_device + WHERE userId='$user_id' + AND signedIn=1 + "; + + $devicesArray = Base_Model::queryFetchAssoc($conn, $sql); + $used_deviceNames = $devicesArray['deviceName'] != null ? $devicesArray['deviceName'] : []; + + $deviceNames = array_values(array_diff($deviceNames,$used_deviceNames)); + if (count($deviceNames) < 1){ + //Ran out of device names + $deviceName = include 'randomId.php'; + }else{ + //Pick from what is left + $randomNumber = rand(0,(count($deviceNames) - 1)); + $deviceName = $deviceNames[$randomNumber]; + } + + //Insert the device with the code so a user with the right code can sign in + $sql = "INSERT INTO user_device (userId,email,signInCode,timestampOfSignInCode, deviceName) + VALUE ('$user_id','$emailaddress','$signInCode',NOW(),'$deviceName')"; + Base_Model::runQuery($conn,$sql); + } + -// Generate and modify email content -$htmlContent = file_get_contents("signInEmail.html"); -$htmlContent = str_replace(array("deviceName", "signInCode"), array($deviceName, $signInCode), $htmlContent); + // Generate and modify email content + $htmlContent = file_get_contents("signInEmail.html"); + $htmlContent = str_replace(array("signInCode"), array($signInCode), $htmlContent); -$from = 'noreply@doenet.org'; -$fromName = 'Doenet Accounts'; -$subject = 'Sign-In Request'; + $from = 'noreply@doenet.org'; + $fromName = 'Doenet Accounts'; + $subject = 'Sign-In Request'; -// Set content-type header for sending HTML email -$headers = "MIME-Version: 1.0" . "\r\n"; -$headers .= "Content-type:text/html;charset=UTF-8" . "\r\n"; -$headers .= 'From: '.$fromName.'<'.$from.'>' . "\r\n"; + // Set content-type header for sending HTML email + $headers = "MIME-Version: 1.0" . "\r\n"; + $headers .= "Content-type:text/html;charset=UTF-8" . "\r\n"; + $headers .= 'From: '.$fromName.'<'.$from.'>' . "\r\n"; -//SEND EMAIL WITH CODE HERE -mail($emailaddress,$subject,$htmlContent, $headers); + //SEND EMAIL WITH CODE HERE + $mailSuccess = mail($emailaddress,$subject,$htmlContent, $headers); -$response_arr = array( - "success" => 1, - "deviceName" => $deviceName, - ); + if (!$mailSuccess && $mode != 'development'){ + throw new Exception("Sending Email Failed."); + } -// set response code - 200 OK -http_response_code(200); +$response_arr = [ + 'success' => true, + "deviceName" => $deviceName, + ]; -echo json_encode($response_arr); + http_response_code(200); +} catch (Exception $e) { + $response_arr = [ + 'success' => false, + 'message' => $e->getMessage(), + ]; + http_response_code(400); -$conn->close(); +} finally { + // make it json format + echo json_encode($response_arr); + $conn->close(); +} diff --git a/public/api/signInEmail.html b/public/api/signInEmail.html index 04d0631196..27c70874a7 100644 --- a/public/api/signInEmail.html +++ b/public/api/signInEmail.html @@ -136,13 +136,10 @@ align="left" >
-
Welcome to Doenet, you've
- requested a sign-in code for
- deviceName.
+
Welcome to Doenet!
- Access code:
+ Sign-in code:
signInCode