You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	| @@ -82,6 +82,15 @@ class SyncTargetOneDrive extends BaseSyncTarget { | ||||
| 	} | ||||
|  | ||||
| 	async initFileApi() { | ||||
| 		let context = Setting.value(`sync.${this.syncTargetId()}.context`); | ||||
| 		context = context === '' ? null : JSON.parse(context); | ||||
| 		let accountProperties = context ? context.accountProperties : null; | ||||
| 		if (!accountProperties) { | ||||
| 			accountProperties = await this.api_.execAccountPropertiesRequest(); | ||||
| 			context ? context.accountProperties = accountProperties : context = { accountProperties: accountProperties }; | ||||
| 			Setting.setValue(`sync.${this.syncTargetId()}.context`, JSON.stringify(context)); | ||||
| 		} | ||||
| 		this.api_.setAccountProperties(accountProperties); | ||||
| 		const appDir = await this.api().appDirectory(); | ||||
| 		const fileApi = new FileApi(appDir, new FileApiDriverOneDrive(this.api())); | ||||
| 		fileApi.setSyncTargetId(this.syncTargetId()); | ||||
| @@ -90,8 +99,15 @@ class SyncTargetOneDrive extends BaseSyncTarget { | ||||
| 	} | ||||
|  | ||||
| 	async initSynchronizer() { | ||||
| 		if (!(await this.isAuthenticated())) throw new Error('User is not authentified'); | ||||
| 		return new Synchronizer(this.db(), await this.fileApi(), Setting.value('appType')); | ||||
| 		try { | ||||
| 			if (!(await this.isAuthenticated())) throw new Error('User is not authentified'); | ||||
| 			return new Synchronizer(this.db(), await this.fileApi(), Setting.value('appType')); | ||||
| 		} catch (error) { | ||||
| 			BaseSyncTarget.dispatch({ type: 'SYNC_REPORT_UPDATE', report: { errors: [error] } }); | ||||
| 			throw error; | ||||
| 		} | ||||
|  | ||||
|  | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -217,7 +217,9 @@ class FileApiDriverOneDrive { | ||||
| 		}; | ||||
|  | ||||
| 		const freshStartDelta = () => { | ||||
| 			const url = `${this.makePath_(path)}:/delta`; | ||||
| 			// Business Accounts are only allowed to make delta requests to the root. For some reason /delta gives an error for personal accounts and :/delta an error for business accounts | ||||
| 			const accountProperties = this.api_.accountProperties_; | ||||
| 			const url = (accountProperties.accountType === 'business') ? `/drives/${accountProperties.driveId}/root/delta` : `${this.makePath_(path)}:/delta`; | ||||
| 			const query = this.itemFilter_(); | ||||
| 			query.select += ',deleted'; | ||||
| 			return { url: url, query: query }; | ||||
| @@ -265,14 +267,14 @@ class FileApiDriverOneDrive { | ||||
|  | ||||
| 		const items = []; | ||||
|  | ||||
| 		// The delta API might return things that happen in subdirectories of the root and we don't want to | ||||
| 		// deal with these since all the files we're interested in are at the root (The .resource dir | ||||
| 		// is special since it's managed directly by the clients and resources never change - only the | ||||
| 		// associated .md file at the root is synced). So in the loop below we check that the parent is | ||||
| 		// indeed the root, otherwise the item is skipped. | ||||
| 		// (Not sure but it's possible the delta API also returns events for files that are copied outside | ||||
| 		//  of the app directory and later deleted or modified. We also don't want to deal with | ||||
| 		//  these files during sync). | ||||
| 		// The delta API might return things that happens in subdirectories and outside of the joplin directory. | ||||
| 		// We don't want to deal with these since all the files we're interested in are at the root of the joplin directory | ||||
| 		// (The .resource dir is special since it's managed directly by the clients and resources never change - only the | ||||
| 		// associated .md file at the root is synced). So in the loop below we check that the parent is indeed the joplin | ||||
| 		// directory, otherwise the item is skipped. | ||||
| 		// At OneDrive for Business delta requests can only make at the root of OneDrive.  Not sure but it's possible that | ||||
| 		// the delta API also returns events for files that are copied outside of the app directory and later deleted or | ||||
| 		// modified when using OneDrive Personal). | ||||
|  | ||||
| 		for (let i = 0; i < response.value.length; i++) { | ||||
| 			const v = response.value[i]; | ||||
|   | ||||
| @@ -13,6 +13,7 @@ class OneDriveApi { | ||||
| 		this.clientId_ = clientId; | ||||
| 		this.clientSecret_ = clientSecret; | ||||
| 		this.auth_ = null; | ||||
| 		this.accountProperties_ = null; | ||||
| 		this.isPublic_ = isPublic; | ||||
| 		this.listeners_ = { | ||||
| 			authRefreshed: [], | ||||
| @@ -73,14 +74,15 @@ class OneDriveApi { | ||||
| 	} | ||||
|  | ||||
| 	async appDirectory() { | ||||
| 		const r = await this.execJson('GET', '/drive/special/approot'); | ||||
| 		const driveId = this.accountProperties_.driveId; | ||||
| 		const r = await this.execJson('GET', `/me/drives/${driveId}/special/approot`); | ||||
| 		return `${r.parentReference.path}/${r.name}`; | ||||
| 	} | ||||
|  | ||||
| 	authCodeUrl(redirectUri) { | ||||
| 		const query = { | ||||
| 			client_id: this.clientId_, | ||||
| 			scope: 'files.readwrite offline_access', | ||||
| 			scope: 'files.readwrite offline_access sites.readwrite.all', | ||||
| 			response_type: 'code', | ||||
| 			redirect_uri: redirectUri, | ||||
| 		}; | ||||
| @@ -320,6 +322,29 @@ class OneDriveApi { | ||||
| 		throw new Error(`Could not execute request after multiple attempts: ${method} ${url}`); | ||||
| 	} | ||||
|  | ||||
| 	setAccountProperties(accountProperties) { | ||||
| 		this.accountProperties_ = accountProperties; | ||||
| 	} | ||||
|  | ||||
| 	async execAccountPropertiesRequest() { | ||||
| 		const response = await shim.fetch('https://graph.microsoft.com/v1.0/me/drive', { | ||||
| 			method: 'GET', | ||||
| 			headers: { | ||||
| 				'Authorization': this.token(), | ||||
| 			}, | ||||
| 		}); | ||||
|  | ||||
| 		if (!response.ok) { | ||||
| 			const text = await response.text(); | ||||
| 			throw new Error(`Could not retrieve account details (drive ID, Account type): ${response.status}: ${response.statusText}: ${text}`); | ||||
| 		} else { | ||||
| 			const data = await response.json(); | ||||
| 			const accountProperties = { accountType: data.driveType, driveId: data.id }; | ||||
| 			return accountProperties; | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	async execJson(method, path, query, data) { | ||||
| 		const response = await this.exec(method, path, query, data); | ||||
| 		const errorResponseText = await response.text(); | ||||
|   | ||||
| @@ -2,7 +2,6 @@ const { Logger } = require('lib/logger.js'); | ||||
| const Setting = require('lib/models/Setting.js'); | ||||
| const { shim } = require('lib/shim.js'); | ||||
| const SyncTargetRegistry = require('lib/SyncTargetRegistry.js'); | ||||
| const { _ } = require('lib/locale.js'); | ||||
|  | ||||
| const reg = {}; | ||||
|  | ||||
| @@ -141,20 +140,6 @@ reg.scheduleSync = async (delay = null, syncOptions = null) => { | ||||
| 				} catch (error) { | ||||
| 					reg.logger().info('Could not run background sync:'); | ||||
| 					reg.logger().info(error); | ||||
|  | ||||
| 					// Special case to display OneDrive Business error. This is the full error that's received when trying to use a OneDrive Business account: | ||||
| 					// | ||||
| 					// {"error":"invalid_client","error_description":"AADSTS50011: The reply address 'http://localhost:1917' does not match the reply addresses configured for | ||||
| 					// the application: 'cbabb902-d276-4ea4-aa88-062a5889d6dc'. More details: not specified\r\nTrace ID: 6e63dac6-8b37-47e2-bd1b-4768f8713400\r\nCorrelation | ||||
| 					// ID: acfd6503-8d97-4349-ae2e-e7a19dd7b6bc\r\nTimestamp: 2017-12-01 13:35:55Z","error_codes":[50011],"timestamp":"2017-12-01 13:35:55Z","trace_id": | ||||
| 					// "6e63dac6-8b37-47e2-bd1b-4768f8713400","correlation_id":"acfd6503-8d97-4349-ae2e-e7a19dd7b6bc"}: TOKEN: null Error: {"error":"invalid_client", | ||||
| 					// "error_description":"AADSTS50011: The reply address 'http://localhost:1917' does not match the reply addresses configured for the application: | ||||
| 					// 'cbabb902-d276-4ea4-aa88-062a5889d6dc'. More details: not specified\r\nTrace ID: 6e63dac6-8b37-47e2-bd1b-4768f8713400\r\nCorrelation ID | ||||
| 					//  acfd6503-8d97-4349-ae2e-e7a19dd7b6bc\r\nTimestamp: 2017-12-01 13:35:55Z","error_codes":[50011],"timestamp":"2017-12-01 13:35:55Z","trace_id": | ||||
| 					// "6e63dac6-8b37-47e2-bd1b-4768f8713400","correlation_id":"acfd6503-8d97-4349-ae2e-e7a19dd7b6bc"} | ||||
| 					if (error && error.message && error.message.indexOf('"invalid_client"') >= 0) { | ||||
| 						reg.showErrorMessageBox(_('Could not synchronise with OneDrive.\n\nThis error often happens when using OneDrive for Business, which unfortunately cannot be supported.\n\nPlease consider using a regular OneDrive account.')); | ||||
| 					} | ||||
| 				} | ||||
| 				reg.setupRecurrentSync(); | ||||
| 				promiseResolve(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user