From b60c94aa8f3268b89e332d1654d456c6fc3e151b Mon Sep 17 00:00:00 2001 From: Shawn Erquhart Date: Fri, 2 Nov 2018 10:29:11 -0400 Subject: [PATCH] improvement(auth): verbose error message when GitHub repo unavailable (#1831) --- .../netlify-cms-backend-bitbucket/src/API.js | 9 ++++- .../src/implementation.js | 29 ++++++++++----- .../netlify-cms-backend-github/package.json | 1 + .../src/implementation.js | 35 +++++++++++++------ .../src/implementation.js | 31 ++++++++++------ packages/netlify-cms-core/src/actions/auth.js | 1 + .../src/components/UI/Toast.js | 1 + yarn.lock | 4 +++ 8 files changed, 81 insertions(+), 30 deletions(-) diff --git a/packages/netlify-cms-backend-bitbucket/src/API.js b/packages/netlify-cms-backend-bitbucket/src/API.js index 884f7b37..77059ed8 100644 --- a/packages/netlify-cms-backend-bitbucket/src/API.js +++ b/packages/netlify-cms-backend-bitbucket/src/API.js @@ -46,7 +46,14 @@ export default class API { ])(req); user = () => this.request('/user'); - hasWriteAccess = () => this.request(this.repoURL).then(res => res.ok); + + hasWriteAccess = async () => { + const response = await this.request(this.repoURL); + if (response.status === 404) { + throw Error('Repo not found'); + } + return response.ok; + }; isFile = ({ type }) => type === 'commit_file'; processFile = file => ({ diff --git a/packages/netlify-cms-backend-bitbucket/src/implementation.js b/packages/netlify-cms-backend-bitbucket/src/implementation.js index 4febf404..6cee102b 100644 --- a/packages/netlify-cms-backend-bitbucket/src/implementation.js +++ b/packages/netlify-cms-backend-bitbucket/src/implementation.js @@ -1,5 +1,6 @@ import semaphore from 'semaphore'; import { flow, trimStart } from 'lodash'; +import { stripIndent } from 'common-tags'; import { CURSOR_COMPATIBILITY_SYMBOL, filterByPropExtension, @@ -61,7 +62,7 @@ export default class Bitbucket { return this.authenticate(user); } - authenticate(state) { + async authenticate(state) { this.token = state.token; this.refreshToken = state.refresh_token; this.api = new API({ @@ -71,13 +72,25 @@ export default class Bitbucket { api_root: this.api_root, }); - return this.api.user().then(user => - this.api.hasWriteAccess(user).then(isCollab => { - if (!isCollab) - throw new Error('Your BitBucker user account does not have access to this repo.'); - return Object.assign({}, user, { token: state.token, refresh_token: state.refresh_token }); - }), - ); + const user = await this.api.user(); + const isCollab = await this.api.hasWriteAccess(user).catch(error => { + error.message = stripIndent` + Repo "${this.repo}" not found. + + Please ensure the repo information is spelled correctly. + + If the repo is private, make sure you're logged into a Bitbucket account with access. + `; + throw error; + }); + + // Unauthorized user + if (!isCollab) { + throw new Error('Your BitBucket user account does not have access to this repo.'); + } + + // Autorized user + return { ...user, token: state.token, refresh_token: state.refresh_token }; } getRefreshedAccessToken() { diff --git a/packages/netlify-cms-backend-github/package.json b/packages/netlify-cms-backend-github/package.json index 85a72ff3..14e98223 100644 --- a/packages/netlify-cms-backend-github/package.json +++ b/packages/netlify-cms-backend-github/package.json @@ -19,6 +19,7 @@ "build": "cross-env NODE_ENV=production webpack" }, "dependencies": { + "common-tags": "^1.8.0", "js-base64": "^2.4.8", "semaphore": "^1.1.0" }, diff --git a/packages/netlify-cms-backend-github/src/implementation.js b/packages/netlify-cms-backend-github/src/implementation.js index ff0719ca..c870a131 100644 --- a/packages/netlify-cms-backend-github/src/implementation.js +++ b/packages/netlify-cms-backend-github/src/implementation.js @@ -1,5 +1,6 @@ import trimStart from 'lodash/trimStart'; import semaphore from 'semaphore'; +import { stripIndent } from 'common-tags'; import AuthenticationPage from './AuthenticationPage'; import API from './API'; @@ -35,7 +36,7 @@ export default class GitHub { return this.authenticate(user); } - authenticate(state) { + async authenticate(state) { this.token = state.token; this.api = new API({ token: this.token, @@ -45,16 +46,28 @@ export default class GitHub { squash_merges: this.squash_merges, initialWorkflowStatus: this.options.initialWorkflowStatus, }); - return this.api.user().then(user => - this.api.hasWriteAccess().then(isCollab => { - // Unauthorized user - if (!isCollab) - throw new Error('Your GitHub user account does not have access to this repo.'); - // Authorized user - user.token = state.token; - return user; - }), - ); + const user = await this.api.user(); + const isCollab = await this.api.hasWriteAccess().catch(error => { + error.message = stripIndent` + Repo "${this.repo}" not found. + + Please ensure the repo information is spelled correctly. + + If the repo is private, make sure you're logged into a GitHub account with access. + + If your repo is under an organization, ensure the organization has granted access to Netlify + CMS. + `; + throw error; + }); + + // Unauthorized user + if (!isCollab) { + throw new Error('Your GitHub user account does not have access to this repo.'); + } + + // Authorized user + return { ...user, token: state.token }; } logout() { diff --git a/packages/netlify-cms-backend-gitlab/src/implementation.js b/packages/netlify-cms-backend-gitlab/src/implementation.js index cf7e7c9c..74019f47 100644 --- a/packages/netlify-cms-backend-gitlab/src/implementation.js +++ b/packages/netlify-cms-backend-gitlab/src/implementation.js @@ -1,5 +1,6 @@ import trimStart from 'lodash/trimStart'; import semaphore from 'semaphore'; +import { stripIndent } from 'common-tags'; import { CURSOR_COMPATIBILITY_SYMBOL } from 'netlify-cms-lib-util'; import AuthenticationPage from './AuthenticationPage'; import API from './API'; @@ -39,7 +40,7 @@ export default class GitLab { return this.authenticate(user); } - authenticate(state) { + async authenticate(state) { this.token = state.token; this.api = new API({ token: this.token, @@ -47,15 +48,25 @@ export default class GitLab { repo: this.repo, api_root: this.api_root, }); - return this.api.user().then(user => - this.api.hasWriteAccess(user).then(isCollab => { - // Unauthorized user - if (!isCollab) - throw new Error('Your GitLab user account does not have access to this repo.'); - // Authorized user - return Object.assign({}, user, { token: state.token }); - }), - ); + const user = await this.api.user(); + const isCollab = await this.api.hasWriteAccess(user).catch(error => { + error.message = stripIndent` + Repo "${this.repo}" not found. + + Please ensure the repo information is spelled correctly. + + If the repo is private, make sure you're logged into a GitLab account with access. + `; + throw error; + }); + + // Unauthorized user + if (!isCollab) { + throw new Error('Your GitLab user account does not have access to this repo.'); + } + + // Authorized user + return { ...user, token: state.token }; } logout() { diff --git a/packages/netlify-cms-core/src/actions/auth.js b/packages/netlify-cms-core/src/actions/auth.js index 6392b167..bcbb8c15 100644 --- a/packages/netlify-cms-core/src/actions/auth.js +++ b/packages/netlify-cms-core/src/actions/auth.js @@ -76,6 +76,7 @@ export function loginUser(credentials) { dispatch(authenticate(user)); }) .catch(error => { + console.error(error); dispatch( notifSend({ message: `${error.message}`, diff --git a/packages/netlify-cms-core/src/components/UI/Toast.js b/packages/netlify-cms-core/src/components/UI/Toast.js index b2b6247c..15370de2 100644 --- a/packages/netlify-cms-core/src/components/UI/Toast.js +++ b/packages/netlify-cms-core/src/components/UI/Toast.js @@ -9,6 +9,7 @@ injectGlobal` .notif__container { z-index: 10000; + white-space: pre-wrap; } `; diff --git a/yarn.lock b/yarn.lock index b2ae34e2..23f9938c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2618,6 +2618,10 @@ common-tags@1.4.0: dependencies: babel-runtime "^6.18.0" +common-tags@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"