diff --git a/package-lock.json b/package-lock.json index 5c8a343..1170e9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@fortawesome/react-fontawesome": "^0.1.14", "@headlessui/react": "^1.4.0", "axios": "^0.21.1", + "crypto-js": "^4.1.1", "emoji-regex": "^9.2.2", "next": "^11.1.0", "preview-office-docs": "^1.0.2", @@ -34,6 +35,7 @@ "use-clipboard-copy": "^0.2.0" }, "devDependencies": { + "@types/crypto-js": "^4.0.2", "@types/prismjs": "^1.16.5", "@types/react": "17.0.11", "@types/react-copy-to-clipboard": "^5.0.0", @@ -443,6 +445,12 @@ "integrity": "sha512-Myxw//kzromB9yWgS8qYGuGVf91oBUUJpNvy5eM50sqvmKLbKjwLxohJnkWGTeeI9v9IBMtPLxz5Gc60FIfvCA==", "dev": true }, + "node_modules/@types/crypto-js": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.0.2.tgz", + "integrity": "sha512-sCVniU+h3GcGqxOmng11BRvf9TfN9yIs8KKjB8C8d75W69cpTfZG80gau9yTx5SxF3gvHGbJhdESzzvnjtf3Og==", + "dev": true + }, "node_modules/@types/hast": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", @@ -506,14 +514,12 @@ "node_modules/@types/prop-types": { "version": "15.7.4", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==", - "dev": true + "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" }, "node_modules/@types/react": { "version": "17.0.11", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.11.tgz", "integrity": "sha512-yFRQbD+whVonItSk7ZzP/L+gPTJVBkL/7shLEF+i9GC/1cV3JmUxEQz6+9ylhUpWSDuqo1N9qEvqS6vTj4USUA==", - "dev": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -560,8 +566,7 @@ "node_modules/@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, "node_modules/@types/unist": { "version": "2.0.6", @@ -1549,6 +1554,11 @@ "node": "*" } }, + "node_modules/crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + }, "node_modules/css-unit-converter": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", @@ -1602,8 +1612,7 @@ "node_modules/csstype": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", - "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==", - "dev": true + "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" }, "node_modules/damerau-levenshtein": { "version": "1.0.7", @@ -5271,7 +5280,6 @@ "version": "8.3.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.6.tgz", "integrity": "sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==", - "dev": true, "dependencies": { "colorette": "^1.2.2", "nanoid": "^3.1.23", @@ -6300,7 +6308,6 @@ "version": "0.6.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -7611,7 +7618,8 @@ "@headlessui/react": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.4.0.tgz", - "integrity": "sha512-C+FmBVF6YGvqcEI5fa2dfVbEaXr2RGR6Kw1E5HXIISIZEfsrH/yuCgsjWw5nlRF9vbCxmQ/EKs64GAdKeb8gCw==" + "integrity": "sha512-C+FmBVF6YGvqcEI5fa2dfVbEaXr2RGR6Kw1E5HXIISIZEfsrH/yuCgsjWw5nlRF9vbCxmQ/EKs64GAdKeb8gCw==", + "requires": {} }, "@napi-rs/triples": { "version": "1.0.3", @@ -7666,7 +7674,8 @@ "@next/react-refresh-utils": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-11.1.0.tgz", - "integrity": "sha512-g5DtFTpLTGa36iy9DuZawtJeitI11gysFGKPQQqy+mNbSFazguArcJ10gAYFlbqpIi4boUamWNI5mAoSPx3kog==" + "integrity": "sha512-g5DtFTpLTGa36iy9DuZawtJeitI11gysFGKPQQqy+mNbSFazguArcJ10gAYFlbqpIi4boUamWNI5mAoSPx3kog==", + "requires": {} }, "@node-rs/helper": { "version": "1.2.1", @@ -7708,6 +7717,12 @@ "integrity": "sha512-Myxw//kzromB9yWgS8qYGuGVf91oBUUJpNvy5eM50sqvmKLbKjwLxohJnkWGTeeI9v9IBMtPLxz5Gc60FIfvCA==", "dev": true }, + "@types/crypto-js": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.0.2.tgz", + "integrity": "sha512-sCVniU+h3GcGqxOmng11BRvf9TfN9yIs8KKjB8C8d75W69cpTfZG80gau9yTx5SxF3gvHGbJhdESzzvnjtf3Og==", + "dev": true + }, "@types/hast": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", @@ -7771,14 +7786,12 @@ "@types/prop-types": { "version": "15.7.4", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==", - "dev": true + "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" }, "@types/react": { "version": "17.0.11", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.11.tgz", "integrity": "sha512-yFRQbD+whVonItSk7ZzP/L+gPTJVBkL/7shLEF+i9GC/1cV3JmUxEQz6+9ylhUpWSDuqo1N9qEvqS6vTj4USUA==", - "dev": true, "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -7825,8 +7838,7 @@ "@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, "@types/unist": { "version": "2.0.6", @@ -7896,7 +7908,8 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true + "dev": true, + "requires": {} }, "acorn-node": { "version": "1.8.2", @@ -7929,7 +7942,8 @@ "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "requires": {} }, "anser": { "version": "1.4.9", @@ -8564,6 +8578,11 @@ "randomfill": "^1.0.3" } }, + "crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + }, "css-unit-converter": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", @@ -8600,8 +8619,7 @@ "csstype": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", - "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==", - "dev": true + "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" }, "damerau-levenshtein": { "version": "1.0.7", @@ -9059,7 +9077,8 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz", "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==", - "dev": true + "dev": true, + "requires": {} }, "eslint-scope": { "version": "5.1.1", @@ -9457,7 +9476,8 @@ "goober": { "version": "2.0.41", "resolved": "https://registry.npmjs.org/goober/-/goober-2.0.41.tgz", - "integrity": "sha512-kwjegMT5018zWydhOQlQneCgCtrKJaPsru7TaBWmTYV0nsMeUrM6L6O8JmNYb9UbPMgWcmtf+9p4Y3oJabIH1A==" + "integrity": "sha512-kwjegMT5018zWydhOQlQneCgCtrKJaPsru7TaBWmTYV0nsMeUrM6L6O8JmNYb9UbPMgWcmtf+9p4Y3oJabIH1A==", + "requires": {} }, "graceful-fs": { "version": "4.2.8", @@ -11347,7 +11367,6 @@ "version": "8.3.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.6.tgz", "integrity": "sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==", - "dev": true, "requires": { "colorette": "^1.2.2", "nanoid": "^3.1.23", @@ -11415,7 +11434,8 @@ "preview-office-docs": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/preview-office-docs/-/preview-office-docs-1.0.2.tgz", - "integrity": "sha512-dVss4jWfVgZJcVskbOPV5ifpFokRYY1ZW54Z6DvwCg/HzNqq8rZw8yVM+nJAFmcFz6Zy7aY9n1/KhPDkm+Ky6Q==" + "integrity": "sha512-dVss4jWfVgZJcVskbOPV5ifpFokRYY1ZW54Z6DvwCg/HzNqq8rZw8yVM+nJAFmcFz6Zy7aY9n1/KhPDkm+Ky6Q==", + "requires": {} }, "prismjs": { "version": "1.24.1", @@ -12080,8 +12100,7 @@ "source-map-js": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", - "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", - "dev": true + "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==" }, "space-separated-tokens": { "version": "1.1.5", @@ -12336,7 +12355,8 @@ "stylis-rule-sheet": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz", - "integrity": "sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw==" + "integrity": "sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw==", + "requires": {} }, "supports-color": { "version": "7.2.0", diff --git a/package.json b/package.json index 78a83dd..20f55e1 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@fortawesome/react-fontawesome": "^0.1.14", "@headlessui/react": "^1.4.0", "axios": "^0.21.1", + "crypto-js": "^4.1.1", "emoji-regex": "^9.2.2", "next": "^11.1.0", "preview-office-docs": "^1.0.2", @@ -36,6 +37,7 @@ "use-clipboard-copy": "^0.2.0" }, "devDependencies": { + "@types/crypto-js": "^4.0.2", "@types/prismjs": "^1.16.5", "@types/react": "17.0.11", "@types/react-copy-to-clipboard": "^5.0.0", diff --git a/pages/api/index.ts b/pages/api/index.ts index 95d7102..a63d42e 100644 --- a/pages/api/index.ts +++ b/pages/api/index.ts @@ -4,6 +4,7 @@ import { posix as pathPosix } from 'path' import apiConfig from '../../config/api.json' import siteConfig from '../../config/site.json' +import { compareHashedToken } from '../../utils/tools' const basePath = pathPosix.resolve('/', apiConfig.base) const encodePath = (path: string) => { @@ -75,11 +76,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const odProtectedToken = await axios.get(token.data['@microsoft.graph.downloadUrl']) // console.log(req.headers['od-protected-token'], odProtectedToken.data.trim()) - if (req.headers['od-protected-token'] !== odProtectedToken.data.trim()) { + if (!compareHashedToken(req.headers['od-protected-token'] as string, odProtectedToken.data)) { res.status(401).json({ error: 'Password required for this folder.' }) return } - } catch (error) { + } catch (error: any) { // Password file not found, fallback to 404 if (error.response.status === 404) { res.status(404).json({ error: "You didn't set a password for your protected folder." }) diff --git a/utils/tools.ts b/utils/tools.ts index 7a9cd7f..5de7921 100644 --- a/utils/tools.ts +++ b/utils/tools.ts @@ -1,4 +1,5 @@ import axios from 'axios' +import sha256 from 'crypto-js/sha256' import useSWR, { cache, Key } from 'swr' import siteConfig from '../config/site.json' @@ -37,10 +38,24 @@ export const useStaleSWR = (url: Key, path: string = '') => { revalidateOnReconnect: true, } - const token = + const storedToken = typeof window !== 'undefined' ? JSON.parse(localStorage.getItem(matchProtectedRoute(path)) as string) : '' + const hashedToken = storedToken ? encryptToken(storedToken) : null - return useSWR([url, token], fetcher, revalidationOptions) + return useSWR([url, hashedToken], fetcher, revalidationOptions) +} + +const encryptToken = (token: string) => { + return sha256(token).toString() +} +/** + * Compares the hash of .password and od-protected-token header + * @param odTokenHeader od-protected-token header (sha256 hashed token) + * @param dotPassword non-hashed .password file + * @returns whether the two hashes are the same + */ +export const compareHashedToken = (odTokenHeader: string, dotPassword: string) => { + return encryptToken(dotPassword.trim()) === odTokenHeader } export const matchProtectedRoute = (route: string) => {