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