Acceder a Google Drive desde una extensión de Firefox


Estoy tratando de acceder (CRUD) Google Drive desde una extensión de Firefox. Las extensiones están codificadas en Javascript, pero ninguno de los dos SDK javascript existentes parecen encajar; el SDK del lado del cliente espera "ventana" para estar disponible, que no es el caso de las extensiones, y el SDK del lado del servidor parece depender de instalaciones específicas de nodo, como un script que funciona en el nodo ya no lo hace cuando lo cargo en Chrome después de ejecutarlo a través de browserify. ¿Estoy atascado usando llamadas REST sin procesar? El script de nodo que funciona se ve así:

var google = require('googleapis');
var readlineSync = require('readline-sync');

var CLIENT_ID = '....',
    CLIENT_SECRET = '....',
    REDIRECT_URL = 'urn:ietf:wg:oauth:2.0:oob',
    SCOPE = 'https://www.googleapis.com/auth/drive.file';

var oauth2Client = new google.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL);

var url = oauth2Client.generateAuthUrl({
  access_type: 'offline', // 'online' (default) or 'offline' (gets refresh_token)
  scope: SCOPE // If you only need one scope you can pass it as string
});

var code = readlineSync.question('Auth code? :');

oauth2Client.getToken(code, function(err, tokens) {
  console.log('authenticated?');
  // Now tokens contains an access_token and an optional refresh_token. Save them.
  if(!err) {
    console.log('authenticated');
    oauth2Client.setCredentials(tokens);
  } else {
    console.log('not authenticated');
  }
});

Envuelvo el nodo GDrive SDK usando browserify en este script:

var Google = new function(){
    this.api = require('googleapis');
    this.clientID = '....';
    this.clientSecret = '....';
    this.redirectURL = 'urn:ietf:wg:oauth:2.0:oob';
    this.scope = 'https://www.googleapis.com/auth/drive.file';
    this.client = new this.api.auth.OAuth2(this.clientID, this.clientSecret, this.redirectURL);
  }
}

Que luego se llama usando después de hacer clic en un botón (si el campo de texto no tiene código, inicia el navegador para obtener uno):

function authorize() {
  var code = document.getElementById("code").value.trim();

  if (code === '') {
    var url = Google.client.generateAuthUrl({access_type: 'offline', scope: Google.scope});
    var win = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow('navigator:browser');
    win.gBrowser.selectedTab = win.gBrowser.addTab(url);
  } else {
    Google.client.getToken(code, function(err, tokens) {
      if(!err) {
        Google.client.setCredentials(tokens);
        // store token
        alert('Succesfully authorized');
      } else {
        alert('Not authorized: ' + err); // always ends here
      }
    });
  }
}

Pero esto produce el error Not authorized: Invalid protocol: https:

Author: retorquere, 2014-09-11

2 answers

Aunque es posible, dependiendo del caso de uso, también podría ser de interés limitado.

Firefox viene con un pequeño servidor http, solo lo básico. Se incluye con fines de prueba, pero esto no es una razón para pasarlo por alto.

Sigamos la guía de inicio rápido para ejecutar una aplicación Drive en Javascript

La parte difícil es establecer los URI de redirección y los orígenes de Javascript. Obviamente, la configuración correcta es http://localhost, pero ¿cómo puede estar seguro de que cada usuario tiene el puerto 80?

No puede y, a menos que tenga control sobre sus usuarios, no se garantiza que ningún puerto funcione para todos. Con esto en mente, elijamos el puerto 49870 y oremos.

Así que ahora Redirigir URI y los orígenes de Javascript se establecen en http://localhost:49870

Asumiendo que usa Add-on SDK, guarde el quickstart.html (recuerde agregar su ID de cliente) en el directorio data de su extensión. Ahora edita tu main.js

const self = require("sdk/self");
const { Cc, Ci } = require("chrome");
const tabs = require("sdk/tabs");
const httpd = require("sdk/test/httpd");

var quickstart = self.data.load("quickstart.html");

var srv = new httpd.nsHttpServer();

srv.registerPathHandler("/gdrive", function handler(request, response){
  response.setHeader("Content-Type", "text/html; charset=utf-8", false);

  let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
  converter.charset = "UTF-8";
  response.write(converter.ConvertFromUnicode(quickstart));
})

srv.start(49870);

tabs.open("http://localhost:49870/gdrive");

exports.onUnload = function (reason) {
  srv.stop(function(){});
};

Observe que quickstart.html no se abre como un archivo local, con un resource: URI. A la Drive API no le gustaría eso. Se sirve en la url http://localhost:49870/gdrive. No hace falta decir que en lugar de html estático podemos usar una plantilla o cualquier otra cosa. También el http://localhost:49870/gdrive puede ser scripted con un PageMod regular.

No considero esto una solución real. Es mejor que nada.

 1
Author: paa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-30 10:28:01

Desde aquí https://developer.mozilla.org/en/docs/Working_with_windows_in_chrome_code podrías intentar window = window || content || {}

Utilice la API de cliente JavaScript y no el nodo.cliente de js. Aunque browserify hará que funcione. Tendrás que exponer el secreto de tu cliente en este último. El flujo de autenticación del lado del cliente es muy diferente al del lado del servidor. Refiérase a https://developers.google.com/accounts/docs/OAuth2

Habiendo dicho todo esto. Realmente no es tan difícil de implemente una aplicación con llamadas basadas en REST. Los métodos de todas las bibliotecas cliente imitan las URL REST correspondientes. Podría configurar algunas funciones propias para manejar la solicitud y la respuesta y el resto sentiría lo mismo.

 1
Author: Gaurav Ramanan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-29 05:18:38