Refactor sync process to use new token retrieval method and update dependencies

- Updated node-fetch to version 2.6.7 to resolve compatibility issues
- Modified main.js to handle new async token retrieval approach
- Simplified start-sync IPC handler to prepare for new authentication flow
- Updated package.json and package-lock.json to reflect dependency changes
- Adjusted renderer.js to work with new GraphApiClient token retrieval method
This commit is contained in:
Tiger Ren 2025-01-29 01:25:31 +08:00
parent edec168bad
commit 3d8cffac3f
7 changed files with 243 additions and 221 deletions

46
main.js
View File

@ -209,39 +209,23 @@ ipcMain.on('select-folder', (event) => {
});
});
ipcMain.on('start-sync', async (event, { destFolder, onedriveSource, items }) => {
console.log('Starting sync with config:', { destFolder, onedriveSource });
console.log(`Processing ${items.length} items...`);
ipcMain.handle('start-sync', async (event, { destFolder, onedriveSource }) => {
console.log('main.js start-sync:', { destFolder, onedriveSource });
try {
// Filter for video files (Live Photos)
const videoItems = items.filter(item =>
item.name.toLowerCase().endsWith('.mov') ||
item.name.toLowerCase().endsWith('.mp4')
);
console.log(`Found ${videoItems.length} video items`);
// Process each video item
for (const item of videoItems) {
if (item['@microsoft.graph.downloadUrl']) {
const filename = `${item.id}${path.extname(item.name)}`;
const filepath = path.join(destFolder, filename);
console.log(`Downloading: ${item.name} as ${filename}`);
await downloadVideo(item['@microsoft.graph.downloadUrl'], filepath);
} else {
console.warn(`No download URL for item: ${item.name}`);
}
}
event.reply('sync-complete', {
totalItems: items.length,
videoItems: videoItems.length
});
const graphHelper = require('./renderer/graphHelper');
const result = await graphHelper.listFolderContents(onedriveSource);
// Send back the results using event.reply
// event.reply('sync-complete', {
// totalItems: result.value.length,
// videoItems: result.value.filter(item =>
// item.name.toLowerCase().endsWith('.mov') ||
// item.name.toLowerCase().endsWith('.mp4')
// ).length
// });
} catch (error) {
console.error('Sync error:', error);
event.reply('sync-error', error.message);
// event.reply('sync-error', error.message);
}
});

191
package-lock.json generated
View File

@ -13,7 +13,7 @@
"@electron/remote": "^2.1.2",
"@microsoft/microsoft-graph-client": "^3.0.2",
"electron-store": "^10.0.0",
"node-fetch": "^3.3.0",
"node-fetch": "^2.6.7",
"uuid": "^11.0.4"
},
"devDependencies": {
@ -51,9 +51,9 @@
}
},
"node_modules/@babel/runtime": {
"version": "7.26.0",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
"integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
"version": "7.26.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.7.tgz",
"integrity": "sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@ -162,9 +162,9 @@
}
},
"node_modules/@types/node": {
"version": "20.17.12",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.12.tgz",
"integrity": "sha512-vo/wmBgMIiEA23A/knMfn/cf37VnuF52nZh5ZoW0GWt4e4sxNquibrMRJ7UQsA06+MBx9r/H1jsI9grYjQCQlw==",
"version": "20.17.16",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.16.tgz",
"integrity": "sha512-vOTpLduLkZXePLxHiHsBLp98mHGnl8RptV4YAO3HfKO5UHjDvySGbxKtpYfy8Sx5+WKcgc45qNreJJRVM3L6mw==",
"dependencies": {
"undici-types": "~6.19.2"
}
@ -326,14 +326,6 @@
"node": ">=10"
}
},
"node_modules/data-uri-to-buffer": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
"engines": {
"node": ">= 12"
}
},
"node_modules/debounce-fn": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-6.0.0.tgz",
@ -451,17 +443,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/dot-prop/node_modules/type-fest": {
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.31.0.tgz",
"integrity": "sha512-yCxltHW07Nkhv/1F6wWBr8kz+5BGMfP+RbRSYFnegVb0qV/UMT0G0ElBloPVerqn4M2ZV80Ir1FtCcYv1cT6vQ==",
"engines": {
"node": ">=16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
@ -471,9 +452,9 @@
}
},
"node_modules/electron": {
"version": "33.2.1",
"resolved": "https://registry.npmjs.org/electron/-/electron-33.2.1.tgz",
"integrity": "sha512-SG/nmSsK9Qg1p6wAW+ZfqU+AV8cmXMTIklUL18NnOKfZLlum4ZsDoVdmmmlL39ZmeCaq27dr7CgslRPahfoVJg==",
"version": "33.3.2",
"resolved": "https://registry.npmjs.org/electron/-/electron-33.3.2.tgz",
"integrity": "sha512-2pWr0frM9UrZGX1d7eoFdMROw10h2vXIWJmXdjwlKnSWWUm18GCrEOUeDUr+IMgz5EjO7JM7FQDHDMApeMgHyg==",
"hasInstallScript": true,
"dependencies": {
"@electron/get": "^2.0.0",
@ -488,9 +469,9 @@
}
},
"node_modules/electron-store": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/electron-store/-/electron-store-10.0.0.tgz",
"integrity": "sha512-BU/QZh+5twHBprRdLu3YZX/rIarmZzhTNpJvAvqG1/yN0mNCrsMh0kl7bM4xaUKDNRiHz1r7wP/7Prjh7cleIw==",
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/electron-store/-/electron-store-10.0.1.tgz",
"integrity": "sha512-Ok0bF13WWdTzZi9rCtPN8wUfwx+yDMmV6PAnCMqjNRKEXHmklW/rV+6DofV/Vf5qoAh+Bl9Bj7dQ+0W+IL2psg==",
"dependencies": {
"conf": "^13.0.0",
"type-fest": "^4.20.0"
@ -502,17 +483,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/electron-store/node_modules/type-fest": {
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.31.0.tgz",
"integrity": "sha512-yCxltHW07Nkhv/1F6wWBr8kz+5BGMfP+RbRSYFnegVb0qV/UMT0G0ElBloPVerqn4M2ZV80Ir1FtCcYv1cT6vQ==",
"engines": {
"node": ">=16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
@ -590,9 +560,9 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"node_modules/fast-uri": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.5.tgz",
"integrity": "sha512-5JnBCWpFlMo0a3ciDy/JckMzzv1U9coZrIhedq+HXxxUfDTAiS0LA8OKVao4G9BxmCVck/jtA5r3KAtRWEyD8Q==",
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
"integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
"funding": [
{
"type": "github",
@ -612,39 +582,6 @@
"pend": "~1.2.0"
}
},
"node_modules/fetch-blob": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "paypal",
"url": "https://paypal.me/jimmywarting"
}
],
"dependencies": {
"node-domexception": "^1.0.0",
"web-streams-polyfill": "^3.0.3"
},
"engines": {
"node": "^12.20 || >= 14.13"
}
},
"node_modules/formdata-polyfill": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
"dependencies": {
"fetch-blob": "^3.1.2"
},
"engines": {
"node": ">=12.20.0"
}
},
"node_modules/fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
@ -954,39 +891,23 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "github",
"url": "https://paypal.me/jimmywarting"
}
],
"engines": {
"node": ">=10.5.0"
}
},
"node_modules/node-fetch": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"dependencies": {
"data-uri-to-buffer": "^4.0.0",
"fetch-blob": "^3.1.4",
"formdata-polyfill": "^4.0.10"
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
"node": "4.x || >=6.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/node-fetch"
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/normalize-url": {
@ -1152,6 +1073,18 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/serialize-error/node_modules/type-fest": {
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
"integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
"optional": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/sprintf-js": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
@ -1174,18 +1107,22 @@
"node": ">= 8.0"
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
},
"node_modules/type-fest": {
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
"integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
"optional": true,
"version": "4.33.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.33.0.tgz",
"integrity": "sha512-s6zVrxuyKbbAsSAD5ZPTB77q4YIdRctkTbJ2/Dqlinwz+8ooH2gd+YA7VA6Pa93KML9GockVvoxjZ2vHP+mu8g==",
"engines": {
"node": ">=10"
"node": ">=16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@ -1216,9 +1153,9 @@
}
},
"node_modules/uuid": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.4.tgz",
"integrity": "sha512-IzL6VtTTYcAhA/oghbFJ1Dkmqev+FpQWnCBaKq/gUluLxliWvO8DPFWfIviRmYbtaavtSQe4WBL++rFjdcGWEg==",
"version": "11.0.5",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.5.tgz",
"integrity": "sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
@ -1227,18 +1164,24 @@
"uuid": "dist/esm/bin/uuid"
}
},
"node_modules/web-streams-polyfill": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
"engines": {
"node": ">= 8"
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/when-exit": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/when-exit/-/when-exit-2.1.3.tgz",
"integrity": "sha512-uVieSTccFIr/SFQdFWN/fFaQYmV37OKtuaGphMAzi4DmmUlrvRBJW5WSLkHyjNQY/ePJMz3LoiX9R3yy1Su6Hw=="
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/when-exit/-/when-exit-2.1.4.tgz",
"integrity": "sha512-4rnvd3A1t16PWzrBUcSDZqcAmsUIy4minDXT/CZ8F2mVDgd65i4Aalimgz1aQkRGU0iH5eT5+6Rx2TK8o443Pg=="
},
"node_modules/wrappy": {
"version": "1.0.2",

View File

@ -14,11 +14,11 @@
"electron": "^33.2.1"
},
"dependencies": {
"@electron/remote": "^2.1.2",
"electron-store": "^10.0.0",
"node-fetch": "^3.3.0",
"uuid": "^11.0.4",
"@azure/msal-node": "^1.18.4",
"@microsoft/microsoft-graph-client": "^3.0.2"
"@electron/remote": "^2.1.2",
"@microsoft/microsoft-graph-client": "^3.0.2",
"electron-store": "^10.0.0",
"node-fetch": "^2.6.7",
"uuid": "^11.0.4"
}
}

View File

@ -15,17 +15,16 @@ const AAD_ENDPOINT_HOST = "https://login.microsoftonline.com/"; // include the t
const msalConfig = {
auth: {
clientId: "d581ab07-3a21-44d3-84c4-16b06bef6266",
authority: `${AAD_ENDPOINT_HOST}common`,
authority: "https://login.microsoftonline.com/consumers",
redirectUri: "msal" + "d581ab07-3a21-44d3-84c4-16b06bef6266" + "://auth"
},
system: {
loggerOptions: {
loggerCallback(loglevel, message, containsPii) {
console.log(message);
},
loggerCallback: (loglevel, message) => console.log(message),
piiLoggingEnabled: false,
logLevel: LogLevel.Verbose,
},
},
logLevel: LogLevel.Verbose
}
}
};
/**
@ -38,12 +37,14 @@ const protectedResources = {
graphMe: {
endpoint: `${GRAPH_ENDPOINT_HOST}v1.0/me`,
// scopes: ["User.Read"],
scopes: ["OneDrive.ReadWrite", "User.Read"]
scopes: ["Files.ReadWrite"]
}
};
const graphScopes = ["Files.ReadWrite"]; // Modern scope for OneDrive access
module.exports = {
msalConfig: msalConfig,
msalConfig,
protectedResources: protectedResources,
graphScopes: graphScopes
};

View File

@ -1,17 +1,14 @@
const { BrowserWindow } = require('@electron/remote');
const { v4: uuidv4 } = require('uuid'); // Add this for GUID generation
const AuthProvider = require("./AuthProvider");
const { protectedResources, msalConfig } = require("./authConfig");
let authProvider;
class GraphApiClient {
constructor() {
this.baseUrl = 'https://graph.microsoft.com/v1.0';
this.clientId = "073204aa-c1e0-4e66-a200-e5815a0aa93d";
this.scopes = "OneDrive.ReadWrite offline_access openid profile";
this.redirectUrl = "https://photos.onedrive.com/auth/login";
this.clientId = "d581ab07-3a21-44d3-84c4-16b06bef6266";
this.scopes = "Files.ReadWrite offline_access";
this.redirectUrl = "https://login.microsoftonline.com/common/oauth2/nativeclient";
}
cleanPath(path) {
@ -23,52 +20,98 @@ class GraphApiClient {
}
async listFolderContents(folderPath) {
const accessToken = await this.getAccessToken();
console.log("listFolderContents accessToken", accessToken);
// Remove AuthProvider usage completely
}
async clearCaches() {
const session = require('@electron/remote').session;
const defaultSession = session.defaultSession;
try {
console.log('graphApiClient listFolderContents:', folderPath);
const tokenRequest = {
scopes: protectedResources.graphMe.scopes
};
console.log('graphApiClient tokenRequest:', tokenRequest);
if (!authProvider) {
authProvider = new AuthProvider(msalConfig);
console.log('graphApiClient AuthProvider created', msalConfig);
}
await authProvider.logout();
const tokenResponse = await authProvider.getToken(tokenRequest);
const account = authProvider.account;
const accessToken = tokenResponse.accessToken;
console.log('graphApiClient Auth received: ', accessToken);
console.log('graphApiClient Auth received: ', account);
await Promise.all([
defaultSession.clearStorageData({
storages: [
'cookies',
'localstorage',
'cachestorage',
'appcache',
'filesystem',
'indexdb',
'shadercache',
'websql',
'serviceworkers',
]
}),
defaultSession.clearCache(),
defaultSession.clearAuthCache()
]);
console.log('All caches cleared successfully');
} catch (error) {
console.error('Error clearing caches:', error);
throw error;
}
}
const cleanPath = this.cleanPath(folderPath);
console.log('graphApiClient Clean path:', cleanPath);
const url = `${this.baseUrl}/me/drive/root:/${cleanPath}:/children`;
console.log('Querying OneDrive items from:', url);
const response = await fetch(url, {
headers: {
'Authorization': `Bearer ${accessToken}`,
'Accept': 'application/json',
'Cookie': auth.cookies,
'Origin': 'https://onedrive.live.com',
'Referer': 'https://onedrive.live.com/'
async getAccessToken() {
await this.clearCaches();
return new Promise((resolve, reject) => {
const authWindow = new BrowserWindow({
width: 800,
height: 600,
show: true,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
webSecurity: false // Allow cross-origin requests
}
});
if (!response.ok) {
const errorData = await response.json();
console.error('Graph API error details:', errorData);
throw new Error(`Graph API error: ${response.status} ${response.statusText}`);
// Handle navigation events
authWindow.webContents.on('will-redirect', (event, url) => {
console.log('Redirect detected:', url);
this.handleAuthResponse(url, authWindow, resolve, reject);
});
authWindow.webContents.on('did-finish-load', () => {
console.log('Finished loading:', authWindow.webContents.getURL());
});
const authUrl = `https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?` +
`client_id=${this.clientId}` +
`&response_type=token` + // Use token flow directly
`&scope=${encodeURIComponent(this.scopes)}` +
`&redirect_uri=${encodeURIComponent(this.redirectUrl)}` +
`&response_mode=fragment` + // Required for token flow
`&prompt=select_account`;
console.log('Loading auth URL:', authUrl);
authWindow.loadURL(authUrl);
});
}
handleAuthResponse(url, authWindow, resolve, reject) {
if (url.startsWith(this.redirectUrl)) {
try {
const hash = new URL(url).hash.substring(1);
const params = new URLSearchParams(hash);
const accessToken = params.get('access_token');
if (accessToken) {
authWindow.close();
resolve({
accessToken: accessToken,
expiresIn: params.get('expires_in')
});
} else {
reject(new Error('No access token found in response'));
}
} catch (error) {
console.error('Error processing auth response:', error);
reject(error);
}
const data = await response.json();
return data.value;
} catch (error) {
console.error('Graph API error:', error);
throw error;
}
}
}

47
renderer/graphHelper.js Normal file
View File

@ -0,0 +1,47 @@
const { PublicClientApplication } = require('@azure/msal-node');
const { msalConfig, graphScopes } = require('./authConfig');
const fetch = (...args) =>
import('node-fetch').then(({default: fetch}) => fetch(...args));
class GraphHelper {
constructor() {
this.pca = new PublicClientApplication(msalConfig);
}
async getAccessToken() {
const accounts = await this.pca.getTokenCache().getAllAccounts();
if (accounts.length > 0) {
try {
return await this.pca.acquireTokenSilent({
account: accounts[0],
scopes: graphScopes
});
} catch (error) {
return this.login();
}
}
return this.login();
}
async login() {
return this.pca.acquireTokenInteractive({
scopes: graphScopes,
openBrowser: async (url) => {
const { shell } = require('electron');
await shell.openExternal(url);
}
});
}
async listFolderContents(folderPath) {
const token = await this.getAccessToken();
const response = await fetch(`https://graph.microsoft.com/v1.0/me/drive/root:${folderPath}:/children`, {
headers: {
Authorization: `Bearer ${token.accessToken}`
}
});
return response.json();
}
}
module.exports = new GraphHelper();

View File

@ -74,25 +74,29 @@ document.getElementById('sync-button').addEventListener('click', async () => {
alert('Please set both destination folder and OneDrive source path first');
return;
}
let originalText = "Sync Now";
try {
// Show loading state
const syncButton = document.getElementById('sync-button');
const originalText = syncButton.textContent;
originalText = syncButton.textContent;
// const originalText = syncButton.textContent;
syncButton.textContent = 'Syncing...';
syncButton.disabled = true;
// Get folder contents using GraphApiClient
console.log('renderer: Getting folder contents:', onedriveSource);
const items = await graphApi.listFolderContents(onedriveSource);
console.log('renderer: Found items:', items.length);
// const items = await graphApi.listFolderContents(onedriveSource);
// console.log('renderer: Found items:', items.length);
// Process the items
// TODO: Handle the items as needed
showStatus(`Found ${items.length} items`);
// Send the items to the main process
ipcRenderer.send('start-sync', { destFolder, onedriveSource , items});
// ipcRenderer.send('start-sync', { destFolder, onedriveSource });
await ipcRenderer.invoke('start-sync', { destFolder, onedriveSource });
} catch (error) {
console.error('Sync error:', error);