mirror of
https://github.com/Nezumi-2711/onedrive-vercel-index.git
synced 2026-09-22 13:38:45 +00:00
oauth inside main project, with public client id and secret
This commit is contained in:
@@ -179,6 +179,14 @@ const FileListing: FunctionComponent<{ query?: ParsedUrlQuery }> = ({ query }) =
|
|||||||
const { data, error, size, setSize } = useProtectedSWRInfinite(path)
|
const { data, error, size, setSize } = useProtectedSWRInfinite(path)
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
|
console.log(error)
|
||||||
|
|
||||||
|
// If error includes 403 which means the user has not completed initial setup, redirect to OAuth page
|
||||||
|
if (error.message.includes('403')) {
|
||||||
|
router.push('/onedrive-vercel-index-oauth/step-1')
|
||||||
|
return <div></div>
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="dark:bg-gray-900 p-3 bg-white rounded">
|
<div className="dark:bg-gray-900 p-3 bg-white rounded">
|
||||||
{error.message.includes('401') ? <Auth redirect={path} /> : <FourOhFour errorMsg={error.message} />}
|
{error.message.includes('401') ? <Auth redirect={path} /> : <FourOhFour errorMsg={error.message} />}
|
||||||
|
|||||||
+3
-1
@@ -1,7 +1,9 @@
|
|||||||
{
|
{
|
||||||
"clientId": "d87bcc39-1750-4ca0-ad54-f8d0efbb2735",
|
"clientId": "d87bcc39-1750-4ca0-ad54-f8d0efbb2735",
|
||||||
|
"obfuscatedClientSecret": "U2FsdGVkX1830zo3/pFDqaBCVBb37iLw3WnBDWGF9GIB2f4apzv0roemp8Y+iIxI3Ih5ecyukqELQEGzZlYiWg==",
|
||||||
"redirectUri": "http://localhost",
|
"redirectUri": "http://localhost",
|
||||||
"base": "/Public",
|
"base": "/Public",
|
||||||
"authApi": "https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
"authApi": "https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
||||||
"driveApi": "https://graph.microsoft.com/v1.0/me/drive"
|
"driveApi": "https://graph.microsoft.com/v1.0/me/drive",
|
||||||
|
"scope": "Files.Read.All Files.ReadWrite.All offline_access"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
webpack: (config) => {
|
webpack: (config) => {
|
||||||
|
config.resolve.fallback = { fs: false, path: false, stream: false, constants: false };
|
||||||
|
|
||||||
// load worker files as a urls with `file-loader`
|
// load worker files as a urls with `file-loader`
|
||||||
config.module.rules.unshift({
|
config.module.rules.unshift({
|
||||||
test: /pdf\.worker\.(min\.)?js/,
|
test: /pdf\.worker\.(min\.)?js/,
|
||||||
|
|||||||
Generated
+118
-4
@@ -18,6 +18,8 @@
|
|||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
"emoji-regex": "^9.2.2",
|
"emoji-regex": "^9.2.2",
|
||||||
"jszip": "^3.7.1",
|
"jszip": "^3.7.1",
|
||||||
|
"keyv": "^4.0.4",
|
||||||
|
"keyv-file": "^0.2.0",
|
||||||
"next": "^12.0.7",
|
"next": "^12.0.7",
|
||||||
"nextjs-progressbar": "^0.0.13",
|
"nextjs-progressbar": "^0.0.13",
|
||||||
"preview-office-docs": "^1.0.2",
|
"preview-office-docs": "^1.0.2",
|
||||||
@@ -39,6 +41,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/crypto-js": "^4.0.2",
|
"@types/crypto-js": "^4.0.2",
|
||||||
|
"@types/keyv": "^3.1.3",
|
||||||
"@types/prismjs": "^1.16.5",
|
"@types/prismjs": "^1.16.5",
|
||||||
"@types/react": "17.0.11",
|
"@types/react": "17.0.11",
|
||||||
"@types/react-copy-to-clipboard": "^5.0.0",
|
"@types/react-copy-to-clipboard": "^5.0.0",
|
||||||
@@ -1132,6 +1135,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.11.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.11.1.tgz",
|
||||||
"integrity": "sha512-DUlIj2nk0YnJdlWgsFuVKcX27MLW0KbKmGVoUHmFr+74FYYNUDAaj9ZqTADvsbE8rfxuVmSFc7KczYn5Y09ozg=="
|
"integrity": "sha512-DUlIj2nk0YnJdlWgsFuVKcX27MLW0KbKmGVoUHmFr+74FYYNUDAaj9ZqTADvsbE8rfxuVmSFc7KczYn5Y09ozg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/keyv": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/localforage": {
|
"node_modules/@types/localforage": {
|
||||||
"version": "0.0.34",
|
"version": "0.0.34",
|
||||||
"resolved": "https://registry.npmjs.org/@types/localforage/-/localforage-0.0.34.tgz",
|
"resolved": "https://registry.npmjs.org/@types/localforage/-/localforage-0.0.34.tgz",
|
||||||
@@ -3273,6 +3285,16 @@
|
|||||||
"url": "https://www.patreon.com/infusion"
|
"url": "https://www.patreon.com/infusion"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fs-extra": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==",
|
||||||
|
"dependencies": {
|
||||||
|
"graceful-fs": "^4.1.2",
|
||||||
|
"jsonfile": "^4.0.0",
|
||||||
|
"universalify": "^0.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fs.realpath": {
|
"node_modules/fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
@@ -4435,6 +4457,11 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/json-buffer": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
|
||||||
|
},
|
||||||
"node_modules/json-parse-better-errors": {
|
"node_modules/json-parse-better-errors": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
||||||
@@ -4474,6 +4501,14 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jsonfile": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||||
|
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
|
||||||
|
"optionalDependencies": {
|
||||||
|
"graceful-fs": "^4.1.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jsx-ast-utils": {
|
"node_modules/jsx-ast-utils": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz",
|
||||||
@@ -4536,6 +4571,24 @@
|
|||||||
"katex": "cli.js"
|
"katex": "cli.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/keyv": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-vqNHbAc8BBsxk+7QBYLW0Y219rWcClspR6WSeoHYKG5mnsSoOH+BL1pWq02DDCVdvvuUny5rkBlzMRzoqc+GIg==",
|
||||||
|
"dependencies": {
|
||||||
|
"json-buffer": "3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/keyv-file": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/keyv-file/-/keyv-file-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-zUQ11eZRmilEUpV1gJSj8mBAHjyXpleQo1iCS0khb+GFRhiPfwavWgn4eDUKNlOyMZzmExnISl8HE1hNbim0gw==",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.1.1",
|
||||||
|
"fs-extra": "^4.0.1",
|
||||||
|
"tslib": "^1.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/language-subtag-registry": {
|
"node_modules/language-subtag-registry": {
|
||||||
"version": "0.3.21",
|
"version": "0.3.21",
|
||||||
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
|
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
|
||||||
@@ -7390,8 +7443,7 @@
|
|||||||
"node_modules/tslib": {
|
"node_modules/tslib": {
|
||||||
"version": "1.14.1",
|
"version": "1.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/tsutils": {
|
"node_modules/tsutils": {
|
||||||
"version": "3.21.0",
|
"version": "3.21.0",
|
||||||
@@ -7600,6 +7652,14 @@
|
|||||||
"url": "https://opencollective.com/unified"
|
"url": "https://opencollective.com/unified"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/universalify": {
|
||||||
|
"version": "0.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||||
|
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/unpipe": {
|
"node_modules/unpipe": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||||
@@ -8643,6 +8703,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.11.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.11.1.tgz",
|
||||||
"integrity": "sha512-DUlIj2nk0YnJdlWgsFuVKcX27MLW0KbKmGVoUHmFr+74FYYNUDAaj9ZqTADvsbE8rfxuVmSFc7KczYn5Y09ozg=="
|
"integrity": "sha512-DUlIj2nk0YnJdlWgsFuVKcX27MLW0KbKmGVoUHmFr+74FYYNUDAaj9ZqTADvsbE8rfxuVmSFc7KczYn5Y09ozg=="
|
||||||
},
|
},
|
||||||
|
"@types/keyv": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/localforage": {
|
"@types/localforage": {
|
||||||
"version": "0.0.34",
|
"version": "0.0.34",
|
||||||
"resolved": "https://registry.npmjs.org/@types/localforage/-/localforage-0.0.34.tgz",
|
"resolved": "https://registry.npmjs.org/@types/localforage/-/localforage-0.0.34.tgz",
|
||||||
@@ -10308,6 +10377,16 @@
|
|||||||
"integrity": "sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg==",
|
"integrity": "sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"fs-extra": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==",
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "^4.1.2",
|
||||||
|
"jsonfile": "^4.0.0",
|
||||||
|
"universalify": "^0.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"fs.realpath": {
|
"fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
@@ -11107,6 +11186,11 @@
|
|||||||
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
|
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"json-buffer": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
|
||||||
|
},
|
||||||
"json-parse-better-errors": {
|
"json-parse-better-errors": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
||||||
@@ -11140,6 +11224,14 @@
|
|||||||
"minimist": "^1.2.5"
|
"minimist": "^1.2.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"jsonfile": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||||
|
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "^4.1.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"jsx-ast-utils": {
|
"jsx-ast-utils": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz",
|
||||||
@@ -11198,6 +11290,24 @@
|
|||||||
"commander": "^6.0.0"
|
"commander": "^6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"keyv": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-vqNHbAc8BBsxk+7QBYLW0Y219rWcClspR6WSeoHYKG5mnsSoOH+BL1pWq02DDCVdvvuUny5rkBlzMRzoqc+GIg==",
|
||||||
|
"requires": {
|
||||||
|
"json-buffer": "3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"keyv-file": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/keyv-file/-/keyv-file-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-zUQ11eZRmilEUpV1gJSj8mBAHjyXpleQo1iCS0khb+GFRhiPfwavWgn4eDUKNlOyMZzmExnISl8HE1hNbim0gw==",
|
||||||
|
"requires": {
|
||||||
|
"debug": "^4.1.1",
|
||||||
|
"fs-extra": "^4.0.1",
|
||||||
|
"tslib": "^1.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"language-subtag-registry": {
|
"language-subtag-registry": {
|
||||||
"version": "0.3.21",
|
"version": "0.3.21",
|
||||||
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
|
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
|
||||||
@@ -13341,8 +13451,7 @@
|
|||||||
"tslib": {
|
"tslib": {
|
||||||
"version": "1.14.1",
|
"version": "1.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"tsutils": {
|
"tsutils": {
|
||||||
"version": "3.21.0",
|
"version": "3.21.0",
|
||||||
@@ -13484,6 +13593,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"universalify": {
|
||||||
|
"version": "0.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||||
|
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
|
||||||
|
},
|
||||||
"unpipe": {
|
"unpipe": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
"emoji-regex": "^9.2.2",
|
"emoji-regex": "^9.2.2",
|
||||||
"jszip": "^3.7.1",
|
"jszip": "^3.7.1",
|
||||||
|
"keyv": "^4.0.4",
|
||||||
|
"keyv-file": "^0.2.0",
|
||||||
"next": "^12.0.7",
|
"next": "^12.0.7",
|
||||||
"nextjs-progressbar": "^0.0.13",
|
"nextjs-progressbar": "^0.0.13",
|
||||||
"preview-office-docs": "^1.0.2",
|
"preview-office-docs": "^1.0.2",
|
||||||
@@ -40,6 +42,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/crypto-js": "^4.0.2",
|
"@types/crypto-js": "^4.0.2",
|
||||||
|
"@types/keyv": "^3.1.3",
|
||||||
"@types/prismjs": "^1.16.5",
|
"@types/prismjs": "^1.16.5",
|
||||||
"@types/react": "17.0.11",
|
"@types/react": "17.0.11",
|
||||||
"@types/react-copy-to-clipboard": "^5.0.0",
|
"@types/react-copy-to-clipboard": "^5.0.0",
|
||||||
|
|||||||
+11
-1
@@ -20,6 +20,7 @@ import {
|
|||||||
faArrowAltCircleDown,
|
faArrowAltCircleDown,
|
||||||
faTrashAlt,
|
faTrashAlt,
|
||||||
faEnvelope,
|
faEnvelope,
|
||||||
|
faCheckCircle,
|
||||||
} from '@fortawesome/free-regular-svg-icons'
|
} from '@fortawesome/free-regular-svg-icons'
|
||||||
import {
|
import {
|
||||||
faPlus,
|
faPlus,
|
||||||
@@ -36,6 +37,10 @@ import {
|
|||||||
faSignOutAlt,
|
faSignOutAlt,
|
||||||
faCloud,
|
faCloud,
|
||||||
faChevronCircleDown,
|
faChevronCircleDown,
|
||||||
|
faExternalLinkAlt,
|
||||||
|
faExclamationCircle,
|
||||||
|
faExclamationTriangle,
|
||||||
|
faHome,
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
import * as Icons from '@fortawesome/free-brands-svg-icons'
|
import * as Icons from '@fortawesome/free-brands-svg-icons'
|
||||||
|
|
||||||
@@ -78,7 +83,12 @@ library.add(
|
|||||||
faEnvelope,
|
faEnvelope,
|
||||||
faCloud,
|
faCloud,
|
||||||
faChevronCircleDown,
|
faChevronCircleDown,
|
||||||
...iconList,
|
faExternalLinkAlt,
|
||||||
|
faExclamationCircle,
|
||||||
|
faExclamationTriangle,
|
||||||
|
faHome,
|
||||||
|
faCheckCircle,
|
||||||
|
...iconList
|
||||||
)
|
)
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }: AppProps) {
|
function MyApp({ Component, pageProps }: AppProps) {
|
||||||
|
|||||||
+32
-13
@@ -1,9 +1,13 @@
|
|||||||
import axios from 'axios'
|
|
||||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
|
||||||
import { posix as pathPosix } from 'path'
|
import { posix as pathPosix } from 'path'
|
||||||
|
|
||||||
|
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||||
|
import axios from 'axios'
|
||||||
|
import Keyv from 'keyv'
|
||||||
|
import { KeyvFile } from 'keyv-file'
|
||||||
|
|
||||||
import apiConfig from '../../config/api.json'
|
import apiConfig from '../../config/api.json'
|
||||||
import siteConfig from '../../config/site.json'
|
import siteConfig from '../../config/site.json'
|
||||||
|
import { revealObfuscatedToken } from '../../utils/accessTokenHandler'
|
||||||
import { compareHashedToken } from '../../utils/protectedRouteHandler'
|
import { compareHashedToken } from '../../utils/protectedRouteHandler'
|
||||||
|
|
||||||
const basePath = pathPosix.resolve('/', apiConfig.base)
|
const basePath = pathPosix.resolve('/', apiConfig.base)
|
||||||
@@ -16,19 +20,28 @@ const encodePath = (path: string) => {
|
|||||||
return `:${encodeURIComponent(encodedPath)}`
|
return `:${encodeURIComponent(encodedPath)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const clientSecret = revealObfuscatedToken(apiConfig.obfuscatedClientSecret)
|
||||||
|
|
||||||
// Store access token in memory, cuz Vercel doesn't provide key-value storage natively
|
// Store access token in memory, cuz Vercel doesn't provide key-value storage natively
|
||||||
let _access_token = ''
|
let _access_token = ''
|
||||||
|
let _refresh_token = ''
|
||||||
const getAccessToken = async () => {
|
const getAccessToken = async () => {
|
||||||
if (_access_token) {
|
if (_access_token) {
|
||||||
console.log('Fetch token from memory.')
|
console.log('Fetch access token from memory.')
|
||||||
return _access_token
|
return _access_token
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return if refresh_token is empty
|
||||||
|
if (!_refresh_token) {
|
||||||
|
console.log('No refresh token, return empty access token.')
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
const body = new URLSearchParams()
|
const body = new URLSearchParams()
|
||||||
body.append('client_id', apiConfig.clientId)
|
body.append('client_id', apiConfig.clientId)
|
||||||
body.append('redirect_uri', apiConfig.redirectUri)
|
body.append('redirect_uri', apiConfig.redirectUri)
|
||||||
body.append('client_secret', process.env.CLIENT_SECRET ? process.env.CLIENT_SECRET : '')
|
body.append('client_secret', clientSecret)
|
||||||
body.append('refresh_token', process.env.REFRESH_TOKEN ? process.env.REFRESH_TOKEN : '')
|
body.append('refresh_token', _refresh_token)
|
||||||
body.append('grant_type', 'refresh_token')
|
body.append('grant_type', 'refresh_token')
|
||||||
|
|
||||||
const resp = await axios.post(apiConfig.authApi, body, {
|
const resp = await axios.post(apiConfig.authApi, body, {
|
||||||
@@ -45,14 +58,26 @@ const getAccessToken = async () => {
|
|||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
const { path = '/', raw = false, next = '' } = req.query
|
const { path = '/', raw = false, next = '' } = req.query
|
||||||
|
|
||||||
|
// Sometimes the path parameter is defaulted to '[...path]' which we need to handle
|
||||||
if (path === '[...path]') {
|
if (path === '[...path]') {
|
||||||
res.status(400).json({ error: 'No path specified.' })
|
res.status(400).json({ error: 'No path specified.' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// If the path is not a valid path, return 400
|
||||||
|
if (typeof path !== 'string') {
|
||||||
|
res.status(400).json({ error: 'Path query invalid.' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof path === 'string') {
|
|
||||||
const accessToken = await getAccessToken()
|
const accessToken = await getAccessToken()
|
||||||
|
|
||||||
|
// Return error 403 if access_token is empty
|
||||||
|
if (!accessToken) {
|
||||||
|
res.status(403).json({ error: 'No access token.' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Handle authentication through .password
|
// Handle authentication through .password
|
||||||
const protectedRoutes = siteConfig.protectedRoutes
|
const protectedRoutes = siteConfig.protectedRoutes
|
||||||
let authTokenPath = ''
|
let authTokenPath = ''
|
||||||
@@ -147,9 +172,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Extract next page token from full @odata.nextLink
|
// Extract next page token from full @odata.nextLink
|
||||||
const nextPage = folderData['@odata.nextLink']
|
const nextPage = folderData['@odata.nextLink'] ? folderData['@odata.nextLink'].match(/&\$skiptoken=(.+)/i)[1] : null
|
||||||
? folderData['@odata.nextLink'].match(/&\$skiptoken=(.+)/i)[1]
|
|
||||||
: null
|
|
||||||
|
|
||||||
// Return paging token if specified
|
// Return paging token if specified
|
||||||
if (nextPage) {
|
if (nextPage) {
|
||||||
@@ -161,8 +184,4 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
}
|
}
|
||||||
res.status(200).json({ file: identityData })
|
res.status(200).json({ file: identityData })
|
||||||
return
|
return
|
||||||
}
|
|
||||||
|
|
||||||
res.status(404).json({ error: 'Path query invalid.' })
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
import Head from 'next/head'
|
||||||
|
import router from 'next/router'
|
||||||
|
|
||||||
|
import siteConfig from '../../config/site.json'
|
||||||
|
import apiConfig from '../../config/api.json'
|
||||||
|
import Navbar from '../../components/Navbar'
|
||||||
|
import Footer from '../../components/Footer'
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
|
|
||||||
|
export default function OAuthStep1() {
|
||||||
|
return (
|
||||||
|
<div className="dark:bg-gray-900 flex flex-col items-center justify-center min-h-screen bg-white">
|
||||||
|
<Head>
|
||||||
|
<title>{`OAuth Step 1 - ${siteConfig.title}`}</title>
|
||||||
|
</Head>
|
||||||
|
|
||||||
|
<main className="bg-gray-50 dark:bg-gray-800 flex flex-col flex-1 w-full">
|
||||||
|
<Navbar />
|
||||||
|
|
||||||
|
<div className="w-full max-w-5xl p-4 mx-auto">
|
||||||
|
<div className="dark:bg-gray-900 dark:text-gray-100 bg-white rounded p-3">
|
||||||
|
<h3 className="font-medium text-xl mb-4">Welcome to your new onedrive-vercel-index 🎉</h3>
|
||||||
|
|
||||||
|
<p className="py-1">
|
||||||
|
Authorisation is required as no valid{' '}
|
||||||
|
<code className="text-sm font-mono underline decoration-wavy decoration-pink-600">access_token</code> or{' '}
|
||||||
|
<code className="text-sm font-mono underline decoration-wavy decoration-green-600">refresh_token</code> is
|
||||||
|
present on this deployed instance.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 className="font-medium text-lg mt-4 mb-2">Step 1: Preparations</h3>
|
||||||
|
<p className="py-1">
|
||||||
|
Check the following configurations (especially <code className="text-sm font-mono">client_id</code> and{' '}
|
||||||
|
<code className="text-sm font-mono">client_secret</code> (obfuscated)) and see if they match the official
|
||||||
|
ones specified in the documentation of{' '}
|
||||||
|
<a
|
||||||
|
href="https://github.com/spencerwooo/onedrive-vercel-index"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="hover:underline text-blue-600 dark:text-blue-500"
|
||||||
|
>
|
||||||
|
onedrive-vercel-index
|
||||||
|
</a>{' '}
|
||||||
|
before proceeding with authorising this application with your own Microsoft account.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="overflow-hidden my-4">
|
||||||
|
<table className="table-auto min-w-full">
|
||||||
|
<tbody>
|
||||||
|
<tr className="bg-white border-y dark:bg-gray-900 dark:border-gray-700">
|
||||||
|
<td className="bg-gray-50 dark:bg-gray-800 py-1 px-3 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400">
|
||||||
|
CLIENT_ID
|
||||||
|
</td>
|
||||||
|
<td className="py-1 px-3 text-gray-500 whitespace-nowrap dark:text-gray-400">
|
||||||
|
<code className="text-sm font-mono">{apiConfig.clientId}</code>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr className="bg-white border-y dark:bg-gray-900 dark:border-gray-700">
|
||||||
|
<td className="bg-gray-50 dark:bg-gray-800 py-1 px-3 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400">
|
||||||
|
CLIENT_SECRET*
|
||||||
|
</td>
|
||||||
|
<td className="py-1 px-3 text-gray-500 whitespace-nowrap dark:text-gray-400">
|
||||||
|
<code className="text-sm font-mono">{apiConfig.obfuscatedClientSecret}</code>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr className="bg-white border-y dark:bg-gray-900 dark:border-gray-700">
|
||||||
|
<td className="bg-gray-50 dark:bg-gray-800 py-1 px-3 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400">
|
||||||
|
REDIRECT_URI
|
||||||
|
</td>
|
||||||
|
<td className="py-1 px-3 text-gray-500 whitespace-nowrap dark:text-gray-400">
|
||||||
|
<code className="text-sm font-mono">{apiConfig.redirectUri}</code>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr className="bg-white border-y dark:bg-gray-900 dark:border-gray-700">
|
||||||
|
<td className="bg-gray-50 dark:bg-gray-800 py-1 px-3 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400">
|
||||||
|
Auth API URL
|
||||||
|
</td>
|
||||||
|
<td className="py-1 px-3 text-gray-500 whitespace-nowrap dark:text-gray-400">
|
||||||
|
<code className="text-sm font-mono">{apiConfig.authApi}</code>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr className="bg-white border-y dark:bg-gray-900 dark:border-gray-700">
|
||||||
|
<td className="bg-gray-50 dark:bg-gray-800 py-1 px-3 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400">
|
||||||
|
Drive API URL
|
||||||
|
</td>
|
||||||
|
<td className="py-1 px-3 text-gray-500 whitespace-nowrap dark:text-gray-400">
|
||||||
|
<code className="text-sm font-mono">{apiConfig.driveApi}</code>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr className="bg-white border-y dark:bg-gray-900 dark:border-gray-700">
|
||||||
|
<td className="bg-gray-50 dark:bg-gray-800 py-1 px-3 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400">
|
||||||
|
API Scope
|
||||||
|
</td>
|
||||||
|
<td className="py-1 px-3 text-gray-500 whitespace-nowrap dark:text-gray-400">
|
||||||
|
<code className="text-sm font-mono">{apiConfig.scope}</code>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="py-1">
|
||||||
|
<FontAwesomeIcon icon="exclamation-triangle" className="mr-1 text-yellow-400" /> If you see anything
|
||||||
|
missing or incorrect, you need to reconfigure <code className="text-sm font-mono">/config/api.json</code>{' '}
|
||||||
|
and redeploy this instance.
|
||||||
|
</p>
|
||||||
|
<p className="py-1">
|
||||||
|
<FontAwesomeIcon icon="exclamation-triangle" className="mr-1 text-yellow-400" />️ If you are previewing
|
||||||
|
this locally, you would need to reauthorise yourself when you eventually deploy the site on Vercel.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="text-right mb-2 mt-6">
|
||||||
|
<button
|
||||||
|
className="text-white bg-gradient-to-r from-cyan-500 to-blue-500 hover:bg-gradient-to-bl focus:ring-4 focus:ring-cyan-300 dark:focus:ring-cyan-800 font-medium rounded-lg text-sm px-4 py-2.5 text-center"
|
||||||
|
onClick={() => {
|
||||||
|
router.push('/onedrive-vercel-index-oauth/step-2')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>Proceed to OAuth</span> <FontAwesomeIcon icon="arrow-right" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
import Head from 'next/head'
|
||||||
|
import router from 'next/router'
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
|
import siteConfig from '../../config/site.json'
|
||||||
|
import Navbar from '../../components/Navbar'
|
||||||
|
import Footer from '../../components/Footer'
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
|
import { extractAuthCodeFromRedirected, generateAuthorisationUrl } from '../../utils/accessTokenHandler'
|
||||||
|
|
||||||
|
export default function OAuthStep2() {
|
||||||
|
const [oAuthRedirectedUrl, setOAuthRedirectedUrl] = useState('')
|
||||||
|
const [authCode, setAuthCode] = useState('')
|
||||||
|
const oAuthUrl = generateAuthorisationUrl()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="dark:bg-gray-900 flex flex-col items-center justify-center min-h-screen bg-white">
|
||||||
|
<Head>
|
||||||
|
<title>{`OAuth Step 2 - ${siteConfig.title}`}</title>
|
||||||
|
</Head>
|
||||||
|
|
||||||
|
<main className="bg-gray-50 dark:bg-gray-800 flex flex-col flex-1 w-full">
|
||||||
|
<Navbar />
|
||||||
|
|
||||||
|
<div className="w-full max-w-5xl p-4 mx-auto">
|
||||||
|
<div className="dark:bg-gray-900 dark:text-gray-100 bg-white rounded p-3">
|
||||||
|
<h3 className="font-medium text-xl mb-4">Welcome to your new onedrive-vercel-index 🎉</h3>
|
||||||
|
|
||||||
|
<p className="py-1">
|
||||||
|
Authorisation is required as no valid{' '}
|
||||||
|
<code className="text-sm font-mono underline decoration-wavy decoration-pink-600">access_token</code> or{' '}
|
||||||
|
<code className="text-sm font-mono underline decoration-wavy decoration-green-600">refresh_token</code> is
|
||||||
|
present on this deployed instance.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 className="font-medium text-lg mt-4 mb-2">Step 2: Get authorisation code</h3>
|
||||||
|
<p className="py-1">The OAuth URL has been generated for you:</p>
|
||||||
|
<div
|
||||||
|
className="relative my-2 font-mono border border-gray-400/20 rounded text-sm bg-gray-50 dark:bg-gray-800 cursor-pointer hover:opacity-80"
|
||||||
|
onClick={() => {
|
||||||
|
window.open(oAuthUrl)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="absolute top-0 right-0 p-1 opacity-60">
|
||||||
|
<FontAwesomeIcon icon="external-link-alt" />
|
||||||
|
</div>
|
||||||
|
<pre className="p-2 whitespace-pre-wrap overflow-x-auto">
|
||||||
|
<code>{oAuthUrl}</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
<p className="py-1">
|
||||||
|
Click on the link to get the{' '}
|
||||||
|
<b className="underline decoration-wavy decoration-yellow-400">authorisation code</b>. Your browser will
|
||||||
|
open a new tab to Microsoft's account login page. Authenticate with your Microsoft account and copy
|
||||||
|
the redirected URL down below.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<input
|
||||||
|
className={`w-full flex-1 border bg-gray-50 dark:bg-gray-800 dark:text-white focus:ring focus:outline-none p-2 font-mono rounded my-2 font-medium text-sm ${
|
||||||
|
authCode
|
||||||
|
? 'border-green-500/50 focus:ring-green-500/30 dark:focus:ring-green-500/40'
|
||||||
|
: 'border-red-500/50 focus:ring-red-500/30 dark:focus:ring-red-500/40'
|
||||||
|
}`}
|
||||||
|
autoFocus
|
||||||
|
type="text"
|
||||||
|
placeholder="http://localhost/?code=M.R3_BAY.c0..."
|
||||||
|
value={oAuthRedirectedUrl}
|
||||||
|
onChange={e => {
|
||||||
|
setOAuthRedirectedUrl(e.target.value)
|
||||||
|
setAuthCode(extractAuthCodeFromRedirected(e.target.value))
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p className="py-1">The authorisation code extracted is:</p>
|
||||||
|
<p className="my-2 font-mono border border-gray-400/20 rounded text-sm bg-gray-50 dark:bg-gray-800 p-2 opacity-80">
|
||||||
|
{authCode || <span className="animate-pulse">Waiting for code...</span>}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{authCode
|
||||||
|
? '✅ You can now proceed onto the next step: requesting your access token and refresh token.'
|
||||||
|
: '❌ No valid code extracted.'}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="text-right mb-2 mt-6">
|
||||||
|
<button
|
||||||
|
className="text-white bg-gradient-to-br from-green-500 to-cyan-400 hover:bg-gradient-to-bl focus:ring-4 focus:ring-green-200 dark:focus:ring-green-800 font-medium rounded-lg text-sm px-4 py-2.5 text-center disabled:cursor-not-allowed disabled:grayscale"
|
||||||
|
disabled={authCode === ''}
|
||||||
|
onClick={() => {
|
||||||
|
router.push({ pathname: '/onedrive-vercel-index-oauth/step-3', query: { authCode } })
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>Get tokens</span> <FontAwesomeIcon icon="arrow-right" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
import Head from 'next/head'
|
||||||
|
import router from 'next/router'
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
|
|
||||||
|
import siteConfig from '../../config/site.json'
|
||||||
|
import Navbar from '../../components/Navbar'
|
||||||
|
import Footer from '../../components/Footer'
|
||||||
|
import { requestTokenWithAuthCode } from '../../utils/accessTokenHandler'
|
||||||
|
|
||||||
|
export default function OAuthStep3({ accessToken, refreshToken, error, description, errorUri }) {
|
||||||
|
return (
|
||||||
|
<div className="dark:bg-gray-900 flex flex-col items-center justify-center min-h-screen bg-white">
|
||||||
|
<Head>
|
||||||
|
<title>{`OAuth Step 3 - ${siteConfig.title}`}</title>
|
||||||
|
</Head>
|
||||||
|
|
||||||
|
<main className="bg-gray-50 dark:bg-gray-800 flex flex-col flex-1 w-full">
|
||||||
|
<Navbar />
|
||||||
|
|
||||||
|
<div className="w-full max-w-5xl p-4 mx-auto">
|
||||||
|
<div className="dark:bg-gray-900 dark:text-gray-100 bg-white rounded p-3">
|
||||||
|
<h3 className="font-medium text-xl mb-4">Welcome to your new onedrive-vercel-index 🎉</h3>
|
||||||
|
|
||||||
|
<p className="py-1">
|
||||||
|
Authorisation is required as no valid{' '}
|
||||||
|
<code className="text-sm font-mono underline decoration-wavy decoration-pink-600">access_token</code> or{' '}
|
||||||
|
<code className="text-sm font-mono underline decoration-wavy decoration-green-600">refresh_token</code> is
|
||||||
|
present on this deployed instance.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 className="font-medium text-lg mt-4 mb-2">Step 3: Get access and refresh tokens</h3>
|
||||||
|
{error ? (
|
||||||
|
<div>
|
||||||
|
<p className="text-red-500 py-1 font-medium">
|
||||||
|
<FontAwesomeIcon icon="exclamation-circle" className="mr-2" />
|
||||||
|
<span>Whoops, looks like we got a problem: {error}.</span>
|
||||||
|
</p>
|
||||||
|
<p className="my-2 font-mono border border-gray-400/20 rounded text-sm bg-gray-50 dark:bg-gray-800 p-2 opacity-80 whitespace-pre-line">
|
||||||
|
{description}
|
||||||
|
</p>
|
||||||
|
{errorUri && (
|
||||||
|
<p>
|
||||||
|
Check out{' '}
|
||||||
|
<a
|
||||||
|
href={errorUri}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="hover:underline text-blue-600 dark:text-blue-500"
|
||||||
|
>
|
||||||
|
Microsoft's official explanation
|
||||||
|
</a>{' '}
|
||||||
|
on the error message.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
<div className="text-right mb-2 mt-6">
|
||||||
|
<button
|
||||||
|
className="text-white bg-gradient-to-br from-red-500 to-orange-400 hover:bg-gradient-to-bl focus:ring-4 focus:ring-red-200 dark:focus:ring-red-800 font-medium rounded-lg text-sm px-4 py-2.5 text-center disabled:cursor-not-allowed disabled:grayscale"
|
||||||
|
onClick={() => {
|
||||||
|
router.push('/onedrive-vercel-index-oauth/step-1')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon="arrow-left" /> <span>Restart</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<p className="py-1 font-medium">Success, the API returned what we needed.</p>
|
||||||
|
<ol className="py-1">
|
||||||
|
{accessToken && (
|
||||||
|
<li>
|
||||||
|
<FontAwesomeIcon icon={['far', 'check-circle']} className="text-green-500" />{' '}
|
||||||
|
<span>
|
||||||
|
Acquired access_token:{' '}
|
||||||
|
<code className="text-sm font-mono opacity-80">{`${accessToken.substring(0, 30)}...`}</code>.
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
{refreshToken && (
|
||||||
|
<li>
|
||||||
|
<FontAwesomeIcon icon={['far', 'check-circle']} className="text-green-500" />{' '}
|
||||||
|
<span>
|
||||||
|
Acquired refresh_token:{' '}
|
||||||
|
<code className="text-sm font-mono opacity-80">{`${refreshToken.substring(0, 50)}...`}</code>.
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p className="py-1">Your onedrive-vercel-index should be up and running. Go back home to find out.</p>
|
||||||
|
|
||||||
|
<div className="text-right mb-2 mt-6">
|
||||||
|
<button
|
||||||
|
className="text-white bg-gradient-to-br from-green-400 via-green-500 to-green-600 hover:bg-gradient-to-bl focus:ring-4 focus:ring-green-200 dark:focus:ring-green-800 font-medium rounded-lg text-sm px-4 py-2.5 text-center disabled:cursor-not-allowed disabled:grayscale"
|
||||||
|
onClick={() => {
|
||||||
|
router.push('/')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon="home" /> <span>Back home</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getServerSideProps({ query }) {
|
||||||
|
const { authCode } = query
|
||||||
|
|
||||||
|
// Return if no auth code is present
|
||||||
|
if (!authCode) {
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
error: 'No auth code present',
|
||||||
|
description: 'Where is the auth code??? Did you follow step 2 you silly donut?',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await requestTokenWithAuthCode(authCode)
|
||||||
|
|
||||||
|
// If error response, return invalid
|
||||||
|
if ('error' in response) {
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
error: response.error,
|
||||||
|
description: response.errorDescription,
|
||||||
|
errorUri: response.errorUri,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { expiryTime, accessToken, refreshToken } = response
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
error: null,
|
||||||
|
expiryTime,
|
||||||
|
accessToken,
|
||||||
|
refreshToken,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-1
@@ -19,7 +19,9 @@ module.exports = {
|
|||||||
indigo: colors.indigo,
|
indigo: colors.indigo,
|
||||||
purple: colors.purple,
|
purple: colors.purple,
|
||||||
pink: colors.pink,
|
pink: colors.pink,
|
||||||
teal: colors.teal
|
teal: colors.teal,
|
||||||
|
cyan: colors.cyan,
|
||||||
|
orange: colors.orange,
|
||||||
},
|
},
|
||||||
extend: {
|
extend: {
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
import CryptoJS from 'crypto-js'
|
||||||
|
import Keyv from 'keyv'
|
||||||
|
import KeyvFile from 'keyv-file'
|
||||||
|
|
||||||
|
import apiConfig from '../config/api.json'
|
||||||
|
|
||||||
|
const AES_SECRET_KEY = 'onedrive-vercel-index'
|
||||||
|
|
||||||
|
export function obfuscateToken(token: string): string {
|
||||||
|
// Encrypt token with AES
|
||||||
|
const encrypted = CryptoJS.AES.encrypt(token, AES_SECRET_KEY)
|
||||||
|
return encrypted.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function revealObfuscatedToken(obfuscated: string): string {
|
||||||
|
// Decrypt SHA256 obfuscated token
|
||||||
|
const decrypted = CryptoJS.AES.decrypt(obfuscated, AES_SECRET_KEY)
|
||||||
|
return decrypted.toString(CryptoJS.enc.Utf8)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateAuthorisationUrl(): string {
|
||||||
|
const { clientId, redirectUri, authApi } = apiConfig
|
||||||
|
const authUrl = authApi.replace('/token', '/authorize')
|
||||||
|
|
||||||
|
// Construct URL parameters for OAuth2
|
||||||
|
const params = new URLSearchParams()
|
||||||
|
params.append('client_id', clientId)
|
||||||
|
params.append('redirect_uri', redirectUri)
|
||||||
|
params.append('response_type', 'code')
|
||||||
|
params.append('scope', 'files.readwrite offline_access')
|
||||||
|
params.append('response_mode', 'query')
|
||||||
|
|
||||||
|
return `${authUrl}?${params.toString()}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function extractAuthCodeFromRedirected(url: string): string {
|
||||||
|
// Return empty string if the url is not the defined redirect uri
|
||||||
|
if (!url.startsWith(apiConfig.redirectUri)) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// New URL search parameter
|
||||||
|
const params = new URLSearchParams(url.split('?')[1])
|
||||||
|
return params.get('code') || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function requestTokenWithAuthCode(
|
||||||
|
code: string
|
||||||
|
): Promise<
|
||||||
|
| { expiryTime: string; accessToken: string; refreshToken: string }
|
||||||
|
| { error: string; errorDescription: string; errorUri: string }
|
||||||
|
> {
|
||||||
|
const { clientId, redirectUri, authApi } = apiConfig
|
||||||
|
const clientSecret = revealObfuscatedToken(apiConfig.obfuscatedClientSecret)
|
||||||
|
|
||||||
|
// Construct URL parameters for OAuth2
|
||||||
|
const params = new URLSearchParams()
|
||||||
|
params.append('client_id', clientId)
|
||||||
|
params.append('redirect_uri', redirectUri)
|
||||||
|
params.append('client_secret', clientSecret)
|
||||||
|
params.append('code', code)
|
||||||
|
params.append('grant_type', 'authorization_code')
|
||||||
|
|
||||||
|
// Request access token
|
||||||
|
return axios
|
||||||
|
.post(authApi, params, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(resp => {
|
||||||
|
const { expires_in, access_token, refresh_token } = resp.data
|
||||||
|
return { expiryTime: expires_in, accessToken: access_token, refreshToken: refresh_token }
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
const { error, error_description, error_uri } = err.response.data
|
||||||
|
return { error, errorDescription: error_description, errorUri: error_uri }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function storeTokens(accessToken: string, refreshToken: string) {
|
||||||
|
// We can safely leverage Vercel's /tmp directory, and persist the tokens with file-system based KV storage
|
||||||
|
const kv = new Keyv({ store: new KeyvFile(), namespace: 'onedrive-vercel-index' })
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user