You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Make fetch and FormData work in both RN and node
This commit is contained in:
		| @@ -7,6 +7,7 @@ import { FileApi } from 'lib/file-api.js'; | ||||
| import { FileApiDriverOneDrive } from 'lib/file-api-driver-onedrive.js'; | ||||
| import { FileApiDriverMemory } from 'lib/file-api-driver-memory.js'; | ||||
| import { FileApiDriverLocal } from 'lib/file-api-driver-local.js'; | ||||
| import { OneDriveApiNodeUtils } from './onedrive-api-node-utils.js'; | ||||
| import { Database } from 'lib/database.js'; | ||||
| import { DatabaseDriverNode } from 'lib/database-driver-node.js'; | ||||
| import { BaseModel } from 'lib/base-model.js'; | ||||
| @@ -685,7 +686,9 @@ async function synchronizer(syncTarget) { | ||||
| 		if (auth) { | ||||
| 			auth = JSON.parse(auth); | ||||
| 		} else { | ||||
| 			auth = await driver.api().oauthDance(vorpal); | ||||
| 			//auth = await driver.api().oauthDance(vorpal); | ||||
| 			const oneDriveApiUtils = new OneDriveApiNodeUtils(driver.api()); | ||||
| 			auth = await oneDriveApiUtils.oauthDance(vorpal); | ||||
| 			Setting.setValue('sync.onedrive.auth', JSON.stringify(auth)); | ||||
| 		} | ||||
|  | ||||
|   | ||||
							
								
								
									
										108
									
								
								CliClient/app/onedrive-api-node-utils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								CliClient/app/onedrive-api-node-utils.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| const fetch = require('node-fetch'); | ||||
| const tcpPortUsed = require('tcp-port-used'); | ||||
| const http = require("http"); | ||||
| const urlParser = require("url"); | ||||
| const FormData = require('form-data'); | ||||
| const enableServerDestroy = require('server-destroy'); | ||||
|  | ||||
| class OneDriveApiNodeUtils { | ||||
|  | ||||
| 	constructor(api) { | ||||
| 		this.api_ = api; | ||||
| 	} | ||||
|  | ||||
| 	api() { | ||||
| 		return this.api_; | ||||
| 	} | ||||
|  | ||||
| 	possibleOAuthDancePorts() { | ||||
| 		return [1917, 9917, 8917]; | ||||
| 	} | ||||
|  | ||||
| 	async oauthDance(targetConsole = null) { | ||||
| 		if (targetConsole === null) targetConsole = console; | ||||
|  | ||||
| 		this.api().setAuth(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.api().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 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, | ||||
| 				}; | ||||
|  | ||||
| 				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; | ||||
| 					} | ||||
|  | ||||
| 					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(); | ||||
| 					}); | ||||
| 				}); | ||||
| 			}); | ||||
|  | ||||
| 			server.on('close', () => { | ||||
| 				if (errorMessage) { | ||||
| 					reject(new Error(errorMessage)); | ||||
| 				} else { | ||||
| 					resolve(this.api().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 { OneDriveApiNodeUtils }; | ||||
| @@ -5,6 +5,8 @@ import { Log } from 'lib/log.js'; | ||||
| import { Menu, MenuOptions, MenuOption, MenuTrigger } from 'react-native-popup-menu'; | ||||
| import { _ } from 'lib/locale.js'; | ||||
| import { Setting } from 'lib/models/setting.js'; | ||||
| import { FileApi } from 'lib/file-api.js'; | ||||
| import { FileApiDriverOneDrive } from 'lib/file-api-driver-onedrive.js'; | ||||
|  | ||||
| const styles = StyleSheet.create({ | ||||
| 	divider: { | ||||
| @@ -38,20 +40,20 @@ class ScreenHeaderComponent extends Component { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	menu_login() { | ||||
| 		this.props.dispatch({ | ||||
| 			type: 'Navigation/NAVIGATE', | ||||
| 			routeName: 'Login', | ||||
| 		}); | ||||
| 	} | ||||
| 	menu_synchronize() { | ||||
| 		// const CLIENT_ID = 'e09fc0de-c958-424f-83a2-e56a721d331b'; | ||||
| 		// const CLIENT_SECRET = 'JA3cwsqSGHFtjMwd5XoF5L5'; | ||||
|  | ||||
| 	menu_logout() { | ||||
| 		let user = { email: null, session: null }; | ||||
| 		Setting.setObject('user', user); | ||||
| 		this.props.dispatch({ | ||||
| 			type: 'USER_SET', | ||||
| 			user: user, | ||||
| 		}); | ||||
| 		// let driver = new FileApiDriverOneDrive(CLIENT_ID, CLIENT_SECRET); | ||||
| 		// let auth = Setting.value('sync.onedrive.auth'); | ||||
| 		 | ||||
| 		// if (auth) { | ||||
| 		// 	auth = JSON.parse(auth); | ||||
| 		// } else { | ||||
| 		// 	driver.api().oauthDance(vorpal); | ||||
| 		// 	//auth = driver.api().oauthDance(vorpal); | ||||
| 		// 	//Setting.setValue('sync.onedrive.auth', JSON.stringify(auth)); | ||||
| 		// } | ||||
| 	} | ||||
|  | ||||
| 	render() { | ||||
| @@ -69,17 +71,10 @@ class ScreenHeaderComponent extends Component { | ||||
| 			menuOptionComponents.push(<View key={'menuOption_' + key++} style={styles.divider}/>); | ||||
| 		} | ||||
|  | ||||
| 		if (this.props.user && this.props.user.session) { | ||||
| 			menuOptionComponents.push( | ||||
| 				<MenuOption value={() => this.menu_logout()} key={'menuOption_' + key++}> | ||||
| 					<Text>{_('Logout')}</Text> | ||||
| 				</MenuOption>); | ||||
| 		} else { | ||||
| 			menuOptionComponents.push( | ||||
| 				<MenuOption value={() => this.menu_login()} key={'menuOption_' + key++}> | ||||
| 					<Text>{_('Login')}</Text> | ||||
| 				</MenuOption>); | ||||
| 		} | ||||
| 		menuOptionComponents.push( | ||||
| 			<MenuOption value={() => this.menu_synchronize()} key={'menuOption_' + key++}> | ||||
| 				<Text>{_('Synchronize')}</Text> | ||||
| 			</MenuOption>); | ||||
|  | ||||
| 		menuOptionComponents.push( | ||||
| 			<MenuOption value={1} key={'menuOption_' + key++}> | ||||
|   | ||||
| @@ -1,9 +1,4 @@ | ||||
| const fetch = require('node-fetch'); | ||||
| const tcpPortUsed = require('tcp-port-used'); | ||||
| const http = require("http"); | ||||
| const urlParser = require("url"); | ||||
| const FormData = require('form-data'); | ||||
| const enableServerDestroy = require('server-destroy'); | ||||
| import { shim } from 'lib/shim.js'; | ||||
| import { stringify } from 'query-string'; | ||||
|  | ||||
| class OneDriveApi { | ||||
| @@ -32,6 +27,10 @@ class OneDriveApi { | ||||
| 		return 'https://login.microsoftonline.com/common/oauth2/v2.0/token'; | ||||
| 	} | ||||
|  | ||||
| 	auth() { | ||||
| 		return this.auth_; | ||||
| 	} | ||||
|  | ||||
| 	setAuth(auth) { | ||||
| 		this.auth_ = auth; | ||||
| 	} | ||||
| @@ -48,9 +47,9 @@ class OneDriveApi { | ||||
| 		return this.clientSecret_; | ||||
| 	} | ||||
|  | ||||
| 	possibleOAuthDancePorts() { | ||||
| 		return [1917, 9917, 8917]; | ||||
| 	} | ||||
| 	// possibleOAuthDancePorts() { | ||||
| 	// 	return [1917, 9917, 8917]; | ||||
| 	// } | ||||
|  | ||||
| 	async appDirectory() { | ||||
| 		let r = await this.execJson('GET', '/drive/special/approot'); | ||||
| @@ -122,7 +121,7 @@ class OneDriveApi { | ||||
| 		for (let i = 0; i < 5; i++) { | ||||
| 			options.headers['Authorization'] = 'bearer ' + this.token(); | ||||
|  | ||||
| 			let response = await fetch(url, options); | ||||
| 			let response = await shim.fetch(url, options); | ||||
| 			if (!response.ok) { | ||||
| 				let errorResponse = await response.json(); | ||||
| 				let error = this.oneDriveErrorResponseToError(errorResponse); | ||||
| @@ -157,7 +156,7 @@ class OneDriveApi { | ||||
| 	async refreshAccessToken() { | ||||
| 		if (!this.auth_) throw new Error('Cannot refresh token: authentication data is missing'); | ||||
|  | ||||
| 		let body = new FormData(); | ||||
| 		let body = new shim.FormData(); | ||||
| 		body.append('client_id', this.clientId()); | ||||
| 		body.append('client_secret', this.clientSecret()); | ||||
| 		body.append('refresh_token', this.auth_.refresh_token); | ||||
| @@ -171,7 +170,7 @@ class OneDriveApi { | ||||
|  | ||||
| 		this.auth_ = null; | ||||
|  | ||||
| 		let response = await fetch(this.tokenBaseUrl(), options); | ||||
| 		let response = await shim.fetch(this.tokenBaseUrl(), options); | ||||
| 		if (!response.ok) { | ||||
| 			let msg = await response.text(); | ||||
| 			throw new Error(msg); | ||||
| @@ -182,89 +181,89 @@ class OneDriveApi { | ||||
| 		this.dispatch('authRefreshed', this.auth_); | ||||
| 	} | ||||
|  | ||||
| 	async oauthDance(targetConsole = null) { | ||||
| 		if (targetConsole === null) targetConsole = console; | ||||
| 	// async oauthDance(targetConsole = null) { | ||||
| 	// 	if (targetConsole === null) targetConsole = console; | ||||
|  | ||||
| 		this.auth_ = null; | ||||
| 	// 	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; | ||||
| 			} | ||||
| 		} | ||||
| 	// 	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'); | ||||
| 	// 	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); | ||||
| 	// 	let authCodeUrl = this.authCodeUrl('http://localhost:' + port); | ||||
|  | ||||
| 		return new Promise((resolve, reject) => {			 | ||||
| 			let server = http.createServer(); | ||||
| 			let errorMessage = null; | ||||
| 	// 	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; | ||||
| 	// 		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(); | ||||
| 				} | ||||
| 	// 			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'); | ||||
| 	// 			if (!query.code) return writeResponse(400, '"code" query parameter is missing'); | ||||
|  | ||||
| 				let body = new 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 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, | ||||
| 				}; | ||||
| 	// 			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; | ||||
| 					} | ||||
| 	// 			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(); | ||||
| 					}); | ||||
| 				}); | ||||
| 			}); | ||||
| 	// 				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.on('close', () => { | ||||
| 	// 			if (errorMessage) { | ||||
| 	// 				reject(new Error(errorMessage)); | ||||
| 	// 			} else { | ||||
| 	// 				resolve(this.auth_); | ||||
| 	// 			} | ||||
| 	// 		}); | ||||
|  | ||||
| 			server.listen(port); | ||||
| 	// 		server.listen(port); | ||||
|  | ||||
| 			enableServerDestroy(server); | ||||
| 	// 		enableServerDestroy(server); | ||||
|  | ||||
| 			targetConsole.log('Please open this URL in your browser to authentify the application:'); | ||||
| 			targetConsole.log(''); | ||||
| 			targetConsole.log(authCodeUrl); | ||||
| 		}); | ||||
| 	} | ||||
| 	// 		targetConsole.log('Please open this URL in your browser to authentify the application:'); | ||||
| 	// 		targetConsole.log(''); | ||||
| 	// 		targetConsole.log(authCodeUrl); | ||||
| 	// 	}); | ||||
| 	// } | ||||
|  | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										15
									
								
								ReactNativeClient/lib/shim.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								ReactNativeClient/lib/shim.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| let shim = {}; | ||||
|  | ||||
| shim.fetch = typeof fetch !== 'undefined' ? fetch : null; | ||||
|  | ||||
| if (!shim.fetch) { | ||||
| 	let moduleName = 'node-fetch'; | ||||
| 	shim.fetch = require(moduleName); | ||||
| } | ||||
|  | ||||
| if (!shim.FormData) { | ||||
| 	let moduleName = 'form-data'; | ||||
| 	shim.FormData = require(moduleName); | ||||
| } | ||||
|  | ||||
| export { shim }; | ||||
| @@ -10,7 +10,6 @@ | ||||
|     "dropbox": "^2.5.4", | ||||
|     "form-data": "^2.1.4", | ||||
|     "moment": "^2.18.1", | ||||
|     "node-fetch": "^1.7.1", | ||||
|     "react": "16.0.0-alpha.6", | ||||
|     "react-native": "0.44.0", | ||||
|     "react-native-action-button": "^2.6.9", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user