146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Custom binding for the Permissions API.
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var binding = require('binding').Binding.create('permissions');
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)var Event = require('event_bindings').Event;
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// These custom binding are only necessary because it is not currently
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// possible to have a union of types as the type of the items in an array.
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Once that is fixed, this entire file should go away.
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// See,
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// https://code.google.com/p/chromium/issues/detail?id=162044
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// https://code.google.com/p/chromium/issues/detail?id=162042
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO(bryeung): delete this file.
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)binding.registerCustomHook(function(api) {
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var apiFunctions = api.apiFunctions;
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var permissions = api.compiledApi;
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  function maybeConvertToObject(str) {
23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    var parts = $String.split(str, '|');
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (parts.length != 2)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return str;
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var ret = {};
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ret[parts[0]] = JSON.parse(parts[1]);
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ret;
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  function convertObjectPermissionsToStrings() {
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (arguments.length < 1)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return arguments;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var args = arguments[0].permissions;
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!args)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return arguments;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (var i = 0; i < args.length; i += 1) {
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (typeof(args[i]) == 'object') {
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        var a = args[i];
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        var keys = $Object.keys(a);
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (keys.length != 1) {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          throw new Error("Too many keys in object-style permission.");
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        arguments[0].permissions[i] = keys[0] + '|' +
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            JSON.stringify(a[keys[0]]);
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return arguments;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Convert complex permissions to strings so they validate against the schema
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  apiFunctions.setUpdateArgumentsPreValidate(
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      'contains', convertObjectPermissionsToStrings);
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  apiFunctions.setUpdateArgumentsPreValidate(
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      'remove', convertObjectPermissionsToStrings);
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  apiFunctions.setUpdateArgumentsPreValidate(
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      'request', convertObjectPermissionsToStrings);
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Convert complex permissions back to objects
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  apiFunctions.setCustomCallback('getAll',
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      function(name, request, response) {
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        for (var i = 0; i < response.permissions.length; i += 1) {
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          response.permissions[i] =
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              maybeConvertToObject(response.permissions[i]);
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // Since the schema says Permissions.permissions contains strings and
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // not objects, validation will fail after the for-loop above.  This
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // skips validation and calls the callback directly, then clears it so
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // that handleResponse doesn't call it again.
757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        try {
767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          if (request.callback)
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            $Function.apply(request.callback, request, [response]);
787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        } finally {
797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          delete request.callback;
807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        }
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      });
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Also convert complex permissions back to objects for events.  The
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // dispatchToListener call happens after argument validation, which works
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // around the problem that Permissions.permissions is supposed to be a list
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // of strings.
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  permissions.onAdded.dispatchToListener = function(callback, args) {
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (var i = 0; i < args[0].permissions.length; i += 1) {
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      args[0].permissions[i] = maybeConvertToObject(args[0].permissions[i]);
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    $Function.call(Event.prototype.dispatchToListener, this, callback, args);
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  };
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  permissions.onRemoved.dispatchToListener =
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      permissions.onAdded.dispatchToListener;
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)});
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)exports.binding = binding.generate();
98