1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/renderer/extensions/runtime_custom_bindings.h"
6
7#include "base/bind.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/values.h"
10#include "chrome/common/extensions/extension.h"
11#include "chrome/common/extensions/extension_messages.h"
12#include "chrome/common/extensions/features/feature.h"
13#include "chrome/common/extensions/manifest.h"
14#include "chrome/renderer/extensions/api_activity_logger.h"
15#include "chrome/renderer/extensions/chrome_v8_context.h"
16#include "chrome/renderer/extensions/dispatcher.h"
17#include "content/public/renderer/render_view.h"
18#include "content/public/renderer/v8_value_converter.h"
19#include "extensions/common/features/feature_provider.h"
20#include "third_party/WebKit/public/web/WebDocument.h"
21#include "third_party/WebKit/public/web/WebFrame.h"
22#include "third_party/WebKit/public/web/WebView.h"
23
24using content::V8ValueConverter;
25
26namespace extensions {
27
28RuntimeCustomBindings::RuntimeCustomBindings(Dispatcher* dispatcher,
29                                             ChromeV8Context* context)
30    : ChromeV8Extension(dispatcher, context) {
31  RouteFunction("GetManifest",
32                base::Bind(&RuntimeCustomBindings::GetManifest,
33                           base::Unretained(this)));
34  RouteFunction("OpenChannelToExtension",
35                base::Bind(&RuntimeCustomBindings::OpenChannelToExtension,
36                           base::Unretained(this)));
37  RouteFunction("OpenChannelToNativeApp",
38                base::Bind(&RuntimeCustomBindings::OpenChannelToNativeApp,
39                           base::Unretained(this)));
40}
41
42RuntimeCustomBindings::~RuntimeCustomBindings() {}
43
44void RuntimeCustomBindings::OpenChannelToExtension(
45    const v8::FunctionCallbackInfo<v8::Value>& args) {
46  // Get the current RenderView so that we can send a routed IPC message from
47  // the correct source.
48  content::RenderView* renderview = GetRenderView();
49  if (!renderview)
50    return;
51
52  // The Javascript code should validate/fill the arguments.
53  CHECK_EQ(2, args.Length());
54  CHECK(args[0]->IsString() && args[1]->IsString());
55
56  ExtensionMsg_ExternalConnectionInfo info;
57  info.source_id = context()->extension() ? context()->extension()->id() : "";
58  info.target_id = *v8::String::Utf8Value(args[0]->ToString());
59  info.source_url = renderview->GetWebView()->mainFrame()->document().url();
60  std::string channel_name = *v8::String::Utf8Value(args[1]->ToString());
61  int port_id = -1;
62  renderview->Send(new ExtensionHostMsg_OpenChannelToExtension(
63      renderview->GetRoutingID(), info, channel_name, &port_id));
64  args.GetReturnValue().Set(static_cast<int32_t>(port_id));
65}
66
67void RuntimeCustomBindings::OpenChannelToNativeApp(
68    const v8::FunctionCallbackInfo<v8::Value>& args) {
69  // Verify that the extension has permission to use native messaging.
70  Feature::Availability availability =
71      FeatureProvider::GetByName("permission")->
72          GetFeature("nativeMessaging")->IsAvailableToContext(
73              GetExtensionForRenderView(),
74              context()->context_type(),
75              context()->GetURL());
76  if (!availability.is_available()) {
77    APIActivityLogger::LogBlockedCall(context()->extension()->id(),
78                                      "nativeMessaging",
79                                      availability.result());
80    return;
81  }
82
83  // Get the current RenderView so that we can send a routed IPC message from
84  // the correct source.
85  content::RenderView* renderview = GetRenderView();
86  if (!renderview)
87    return;
88
89  // The Javascript code should validate/fill the arguments.
90  CHECK(args.Length() >= 2 &&
91        args[0]->IsString() &&
92        args[1]->IsString());
93
94  std::string extension_id = *v8::String::Utf8Value(args[0]->ToString());
95  std::string native_app_name = *v8::String::Utf8Value(args[1]->ToString());
96
97  int port_id = -1;
98  renderview->Send(new ExtensionHostMsg_OpenChannelToNativeApp(
99      renderview->GetRoutingID(),
100      extension_id,
101      native_app_name,
102      &port_id));
103  args.GetReturnValue().Set(static_cast<int32_t>(port_id));
104}
105
106void RuntimeCustomBindings::GetManifest(
107    const v8::FunctionCallbackInfo<v8::Value>& args) {
108  CHECK(context()->extension());
109
110  scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
111  args.GetReturnValue().Set(
112      converter->ToV8Value(context()->extension()->manifest()->value(),
113                           context()->v8_context()));
114}
115
116}  // namespace extensions
117