0
  1. We have created service account on GCP console.
  2. We have enabled domain-wide delegation - which helps to authenticate as a domain user and list the Drive files
  3. We have added private key, client email and domain name
  4. We have set the necessary scope in our case is https://www.googleapis.com/auth/drive.readonly
  5. We have enabled OAuth2 library from AppScript
  6. Now we are looping through all users, and to create a service account token on their behalf
  7. With the access token we are trying to access each user’s drive files

I am trying to get details of each user's google drive file id but.. it is just returning my drive and also creates appscript file in my drive which does not support revision.

function myFunction() {
  let users = AdminDirectory.Users.list({ "domain": "domsin name" }).users;
  Logger.log(users.length);
  users.forEach(function (user) {
    // Logger.log(user)
    user = user.primaryEmail;
    getService(user).reset();
    Logger.log(user)
    let service = getService(user);
    if (service.hasAccess()) {
      Logger.log("service has access");
      let files = [];
      let userEmail = user;
      let userFiles = Drive.Files.list({
        q: "'" + userEmail + "' in owners",
        fields: 'items(id)'
      }).items;
      for (let j = 0; j < userFiles.length; j++) {
        files.push(userFiles[j]);
      }

      const fileList = files.map(obj => obj.id);

      Logger.log(fileList);
      
      const cutoffDate = '2020-02-23T18:25:00+00:00';
      fileList.forEach((file) => {
        Logger.log(`processing file ${file}`)
        processBinary(file, cutoffDate)
      })
    }
    else {
      Logger.log(service.getLastError());
    }
  }
  )
}

let PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----\n";

let CLIENT_EMAIL = 'client_Email';

function getService(user) {
  return OAuth2.createService('List users')
    .setTokenUrl('https://accounts.google.com/o/oauth2/token')
    .setPrivateKey(PRIVATE_KEY)
    .setIssuer(CLIENT_EMAIL)
    .setSubject(user)
    .setPropertyStore(PropertiesService.getScriptProperties())
    .setParam('access_type', 'offline')
    .setScope("https://www.googleapis.com/auth/drive.readonly");
}

function processBinary(fileID, cutoffDate) {
  let file = DriveApp.getFileById(fileID)
  Logger.log("working on non-google file: %s", file.getName())
  let revisions = Drive.Revisions.list(file.getId())
  let corruptVersions = findCorruptedVersions(revisions.items, cutoffDate)


  corruptVersions.forEach(function (revision) {
    Logger.log("removing file %s, version %s, from author %s, from time %s", file.getName(), revision.id, revision.lastModifyingUser.displayName, revision.modifiedDate)
    try {

      let x = Drive.Revisions.remove(file.getId(), revision.id)
      Logger.log(x)


      /*
     * Permanently deletes a file version.
     * You can only delete revisions for files with binary content, like images or videos.
     * Revisions for other files, like Google Docs or Sheets,
     * and the last remaining file version can't be deleted
     *
     * */

    } catch (err) {
      Logger.log(err)
      Logger.log("problem deleting version for file: %s", file.getName())
    }

  })
}

function findCorruptedVersions(items, cutoffDate) {
  /*
  * finds the most recent version before the restore date
  */
  let cutDate = new Date(cutoffDate)
  let compareCut = function (item) {
    let revDate = new Date(item.modifiedDate);
    return cutDate < revDate
  }
  //find revisions after cut off date
  let laterRevs = items.filter(compareCut)


  return laterRevs;
}

1 Answers1

0

I guess the error might be that impersonation is not being performed. Maybe you should check your function getService(user)

As explained in this article about service account access the user to impersonate has to be passed on the Subject just as you did.

However maybe some other method or property takes priority. So you could try one of the following:

  • Reorder the setIssuer method to be the last one
  • Get rid of other method that might override the subject (for example setIssuer)
  • change the code to enforce to a specific testing user (user = <username>@<yourdomain.com>;)

EDIT:

Here I found something interesting:

When creating the OAuth2 service the parameter should be unique

// Create a new service with the given name. The name will be used when
// persisting the authorized token, so ensure it is unique within the
// scope of the property store.

Even more, you have an example that shows you how you can make it unique:

OAuth2.createService('GoogleDrive:' + USER_EMAIL)