diff --git a/CliClient/app/main.js b/CliClient/app/main.js
index 1a6b64a82..526de9fb7 100644
--- a/CliClient/app/main.js
+++ b/CliClient/app/main.js
@@ -677,27 +677,28 @@ async function synchronizer(syncTarget) {
let fileApi = null;
if (syncTarget == 'onedrive') {
- const CLIENT_ID = 'e09fc0de-c958-424f-83a2-e56a721d331b';
- const CLIENT_SECRET = 'JA3cwsqSGHFtjMwd5XoF5L5';
+ let oneDriveApi = oneDriveApi.instance();
+ // const CLIENT_ID = 'e09fc0de-c958-424f-83a2-e56a721d331b';
+ // const CLIENT_SECRET = 'JA3cwsqSGHFtjMwd5XoF5L5';
- let driver = new FileApiDriverOneDrive(CLIENT_ID, CLIENT_SECRET);
+ //let driver = new FileApiDriverOneDrive(CLIENT_ID, CLIENT_SECRET);
+ let driver = new FileApiDriverOneDrive(oneDriveApi);
let auth = Setting.value('sync.onedrive.auth');
if (auth) {
auth = JSON.parse(auth);
} else {
- //auth = await driver.api().oauthDance(vorpal);
- const oneDriveApiUtils = new OneDriveApiNodeUtils(driver.api());
+ const oneDriveApiUtils = new OneDriveApiNodeUtils(oneDriveApi);
auth = await oneDriveApiUtils.oauthDance(vorpal);
Setting.setValue('sync.onedrive.auth', JSON.stringify(auth));
}
- driver.api().setAuth(auth);
- driver.api().on('authRefreshed', (a) => {
+ //oneDriveApi.setAuth(auth);
+ oneDriveApi.on('authRefreshed', (a) => {
Setting.setValue('sync.onedrive.auth', JSON.stringify(a));
});
- let appDir = await driver.api().appDirectory();
+ let appDir = await oneDriveApi.appDirectory();
logger.info('App dir: ' + appDir);
fileApi = new FileApi(appDir, driver);
fileApi.setLogger(logger);
diff --git a/CliClient/app/onedrive-api-node-utils.js b/CliClient/app/onedrive-api-node-utils.js
index 1ec7c4b3c..fe6bb6b16 100644
--- a/CliClient/app/onedrive-api-node-utils.js
+++ b/CliClient/app/onedrive-api-node-utils.js
@@ -53,35 +53,49 @@ class OneDriveApiNodeUtils {
if (!query.code) return writeResponse(400, '"code" query parameter is missing');
- let body = new FormData();
- body.append('client_id', this.api().clientId());
- body.append('client_secret', this.api().clientSecret());
- body.append('code', query.code ? query.code : '');
- body.append('redirect_uri', 'http://localhost:' + port.toString());
- body.append('grant_type', 'authorization_code');
+ // let body = new FormData();
+ // body.append('client_id', this.api().clientId());
+ // body.append('client_secret', this.api().clientSecret());
+ // body.append('code', query.code ? query.code : '');
+ // body.append('redirect_uri', 'http://localhost:' + port.toString());
+ // body.append('grant_type', 'authorization_code');
- let options = {
- method: 'POST',
- body: body,
- };
+ // let options = {
+ // method: 'POST',
+ // body: body,
+ // };
- fetch(this.api().tokenBaseUrl(), options).then((r) => {
- if (!r.ok) {
- errorMessage = 'Could not retrieve auth code: ' + r.status + ': ' + r.statusText;
- writeResponse(400, errorMessage);
- targetConsole.log('');
- targetConsole.log(errorMessage);
- server.destroy();
- return;
- }
+ // fetch(this.api().tokenBaseUrl(), options).then((r) => {
- return r.json().then((json) => {
- this.api().setAuth(json);
- writeResponse(200, 'The application has been authorised - you may now close this browser tab.');
- targetConsole.log('');
- targetConsole.log('The application has been successfully authorised.');
- server.destroy();
- });
+ // this.api().execTokenRequest(query.code, 'http://localhost:' + port.toString()).then((r) => {
+ // if (!r.ok) {
+ // errorMessage = 'Could not retrieve auth code: ' + r.status + ': ' + r.statusText;
+ // writeResponse(400, errorMessage);
+ // targetConsole.log('');
+ // targetConsole.log(errorMessage);
+ // server.destroy();
+ // return;
+ // }
+
+ // return r.json().then((json) => {
+ // this.api().setAuth(json);
+ // writeResponse(200, 'The application has been authorised - you may now close this browser tab.');
+ // targetConsole.log('');
+ // targetConsole.log('The application has been successfully authorised.');
+ // server.destroy();
+ // });
+ // });
+
+ this.api().execTokenRequest(query.code, 'http://localhost:' + port.toString()).then(() => {
+ writeResponse(200, 'The application has been authorised - you may now close this browser tab.');
+ targetConsole.log('');
+ targetConsole.log('The application has been successfully authorised.');
+ server.destroy();
+ }).catch((error) => {
+ writeResponse(400, error.message);
+ targetConsole.log('');
+ targetConsole.log(error.message);
+ server.destroy();
});
});
diff --git a/ReactNativeClient/lib/components/screen-header.js b/ReactNativeClient/lib/components/screen-header.js
index 50bbb755b..dc3bcd230 100644
--- a/ReactNativeClient/lib/components/screen-header.js
+++ b/ReactNativeClient/lib/components/screen-header.js
@@ -41,6 +41,11 @@ class ScreenHeaderComponent extends Component {
}
menu_synchronize() {
+ this.props.dispatch({
+ type: 'Navigation/NAVIGATE',
+ routeName: 'OneDriveLogin',
+ });
+
// const CLIENT_ID = 'e09fc0de-c958-424f-83a2-e56a721d331b';
// const CLIENT_SECRET = 'JA3cwsqSGHFtjMwd5XoF5L5';
diff --git a/ReactNativeClient/lib/components/screens/onedrive-login.js b/ReactNativeClient/lib/components/screens/onedrive-login.js
new file mode 100644
index 000000000..f192c1f9c
--- /dev/null
+++ b/ReactNativeClient/lib/components/screens/onedrive-login.js
@@ -0,0 +1,90 @@
+import React, { Component } from 'react';
+import { View } from 'react-native';
+import { WebView, Button } from 'react-native';
+import { connect } from 'react-redux'
+import { Log } from 'lib/log.js'
+import { ScreenHeader } from 'lib/components/screen-header.js';
+import { OneDriveApi } from 'lib/onedrive-api.js';
+import { _ } from 'lib/locale.js';
+
+class OneDriveLoginScreenComponent extends React.Component {
+
+ static navigationOptions(options) {
+ return { header: null };
+ }
+
+ constructor() {
+ super();
+ this.state = { webviewUrl: '' };
+ this.authCode_ = null;
+ }
+
+ componentWillMount() {
+ this.setState({
+ webviewUrl: this.api().authCodeUrl(this.redirectUrl()),
+ });
+ }
+
+ api() {
+ return OneDriveApi.instance();
+
+ redirectUrl() {
+ return 'https://login.microsoftonline.com/common/oauth2/nativeclient';
+ }
+
+ async webview_load(noIdeaWhatThisIs) {
+ // This is deprecated according to the doc but since the non-deprecated property (source)
+ // doesn't exist, use this for now. The whole component is completely undocumented
+ // at the moment so it's likely to change.
+ const url = noIdeaWhatThisIs.url;
+
+ console.info('URL: ' + url);
+
+ if (!this.authCode_) {
+ if (url.indexOf(this.redirectUrl() + '?code=') === 0) {
+ let code = url.split('?code=');
+ this.authCode_ = code[1];
+
+ await this.api().execTokenRequest(this.authCode_, this.redirectUrl(), true);
+ Setting.setValue('sync.onedrive.auth', JSON.stringify(this.api().auth()));
+ oneDriveApi.on('authRefreshed', (a) => {
+ Setting.setValue('sync.onedrive.auth', JSON.stringify(a));
+ });
+
+ let appDir = await this.api().appDirectory();
+
+ Log.info('APP DIR: ' + appDir);
+ // fileApi = new FileApi(appDir, driver);
+ // fileApi.setLogger(logger);
+ }
+ }
+ }
+
+ render() {
+ const source = {
+ uri: this.state.webviewUrl,
+ }
+
+ //
+
+ return (
+
+
+ { this.webview_load(o); }}
+ />
+
+ );
+ }
+
+}
+
+const OneDriveLoginScreen = connect(
+ (state) => {
+ return {};
+ }
+)(OneDriveLoginScreenComponent)
+
+export { OneDriveLoginScreen };
\ No newline at end of file
diff --git a/ReactNativeClient/lib/file-api-driver-onedrive.js b/ReactNativeClient/lib/file-api-driver-onedrive.js
index 5ea93c705..669db2299 100644
--- a/ReactNativeClient/lib/file-api-driver-onedrive.js
+++ b/ReactNativeClient/lib/file-api-driver-onedrive.js
@@ -5,8 +5,10 @@ import { OneDriveApi } from 'lib/onedrive-api.js';
class FileApiDriverOneDrive {
- constructor(clientId, clientSecret) {
- this.api_ = new OneDriveApi(clientId, clientSecret);
+ //constructor(clientId, clientSecret) {
+ constructor(api) {
+ this.api_ = api;
+ //this.api_ = new OneDriveApi(clientId, clientSecret);
}
api() {
diff --git a/ReactNativeClient/lib/onedrive-api.js b/ReactNativeClient/lib/onedrive-api.js
index 0fe16f032..c582bbc56 100644
--- a/ReactNativeClient/lib/onedrive-api.js
+++ b/ReactNativeClient/lib/onedrive-api.js
@@ -12,6 +12,15 @@ class OneDriveApi {
};
}
+ static instance() {
+ if (this.instance_) return this.instance_;
+
+ const CLIENT_ID = 'e09fc0de-c958-424f-83a2-e56a721d331b';
+ const CLIENT_SECRET = 'JA3cwsqSGHFtjMwd5XoF5L5';
+ this.instance_ = new OneDriveApi(CLIENT_ID, CLIENT_SECRET);
+ return this.instance_;
+ }
+
dispatch(eventName, param) {
let ls = this.listeners_[eventName];
for (let i = 0; i < ls.length; i++) {
@@ -47,10 +56,6 @@ class OneDriveApi {
return this.clientSecret_;
}
- // possibleOAuthDancePorts() {
- // return [1917, 9917, 8917];
- // }
-
async appDirectory() {
let r = await this.execJson('GET', '/drive/special/approot');
return r.parentReference.path + '/' + r.name;
@@ -66,6 +71,34 @@ class OneDriveApi {
return 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize?' + stringify(query);
}
+ async execTokenRequest(code, redirectUri, isPublic = false) {
+ let body = new shim.FormData();
+ body.append('client_id', this.clientId());
+ if (!isPublic) body.append('client_secret', this.clientSecret());
+ body.append('code', code);
+ body.append('redirect_uri', redirectUri);
+ body.append('grant_type', 'authorization_code');
+
+ const r = await shim.fetch(this.tokenBaseUrl(), {
+ method: 'POST',
+ body: body,
+ })
+
+ if (!r.ok) {
+ const text = await r.text();
+ throw new Error('Could not retrieve auth code: ' + r.status + ': ' + r.statusText + ': ' + text);
+ }
+
+ try {
+ const json = await r.json();
+ this.setAuth(json);
+ } catch (error) {
+ const text = await r.text();
+ error.message += ': ' + text;
+ throw error;
+ }
+ }
+
oneDriveErrorResponseToError(errorResponse) {
if (!errorResponse) return new Error('Undefined error');
@@ -181,90 +214,6 @@ class OneDriveApi {
this.dispatch('authRefreshed', this.auth_);
}
- // async oauthDance(targetConsole = null) {
- // if (targetConsole === null) targetConsole = console;
-
- // this.auth_ = null;
-
- // let ports = this.possibleOAuthDancePorts();
- // let port = null;
- // for (let i = 0; i < ports.length; i++) {
- // let inUse = await tcpPortUsed.check(ports[i]);
- // if (!inUse) {
- // port = ports[i];
- // break;
- // }
- // }
-
- // if (!port) throw new Error('All potential ports are in use - please report the issue at https://github.com/laurent22/joplin');
-
- // let authCodeUrl = this.authCodeUrl('http://localhost:' + port);
-
- // return new Promise((resolve, reject) => {
- // let server = http.createServer();
- // let errorMessage = null;
-
- // server.on('request', (request, response) => {
- // const query = urlParser.parse(request.url, true).query;
-
- // function writeResponse(code, message) {
- // response.writeHead(code, {"Content-Type": "text/html"});
- // response.write(message);
- // response.end();
- // }
-
- // if (!query.code) return writeResponse(400, '"code" query parameter is missing');
-
- // let body = new shim.FormData();
- // body.append('client_id', this.clientId());
- // body.append('client_secret', this.clientSecret());
- // body.append('code', query.code ? query.code : '');
- // body.append('redirect_uri', 'http://localhost:' + port.toString());
- // body.append('grant_type', 'authorization_code');
-
- // let options = {
- // method: 'POST',
- // body: body,
- // };
-
- // fetch(this.tokenBaseUrl(), options).then((r) => {
- // if (!r.ok) {
- // errorMessage = 'Could not retrieve auth code: ' + r.status + ': ' + r.statusText;
- // writeResponse(400, errorMessage);
- // targetConsole.log('');
- // targetConsole.log(errorMessage);
- // server.destroy();
- // return;
- // }
-
- // return r.json().then((json) => {
- // this.auth_ = json;
- // writeResponse(200, 'The application has been authorised - you may now close this browser tab.');
- // targetConsole.log('');
- // targetConsole.log('The application has been successfully authorised.');
- // server.destroy();
- // });
- // });
- // });
-
- // server.on('close', () => {
- // if (errorMessage) {
- // reject(new Error(errorMessage));
- // } else {
- // resolve(this.auth_);
- // }
- // });
-
- // server.listen(port);
-
- // enableServerDestroy(server);
-
- // targetConsole.log('Please open this URL in your browser to authentify the application:');
- // targetConsole.log('');
- // targetConsole.log(authCodeUrl);
- // });
- // }
-
}
export { OneDriveApi };
\ No newline at end of file
diff --git a/ReactNativeClient/lib/shim.js b/ReactNativeClient/lib/shim.js
index 874f369c4..7084166b5 100644
--- a/ReactNativeClient/lib/shim.js
+++ b/ReactNativeClient/lib/shim.js
@@ -1,6 +1,7 @@
let shim = {};
shim.fetch = typeof fetch !== 'undefined' ? fetch : null;
+shim.FormData = typeof FormData !== 'undefined' ? FormData : null;
if (!shim.fetch) {
let moduleName = 'node-fetch';
diff --git a/ReactNativeClient/root.js b/ReactNativeClient/root.js
index 9172b6420..b6788bc1f 100644
--- a/ReactNativeClient/root.js
+++ b/ReactNativeClient/root.js
@@ -19,6 +19,7 @@ import { FolderScreen } from 'lib/components/screens/folder.js'
import { FoldersScreen } from 'lib/components/screens/folders.js'
import { LoginScreen } from 'lib/components/screens/login.js'
import { LoadingScreen } from 'lib/components/screens/loading.js'
+import { OneDriveLoginScreen } from 'lib/components/screens/onedrive-login.js'
import { Setting } from 'lib/models/setting.js'
import { Synchronizer } from 'lib/synchronizer.js'
import { MenuContext } from 'react-native-popup-menu';
@@ -184,6 +185,7 @@ const AppNavigator = StackNavigator({
Folders: { screen: FoldersScreen },
Login: { screen: LoginScreen },
Loading: { screen: LoadingScreen },
+ OneDriveLogin: { screen: OneDriveLoginScreen },
});
class AppComponent extends React.Component {