Gerald пре 2 месеци
родитељ
комит
4e6aba5dcf

+ 0 - 3
.github/workflows/ci.yml

@@ -30,12 +30,9 @@ jobs:
       - name: Build
       - name: Build
         env:
         env:
           SYNC_DROPBOX_CLIENT_ID: ${{ secrets.SYNC_DROPBOX_CLIENT_ID }}
           SYNC_DROPBOX_CLIENT_ID: ${{ secrets.SYNC_DROPBOX_CLIENT_ID }}
-          SYNC_GOOGLE_CLIENT_ID: ${{ secrets.SYNC_GOOGLE_CLIENT_ID }}
-          SYNC_GOOGLE_CLIENT_SECRET: ${{ secrets.SYNC_GOOGLE_CLIENT_SECRET }}
           SYNC_GOOGLE_DESKTOP_ID: ${{ secrets.SYNC_GOOGLE_DESKTOP_ID }}
           SYNC_GOOGLE_DESKTOP_ID: ${{ secrets.SYNC_GOOGLE_DESKTOP_ID }}
           SYNC_GOOGLE_DESKTOP_SECRET: ${{ secrets.SYNC_GOOGLE_DESKTOP_SECRET }}
           SYNC_GOOGLE_DESKTOP_SECRET: ${{ secrets.SYNC_GOOGLE_DESKTOP_SECRET }}
           SYNC_ONEDRIVE_CLIENT_ID: ${{ secrets.SYNC_ONEDRIVE_CLIENT_ID }}
           SYNC_ONEDRIVE_CLIENT_ID: ${{ secrets.SYNC_ONEDRIVE_CLIENT_ID }}
-          SYNC_ONEDRIVE_CLIENT_SECRET: ${{ secrets.SYNC_ONEDRIVE_CLIENT_SECRET }}
         run: yarn && yarn build
         run: yarn && yarn build
 
 
       - name: Get version and SHA
       - name: Get version and SHA

+ 0 - 3
.github/workflows/release-edge.yml

@@ -29,12 +29,9 @@ jobs:
       - name: Build
       - name: Build
         env:
         env:
           SYNC_DROPBOX_CLIENT_ID: ${{ secrets.SYNC_DROPBOX_CLIENT_ID }}
           SYNC_DROPBOX_CLIENT_ID: ${{ secrets.SYNC_DROPBOX_CLIENT_ID }}
-          SYNC_GOOGLE_CLIENT_ID: ${{ secrets.SYNC_GOOGLE_CLIENT_ID }}
-          SYNC_GOOGLE_CLIENT_SECRET: ${{ secrets.SYNC_GOOGLE_CLIENT_SECRET }}
           SYNC_GOOGLE_DESKTOP_ID: ${{ secrets.SYNC_GOOGLE_DESKTOP_ID }}
           SYNC_GOOGLE_DESKTOP_ID: ${{ secrets.SYNC_GOOGLE_DESKTOP_ID }}
           SYNC_GOOGLE_DESKTOP_SECRET: ${{ secrets.SYNC_GOOGLE_DESKTOP_SECRET }}
           SYNC_GOOGLE_DESKTOP_SECRET: ${{ secrets.SYNC_GOOGLE_DESKTOP_SECRET }}
           SYNC_ONEDRIVE_CLIENT_ID: ${{ secrets.SYNC_ONEDRIVE_CLIENT_ID }}
           SYNC_ONEDRIVE_CLIENT_ID: ${{ secrets.SYNC_ONEDRIVE_CLIENT_ID }}
-          SYNC_ONEDRIVE_CLIENT_SECRET: ${{ secrets.SYNC_ONEDRIVE_CLIENT_SECRET }}
         run: |
         run: |
           mkdir -p $ASSETS_DIR
           mkdir -p $ASSETS_DIR
           yarn build
           yarn build

+ 0 - 3
.github/workflows/release.yml

@@ -29,12 +29,9 @@ jobs:
       - name: Build
       - name: Build
         env:
         env:
           SYNC_DROPBOX_CLIENT_ID: ${{ secrets.SYNC_DROPBOX_CLIENT_ID }}
           SYNC_DROPBOX_CLIENT_ID: ${{ secrets.SYNC_DROPBOX_CLIENT_ID }}
-          SYNC_GOOGLE_CLIENT_ID: ${{ secrets.SYNC_GOOGLE_CLIENT_ID }}
-          SYNC_GOOGLE_CLIENT_SECRET: ${{ secrets.SYNC_GOOGLE_CLIENT_SECRET }}
           SYNC_GOOGLE_DESKTOP_ID: ${{ secrets.SYNC_GOOGLE_DESKTOP_ID }}
           SYNC_GOOGLE_DESKTOP_ID: ${{ secrets.SYNC_GOOGLE_DESKTOP_ID }}
           SYNC_GOOGLE_DESKTOP_SECRET: ${{ secrets.SYNC_GOOGLE_DESKTOP_SECRET }}
           SYNC_GOOGLE_DESKTOP_SECRET: ${{ secrets.SYNC_GOOGLE_DESKTOP_SECRET }}
           SYNC_ONEDRIVE_CLIENT_ID: ${{ secrets.SYNC_ONEDRIVE_CLIENT_ID }}
           SYNC_ONEDRIVE_CLIENT_ID: ${{ secrets.SYNC_ONEDRIVE_CLIENT_ID }}
-          SYNC_ONEDRIVE_CLIENT_SECRET: ${{ secrets.SYNC_ONEDRIVE_CLIENT_SECRET }}
         run: |
         run: |
           mkdir -p $ASSETS_DIR $TEMP_DIR
           mkdir -p $ASSETS_DIR $TEMP_DIR
 
 

+ 0 - 3
scripts/webpack.conf.js

@@ -38,12 +38,9 @@ const defsObj = {
   ...pickEnvs([
   ...pickEnvs([
     'DEBUG',
     'DEBUG',
     'VM_VER',
     'VM_VER',
-    'SYNC_GOOGLE_CLIENT_ID',
-    'SYNC_GOOGLE_CLIENT_SECRET',
     'SYNC_GOOGLE_DESKTOP_ID',
     'SYNC_GOOGLE_DESKTOP_ID',
     'SYNC_GOOGLE_DESKTOP_SECRET',
     'SYNC_GOOGLE_DESKTOP_SECRET',
     'SYNC_ONEDRIVE_CLIENT_ID',
     'SYNC_ONEDRIVE_CLIENT_ID',
-    'SYNC_ONEDRIVE_CLIENT_SECRET',
     'SYNC_DROPBOX_CLIENT_ID',
     'SYNC_DROPBOX_CLIENT_ID',
   ]),
   ]),
   'process.env.INIT_FUNC_NAME': JSON.stringify(INIT_FUNC_NAME),
   'process.env.INIT_FUNC_NAME': JSON.stringify(INIT_FUNC_NAME),

+ 82 - 56
src/background/sync/onedrive.js

@@ -1,54 +1,65 @@
-// Reference: https://dev.onedrive.com/README.htm
-import { dumpQuery, noop } from '@/common';
+// References
+// - https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow
+import { dumpQuery, getUniqId, loadQuery, noop } from '@/common';
 import { FORM_URLENCODED, VM_HOME } from '@/common/consts';
 import { FORM_URLENCODED, VM_HOME } from '@/common/consts';
 import { AUTHORIZING, ERROR, UNAUTHORIZED } from '@/common/consts-sync';
 import { AUTHORIZING, ERROR, UNAUTHORIZED } from '@/common/consts-sync';
 import { objectGet } from '@/common/object';
 import { objectGet } from '@/common/object';
 import {
 import {
-  getURI, getItemFilename, BaseService, isScriptFile, register,
+  BaseService,
+  getCodeChallenge,
+  getCodeVerifier,
+  getItemFilename,
+  getURI,
+  isScriptFile,
   openAuthPage,
   openAuthPage,
+  register,
 } from './base';
 } from './base';
 
 
 const config = {
 const config = {
   client_id: process.env.SYNC_ONEDRIVE_CLIENT_ID,
   client_id: process.env.SYNC_ONEDRIVE_CLIENT_ID,
-  client_secret: process.env.SYNC_ONEDRIVE_CLIENT_SECRET,
   redirect_uri: VM_HOME + 'auth_onedrive.html',
   redirect_uri: VM_HOME + 'auth_onedrive.html',
 };
 };
 
 
 const OneDrive = BaseService.extend({
 const OneDrive = BaseService.extend({
   name: 'onedrive',
   name: 'onedrive',
   displayName: 'OneDrive',
   displayName: 'OneDrive',
-  urlPrefix: 'https://api.onedrive.com/v1.0',
+  urlPrefix: 'https://graph.microsoft.com/v1.0',
   refreshToken() {
   refreshToken() {
     const refreshToken = this.config.get('refresh_token');
     const refreshToken = this.config.get('refresh_token');
     return this.authorized({
     return this.authorized({
-      refresh_token: refreshToken,
       grant_type: 'refresh_token',
       grant_type: 'refresh_token',
-    })
-    .then(() => this.prepare());
+      refresh_token: refreshToken,
+    }).then(() => this.prepare());
   },
   },
   user() {
   user() {
-    const requestUser = () => this.loadData({
-      url: '/drive',
-      responseType: 'json',
-    });
+    const requestUser = () =>
+      this.loadData({
+        url: '/drive/special/approot',
+        responseType: 'json',
+      });
+    let unauthorized = false;
     return requestUser()
     return requestUser()
-    .catch((res) => {
-      if (res.status === 401) {
-        return this.refreshToken().then(requestUser);
-      }
-      throw res;
-    })
-    .catch((res) => {
-      if (res.status === 400 && objectGet(res, 'data.error') === 'invalid_grant') {
+      .catch((res) => {
+        if (!unauthorized && res.status === 401) {
+          unauthorized = true;
+          return this.refreshToken().then(requestUser);
+        }
+        throw res;
+      })
+      .catch((res) => {
+        if (
+          res.status === 400 &&
+          objectGet(res, 'data.error') === 'invalid_grant'
+        ) {
+          return Promise.reject({
+            type: UNAUTHORIZED,
+          });
+        }
         return Promise.reject({
         return Promise.reject({
-          type: UNAUTHORIZED,
+          type: ERROR,
+          data: res,
         });
         });
-      }
-      return Promise.reject({
-        type: ERROR,
-        data: res,
       });
       });
-    });
   },
   },
   handleMetaError(res) {
   handleMetaError(res) {
     if (res.status === 404) {
     if (res.status === 404) {
@@ -64,19 +75,17 @@ const OneDrive = BaseService.extend({
     return this.loadData({
     return this.loadData({
       url: '/drive/special/approot/children',
       url: '/drive/special/approot/children',
       responseType: 'json',
       responseType: 'json',
-    })
-    .then(data => data.value.filter(item => item.file && isScriptFile(item.name)).map(normalize));
+    }).then((data) =>
+      data.value
+        .filter((item) => item.file && isScriptFile(item.name))
+        .map(normalize),
+    );
   },
   },
   get(item) {
   get(item) {
     const name = getItemFilename(item);
     const name = getItemFilename(item);
     return this.loadData({
     return this.loadData({
-      url: `/drive/special/approot:/${encodeURIComponent(name)}`,
-      responseType: 'json',
-    })
-    .then(data => this.loadData({
-      url: data['@content.downloadUrl'],
-      delay: false,
-    }));
+      url: `/drive/special/approot:/${encodeURIComponent(name)}:/content`,
+    });
   },
   },
   put(item, data) {
   put(item, data) {
     const name = getItemFilename(item);
     const name = getItemFilename(item);
@@ -88,8 +97,7 @@ const OneDrive = BaseService.extend({
       },
       },
       body: data,
       body: data,
       responseType: 'json',
       responseType: 'json',
-    })
-    .then(normalize);
+    }).then(normalize);
   },
   },
   remove(item) {
   remove(item) {
     // return 204
     // return 204
@@ -97,26 +105,43 @@ const OneDrive = BaseService.extend({
     return this.loadData({
     return this.loadData({
       method: 'DELETE',
       method: 'DELETE',
       url: `/drive/special/approot:/${encodeURIComponent(name)}`,
       url: `/drive/special/approot:/${encodeURIComponent(name)}`,
-    })
-    .catch(noop);
+    }).catch(noop);
   },
   },
-  authorize() {
+  async authorize() {
+    this.session = {
+      state: getUniqId(),
+      codeVerifier: getCodeVerifier(),
+    };
     const params = {
     const params = {
       client_id: config.client_id,
       client_id: config.client_id,
-      scope: 'onedrive.appfolder wl.offline_access',
+      scope: 'openid profile Files.ReadWrite.AppFolder offline_access',
       response_type: 'code',
       response_type: 'code',
       redirect_uri: config.redirect_uri,
       redirect_uri: config.redirect_uri,
+      state: this.session.state,
+      ...(await getCodeChallenge(this.session.codeVerifier)),
     };
     };
-    const url = `https://login.live.com/oauth20_authorize.srf?${dumpQuery(params)}`;
+    const url = `https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?${dumpQuery(
+      params,
+    )}`;
     openAuthPage(url, config.redirect_uri);
     openAuthPage(url, config.redirect_uri);
   },
   },
   checkAuth(url) {
   checkAuth(url) {
-    const redirectUri = `${config.redirect_uri}?code=`;
+    const redirectUri = `${config.redirect_uri}?`;
+    if (!url.startsWith(redirectUri)) return;
+    const query = loadQuery(url.slice(redirectUri.length));
+    const { state, codeVerifier } = this.session || {};
+    this.session = null;
+    if (query.state !== state || !query.code) return;
     if (url.startsWith(redirectUri)) {
     if (url.startsWith(redirectUri)) {
       this.authState.set(AUTHORIZING);
       this.authState.set(AUTHORIZING);
-      this.checkSync(this.authorized({
-        code: url.slice(redirectUri.length),
-      }));
+      this.checkSync(
+        this.authorized({
+          code: query.code,
+          code_verifier: codeVerifier,
+          grant_type: 'authorization_code',
+          redirect_uri: config.redirect_uri,
+        }),
+      );
       return true;
       return true;
     }
     }
   },
   },
@@ -131,20 +156,21 @@ const OneDrive = BaseService.extend({
   authorized(params) {
   authorized(params) {
     return this.loadData({
     return this.loadData({
       method: 'POST',
       method: 'POST',
-      url: 'https://login.live.com/oauth20_token.srf',
+      url: 'https://login.microsoftonline.com/consumers/oauth2/v2.0/token',
       prefix: '',
       prefix: '',
       headers: {
       headers: {
         'Content-Type': FORM_URLENCODED,
         'Content-Type': FORM_URLENCODED,
       },
       },
-      body: dumpQuery(Object.assign({}, {
-        client_id: config.client_id,
-        client_secret: config.client_secret,
-        redirect_uri: config.redirect_uri,
-        grant_type: 'authorization_code',
-      }, params)),
+      body: dumpQuery(
+        Object.assign(
+          {
+            client_id: config.client_id,
+          },
+          params,
+        ),
+      ),
       responseType: 'json',
       responseType: 'json',
-    })
-    .then((data) => {
+    }).then((data) => {
       if (data.access_token) {
       if (data.access_token) {
         this.config.set({
         this.config.set({
           uid: data.user_id,
           uid: data.user_id,
@@ -157,7 +183,7 @@ const OneDrive = BaseService.extend({
     });
     });
   },
   },
 });
 });
-if (config.client_id && config.client_secret) register(OneDrive);
+if (config.client_id) register(OneDrive);
 
 
 function normalize(item) {
 function normalize(item) {
   return {
   return {