Skip to content

Commit

Permalink
WIP implementing Gitlab backend
Browse files Browse the repository at this point in the history
- Implement OAuth sign in
- Stub of sync backend
  • Loading branch information
chasecaleb committed Oct 28, 2021
1 parent f315500 commit c71bf71
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 3 deletions.
4 changes: 3 additions & 1 deletion .env.sample
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
REACT_APP_DROPBOX_CLIENT_ID=your_dropbox_client_id
REACT_APP_GOOGLE_DRIVE_API_KEY=your_google_drive_api_key
REACT_APP_GOOGLE_DRIVE_CLIENT_ID=your_google_drive_oauth_client_id
REACT_APP_GOOGLE_DRIVE_CLIENT_ID=your_google_drive_oauth_client_id
REACT_APP_GITLAB_CLIENT_ID=your_gitlab_client_id
REACT_APP_GITLAB_SECRET=your_gitlab_secret
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ tags
npm-debug.log*
yarn-debug.log*
yarn-error.log*
/.log/

*~

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"node": "^12.13.1"
},
"dependencies": {
"@bity/oauth2-auth-code-pkce": "^2.13.0",
"bowser": "^2.11.0",
"classnames": "^2.2.6",
"date-fns": "^2.16.1",
Expand Down
34 changes: 34 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import { setDisappearingLoadingMessage, restoreStaticFile } from './actions/base
import createDropboxSyncBackendClient from './sync_backend_clients/dropbox_sync_backend_client';
import createGoogleDriveSyncBackendClient from './sync_backend_clients/google_drive_sync_backend_client';
import createWebDAVSyncBackendClient from './sync_backend_clients/webdav_sync_backend_client';
import createGitLabSyncBackendClient, {
createGitlabOAuth,
} from './sync_backend_clients/gitlab_sync_backend_client';

import './base.css';

Expand Down Expand Up @@ -80,6 +83,37 @@ export default class App extends PureComponent {
client,
});
break;
case 'GitLab':
const gitlabOAuth = createGitlabOAuth();
if (gitlabOAuth.isAuthorized()) {
client = createGitLabSyncBackendClient(gitlabOAuth);
initialState.syncBackend = Map({
isAuthenticated: true,
client,
});
} else {
gitlabOAuth
.isReturningFromAuthServer()
.then((hasAuthCode) => {
if (hasAuthCode) {
// OAuth client handles persistence, so we just need to fetch a token without
// worrying about storing it ourselves.
gitlabOAuth.getAccessToken().then(() => {
window.location.search = '';
});
} else {
// Edge case: somehow OAuth success redirect occurred but there isn't a code in
// the current location's search params. This /shouldn't/ happen in practice.
alert('An unexpected error occurred, refresh and try again');
throw new Error('Unexpected application state');
}
})
.catch((error) => {
console.log(error);
alert('Failed to sign in with GitLab');
});
}
break;
case 'WebDAV':
client = createWebDAVSyncBackendClient(
getPersistedField('webdavEndpoint'),
Expand Down
4 changes: 4 additions & 0 deletions src/actions/sync_backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ActionCreators } from 'redux-undo';
import { setLoadingMessage, hideLoadingMessage, clearModalStack, setIsLoading } from './base';
import { parseFile, setDirty, setLastSyncAt, setOrgFileErrorMessage } from './org';
import { localStorageAvailable, persistField } from '../util/settings_persister';
import { createGitlabOAuth } from '../sync_backend_clients/gitlab_sync_backend_client';

import { addSeconds } from 'date-fns';

Expand All @@ -20,6 +21,9 @@ export const signOut = () => (dispatch, getState) => {
case 'Google Drive':
gapi.auth2.getAuthInstance().signOut();
break;
case 'GitLab':
createGitlabOAuth().reset();
break;
default:
}

Expand Down
78 changes: 78 additions & 0 deletions src/components/SyncServiceSignIn/gitlab.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 12 additions & 2 deletions src/components/SyncServiceSignIn/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import './stylesheet.css';

import DropboxLogo from './dropbox.svg';
import GoogleDriveLogo from './google_drive.png';
import GitLabLogo from './gitlab.svg';

import { persistField } from '../../util/settings_persister';
import { createGitlabOAuth } from '../../sync_backend_clients/gitlab_sync_backend_client';

import { Dropbox } from 'dropbox';

import _ from 'lodash';

function WebDAVForm() {
Expand Down Expand Up @@ -118,7 +119,7 @@ export default class SyncServiceSignIn extends PureComponent {
constructor(props) {
super(props);

_.bindAll(this, ['handleDropboxClick', 'handleGoogleDriveClick']);
_.bindAll(this, ['handleDropboxClick', 'handleGoogleDriveClick', 'handleGitlabClick']);
}

handleDropboxClick() {
Expand Down Expand Up @@ -160,6 +161,11 @@ export default class SyncServiceSignIn extends PureComponent {
}
}

handleGitlabClick() {
persistField('authenticatedSyncService', 'GitLab');
createGitlabOAuth().fetchAuthorizationCode();
}

render() {
return (
<div className="sync-service-sign-in-container">
Expand All @@ -182,6 +188,10 @@ export default class SyncServiceSignIn extends PureComponent {
<GoogleDriveNote />
</div>

<div className="sync-service-container">
<img src={GitLabLogo} alt="GitLab logo" onClick={this.handleGitlabClick} />
</div>

<div className="sync-service-container">
<WebDAVForm />
</div>
Expand Down
87 changes: 87 additions & 0 deletions src/sync_backend_clients/gitlab_sync_backend_client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* global process */
import { OAuth2AuthCodePKCE } from '@bity/oauth2-auth-code-pkce';
import { isEmpty } from 'lodash';

export const createGitlabOAuth = () =>
new OAuth2AuthCodePKCE({
authorizationUrl: 'https://gitlab.com/oauth/authorize',
tokenUrl: 'https://gitlab.com/oauth/token',
clientId: process.env.REACT_APP_GITLAB_CLIENT_ID,
redirectUrl: window.location.origin,
scopes: ['api'],
extraAuthorizationParams: {
clientSecret: process.env.REACT_APP_GITLAB_SECRET,
},
extraRefreshParams: {
clientSecret: process.env.REACT_APP_GITLAB_SECRET,
},
onAccessTokenExpiry: (refreshToken) => refreshToken(),
onInvalidGrant: (refreshAuthCodeOrToken) => refreshAuthCodeOrToken(),
});

/**
* @param {OAuth2AuthCodePKCE} oauthClient
*/
export default (oauthClient) => {
const decoratedFetch = oauthClient.decorateFetchHTTPClient(fetch);

const isSignedIn = () => new Promise((resolve) => resolve(oauthClient.isAuthorized()));

// FIXME stub
const getDirectoryListing = (path) =>
new Promise((resolve) =>
resolve({
listing: [],
hasMore: false,
})
);

// FIXME stub
const getMoreDirectoryListing = (additionalSyncBackendState) =>
new Promise((resolve) =>
resolve({
listing: [],
hasMore: false,
})
);

// FIXME stub
const updateFile = (path, contents) => new Promise((resolve) => resolve());

// FIXME stub
const createFile = (path, contents) => new Promise((resolve) => resolve());

// FIXME stub
const getFileContentsAndMetadata = (path) =>
new Promise((resolve) =>
resolve({
contents: '* FIXME',
lastModifiedAt: new Date(),
})
);

// FIXME stub
const getFileContents = (path) => {
if (isEmpty(path)) return Promise.reject('No path given');
return new Promise((resolve, reject) =>
getFileContentsAndMetadata(path)
.then(({ contents }) => resolve(contents))
.catch(reject)
);
};

// FIXME stub
const deleteFile = (path) => new Promise((resolve) => resolve());

return {
type: 'Dropbox',
isSignedIn,
getDirectoryListing,
getMoreDirectoryListing,
updateFile,
createFile,
getFileContentsAndMetadata,
getFileContents,
deleteFile,
};
};
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1752,6 +1752,11 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"

"@bity/oauth2-auth-code-pkce@^2.13.0":
version "2.13.0"
resolved "https://registry.yarnpkg.com/@bity/oauth2-auth-code-pkce/-/oauth2-auth-code-pkce-2.13.0.tgz#cee077db75182b01e9b576a52ee408480d39bdc5"
integrity sha512-jAVsbLIVHvo0Lm6sj2t3ltiLbWKvTlkVflHCiV9DRk1w9FBEOjpJD7OJXkeWBY0Vgr+XiGIm80yJa+sa8XpnWQ==

"@cnakazawa/watch@^1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef"
Expand Down

0 comments on commit c71bf71

Please sign in to comment.